Skip to content

feat(hooks)!: simplify dream system — capture + directive + background Dream agent#248

Merged
dean0x merged 26 commits into
mainfrom
feat/simplify-dream-system
Jul 4, 2026
Merged

feat(hooks)!: simplify dream system — capture + directive + background Dream agent#248
dean0x merged 26 commits into
mainfrom
feat/simplify-dream-system

Conversation

@dean0x

@dean0x dean0x commented Jul 3, 2026

Copy link
Copy Markdown
Owner

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: capture-prompt / capture-turn / capture-question (always-on) dual-append every user turn, assistant turn, and answered AskUserQuestion to the memory and dream .pending-turns.jsonl queues via the shared queue-append helper (200→100 overflow truncation). Gating is config-only — the decisions field in dream config, mirroring memory's ADR-001; the .disabled sentinel is gone everywhere.
  • Trigger: session-start-context Section 2 — when the dream queue is non-empty (or a crashed run left a .pending-turns.processing batch older than 900s), it resolves the model (project decisions.json → global ~/.devflow/decisions.jsonopus) and emits a --- DREAM MAINTENANCE --- directive: spawn Agent(subagent_type="Dream", model=<resolved>, run_in_background: true), do not narrate. A fresh .processing suppresses the directive (a live agent owns the batch). Queue emptiness is the natural gate — no throttle, no lock, no claude-on-PATH check.
  • Processor: the restored Dream agent (shared/agents/dream.md, opus, self-contained). It claims the queue itself (atomic mv.processing; merges + re-claims a stale leftover; exits silently on a lost race or fresh .processing; heartbeat touch at the detection→curation boundary), reads decisions-log.jsonl / decisions.md / pitfalls.md / .decisions-usage.json directly, appends/edits observations one JSONL row at a time, and calls only three plumbing ops: assign-anchor, retire-anchor (numbering + render — Iron Law), and rotate-observations (date-arithmetic archival). Detection bar, ADR-XOR-PF, dedup, and curation bounds (≤5 changes, 7-day window) are unchanged.
  • Consume-then-delete: removing .processing is 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-worker hook + background-dream-update detached worker (318 lines: worker lock, watchdog, model resolution, success stamp) + dream-procedure.md + lib/staleness.cjs
  • merge-observation and count-active json-helper ops (the agent edits the log and reads rendered files itself)
  • .devflow/decisions/.disabled sentinel, dream/.last-dream-ok, dream/last-run-summary, dream/.worker.lock — plus manageSentinel/sentinel.ts and the three path helpers for them
  • DEVFLOW_BG_DREAM guard across all hooks (no dream claude -p session exists; DEVFLOW_BG_UPDATER stays for the memory worker)

The detached claude -p implementation is preserved in git history (bf34dab, 5217b6c, 3bb9bbb) for future resurrection.

CLI + migration

  • devflow decisions --enable/--disable are 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.ts slims to removeDreamHook/hasDreamHook (upgrade cleanup of the stale settings entry); init sweeps the four deleted hook files via LEGACY_HOOK_FILES.
  • New per-project migration purge-dream-worker-state-v1 removes the inert worker-state leftovers on upgrade.

Race safety

Live-vs-crashed .processing is discriminated by mtime (900s, both in the hook and the agent). Two sessions racing on the queue are settled by the atomic mv (one winner). A double stale-reclaim is possible in a sub-second window >900s after a crash — accepted; dedup rules and assign-anchor preconditions bound the damage to redundant analysis.

Accepted risks (conscious)

  • Directive spawn depends on model compliance — a skipped spawn delays processing to the next session; the queue persists (bounded by the existing 200→100 truncation).
  • Unrelated claude -p sessions receive the directive (SessionStart fires there) — pre-existing exposure class, lived with before.
  • Transitional window: an in-flight old worker during upgrade may capture one batch of its own turns (one-shot junk rows).

Testing

  • Full suite green at every commit (1816 tests), npm run build, tsc --noEmit — zero warnings.
  • New directive tests cover the emission matrix (queue non-empty / empty / decisions:false / DEVFLOW_BG_UPDATER=1 / fresh vs stale .processing), model resolution (project > global > opus), and directive format.
  • New tests/dream-agent.test.ts pins the agent contract: frontmatter, claim/heartbeat/consume-then-delete protocol, and negatives (no count-active, staleness.cjs, merge-observation, .last-dream-ok, last-run-summary).
  • Manual smoke: seeded queue → directive with resolved model + project root; empty queue → silent.

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 in tests/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 from decisions-ledger.jsonl mirroring render-decisions.cjs semantics (D309), rendered as a dim Learning: N decisions, M pitfalls line. Layout flattened: todos moved to the end of the capacity line, Info/Activity section break removed (pendingBreak machinery deleted).

    devflow · feat/payments* · 2↑ 1↓ · v2.0.0 +14 · 2 worktrees · 8 files · +280 -2
    Context ███░░░░░ 34% · 5h ████░░░░ 45% (2h 15m) · 3/7 todos
    Fable 5 [200k] · 2 CLAUDE.md · 12 rules · 3 MCPs · 8 hooks · $4.20
    Learning: 12 decisions, 4 pitfalls
    

