Repository navigation
Description
Summary
Across 3 different takeover projects (TypeScript SEO pipeline, Hugo + Python content site, Django + React SaaS), each running wanman run --loops 3, all 9 loops were classified idle with reason "no state changes detected". ceo agent was actively running tools (Bash/Read/Skill) in every loop but never reached wanman task create / wanman initiative create. Hypothesized root cause: each loop spawns a fresh ceo subprocess with no memory of prior loops' exploration, so multi-loop budget cannot productively accumulate.
Reproduction
- Customize three takeover overlays (different agents.json rosters, project-specific skills + AGENT.md operating manuals)
- For each project:
cd <project>/.wanman && wanman run "<goal>" --loops 3 - Inspect
deliverables/loop-events.ndjsonandwanman.db
Observed evidence
Project A (TS stack) spawns: Counter({'ceo': 8}) classifications: 8× idle
Project B (Hugo+Py stack) spawns: Counter({'ceo': 3}) classifications: 3× idle
Project C (Django+React) spawns: Counter({'ceo': 3}) classifications: 3× idle
In each project:
wanman.dbended at 0 bytes (no rows in initiatives/tasks/capsules tables —sqlite3 wanman.db "SELECT * FROM initiatives"returnsError: no such table: initiatives)- Each ceo agent's
output/directory was never created (ceo wrote nothing) - Each loop ndjson event:
{"type":"loop.classified", "classification":"idle", "reasons":["no state changes detected"]}
Typical per-loop log pattern observed:
07:55:08 agent-process spawning agent (ceo)
07:55:13 agent-process tool_call (ceo, tool:Skill)
07:55:18 agent-process tool_call (ceo, tool:Read)
07:55:34 agent-process tool_call (ceo, tool:Bash)
... [several minutes of Read/Bash/Skill calls reading docs]
loop ends → next loop spawns FRESH ceo subprocess → repeats reading from zero
Why this looks structural, not just a prompt issue
Transparent caveat: my AGENT.md gave ceo a heavy startup sequence (read 5-8 canonical files + 2-3 skill files before acting). The first loop exhausting on exploration is plausibly a prompt issue.
But the structural concern: even with a shorter prompt, the nth loop still spawns a fresh ceo subprocess that has no memory of what loop n-1 read or concluded. So --loops N cannot help an exploration-then-act problem because each loop is independent. The only path to a productive run is for a single loop's session to fit the entire (read + plan + write) cycle in its time budget.
Verified the multi-loop assumption from ndjson: every loop emits an agent.spawned event for ceo, and every loop is independently classified.
Impact
- "Take a moment to deeply understand the project" is a natural ceo behavior on a fresh takeover, so this hits new users immediately
- 0%-productive runs leave
wanman.dbschema un-initialized → subsequentwanman task list/wanman initiative listerror with "no such table" - The supervisor sends
[local] Mission control: sent backlog-drained steer to ceoafter the first idle loop, but the steer cannot help if the next loop's new ceo has to start from zero anyway
Possible directions
- Persist ceo working memory across loops — write a per-agent scratchpad / session summary to
wanman.dbat end of each loop, prepend to next loop's prompt context - Single long-running ceo process that treats loop boundaries as logical checkpoints rather than process boundaries
- Pre-resolved project digest — at supervisor start, run a one-time "project digest" agent whose output is cached and prepended to every subsequent ceo loop (avoid every ceo re-reading the same source files)
- Documentation — if "fast-acting first loop" is the design intent, document the AGENT.md startup-sequence constraint explicitly so users don't author read-heavy prompts
Acceptance
- Across multi-loop runs on a fresh project, the second or third loop's ceo benefits from the first loop's exploration (no zero-restart)
- After 3 loops on a previously-fresh project, at least 1-3 initiatives or tasks exist (or supervisor explicitly explains why not in deliverables)
-
wanman.dbschema is initialized even on idle loops (avoid "no such table" errors when users inspect state mid-run)
Environment
- wanman: built from
chekusu/wanmanmain (lastpushed_at2026-04-25) - runtime:
claude(default) - Node 20+, pnpm 9+
- Single-host, local supervisor mode (no db9 brain attached)
Activity
jerryleooo commentedon Apr 28, 2026
Self-correction after reading the code
I owe a refinement to the original framing. After reading
packages/runtime/src/preamble.tsandagent-process.ts:252-257, I see wanman does propagate state across 24/7 respawns via the preamble system — I overstated the problem.What wanman actually does today
On every 24/7 respawn,
generatePreamble()injects a markdown block into the agent's prompt:So tasks and messages do survive respawn boundaries. My original claim "no cross-loop working memory" was too strong.
The precise gap
The preamble only surfaces already-externalized state (rows in
tasks, rows inmessages). It does not capture an agent's in-flight exploration:In our reproduction, ceo's loop 1 spent 4-5 minutes on
Read/Bash/Skillexploration but never reachedwanman task createorwanman send. So the preamble for loop 2 contained essentially nothing:Empty. Loop 2's ceo restarted exploration from zero. Loop 3 same. Compounded across 11 loops in the rebuilt-with-PR-#2 run, the result was still
11 loops, 0 productive (0%).Refined problem statement
Refined acceptance for the fix
wanman scratchpad setCLI or an automatic transcript-summary write at loop end)generatePreamble()includes scratchpad content alongside tasks/messagesThis is meaningfully smaller in scope than my original "needs cross-loop working memory" framing — the existing preamble plumbing covers most of the wiring. The missing piece is just one more state column (per-agent scratchpad) and a CLI/auto-mechanism to populate it.
Side note on PR #2 (idle_cached + Claude session resume)
For completeness: the merged
idle_cached+claude --resumepath solves a related-but-different problem (preserving Claude's conversation history across on-demand triggers). It does not apply to the 24/7 respawn path described above —agent-process.ts:430only readslastSessionIdwhenlifecycle === 'idle_cached'. So PR #2 is great for stateful on-demand roles ("support" agent that remembers the customer) but doesn't change ceo-style continuous loops.Confirmed by re-running the same 3 projects with a freshly rebuilt wanman after PR #2 merge: all loops still classified
idle, no productivity change. (Expected — different code path.)Apologies for the imprecise original wording.
guo-yu commentedon May 16, 2026
I re-checked this against current
main, and the refined version of the issue is confirmed by the code path.What I found:
packages/runtime/src/preamble.tsonly acceptstasks,recentMessages, loop metadata, and optionalsteerReason. There is no scratchpad/session-note input today.packages/runtime/src/agent-process.tsrespawns a fresh CLI subprocess every loop. It injects the generated preamble before the goal prompt, but does not pass a resumed Claude session id in this path.lastSessionId/resumeSessionIdis only used foridle_cachedtrigger runs, not for the 24/7 respawn loop. So your side note about PR feat(runtime): add idle_cached lifecycle + Claude session resume #2 not helping this specific case is accurate.scratchpadconcept in the runtime/core types or CLI commands.So the precise gap is not “no state at all across loops”; the existing preamble carries externalized state. The gap is that exploration state before the first DB/message write is invisible to later loops.
A good implementation shape would be:
runId + agentName.wanman scratchpad set/append) or an automatic end-of-run summary hook fed by the adapter event log.PreambleInput/generatePreamble()to include a concise### Scratchpadsection.I would keep this open as a valid runtime issue. It is smaller than the original framing but still important for read-heavy takeover prompts.