Date: 2026-05-27 Author: adhoc-swarm-research (read-only scoping pass, ~1–2h) Status: Proposal — no code changes made. Owner directive 15:29 today. Scope: What's actually been hurting us this week, what off-the-shelf tooling would buy us if we adopted it, and the smallest set of incremental fixes that would move the needle without rewriting the swarm.
These are the failure modes the bus, the handoffs, and the audit docs document — not speculative. Each is paired with the cheapest fix later in §3.
ci-backend-retarget filler hung 45h before finishing the rollout (referenced verbatim in the 11:52 valideerleeftijd bus line and in HANDOFF-2026-05-20). We killed 4+ stuck one-shots in this session alone (manager/orchestrator/worker shells left sitting on a dead JSONL stream).claude -p invoked via start-agent.sh/run-agent.sh has no wall-clock budget. When the model stalls (network blip, 429, "Not logged in", or a quiet stdin), the wrapper process sits forever; nothing reaps it.auditPic one-shots running concurrently in the same checkout collided on the working tree; we pivoted the manager to serial-mode for auditPic on the spot. The shared /Users/sarkout/projects/prive/<repo> working copy is mutated by git checkout, npm install, ./mvnw …, and Helm templating, none of which are concurrency-safe.git status blocking commits, intermittent test failures.bus.log and the inbox, but has no idempotency key on the work it's seen. A restart can re-execute "the latest unfinished-looking message."HTTP 429 + "Not logged in" from the CLI session expiring, with no agent able to refresh the credential. Documented in HANDOFF-2026-05-20 + bus lines around 5/25.kubectl get pods / git log -1 snapshot. Reports decay in seconds in a deploy-heavy loop, but the bus line stays.--context transip-k3s whenever it wants.owner-messages-watchdog.log.Pragmatic assessment: what would this buy us beyond bus.log + .swarm/inbox? Most agent frameworks are designed for LLM-internal multi-agent chat, not "supervise N long-running shell wrappers on a laptop+VPS." That changes the verdict for several of them.
| Tool | Verdict | Why |
|---|---|---|
| timeout (coreutils) wrapper | ✅ Adopt now | One-line fix for §1.1 ghosts. timeout 1800 claude -p … and we're done. Zero new deps. |
| launchd (already used for designqa plist) | ✅ Keep, extend | macOS-native, restarts on crash, logs to file. Use it for orchestrator/manager/watchdog instead of start-claude.sh nohup. We already have one plist (com.glorylabs.swarm.designqa.plist) — pattern is proven. |
| supervisord | ❌ Skip | Cross-platform but redundant with launchd on macOS; adds a Python dep and a config-file dialect. |
| systemd timers | ❌ N/A | Linux-only; the supervising machine is a Mac. (VPS uses systemd, but agents don't run there.) |
| just / make | ⚠️ Optional | Better ergonomics for the run-*.sh family, but not a supervisor. Defer. |
| Tool | Verdict | Why |
|---|---|---|
| Redis Streams | ⚠️ Maybe — Phase 2 | Persistent, append-only, has consumer groups + ack/retry semantics (which bus.log doesn't). Would solve §1.3 (idempotency via message-id ACKs) and §1.7 (cursors). We already run Redis locally per project. Cost: every agent needs a Redis client; bus.log greppability is lost (need a bus tail CLI). |
| NATS JetStream | ❌ Skip | Strictly more powerful than Redis Streams but adds an unfamiliar daemon. Redis is already on every dev box. |
| Temporal | ❌ Skip | Brilliant for durable workflows; massive overkill for "run claude -p with a 30-min budget." Adds a server, a worker SDK, and a learning curve for ~3 humans. |
| PostgreSQL LISTEN/NOTIFY | ❌ Skip | Same shape as Redis Streams without the consumer-group ergonomics. |
Bottom line: stay on bus.log until idempotency (§1.3) actually re-bites us. The grep-ability and "human can read it" property of a flat file is worth a lot.
| Tool | Verdict | Why |
|---|---|---|
| OpenAI Swarm (now archived; succeeded by Agents SDK) | ❌ Skip | Designed for handoffs between LLM agents in one process. We're orchestrating shell processes across machines and Claude sessions — different problem. |
| LangGraph | ❌ Skip | State-machine for a single Python process. Doesn't model "ephemeral one-shot subprocess with a 5h credit budget." Adopting it = rewriting the swarm in Python around a graph runtime; the orchestration we have is the graph. |
| CrewAI / AutoGen / LlamaIndex Workflows | ❌ Skip | Same shape as LangGraph: designed to coordinate LLM calls within an app, not to be a control plane for long-running CLI agents on different machines. They also assume OpenAI-shaped API access — re-plumbing them onto claude -p is non-trivial and brittle. |
| Claude Code's own Task / Agent tool | ✅ Already using | The Agent/TaskCreate tooling in this very session is a structured agent framework — and it has proper lifecycle + cancel + result capture, which bus.log doesn't. Worth leaning harder on Claude-Code Agents for short-lived research/audit tasks instead of spinning ad-hoc one-shots. |
Bottom line: the gap isn't "we need an agent framework." It's "we need a 30-line supervisor with timeouts and idempotency." Any framework large enough to be useful is also large enough to recreate the bugs we just fixed.
| Tool | Verdict | Why |
|---|---|---|
| Langfuse (self-hosted) | ⚠️ Worth a half-day spike | Would give us per-agent cost + latency + token traces with a real UI. Today we have zero visibility into "which agent burned the 44h budget." Self-hostable, free tier ample. Risk: requires routing claude calls through a proxy that Langfuse can capture — claude-code CLI doesn't natively emit OTLP. |
| Helicone | ⚠️ Same shape | Hosted; cheaper to start. Same proxy concern. |
| OpenTelemetry | ❌ Premature | We don't have a service mesh of agents — we have ~10 shell scripts. OTel for a shell-script fleet is a tarpit. |
| A tiny claude-usage.log aggregator | ✅ Adopt | We already have adhoc-claude-usage.log in .swarm/logs/. A 20-line awk summary + a daily cron post to the bus would catch §1.4 (budget stalls) without any new dep. |
git worktree add /tmp/swarm-<repo>-<ts> HEAD). The orchestrator/manager (persistent) stays on the primary checkout.run-agent.sh. Cleanup: git worktree prune daily. Disk: negligible (worktrees share .git).These are the high-leverage, low-blast-radius fixes. Roughly ordered by effort/value.
claude -p … invocations in timeout --signal=TERM --kill-after=30s 1800 … (30-min budget, configurable per-task).<agent> -> manager: TIMEOUT after 1800s — task <id> killed, requeue=manual..swarm/run-agent.sh. Highest ROI fix in this document.<repo>/.swarm-lock ({pid, agent_id, started_at, heartbeat_at}). Heartbeats every 60s.bus.jsonl with {ts, from, to, type, task_id, msg_id, in_reply_to, body}.task_id derived from a content hash of the task statement → automatic duplicate-dispatch detection (§3.6).bus.jsonl; humans still tail bus.log. Dual-write keeps the grep-ability we love.last_owner_msg_seen_ts next to owner-messages-watchdog.log. On rehydrate, refuses to ACK anything older than the last unread owner message.kubectl get pods, gh pr view, curl /actuator/health) and embed the snapshot in the task body. The worker compares against current state at start and aborts if the snapshot is stale > 5 min.snapshot.sh.task_id = sha1(repo + normalized_task_body) written into the inbox filename. run-agent.sh refuses to launch if task_id is already in .swarm/completed/ from the last 60 min.run-agent.sh. Highest ROI after §3.1.KUBECONFIG_CONTEXT == transip-k3s and the task wasn't explicitly tagged FINAL-PROMOTION, refuse and post NEED-HUMAN ladder-violation. One bash function in RECIPE.md-aligned helpers.claude -p 'echo ok' heartbeat. If it returns 429 / "Not logged in", it posts NEED-HUMAN credentials to the orchestrator immediately — no waiting for the next scheduled agent to fail silently.replay.sh that feeds it to a dry-run orchestrator and asserts no duplicate dispatches, no APPROVAL-NEEDED dropped, no crossed ACKs. Run before any change to MANAGER-PROMPT.md / ORCHESTRATOR-PROMPT.md.claude -p cleanly.Agent/TaskCreate tooling we already have is the right "framework" for short tasks.bus.log as the human-facing log (humans must keep being able to tail -F it).claude -p through a different SDK.# TIMEOUT: 3600 task-header override.End of proposal. No code touched. Recommended next step: a single PR implementing §3.1 + §3.7 (the two highest-ROI fixes), behind a SWARM_V2=1 env flag so we can A/B the rollout against the existing wrappers.
Reacties