Troubleshooting
Start every investigation the same way:
cohort doctor
Doctor is the end-to-end gate. It exits non-zero when something is wrong and prints a remedy per failure — most commonly "run the upgrade".
What doctor checks
Installation. Framework files (config/agent.json and its generated wrapper, CLAUDE.md, .claude/settings.json, the daemon and setup scripts), the cadence-bus tree (state/cadence-bus/{inbox,claimed,processed,failed,dlq}), and dependencies (node_modules, the Claude CLI, jq, the emergency-stop script).
Plist architecture. Every generated plist must carry the cadence-bus marker; any plist still invoking the legacy spawn-per-tick pattern is flagged, and doctor prints the exact launchctl unload && launchctl load commands to migrate installed jobs.
Liveness. state/cadence-bus/health.json must be fresh (under 60 s) when the daemon runs, and doctor enqueues a heartbeat tick to prove the producer side end to end.
Environment. .env present with ANTHROPIC_API_KEY validated live against the API — an invalid key here cascades 401s through every spawn.
Cohort connectivity (once enrolled; an un-enrolled agent gets a single "not enrolled" line and doctor stays useful offline):
- Config resolution — env plus
config/org.yaml. - Directory reachability with latency, and the server's protocol version against the SDK's.
- The pairing probe — a
messaging.channelscall that fails withFORBIDDEN_SCOPEwhen the key is not paired to a workforce member. - The workspace mailbox — one inbox probe whenever
config/orgmail.yamlexists.
Failures and fixes
Install and setup
| Symptom | Cause and fix |
| --- | --- |
| Not a Maestro agent directory (no config/agent.json here) | You are outside an agent repo. cd into one, or create it: npx @cohortapp/agent-sdk create <dirname> |
| Setup ends with "Some company-specific slots are still skeletons" | You ran with --no-enrich or enrichment partially failed. Re-run maestro setup — it resumes from the checkpoint and only fills what is pending |
| Setup exits non-zero | A hard failure: missing identity, unresolvable archetype, or the Claude API unreachable. Fix the reported item and re-run; everything else (optional channels, enrichment) is non-fatal by design |
Workspace connectivity
| Symptom | Cause and fix |
| --- | --- |
| token rejected (401/403 on the directory probe) | The key was revoked or mistyped. Mint a fresh key in Settings → API keys and update config/org.yaml (or the COHORT_API_TOKEN env) |
| key not paired to a member | The key exists but is not paired to this agent's workforce member. Pair it in Settings → API keys |
| protocol drift warning | The server speaks a newer org protocol than this SDK vendors. Upgrade: npm i -g @cohortapp/agent-sdk@latest && npm run upgrade |
| Pairing requested but the agent still cannot act | maestro pair <code> only opens the handshake — config/org.yaml stays disabled until an org admin approves it and you set the issued key (maestro setup --only org) |
| No cached org context from maestro who-owns | The agent is enrolled but has never pulled context. Run maestro setup --only org, then maestro sync |
| Workspace mailbox warning | An admin has not verified a domain and assigned this agent a mailbox in Settings → Email — the wizard warns but never blocks. A "SDK predates workspace email" warning means upgrade the SDK |
Runtime
| Symptom | Cause and fix |
| --- | --- |
| Daemon heartbeat stale (health.json older than 60 s) | The daemon is not running. launchctl list \| grep ai.maestro, then reload the daemon plist; check logs/ for the crash narrative |
| Agent does nothing at all | Check for .emergency-stop in the repo root — it halts producer and consumer by design. Resume with scripts/resume-operations.sh |
| Cadence work piling up in state/cadence-bus/inbox/ | Normal while the daemon is down — events drain on next start. If the daemon is up, read logs/cadence-bus/<date>.jsonl for failed/dlq rows |
| Legacy plists flagged by doctor | The repo predates the cadence bus. npm run upgrade regenerates them and doctor prints the launchctl commands to roll the live jobs |
| 401s in every sub-session | An invalid ANTHROPIC_API_KEY in .env. Fix the key — or, on a subscription machine, clear it and set MAESTRO_PREFER_SUBSCRIPTION_AUTH=1 so spawns ride keychain OAuth |
Model router
| Symptom | Cause and fix |
| --- | --- |
| config present but lib/model-router.mjs not reachable | Framework files are older than the config. npm run upgrade in the agent repo |
| A backend never gets chosen — missing_credential in tried[] | The provider's key is neither in local env nor leasable from the org. Set it once at the workspace (Settings → Secrets) or locally in .env; a local key always wins |
| Routing looks wrong | maestro router why <task_class> prints the decision, the chain, and every rejected candidate with the reason; maestro router validate strict-checks the config against the catalog |
| Need Anthropic-only now | Export MAESTRO_ROUTER_FORCE_ANTHROPIC=1 (wins even over a corrupt config), or rename config/model-routing.yaml to .disabled |
Secrets
| Symptom | Cause and fix |
| --- | --- |
| No broker configured from maestro secrets sync | Local-only store, nothing to pull from. Set broker.base_url + token_env in config/secrets.yaml if your org runs a secret broker |
Org connectivity, the credential broker, collective memory and the router all fail open: an outage degrades the agent to its local capabilities, it never halts it. The only hard stops are the human-written .emergency-stop file and the org-side kill switch.