Skip to content

Architecture Overview

Components

graph LR
    subgraph "Mac Mini M4"
        EX[executor.sh<br>LaunchAgent]
        CC[Claude Code<br>Opus/Sonnet]
        MCP[MCP Servers<br>GitHub, Discord, etc.]
        XC[Xcode<br>Build & Test]
    end

    subgraph "External"
        GH[GitHub API<br>Issues & PRs]
        DC[Discord<br>#ibuild-e]
        ASC[App Store Connect]
        RC[RevenueCat]
    end

    EX -->|polls| GH
    EX -->|spawns| CC
    CC -->|uses| MCP
    CC -->|builds| XC
    MCP -->|notifies| DC
    MCP -->|reads| ASC
    MCP -->|reads| RC
    CC -->|pushes & PRs| GH

Executor Loop

The executor (executor.sh) runs as a macOS LaunchAgent and loops indefinitely:

while true:
    issue = find_next_issue()        # Search GitHub for agent-ready issues
    if not issue:
        sleep(60)
        continue

    claim_issue(issue)               # Add agent-claimed label
    workspace = clone_repo(issue)    # Clone to /tmp/executor-workspaces/

    run_claude(workspace, issue)     # Run Claude Code with MCP

    if commits_exist(workspace):
        push_and_create_pr()         # Push branch, create PR
    else:
        report_failure()             # Comment on issue, add agent-failed label

    cleanup(workspace)               # Delete workspace
    sleep(5)

Issue Label Flow

stateDiagram-v2
    [*] --> agent_ready: Issue created with label
    agent_ready --> agent_claimed: Executor picks up
    agent_claimed --> PR_Created: Claude makes commits
    agent_claimed --> agent_failed: Claude fails / no commits
    PR_Created --> Merged: Auto-merge
    PR_Created --> agent_claimed: Review requires changes
    agent_failed --> agent_ready: Human relabels for retry
    Merged --> [*]: Issue auto-closed
Label Meaning
agent-ready Available for pickup by executor
agent-claimed Being worked on — do not touch
agent-failed Executor failed — needs human review. Relabel to agent-ready to retry.
agent-opus Use Opus model instead of Sonnet (more capable, slower)

File Structure

mac-executor/
├── executor.sh              # Main executor loop (LaunchAgent)
├── prompt.md                # System prompt for Claude Code
├── executor-settings.json   # Permission allow/deny lists
├── repos.json               # Managed repositories
├── .mcp.json                # MCP server configuration
├── CLAUDE.md                # Agent identity and rules
├── IDENTITY.md              # Agent persona
├── SOUL.md                  # Agent behavior guidelines
├── setup/
│   └── install-executor.sh  # LaunchAgent installer
├── scripts/
│   ├── consolidate-learnings.sh
│   └── resolve-pr-conversations.sh
├── knowledge/
│   └── per-app/             # App-specific knowledge files
└── docs/                    # This documentation

Security Boundaries

The executor operates under strict rules defined in CLAUDE.md:

Category Rule
Forbidden Submit to App Store, merge PRs, push to main, delete branches
Forbidden Modify pricing, create/delete RevenueCat resources
Forbidden Access Bitwarden, TOTP, Pushbullet
Forbidden Reply to Cuti-E conversations
Allowed Read from GitHub, ASC, RevenueCat, Cuti-E, Memory
Allowed Write code, create PRs, comment on issues
Allowed Send Discord/Slack notifications
Escalation Add requires-human-approval label for production actions