N coordinated agents on shared task list using Claude Code native teams
52
42%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./skills/team/SKILL.mdSpawn N coordinated agents working on a shared task list using Claude Code's native team tools. Replaces the legacy /swarm skill (SQLite-based) with built-in team management, inter-agent messaging, and task dependencies -- no external dependencies required.
The swarm compatibility alias was removed in #1131.
/oh-my-claudecode:team N:agent-type "task description"
/oh-my-claudecode:team "task description"
/oh-my-claudecode:team ralph "task description"team-exec stage (e.g., executor, debugger, designer, codex, gemini). Optional; defaults to stage-aware routing. Use codex to spawn Codex CLI workers or gemini for Gemini CLI workers (requires respective CLIs installed). See Stage Agent Routing below./team 5:executor "fix all TypeScript errors across the project"
/team 3:debugger "fix build errors in src/"
/team 4:designer "implement responsive layouts for all page components"
/team "refactor the auth module with security review"
/team ralph "build a complete REST API for user management"
# With Codex CLI workers (requires: npm install -g @openai/codex)
/team 2:codex "review architecture and suggest improvements"
# With Gemini CLI workers (requires: npm install -g @google/gemini-cli)
/team 2:gemini "redesign the UI components"
# Mixed: Codex for backend analysis, Gemini for frontend (use /ccg instead for this)User: "/team 3:executor fix all TypeScript errors"
|
v
[TEAM ORCHESTRATOR (Lead)]
|
+-- TeamCreate("fix-ts-errors")
| -> lead becomes team-lead@fix-ts-errors
|
+-- Analyze & decompose task into subtasks
| -> explore/architect produces subtask list
|
+-- TaskCreate x N (one per subtask)
| -> tasks #1, #2, #3 with dependencies
|
+-- TaskUpdate x N (pre-assign owners)
| -> task #1 owner=worker-1, etc.
|
+-- Task(team_name="fix-ts-errors", name="worker-1") x 3
| -> spawns teammates into the team
|
+-- Monitor loop
| <- SendMessage from teammates (auto-delivered)
| -> TaskList polling for progress
| -> SendMessage to unblock/coordinate
|
+-- Completion
-> SendMessage(shutdown_request) to each teammate
<- SendMessage(shutdown_response, approve: true)
-> TeamDelete("fix-ts-errors")
-> rm .omc/state/team-state.jsonStorage layout (managed by Claude Code):
~/.claude/
teams/fix-ts-errors/
config.json # Team metadata + members array
tasks/fix-ts-errors/
.lock # File lock for concurrent access
1.json # Subtask #1
2.json # Subtask #2 (may be internal)
3.json # Subtask #3
...Team execution follows a staged pipeline:
team-plan -> team-prd -> team-exec -> team-verify -> team-fix (loop)
Each pipeline stage uses specialized agents -- not just executors. The lead selects agents based on the stage and task characteristics.
| Stage | Required Agents | Optional Agents | Selection Criteria |
|---|---|---|---|
| team-plan | explore (haiku), planner (opus) | analyst (opus), architect (opus) | Use analyst for unclear requirements. Use architect for systems with complex boundaries. |
| team-prd | analyst (opus) | critic (opus) | Use critic to challenge scope. |
| team-exec | executor (sonnet) | executor (opus), debugger (sonnet), designer (sonnet), writer (haiku), test-engineer (sonnet) | Match agent to subtask type. Use executor (model=opus) for complex autonomous work, designer for UI, debugger for compilation issues, writer for docs, test-engineer for test creation. |
| team-verify | verifier (sonnet) | test-engineer (sonnet), security-reviewer (sonnet), code-reviewer (opus) | Always run verifier. Add security-reviewer for auth/crypto changes. Add code-reviewer for >20 files or architectural changes. code-reviewer also covers style/formatting checks. |
| team-fix | executor (sonnet) | debugger (sonnet), executor (opus) | Use debugger for type/build errors and regression isolation. Use executor (model=opus) for complex multi-file fixes. |
Routing rules:
N:agent-type parameter only overrides the team-exec stage worker type. All other stages use stage-appropriate specialists.opus agents to sonnet, sonnet to haiku where quality permits. team-verify always uses at least sonnet.security-reviewer + code-reviewer (opus) in team-verify.explore scans codebase, planner creates task graph, optionally analyst/architect for complex tasks.analyst extracts requirements, optionally critic.TeamCreate, TaskCreate, assignment, and worker spawn are complete.verifier + task-appropriate reviewers (see routing table).team-fix.executor/debugger depending on defect type.team-exec then team-verify.Continue team-exec -> team-verify -> team-fix until:
team-fix is bounded by max attempts. If fix attempts exceed the configured limit, transition to terminal failed (no infinite loop).
When transitioning between stages, important context — decisions made, alternatives rejected, risks identified — lives only in the lead's conversation history. If the lead's context compacts or agents restart, this knowledge is lost.
Each completing stage MUST produce a handoff document before transitioning.
The lead writes handoffs to .omc/handoffs/<stage-name>.md.
## Handoff: <current-stage> → <next-stage>
- **Decided**: [key decisions made in this stage]
- **Rejected**: [alternatives considered and why they were rejected]
- **Risks**: [identified risks for the next stage]
- **Files**: [key files created or modified]
- **Remaining**: [items left for the next stage to handle].omc/handoffs/ for session resume. They are not deleted by TeamDelete.## Handoff: team-plan → team-exec
- **Decided**: Microservice architecture with 3 services (auth, api, worker). PostgreSQL for persistence. JWT for auth tokens.
- **Rejected**: Monolith (scaling concerns), MongoDB (team expertise is SQL), session cookies (API-first design).
- **Risks**: Worker service needs Redis for job queue — not yet provisioned. Auth service has no rate limiting in initial design.
- **Files**: DESIGN.md, TEST_STRATEGY.md
- **Remaining**: Database migration scripts, CI/CD pipeline config, Redis provisioning..omc/handoffs/ to recover stage transition context./oh-my-claudecode:cancel requests teammate shutdown, waits for responses (best effort), marks phase cancelled with active=false, captures cancellation metadata, then deletes team resources and clears/preserves Team state per policy. Handoff files in .omc/handoffs/ are preserved for potential resume.complete, failed, and cancelled.Use explore or architect (via MCP or agent) to analyze the codebase and break the task into N subtasks:
subject and detailed descriptionCall TeamCreate with a slug derived from the task:
{
"team_name": "fix-ts-errors",
"description": "Fix all TypeScript errors across the project"
}Response:
{
"team_name": "fix-ts-errors",
"team_file_path": "~/.claude/teams/fix-ts-errors/config.json",
"lead_agent_id": "team-lead@fix-ts-errors"
}The current session becomes the team lead (team-lead@fix-ts-errors).
Write OMC state using the state_write MCP tool for proper session-scoped persistence:
state_write(mode="team", active=true, current_phase="team-plan", state={
"team_name": "fix-ts-errors",
"agent_count": 3,
"agent_types": "executor",
"task": "fix all TypeScript errors",
"fix_loop_count": 0,
"max_fix_loops": 3,
"linked_ralph": false,
"stage_history": "team-plan"
})Note: The MCP
state_writetool transports all values as strings. Consumers must coerceagent_count,fix_loop_count,max_fix_loopsto numbers andlinked_ralphto boolean when reading state.
State schema fields:
| Field | Type | Description |
|---|---|---|
active | boolean | Whether team mode is active |
current_phase | string | Current pipeline stage: team-plan, team-prd, team-exec, team-verify, team-fix |
team_name | string | Slug name for the team |
agent_count | number | Number of worker agents |
agent_types | string | Comma-separated agent types used in team-exec |
task | string | Original task description |
fix_loop_count | number | Current fix iteration count |
max_fix_loops | number | Maximum fix iterations before failing (default: 3) |
linked_ralph | boolean | Whether team is linked to a ralph persistence loop |
stage_history | string | Comma-separated list of stage transitions with timestamps |
Update state on every stage transition:
state_write(mode="team", current_phase="team-exec", state={
"stage_history": "team-plan:2026-02-07T12:00:00Z,team-prd:2026-02-07T12:01:00Z,team-exec:2026-02-07T12:02:00Z"
})Read state for resume detection:
state_read(mode="team")If active=true and current_phase is non-terminal, resume from the last incomplete stage instead of creating a new team.
Call TaskCreate for each subtask. Set dependencies with TaskUpdate using addBlockedBy.
// TaskCreate for subtask 1
{
"subject": "Fix type errors in src/auth/",
"description": "Fix all TypeScript errors in src/auth/login.ts, src/auth/session.ts, and src/auth/types.ts. Run tsc --noEmit to verify.",
"activeForm": "Fixing auth type errors"
}Response stores a task file (e.g. 1.json):
{
"id": "1",
"subject": "Fix type errors in src/auth/",
"description": "Fix all TypeScript errors in src/auth/login.ts...",
"activeForm": "Fixing auth type errors",
"owner": "",
"status": "pending",
"blocks": [],
"blockedBy": []
}For tasks with dependencies, use TaskUpdate after creation:
// Task #3 depends on task #1 (shared types must be fixed first)
{
"taskId": "3",
"addBlockedBy": ["1"]
}Pre-assign owners from the lead to avoid race conditions (there is no atomic claiming):
// Assign task #1 to worker-1
{
"taskId": "1",
"owner": "worker-1"
}Spawn N teammates using Task with team_name and name parameters. Each teammate gets the team worker preamble (see below) plus their specific assignment.
{
"subagent_type": "oh-my-claudecode:executor",
"team_name": "fix-ts-errors",
"name": "worker-1",
"prompt": "<worker-preamble + assigned tasks>"
}Response:
{
"agent_id": "worker-1@fix-ts-errors",
"name": "worker-1",
"team_name": "fix-ts-errors"
}Side effects:
config.json members arraymetadata._internal: true) tracking the agent lifecycleTaskList output -- filter them when counting real tasksIMPORTANT: Spawn all teammates in parallel (they are background agents). Do NOT wait for one to finish before spawning the next.
The lead orchestrator monitors progress through two channels:
Inbound messages -- Teammates send SendMessage to team-lead when they complete tasks or need help. These arrive automatically as new conversation turns (no polling needed).
TaskList polling -- Periodically call TaskList to check overall progress:
#1 [completed] Fix type errors in src/auth/ (worker-1)
#3 [in_progress] Fix type errors in src/api/ (worker-2)
#5 [pending] Fix type errors in src/utils/ (worker-3)Format: #ID [status] subject (owner)
Coordination actions the lead can take:
message with guidance or missing contextTaskUpdate to assign pending tasks to them and notify via SendMessageMonitor for stuck or failed teammates:
in_progress for more than 5 minutes without messages, send a status checkOn every stage transition, update OMC state:
// Entering team-exec after planning
state_write(mode="team", current_phase="team-exec", state={
"stage_history": "team-plan:T1,team-prd:T2,team-exec:T3"
})
// Entering team-verify after execution
state_write(mode="team", current_phase="team-verify")
// Entering team-fix after verify failure
state_write(mode="team", current_phase="team-fix", state={
"fix_loop_count": 1
})This enables:
state_read(mode="team") reveals the last stage and team name for recoverycurrent_phase to know what cleanup is neededWhen all real tasks (non-internal) are completed or failed:
completed via TaskListshutdown_request to each active teammate:
{
"type": "shutdown_request",
"recipient": "worker-1",
"content": "All work complete, shutting down team"
}shutdown_response(approve: true) and terminatesTeamDelete to clean up:
{ "team_name": "fix-ts-errors" }{
"success": true,
"message": "Cleaned up directories and worktrees for team \"fix-ts-errors\"",
"team_name": "fix-ts-errors"
}.omc/state/team-state.jsonWhen spawning teammates, include this preamble in the prompt to establish the work protocol. Adapt it per teammate with their specific task assignments.
You are a TEAM WORKER in team "{team_name}". Your name is "{worker_name}".
You report to the team lead ("team-lead").
You are not the leader and must not perform leader orchestration actions.
== WORK PROTOCOL ==
1. CLAIM: Call TaskList to see your assigned tasks (owner = "{worker_name}").
Pick the first task with status "pending" that is assigned to you.
Call TaskUpdate to set status "in_progress":
{"taskId": "ID", "status": "in_progress", "owner": "{worker_name}"}
2. WORK: Execute the task using your tools (Read, Write, Edit, Bash).
Do NOT spawn sub-agents. Do NOT delegate. Work directly.
3. COMPLETE: When done, mark the task completed:
{"taskId": "ID", "status": "completed"}
4. REPORT: Notify the lead via SendMessage:
{"type": "message", "recipient": "team-lead", "content": "Completed task #ID: <summary of what was done>", "summary": "Task #ID complete"}
5. NEXT: Check TaskList for more assigned tasks. If you have more pending tasks, go to step 1.
If no more tasks are assigned to you, notify the lead:
{"type": "message", "recipient": "team-lead", "content": "All assigned tasks complete. Standing by.", "summary": "All tasks done, standing by"}
6. SHUTDOWN: When you receive a shutdown_request, respond with:
{"type": "shutdown_response", "request_id": "<from the request>", "approve": true}
== BLOCKED TASKS ==
If a task has blockedBy dependencies, skip it until those tasks are completed.
Check TaskList periodically to see if blockers have been resolved.
== ERRORS ==
If you cannot complete a task, report the failure to the lead:
{"type": "message", "recipient": "team-lead", "content": "FAILED task #ID: <reason>", "summary": "Task #ID failed"}
Do NOT mark the task as completed. Leave it in_progress so the lead can reassign.
== RULES ==
- NEVER spawn sub-agents or use the Task tool
- NEVER run tmux pane/session orchestration commands (for example `tmux split-window`, `tmux new-session`)
- NEVER run team spawning/orchestration skills or commands (for example `$team`, `$ultrawork`, `$autopilot`, `$ralph`, `omc team ...`, `omx team ...`)
- ALWAYS use absolute file paths
- ALWAYS report progress via SendMessage to "team-lead"
- Use SendMessage with type "message" only -- never "broadcast"When composing teammate prompts, append a short addendum based on worker type:
claude_worker: Emphasize strict TaskList/TaskUpdate/SendMessage loop and no orchestration commands.codex_worker: Emphasize CLI API lifecycle (omc team api ... --json) and explicit failure ACKs with stderr.gemini_worker: Emphasize bounded file ownership and milestone ACKs after each completed sub-step.This addendum must preserve the core rule: worker = executor only, never leader/orchestrator.
{
"type": "message",
"recipient": "team-lead",
"content": "Completed task #1: Fixed 3 type errors in src/auth/login.ts and 2 in src/auth/session.ts. All files pass tsc --noEmit.",
"summary": "Task #1 complete"
}{
"type": "message",
"recipient": "worker-2",
"content": "Task #3 is now unblocked. Also pick up task #5 which was originally assigned to worker-1.",
"summary": "New task assignment"
}{
"type": "broadcast",
"content": "STOP: shared types in src/types/index.ts have changed. Pull latest before continuing.",
"summary": "Shared types changed"
}CRITICAL: Steps must execute in exact order. Never call TeamDelete before shutdown is confirmed.
Step 1: Verify completion
Call TaskList — verify all real tasks (non-internal) are completed or failed.Step 2: Request shutdown from each teammate
Lead sends:
{
"type": "shutdown_request",
"recipient": "worker-1",
"content": "All work complete, shutting down team"
}Step 3: Wait for responses (BLOCKING)
shutdown_responseTeammate receives and responds:
{
"type": "shutdown_response",
"request_id": "shutdown-1770428632375@worker-1",
"approve": true
}After approval:
config.json members arrayStep 4: TeamDelete — only after ALL teammates confirmed or timed out
{ "team_name": "fix-ts-errors" }Step 5: Orphan scan
Check for agent processes that survived TeamDelete:
node "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-orphans.mjs" --team-name fix-ts-errorsThis scans for processes matching the team name whose config no longer exists, and terminates them (SIGTERM → 5s wait → SIGKILL). Supports --dry-run for inspection.
Shutdown sequence is BLOCKING: Do not proceed to TeamDelete until all teammates have either:
shutdown_response with approve: true), ORIMPORTANT: The request_id is provided in the shutdown request message that the teammate receives. The teammate must extract it and pass it back. Do NOT fabricate request IDs.
The team skill supports hybrid execution combining Claude agent teammates with external CLI workers (Codex CLI and Gemini CLI). Both types can make code changes -- they differ in capabilities and cost. These are standalone CLI tools, not MCP servers.
Tasks are tagged with an execution mode during decomposition:
| Execution Mode | Provider | Capabilities |
|---|---|---|
claude_worker | Claude agent | Full Claude Code tool access (Read/Write/Edit/Bash/Task). Best for tasks needing Claude's reasoning + iterative tool use. |
codex_worker | Codex CLI (tmux pane) | Full filesystem access in working_directory. Runs autonomously via tmux pane. Best for code review, security analysis, refactoring, architecture. Requires npm install -g @openai/codex. |
gemini_worker | Gemini CLI (tmux pane) | Full filesystem access in working_directory. Runs autonomously via tmux pane. Best for UI/design work, documentation, large-context tasks. Requires npm install -g @google/gemini-cli. |
Tmux CLI workers run in dedicated tmux panes with filesystem access. They are autonomous executors, not just analysts:
working_directory set to the project rootKey difference from Claude teammates:
| Task Type | Best Route | Why |
|---|---|---|
| Iterative multi-step work | Claude teammate | Needs tool-mediated iteration + team communication |
| Code review / security audit | CLI worker or specialist agent | Autonomous execution, good at structured analysis |
| Architecture analysis / planning | architect Claude agent | Strong analytical reasoning with codebase access |
| Refactoring (well-scoped) | CLI worker or executor agent | Autonomous execution, good at structured transforms |
| UI/frontend implementation | designer Claude agent | Design expertise, framework idioms |
| Large-scale documentation | writer Claude agent | Writing expertise + large context for consistency |
| Build/test iteration loops | Claude teammate | Needs Bash tool + iterative fix cycles |
| Tasks needing team coordination | Claude teammate | Needs SendMessage for status updates |
/team 3:executor "refactor auth module with security review"
Task decomposition:
#1 [codex_worker] Security review of current auth code -> output to .omc/research/auth-security.md
#2 [codex_worker] Refactor auth/login.ts and auth/session.ts (uses #1 findings)
#3 [claude_worker:designer] Redesign auth UI components (login form, session indicator)
#4 [claude_worker] Update auth tests + fix integration issues
#5 [gemini_worker] Final code review of all changesThe lead runs #1 (Codex security analysis), then #2 and #3 in parallel (Codex refactors backend, designer agent redesigns frontend), then #4 (Claude teammate handles test iteration), then #5 (Gemini final review).
For large ambiguous tasks, run analysis before team creation:
Task(subagent_type="oh-my-claudecode:planner", ...) with task description + codebase contextThis is especially useful when the task scope is unclear and benefits from external reasoning before committing to a specific decomposition.
The lead can proactively ingest outbox messages from CLI workers using the outbox reader utilities, enabling event-driven monitoring without relying solely on SendMessage delivery.
readNewOutboxMessages(teamName, workerName) -- Read new outbox messages for a single worker using a byte-offset cursor. Each call advances the cursor, so subsequent calls only return messages written since the last read. Mirrors the inbox cursor pattern from readNewInboxMessages().
readAllTeamOutboxMessages(teamName) -- Read new outbox messages from ALL workers in a team. Returns an array of { workerName, messages } entries, skipping workers with no new messages. Useful for batch polling in the monitor loop.
resetOutboxCursor(teamName, workerName) -- Reset the outbox cursor for a worker back to byte 0. Useful when re-reading historical messages after a lead restart or for debugging.
getTeamStatus() in the Monitor PhaseThe getTeamStatus(teamName, workingDirectory, heartbeatMaxAgeMs?) function provides a unified snapshot combining:
Example usage in the monitor loop:
const status = getTeamStatus('fix-ts-errors', workingDirectory);
for (const worker of status.workers) {
if (!worker.isAlive) {
// Worker is dead -- reassign its in-progress tasks
}
for (const msg of worker.recentMessages) {
if (msg.type === 'task_complete') {
// Mark task complete, unblock dependents
} else if (msg.type === 'task_failed') {
// Handle failure, possibly retry or reassign
} else if (msg.type === 'error') {
// Log error, check if worker needs intervention
}
}
}
if (status.taskSummary.pending === 0 && status.taskSummary.inProgress === 0) {
// All work done -- proceed to shutdown
}| Message Type | Action |
|---|---|
task_complete | Mark task completed, check if blocked tasks are now unblocked, notify dependent workers |
task_failed | Increment failure sidecar, decide retry vs reassign vs skip |
idle | Worker has no assigned tasks -- assign pending work or begin shutdown |
error | Log the error, check consecutiveErrors in heartbeat for quarantine threshold |
shutdown_ack | Worker acknowledged shutdown -- safe to remove from team |
heartbeat | Update liveness tracking (redundant with heartbeat files but useful for latency monitoring) |
This approach complements the existing SendMessage-based communication by providing a pull-based mechanism for MCP workers that cannot use Claude Code's team messaging tools.
SendMessage to lead reporting the failureTaskUpdate to set new owner, then SendMessage to the new ownerTaskList -- task stuck in in_progress for too longSendMessage to the teammate asking for statusTaskUpdateTaskUpdate with modified blockedBy)SendMessageconfig.json membersTask(team_name, name)When the user invokes /team ralph, says "team ralph", or combines both keywords, team mode wraps itself in Ralph's persistence loop. This provides:
Team+Ralph activates when:
/team ralph "task" or /oh-my-claudecode:team ralph "task"team and ralph in the promptMAGIC KEYWORD: RALPH alongside team contextBoth modes write their own state files with cross-references:
// Team state (via state_write)
state_write(mode="team", active=true, current_phase="team-plan", state={
"team_name": "build-rest-api",
"linked_ralph": true,
"task": "build a complete REST API"
})
// Ralph state (via state_write)
state_write(mode="ralph", active=true, iteration=1, max_iterations=10, current_phase="execution", state={
"linked_team": true,
"team_name": "build-rest-api"
})team-plan -> team-prd -> team-exec -> team-verifyteam-verify passes: Ralph runs architect verification (STANDARD tier minimum)/oh-my-claudecode:cancelteam-verify fails OR architect rejects: team enters team-fix, then loops back to team-exec -> team-verifymax_fix_loops: Ralph increments iteration and retries the full pipelinemax_iterations: terminal failed stateCancel either mode cancels both:
See Cancellation section below for details.
If the lead crashes mid-run, the team skill should detect existing state and resume:
~/.claude/teams/ for teams matching the task slugconfig.json to discover active membersTaskList to determine current progressThis prevents duplicate teams and allows graceful recovery from lead failures.
| Aspect | Team (Native) | Swarm (Legacy SQLite) |
|---|---|---|
| Storage | JSON files in ~/.claude/teams/ and ~/.claude/tasks/ | SQLite in .omc/state/swarm.db |
| Dependencies | better-sqlite3 not needed | Requires better-sqlite3 npm package |
| Task claiming | TaskUpdate(owner + in_progress) -- lead pre-assigns | SQLite IMMEDIATE transaction -- atomic |
| Race conditions | Possible if two agents claim same task (mitigate by pre-assigning) | None (SQLite transactions) |
| Communication | SendMessage (DM, broadcast, shutdown) | None (fire-and-forget agents) |
| Task dependencies | Built-in blocks / blockedBy arrays | Not supported |
| Heartbeat | Automatic idle notifications from Claude Code | Manual heartbeat table + polling |
| Shutdown | Graceful request/response protocol | Signal-based termination |
| Agent lifecycle | Auto-tracked via internal tasks + config members | Manual tracking via heartbeat table |
| Progress visibility | TaskList shows live status with owner | SQL queries on tasks table |
| Conflict prevention | Owner field (lead-assigned) | Lease-based claiming with timeout |
| Crash recovery | Lead detects via missing messages, reassigns | Auto-release after 5-min lease timeout |
| State cleanup | TeamDelete removes everything | Manual rm of SQLite database |
When to use Team over Swarm: Always prefer /team for new work. It uses Claude Code's built-in infrastructure, requires no external dependencies, supports inter-agent communication, and has task dependency management.
The /oh-my-claudecode:cancel skill handles team cleanup:
state_read(mode="team") to get team_name and linked_ralphshutdown_request to all active teammates (from config.json members)shutdown_response from each (15s timeout per member)TeamDelete to remove team and task directoriesstate_clear(mode="team")linked_ralph is true, also clear ralph: state_clear(mode="ralph")When team is linked to ralph, cancellation follows dependency order:
--force): Clears both team and ralph state unconditionally via state_clear.If teammates are unresponsive, TeamDelete may fail. In that case, the cancel skill should wait briefly and retry, or inform the user to manually clean up ~/.claude/teams/{team_name}/ and ~/.claude/tasks/{team_name}/.
When OMC_RUNTIME_V2=1 is set, the team runtime uses an event-driven architecture instead of the legacy done.json polling watchdog:
.omc/state/team/{teamName}/events.jsonl.omc/state/team/{teamName}/workers/{name}/status.jsonThe v2 runtime is feature-flagged and can be enabled per-session. The legacy v1 runtime remains the default.
When OMC_TEAM_SCALING_ENABLED=1 is set, the team supports mid-session scaling:
Optional settings via .omc-config.json:
{
"team": {
"maxAgents": 20,
"defaultAgentType": "executor",
"monitorIntervalMs": 30000,
"shutdownTimeoutMs": 15000
}
}executor)TaskList (default: 30s)Note: Team members do not have a hardcoded model default. Each teammate is a separate Claude Code session that inherits the user's configured model. Since teammates can spawn their own subagents, the session model acts as the orchestration layer while subagents can use any model tier.
On successful completion:
TeamDelete handles all Claude Code state:
~/.claude/teams/{team_name}/ (config)~/.claude/tasks/{team_name}/ (all task files + lock)state_clear(mode="team")state_clear(mode="ralph")/oh-my-claudecode:cancel which handles all cleanup automatically.IMPORTANT: Call TeamDelete only AFTER all teammates have been shut down. TeamDelete will fail if active members (besides the lead) still exist in the config.
MCP workers can operate in isolated git worktrees to prevent file conflicts between concurrent workers.
Worktree creation: Before spawning a worker, call createWorkerWorktree(teamName, workerName, repoRoot) to create an isolated worktree at .omc/worktrees/{team}/{worker} with branch omc-team/{teamName}/{workerName}.
Worker isolation: Pass the worktree path as the workingDirectory in the worker's BridgeConfig. The worker operates exclusively in its own worktree.
Merge coordination: After a worker completes its tasks, use checkMergeConflicts() to verify the branch can be cleanly merged, then mergeWorkerBranch() to merge with --no-ff for clear history.
Team cleanup: On team shutdown, call cleanupTeamWorktrees(teamName, repoRoot) to remove all worktrees and their branches.
| Function | Description |
|---|---|
createWorkerWorktree(teamName, workerName, repoRoot, baseBranch?) | Create isolated worktree |
removeWorkerWorktree(teamName, workerName, repoRoot) | Remove worktree and branch |
listTeamWorktrees(teamName, repoRoot) | List all team worktrees |
cleanupTeamWorktrees(teamName, repoRoot) | Remove all team worktrees |
checkMergeConflicts(workerBranch, baseBranch, repoRoot) | Non-destructive conflict check |
mergeWorkerBranch(workerBranch, baseBranch, repoRoot) | Merge worker branch (--no-ff) |
mergeAllWorkerBranches(teamName, repoRoot, baseBranch?) | Merge all completed workers |
createSession() in tmux-session.ts does NOT handle worktree creation — worktree lifecycle is managed separately via git-worktree.tssanitizeName() to prevent injectionInternal tasks pollute TaskList -- When a teammate is spawned, the system auto-creates an internal task with metadata._internal: true. These appear in TaskList output. Filter them when counting real task progress. The subject of an internal task is the teammate's name.
No atomic claiming -- Unlike SQLite swarm, there is no transactional guarantee on TaskUpdate. Two teammates could race to claim the same task. Mitigation: The lead should pre-assign owners via TaskUpdate(taskId, owner) before spawning teammates. Teammates should only work on tasks assigned to them.
Task IDs are strings -- IDs are auto-incrementing strings ("1", "2", "3"), not integers. Always pass string values to taskId fields.
TeamDelete requires empty team -- All teammates must be shut down before calling TeamDelete. The lead (the only remaining member) is excluded from this check.
Messages are auto-delivered -- Teammate messages arrive to the lead as new conversation turns. No polling or inbox-checking is needed for inbound messages. However, if the lead is mid-turn (processing), messages queue and deliver when the turn ends.
Teammate prompt stored in config -- The full prompt text is stored in config.json members array. Do not put secrets or sensitive data in teammate prompts.
Members auto-removed on shutdown -- After a teammate approves shutdown and terminates, it is automatically removed from config.json. Do not re-read config expecting to find shut-down teammates.
shutdown_response needs request_id -- The teammate must extract the request_id from the incoming shutdown request JSON and pass it back. The format is shutdown-{timestamp}@{worker-name}. Fabricating this ID will cause the shutdown to fail silently.
Team name must be a valid slug -- Use lowercase letters, numbers, and hyphens. Derive from the task description (e.g., "fix TypeScript errors" becomes "fix-ts-errors").
Broadcast is expensive -- Each broadcast sends a separate message to every teammate. Use message (DM) by default. Only broadcast for truly team-wide critical alerts.
CLI workers are one-shot, not persistent -- Tmux CLI workers have full filesystem access and CAN make code changes. However, they run as autonomous one-shot jobs -- they cannot use TaskList/TaskUpdate/SendMessage. The lead must manage their lifecycle: write prompt_file, spawn CLI worker, read output_file, mark task complete. They don't participate in team communication like Claude teammates do.
48ffaac
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.