Skip to content

Dreaming mode: learn a person's work offline and suggest improvements - #300

Merged
arjunjaggi34 merged 4 commits into
mainfrom
claude/dreaming-mode-296
Oct 28, 2026
Merged

arjunjaggi34 merged 4 commits into
mainfrom
claude/dreaming-mode-296

Conversation

@arjunjaggi34

@arjunjaggi34 arjunjaggi34 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Closes #296.

Adds Dreaming mode: while zorp is idle it looks over how a person has worked and comes back with suggestions, each one a proposal backed by the exact conversations it came from and doing nothing until the person accepts it.

The first commit on this branch was the spec and ADR only, for approval (the issue's step 1). That was approved, and this adds the implementation. ADR 0144 is now accepted.

The rule it is designed around (ADR 0063)

zorp stores no sentence a model composed about the person, because the agent's guesses must never become its own evidence. Dreaming mode keeps that four ways, and each has a test:

  • Detection is code; the model only words it. zorp-agent/src/dream/detectors.rs runs over code-derived columns only (the verbatim first message, project membership, the code-derived exit status of the commands a conversation ran) and returns evidence rows, never prose — the same split critique and the aryabhatta detectors use. The three detectors are recurring requests, unfiled clusters, and repeated failures.
  • The model only words a pattern, and even that is optional. The default TemplatePhraser writes the suggestion from the pattern's own code-derived summary with no model call, so Dreaming mode works offline. phrase_prompt builds the fenced, nonce-marked user block a model-backed Phraser would send (the shape memory and title use); the trait is the seam, and none of the rules change with it. This is the one departure from the original sketch, called out in the ADR.
  • A suggestion is a proposal. It is shown with links to the exact conversations and does nothing until a person accepts it. Accepting creates an ordinary object through the same path a person uses: an unfiled cluster becomes a project, a recurring request or repeated failure becomes a flavor that is untrusted until trusted (ADR 0123). A dismissed suggestion's signature blocks the same pattern from being raised again.
  • Suggestions never reach messages, task, the recall index, or the memory block. They live in their own suggestions table (kind, evidence ids, model-authored wording, state new/accepted/dismissed), kept apart the way display_title is from task (ADR 0069).

What's here

  • zorp-agent/src/dream/ — detectors, the pass (run_pass, dedup by signature against every stored suggestion), the Phraser trait + TemplatePhraser, gather (reads the local store), and accept.
  • zorp-agent/src/session.rs — the suggestions table and its methods.
  • CLI — zorp-agent dreams (list), dreams run, dreams accept <id>, dreams dismiss <id>.
  • zorp-web — GET /api/dreams, POST /api/dreams/run, POST /api/dreams/:id/accept, POST /api/dreams/:id/dismiss, in every build (a suggestion is a store row, like a project). The "While you were away" card in the sidebar (web/src/dreams.ts), with evidence links and Accept / Dismiss; the model-authored wording lands through textContent, labelled. The background pass is a worker beside the recall sweep, off unless ZORP_DREAM is set (ZORP_DREAM_SWEEP_SECS for the interval).

Tests

  • no_tool_starts_a_dream_pass (zorp-agent/src/agent.rs): no model tool runs a pass or acts on a suggestion.
  • zorp-agent/tests/dream_isolation.rs: the wording never lands in messages or task, the recall and memory code never reads the suggestions table, and a dismissed pattern is not raised again.
  • Detector and pass unit tests; web/test/dreams.test.ts (the wording is never markup; the kind is said in code; evidence opens the cited conversation).
  • Listed in zorp-agent/src/state.rs so it can be seen and cleared.

Where the issue and the code disagreed: the issue sketches a model phrasing every suggestion; the default here phrases in code (TemplatePhraser) so the feature works offline, with a model-backed phraser as a drop-in behind the Phraser trait. The ADR records this.

Ran cargo fmt --all, cargo build --workspace, cargo clippy --workspace --all-targets, cargo test -p zorp-agent, cargo test -p zorp-web, and npm run check, npm test, npm run build in web/.

The Mac app's native card for this is a follow-up (the desktop app mirrors the browser API; this adds the routes it would call).


Generated by Claude Code

Per the issue, this is the spec-and-ADR-first step before any code. It adds
only the design:

- docs/decisions/0144-...md (status: proposed): how Dreaming mode keeps
  ADR 0063. Detection is code over code-derived columns and the model only
  words a suggestion from the evidence; a suggestion is a proposal shown with
  its evidence that does nothing until a person accepts it; suggestions live
  in their own table labelled model-authored and are never read as evidence
  by recall, the memory block, or messages; it is local, off by default, and
  a person starts it, with no model tool turning it on.
- docs/superpowers/specs/2026-10-27-dreaming-mode-design.md: the shape, the
  detectors, the dream pass, storage, surfaces, and the tests it would get.

No implementation is included. This is a person's call before any code, so
the ADR is `proposed` and waiting on approval.

Part of #296

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K7qLzxWmLqkYQQLiQqJtiu
Implements the design approved in the spec and ADR 0144 (now accepted).

Detection is code, and a suggestion is a proposal:

- zorp-agent/src/dream/: detectors over code-derived columns (recurring
  requests, unfiled clusters, repeated failures), the dream pass, and the
  Phraser trait. The default TemplatePhraser uses no model; phrase_prompt
  builds the fenced, nonce-marked block a model-backed phraser would send.
  accept() creates a project or writes an untrusted flavor through the same
  code path a person uses.
- The suggestions table (session.rs): kind, evidence ids, model-authored
  wording, and state (new/accepted/dismissed), kept apart from messages the
  way display_title is from task.
- CLI: zorp-agent dreams, with run, accept, and dismiss.
- zorp-web: GET /api/dreams, POST /api/dreams/run, and
  /api/dreams/:id/{accept,dismiss}, in every build, plus the "While you were
  away" card in the sidebar. The background pass runs only when ZORP_DREAM is
  set, beside the recall sweep.

Guards:

- no_tool_starts_a_dream_pass pins that no model tool runs a pass or acts on
  a suggestion.
- tests/dream_isolation.rs pins that the wording never reaches messages,
  task, or the recall and memory code.
- Listed in state.rs so it can be seen and cleared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K7qLzxWmLqkYQQLiQqJtiu
@arjunjaggi34 arjunjaggi34 changed the title Dreaming mode: spec and ADR first (for approval before any code) Dreaming mode: learn a person's work offline and suggest improvements Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

CI status on the current head (7d7de40): every gating job is green — build-and-test (ubuntu + macOS), windows, msrv, clippy, web, features, harness, and Desktop App (macOS).

The one non-green check is research-pr, which shows cancelled — the job's 60-minute timeout-minutes cap being hit while it builds the bundled DuckDB amalgamation from a cold cache, not a code failure. This PR's own research-feature tests (zorp-agent --features research, zorp-web --features research) pass locally, and the same CI job passed on #298 with a warm shared cache (research-stack), which is the tell that this is cold-build timing rather than anything in this PR.

I can't re-run the job myself (the GitHub App lacks actions: write, so a re-run returns 403), and the timeout is a workflow setting I'm not widening this PR to touch. A maintainer re-run, or the shared cache warming once a research-touching PR lands on main, should clear it. I'll keep watching.


Generated by Claude Code


Generated by Claude Code

accept() looked a suggestion up in any state and always created its
object, so a double click, a stale card, or a repeated CLI invocation
created a second project or rewrote the flavor. Guard on the stored
state (not the caller's possibly stale row): only a `new` suggestion can
be accepted. Add a test for the stale-row path, and a test that a flavor
description carrying a backslash, a quote and TOML brackets stays one
key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K7qLzxWmLqkYQQLiQqJtiu
# Conflicts:
#	docs/DECISIONS.md
#	zorp-agent/src/lib.rs
#	zorp-agent/src/session.rs
#	zorp-agent/src/state.rs
@arjunjaggi34
arjunjaggi34 merged commit 42a8a0e into main Oct 28, 2026
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.

Dreaming mode: learn a person's work and habits offline, and suggest improvements

2 participants