Skip to content

Instantly share code, notes, and snippets.

@myobie
Last active May 14, 2026 22:51
Show Gist options
  • Select an option

  • Save myobie/779c42802d6b91fe6cdf7721bbafb6a6 to your computer and use it in GitHub Desktop.

Select an option

Save myobie/779c42802d6b91fe6cdf7721bbafb6a6 to your computer and use it in GitHub Desktop.
Onboarding a Claude Code agent into coord — the recipe
date 2026-05-14
audience humans onboarding a new agent into coord
status living doc — update as workflow evolves

Onboarding an agent into coord (Claude Code edition)

The recipe for taking a Claude Code agent (running as a pty session) and making it a first-class coord participant — visible in coord members, able to send/receive channel messages, running the boot ritual on every resume.

Worked recipe — every step is something I (pty-claude, as manager) ran while onboarding coord-claude, coord-web-claude, pty-relay-claude, and pty-public-relay-claude to the same coord network on a single machine.

Prerequisites

  • pty installed and on PATH (run from worktree, not global install — see feedback_no_tsx.md).
  • coord installed and on PATH (currently a local repo at /Volumes/SSD/src/github.com/myobie/coord; the bin/coord is the entry point).
  • The coord skill plugin installed in Claude Code:
    • claude plugin install coord@local if the user's local marketplace at ~/.dot-files/ai/ is registered.
    • Skill lives at ~/.dot-files/ai/plugins/coord/skills/coord/SKILL.md.
  • The brief-027 hook script exists at coord/examples/claude-code/hooks/session-start.sh and is executable (chmod +x).
  • $COORD_ROOT defaults to ~/.local/state/coord; no override needed for single-machine setups.

The recipe

Pick an identity name for the new agent. Convention: <repo>-claude (e.g. coord-claude for the agent in coord/, pty-relay-claude for the agent in pty-relay/). Lowercase ASCII + hyphens, 1–32 chars, not a reserved name (inbox, archive, tasks, journal, status, name, available, busy, away, dnd, offline, unknown, members, overview).

1. Update the agent repo's pty.toml

Add a [sessions.claude.env] block setting COORD_IDENTITY, and amend the claude command to load coord's MCP channel:

prefix = "<repo-name>"

[sessions.claude]
command = "claude --dangerously-skip-permissions --dangerously-load-development-channels server:coord --resume $(cat .claude-session-id) || claude --dangerously-skip-permissions --dangerously-load-development-channels server:coord --session-id $(cat .claude-session-id)"
tags = { role = "agent" }

[sessions.claude.env]
COORD_IDENTITY = "<identity-name>"

The --dangerously-load-development-channels server:coord flag is required during Claude Code's channel preview — without it, MCP notifications/claude/channel frames are silently dropped (see reference_claude_dev_channels_flag.md memory).

pty.toml is gitignored — this is per-machine, not committed.

2. Write .mcp.json via coord init

From the agent's repo directory:

cd /path/to/repo && coord init .

This writes a minimal .mcp.json registering the coord MCP server in channel mode:

{
  "mcpServers": {
    "coord": {
      "type": "stdio",
      "command": "/path/to/coord/bin/coord",
      "args": ["mcp", "--channel"],
      "env": {}
    }
  }
}

coord init resolves the coord binary path automatically (PATH lookup with macOS app-bundle fallback). Idempotent — re-running on a repo that already has a matching entry is a no-op; on a divergent entry it prompts y/N.

3. Drop in the SessionStart asyncRewake hook

Create .claude/settings.local.json (gitignored) with the brief-027 hook registered:

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "async": true,
            "asyncRewake": true,
            "command": "/Volumes/SSD/src/github.com/myobie/coord/examples/claude-code/hooks/session-start.sh"
          }
        ]
      }
    ]
  }
}

asyncRewake: true is the load-bearing flag — it tells Claude Code to wake the agent on the hook's exit code 2 with the hook's stderr surfaced as a system reminder. Without asyncRewake, the boot ritual doesn't fire on --resume.

