Skill: athola/nm-conjure-agent-teams (version 1.0.2)

--- name: agent-teams description: Coordinate Claude Code Agent Teams through filesystem-based protocol. Use version: 1.9.5 triggers: - agent-teams - multi-agent - coordination - tmux - task-management - messaging metadata: {"openclaw": {"homepage": "https://github.com/athola/claude-night-market/tree/master/plugins/conjure", "emoji": "\ud83e\udd9e", "requires": {"config": ["night-market.delegation-core", "night-market.leyline:damage-control", "night-market.leyline:risk-classification"]}}} source: claude-night-market source_plugin: conjure --- > **Night Market Skill** — ported from [claude-night-market/conjure](https://github.com/athola/claude-night-market/tree/master/plugins/conjure). For the full experience with agents, hooks, and commands, install the Claude Code plugin. ## Table of Contents - [Overview](#overview) - [When to Use](#when-to-use) - [Prerequisites](#prerequisites) - [Protocol Architecture](#protocol-architecture) - [Quick Start](#quick-start) - [Coordination Workflow](#coordination-workflow) - [Module Reference](#module-reference) - [Integration with Conjure](#integration-with-conjure) - [Troubleshooting](#troubleshooting) - [Exit Criteria](#exit-criteria) # Agent Teams Coordination ## Overview Claude Code Agent Teams enables multiple Claude CLI processes to collaborate on shared work through a filesystem-based coordination protocol. Each teammate runs as an independent `claude` process in a tmux pane, communicating via JSON files guarded by `fcntl` locks. No database, no daemon, no network layer. This skill provides the patterns for orchestrating agent teams effectively. ## When To Use - Parallel implementation across multiple files or modules - Multi-agent code review (one agent reviews, another implements fixes) - Large refactoring requiring coordinated changes across subsystems - Tasks with natural parallelism that benefit from concurrent agents ## When NOT To Use - Single-file changes or small tasks (overhead exceeds benefit) - Tasks requiring tight sequential reasoning (agents coordinate loosely) - When `claude` CLI is not available or tmux is not installed ## Prerequisites ```bash # Verify Claude Code CLI claude --version # Verify tmux (required for split-pane mode) tmux -V # Enable experimental feature (set by spawner automatically) export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 ``` ## Protocol Architecture ``` ~/.claude/ teams/<team-name>/ config.json # Team metadata + member roster inboxes/ <agent-name>.json # Per-agent message queue .lock # fcntl exclusive lock tasks/<team-name>/ 1.json ... N.json # Auto-incrementing task files .lock # fcntl exclusive lock ``` **Design principles:** - **Filesystem is the database**: JSON files, atomic writes via `tempfile` + `os.replace` - **fcntl locking**: Prevents concurrent read/write corruption on inboxes and tasks - **Numbered tasks**: Auto-incrementing IDs with sequential file naming - **Loose coupling**: Agents poll their own inbox; no push notifications ## Quick Start ### 1. Create a Team ```bash # Programmatic team setup (via MCP or direct API) # Team config written to ~/.claude/teams/<team-name>/config.json ``` The team config contains: - `name`, `description`, `created_at` (ms timestamp) - `lead_agent_id`, `lead_session_id` - `members[]` — array of LeadMember and TeammateMember objects ### 2. Spawn Teammates Each teammate is a separate `claude` CLI process launched with identity flags: ```bash claude --agent-id "backend@my-team" \ --agent-name "backend" \ --team-name "my-team" \ --agent-color "#FF6B6B" \ --parent-session-id "$SESSION_ID" \ --agent-type "general-purpose" \ --model sonnet ``` See `modules/spawning-patterns.md` for tmux pane management and color assignment. ### 3. Create Tasks with Dependencies ```json { "id": "1", "subject": "Implement API endpoints", "description": "Create REST endpoints for user management", "status": "pending", "owner": null, "blocks": ["3"], "blocked_by": [], "metadata": {} } ``` See `modules/task-coordination.md` for state machine and dependency management. ### 4. Coordinate via Messages ```json { "from": "team-lead", "text": "API endpoints are ready for integration testing", "timestamp": "2026-02-07T22:00:00Z", "read": false, "summary": "API ready" } ``` See `modules/messaging-protocol.md` for message types and inbox operations. ## Coordination Workflow 1. **`agent-teams:team-created`** — Initialize team config and directories 2. **`agent-teams:teammates-spawned`** — Launch agents in tmux panes 3. **`agent-teams:tasks-assigned`** — Create tasks with dependencies, assign owners 4. **`agent-teams:coordination-active`** — Agents claim tasks, exchange messages, mark completion 5. **`agent-teams:team-shutdown`** — Graceful shutdown with approval protocol ## Crew Roles Each team member has a `role` that determines their capabilities and task compatibility. Five roles are defined: `implementer` (default), `researcher`, `tester`, `reviewer`, and `architect`. Roles constrain which risk tiers an agent can handle — see `modules/crew-roles.md` for the full capability matrix and role-risk compatibility table. ## Team Formation For mission-level team sizing, use the Team Formation rules from `references/team-formation.md`. This defines: - **Role definitions**: Coordinator (mission lead), Agents (task owners), Reviewer (adversarial challenger) - **Team sizing rules**: Simple (1), Moderate (2-4), Complex (5-7), Critical (5-10) - **Maximum team size**: 10 agents (coordination overhead limit) - **File ownership rules**: Prevent conflicts with clear ownership See `references/team-formation.md` for full team sizing guidance and example team formations. ## Health Monitoring Team members can be monitored for health via heartbeat messages and claim expiry. The lead polls team health every 60s with a 2-stage stall detection protocol (health_check probe + 30s wait). Stalled agents have their tasks released and are restarted or replaced following the "replace don't wait" doctrine. See `modules/health-monitoring.md` for the full protocol and state machine. ## Module Reference - **team-management.md**: Team lifecycle, config format, member management - **messaging-protocol.md**: Message types, inbox operations, locking patterns - **task-coordination.md**: Task CRUD, state machine, dependency cycle detection - **spawning-patterns.md**: tmux spawning, CLI flags, pane management - **crew-roles.md**: Role taxonomy, capability matrix, role-risk compatibility - **health-monitoring.md**: Heartbeat protocol, stall detection, automated recovery ## Integration with Conjure Agent Teams extends the conjure delegation model: | Conjure Pattern | Agent Teams Equivalent | |-----------------|----------------------| | `delegation-core:task-assessed` | `agent-teams:team-created` | | `delegation-core:handoff-planned` | `agent-teams:tasks-assigned` | | `delegation-core:results-integrated` | `agent-teams:team-shutdown` | | External LLM execution | Teammate agent execution | Use `Skill(conjure:delegation-core)` first to determine if the task benefits from multi-agent coordination vs. single-service delegation. ## Worktree Isolation Alternative (Claude Code 2.1.49+) For parallel agents that modify files, `isolation: worktree` provides a lightweight alternative to filesystem-based coordination. Each agent runs in its own temporary git worktree, eliminating the need for `fcntl` locking or inbox-based conflict avoidance on shared files. - **When to prefer worktrees over agent teams messaging**: Agents work on overlapping files but don't need mid-execution communication - **When to prefer agent teams messaging**: Agents need to coordinate discoveries or adjust plans based on each other's progress - **Combine both**: Use agent teams for coordination with `isolation: worktree` per teammate for filesystem safety ## Troubleshooting ### Common Issues **tmux not found** Install via package manager: `brew install tmux` / `apt install tmux` **Stale lock files** If an agent crashes mid-operation, lock files may persist. Remove `.lock` files manually from `~/.claude/teams/<team>/inboxes/` or `~/.claude/tasks/<team>/` **Orphaned tasks** Tasks claimed by a crashed agent stay `in_progress` indefinitely. Use `modules/health-monitoring.md` for heartbeat-based stall detection and automatic task release. The health monitoring protocol detects unresponsive agents within 60s + 30s probe window and releases their tasks for reassignment. **Message ordering** Filesystem timestamp resolution varies (HFS+ = 1s granularity). Use numbered filenames or UUID-sorted names to avoid collision on rapid message bursts. **Model errors on Bedrock/Vertex/Foundry (pre-2.1.39)** Teammate agents could use incorrect model identifiers on enterprise providers, causing 400 errors. Upgrade to Claude Code 2.1.39+ for correct model ID qualification across all providers. **Nested session guard (2.1.39+)** If `claude` refuses to launch within an existing session, ensure you're using tmux pane splitting (not subshell invocation). The guard is intentional — see `modules/spawning-patterns.md` for details. ## Exit Criteria - [ ] Team created with config and directories - [ ] Teammates spawned and registered in config - [ ] Tasks created with dependency graph (no cycles) - [ ] Agents coordinating via inbox messages - [ ] Graceful shutdown completed

path: modules/crew-roles.md
content: ---
name: crew-roles
description: Role taxonomy, capability matrix, and role-risk compatibility for agent team members
parent_skill: conjure:agent-teams
category: delegation-framework
estimated_tokens: 200
---

# Crew Roles

## Role Taxonomy

Each team member has a `role` that determines their capabilities and the types of tasks they can be assigned.

| Role | Tools | Focus | Use When |
|------|-------|-------|----------|
| `implementer` | All tools | Code implementation | Building features, fixing bugs |
| `researcher` | Read-only | Investigation, analysis | Codebase exploration, design research |
| `tester` | Read + test execution | Testing, validation | Writing tests, running test suites |
| `reviewer` | Read-only + comment | Code review, quality | Reviewing PRs, auditing code quality |
| `architect` | All tools | Planning, design | System design, architectural decisions |

**Default role**: `implementer` (backward compatible — members without an explicit role are treated as implementers).

## Capability Matrix

| Capability | implementer | researcher | tester | reviewer | architect |
|-----------|:-----------:|:----------:|:------:|:--------:|:---------:|
| Read files | Yes | Yes | Yes | Yes | Yes |
| Write files | Yes | No | No | No | Yes |
| Edit files | Yes | No | No | No | Yes |
| Run tests | Yes | No | Yes | No | Yes |
| Run builds | Yes | No | Yes | No | Yes |
| Git operations | Yes | No | No | No | Yes |
| Create tasks | Yes | No | No | Yes | Yes |
| Send messages | Yes | Yes | Yes | Yes | Yes |
| Plan mode | Optional | No | No | No | Required |

## Role-Risk Compatibility

Not all roles can handle all risk tiers. The lead validates compatibility before assigning tasks:

| Risk Tier | Allowed Roles | Additional Requirement |
|-----------|--------------|----------------------|
| **GREEN** | Any role | None |
| **YELLOW** | implementer, tester, architect | None |
| **RED** | implementer, architect | Lead oversight required |
| **CRITICAL** | architect only | Human approval required |

**Rationale:**
- GREEN tasks are safe for anyone, including researchers and reviewers
- YELLOW tasks need write access (implementer/architect) or test execution (tester)
- RED tasks need experienced agents with full tool access and active lead monitoring
- CRITICAL tasks need the most strategic role (architect) with human sign-off

## Role Assignment

### At Spawn Time

Roles are assigned when spawning teammates:

```bash
claude --agent-id "backend@my-team" \
       --agent-name "backend" \
       --agent-role "implementer" \
       --team-name "my-team" \
       ...
```

### Dynamic Role Change

Roles can be changed during execution via team config update:

```json
{
  "agent_id": "backend@my-team",
  "role": "reviewer"
}
```

Role changes take effect immediately. The lead should reassign any in-progress tasks that are incompatible with the new role.

## Role-Based Task Routing

When the lead assigns tasks, it should consider role compatibility:

```
For each pending task:
  1. Determine task risk tier (from metadata or classify)
  2. Filter available agents by role-risk compatibility
  3. Prefer agents whose role matches the task type:
     - Implementation tasks → implementer
     - Research/investigation → researcher
     - Test writing/validation → tester
     - Code review → reviewer
     - Architecture/planning → architect
  4. Assign to best-fit available agent
```


path: modules/health-monitoring.md
content: ---
name: health-monitoring
description: Agent health tracking, stall detection, and automated recovery via heartbeat monitoring and claim expiry
parent_skill: conjure:agent-teams
category: delegation-framework
estimated_tokens: 250
---

# Health Monitoring

## Member Health Fields

Each team member's config gains a `health` object for tracking operational status:

```json
{
  "agent_id": "backend@my-team",
  "name": "backend",
  "role": "implementer",
  "health": {
    "status": "healthy",
    "last_heartbeat": "2026-02-07T22:15:00Z",
    "last_task_update": "2026-02-07T22:14:30Z",
    "stall_count": 0,
    "replacement_count": 0
  }
}
```

Members without a `health` object operate as before (no health monitoring — backward compatible).

| Field | Type | Description |
|-------|------|-------------|
| `status` | string | `healthy`, `stalled`, `unresponsive`, `replaced` |
| `last_heartbeat` | ISO 8601 | Last heartbeat message timestamp |
| `last_task_update` | ISO 8601 | Last task status change by this agent |
| `stall_count` | integer | Number of times this agent has been marked stalled |
| `replacement_count` | integer | Number of times this agent has been replaced |

## Task Claim Fields

Tasks gain claim tracking fields in metadata:

```json
{
  "id": "5",
  "owner": "backend@my-team",
  "metadata": {
    "claimed_at": "2026-02-07T22:10:00Z",
    "claim_expiry_seconds": 300
  }
}
```

| Field | Default | RED | CRITICAL |
|-------|---------|-----|----------|
| `claim_expiry_seconds` | 300 (5 min) | 600 (10 min) | 900 (15 min) |

Higher-risk tasks get longer claim windows because they legitimately take more time and require more careful execution.

## Health Check Protocol

### Lead Polling Loop

The lead agent checks team health every 60 seconds:

```
Every 60s:
  For each member where status != "replaced":
    1. Check last_heartbeat age
    2. If age > claim_expiry_seconds:
       → Enter 2-stage stall detection
    3. If status == "stalled" and stall_duration > 60s:
       → Mark as "unresponsive"
       → Trigger recovery
```

### 2-Stage Stall Detection

Stage 1 prevents false positives from temporary delays:

```
Stage 1: Probe
  Send health_check message to agent's inbox
  Wait 30 seconds

Stage 2: Confirm
  Check if agent responded with heartbeat
  If yes: Reset stall timer, mark "healthy"
  If no:  Mark "stalled", increment stall_count
```

### Recovery Actions

When an agent is confirmed stalled or unresponsive:

```
stalled (stall_count == 1):
  → Release claimed tasks (set owner = null, status = "pending")
  → Send stall_alert broadcast to team
  → Attempt restart: kill tmux pane, respawn with same identity

stalled (stall_count >= 2):
  → Mark as "unresponsive"
  → Release all tasks
  → Follow leyline:damage-control/modules/agent-crash-recovery.md
  → "Replace don't wait" doctrine: spawn fresh agent

replaced:
  → Agent is permanently decommissioned
  → Inbox preserved for audit
  → All tasks reassigned to other agents
```

## Member Health States

State machine for member health:

```
           heartbeat received
healthy ◄──────────────────── stalled
  │                              │
  │ no heartbeat                 │ no response to
  │ (> claim_expiry)             │ health_check (30s)
  │                              │
  v                              v
stalled ──────────────────► unresponsive
                                 │
                                 │ replacement spawned
                                 │
                                 v
                              replaced
```

**Transitions:**
- `healthy → stalled`: No heartbeat within claim_expiry_seconds
- `stalled → healthy`: Agent responds to health_check
- `stalled → unresponsive`: Agent fails to respond within 30s of health_check
- `unresponsive → replaced`: After 2 failed recovery attempts, fresh agent spawned
- `replaced`: Terminal state — agent is decommissioned

## Heartbeat Protocol

Agents send periodic heartbeat messages to maintain healthy status:

```json
{
  "from": "backend",
  "type": "heartbeat",
  "text": "{\"task_id\": \"5\", \"progress_percent\": 60}",
  "timestamp": "2026-02-07T22:15:00Z"
}
```

Heartbeats are sent:
- Every 60 seconds during active work
- After each task status change
- In response to `health_check` messages from the lead

## Teammate Memory Management (2.1.63+)

Long-running teammates previously retained all messages
in AppState even after conversation compaction. This
caused unbounded memory growth in sustained team
sessions. Fixed in 2.1.63: teammate message state is
now properly compacted. Heavy progress message payloads
are stripped during compaction, further reducing memory
pressure in teams with frequent status updates.

## TeammateIdle / TaskCompleted Shutdown (2.1.69+)

`TeammateIdle` and `TaskCompleted` hooks now support
returning `{"continue": false, "stopReason": "..."}` to
stop the teammate, matching `Stop` hook behavior. This
enables graceful teammate shutdown from hook logic
without requiring the lead to send explicit kill
signals.

Use cases for team health:

- Stop a teammate that has been idle too long
  (via `TeammateIdle` hook)
- Stop a teammate after completing its final task
  (via `TaskCompleted` hook)
- Implement budget-based shutdown (stop after N tasks
  or N tokens consumed)

```json
{
  "continue": false,
  "stopReason": "Budget exhausted after 5 tasks"
}
```

## Background Agent Notification Fix (2.1.71+)

Background agent completion notifications previously
omitted the output file path. This made it difficult
for parent agents (including team leads) to recover
agent results after context compaction. Fixed in 2.1.71:
completion notifications now include the output file
path, enabling reliable result retrieval even after
the parent's context has been compacted.

## `--print` Team Agent Fix (2.1.71+)

`--print` mode previously hung indefinitely when team
agents were configured, because the exit loop waited
on long-lived `in_process_teammate` tasks that never
complete. Fixed in 2.1.71: the exit loop no longer
blocks on teammate tasks. This unblocks CI/automation
workflows that use `--print` with team configurations.

## Team Agent Model Inheritance (2.1.72+)

Team agents now inherit the leader's model. Previously,
team agents used their own default model regardless of
the leader's configuration. This ensures consistent
model behavior across the team and eliminates the need
to configure each team agent's model separately.

## Subagent Model Downgrade Fix (2.1.73+)

Subagents with `model: opus`/`sonnet`/`haiku` were
silently downgraded to older model versions on Bedrock,
Vertex, and Microsoft Foundry. For example, `model: opus`
could resolve to Opus 4.1 instead of Opus 4.6 on these
providers. Fixed in 2.1.73: model aliases now resolve to
the current version on all providers, matching first-party
API behavior.

The default Opus model on these providers also changed
from 4.1 to 4.6, so both explicit alias resolution and
default behavior are now correct.

## Agent Resume via SendMessage (2.1.77+)

The Agent tool no longer accepts a `resume` parameter.
Use `SendMessage({to: agentId})` to continue a stopped
agent. SendMessage now auto-resumes stopped agents in the
background instead of returning an error. This simplifies
the recovery workflow: stopped agents no longer require
re-spawning, and the lead agent can resume team members
directly via SendMessage.

## Background Bash 5GB Output Limit (2.1.77+)

Background bash tasks are now killed if output exceeds
5GB, preventing runaway processes from filling disk. This
protects against infinite logging loops, verbose builds,
or accidental `cat /dev/urandom` in background tasks
within agent team workflows.

## Teammate Pane Close Fix (2.1.77+)

Fixed teammate panes not closing when the leader exits.
Previously, tmux panes for team agents could persist
after the leader session terminated, requiring manual
cleanup.

## Background Agent Partial Results Preserved (2.1.76+)

Killing a background agent now preserves whatever partial
results it had generated up to the point of termination.
Results appear in the conversation context, allowing the
main agent or the user to build on partial work instead
of starting over. Combined with 2.1.71 background agent
notification output file paths, partial results are
recoverable after both interruption and compaction.

This improves team resilience: if a team member agent is
killed due to a stall or timeout, its partial work is
not lost. The lead agent can incorporate partial results
when reassigning the task.

## Agent Teams Footer Hint Fix (2.1.75+)

Fixed the footer hint in agent teams showing "down to
expand" instead of the correct "shift + down to expand".
Users were pressing the wrong key combination based on
the incorrect hint. The footer now correctly indicates
`shift + down-arrow` for expanding agent output panels.

## Background Bash Process Cleanup (2.1.73+)

Background bash processes spawned by subagents were not
cleaned up when the agent exited, causing orphaned
processes to accumulate in long sessions. Fixed in
2.1.73: agent exit now properly terminates child bash
processes. This is particularly relevant for agent team
workflows where many subagents spawn bash commands
during parallel execution.

## Integration with Damage Control

When recovery actions fail, escalate through `leyline:damage-control`:

- Agent crash → `leyline:damage-control/modules/agent-crash-recovery.md`
- Context overflow detected → `leyline:damage-control/modules/context-overflow.md`
- Task failures after replacement → `leyline:damage-control/modules/partial-failure-handling.md`


path: modules/messaging-protocol.md
content: ---
name: messaging-protocol
description: Message types, inbox operations, and fcntl-based concurrency control
parent_skill: conjure:agent-teams
category: delegation-framework
estimated_tokens: 200
---

# Messaging Protocol

## Inbox Structure

Each agent has a dedicated inbox file:

```
~/.claude/teams/<team>/inboxes/<agent-name>.json
```

Content is a JSON array of message objects. An empty inbox is `[]`.

## Message Format (InboxMessage)

```json
{
  "from": "team-lead",
  "text": "Implement the auth middleware next",
  "timestamp": "2026-02-07T22:00:00Z",
  "read": false,
  "summary": "Auth middleware task",
  "color": "#FF6B6B"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `from` | string | yes | Sender agent name |
| `type` | string | no | Message type: `"heartbeat"`, `"health_check"`, `"stall_alert"`, `"plan_approval"`, `"shutdown"`. Omit for plain direct messages. |
| `text` | string | yes | Message body (plain text or serialized JSON) |
| `timestamp` | string | yes | ISO 8601 timestamp |
| `read` | boolean | yes | Read-state flag (default: `false`) |
| `summary` | string | no | Short summary for quick scanning |
| `color` | string | no | Display color for UI |

## Message Types

### Direct Messages
Plain text or structured payloads sent to a specific agent's inbox.

```python
send_plain_message(team, to_agent, text, summary=None)
```

### Broadcast Messages
Sent to all team members' inboxes simultaneously.

```python
send_broadcast(team, from_agent, text, summary=None)
```

### Task Assignments
Structured notification when a task's `owner` field changes.

```python
send_task_assignment(team, to_agent, task)
```

### Shutdown Requests
Structured request with a unique ID for graceful agent termination.

```python
send_shutdown_request(team, to_agent, request_id)
```

### Heartbeat
Periodic health signal from agent to lead. Includes current task and progress.

```json
{
  "from": "backend",
  "type": "heartbeat",
  "text": "{\"task_id\": \"5\", \"progress_percent\": 60}",
  "timestamp": "2026-02-07T22:15:00Z",
  "summary": "heartbeat: T5 60%"
}
```

### Health Check
Request from lead to verify agent is responsive. Agent must respond with a heartbeat within 30s.

```json
{
  "from": "team-lead",
  "type": "health_check",
  "text": "{\"request_id\": \"hc-001\"}",
  "timestamp": "2026-02-07T22:16:00Z",
  "summary": "health check request"
}
```

### Stall Alert
Broadcast from lead when an agent is detected as stalled. Includes stalled agent identity and released tasks.

```json
{
  "from": "team-lead",
  "type": "stall_alert",
  "text": "{\"stalled_agent\": \"backend\", \"released_tasks\": [\"5\", \"6\"]}",
  "timestamp": "2026-02-07T22:17:00Z",
  "summary": "backend stalled, tasks 5,6 released"
}
```

### Plan Approvals
Response messages confirming or rejecting proposed plans.

```json
{
  "from": "team-lead",
  "type": "plan_approval",
  "text": "{\"task_id\": \"3\", \"approved\": true, \"notes\": \"Proceed with approach A\"}",
  "timestamp": "2026-02-07T22:20:00Z",
  "summary": "plan approved: T3"
}
```

```python
send_plan_approval(team, to_agent, task_id, approved, notes=None)
```

## fcntl File Locking

All inbox operations use exclusive file locks to prevent concurrent corruption:

```python
import fcntl

lock_path = inbox_dir / ".lock"
lock_path.touch()

with open(lock_path) as lock_fd:
    fcntl.flock(lock_fd, fcntl.LOCK_EX)   # Acquire exclusive lock
    try:
        # Read, modify, write inbox JSON
        messages = json.loads(inbox_path.read_text())
        messages.append(new_message)
        inbox_path.write_text(json.dumps(messages))
    finally:
        fcntl.flock(lock_fd, fcntl.LOCK_UN)  # Release lock
```

**Crash recovery**: If an agent dies while holding a lock, the OS releases the `fcntl` lock automatically. However, the inbox file may be in an inconsistent state if the write was interrupted. Wrap writes in the atomic pattern from `team-management.md`.

## Read Operations

`read_inbox(agent)` supports:
- `unread_only=True`: Filter to messages where `read == false`
- `mark_as_read=True`: Set `read = true` on returned messages within the lock

## Polling Pattern

Agents poll their inbox on a timer (no push mechanism). The MCP server implements `poll_inbox()` with a 30-second maximum wait, returning early when new messages arrive.


path: modules/spawning-patterns.md
content: ---
name: spawning-patterns
description: tmux-based agent spawning, CLI identity flags, and pane management
parent_skill: conjure:agent-teams
category: delegation-framework
estimated_tokens: 200
---

# Spawning Patterns

## Overview

Each teammate runs as an independent `claude` CLI process in a tmux split pane. The team lead spawns teammates via `tmux split-window`, passing identity flags so each agent knows its role within the team.

## Required Environment Variables

```bash
export CLAUDECODE=1
export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
```

These are set automatically by the spawner before launching each teammate.

### Nested Session Guard (Claude Code 2.1.39+)

Claude Code 2.1.39 added a guard that prevents launching `claude` inside another `claude` session. Agent teams are **unaffected** because:
- tmux `split-window` creates an independent shell environment
- The `CLAUDECODE=1` env var is set explicitly per pane, not inherited from a parent session
- The guard targets accidental recursive invocations, not intentional team spawning

If you encounter the guard unexpectedly, ensure you're using tmux or iTerm2 pane splitting (not subshell invocations like `claude -p "..." | ...` within an existing session).

## CLI Identity Flags

```bash
claude \
  --agent-id "backend@my-team" \
  --agent-name "backend" \
  --team-name "my-team" \
  --agent-color "#FF6B6B" \
  --agent-role "implementer" \
  --parent-session-id "$LEAD_SESSION_ID" \
  --agent-type "general-purpose" \
  --model sonnet
```

| Flag | Format | Description |
|------|--------|-------------|
| `--agent-id` | `<name>@<team>` | Unique agent identifier |
| `--agent-name` | string | Human-readable name |
| `--team-name` | string | Team this agent belongs to |
| `--agent-color` | hex color | Visual distinction in tmux |
| `--parent-session-id` | string | Links to lead agent's session |
| `--agent-type` | string | Role type (e.g., `general-purpose`) |
| `--agent-role` | string | Crew role: `implementer`, `researcher`, `tester`, `reviewer`, `architect` (default: `implementer`) |
| `--model` | string | Model selection: `sonnet`, `opus`, `haiku` (2.1.39+ correctly qualifies for Bedrock/Vertex/Foundry). **Always pass an explicit model name, never `inherit`** (see warning below) |
| `--plan-mode-required` | flag | Optional: enforce planning mode |

### Team Agent Model Bug (2.1.69+)

When spawning team agents via the `Agent` tool (not
tmux CLI), `inherit` is written as a literal string
into the team config instead of being resolved to the
lead's model. The spawned agent then fails with:

> There's an issue with the selected model (inherit).

**Workaround**: Always pass an explicit model name
(`sonnet`, `opus`, `haiku`) via `--model` when spawning
team agents. Never use `inherit` or omit the flag in
team contexts. This does not affect subagents (non-team
Agent tool calls), which resolve `inherit` correctly.

Tracked upstream: anthropics/claude-code#31069

### Subagent Model Downgrade Fix (2.1.73+)

Subagent `model: opus`/`sonnet`/`haiku` aliases were
silently downgraded to older versions on Bedrock,
Vertex, and Microsoft Foundry (e.g., Opus 4.1 instead
of 4.6). Fixed in 2.1.73: aliases now resolve to the
current version on all providers.

The default Opus model on Bedrock/Vertex/Foundry also
changed from 4.1 to 4.6 in this release.

### `--bare` Flag for Scripted Agents (2.1.81+)

Skips hooks, LSP, plugin sync, skill walks, auto-memory,
OAuth/keychain, CLAUDE.md, `.mcp.json`. Fastest startup
for CI/scripted use. Requires `ANTHROPIC_API_KEY` or
`apiKeyHelper` via `--settings`. Will become default for
`-p` in a future release.

### Agent `initialPrompt` Frontmatter (2.1.83+)

Agents can declare `initialPrompt` to auto-submit a
first turn on spawn without the parent providing an
initial message.

### Agent `effort`/`maxTurns`/`disallowedTools` (2.1.78+)

Plugin-shipped agents support effort level override,
turn limits, and tool restrictions in frontmatter.
Security: `hooks`, `mcpServers`, `permissionMode` NOT
supported for plugin agents.

### Worktree in Non-Git Repos Fix (2.1.85+)

Fixed `--worktree` exiting with error in non-git
repositories before the WorktreeCreate hook could run.

### Agent Tool `resume` Parameter Removed (2.1.77+)

The Agent tool no longer accepts a `resume` parameter.
Use `SendMessage({to: agentId})` to continue a previously
spawned agent. New Agent calls always start fresh and
need full task context. SendMessage now auto-resumes
stopped agents in the background (no error returned).

Update any spawning code that used `Agent(resume: true)`
or `Agent(resume: agentId)` to use SendMessage instead.

### Stale Worktree Cleanup Race Fix (2.1.77+)

Fixed a race condition where the 2.1.76 stale-worktree
cleanup could delete an agent worktree that was being
actively resumed from a previous crash. The cleanup now
checks whether the worktree is being recovered before
deleting it.

### `-n` / `--name` CLI Flag (2.1.76+)

Sets a display name for the session at startup:
`claude -n "refactor-auth"`. Name appears on the prompt
bar, session listings, Remote Control titles, and
transcript metadata. Combined with `/color` (2.1.75+),
provides complete session identification at launch
without needing `/rename` mid-session.

### `worktree.sparsePaths` Setting (2.1.76+)

For `claude --worktree` in large monorepos. Uses git
sparse-checkout (cone mode) to materialize only the
listed directories:

```json
{
  "worktree": {
    "sparsePaths": ["packages/my-app", "shared/utils"]
  }
}
```

Files outside `sparsePaths` are not checked out. Can
combine with `worktree.symlinkDirectories`. Reduces
checkout time and disk usage for parallel agent dispatch
in monorepos.

### Worktree Startup Performance (2.1.76+)

Two improvements for `claude --worktree`:

1. Reads `.git/refs/` and `.git/packed-refs` directly
   instead of shelling out to `git branch -r`
2. Skips redundant `git fetch` when the remote branch
   is already available locally

Reduces worktree creation latency, particularly on slow
networks where the 120s git timeout was a bottleneck.

### Stale Worktree Cleanup (2.1.76+)

Worktrees left behind after interrupted parallel runs
are now automatically cleaned up. Detects orphaned
worktrees whose associated session or agent is no longer
running. Prevents disk space accumulation from aborted
parallel agent runs.

### `--plugin-dir` Single Path (2.1.76+)

`--plugin-dir` now accepts only one path per flag. Use
repeated flags for multiple directories:
`claude --plugin-dir /a --plugin-dir /b`. Previously
accepted colon-separated paths.

### `/color` Command for Session Identification (2.1.75+)

The `/color` command sets a custom border color on the
prompt bar for the current session (e.g., `/color orange`,
`/color blue`). Does not persist across session resume.
Useful for visually distinguishing team agents in
different tmux panes or iTerm2 splits.

Can be invoked at session launch: `claude "/color yellow"`.
Slash command chaining is not supported, so combining
`/color` and `/rename` at startup requires a shell alias.

### Session Name on Prompt Bar (2.1.75+)

`/rename` now displays the session name on the prompt
bar and propagates it to the terminal title via OSC 0/2
escape sequences. Terminal emulators that support these
sequences show the name in tab/window titles. Combined
with `/color`, this gives each team agent a distinct
visual identity.

Related fix: `/resume` no longer loses session names
after resuming a forked or continued session.

### Full Model IDs in Agent Frontmatter (2.1.74+)

Agent `model:` fields now accept full model IDs (e.g.,
`claude-opus-4-6`, `claude-opus-4-5-20251101`) in
addition to aliases (`opus`, `sonnet`, `haiku`).
Previously, full IDs were silently ignored, falling
back to the default model. Agents now accept the same
values as `--model`: aliases, full IDs, and
provider-specific strings (Bedrock ARNs, Vertex names,
Foundry deployments).

## Agent ID Format

The agent-id follows the pattern `<name>@<team-name>`, creating a unique namespace:
- `backend@refactor-team`
- `frontend@refactor-team`
- `reviewer@code-review`

## tmux Pane Management

### Spawning

```bash
# Split current window horizontally, run claude in new pane
tmux split-window -h "CLAUDECODE=1 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 \
  claude --agent-id backend@my-team --agent-name backend ..."
```

The spawner captures the new pane ID from tmux and stores it in the team config's member entry (`tmux_pane_id` field).

### Color Assignment

Colors are assigned from a palette based on member index:
```
["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7", "#DDA0DD", "#98D8C8", "#F7DC6F"]
```

### Killing a Pane

```bash
tmux kill-pane -t <pane_id>
```

Used during force-kill and graceful shutdown after approval.

## iTerm2 Alternative

Agent Teams also supports iTerm2 with the `it2` CLI as an alternative to tmux. The coordination protocol (files, messages, tasks) is identical — only the terminal multiplexer differs.

## Agent Name Validation

- Must match `^[A-Za-z0-9_-]+$`
- Under 64 characters
- Cannot be `team-lead` (reserved for the lead agent)
- Must be unique within the team

## Spawning Sequence

1. Validate agent name (uniqueness, format)
2. Assign color from palette
3. Create `TeammateMember` with metadata (model, type, cwd)
4. Register member in team config (atomic write)
5. Create empty inbox file for the agent
6. Send initial prompt to agent's inbox via messaging protocol
7. Execute `tmux split-window` with full CLI flags
8. Capture and store `tmux_pane_id` in member config

## Graceful Shutdown Protocol

1. Lead sends `shutdown_request` message with unique
   request ID
2. Teammate receives request, finishes current work
3. Teammate sends `shutdown_response` approving the
   shutdown
4. Lead calls `process_shutdown_approved` to clean up
   pane and config

### Bulk Agent Kill (2.1.53+)

Pressing `ctrl+f` kills all background agents with a
single aggregate notification instead of one per agent.
The command queue is properly cleared on bulk kill.
This prevents notification storms when terminating N
agents simultaneously and ensures no orphaned commands
remain in the queue after termination.


path: modules/task-coordination.md
content: ---
name: task-coordination
description: Task CRUD, state machine, dependency graph, and cycle detection
parent_skill: conjure:agent-teams
category: delegation-framework
estimated_tokens: 200
---

# Task Coordination

## Task File Format

Tasks are numbered JSON files in `~/.claude/tasks/<team>/`:

```json
{
  "id": "1",
  "subject": "Implement user API",
  "description": "Create CRUD endpoints for user management",
  "status": "pending",
  "owner": null,
  "active_form": null,
  "blocks": ["3"],
  "blocked_by": [],
  "metadata": {
    "priority": "high",
    "estimated_hours": 2,
    "risk_tier": "GREEN"
  }
}
```

## Task State Machine

```
pending (0) --> in_progress (1) --> completed (2)
                                     |
                               [deleted] (removes file)
```

**Forward-only transitions**: Backward transitions (e.g., `completed` to `in_progress`) are prohibited. The numeric ordering enforces this: a task can only move to a higher-numbered state.

**Deleted**: Special status that unlinks the task file and removes all dependency references from other tasks.

## Dependency Management

### Fields

- `blocks`: List of task IDs that this task prevents from starting
- `blocked_by`: List of task IDs that must complete before this task can start

### Bidirectional Synchronization

When adding a dependency edge, both sides update automatically:
- Adding task `1` to task `3`'s `blocked_by` also adds `3` to task `1`'s `blocks`
- Removing a dependency cleans both directions

### Blocked Task Validation

A task cannot transition to `in_progress` while its `blocked_by` list contains any non-completed tasks. The update operation checks this constraint before allowing state changes.

## Cycle Detection (BFS)

Before adding a dependency edge, the system runs breadth-first search through the existing dependency graph to prevent circular dependencies:

```python
def _would_create_cycle(tasks: dict, from_id: str, to_id: str) -> bool:
    """BFS from to_id through 'blocks' edges. Cycle if we reach from_id."""
    visited = set()
    queue = [to_id]
    while queue:
        current = queue.pop(0)
        if current == from_id:
            return True  # Cycle detected
        if current in visited:
            continue
        visited.add(current)
        queue.extend(tasks[current].get("blocks", []))
    return False
```

The check examines both on-disk state and pending in-memory changes before allowing new edges.

## CRUD Operations

### Create
```python
task = create_task(team, subject, description, owner=None, blocks=[], metadata={})
# Auto-increments ID, writes <id>.json, returns created task
```

### Read
```python
task = get_task(team, task_id)       # Single task
tasks = list_tasks(team)             # All tasks
```

### Update
Three-phase operation within file lock:
1. **Read**: Load current task state from disk
2. **Validate**: Check state transition rules, dependency constraints
3. **Mutate**: Apply changes, flush related tasks atomically

When `owner` changes, the system auto-sends a task assignment message to the new assignee's inbox.

### Delete
Setting `status: "deleted"` triggers:
1. Remove all `blocks`/`blocked_by` references from other tasks
2. Unlink the task JSON file from disk

## Risk-Aware Task Assignment

When `leyline:risk-classification` is available, the lead validates risk tier before assigning tasks:

1. **Read `risk_tier`** from task metadata (default: `"GREEN"` if absent)
2. **Validate assignment**: Check that the assigned agent's role is compatible with the tier (see `conjure:agent-teams/modules/crew-roles.md`)
3. **Apply parallel constraints**: Respect the risk-tier parallel safety matrix — no RED+RED, never parallel CRITICAL
4. **Set verification gates**: Task completion requires passing the tier-appropriate verification gates from `leyline:risk-classification/modules/verification-gates.md`

## Concurrency Safety

All task operations use `fcntl` exclusive locks on `~/.claude/tasks/<team>/.lock` to prevent concurrent modification. The lock is held for the entire read-validate-mutate cycle.


path: modules/team-management.md
content: ---
name: team-management
description: Team lifecycle, config format, member management, and atomic persistence patterns
parent_skill: conjure:agent-teams
category: delegation-framework
estimated_tokens: 200
---

# Team Management

## Directory Structure

```
~/.claude/teams/<team-name>/
  config.json        # Team metadata + member roster
  inboxes/           # Per-agent message queues
    .lock            # Shared lock file
~/.claude/tasks/<team-name>/
  .lock              # Task directory lock
```

## Team Config Schema

```json
{
  "name": "my-team",
  "description": "Backend refactoring team",
  "created_at": 1738972800000,
  "lead_agent_id": "team-lead@my-team",
  "lead_session_id": "sess_abc123",
  "members": [
    {
      "agent_id": "team-lead@my-team",
      "name": "team-lead",
      "agent_type": "lead",
      "model": "sonnet",
      "joined_at": 1738972800000,
      "tmux_pane_id": "%0",
      "cwd": "/home/user/project"
    },
    {
      "agent_id": "backend@my-team",
      "name": "backend",
      "agent_type": "general-purpose",
      "role": "implementer",
      "model": "sonnet",
      "joined_at": 1738972801000,
      "tmux_pane_id": "%1",
      "cwd": "/home/user/project",
      "health": {
        "status": "healthy",
        "last_heartbeat": "2026-02-07T22:00:01Z",
        "last_task_update": null,
        "stall_count": 0,
        "replacement_count": 0
      }
    }
  ]
}
```

## Team Name Validation

Names must match `^[A-Za-z0-9_-]+$` and be under 64 characters. This ensures filesystem-safe directory names across platforms.

Invalid: `my team`, `team/name`, `team.v2`
Valid: `my-team`, `backend_v2`, `refactor-2026`

## Member Management

**Adding**: Validate name uniqueness within the team, append to `members[]`, persist config.

**Removing**: Filter out target member by name. The `team-lead` member cannot be removed. Write updated config atomically.

## Atomic Write Pattern

Config persistence uses a two-phase atomic write to prevent partial reads from concurrent agents:

1. Create temporary file via `mkstemp()` in the same directory
2. Write full JSON content to temp file
3. `os.replace(temp_path, config_path)` — atomic on POSIX systems

This guarantees that any agent reading `config.json` sees either the old or new version, never a partial write.

## Team Lifecycle

1. **Create**: Initialize directories, write initial config with lead member
2. **Grow**: Spawn teammates, register in config via atomic write
3. **Operate**: Agents coordinate through tasks and messages
4. **Shrink**: Remove completed teammates, clean up their inboxes
5. **Delete**: Requires all non-lead members removed first; purges both `teams/` and `tasks/` directories

## Member Health States

Members with a `health` object follow a state machine for health tracking:

```
healthy → stalled → unresponsive → replaced
  ▲          │
  └──────────┘ (recovery succeeds)
```

- **healthy**: Agent is responsive, heartbeat within claim expiry
- **stalled**: No heartbeat received within claim_expiry_seconds, health_check sent
- **unresponsive**: Failed to respond to health_check within 30s
- **replaced**: Agent decommissioned, fresh agent spawned with new identity

Members without a `health` object work as before (no health monitoring). See `modules/health-monitoring.md` for full protocol. The `role` field (default: `"implementer"`) determines the agent's capability set — see `modules/crew-roles.md`.

## Single Team Per Session

Each MCP server session manages exactly one team. This simplifies state management and prevents cross-team interference.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)