TORCH (Task Orchestration via Relay-Coordinated Handoff) is the name for the Nostr-based distributed task locking system used to coordinate multi-agent development. Adds docs/agents/TORCH.md covering: - Protocol overview with sequence diagram - NIP-78 event schema with tag breakdown - Ephemeral key lifecycle and why no secrets are needed - Race detection mechanism - Auto-expiration via NIP-40 - Configuration reference - Architecture diagram - Path toward a generalizable drop-in package for any repo Also references TORCH by name in AGENTS.md, scheduler-flow.md, nostr-lock.mjs header, and CLAUDE.md key documentation table. https://claude.ai/code/session_01BpDsVSAkVWtJLnfKxsB9ib
4.6 KiB
Scheduler Flow (Single Source of Truth)
Use this document for all scheduler runs. Task locking uses the TORCH protocol (see docs/agents/TORCH.md).
Scheduler Override (Top-Line Rule)
During scheduler execution, the scheduler-specific instructions in this document and the cadence prompt (daily-scheduler.md or weekly-scheduler.md) supersede generic AGENTS workflow details when they conflict.
Global rules that still apply
- Follow core safety and policy constraints (no harmful behavior, no secret exfiltration, no policy violations).
- Do not perform destructive or irreversible actions unless explicitly required by the scheduler task definition.
- Keep repository integrity checks (e.g., required lint/test commands in the scheduler flow) and leave an auditable log trail.
- Respect non-interactive execution constraints and do not pause for manual approvals.
Generic AGENTS workflow details intentionally ignored for scheduler runs
- The normal "one subsystem per PR" restriction, because scheduler operations are orchestration/meta-work that may touch scheduler logs, prompts, and coordination docs together.
- The standard task-claim sequence described for general agents when it conflicts with the stricter, numbered MUST sequence below.
- Generic start-of-task bookkeeping patterns not referenced by scheduler prompts (for example, creating extra context/todo artifacts) when they would add noise to automated scheduler runs.
Numbered MUST Procedure
-
MUST set cadence variables before any command:
cadence=dailyorweeklylog_dir=docs/agents/task-logs/<cadence>/branch_prefix=agents/<cadence>/prompt_dir=docs/agents/prompts/<cadence>/
-
MUST run the preflight check to build the exclusion set:
node scripts/agent/nostr-lock.mjs check --cadence <cadence>This queries Nostr relays for active lock events and returns JSON with
lockedandavailableagent lists. Use thelockedarray as the exclusion set. -
MUST read both policy files before selecting an agent:
cat AGENTS.md CLAUDE.md -
MUST run this command to identify the latest cadence log file, then choose the next roster agent not in the exclusion set:
ls -1 <log_dir> | sort | tail -n 1 -
MUST stop and write a
_failed.mdlog withAll roster tasks currently claimed by other agentswhen every roster agent is excluded. -
MUST claim the selected agent:
AGENT_PLATFORM=<jules|claude-code|codex> \ node scripts/agent/nostr-lock.mjs lock \ --agent <agent-name> \ --cadence <cadence>The script generates an ephemeral keypair, publishes a NIP-78 lock event to Nostr relays with NIP-40 auto-expiration (2 hours), and performs a built-in race check. No tokens or secrets needed.
- Exit code 0 = lock acquired, proceed to Step 7.
- Exit code 3 = race lost (another agent claimed first). Return to Step 2.
- Exit code 2 = relay error. Write a
_failed.mdlog with reasonNostr relay errorand stop.
-
MUST execute
<prompt_dir>/<prompt-file>end-to-end. -
MUST create exactly one final status file (
_completed.mdor_failed.md), runnpm run lint, then commit and push.
Canonical Example Run
# Step 1: Set cadence
cadence=daily
# Step 2: Preflight — check Nostr locks
$ node scripts/agent/nostr-lock.mjs check --cadence daily
{
"cadence": "daily",
"date": "2026-02-14",
"locked": ["audit-agent"],
"available": ["ci-health-agent", "const-refactor-agent", ...],
"lockCount": 1,
"locks": [...]
}
# Step 3: Read policies
$ cat AGENTS.md CLAUDE.md
...
# Step 4: Check logs, select next agent
$ ls -1 docs/agents/task-logs/daily/ | sort | tail -n 1
2026-02-13_18-40-00_load-test-agent_completed.md
Selected agent: nip-research-agent
# Step 6: Claim via Nostr lock
$ AGENT_PLATFORM=jules node scripts/agent/nostr-lock.mjs lock --agent nip-research-agent --cadence daily
Locking: agent=nip-research-agent, cadence=daily, date=2026-02-14
Step 1: Checking for existing locks...
Step 2: Generating ephemeral keypair...
Step 3: Building lock event...
Step 4: Publishing to relays...
Published to 3/3 relays
Step 5: Race check...
RACE CHECK: won
LOCK_STATUS=ok
LOCK_EVENT_ID=ea2724c76d2bd707...
LOCK_AGENT=nip-research-agent
LOCK_CADENCE=daily
LOCK_EXPIRES_ISO=2026-02-14T02:00:00.000Z
# Step 7: Execute agent prompt
(agent runs nip-research-agent prompt...)
# Step 8: Finalize
$ npm run lint
> lint passed
Wrote: docs/agents/task-logs/daily/2026-02-14_00-12-00_nip-research-agent_completed.md