CLI tools and operational extensions for the void architecture on ATProtocol.
void-cli AGENT_IMPLEMENTATION_SPEC.md
11 kB · 424 lines
Markdown

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:

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):

# ~/.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 <platform> <id> → unified URI

2.3 Enhanced Outbox Schema (v2.0) #

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 #

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) #

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

# 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

# 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

# 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:

Week 2:

Week 3:

4.2 Phase 2: Agent Experience Optimization #

Command shortcuts for agents:

# 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:

# 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 #


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 #

# 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 #

# 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 #

# 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.