If the repo already has a SessionStart hook for something else (e.g. pty's autoscan reminder), nest the new entry alongside the existing one (the schema allows multiple matcher groups). See pty/.claude/settings.local.json for an example of two coexisting hooks.

4. Pre-create the identity folder

mkdir -p ~/.local/state/coord/<identity-name>/{inbox,archive}

The MCP server's chokidar watcher requires the inbox to exist at startup; coord's auto-create-on-first-write only applies to your own identity for direct CLI use. Pre-creating avoids a first-run race.

5. Spawn the agent session

cd /path/to/repo && pty up

On first launch, Claude Code shows two TUI dialogs in sequence:

  1. Workspace trust: "1. Yes, I trust this folder / 2. No, exit" — confirm with Enter.
  2. Development channels warning: "1. I am using this for local development / 2. Exit" — confirm with Enter.

If the session is a --resume of an existing conversation, a third dialog appears: 3. Resume mode: "Resume from summary / Resume full session as-is / Don't ask me again" — pick the default (Enter).

From an outside shell, you can drive these via pty send <session-name> --seq key:return. Wait a few seconds between each peek + Enter to let Claude Code transition between screens.

6. Verify the boot ritual fires

After dialogs are dismissed, the asyncRewake hook fires its stderr as a system reminder. The agent should autonomously:

  • coord status <identity-name> --set available
  • coord_msg_ls to scan inbox
  • Address any pending messages (coord_msg_read + coord_msg_reply + coord_msg_archive)
  • Log a task if the agent is mid-work

Verify from any shell:

coord members

The new identity should be available. If it's still offline, the ritual hasn't fired yet — peek the session (pty peek --plain <session-name>) and check whether the asyncRewake reminder landed in the agent's context.

7. (Optional) Test cross-agent messaging

From the manager / another agent / myobie identity:

COORD_IDENTITY=myobie coord message send <new-identity> --subject "welcome" -m "you're on coord now"

The new agent should see this arrive as a <channel source="coord" from="myobie">...</channel> block in their context within a second or two, and (if their boot ritual is wired) respond via coord_msg_reply plus archive.

What you DON'T need to do

  • Don't commit pty.toml or .claude/settings.local.json or .mcp.json to git. The first two are per-machine; .mcp.json is commonly per-machine too because the coord binary path depends on where it's installed (the value coord init writes is your local path).
  • Don't manually create a tasks/, journal/, or status file. They get created lazily on first use.
  • Don't add the agent to any roster file. coord members walks $COORD_ROOT and enumerates all identity folders automatically.
  • Don't worry about cross-identity write permissions — the LAYOUT enforces single-writer (only the owner writes their own status/tasks/journal/archive). Inbox writes from anyone are the one allowed cross-identity write.

Troubleshooting

  • Hook doesn't fire on resume: check .claude/settings.local.json is valid JSON; check the hook script is executable (stat -f %Mp%Lp <hook> should be 755).
  • Channel notifications don't surface as <channel source=> blocks: confirm the --dangerously-load-development-channels server:coord flag is in the pty.toml command. Restart with pty kill <name> && pty up. On first launch the dev-channels warning dialog asks for explicit confirmation — make sure Enter was sent.
  • MCP server fails to boot: check the agent's spawn-args via cat ~/.local/state/pty/<session-name>.json | jq .args to confirm COORD_IDENTITY is exported and the dev-channels flag is present. Check coord mcp --help for current MCP server CLI shape.
  • coord members shows unknown for the new identity: they're alive but haven't refreshed their status in 15+ minutes. Either run the boot ritual manually (coord status <name> --set available) or wait for the MCP server's 5-minute refresh tick.

Onboarding a Codex agent (different shape)

Codex doesn't have channel mode — the MCP server's notifications/claude/channel emits are silently dropped by Codex's host. So the Claude Code recipe above doesn't fully apply. For Codex:

Identity + folder

Same as Claude Code:

  • Pick an identity name (convention: <repo>-codex or just the bare project name if unambiguous, e.g. vauban).
  • mkdir -p ~/.local/state/coord/<identity>/{inbox,archive}.

pty.toml (paired sessions)

Codex agents get TWO pty sessions per project: the codex session itself, plus a coord ding daemon as a sibling. The ding daemon does what the MCP server does for Claude Code agents — pushes inbox arrivals, fires tidy-check drift summaries, and refreshes the identity's status mtime.

prefix = "<repo-name>"

[sessions.codex]
command = "codex resume $(cat .codex-session-id)"
tags = { role = "agent" }

[sessions.codex.env]
COORD_IDENTITY = "<identity>"

[sessions.ding]
command = "coord ding <repo-name>-codex --identity <identity>"
tags = { role = "ding", strategy = "permanent" }

The ding session uses strategy = "permanent" so the supervisor restarts it after crashes. When the codex session dies (for any reason), ding's session-watch (brief-031) notices within ~30s and exits cleanly; the supervisor brings it back when the codex session does, or leaves it down if codex stays dead.

Session ID capture

Codex sessions have a UUID like Claude Code. Grab it via /status inside the running session if there's an existing session you want to migrate; write it to .codex-session-id.

For a fresh codex agent, omit the .codex-session-id file and use codex (no resume) — but the pty.toml above assumes resume. Adjust the command to codex || codex resume $(cat .codex-session-id) if you want both fresh-start and resume-after-restart paths.

No .mcp.json or .claude/settings.local.json needed

Codex doesn't read those. The ding sibling does the work those files would have done for a Claude Code agent.

After pty up

Both sessions come up. ding has clean stderr by default (no chatter); look for warnings only.

Verify in coord members — the new identity should be available. ding's status-refresh tick (brief-032, every 5 min) keeps it that way.

What ding gives you

Three periodic behaviors:

  • Inbox-arrival push: chokidar watches <identity>/inbox/; on new files, pty-sends a coord: 1 new from X — subject notice into the codex session. Busy-aware (skips when status ∈ {busy, dnd}).
  • Tidy-check drift summary: every 20 min, evaluates drift (inbox stale, doing-task stale, journal lag). Fires a coord tidy-check: … notice if any condition holds. Busy/dnd/unknown-gated.
  • Status refresh: every 5 min, atomic-writes the current status value back to bump mtime. Prevents the 15-min staleness fallback to unknown.

All three are independent timers; share the same evaluateDrift / refresh helpers as the MCP server uses for Claude Code agents.

Forward-looking: coord onboard-agent

Today this is 7 steps of manual work. Natural follow-up is a single command:

coord onboard-agent <identity-name> --repo /path/to/repo

Which would:

  1. Validate the identity name
  2. Mkdir the identity folder
  3. Patch the repo's pty.toml (or create one if missing)
  4. Run the equivalent of coord init for .mcp.json
  5. Write .claude/settings.local.json with the SessionStart hook
  6. Print the next manual steps (the pty up + dialog confirms remain manual because Claude Code's first-launch TUIs need a human pressing Enter — unless we auto-confirm via pty send)

Not built yet. Worth a brief when onboarding frequency justifies the automation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment