Filigree is built for AI coding agents. This guide covers how foreground agents, background subagents, and multi-agent teams interact with filigree 3.0.0.
Foreground agents (Claude Code, Codex) use the MCP server directly — see the MCP Server Reference for the current live tool count and full read/write surface.
filigree install --claude-code # Set up MCP for Claude Code
filigree install --codex # Set up MCP for Codex via runtime autodiscoveryOnce installed, agents call MCP tools like work_ready, work_start, and issue_close natively. See MCP Server Reference for the full tool list.
Background subagents use the CLI with --json for structured output:
filigree --actor sub-agent-3 start-next-work --assignee sub-agent-3 --json
filigree --actor sub-agent-3 close <issue-id> --jsonThe --json flag returns machine-readable responses in the unified 3.0.0 envelopes (see "Response Shapes" below). The --actor flag sets the identity in the audit trail so you can track which agent performed each action.
The recommended pattern for agents working with filigree 3.0.0:
- Orient — read
filigree://contextresource for project state - Find work —
work_readyto find unblocked work sorted by priority - Start —
work_start(specific issue) orwork_start_next(highest-priority ready) atomically claims and transitions to the issue type's reachable working status in one step - Work — do the task,
comment_addto log progress - Close —
issue_closewhen done (response includes newly-unblocked items) - Repeat — loop back to step 2
The atomic primitives work_claim / work_claim_next still exist for niche use (reserve without transitioning), but work_start / work_start_next are the usual path in 3.0.0.
All MCP tools and CLI --json output use the unified 3.0.0 envelopes:
- Batch ops return
{succeeded: [...], failed: [{id, error, code}, ...], newly_unblocked?: [...]}.failedis always present (empty list if none);newly_unblockedis present only when non-empty (omitted when the op unblocked nothing). Passresponse_detail="full"(MCP) or--detail=full(CLI) to get full records back instead of slim summaries. - List ops return
{items: [...], has_more: bool, next_offset?: int}.has_moreis always present;next_offsetappears only when there is a next page. - Errors return
{error: str, code: ErrorCode, details?: dict}wherecodeis one of:VALIDATION,NOT_FOUND,CONFLICT,INVALID_TRANSITION,PERMISSION,NOT_INITIALIZED,IO,INVALID_API_URL,FILE_REGISTRY_DISPLACED,REGISTRY_UNAVAILABLE,LOOMWEAVE_REGISTRY_VERSION_MISMATCH,LOOMWEAVE_OUT_OF_SYNC,BRIEFING_BLOCKED,STOP_FAILED,SCHEMA_MISMATCH,INTERNAL. (LOOMWEAVE_OUT_OF_SYNCmeans the installed loomweave registry is present but out of sync; remediation isloomweave analyze.)
The issue ID is always exposed as issue_id (in MCP inputs, response payloads, and CLI JSON). Status is always status; "state" was retired as a user-facing word in 2.0 and stays retired in 3.0.0.
When the installed filigree is older than the project's database, the MCP server still launches in warm-but-degraded mode. Most tool calls return an ErrorResponse with code: SCHEMA_MISMATCH and upgrade guidance; mcp_status_get remains available as a safe read-only diagnostic. Surface that message to the user — do not retry. The fix is uv tool install --upgrade filigree (or whatever installed it).
When an agent resumes after downtime, it can catch up on what happened:
filigree changes --since 2026-02-14T10:00:00 --jsonVia MCP:
change_list(since="2026-02-14T10:00:00")
Returns all events since the timestamp — status changes, new issues, closed items, dependency changes. The agent can reconstruct what happened while it was offline and adjust its plan accordingly.
When multiple agents are active, work_start prevents double-work. It uses optimistic locking on assignee and atomically advances the status — both land or neither does. If another agent already claimed the issue, the operation fails with code: CONFLICT rather than silently overwriting.
# Agent 1 starts successfully
filigree --actor agent-1 start-next-work --assignee agent-1
# Returns: {"issue_id": "proj-a3f9b2e1c0", "title": "Fix auth bug", "status": "in_progress", ...}
# Agent 2 tries the same issue — fails
filigree --actor agent-2 start-work proj-a3f9b2e1c0 --assignee agent-2
# Returns: {"error": "...", "code": "CONFLICT", "details": {"current_assignee": "agent-1"}}
# Exit code 4Via MCP:
work_start(issue_id="...", assignee="agent-1") # Claim + transition atomically
work_start_next(assignee="agent-1", priority_max=1) # Highest-priority ready, with filters
work_claim(issue_id="...", assignee="agent-2") # Niche: reserve without transitioning
work_release(issue_id="...") # Clear assignee without changing status
work_release(issue_id="...", actor="agent-1", if_held=True) # Unassigned no-op; held-by-other returns CONFLICT
work_heartbeat(issue_id="...", actor="agent-1") # Refresh claim liveness
work_stale_list(stale_after_hours=48, expires_within_hours=2) # Find abandoned, expired, or soon-expiring claims
work_reclaim(issue_id="...", assignee="agent-2", expected_assignee="agent-1", reason="missed heartbeat")
Active claims carry claimed_at, last_heartbeat_at, and claim_expires_at
timestamps. Agents doing longer work should heartbeat periodically; coordinators
can inspect stale claims and reclaim only with an expected_assignee check so a
fresh holder is not overwritten.
work_start_next (and the underlying work_claim_next) selects the next issue by:
priorityascending (0 = critical first)created_atascending (oldest first within a priority tier)issue_idascending (deterministic tie-break)
Agents can specialise by claiming only certain types or priority ranges:
filigree --actor bug-fixer start-next-work --assignee bug-fixer --type=bug
filigree --actor critical-agent start-next-work --assignee critical-agent --priority-max=1Every mutation records an actor. The --actor flag (CLI) or actor parameter (MCP) sets who performed the action. The CLI flag works in either position — before the verb (group-level) or after it (per-verb); the post-verb value overrides the group-level one:
filigree --actor agent-alpha create "Fix auth" # before the verb
filigree close proj-a3f9b2e1c0 --actor agent-beta # after the verb (overrides group-level)Via MCP, every write tool accepts an actor parameter:
issue_create(title="Fix auth", actor="agent-alpha")
issue_close(issue_id="proj-a3f9b2e1c0", actor="agent-beta")
Event history is queryable per-issue or globally:
filigree events <issue-id> # Per-issue history
filigree changes --since 2026-02-14T10:00 # Global event streamFiligree generates a context.md file on every mutation, stored at .weft/filigree/context.md (legacy installs that have not yet migrated store it at .filigree/context.md). This file contains:
- Project vitals (prefix, enabled packs, issue counts)
- Ready work queue (unblocked, sorted by priority)
- Blocked issues with their blocker details
- Recent activity
Agents read this via the filigree://context MCP resource or summary_get tool at session start. Because it's pre-computed, there's no query overhead — the agent gets instant orientation.
Standardised since 2.0 (unchanged in 3.0.0) so automated callers can branch on retryability:
| Code | Meaning |
|---|---|
| 0 | success (including empty results) |
| 1 | operational error (PERMISSION, INVALID_TRANSITION, IO, NOT_FOUND, INVALID_API_URL, STOP_FAILED) |
| 2 | usage / validation error (VALIDATION) |
| 3 | not initialized / schema mismatch (NOT_INITIALIZED, SCHEMA_MISMATCH) |
| 4 | contention / conflict (CONFLICT) — safe to retry |
A typical multi-agent setup with filigree:
Team Lead (foreground, MCP)
├── Reads context.md at session start
├── Creates and prioritises issues
├── Monitors progress via stats_get
│
Worker Agent 1 (background, CLI --json)
├── start-next-work --assignee worker-1 --type=task
├── Works on claimed issue
├── close when done, start-next-work again
│
Worker Agent 2 (background, CLI --json)
├── start-next-work --assignee worker-2 --type=bug
├── Specialises in bug fixes
├── Uses add-comment to log investigation progress
Each agent uses a distinct --actor identity, starts work atomically, and the event stream provides full visibility into who did what and when.