Skip to main content

ADR-210: Background Agent Manifest for Session Recovery

Status

Accepted — 2026-02-18

Context

When Claude Code sessions approach their context limit, the system compacts prior messages to free space. Background agents launched via Task(run_in_background=true) survive compaction — their processes continue running and their output files remain on disk — but the context about them (agent IDs, target file paths, what they were asked to do) is lost.

This creates two failure modes:

  1. Duplicate work: The next session re-launches agents that are already running, wasting tokens and producing conflicting output files.
  2. Orphaned agents: Completed background agents go unnoticed because no one checks their output files.

Root Cause

Background agent launches are ephemeral conversation events. Once compacted, the only surviving reference is in system-reminder tags (which preserve agent IDs but not intent or output paths).

Observed Incident

2026-02-18: Three MoE judge agents (G.6.5) were launched in parallel. Session compacted before completion was logged. The next session had no record of their existence, requiring manual recovery by grepping session logs and checking output files.

Decision

Implement a PostToolUse:Task hook (background-agent-manifest.py) that intercepts every Task tool call and, when run_in_background=true, writes a structured JSONL manifest entry containing:

FieldSourcePurpose
timestampUTC ISO 8601When the agent was launched
agent_idtool_result parsingUnique agent identifier
subagent_typetool_input.subagent_typeAgent type (e.g., synthesis-writer)
descriptiontool_input.descriptionShort task description
prompt_previewFirst 200 chars of promptWhat the agent was asked to do
output_filetool_result parsingWhere to find agent output
session_idCLAUDE_SESSION_ID envWhich session launched it
cwdCLAUDE_PROJECT_DIR envWorking directory context
statusAlways "launched"Initial state

Manifest Locations

  1. Global manifest: ~/.coditect-data/agent-manifests/background-agents-YYYY-MM-DD.jsonl

    • One file per day, append-only
    • Survives across all sessions and projects
  2. Project manifest (best-effort): ~/.coditect-data/session-logs/projects/{project-id}/{machine-uuid}/.background-agents.jsonl

    • Project-scoped for targeted recovery
    • Uses existing project detection from scripts.core.paths.discover_project()

Recovery Workflow

A recovering session can:

# Check today's background agents
cat ~/.coditect-data/agent-manifests/background-agents-$(date -u +%Y-%m-%d).jsonl | python3 -m json.tool

# Check specific agent output
tail -20 /path/from/manifest/output_file

# Check project-level agents
cat ~/.coditect-data/session-logs/projects/PILOT/{machine}/.background-agents.jsonl

Consequences

Positive

  • Zero-cost recovery: Any session can discover agents launched by prior sessions without re-scanning conversation history
  • No workflow change: The hook is transparent — it fires automatically on every background Task call
  • Append-only safety: JSONL format means concurrent writers don't corrupt each other
  • Project-scoped: Project manifest enables targeted recovery within project context

Negative

  • Parse dependency: Agent ID and output file extraction relies on parsing tool_result string format, which could change across Claude Code versions
  • No completion tracking: The manifest records launches but not completions — a future hook could update status
  • Disk accumulation: JSONL files grow indefinitely (mitigated by daily rotation)

Operational Discipline (Complementary)

This hook is the automated enforcement. The complementary operational discipline is:

Always log agent IDs and target file paths to the session log immediately after launch, before doing anything else.

Even without the hook, this pattern ensures session log entries survive compaction and are grep-able by future sessions.

Alternatives Considered

  1. Session log-only approach: Rely on manual session log entries. Rejected: too easy to forget under time pressure, and the session log itself can compact.
  2. Database approach: Write to sessions.db. Rejected: over-engineered for append-only manifest data; JSONL is simpler and more portable.
  3. Environment variable approach: Set env vars with agent IDs. Rejected: doesn't survive process boundaries.

Implementation

  • Hook: hooks/background-agent-manifest.py
  • Registration: .claude/settings.local.json under H.P.005-HOOKS.PostToolUse with matcher Task
  • Dependencies: Python 3, stdlib only (json, pathlib, datetime)
  • ADR-155: Project-Scoped Session Logs (provides project detection)
  • ADR-173: Structured Inter-Session Message Schema (bus-based coordination)
  • Hook: hooks/background-agent-manifest.py
  • Track: H (Framework)