dean0x and others added 12 commits July 3, 2026 01:36
- 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.
@dean0x

dean0x commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

Provisional decisions ratified by user (2026-07-03): worker model default opus; run visibility via one-shot last-run-summary (written only-when-changed, injected once then deleted); one qa row per question. Changed by user: decisions --disable now also drains the dream pending-turns queue, mirroring memory's disable semantics (skipped while a worker lock is held) — implemented in 3bb9bbb.

dean0x added 4 commits July 4, 2026 01:52
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.
@dean0x dean0x changed the title feat(hooks)!: simplify dream system — unified capture + detached dream worker feat(hooks)!: simplify dream system — capture + directive + background Dream agent Jul 3, 2026
dean0x added 3 commits July 4, 2026 10:35
…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.
@dean0x

dean0x commented Jul 4, 2026

Copy link
Copy Markdown
Owner Author

Code Review Findings — PR #248: Simplify Dream System

Critical Issues (Blocking)

1. Documentation references removed machinerydocs/reference/file-organization.md:207-208 (97% confidence)

  • The "Project Knowledge" table was updated to say "The detached dream worker" renders decisions, but this PR removes the detached worker. The new architecture uses the in-session Dream agent.
  • Fix: Update to "Dream agent via assign-anchor" to match the new implementation and CLAUDE.md.

High-Priority Issues (Should Fix)

2. Stale hook-event listdocs/reference/file-organization.md:172 (90% confidence)

  • SessionEnd hook removed, PostToolUse hook added, but doc still lists (UserPromptSubmit, Stop, SessionStart, SessionEnd, PreCompact) instead of (UserPromptSubmit, PostToolUse, Stop, SessionStart, PreCompact).

3. Inconsistent delimiter representationscripts/hooks/capture-turn:34 (82% confidence)

  • SOH (0x01) delimiter embedded as raw control byte here, but the shared helper (json-parse:173) uses jq escape "", and your node fallback (line 38) uses \x01. Contradicts queue-append principle (no invisible bytes in source).

4. Duplicated legacy-marker sweep predicatesrc/cli/commands/decisions.ts:277-291 + src/cli/utils/migrations.ts (85% confidence)

  • Both modules implement identical predicate for identifying retired dream marker files. Risk: DRY violation, future changes must be synced in two places.
  • Fix: Extract shared helper sweepLegacyDreamMarkers(dreamDir) in src/cli/utils/dream-legacy.ts.

5. HUD count duplicates render-decisions.cjs semanticssrc/cli/hud/components/decisions-counts.ts:15,31-34 (82% confidence)

  • INACTIVE_STATUSES set redefined here; must mirror scripts/hooks/lib/render-decisions.cjs:48 exactly. Risk: silent desync if status vocabulary changes.
  • Fix: Add contract test asserting HUD's INACTIVE_STATUSES matches cjs implementation.

6. Stale inline commentsrc/cli/commands/decisions.ts:84 (88% confidence)

  • Comment says "Shared log path for --status, --list, --clear" but --clear now resolves its own path from gitRoot. Comment is transition residue.
  • Fix: Update to "Shared log path for --status and --list (cwd-based)".

7. Long single-function dispatchsrc/cli/commands/decisions.ts:60-377 (82% confidence)

  • 317-line .action() callback handles 7 sub-commands inline; exceeds CRITICAL function-length metric (>200 lines). Code you touched (extended branches).
  • Fix: Extract handlers (handleReset, handleClear, etc.) and leave .action as thin router.

Medium-Priority Issues (Should Fix)

8. HUD styling inconsistencysrc/cli/hud/components/decisions-counts.ts:90-94 vs config-counts.ts:97-98 (80% confidence)

  • Sibling count components format differently (decisions dims whole string, config dims per-part with middot separator).

9. Incorrect command wording in cli-referencedocs/cli-reference.md:81-82 (85% confidence)

  • Says decisions --enable # Register the decisions hook but command flips config only (hooks are always-on). New model is config-based gating.
  • Fix: Reword to "Enable/Disable decisions detection" to match actual implementation.

10. Stale comment in hook helperscripts/hooks/ensure-devflow-init:3 (96% confidence)

  • Header says "Called from dream-capture, dream-dispatch, and pre-compact-memory" but dream-capture/dispatch are deleted. Current callers are capture-prompt/turn/question, memory-worker, pre-compact.
  • Fix: Update to current callers only.

Summary

Category CRITICAL HIGH MEDIUM LOW
Blocking 1 - - -
Should Fix - 3 5 2

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)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

dean0x and others added 5 commits July 4, 2026 11:05
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>
dean0x added 2 commits July 4, 2026 11:17
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.
@dean0x dean0x merged commit da648f3 into main Jul 4, 2026
2 checks passed
@dean0x dean0x deleted the feat/simplify-dream-system branch July 4, 2026 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant