# Social CLI - Agent Implementation Specification **Repository:** `tangled.org:void.comind.network/void-cli` **Date:** 2026-03-24 **Scope:** Agent-optimized social media automation CLI with multi-platform support --- ## 1. Current State ### 1.1 Core Capabilities The CLI currently supports ATProto/Bluesky with the following commands: | Command | Purpose | Agent-Relevant | |---------|---------|----------------| | `sync` | Fetch notifications to `inbox.yaml` | Yes - triggers wake-up logic | | `dispatch` | Post from `outbox.yaml` | Yes - requires strict validation | | `monitor` | Horizon radar for discovery | Yes - enables proactive posting | | `post` | Direct single post | No - bypasses outbox pattern | | `search` | Bluesky search | Yes - for research/validation | | `feed` | Timeline consumption | Yes - input for synthesis | | `ingest-thread` | Full thread archival | Yes - context building | | `annotate` | Margin annotation | Yes - archival memory dual-purpose | | `fetch-history` | User corpus download | Yes - for training/analysis | ### 1.2 Architecture **Pipeline Pattern (Agent-Optimized):** ``` inbox.yaml → [Agent logic] → outbox.yaml → dispatch → Bluesky ↓ archival_memory (annotations) ``` **Key Files:** - `src/void_tools/cli.py` - Main CLI logic (~1150 lines) - `src/void_tools/client.py` - ATProto client wrapper - `src/void_tools/constitutional_linter.py` - Tone enforcement - `src/void_tools/monitor.py` - Horizon radar - `src/void_tools/precheck.py` - Pre-invocation heuristic ### 1.3 Critical Features (Recently Added) **Pre-Flight Validation (2026-03-24):** - `validate_outbox()` function checks all actions before dispatch - Validates: action field existence, valid types, posts structure, grapheme counts, mandatory annotations, target_id resolution - Strict-by-default: warnings treated as fatal errors - `--lenient` flag to opt out, `--dry-run` for validation-only **Annotation Dual-Purpose:** All dispatched posts include `at.margin.annotation` records that auto-mirror to Letta archival memory. Public record doubles as internal knowledge base. --- ## 2. Desired Functionality ### 2.1 Multi-Platform Support **Phase 1: X (Twitter) Integration** New platform abstraction layer: ```python class SocialPlatform(ABC): @abstractmethod def post(self, text: str, **kwargs) -> PostRef: pass @abstractmethod def reply(self, target_uri: str, text: str, **kwargs) -> PostRef: pass @abstractmethod def notifications(self) -> list[Notification]: pass class ATProtoPlatform(SocialPlatform): ... class XPlatform(SocialPlatform): ... ``` **Configuration Schema (Expanded):** ```yaml # ~/.config/social-cli/config.yaml version: "2.0" default_platform: bsky agent_mode: true # Enables agent-optimized patterns accounts: bsky: handle: void.comind.network pds: comind.network credentials: .env.bsky # Path to env file x: handle: void_2 api_key: ${X_API_KEY} api_secret: ${X_API_SECRET} access_token: ${X_ACCESS_TOKEN} bearer_token: ${X_BEARER_TOKEN} threads: handle: void.threads.net # Meta Business API credentials ``` ### 2.2 Unified URI Scheme **Cross-platform addressing:** ``` social://bsky/did:plc:.../app.bsky.feed.post/3mht... social://x/1234567890123456789 social://threads/1234567890 social://mastodon/123456789@instance.social ``` Resolution endpoints: - `void-cli resolve social://x/123...` → platform-native URI - `void-cli canonical ` → unified URI ### 2.3 Enhanced Outbox Schema (v2.0) ```yaml version: "2.0" config: mark_seen: true platforms: [bsky, x] # Cross-post targets actions: - action: reply target_id: "notif_123" platforms: bsky: posts: ["Bluesky-specific text"] # Platform-aware x: posts: ["X-optimized under 280 chars"] unified: posts: ["Default text if platform not specified"] annotation: text: "Cross-platform response to user query" - action: post platforms: [bsky, x, threads] # Broadcast posts: - "Announcing something important" - action: thread platforms: [bsky] # Long-form on ATProto only posts: - "First post" - "Second post" - "Third post" - action: quote target_uri: "social://x/123..." platforms: [bsky] # Quote X post on Bluesky posts: - "Commentary on this X post" ``` ### 2.4 Platform-Aware Validation ```python PLATFORM_LIMITS = { 'bsky': {'chars': 300, 'media': 4, 'threads': True}, 'x': {'chars': 280, 'media': 4, 'threads': False}, # Premium allows 25000 'threads': {'chars': 500, 'media': 10, 'threads': True}, } ``` Validation per platform before dispatch. Graceful degradation: - If text > 280 but < 300: Post to Bsky, skip X rather than truncate - Option: Auto-split threads on X vs single long post on Bsky --- ## 3. Agent-Specific Requirements ### 3.1 Batch Atomicity (Preserved) ```yaml actions: # All succeed or all fail - no partial states - action: post platforms: [bsky, x] posts: ["Simultaneous broadcast"] rollback_on_failure: true # Delete from platforms where posted if any fail ``` ### 3.2 Notification Aggregation **Current:** Single inbox per platform **Desired:** Unified inbox across platforms ```yaml # inbox.yaml (Unified) - id: notif_bsky_123 platform: bsky type: reply author: '@user.bsky.social' uri: social://bsky/... - id: notif_x_456 platform: x type: reply author: '@user_x' uri: social://x/... ``` ### 3.3 Memory Integration **Current:** Annotations auto-mirror to Letta archival memory **Desired:** Platform-aware extraction ```python # Auto-extract from dispatched posts memory_update: target_handle: "user.bsky.social" platform: bsky # Track platform preference facts: - "User prefers technical discussion" - "Active on Bluesky daily, X weekly" ``` ### 3.4 Wake-Up Triggers **Current:** Bsky-only via `precheck.py` **Desired:** Multi-platform heuristic ```python # precheck_v2.py WAKE_CONDITIONS = { 'any_platform_admin_mention': True, 'bsky_threshold': 3, 'x_threshold': 2, # Lower threshold for X (slower platform) 'horizon_matches': 1, # Agentic discovery trigger } ``` --- ## 4. Execution Goals ### 4.1 Phase 1: X Integration **Week 1:** - [ ] Create `XPlatform` class implementing `SocialPlatform` - [ ] Add X credentials to config schema - [ ] Implement `x notifications` command - [ ] Implement `x post` and `x reply` commands - [ ] Add X validation (280 char limit) **Week 2:** - [ ] Unified inbox across Bsky + X - [ ] Cross-platform outbox schema v2.0 - [ ] Platform-aware dispatch logic - [ ] Update precheck for multi-platform wake-up **Week 3:** - [ ] Testing with existing agent workflows - [ ] Documentation for agent consumption - [ ] Migration guide from void-cli → social-cli ### 4.2 Phase 2: Agent Experience Optimization **Command shortcuts for agents:** ```bash # Single-command replies social-cli quick-reply social://bsky/... "Text" # Status check for wake-up decisions social-cli actionable-check # Returns exit code 0/1, no text output # Batch operations social-cli bulk-draft --from-summary summary.yaml ``` **YAML simplification:** ```yaml # Concise format for agents dispatch: - reply: "notif_123" text: "Response text" platforms: [bsky, x] - post: "Announcement" platforms: [bsky, x, threads] ``` ### 4.3 Phase 3: Advanced Features - [ ] Thread continuation detection ("say more" → auto-thread) - [ ] Cross-platform engagement analytics - [ ] Best-time-to-post prediction per platform - [ ] Content repurposing (long Bsky post → X thread auto-split) --- ## 5. Architectural Decisions ### 5.1 Preserve These Patterns 1. **Outbox-as-transaction** - Batch atomicity is essential for agent consistency 2. **Pre-flight validation** - Fail fast before network calls 3. **Archival dual-purpose** - Public posts = private memory 4. **Git-auditable** - Every state change committed/archived ### 5.2 Change These Patterns 1. **Platform assumptions** - ATProto URLs hardcoded in current version 2. **Single-platform auth** - `.env` pattern assumes one account 3. **Notification format** - Bsky-specific fields in inbox.yaml 4. **Dispatch logic** - Platform-agnostic handlers needed ### 5.3 Design Principles 1. **Agent-First:** CLI is headless-first, interactive-second 2. **Strict-Default:** Validation strictness prevents network errors 3. **Graceful Degradation:** Cross-post failures don't cascade 4. **Unified Interface:** Same YAML schema, platform-agnostic logic --- ## 6. Testing Requirements ### 6.1 Agent Workflow Tests ```bash # Test 1: Standard Sync-Scan-Search-Dispatch ./agent_test.sh # 1. sync → inbox populated # 2. monitor → horizon populated # 3. agent invoked → drafts outbox # 4. dispatch → posts to all platforms # 5. notifications marked seen # Test 2: Cross-platform reply social-cli quick-draft reply social://bsky/... --text "Response" --platforms bsky,x social-cli dispatch # Verify: Posted to Bsky AND X, both in archives # Test 3: Platform-specific limits social-cli dispatch --dry-run outbox_long_post.yaml # Expected: Error for X (too long), pass for Bsky ``` ### 6.2 Validation Tests ```bash # Missing action field social-cli dispatch --dry-run bad_outbox.yaml # Expected: Exit 1, error "Missing required 'action' field" # X character limit exceeded social-cli dispatch --dry-run long_text.yaml --platform x # Expected: Exit 1, error "Text exceeds 280 characters" ``` --- ## 7. Migration Path ### 7.1 From void-cli to social-cli ```bash # Step 1: Rename (backwards compatible) mv void-cli social-cli ln -s social-cli void-cli # Symlink for existing scripts # Step 2: Config migration cp .env .env.bsky # Add X credentials to .env.x # Step 3: Update config.yaml echo 'version: "2.0"' >> config.yaml echo 'default_platform: bsky' >> config.yaml # Step 4: Test existing workflows ./run_bots.py # Should work unchanged ``` ### 7.2 Breaking Changes - None expected for ATProto-only workflows - X addition is additive - New unified URI scheme is opt-in --- ## 8. Success Metrics 1. **Agent uptime:** Zero dispatch failures due to validation gaps 2. **Cross-platform reach:** Single outbox → multiple platforms 3. **Latency:** Sub-30s from notification to reply on all platforms 4. **Atomicity:** 0% partial dispatch rates --- ## 9. Appendix: Key Code Locations ### 9.1 Dispatch Logic **File:** `src/void_tools/cli.py` **Function:** `cmd_dispatch()` (line ~414) **Key addition:** Platform routing logic after validation ### 9.2 Validation Logic **File:** `src/void_tools/cli.py` **Function:** `validate_outbox()` (line ~14) **Key addition:** Per-platform limit checking ### 9.3 Configuration Loading **File:** `src/void_tools/cli.py` **Function:** `get_client()` **Key addition:** Multi-platform credential switching ### 9.4 Wake-Up Logic **File:** `src/void_tools/precheck.py` **Key addition:** Aggregate across platforms --- **End of Specification** **Next Step:** Fork repository at `tangled.org:void.comind.network/void-cli` and begin X platform implementation following Phase 1 timeline.