feat(hooks)!: simplify dream system — capture + directive + background Dream agent#248
Conversation
- dream-lock: replace BSD-only `stat -f %m` with portable get_mtime, falling back to treating an existing lock as maximally stale (not a hard crash) when get_mtime isn't sourced yet by the caller. - hooks.ts: add optional `matcher` field to HookMatcher (PostToolUse hook registration support for a later AskUserQuestion capture hook). - json-helper.cjs: make merge-observation self-locking on .devflow/dream/.observations.lock, mirroring assign-anchor's internal locking on .decisions.lock. Removes the caller lock-dance requirement. Part of the dream system simplification (Phase 0 of 2-coder sequence).
New hooks (dual-append to memory + dream queues, independently gated):
- queue-append: shared JSONL-append helper (umask-077 creation, 200->100
overflow truncation under lock, one-fork combined memory+decisions
config read via queue_read_gates).
- capture-prompt (UserPromptSubmit): dual-append user turn, modeled on
dream-dispatch which stays untouched.
- capture-turn (Stop): dual-append assistant turn + decisions usage
scanner (D29 grep-first), modeled on dream-capture which stays
untouched. Never spawns a process.
- capture-question (PostToolUse, AskUserQuestion): one {role:"qa"} row
per question, Q/A independently truncated at 1000 chars. Payload
shape pinned against a real scratch-project PostToolUse probe plus
mined transcript samples (multi-question success + a real
InputValidationError case) — see the handoff doc for specifics.
- memory-worker (Stop): 120s-throttle + nohup-spawn block lifted
verbatim from dream-capture, registered after capture-turn so
append-before-spawn ordering holds by array position.
Modified (additive):
- background-memory-update: qa rows now emit a "Q&A:" stanza into
TURNS_TEXT and count as content-bearing in the orphan-only guard
(renamed _HAS_ASSISTANT -> _HAS_CONTENT); added a DEVFLOW_BG_DREAM
re-entrancy guard.
- session-start-memory: added DEVFLOW_BG_UPDATER/DEVFLOW_BG_DREAM
re-entrancy guards (latent pre-existing gap); added a cold-path
recovery for orphaned .pending-turns.processing (mirrors
dream-recover's logic, duplicated rather than sourced since
dream-recover is slated for removal in the follow-up cutover).
Part of the dream system simplification (Phase 1 of 2-coder sequence).
…ation New: - dream-procedure.md: combined decisions-detection + curation procedure, read directly by the dream worker's claude -p session (not a skill -- skills do not load in claude -p). Carries over the abstain-by-default bar, NOT-a-decision/NOT-a-pitfall lists, ADR-XOR-PF rule, dedup-first discipline, and curation bounds (<=5 changes, 7-day protection window) from shared/skills/dream-decisions + dream-curation, adapted for self-locking ops and worker-owned lifecycle (no marker claim/heartbeat/merge ceremony). Ends with rotate-observations then touch .last-dream-ok; writes last-run-summary only when the ledger changed. - background-dream-update: detached worker skeleton adapted from background-memory-update — mkdir lock on .worker.lock (900s stale, fail-fast ~2s acquire, unlike the memory worker's 90s wait), dual- signal decisions re-check, leftover .processing merge + rename-claim, model resolved from project then global decisions.json (default opus), claude -p with a short path-pointing prompt (the agent reads the claimed queue snapshot itself -- no raw content ever appears in the prompt or argv), 600s watchdog, and a strictly-newer-than- pre-spawn-baseline .last-dream-ok stamp as the success gate. - spawn-dream-worker (SessionStart): re-entrancy guards, dual-signal decisions gate, (queue non-empty OR leftover .processing) check with no jq parse, claude-on-PATH check, nohup spawn. No stdout directive. Modified (additive only): - session-start-context: added DEVFLOW_BG_DREAM/DEVFLOW_BG_UPDATER re-entrancy guards; added AC-F15 last-run-summary injection next to the decisions TL;DR (deletes the file after injecting). Section 2 (old pending-work directive flow) is untouched -- its removal is coupled to retiring dream-collect-tasks/dream-recover in a later cutover. - pre-compact-memory: added the same re-entrancy guards (latent pre-existing gap). Part of the dream system simplification (Phase 2 of 2-coder sequence).
New dedicated test files: - tests/queue-append.test.ts: queue_append_row/queue_append_both/ queue_read_gates -- 0600 creation, escaping fuzz (quotes, newlines, command substitution, unicode), 200->100 overflow under lock, degraded no-jq path, 20-parallel-append interleave, truncate-vs- append race (asserts no corruption, not zero data loss -- an accepted-class race shared with the pre-existing memory design). - tests/capture-hooks.test.ts: capture-prompt, capture-turn (incl. AC-F5 never-spawns), capture-question (real mined multi-question + errored AskUserQuestion fixtures), memory-worker, spawn-dream-worker. - tests/background-dream-update.test.ts: DW1 happy path (real json-helper.cjs ops), DW3 prompt path-pointing, DW4 malformed rows tolerated, DW5 leftover-.processing merge, DW6 watchdog/invariant/ stamp-not-advanced, DW7 lock fail-fast/stale-evict, DW8 CLI contract (no skip-permissions, DEVFLOW_BG_DREAM=1, no hostile argv/stdin), and AC-C3 dream-procedure.md contract pinning. Additive-only changes to existing files: - tests/sentinel.test.ts: new DEVFLOW_BG_UPDATER/DEVFLOW_BG_DREAM guard cases for session-start-context, session-start-memory, and pre-compact-memory (existing guard describes untouched). - tests/eager-memory-refresh.test.ts: S18 (qa rows in background-memory-update -- orphan gate + TURNS_TEXT agreement) and S19 (session-start-memory cold-path .pending-turns.processing recovery). - tests/learning/merge-observation.test.ts: AC-C4 self-locking concurrency test (15 parallel invocations, no corruption, CLI signature unchanged). - tests/shell-hooks.test.ts: HOOK_SCRIPTS bash -n entries for the 7 new scripts. 1913 tests passing (1794 baseline + 119 new), 0 new failures.
…m worker
Replaces the marker-pipeline decisions/curation flow (SessionEnd eval-* modules
writing per-session .json markers, consumed by a SessionStart Dream subagent via
session-start-context's directive-emission + dream-collect-tasks/dream-recover)
with a hook-spawned detached `claude -p` worker that reads scripts/hooks/dream-procedure.md
directly. Queue-append is unified across memory and dream into a shared
capture-prompt/capture-turn/capture-question bundle (capture.ts), independent of
the Stop-hook throttle/spawn logic (now memory-worker, for memory) and the
SessionStart spawn gate (now spawn-dream-worker + dream.ts, for decisions).
Deletions: scripts/hooks/{dream-capture,dream-dispatch,dream-evaluate,eval-helpers,
eval-decisions,eval-curation,dream-collect-tasks,dream-recover,lib/transcript-filter.cjs,
lib/dream-ops.cjs}, shared/agents/dream.md, shared/skills/{dream-decisions,dream-curation}/,
json-helper.cjs's read-dream dispatch, session-start-context's Section 2 (DREAM
MAINTENANCE directive).
TS/CLI: new capture.ts (capture-prompt/capture-turn/capture-question, always-on)
and dream.ts (spawn-dream-worker, always-on); memory.ts rebased to a 3-hook bundle
(Stop/SessionStart/PreCompact) with dream-dispatch/dream-capture/dream-evaluate
added to the legacy sweep; init.ts wires the capture+dream bundles unconditionally
in the order required for Stop=[capture-turn, memory-worker] and
SessionStart=[session-start-memory, session-start-context, spawn-dream-worker];
uninstall.ts strips the new bundles; decisions-config.ts drops max_daily_runs/
throttle_minutes (the new worker has no daily cap — it's gated by queue
non-emptiness) and defaults model to opus; decisions.ts's --clear/--reset now
resolve the git root explicitly (fixes a subdirectory-cwd bug) and skip a project
entirely while .devflow/dream/.worker.lock is held; project-paths.ts adds the new
dream queue/stamp/lock path helpers; plugins.ts removes the dream agent and
dream-decisions/dream-curation skills from core-skills/ambient with LEGACY array
entries for upgrade cleanup.
BREAKING CHANGES: SessionEnd hook removed entirely. Marker files
(decisions.*.json/curation.*.json and their .processing/.retries/.failed
variants) are no longer read or written — a migration sweeps legacy state
separately. DecisionsConfig.max_daily_runs/throttle_minutes dropped (silently
ignored if present in on-disk config). Decisions model default changed from
sonnet to opus. The dream agent and its 2 per-task skills are removed.
Co-Authored-By: Claude <noreply@anthropic.com>
…am-marker-pipeline-v1) Adds a per-project migration that removes decisions.*/curation.* markers (.json/.processing/.retries/.failed) and the legacy stamp files (.decisions-runs-today, .curation-last, .processor-spawned-at) left behind by the retired SessionEnd eval-*/dream-collect-tasks/dream-recover marker pipeline. ENOENT-idempotent; non-ENOENT errors are rethrown so a real failure surfaces to the migration runner instead of being silently swallowed. Never touches config.json (shared multi-feature config), the new .pending-turns.jsonl/.pending-turns.processing queue, .last-dream-ok, or .worker.lock — all owned by the new detached background-dream-update worker. .decisions-runs-today historically lived at .devflow/dream/.decisions-runs-today (written by the now-deleted eval-decisions module via $DREAM_DIR), not under .devflow/decisions/ despite the similar name — swept from its real location. Co-Authored-By: Claude <noreply@anthropic.com>
Rewrites CLAUDE.md's Working Memory and Decisions pipeline sections, the hooks tree, runtime-file listings, and Model Strategy paragraph to describe only the new architecture (capture-prompt/capture-turn/capture-question, memory-worker + background-memory-update, spawn-dream-worker + background-dream-update reading dream-procedure.md) — no before/after narration. Updates skill/agent counts (40 skills, 15 agents) in CLAUDE.md, README.md, and docs/reference/file-organization.md. Rewrites file-organization.md's hooks tree and Dream Hooks section, and working-memory.md's hook table and file structure notes, to match. Updates cli-reference.md's `decisions --configure` description to the slimmed model/debug/scope prompt set. Co-Authored-By: Claude <noreply@anthropic.com>
…stem
The phased dream-system-simplification work (phases 0-2 + cutover) left
several comments pointing at scripts deleted by the cutover commit itself,
or at the pre-cutover owner of behavior that moved during the same branch:
- capture-prompt/capture-turn claimed dream-dispatch/dream-capture "stays
in place, unmodified" — both were deleted by the cutover commit.
- memory-worker/queue-append cited dream-capture/dream-evaluate as design
precedent for logic that now lives only in the new scripts.
- background-memory-update's header said it's spawned by dream-capture
(now memory-worker) and pointed crash-recovery/throttle attribution at
dream-recover/dream-capture (both deleted; the behavior now lives in
session-start-memory and memory-worker respectively).
- session-start-memory described its inline cold-path recovery as
"mirroring dream-recover... scheduled for removal" — dream-recover was
already removed earlier in this same branch.
- background-dream-update's model-resolution comment said its opus
fallback was "intentionally DIFFERENT" from DecisionsConfig's TS-side
default ("sonnet") — that TS default was changed to opus in this same
branch, so the two are now intentionally in sync, not different.
- CLAUDE.md's Working Memory paragraph attributed queue-overflow
truncation to memory-worker, which never touches the queue; that's
queue-append's job (used by capture-prompt/capture-turn).
- memory.ts's MEMORY_HOOK_CONFIG doc trimmed a "formerly X/Y" parenthetical
that just listed retired hook names with no forward value.
All changes are comment/doc-only — no behavior, log output, or test
contract changed. Full suite verified green after the edits (1861/1861).
- background-dream-update: cd to PROJECT_ROOT before spawning the claude agent so dream-procedure.md's project-root-relative paths (.devflow/...) and $(pwd) calls (staleness.cjs, render-decisions.cjs, count-active) resolve correctly. The worker can be spawned with a CWD deep inside the project (resolve-project-root docs this), so process cwd was not guaranteed to equal the project root — decisions could render into a stray nested .devflow/ or the wrong location. - dream-procedure.md: count-active was called with the worktree arg missing (count-active "decision"), so json-helper treated "decision" as the worktree path and always returned 0. Use the canonical count-active "$(pwd)" <type> form, matching the adjacent staleness.cjs and render-decisions.cjs invocations.
… self-guard Three review findings on feat/simplify-dream-system: - AC-F15: add behavioral tests for session-start-context's dream last-run-summary inject-once-then-delete (seeded file injected under DREAM LAST RUN header then removed; no file -> no header; DEVFLOW_BG_DREAM=1 -> guard exits before the file is ever touched). No hook change needed — the re-entrancy guards already precede all filesystem writes/deletes. - settings.json template seeds Stop->capture-turn but was missing UserPromptSubmit->capture-prompt and PostToolUse(matcher AskUserQuestion)->capture-question. init's addCaptureHooks heals this at runtime, but the seed file now matches the AC-C2 end-state shape exactly. Pinned with a new test suite reading the shipped template. - background-memory-update guarded DEVFLOW_BG_DREAM but not DEVFLOW_BG_UPDATER at its top (background-dream-update already guards both). Added the matching self-guard, belt-and-suspenders since the spawn site already guards, plus behavioral tests confirming both guards fire before the queue is claimed or any log file is written. Co-Authored-By: Claude <noreply@anthropic.com>
…ics) devflow decisions --disable now also deletes .devflow/dream/.pending-turns.jsonl and .pending-turns.processing for the current project, so stale turns don't get reprocessed on re-enable — matching memory.ts's drain-on-disable behavior for the sibling memory queue. The drain is skipped entirely (config/sentinel still flip) while a live background-dream-update worker holds .devflow/dream/.worker.lock, same rule already used by --clear/--reset. --enable is unchanged.
|
Provisional decisions ratified by user (2026-07-03): worker model default opus; run visibility via one-shot |
Restore shared/agents/dream.md as a self-contained background agent (opus, refs devflow:apply-decisions only): it claims the dream queue itself (atomic mv -> .processing, 900s mtime staleness discrimination, heartbeat at the detection->curation boundary), reads and edits decisions-log.jsonl directly one JSONL row at a time, and calls only the assign-anchor/retire-anchor/rotate-observations plumbing ops. Consume-then-delete: removing .processing is its final act; the final message is the run's only visibility surface. Register the agent in devflow-core-skills + devflow-ambient and drop 'dream' from LEGACY_AGENT_NAMES so the installer no longer sweeps the restored agent after copying it.
session-start-context gains Section 2: when the dream queue is non-empty (or a crashed run left a stale .processing batch, 900s mtime threshold), it resolves the model (project decisions.json -> global -> opus) and emits a DREAM MAINTENANCE directive telling the main model to spawn the background Dream agent. Queue emptiness is the natural gate — no throttle, no worker lock, no success stamp. A fresh .processing suppresses the directive (a live agent owns the batch). Deleted: spawn-dream-worker, background-dream-update, dream-procedure.md, lib/staleness.cjs, the last-run-summary injection (the agent's final message is the run's visibility surface), the merge-observation and count-active json-helper ops (the agent edits decisions-log.jsonl directly, one row at a time, and reads rendered files itself), and the DEVFLOW_BG_DREAM guard across all hooks (no claude -p dream session exists to guard against; DEVFLOW_BG_UPDATER stays for the memory worker). Gating is config-only (`decisions` in dream config): queue_read_gates loses its sentinel parameter, capture hooks drop the sentinel argument, and decisions-usage-scan.cjs drops its internal .disabled check (the capture-turn caller already gates). The detached claude -p implementation this replaces is preserved in git history: bf34dab, 5217b6c, 3bb9bbb. BREAKING CHANGE: scripts/hooks/spawn-dream-worker and background-dream-update no longer exist; the settings template seeds two SessionStart hooks instead of three. `devflow init` sweeps the stale files and hook entries on upgrade.
…state migration devflow decisions --enable/--disable now write only the dream config field — the .disabled sentinel is gone everywhere (every sentinel writer also wrote config, so no user intent is lost). --disable drains the dream queue unconditionally: with no worker lock in the architecture, a mid-run Dream agent whose claimed batch vanishes aborts without changes, which is exactly what disabling should do. --clear/--reset drop their worker-lock guards and .last-dream-ok references for the same reason. dream.ts slims to removeDreamHook/hasDreamHook (upgrade cleanup of the retired spawn-dream-worker settings entry); init no longer registers a dream hook and sweeps the four deleted hook files via LEGACY_HOOK_FILES. manageSentinel and its sentinel.ts module are removed with their last consumer, as are the getDreamLastOkPath/getDreamWorkerLockDir/ getDecisionsDisabledSentinel path helpers (TS + CJS mirror). New per-project migration purge-dream-worker-state-v1 unlinks decisions/.disabled, dream/.last-dream-ok, dream/last-run-summary, and removes the dream/.worker.lock directory — inert leftovers of the detached worker.
Rewrite CLAUDE.md (Decisions pipeline, hooks list, dream dir, Model Strategy, agent roster), docs/reference/file-organization.md, docs/working-memory.md, skills-architecture.md, the docs-framework skill, and the dream-capture-system feature knowledge base for the directive-spawned Dream agent architecture. Strip transition residue from code comments: "(old behavior)" idioms, the removed-guard note in preamble, era narrations in memory.ts and observation-io.ts, decisions-config.ts worker references, and stale test comments.
…e-clicks Three new default-ON entries in the Claude Code flags registry: disableBundledSkills setting, ANTHROPIC_DEFAULT_SONNET_MODEL pinned to claude-sonnet-4-6, and CLAUDE_CODE_DISABLE_MOUSE_CLICKS. Registry count 18 → 21 in CLAUDE.md.
Bring back the learning-counts HUD line removed with the learning pipeline (59db82e), rebuilt on the decisions ledger: counts active anchored rows from decisions-ledger.jsonl, mirroring the render-decisions.cjs active-row semantics so the numbers always match the rendered decisions.md/pitfalls.md (D309). Renders as a dim 'Learning: N decisions, M pitfalls' line in the Activity section, hidden when the ledger is absent or every entry is retired.
Todos render at the end of the capacity line (context · quota · todos) and the Info/Activity blank-line break is removed — the HUD is one compact block. LINE_GROUPS no longer carries null section breaks, so the pendingBreak machinery goes with it.
Code Review Findings — PR #248: Simplify Dream SystemCritical Issues (Blocking)1. Documentation references removed machinery —
High-Priority Issues (Should Fix)2. Stale hook-event list —
3. Inconsistent delimiter representation —
4. Duplicated legacy-marker sweep predicate —
5. HUD count duplicates render-decisions.cjs semantics —
6. Stale inline comment —
7. Long single-function dispatch —
Medium-Priority Issues (Should Fix)8. HUD styling inconsistency —
9. Incorrect command wording in cli-reference —
10. Stale comment in hook helper —
Summary
8 of 10 issues are documentation or comment stale-naming (applies ADR-003). 2 architectural duplications (HUD semantics, legacy-marker predicate) warrant extraction. 1 critical doc error (detached dream worker) blocks merge. Claude Code — Code Review Agent v2 |
| @@ -9,7 +9,7 @@ devflow/ | |||
| ├── .claude-plugin/ # Marketplace registry (repo root) | |||
There was a problem hiding this comment.
CRITICAL (97% confidence): This row was changed to reference 'The detached dream worker' which is exactly what this PR removes. The new architecture uses the in-session Dream agent (shared/agents/dream.md) to render decisions/pitfalls via render-decisions.cjs, not a detached worker.
Please update the Source column to: Dream agent via assign-anchor (renders via render-decisions.cjs)
This ensures the documentation accurately reflects the new implementation and applies ADR-003 (end-state only, no residue of retired machinery).
Credit the Dream agent (not the removed detached dream worker) for decisions.md/pitfalls.md rendering, correct the Settings Override hook list (PostToolUse added, SessionEnd removed), fix decisions CLI help text for the config-only enable/disable model, and document the purge-dream-marker-pipeline-v1 migration alongside its sibling. applies ADR-003 Co-Authored-By: Claude <noreply@anthropic.com>
…ment session-start-context now allowlists DREAM_MODEL to opus/sonnet/haiku (fallback "opus", matching decisions-config.ts DEFAULTS.model) before interpolating it into the injected SessionStart directive. Defense in depth against a malformed decisions.json value carrying newlines/quotes into the session prompt. Also corrects ensure-devflow-init's header comment: dream-capture and dream-dispatch no longer exist (removed in the dream simplification); actual callers are capture-prompt, capture-turn, capture-question, memory-worker, and pre-compact-memory. applies ADR-003 Co-Authored-By: Claude <noreply@anthropic.com>
- Add a contract test comparing gatherDecisionsCounts' active/inactive determination against render-decisions.cjs's isActive() across the full decisions_status matrix, so the two can no longer silently diverge (D309). - Document the intentional single-dimmed-clause render style in decisions-counts.ts vs config-counts.ts's per-part dim + middot join. - Normalize removeCaptureHooks' no-change return to the same pretty-printed format as the mutating return for object callers, with a regression test. Co-Authored-By: Claude <noreply@anthropic.com>
…cwd log path - Extract sweepLegacyDreamMarkers/drainDreamQueue into a shared src/cli/utils/dream-cleanup.ts, deduplicating the legacy marker sweep (decisions.ts --reset + purge-dream-marker-pipeline-v1 migration) and the dream queue drain (--clear + --disable). applies ADR-003. - Split decisionsCommand's 300+ line action callback into named handlers (handleStatus/handleList/handleConfigure/handleReset/handleClear/ handleEnable/handleDisable) behind a thin router; behavior unchanged. - Fix --list to resolve the decisions log via the git root (falling back to cwd outside a git project) instead of always using process.cwd(), matching --status/--clear/--reset/--disable and fixing a real bug where --list run from a subdirectory read a nonexistent cwd-relative log. - Drop the stale "Shared log path for --status, --list, --clear" comment now that each handler resolves its own log path. Co-Authored-By: Claude <noreply@anthropic.com>
…SOH byte capture-turn inlined its own jq/node cwd+last_assistant_message extraction with a literal invisible 0x01 byte in the jq program, contradicting queue-append's own "no invisible bytes hiding in the source" principle. Generalize json_extract_cwd_prompt into json_extract_cwd_field(field) in json-parse (and the matching json-helper.cjs node fallback), have capture-turn call it with "last_assistant_message", and delegate the existing json_extract_cwd_prompt to the new helper so capture-prompt and preamble are unaffected. Removes the now-dead extract-cwd-prompt op (applies ADR-003 — leave the end-state, not the transition) instead of leaving both implementations side by side. Also adds the guard/fallback comments capture-prompt and capture-turn already carry to capture-question, so all three capture hooks read identically. Co-Authored-By: Claude <noreply@anthropic.com>
Four subcommand handlers (reset, clear, enable, disable) repeated the same "resolve git root or warn and bail" block with only the warning suffix differing. Factor it into requireGitRoot(actionSuffix).
Reflects the /resolve pass: shared json_extract_cwd_field extraction, DREAM_MODEL allowlist validation, dream-cleanup.ts extraction, decisions.ts router restructure, HUD isActive() contract test, and the sentinel.test.ts -> config-disable-guards.test.ts rename.
Summary
Simplifies the dream (decisions) system to capture + directive + background Dream agent: shell scripts only capture turns and trigger processing; the LLM does all processing by reading and editing the data files directly.
capture-prompt/capture-turn/capture-question(always-on) dual-append every user turn, assistant turn, and answeredAskUserQuestionto the memory and dream.pending-turns.jsonlqueues via the sharedqueue-appendhelper (200→100 overflow truncation). Gating is config-only — thedecisionsfield in dream config, mirroring memory's ADR-001; the.disabledsentinel is gone everywhere.session-start-contextSection 2 — when the dream queue is non-empty (or a crashed run left a.pending-turns.processingbatch older than 900s), it resolves the model (projectdecisions.json→ global~/.devflow/decisions.json→opus) and emits a--- DREAM MAINTENANCE ---directive: spawnAgent(subagent_type="Dream", model=<resolved>, run_in_background: true), do not narrate. A fresh.processingsuppresses the directive (a live agent owns the batch). Queue emptiness is the natural gate — no throttle, no lock, no claude-on-PATH check.shared/agents/dream.md, opus, self-contained). It claims the queue itself (atomicmv→.processing; merges + re-claims a stale leftover; exits silently on a lost race or fresh.processing; heartbeattouchat the detection→curation boundary), readsdecisions-log.jsonl/decisions.md/pitfalls.md/.decisions-usage.jsondirectly, appends/edits observations one JSONL row at a time, and calls only three plumbing ops:assign-anchor,retire-anchor(numbering + render — Iron Law), androtate-observations(date-arithmetic archival). Detection bar, ADR-XOR-PF, dedup, and curation bounds (≤5 changes, 7-day window) are unchanged..processingis the agent's final act; a crash leaves the batch for the next session's stale-merge recovery. Run visibility is the agent's 1–3 line final message — native background-task visibility, no status files.Removed machinery
spawn-dream-workerhook +background-dream-updatedetached worker (318 lines: worker lock, watchdog, model resolution, success stamp) +dream-procedure.md+lib/staleness.cjsmerge-observationandcount-activejson-helper ops (the agent edits the log and reads rendered files itself).devflow/decisions/.disabledsentinel,dream/.last-dream-ok,dream/last-run-summary,dream/.worker.lock— plusmanageSentinel/sentinel.tsand the three path helpers for themDEVFLOW_BG_DREAMguard across all hooks (no dreamclaude -psession exists;DEVFLOW_BG_UPDATERstays for the memory worker)The detached
claude -pimplementation is preserved in git history (bf34dab,5217b6c,3bb9bbb) for future resurrection.CLI + migration
devflow decisions --enable/--disableare config-only;--disable(and--clear) drain the dream queue unconditionally — a mid-run agent whose files vanish aborts without changes, which is the desired outcome of disabling.dream.tsslims toremoveDreamHook/hasDreamHook(upgrade cleanup of the stale settings entry); init sweeps the four deleted hook files viaLEGACY_HOOK_FILES.purge-dream-worker-state-v1removes the inert worker-state leftovers on upgrade.Race safety
Live-vs-crashed
.processingis discriminated by mtime (900s, both in the hook and the agent). Two sessions racing on the queue are settled by the atomicmv(one winner). A double stale-reclaim is possible in a sub-second window >900s after a crash — accepted; dedup rules andassign-anchorpreconditions bound the damage to redundant analysis.Accepted risks (conscious)
claude -psessions receive the directive (SessionStart fires there) — pre-existing exposure class, lived with before.Testing
npm run build,tsc --noEmit— zero warnings.decisions:false/DEVFLOW_BG_UPDATER=1/ fresh vs stale.processing), model resolution (project > global > opus), and directive format.tests/dream-agent.test.tspins the agent contract: frontmatter, claim/heartbeat/consume-then-delete protocol, and negatives (nocount-active,staleness.cjs,merge-observation,.last-dream-ok,last-run-summary).Untouched
Memory pipeline (worker, locks, throttle), knowledge system, ambient, capture semantics, ledger render engine,
decisions-index.cjs,/resolve-side decisions consumption,devflow decisions list|--configure.Also in this PR (folded in)
feat(flags)
1260d4f— three new default-ON Claude Code flags:disable-bundled-skills(disableBundledSkills: true),pin-sonnet-4-6(ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6),disable-mouse-clicks(CLAUDE_CODE_DISABLE_MOUSE_CLICKS=1); registry 18 → 21, covered intests/flags.test.ts.feat(hud)
481a787+34fd95b(folded from feat(hud): restore decisions/pitfalls counts segment #250) — restores the decisions/pitfalls counts line, rebuilt on the decisions ledger: counts active anchored rows fromdecisions-ledger.jsonlmirroringrender-decisions.cjssemantics (D309), rendered as a dimLearning: N decisions, M pitfallsline. Layout flattened: todos moved to the end of the capacity line, Info/Activity section break removed (pendingBreakmachinery deleted).