diff --git a/.changeset/716-run-liveness-check.md b/.changeset/716-run-liveness-check.md deleted file mode 100644 index ec29f531..00000000 --- a/.changeset/716-run-liveness-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Self-heal a run whose process died without writing its `end` event (#716). A crash, `kill -9`, or the machine sleeping used to leave `.the-framework/run.json` stuck at `status: running` forever: the dashboard showed a permanently RUNNING row whose Stop was a no-op (nothing was left to consume `control.jsonl`), and it only cleared on a daemon restart. The run now records its owning pid and host in `run.json`, and `readLiveMeta` flips a `running` run to `stopped` (and archives it) on read when that owning process is gone on this host, so the dashboard clears the stuck row on the next poll. Runs whose meta predates this field are left to the existing boot-time reconcile. diff --git a/.changeset/720-auto-resume-finished-run.md b/.changeset/720-auto-resume-finished-run.md deleted file mode 100644 index ecfd3df4..00000000 --- a/.changeset/720-auto-resume-finished-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Resume a finished run by messaging it (#720). After a run ends (Stop, or it finishes) the dashboard used to drop the chat composer, so the conversation was a dead end. The finished-run view now keeps a composer, and sending a message spins a fresh run whose opening prompt `--resume`s the ended run's captured session id, continuing the same conversation with full prior context. New plumbing: `DriverStartOptions.resumeSessionId` seeds the Claude Code session so its very first prompt resumes (the framing is skipped, since the resumed transcript already carries it); `AwaitRoundsOptions.resume` / `RunPromptOptions.resumeSessionId` carry it through `runPrompt`; and it threads from the dashboard as `StartRunOptions.resumeSession` -> the `--resume-session ` CLI flag. A continuation is sent as a `prompt` run; a fresh run is byte-identical to before. diff --git a/.changeset/add-project-flow.md b/.changeset/add-project-flow.md deleted file mode 100644 index 482cce19..00000000 --- a/.changeset/add-project-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the "Add project(s)" install flow to the dashboard. A `POST /api/projects` (guarded like the other state-changing routes) installs The Framework into a repo, or every git repo directly under a folder, then registers each so it shows up in the Projects list; the daemon wires it to install-core. The Projects sidebar gains an "Add" control with a small path form (single repo or "folder of repos"), shown only when the server enables adding. Also fixes `enumerateGitRepos` to detect repo roots via `git rev-parse --show-prefix` instead of comparing `--show-toplevel` to the path, which failed across a symlink (e.g. macOS `/var` -> `/private/var`) and returned no repos. diff --git a/.changeset/agent-cli-abort-no-error.md b/.changeset/agent-cli-abort-no-error.md deleted file mode 100644 index b417eb52..00000000 --- a/.changeset/agent-cli-abort-no-error.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Fix the agent-CLI runner emitting a spurious `error` event after a run is aborted. On abort the turn rejects and settles, but the killed child process still fires `close` afterward, and the close handler emitted an `error` (and would have emitted `result`) telemetry event before checking whether the turn had already settled. The dashboard event stream saw a phantom agent error after a clean Stop. The close handler now returns early once the turn has settled, so an abort produces exactly one outcome. diff --git a/.changeset/agent-flag.md b/.changeset/agent-flag.md deleted file mode 100644 index 46891c75..00000000 --- a/.changeset/agent-flag.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add `--agent claude|codex`, which picks the agent that drives a run. The Codex driver shipped but nothing selected it, so it was unreachable; now both driver paths (the build itself and the auto-select routing turn before it) honor the flag, and preflight probes the agent you asked for rather than always `claude`. Default stays `claude`. - -Codex reports no price and no quota, so the spend cap and the consumption limits cannot gate it and previously would have no-opped in silence. A run now says which guards are not in force instead of letting `--max-cost` imply one, and it no longer offers a Claude Code session link for a session that isn't Claude's. diff --git a/.changeset/agent-logos-656.md b/.changeset/agent-logos-656.md deleted file mode 100644 index 4567f7a1..00000000 --- a/.changeset/agent-logos-656.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Rework the run's agent + model picker into a tree (#656, #658). The dropdown's top level is the coding agents, each showing its logo (Claude / Codex, #656); hovering an agent reveals only that agent's own models, and picking a model sets both the agent and model together — so an incompatible pair (e.g. Codex with a Claude model) can no longer be chosen. The trigger shows the current agent's logo then the model, with the agent name in the tooltip. diff --git a/.changeset/agent-picker-650.md b/.changeset/agent-picker-650.md deleted file mode 100644 index bcce53a6..00000000 --- a/.changeset/agent-picker-650.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add an agent picker to the dashboard (#650). The Start form can now choose the coding agent that drives the run — Claude Code or Codex — alongside the model, wiring the existing `--agent` flag. It persists as a preference (`agent`, validated to the known set) and maps to a run's `--agent` (only non-default `codex` emits a flag). Agent and model share one dropdown (a submenu each), styled like the Presets menu, and the "New preset" panel spans the full width. diff --git a/.changeset/auto-accept-naming-325.md b/.changeset/auto-accept-naming-325.md deleted file mode 100644 index 43ae8fa2..00000000 --- a/.changeset/auto-accept-naming-325.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Untangle the two "autopilot" concepts in the dashboard (#325): the countdown text now reads "Auto accept in 10s" (and "Auto accept canceled" / "Auto accept off"), so "autopilot" is left to mean the mode preset. The checkbox that arms the countdown is labeled "Autopilot", per Rom's call on the issue. diff --git a/.changeset/auto-git-init-add-project-473.md b/.changeset/auto-git-init-add-project-473.md deleted file mode 100644 index 8deacfd1..00000000 --- a/.changeset/auto-git-init-add-project-473.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Adding a project that isn't a git repo now initializes one for you instead of failing with `fatal: not a git repository`. `installProject` detects a non-repo folder and runs `git init` before its usual commit-and-install flow, so a plain directory can be added straight from the dashboard. The install result reports `initialized: true` when it did so. diff --git a/.changeset/backlog-turn-signals.md b/.changeset/backlog-turn-signals.md deleted file mode 100644 index 3440dbbb..00000000 --- a/.changeset/backlog-turn-signals.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Fix backlog turns dropping the agent's signals. The backlog loop prompts through the run's own driver session, so a backlog turn carries the same signal protocol as any other turn, but it only ever parsed await gates. `showMarkdown()` views never reached the dashboard rail, `setSessionName()` was ignored, and `setReadyForMerge()` never emitted `ready-for-merge`, so `--post-merge` could not fire from backlog work. The turn-signal parsing (views, session name, ready-for-merge) was duplicated verbatim in the build path and the direct prompt path and missing from the third; it is now one `createTurnSignalEmitter` used by all three, with the backlog loop sharing a single emitter so `ready-for-merge` still fires once across every item. diff --git a/.changeset/browser-dashboard-toggle-467.md b/.changeset/browser-dashboard-toggle-467.md deleted file mode 100644 index 2d477b13..00000000 --- a/.changeset/browser-dashboard-toggle-467.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add a "Browser" toggle to the dashboard Start form so `--browser` (give the agent a real browser via chrome-devtools-mcp, #452) is reachable from daemon/dashboard-started runs, not just the CLI. Mirrors the Post-merge cleanup pref: a `browser` preference flows to `StartRunOptions.browser` and on to the `--browser` flag. diff --git a/.changeset/browser-mcp-452.md b/.changeset/browser-mcp-452.md deleted file mode 100644 index 0cde726a..00000000 --- a/.changeset/browser-mcp-452.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add `--browser`: give the agent a real browser during the run via chrome-devtools-mcp. When set, the driver writes a temp `--mcp-config` wiring `chrome-devtools-mcp`, so the agent can navigate pages, read console + network output, inspect the DOM, and screenshot while it works instead of flying blind on frontend changes. Off by default; host-side only (no runner change), and the MCP servers merge with the user's own rather than replacing them. The `ClaudeCodeDriver` gains an `mcpServers` option backing this. diff --git a/.changeset/business-knowledge-537.md b/.changeset/business-knowledge-537.md deleted file mode 100644 index 85704cc3..00000000 --- a/.changeset/business-knowledge-537.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Collect business knowledge in the repo (#537). Every run now puts `.the-framework/README.md`, `.the-framework/DECISIONS.md` and `.the-framework/KNOWLEDGE-BASE.md` on the `Context:` line, so the agent reads whatever the project already knows about itself, and the post-merge prompt gained a `## Business knowledge` section asking it to fold back what the session taught that the code cannot show. The docs go with the built-in system prompt: `--vanilla` still injects nothing but the user's own dirs. `--eco-auto-maintenance` now drops the post-merge prompt's `## Maintenance` section instead of skipping the whole run, which would have taken business knowledge with it. diff --git a/.changeset/chat-running-run.md b/.changeset/chat-running-run.md deleted file mode 100644 index 85baa550..00000000 --- a/.changeset/chat-running-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Live chat: send more messages to a running run. The dashboard's run view gains a composer, and the run stays open after the agent goes idle to take the user's own messages (the "stay-open" lifecycle) until it is stopped. Each message continues the same agent session via `claude --resume `, so the conversation keeps full context, and rides the existing `control.jsonl` steering channel as a new `message` kind next to Stop and choice picks. Wired only for an interactive run (a live dashboard / daemon); a headless run ends when the agent stops asking, exactly as before. The Claude Code driver gains a `resume` prompt option (`DriverPromptOptions.resume`) that continues the retained session and skips the redundant system-prompt re-append. diff --git a/.changeset/cli-real-version.md b/.changeset/cli-real-version.md deleted file mode 100644 index d3f9d555..00000000 --- a/.changeset/cli-real-version.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Fix `framework --version` (and the bare-`framework` footer) reporting `0.0.0` instead of the real package version (#312). The version is now read from the package's own `package.json` at runtime, so it always matches what is installed. diff --git a/.changeset/cli-update-check.md b/.changeset/cli-update-check.md deleted file mode 100644 index 00757d3d..00000000 --- a/.changeset/cli-update-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Bare `framework` now tells you whether the CLI is up to date (#312): after the version footer it checks npm's `dist-tags.latest` (2.5s cap) and prints "Up to date" or "Update available: vX (you have vY). Run: npm i -g @gemstack/framework". Offline or on any fetch failure it prints nothing. Display only; no auto-update. diff --git a/.changeset/codex-driver.md b/.changeset/codex-driver.md deleted file mode 100644 index 4df86404..00000000 --- a/.changeset/codex-driver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add `CodexDriver`: The Framework can drive the Codex CLI as a second agent, on the user's own ChatGPT subscription with no API key. Generalizes the agent-CLI process handling into `runAgentCli` so a second agent reuses it rather than copying it. Codex reports no price and no quota, so it omits usage rather than claim a run was free, and the consumption limits stay Claude-only. diff --git a/.changeset/compact-controls-options-menu-654.md b/.changeset/compact-controls-options-menu-654.md deleted file mode 100644 index b0a429a2..00000000 --- a/.changeset/compact-controls-options-menu-654.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Tidy the Start-form run controls (#654): the Presets and Agent·Model dropdowns are now compact, the six Global options (Autopilot, Technical control, Disable system prompt, Eco, Post-merge cleanup, Browser) collapse into one "Options" checkbox dropdown next to Presets (with Eco's sub-drops when Eco is on), and the Agent·Model menu sits at the end of the row. diff --git a/.changeset/confirmation-gate-358.md b/.changeset/confirmation-gate-358.md deleted file mode 100644 index 143f12f8..00000000 --- a/.changeset/confirmation-gate-358.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Turn-boundary gate for plan approval (`showMarkdown()` + AWAIT): a build turn that ends with an `await-confirmation` block (the #326 large-scope PLAN flow) now pauses the run with a green Approve and a red Decline button on the dashboard. Approve resumes the build; Decline logs "Plan declined, awaiting user instructions." and stops the run cleanly (like the budget cap), so nothing reviews or improves work the user just declined. Headless runs auto-approve, keeping programmatic runs deterministic. Try it offline with `FRAMEWORK_FAKE_AWAIT=confirmation`. diff --git a/.changeset/consumption-guard.md b/.changeset/consumption-guard.md deleted file mode 100644 index 98f10402..00000000 --- a/.changeset/consumption-guard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Turn the consumption limits on for real runs. `startConsumptionGuard` composes the poller and the limits into the gate a run consults, the CLI reads the limits from the user's preferences and wires it into both run paths, and the direct prompt path gained the same pause the build path got. A driver that can't report a quota leaves the run ungated. diff --git a/.changeset/consumption-limits-config.md b/.changeset/consumption-limits-config.md deleted file mode 100644 index 6a6c6e57..00000000 --- a/.changeset/consumption-limits-config.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Let the user set the consumption limits. The preferences now carry a checkbox and a percentage per limit, and `resolveConsumptionLimits` fills any gap with the defaults. Preference sanitizing was boolean-only, so a percentage was silently dropped on both read and write; it now validates per-limit and falls back to the default rather than leaving the account unguarded. diff --git a/.changeset/consumption-limits-decision.md b/.changeset/consumption-limits-decision.md deleted file mode 100644 index acd3d9d8..00000000 --- a/.changeset/consumption-limits-decision.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add the consumption-limit decision layer: `ConsumptionMeter` tracks the account's weekly quota meter over time, and `consumptionStatus` reports where the session / 5h / daily limits stand and which one is reached. Handles the weekly reset, reports partial coverage honestly, and fails open when the quota can't be read. diff --git a/.changeset/consumption-pause.md b/.changeset/consumption-pause.md deleted file mode 100644 index 087f57d3..00000000 --- a/.changeset/consumption-pause.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Pause a run when a consumption limit is reached. `runFramework` takes a `consumptionGate` consulted between turns; a reached limit stops the run cleanly (like the budget cap) and leaves a `Resume ` entry on the workspace's backlog, so a later run picks the work back up. An unreadable quota carries on rather than stopping the work. diff --git a/.changeset/context-file-chips-661.md b/.changeset/context-file-chips-661.md deleted file mode 100644 index 39170f2a..00000000 --- a/.changeset/context-file-chips-661.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Show the files picked into a run's Context (#661). Files added via a `#` mention or the right-rail file tree were counted ("Context · 1 selected") but never shown, so clearing the prompt left them selected with no way to see or remove them. They now appear inside the Context section, listed like the repo rows but with an X to remove (which also unticks the file in the tree, since they share one context set). The Context section's contents get the same bordered box as the prompt disclosure, and that disclosure is renamed to just "Actual prompt". The Context header now breaks its count down as "N projects · N files", and the right-rail Files tab badge counts only selected files (not the whole-repo entries that also live in the context set). diff --git a/.changeset/context-fragment-tickets.md b/.changeset/context-fragment-tickets.md deleted file mode 100644 index 66c06c26..00000000 --- a/.changeset/context-fragment-tickets.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Expand the run-start context fragment (#683): alongside `DECISIONS.md` and `KNOWLEDGE-BASE.md` the agent now also sees `GOAL.md`, `tickets/**.md` (pointed at the `.the-framework/ticketing-format.md` spec from #684), and the `TODO-AGENTS.md` task queue. The set is split into `CONTEXT_DOCS` (read at start) and the `BUSINESS_KNOWLEDGE_DOCS` subset the agent also updates at merge, so the roadmap/queue pointers are read-only context. diff --git a/.changeset/context-hide-current-project-665.md b/.changeset/context-hide-current-project-665.md deleted file mode 100644 index 71e1da04..00000000 --- a/.changeset/context-hide-current-project-665.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Don't offer the current project as a Context focus target (#665). The Context → Projects list is for pulling *other* repos into the agent's focus; the current project is already the run's workspace, so ticking it was redundant. It's now excluded from the list (and from the "N projects" count), with a "No other repos to add" hint when it's the only registered project. diff --git a/.changeset/context-selector.md b/.changeset/context-selector.md deleted file mode 100644 index 6a4c7c0d..00000000 --- a/.changeset/context-selector.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add the context selector and trust-on-add to the dashboard (#439, part of #314). The Start form gains a "Context" picker — tick the registered repos to focus the agent on, and each becomes one `Context: ` line in the run's system prompt (the agent can still reach every repo; this just narrows where it looks). Threaded through as a repeatable `--context ` CLI flag and `StartRunOptions.context`. Adding a project now asks "do you trust this repository?" first, warning about prompt-injection risk before the agent is given read access. - -Also hardens the daemon's Telefunc mount: a bare `GET /_telefunc` (which a browser tab issues on reconnect) made telefunc throw an unhandled rejection that crashed the daemon; the mount now catches it and returns 400. diff --git a/.changeset/context-two-col-663.md b/.changeset/context-two-col-663.md deleted file mode 100644 index 732d2665..00000000 --- a/.changeset/context-two-col-663.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Lay out the expanded Context section as two columns (#663): a "Projects" column (repo checkboxes) beside a "Files" column (removable file rows), each under its own heading. The Files column shows a hint when nothing is picked, and the repos' "can still reach the rest" note moves to the Projects heading tooltip. diff --git a/.changeset/controls-row-layout-668.md b/.changeset/controls-row-layout-668.md deleted file mode 100644 index 4a4af130..00000000 --- a/.changeset/controls-row-layout-668.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Tidy the run controls row (#668): the Global-options button becomes a gear icon with the on-count as a small corner badge (no "Options" text), the agent/model picker moves to the start of the row, and the "Start run" button sits at the end of that same row (the note/error stay below). diff --git a/.changeset/custom-presets-626.md b/.changeset/custom-presets-626.md deleted file mode 100644 index bc20a33f..00000000 --- a/.changeset/custom-presets-626.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Custom presets (#626): save your own prompts as reusable presets beside the built-in ones. A "+ Preset" button under the prompt textarea captures the current editor text (or a fresh one) under a name; saved presets render as buttons that load their prompt back into the editor, and each has a delete. They persist in the daemon preferences (`customPresets`), sanitized and capped so a hand-edited registry can't bloat the home file. For the users (Rom, nitedani) who keep hand-crafting high-signal prompts, this makes them one click to re-run. diff --git a/.changeset/daemon-foreground.md b/.changeset/daemon-foreground.md deleted file mode 100644 index 3a571a37..00000000 --- a/.changeset/daemon-foreground.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Bare `framework` now runs the dashboard server in the foreground (#456): Ctrl+C stops it, and the server's logs and any errors it throws are visible in the terminal. `framework --daemon` does what bare `framework` used to do, running the dashboard in the background (detached) and returning after printing the convenience commands. If a background daemon is already running, bare `framework` reports its URL and defers instead of fighting for the port. diff --git a/.changeset/daemon-no-nested-self-register-647.md b/.changeset/daemon-no-nested-self-register-647.md deleted file mode 100644 index 9b757c09..00000000 --- a/.changeset/daemon-no-nested-self-register-647.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Stop the daemon from registering its own cwd as a duplicate project. When the daemon runs from a subfolder of an already-tracked repo (e.g. the package dir the binary lives in), it created `.the-framework/` for its own state and then re-added that subfolder as a nested project on every boot. `registerHomeProject` now skips a cwd that lives inside an already-registered project. diff --git a/.changeset/daemon-serves-dashboard.md b/.changeset/daemon-serves-dashboard.md deleted file mode 100644 index 97f40727..00000000 --- a/.changeset/daemon-serves-dashboard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -The daemon can now serve the new Vike + Telefunc dashboard bundle (#405). Opt in with `FRAMEWORK_DASHBOARD=next` (serves the prerendered SPA at `/`, with the legacy `page.ts` at `/legacy`) or `FRAMEWORK_DASHBOARD=legacy` (mounts the Telefunc surface at `/_telefunc` while `page.ts` stays at `/`). Unset keeps today's behavior exactly. The dashboard's read + steer RPCs and the live-event Channel are served in-process at `/_telefunc` (same-origin guarded), backed by a new `@gemstack/framework/dashboard-rpc` subpath; `starting` a run over Telefunc lands next. diff --git a/.changeset/daemon-stop-waits-514.md b/.changeset/daemon-stop-waits-514.md deleted file mode 100644 index c4ee6d0e..00000000 --- a/.changeset/daemon-stop-waits-514.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Fix `framework stop` returning before the daemon has actually exited (#514). It signalled SIGTERM and removed the state file straight away, so restarting immediately raced the old process for the port: the new daemon hit EADDRINUSE, never reported itself ("the daemon did not come up in time"), and the old one kept serving a stale bundle with no state file left to stop it by. `stopDaemon` now waits for the process to exit before returning, escalating SIGTERM to SIGKILL if a wedged shutdown outlasts the grace period. diff --git a/.changeset/dashboard-actions.md b/.changeset/dashboard-actions.md deleted file mode 100644 index 663a25a7..00000000 --- a/.changeset/dashboard-actions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Restore the dashboard actions on the new dashboard (#433): the Start form now carries the Global options (autopilot, technical, vanilla, eco) and the run presets (Research, Readability, Maintainability), the interactive choice gate auto-accepts the recommended pick on an autopilot countdown, a Deploy card shows the chosen render + target, and projects can be added from the Projects sidebar over a new `sendAddProject` telefunction. Adds a browser-safe `deployPlan` projection and the preset builders to `@gemstack/framework/client`. diff --git a/.changeset/dashboard-agent-views-441.md b/.changeset/dashboard-agent-views-441.md deleted file mode 100644 index 2ecd0455..00000000 --- a/.changeset/dashboard-agent-views-441.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Let the agent push ad-hoc markdown views into the dashboard right rail. A `show-markdown` block in a turn (non-blocking, unlike a choice gate) becomes a `view` event that renders as a first-class Views tab in the right rail, with a sticky top-nav to jump between views. Re-showing the same title updates that view in place. diff --git a/.changeset/dashboard-browser-notifications.md b/.changeset/dashboard-browser-notifications.md deleted file mode 100644 index e5af5d79..00000000 --- a/.changeset/dashboard-browser-notifications.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): opt-in browser notifications on the dashboard for run-end and choice gates (#317) - -The localhost dashboard can now notify you when a run finishes (or fails/stops) and when a run reaches a `` gate that needs your input (e.g. a PLAN.md approval). Opt in via the header bell; it only nudges when the dashboard tab is backgrounded, so a run you are watching stays quiet. diff --git a/.changeset/dashboard-center-main.md b/.changeset/dashboard-center-main.md deleted file mode 100644 index be7ac55e..00000000 --- a/.changeset/dashboard-center-main.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Center the dashboard's main grid in the content column. `main` had a `max-width: 1100px` cap but no horizontal centering, so on a wide window the panels hugged the left edge next to the runs sidebar. Add `margin: 0 auto` so the capped grid sits centered. diff --git a/.changeset/dashboard-control-channel.md b/.changeset/dashboard-control-channel.md deleted file mode 100644 index 976902f6..00000000 --- a/.changeset/dashboard-control-channel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Dashboard control channel: the persistent daemon dashboard can now steer any run in its workspace. Its Stop button and choice picks append to `.framework/control.jsonl`; the run tails the file and aborts or resolves its parked gate. Gates now pause whenever a workspace daemon is live, not only when the run owns its own dashboard; headless behavior without a daemon is unchanged. Also fixes the fresh-workspace daemon startup: bare `framework` in a project with no `.framework/` yet used to fail and leave a zombie server on the port. diff --git a/.changeset/dashboard-default-next.md b/.changeset/dashboard-default-next.md deleted file mode 100644 index 59566689..00000000 --- a/.changeset/dashboard-default-next.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -The new Vike + Telefunc dashboard (#405) is now what the daemon serves by default at `/`; the legacy `page.ts` dashboard moves to `/legacy`. Set `FRAMEWORK_DASHBOARD=legacy` to keep `page.ts` at `/` (the escape hatch), and if a build ever ships without the prerendered bundle the daemon falls back to `page.ts` automatically. The `release` flow now runs `bundle:dashboard` so the published package ships the dashboard assets. diff --git a/.changeset/dashboard-document-sidebar.md b/.changeset/dashboard-document-sidebar.md deleted file mode 100644 index d13e429c..00000000 --- a/.changeset/dashboard-document-sidebar.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): document sidebar on the dashboard, rendering the run's PLAN.md / TODO.md (#319) - -The localhost dashboard now surfaces the `PLAN.md` and `TODO.md` the agent writes at the workspace root (via the anti-lazy-pill) in a right sidebar, rendered as markdown with a sticky tab nav to jump between them. A new `GET /api/docs` endpoint reads the surfaced docs (fixed filenames, gated on the workspace `cwd` like `/api/runs`); the sidebar polls it so a plan written mid-run appears, and stays hidden when there are no docs. diff --git a/.changeset/dashboard-editor-preference.md b/.changeset/dashboard-editor-preference.md deleted file mode 100644 index e909e0b6..00000000 --- a/.changeset/dashboard-editor-preference.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add a preferred-editor dashboard preference (#727). "Open in editor" now uses a stored `editor` preference (an editor CLI such as `code`, `cursor`, or `zed`), falling back to `$FRAMEWORK_EDITOR` and then `code` as before. The Settings gear offers a picker that auto-detects the editors installed on the daemon's machine by probing their launchers on PATH (`onEditors`), plus a "Default" entry to clear the choice. A public host, which has no local checkout to open, detects nothing. diff --git a/.changeset/dashboard-layout-fill-height.md b/.changeset/dashboard-layout-fill-height.md deleted file mode 100644 index 5eab17f0..00000000 --- a/.changeset/dashboard-layout-fill-height.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Make the dashboard layout fill the viewport height. `#layout` only grew to its content height, so on a short page the runs-sidebar right border stopped partway down instead of reaching the bottom. Give `#layout` a `min-height: calc(100vh - 57px)` (matching the sidebar's existing header-height key) so the stretched sidebar runs full-height. diff --git a/.changeset/dashboard-overview-437.md b/.changeset/dashboard-overview-437.md deleted file mode 100644 index 9e899531..00000000 --- a/.changeset/dashboard-overview-437.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add an Overview section to the top of the dashboard's first sidebar. It gives a cross-project glance over a new `onOverview` Telefunc read: what the agent is running right now (from each project's live run meta), the total open TODO count across all projects, and the most recently active projects. Clicking any of them selects the project. diff --git a/.changeset/dashboard-overview-page.md b/.changeset/dashboard-overview-page.md deleted file mode 100644 index 3dcc415d..00000000 --- a/.changeset/dashboard-overview-page.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Move the cross-project Overview out of the first sidebar and into a proper dashboard page. The sidebar is now just an "Overview" nav item plus the project list, so it reads as a simple switcher. Selecting Overview (or opening the dashboard with no project picked) shows an at-a-glance landing: KPI tiles (projects, active runs, open TODOs, total runs), a two-week run-activity chart, how past runs ended, what the agent is working on now, the TODO backlog, and a projects table. It is backed by a new `onDashboard` read (a projection of the same run.json / runs/ / TODO files), so nothing new is stored. diff --git a/.changeset/dashboard-port-4200.md b/.changeset/dashboard-port-4200.md deleted file mode 100644 index e20bcfe1..00000000 --- a/.changeset/dashboard-port-4200.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Default dashboard port is now 4200 (was 4477): easier to remember. Pass `--port` to override. diff --git a/.changeset/dashboard-preferences.md b/.changeset/dashboard-preferences.md deleted file mode 100644 index b47cffbd..00000000 --- a/.changeset/dashboard-preferences.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Persist the dashboard's Global options (Autopilot, Technical, Vanilla, Eco) in the same `the-framework.json` as the project list, read and written daemon-side over Telefunc (`onPreferences` / `savePreferences`), so they survive restarts without localStorage (#410). The registry file becomes an object `{ projects, preferences }`; older bare-array files still read and are migrated on the next write. diff --git a/.changeset/dashboard-project-log-panel.md b/.changeset/dashboard-project-log-panel.md deleted file mode 100644 index 89cf95f3..00000000 --- a/.changeset/dashboard-project-log-panel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add a Project log panel to the dashboard (#384). It surfaces the committed `.the-framework/LOGS.md` history (#378/#379) for the workspace: every loop/prompt/build run with its title, status, kind, session link, and a loop's constituent prompts, newest-first. Served by a new `GET /api/logs` endpoint and refreshed on load, on run-end, and on an interval. All fields are escaped and the session link is passed through the page's safe-URL guard, since the log is agent-authored. diff --git a/.changeset/dashboard-queue-438.md b/.changeset/dashboard-queue-438.md deleted file mode 100644 index b5cff1f8..00000000 --- a/.changeset/dashboard-queue-438.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add a cross-project Queue section to the dashboard's first sidebar. It aggregates the open `TODO.md` items across every registered project over a new `onQueue` Telefunc read, so the whole backlog is visible in one place instead of per-selected-project only. Clicking a project in the queue selects it. diff --git a/.changeset/dashboard-read-model.md b/.changeset/dashboard-read-model.md deleted file mode 100644 index 53a1eb88..00000000 --- a/.changeset/dashboard-read-model.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Export `readDocs` + the `WorkspaceDoc` type from the package root, so a separate dashboard can read the same surfaced PLAN/TODO docs the daemon serves (#405 phase 2). diff --git a/.changeset/dashboard-run-history.md b/.changeset/dashboard-run-history.md deleted file mode 100644 index 7a0f1e0c..00000000 --- a/.changeset/dashboard-run-history.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): browse a project's run history in the dashboard (#303) - -The dashboard now has a left sidebar listing a project's past runs (intent, status, session link); clicking one replays that run's projection in the main view, and "Back to live" returns to the current run. Each finished run is archived under `.framework/runs/.jsonl` + `.framework/runs/.json` (a crash that skips the final flush is archived on the next run), and served over `GET /api/runs` and `GET /api/runs/`. Single project only. Closes #303. diff --git a/.changeset/dashboard-run-view.md b/.changeset/dashboard-run-view.md deleted file mode 100644 index a6b36903..00000000 --- a/.changeset/dashboard-run-view.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add event-stream projections for the dashboard's run overview: `loopStatus` and `sessionInfo` derive the production-grade loop status and the live session from a `FrameworkEvent[]`. They plus `formatFrameworkEvent` are re-exported from a new browser-safe `@gemstack/framework/client` subpath (no Node imports), so the dashboard renders the rich run view (loop status and a human-readable event log instead of raw JSON) across the live view, past-run replay, and the relay watch view. diff --git a/.changeset/dashboard-send-start.md b/.changeset/dashboard-send-start.md deleted file mode 100644 index ba8948b0..00000000 --- a/.changeset/dashboard-send-start.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -The new dashboard can now start a run over Telefunc (#405). A `sendStart` telefunction reaches the daemon's own `startRun` closure through the Telefunc request context, so it runs in-process with the one-run-per-project busy guard intact (a second start returns `busy`). Served at `/_telefunc` alongside the read + steer RPCs, same-origin guarded. diff --git a/.changeset/dashboard-start-run.md b/.changeset/dashboard-start-run.md deleted file mode 100644 index 91a51a21..00000000 --- a/.changeset/dashboard-start-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Start runs from the daemon dashboard (#345): a prompt textarea + `POST /api/start` that spawns `framework "" --no-dashboard` as a detached child, with a one-run-at-a-time guard. The started run streams into the page via the tailed event log and is steerable (gates + Stop) through the control channel. diff --git a/.changeset/dashboard-sticky-header-sidebar.md b/.changeset/dashboard-sticky-header-sidebar.md deleted file mode 100644 index 5af808f5..00000000 --- a/.changeset/dashboard-sticky-header-sidebar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Keep the dashboard header and sidebar in view while scrolling. The header is now sticky at the top (with a background and z-index so content scrolls under it), and the app-running banner and the runs sidebar stick just below it. On a long page you no longer lose the title, stop button, and run list when you scroll down. diff --git a/.changeset/dashboard-theme-preference.md b/.changeset/dashboard-theme-preference.md deleted file mode 100644 index 4b81bfb0..00000000 --- a/.changeset/dashboard-theme-preference.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add a `theme` dashboard preference (#725): `system` (the default, following the OS), `light`, or `dark`. Stored in `the-framework.json` alongside the other preferences and sanitized against the known set. The dashboard applies it by toggling the `.dark` class (following live OS changes while on `system`) and exposes a system/light/dark picker in the Settings gear, replacing the previously hardcoded dark-only mode. diff --git a/.changeset/discord-notify-toggle-627.md b/.changeset/discord-notify-toggle-627.md deleted file mode 100644 index 513689ea..00000000 --- a/.changeset/discord-notify-toggle-627.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Per-user Discord toggle for the "needs you" notifications (#627): Discord was env-only (set `DISCORD_WEBHOOK` and it posted). Now a `notifyDiscord` preference (default off) gates the daemon watcher on top of the webhook — the webhook is *where* to post, the preference is *whether* to. It is checked at post time, so the new header toggle (beside the browser bell) takes effect without restarting the daemon, and the watcher keeps its baseline warm while off so flipping it on starts from now rather than blasting the open backlog. diff --git a/.changeset/doc-sidebar-session-scoped.md b/.changeset/doc-sidebar-session-scoped.md deleted file mode 100644 index 66c3c240..00000000 --- a/.changeset/doc-sidebar-session-scoped.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -fix(framework): surface session-scoped PLAN/TODO docs in the dashboard sidebar (#323) - -The document sidebar now also surfaces the session-scoped `PLAN_.agent.md` / `TODO_.agent.md` files The Framework writes per run (#323/#326), not just flat `PLAN.md` / `TODO.md`. Flat files stay supported as a fallback for hand-written docs. Names are matched against the workspace root with a fixed slug pattern, so there is still no path traversal. diff --git a/.changeset/driver-usage-omit-cost.md b/.changeset/driver-usage-omit-cost.md deleted file mode 100644 index 80dafc24..00000000 --- a/.changeset/driver-usage-omit-cost.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Fix the Claude Code driver reporting `costUsd: 0` when a result line carries token usage but no price. `DriverUsage.costUsd` is documented as omitted (never `0`) when there is no price, because the budget cap reads `0` as "this turn was free" rather than "the price is unknown" (#540). The driver now omits the field in that case, matching the Codex driver and the type's own contract. Claude runs that do report a price are unchanged. diff --git a/.changeset/ensure-presets-post-merge.md b/.changeset/ensure-presets-post-merge.md deleted file mode 100644 index 5cbcecc9..00000000 --- a/.changeset/ensure-presets-post-merge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -`runPostMerge` now materializes the quality presets before queueing, so the post-merge TODO entries' `filePath` values always resolve (#598). Previously the presets were written only on install and are gitignored, so a repo activated before that feature shipped, or a fresh clone, had no preset files and the queued entry pointed at a path that did not exist. Best-effort: a materialize failure is reported, never fatal. diff --git a/.changeset/eventstream-iterator-cancel.md b/.changeset/eventstream-iterator-cancel.md deleted file mode 100644 index b0a96e59..00000000 --- a/.changeset/eventstream-iterator-cancel.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/ai-autopilot': patch ---- - -fix(ai-autopilot): EventStream iterators are now cancellable - -A consumer's async iterator gained a `return()` that drops its waiter from the stream and settles any pending `next()`. Previously a consumer that stopped iterating (e.g. a disconnected SSE client) left its waiter registered until the next `push`/`close`, so many short-lived consumers on an idle stream leaked. Live iteration and history replay are unchanged. diff --git a/.changeset/fake-fs-escape-guard.md b/.changeset/fake-fs-escape-guard.md deleted file mode 100644 index ac734a56..00000000 --- a/.changeset/fake-fs-escape-guard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/ai-autopilot": patch ---- - -FakeFs now enforces the same workspace-escape guard as the real runners. Its filesystem previously stored any path as a map key, so a `write('../evil.txt', ...)` that a real runner rejects was silently accepted. Code exercised only against `FakeRunner` never saw the escape path, then threw against Docker/Local/WebContainer. `FakeFs` now routes every path through the shared `safeSegments` guard, rejecting escapes and resolving `.`/`..` exactly as the real runners do. diff --git a/.changeset/file-context-picker-504.md b/.changeset/file-context-picker-504.md deleted file mode 100644 index 013dd76c..00000000 --- a/.changeset/file-context-picker-504.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add `#` to the dashboard prompt editor to reference a project file as run context (#504). The finer-grained sibling of `@` (which focuses a whole repo): type `#` to filter the project's files (via `git ls-files`, honoring .gitignore) and pick one, inserting a chip that adds its repo-relative path to the run Context. Backed by a new `onProjectFiles` read RPC; localhost-only, since the relay has no checkout. diff --git a/.changeset/framework-dashboard-csrf-xss.md b/.changeset/framework-dashboard-csrf-xss.md deleted file mode 100644 index 85435e8e..00000000 --- a/.changeset/framework-dashboard-csrf-xss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Harden the dashboard against cross-site abuse and event-borne XSS. The state-changing dashboard routes (`/stop`, `/choice`, `/api/start`) now reject any request whose `Origin` is a foreign site, so a page on another origin can no longer drive the localhost dashboard into spawning or steering a run (a non-browser caller that sends no `Origin` is unaffected). The client render pipeline no longer trusts event strings: link URLs (session link, preview URL, run-history link) are scheme-checked so a `javascript:` URL collapses to `#`, and the HTML escaper now escapes quotes so a relay-published event can't break out of an attribute (e.g. a choice option id like `x" autofocus onfocus=...`). diff --git a/.changeset/framework-maintain-sweep.md b/.changeset/framework-maintain-sweep.md deleted file mode 100644 index e6e4f75a..00000000 --- a/.changeset/framework-maintain-sweep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add `framework maintain` (#298): a background maintenance sweep. It walks the registered repos, and for each that has grown commits since its last review it runs the maintainability loop on them (`framework prompt`, budget-capped by `--max-cost`, bounded by `--max-repos`). A first-seen repo is baselined (recorded, not reviewed retroactively); per-repo review state lives in `.the-framework/maintenance.json`. `--dry-run` previews the plan. Also exports the maintenance API (`assessRepo`, `planMaintenanceSweep`, `maintainSweep`, review state helpers). diff --git a/.changeset/framework-system-prompt-injection.md b/.changeset/framework-system-prompt-injection.md deleted file mode 100644 index 078fbf85..00000000 --- a/.changeset/framework-system-prompt-injection.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): inject a system prompt into every prompt (anti-lazy-pill + SYSTEM.md) - -Every run is now framed with a built-in system prompt: the validated anti-lazy-pill (#297), which turns unclear scope into a ranked list, a large scope into a `PLAN.md`, and a very large one into a `TODO.md` backlog, so the agent builds a real backend and declares what it descopes instead of silently faking it. Drop a `SYSTEM.md` at the workspace root to add project-specific instructions on top, or set `antiLazyPill: false` in `the-framework.yml` to remove the built-in default. Closes #301. diff --git a/.changeset/global-options-engine-314.md b/.changeset/global-options-engine-314.md deleted file mode 100644 index d427b99a..00000000 --- a/.changeset/global-options-engine-314.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Thread the #314 Global options through the run engine (#370). `POST /api/start` now carries an `options` object which the daemon turns into CLI flags: `--vanilla` removes the built-in #326 system prompt entirely (raw Claude Code), and `--eco-auto-planning` / `--eco-auto-research` / `--eco-auto-maintenance` drop the matching #326 sections to save tokens (Autopilot and Technical keep mapping to modes). `system-prompt.ts` drops the Eco sections at render, so the #343 Prompts panel reflects the toggles live; the #326 template stays byte-identical. The dashboard panel that drives these lands separately (#371); all fields default off, so today's behavior is unchanged. diff --git a/.changeset/global-options-panel-314.md b/.changeset/global-options-panel-314.md deleted file mode 100644 index 7db9f876..00000000 --- a/.changeset/global-options-panel-314.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add the #314 Global options panel to the dashboard (#371). Beside the Start box the daemon dashboard now shows persistent toggles: Autopilot (auto-accept, sharing its key with the choice-panel toggle so the two stay in lockstep), Technical control, Vanilla (remove all system prompts, fully transparent), and Eco with Auto planning / Auto research / Auto maintenance to trim the built-in prompt. Each persists in localStorage and rides along in the `POST /api/start` body, so flipping a toggle changes what the run gets (and, with the engine plumbing in #370, what the #343 Prompts panel shows). Vanilla disables Eco, since a removed prompt has nothing left to trim. diff --git a/.changeset/human-intervention-toggle.md b/.changeset/human-intervention-toggle.md deleted file mode 100644 index 683891b8..00000000 --- a/.changeset/human-intervention-toggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Make the "Needs you" (human intervention) notifications a real toggle (#627). It was always-on before; now it is a default-on `notifyHumanIntervention` preference, so it can be turned off like the other categories. Gates both the browser notification and the daemon's Discord delivery on the category (default on) in addition to the delivery method. diff --git a/.changeset/inject-action-layer-in-build-500.md b/.changeset/inject-action-layer-in-build-500.md deleted file mode 100644 index 40a7358f..00000000 --- a/.changeset/inject-action-layer-in-build-500.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Fix the #326 action-layer protocols being dropped from a build run's system prompt when the built-in prompt is off. `runFramework` nested the `AWAIT_PROTOCOL` and `SIGNAL_PROTOCOL` blocks inside the built-in-prompt branch, so a `--vanilla` build (or `antiLazyPill: false` via `the-framework.yml`) with no `SYSTEM.md` injected neither — leaving the agent with no way to emit `set-session-name` / `ready-for-merge`, so `setReadyForMerge()` and the `--post-merge` quality suite silently never fired. The protocols are now appended unconditionally, matching the direct-prompt path (`runPrompt`). diff --git a/.changeset/interactive-choices-autopilot.md b/.changeset/interactive-choices-autopilot.md deleted file mode 100644 index 4c1c59b6..00000000 --- a/.changeset/interactive-choices-autopilot.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): interactive choice gate + autopilot in the dashboard (#304) - -A run can now pause on a choice and wait for you: the dashboard shows a "Your call" panel with the options. Accept with the button or Ctrl+Enter, or leave the `[x] autopilot` countdown auto-accept the recommended option after 10s (moving the mouse cancels it). New `requestChoice` option on `runFramework`, `choice` / `choice-resolved` events, and a `POST /choice` dashboard route; a headless run with no handler auto-accepts the recommended option, so nothing else changes. Closes #304. diff --git a/.changeset/knowledge-docs-repo-root.md b/.changeset/knowledge-docs-repo-root.md deleted file mode 100644 index fda69af1..00000000 --- a/.changeset/knowledge-docs-repo-root.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Apply Rom's #559 review to the business-knowledge docs (#537): drop `README.md` (a repo's own `README.md` already covers the overview), move `DECISIONS.md` and `KNOWLEDGE-BASE.md` to the repo root, and show each doc's one-line gloss in the injected `Context:` too, not just the post-merge prompt. The `## Business knowledge` prompt text is now his verbatim wording. diff --git a/.changeset/last-activity-includes-runs-645.md b/.changeset/last-activity-includes-runs-645.md deleted file mode 100644 index 7d643bd6..00000000 --- a/.changeset/last-activity-includes-runs-645.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Fix "last activity" so it reflects runs, not just `LOGS.md`. A project's `lastActivityAt` is now the newest of its latest `LOGS.md` entry and its most recent run (live or archived), so a project with runs no longer reads "no activity yet" just because a run stopped before writing to `LOGS.md`. diff --git a/.changeset/lifecycle-signals-326.md b/.changeset/lifecycle-signals-326.md deleted file mode 100644 index 3edc8452..00000000 --- a/.changeset/lifecycle-signals-326.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the `setSessionName()` and `setReadyForMerge()` lifecycle signals (#326). Both are non-blocking turn-boundary signals, the same shape as the existing `show-markdown` view: the agent emits a fenced `set-session-name` / `ready-for-merge` block and keeps working, and the framework records it and reflects it in the dashboard. `setSessionName()` labels the run with the `[a-z0-9-]` slug it chose (also its `the-framework/` branch); `setReadyForMerge()` flips the run's status from building to ready-for-review. The dashboard shows the session name and a status dot (amber while building, green once ready) in both the run overview and the cross-project "working now" list. This is the signal the post-merge quality suite will hang off. diff --git a/.changeset/live-run-in-runs-list.md b/.changeset/live-run-in-runs-list.md deleted file mode 100644 index 7b8da82f..00000000 --- a/.changeset/live-run-in-runs-list.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Dashboard: show the live run in the Runs rail with a RUNNING status. The in-progress run now appears as the top row of the list (pulsing dot, RUNNING badge, and the prompt), matching the history rows, instead of being hidden behind the abstract "Live" button; clicking it follows the live stream as before. `onRuns` prepends the live run (from `run.json`) when one is running, and the Start form seeds an optimistic row so the run shows the instant you click Start, before the spawned process writes its `run.json`. diff --git a/.changeset/maintainability-preset-361.md b/.changeset/maintainability-preset-361.md deleted file mode 100644 index 19b075b8..00000000 --- a/.changeset/maintainability-preset-361.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -New [Maintainability] preset button on the dashboard (#361): prefills the deliberately minimal refactor-for-future-changes prompt ("look for maintainability red flags, and fix them") into the start textarea for review or editing; Start runs the text verbatim as a direct prompt run. The one blank, ``, defaults to `this PR`. diff --git a/.changeset/multi-project-daemon-reads.md b/.changeset/multi-project-daemon-reads.md deleted file mode 100644 index 3a7e1458..00000000 --- a/.changeset/multi-project-daemon-reads.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Make the dashboard multi-project on the read side: `GET /api/projects` lists the registered projects (from the registry) with a per-project summary (name, activated, last activity), and `?project=` on `/api/logs`, `/api/runs`, `/api/runs/`, and `/api/docs` reads that project's data (an absent id keeps the daemon's own workspace, single-project back-compat). The daemon auto-registers its own workspace on boot when it is activated, so the Projects list is populated for the common single-project case. Live event streaming and per-project run start/stop stay single-project for now. Adds `ProjectSummary` / `ProjectsProvider` / `summarizeProject` / `defaultProjectsProvider`. diff --git a/.changeset/multi-project-install-core.md b/.changeset/multi-project-install-core.md deleted file mode 100644 index 87e2466d..00000000 --- a/.changeset/multi-project-install-core.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the install-core module: `installProject(cwd)` activates a repo for The Framework by creating the `.the-framework/` marker with a seeded `LOGS.md`, committing any pre-existing dirty changes first (`[The Framework] uncommitted changes`) so the install commit (`[The Framework] install The Framework`) is clean; an already-activated repo is a no-op. Also `enumerateGitRepos(dir)` lists the immediate child directories that are their own git repo roots (for the "add a directory of repos" flow). Pure core over the existing `GitRunner` + `StoreFs` seams; any git failure surfaces as a value, never a throw. No daemon or UI wiring yet. diff --git a/.changeset/multi-project-registry-module.md b/.changeset/multi-project-registry-module.md deleted file mode 100644 index b5e81115..00000000 --- a/.changeset/multi-project-registry-module.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the multi-project registry module: reads and writes the list of projects The Framework is installed into, as a small `{id, path, addedAt}` JSON index under the user's config dir. Exposes `projectId`, `registryPath`, `listProjects`, `addProject`, `removeProject`, and an injectable `RegistryFs` seam with a `nodeRegistryFs()` adapter. No daemon or UI wiring yet. diff --git a/.changeset/multi-select-gate-332.md b/.changeset/multi-select-gate-332.md deleted file mode 100644 index 17489158..00000000 --- a/.changeset/multi-select-gate-332.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add a multi-select gate (`showMultiSelect()`): a dashboard checklist with pre-checked defaults that pauses the run and resolves to the selected subset. Built on the existing single-select choice gate (same panel and POST-back resolver), exposed as `requestMultiSelect()`; a headless run auto-accepts the default set. This is the primitive the [Research] preset uses to let the user pick which problems to deep-dive. diff --git a/.changeset/multiselect-turn-boundary-gate.md b/.changeset/multiselect-turn-boundary-gate.md deleted file mode 100644 index a5189e18..00000000 --- a/.changeset/multiselect-turn-boundary-gate.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): turn an agent's showMultiSelect()+AWAIT into a live checklist gate (#339) - -The multi twin of the single-select turn-boundary gate (#337). When a build turn ends on an `await-multiselect` block, the framework shows a checklist on the dashboard (via `requestMultiSelect`, with the agent-marked defaults pre-checked), waits for the selection, and re-prompts the agent to continue from it. This is what the research preset needs to let the user pick which problems to deep-dive. Same safety as #337: a no-op when headless and when the agent just finishes. diff --git a/.changeset/nervous-donkeys-invent.md b/.changeset/nervous-donkeys-invent.md deleted file mode 100644 index 0d543c90..00000000 --- a/.changeset/nervous-donkeys-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Report a failed relay publish instead of dropping it. `relayPublisher` never checked the HTTP response, so only a thrown fetch reached `onError` and every error status was silent: `--share ` printed a shareable link and then reported nothing, forever. diff --git a/.changeset/new-activity-discord-627.md b/.changeset/new-activity-discord-627.md deleted file mode 100644 index 1a81ee33..00000000 --- a/.changeset/new-activity-discord-627.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Discord delivery for the "New activity" notifications category (#627): the daemon now also watches the run activity feed and posts to Discord when a run starts or finishes, so the default-off activity category reaches you with no dashboard open — the same path the interventions watcher uses for the "needs you" queue. Double-gated at post time so the header toggles take effect without a daemon restart: both the category (`notifyNewActivity`) and the Discord method (`notifyDiscord`) must be on, on top of a `DISCORD_WEBHOOK` being set. The runs already going when the daemon starts are folded into a baseline (no start-up blast). Completes the browser + Discord matrix for both notification categories. diff --git a/.changeset/new-activity-notifications-627.md b/.changeset/new-activity-notifications-627.md deleted file mode 100644 index 36adc51b..00000000 --- a/.changeset/new-activity-notifications-627.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -"New activity" notifications (#627): a default-off notification *category* alongside the always-on "needs you" one. Turn it on (the new Activity toggle in the header, beside the browser bell and Discord toggle) and you get a ping when a run starts and when it finishes, not just when something needs you. It is a category, not a method, so it rides whichever delivery methods are on: browser notifications when the bell is on. A cross-project `onActivity` feed (`buildActivity`) drives it, diffed the same way as the interventions queue, so the runs already going when the page loads are folded into a baseline rather than announced. diff --git a/.changeset/notifications-menu.md b/.changeset/notifications-menu.md deleted file mode 100644 index 85942752..00000000 --- a/.changeset/notifications-menu.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Consolidate the dashboard header's three notification icons (browser bell, Discord, activity pulse) into one labeled "Notifications" bell that opens a popover (#676). The popover groups the toggles the way the model actually works: a "Deliver to" section (Browser, Discord) for where notifications go, and a "Notify me about" section where "Needs you" is shown as always-on and "New activity" is an opt-in toggle. The bell shows an active state and dot when a delivery method is on. Purely the header control; the underlying preferences and notification hooks are unchanged. diff --git a/.changeset/olive-pumas-shake.md b/.changeset/olive-pumas-shake.md deleted file mode 100644 index 8826885f..00000000 --- a/.changeset/olive-pumas-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework-dashboard': patch ---- - -Stop dropping failed dashboard reads. Every panel wrote its own async effect and only the usage panel caught, so a daemon restart made each of the others an unhandled rejection every tick. They now share two hooks (`useLoaded`/`usePolled`) that keep the last value through a failed read, reset on a project switch rather than showing the previous project's data, and retire an in-flight read on unmount — including the Runs rail's `reload`, which was unguarded and could write a stale project's runs. diff --git a/.changeset/on-before-mergeable-no-branch.md b/.changeset/on-before-mergeable-no-branch.md deleted file mode 100644 index 4544fd7b..00000000 --- a/.changeset/on-before-mergeable-no-branch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -The on-before-mergeable follow-up no longer strands its output on a branch nothing merges. It was spawned as a plain `framework prompt` run, so it inherited the #326 system prompt's `### Session name` step and committed + created + checked out a fresh `the-framework/` branch before writing anything. Its output (the queued quality TODO entries and the business-knowledge docs, `DECISIONS.md` / `KNOWLEDGE-BASE.md`) landed on that branch, which nothing merges, so the next run branched from main and could not see it. The follow-up is a follow-up to a session, not a session of its own, so it now runs `--vanilla` (no built-in prompt, hence no session-name step) and stays on the session's current branch, where its output rides to review and merge with the work. diff --git a/.changeset/one-jsonl-tailer.md b/.changeset/one-jsonl-tailer.md deleted file mode 100644 index bd196794..00000000 --- a/.changeset/one-jsonl-tailer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Fix the dashboard's event tail dropping a same-length rewrite. There were two JSONL tailers: `JsonlTailer` detects an in-place truncate both by the file shrinking and by it being rewritten to the same length (mtime advanced), while `tailEvents`, which is what the dashboard Channel runs, only checked for a shrink and never read mtime. A fresh run that rewrote `events.jsonl` to the same byte length was invisible to the dashboard. The two tailers, and the two hand-rolled `fs.watch`-plus-poll drivers behind them, are now one `JsonlTailer` + one `followFile`, so the run's control tail and the dashboard's event tail share the tested behavior instead of drifting. `tailEvents` had no test of its own; it has three now. diff --git a/.changeset/optional-cost.md b/.changeset/optional-cost.md deleted file mode 100644 index 07b59088..00000000 --- a/.changeset/optional-cost.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Report an agent's tokens when it reports no price. `DriverUsage.costUsd` is now optional: tokens are what every agent reports, a price is what only some do. Codex reported real token counts that we were dropping on the floor, and now surfaces them; a run with no price shows `tokens: 13,570 (5 out)` rather than nothing at all, and never a `$0` that would read as free. Claude runs are unchanged and still show their spend line. - -The spend cap only ever fires on a reported price, so it stays Claude-only and the CLI says so rather than implying otherwise. We deliberately do not invent prices from a model table: that number would go stale silently, and under a subscription nobody is billed per token anyway. What a subscription actually spends is quota, which the consumption limits gate on. diff --git a/.changeset/panel-file-tree-492.md b/.changeset/panel-file-tree-492.md deleted file mode 100644 index 99227db8..00000000 --- a/.changeset/panel-file-tree-492.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add a file tree to the dashboard's project panel (#492). It lives as the first tab in the right rail (Files · Docs · Log) and is a file-level context picker: a lazy, collapsible tree (animate-ui Files) built from `git ls-files`, where ticking a file adds it to the run Context — the same set the `#` picker and whole-repo Context selector feed. Per-file git-status dots (untracked/modified/deleted) come from a new `onProjectFileStatus` RPC, rolled up to folders. - -Also refines the project action bar: git status folds inline on the left; Open on GitHub / Open folder / Open in editor become icon-only buttons with tooltips (a small Base UI Tooltip, no Radix added); and Preview is renamed Serve — a play button that becomes a segmented Open ↗ / Stop ⏹ control while serving. diff --git a/.changeset/per-project-daemon-393.md b/.changeset/per-project-daemon-393.md deleted file mode 100644 index 859d2299..00000000 --- a/.changeset/per-project-daemon-393.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Per-project daemon runs + one daemon per machine (#393). Dashboard-started runs, Stop, and choice picks now carry the viewed project id, so the daemon spawns each run with that project's `--cwd`, steers it through that project's own control log, and guards one run per project. Daemon liveness moved from a per-workspace `.the-framework/daemon.json` to a single global file beside the registry (`$XDG_CONFIG_HOME/the-framework-daemon.json`), so `framework` and `framework stop` in any repo find the same daemon. Per-project live event streaming is folded in with the dashboard rebuild (#405). diff --git a/.changeset/per-run-new-dashboard.md b/.changeset/per-run-new-dashboard.md deleted file mode 100644 index f0eb61d6..00000000 --- a/.changeset/per-run-new-dashboard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Serve the new Vike + Telefunc dashboard for per-run foreground runs and `--resume`, not just the daemon. `framework ""` and `framework --resume` now serve the rebuilt dashboard in single-project mode, scoped to that run's workspace without touching the global registry, and the live run steers over its own `.the-framework/control.jsonl` even with no daemon running. Falls back to the legacy `page.ts` when the bundle is absent or `--no-persist` is set. Adds `singleProjectProvider` and `resolveDashboardBundle` to the public surface. diff --git a/.changeset/persistent-dashboard-daemon.md b/.changeset/persistent-dashboard-daemon.md deleted file mode 100644 index a5da1ddc..00000000 --- a/.changeset/persistent-dashboard-daemon.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): persistent background dashboard daemon (#302) - -Bare `framework` now ensures a long-lived dashboard process for the workspace and prints its URL plus the convenience commands; `framework stop` shuts it down. The dashboard is a projection of `.framework/events.jsonl`: the detached daemon tails the log and pushes each new event to connected browsers, so it outlives any single run. The tailer also detects an in-place truncation when a fresh run rewrites the log to the same byte length (size unchanged but mtime advanced), and the daemon spawn refuses to re-exec a test entry so a `node --test` run can never fork-bomb itself. diff --git a/.changeset/post-merge-quality-suite-326.md b/.changeset/post-merge-quality-suite-326.md deleted file mode 100644 index d9897a73..00000000 --- a/.changeset/post-merge-quality-suite-326.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the post-merge quality suite (#326): when a run signals `setReadyForMerge()`, optionally fire the maintainability, readability, and security-audit passes over the same workspace. Enabled per run by the new `--post-merge` CLI flag, or from the dashboard's Global options via a "Post-merge cleanup" toggle (persisted as the `postMergeQuality` preference, mapped to `--post-merge` on the spawned run). The three passes run **sequentially** — they edit and commit the same git tree, so concurrent writers would race on the index lock; worktree-isolated parallelism is a follow-up. Each pass is a plain `framework prompt` child carrying no `--post-merge`, so a quality pass never triggers its own suite. Off by default. diff --git a/.changeset/post-merge-todo-entries-556.md b/.changeset/post-merge-todo-entries-556.md deleted file mode 100644 index 60901470..00000000 --- a/.changeset/post-merge-todo-entries-556.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Post-merge now queues the quality follow-ups instead of running them (#556), which is what the #326 doc says and what composes with the backlog loop (#323/#538). On `setReadyForMerge()`, a `--post-merge` run used to fire maintainability, readability and security-audit as three child `framework prompt` runs back to back, on the spot. It now fires one short turn that appends "Apply preset X on the changes introduced by " entries to the session's TODO file, and lets the loop pick them up. Cheaper by a lot: a few TODO lines rather than three full preset passes serialized on the same git index. - -The readability entry is gated on Technical control, per the doc. That setting already existed as a preference, a `--technical` flag and a Global options toggle; it just never reached the prompts, so `TfContext` gains `settings.technical_control` and `session_name`. The session name is carried on run state: the agent sets it before its first change and the post-merge prompt reads it afterwards. - -`--eco-auto-maintenance` does something again. #326 moved the maintenance section out of the system prompt, which left the flag inert (#555); the post-merge prompt is exactly that section, so the flag now skips it. - -The post-merge prompt is flattened rather than verbatim from the doc, and this is the one place the prompts depart from it. The doc nests `${{ tf.session_name }}` inside the outer `${{ ... }}` and puts backticks inside a backtick template literal; the fragment regex is non-greedy, so the outer fragment closes on the inner `}}` and what is left is not valid JS. It throws `TemplateFragmentError` today, with or without the new context fields. Same branch, same output, one fragment, and a test now rejects any nested fragment so the prompt cannot regress into a shape that will not render. - -`POST_MERGE_PASSES` and `runPostMergeSuite` are replaced by `runPostMerge` and `renderPostMergePrompt`. The three preset modules are untouched: the dashboard buttons still use them. diff --git a/.changeset/preset-filepath.md b/.changeset/preset-filepath.md deleted file mode 100644 index 5967f0b1..00000000 --- a/.changeset/preset-filepath.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Post-merge TODO entries now carry the preset's `filePath` instead of a bare preset name (#326). The entry reads `Apply .the-framework/presets/.md with tf.params.what set to "changes introduced by "`, and `installProject` materializes the presets into `.the-framework/presets/*.md` so that path resolves to a real file the picked-up agent opens. Closes the fidelity gap where the queue sent a preset name and the agent had to guess the prompt. The materialized presets are gitignored (regenerated on install, tracking the framework version). New: `PRESETS`, `PRESET_DIR`, `presetFilePath`, `presetContext`, `materializePresets`. diff --git a/.changeset/preset-params-330.md b/.changeset/preset-params-330.md deleted file mode 100644 index ccd60ce5..00000000 --- a/.changeset/preset-params-330.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add preset-prompt param substitution (``), the foundation for prompt-preset buttons. A preset prompt template can carry `` placeholders substituted from supplied values or declared defaults; unfilled params are surfaced so a caller can ask the user to fill the blanks. diff --git a/.changeset/preset-params-fragments.md b/.changeset/preset-params-fragments.md deleted file mode 100644 index adef8b4a..00000000 --- a/.changeset/preset-params-fragments.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Standardize the preset prompts on the `${{ tf.params.what }}` fragment syntax (the same the system prompt uses) and retire the bespoke `` primitive. `renderPrompt(what)` is unchanged and produces byte-identical output; the removed exports (`renderPresetPrompt`, `PARAM_PATTERN`, `extractParamNames`, `unfilledParams`, `PresetParamError`, `PresetParam`, `PresetParamOptions`) had no other consumers. Prereq for #326's post-merge preset `filePath` entries. diff --git a/.changeset/presets-dropdown-649.md b/.changeset/presets-dropdown-649.md deleted file mode 100644 index e22172b9..00000000 --- a/.changeset/presets-dropdown-649.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Collapse the Start-form preset controls into one "Presets" dropdown (shadcn base / Base UI). The built-in presets, the user's saved presets (each removable), and "New preset…" now live in a single menu instead of a row of buttons, keeping the prompt area compact as presets grow. diff --git a/.changeset/presets-prefill-textarea.md b/.changeset/presets-prefill-textarea.md deleted file mode 100644 index 9ca103dc..00000000 --- a/.changeset/presets-prefill-textarea.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Dashboard presets only prefill the textarea (#353): the [Research] button now loads the full rendered preset prompt for review and editing, and nothing runs until Start / Ctrl+Enter. The edited text is sent verbatim via a new `prompt` start kind and `framework prompt ` subcommand (the direct path: gates honored, no build pipeline). Clearing the box reverts Start to a normal build run. diff --git a/.changeset/preview-button-475.md b/.changeset/preview-button-475.md deleted file mode 100644 index cfe5b335..00000000 --- a/.changeset/preview-button-475.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add a dashboard **Preview** button (#475): serve a project's built result on demand, decoupled from an agent run. One click runs the project's dev script (`dev`/`start`/`preview`/`serve`) and surfaces the live localhost URL it announces, with a **Stop** to tear it down; a project with a plain `index.html` and no dev script is served by a built-in static server instead. The preview lives in the daemon (one per project, idempotent to open) and is torn down on daemon shutdown; the button rehydrates after a reload. A preview that exits on its own (a crash, a build error) is evicted so the next open restarts it rather than handing back a dead URL. Exposed as three Telefunc RPCs (`sendPreview` / `sendStopPreview` / `onPreviewStatus`) and the `startPreview` helper. diff --git a/.changeset/project-git-status.md b/.changeset/project-git-status.md deleted file mode 100644 index 317f9026..00000000 --- a/.changeset/project-git-status.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add a git-status line to the dashboard project panel: the active branch, a clean/dirty indicator, and the linked PR (number, state, link). Backed by a new `onGitStatus` read; branch and dirty come from git, the PR is a best-effort `gh` lookup that degrades to nothing when gh is missing/unauthed or there is no PR. Hidden when the project is not a git repo. diff --git a/.changeset/project-open-in-app.md b/.changeset/project-open-in-app.md deleted file mode 100644 index d7a24d32..00000000 --- a/.changeset/project-open-in-app.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add "Open folder" and "Open in editor" buttons to the dashboard project panel (localhost-only). The daemon spawns the OS file manager (open / xdg-open / explorer) or an editor (the `code` CLI, or `$FRAMEWORK_EDITOR`) on the project's own path. A missing command surfaces a friendly error. Safe on a public host: no local checkout to resolve, so nothing is spawned. diff --git a/.changeset/project-open-on-github.md b/.changeset/project-open-on-github.md deleted file mode 100644 index 88deba5b..00000000 --- a/.changeset/project-open-on-github.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add an "Open on GitHub" button to the dashboard project panel. When the repo has a github.com `origin` remote, the panel shows a one-click link to it (backed by a new `onGithubUrl` read that normalizes the ssh/https remote forms). Hidden when there is no GitHub remote, so it never shows empty. diff --git a/.changeset/project-second-sidebar.md b/.changeset/project-second-sidebar.md deleted file mode 100644 index f04903f3..00000000 --- a/.changeset/project-second-sidebar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the per-project second sidebar and main view. The second sidebar now shows the selected project's loops/prompts (its `.the-framework/LOGS.md`, scoped via `?project=`) with its Runs archive below it, both following the selection. The main view shows the selected or latest loop/prompt claude.ai/code-style (kind, title, status, session link, and a loop's constituent prompts); clicking a loop in the sidebar opens it. On load the most recently active project is auto-selected, so the view is populated immediately. diff --git a/.changeset/projects-sidebar.md b/.changeset/projects-sidebar.md deleted file mode 100644 index 4399e2c4..00000000 --- a/.changeset/projects-sidebar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the Projects sidebar to the dashboard: a leftmost nav with Overview (project count plus the most recently active projects), Projects (every registered project with an activation dot and last-activity, from `/api/projects`), and Queue (the open TODO items aggregated across all projects). Selecting a project re-points the project log to `?project=`. The per-project second sidebar and main view come next. diff --git a/.changeset/queue-awaiting-intervention-636.md b/.changeset/queue-awaiting-intervention-636.md deleted file mode 100644 index 3c1b8fb7..00000000 --- a/.changeset/queue-awaiting-intervention-636.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Queue "needs you" now surfaces paused runs, not just PRs (#636, part of #624): a live run that stopped mid-flight to ask a question shows up alongside open PRs in the Overview card, the sidebar badge, and the #627 browser + Discord notifications. `RunMeta` folds a `pendingChoice` from the `choice`/`choice-resolved` events, and `Intervention` gains a second `kind: 'awaiting'` — the card jumps into that project to answer, and the Discord message reads "awaiting your answer" with a link back to the dashboard. diff --git a/.changeset/queue-discord-notify-627.md b/.changeset/queue-discord-notify-627.md deleted file mode 100644 index 0a4ed499..00000000 --- a/.changeset/queue-discord-notify-627.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Discord notifications for the Queue's "needs you" list (#627): when `DISCORD_WEBHOOK` is set, the daemon watches the interventions queue and posts a message when a new PR lands — so you are notified even with no dashboard open. The PRs already open when the daemon starts are folded into a baseline (no start-up blast); the env var is the opt-in. Complements the in-browser notifications from the same queue. diff --git a/.changeset/queue-interventions-632.md b/.changeset/queue-interventions-632.md deleted file mode 100644 index 7968e98c..00000000 --- a/.changeset/queue-interventions-632.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add the Queue's cross-project "needs you" projection (#632, part of #624): `buildInterventions` rolls up every registered project's open, non-draft PRs (via `gh pr list`, degrading to empty with no remote / no gh), newest first, and exposes them over a new `onInterventions()` dashboard read. This is the first slice of the interventions queue — proposals and finished work both surface as PRs to review or close. diff --git a/.changeset/queue-notifications-627.md b/.changeset/queue-notifications-627.md deleted file mode 100644 index 8471fdbe..00000000 --- a/.changeset/queue-notifications-627.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Browser notifications for the Queue's "needs you" list (#627): when a new PR lands on the interventions queue, the dashboard fires a browser notification that opens the PR on click. A bell in the header toggles it and requests permission; the preference (`notifyBrowser`, on by default) persists with the others. Existing PRs at page load are folded into a baseline, so you are only told about items that appear while you are watching. (Discord delivery and the paused-run trigger are follow-ups.) diff --git a/.changeset/quota-panel-reads.md b/.changeset/quota-panel-reads.md deleted file mode 100644 index b6b7df16..00000000 --- a/.changeset/quota-panel-reads.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Serve the usage panel's numbers: an `onQuota` RPC returning the account's quota windows plus where the consumption limits stand, backed by a quota source the daemon polls for its whole life (the per-run guard dies with its run, but the panel has to show the account while nothing is running). A host with no agent to ask reports it has no reading rather than an empty one. diff --git a/.changeset/quota-poller.md b/.changeset/quota-poller.md deleted file mode 100644 index 442afbf4..00000000 --- a/.changeset/quota-poller.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add `QuotaPoller`: keeps the account's quota reading fresh on a slow timer and feeds the consumption meter. Backs off when the agent's usage fetch is refused rather than retrying into the penalty window, gives up on an authoritative failure, and keeps the last good reading across a transient one. diff --git a/.changeset/quota-readout.md b/.changeset/quota-readout.md deleted file mode 100644 index f4eafcfb..00000000 --- a/.changeset/quota-readout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Read the account's subscription quota on demand via the agent's own `/usage` command, as `Driver.readQuota()`. Reports the percentage of each window consumed (session, week, per-model week), which is what a consumption limit needs and what the per-turn rate-limit telemetry could not give. Costs no tokens, and the CLI reaches Anthropic with its own credentials, so The Framework never handles the user's token. diff --git a/.changeset/rate-limit-telemetry.md b/.changeset/rate-limit-telemetry.md deleted file mode 100644 index ec4185c7..00000000 --- a/.changeset/rate-limit-telemetry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Capture the agent's rate-limit telemetry. Claude Code reports where the account's subscription quota stands on every turn of its `stream-json` output, and the parser was dropping it. It now surfaces as a `rate-limit` driver event carrying the status, the quota window, and when that window resets, so it persists and reaches the dashboard like any other driver event. New `DriverRateLimit` type. diff --git a/.changeset/readability-preset-360.md b/.changeset/readability-preset-360.md deleted file mode 100644 index 57f1c289..00000000 --- a/.changeset/readability-preset-360.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -New [Readability] preset button on the dashboard (#360): prefills Rom's refactor-for-human-readers prompt (architectural seams, linearity/altitude pass, exhaustive per-function rating lists, one commit per refactor) into the start textarea for review or editing; Start runs the text verbatim as a direct prompt run. The one blank, ``, defaults to `this PR`. diff --git a/.changeset/reconcile-orphaned-runs-642.md b/.changeset/reconcile-orphaned-runs-642.md deleted file mode 100644 index f552eccc..00000000 --- a/.changeset/reconcile-orphaned-runs-642.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Reconcile orphaned runs on daemon start. A run a dead process left marked `running` (a crash, kill, or daemon restart) no longer shows as active forever with a no-op Stop: a freshly started daemon drives no in-flight run, so at boot any such run across registered projects is flipped to `stopped` (the live one archived first, keeping its history). diff --git a/.changeset/registry-single-file.md b/.changeset/registry-single-file.md deleted file mode 100644 index 9ed8eac5..00000000 --- a/.changeset/registry-single-file.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Store the multi-project registry as a single file, `.bashrc`-style: `$HOME/.the-framework.json` (or `$XDG_CONFIG_HOME/the-framework.json`) instead of a `projects.json` nested inside a `.the-framework/` directory (#390). diff --git a/.changeset/relay-body-bytes.md b/.changeset/relay-body-bytes.md deleted file mode 100644 index f1a4bb65..00000000 --- a/.changeset/relay-body-bytes.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Fix the relay's publish-body reader corrupting multibyte payloads and mis-applying its size cap. It decoded each TCP chunk independently (`body += chunk`), so a multibyte UTF-8 codepoint split across a chunk boundary decoded to replacement characters; and it compared the running string's `.length` (UTF-16 code units) against `maxBodyBytes`, so the cap was wrong for any non-ASCII body. It now accumulates raw `Buffer`s, caps on the byte count, and decodes once at the end. diff --git a/.changeset/relay-new-dashboard.md b/.changeset/relay-new-dashboard.md deleted file mode 100644 index 4adf84b4..00000000 --- a/.changeset/relay-new-dashboard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Serve the new Vike + Telefunc dashboard from the run relay (`--share`), in a read-only watch mode. The relay now serves the prerendered SPA and streams events over the same Telefunc `onEvents` Channel the daemon uses, sourced from its in-memory run instead of a file. Only the live event stream is exposed (an empty projects provider neutralizes the file/registry RPCs on the public host, and no run can be started or steered). The shareable viewer URL moves from `/r/:id/` to `/?run=:id` (old links redirect); ingest stays at `/r/:id/publish`. This removes the relay's dependency on the legacy `page.ts`. Adds `makeTelefuncMount`, `serveClientBundle`, `emptyProjectsProvider`, and the `EventsSource` type to the public surface. diff --git a/.changeset/relay-sandbox-hardening.md b/.changeset/relay-sandbox-hardening.md deleted file mode 100644 index 473cf38d..00000000 --- a/.changeset/relay-sandbox-hardening.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -fix(framework): harden the run relay and workspace sandbox against resource exhaustion - -- The relay now caps how many runs it holds in memory and evicts the least-recently-used one on overflow. Because it is unauthenticated, an anonymous request to `/r//…` could previously create per-run state that was never freed; run creation is now bounded (`maxRuns`, default 200). -- A disconnected SSE viewer now cancels its stream iterator, releasing its waiter immediately instead of lingering on the stream until the next event (which may never arrive for an idle run). -- `snapshotWorkspace` checks a file's size before reading it, so a large asset in the workspace is skipped without ever being loaded into memory during a `--sandbox docker` sync. -- `relayPublisher`'s POST has a timeout, so a relay that accepts a connection but never responds can no longer hang the CLI on exit (`flush()`). diff --git a/.changeset/remove-architect-545.md b/.changeset/remove-architect-545.md deleted file mode 100644 index 831a8a8f..00000000 --- a/.changeset/remove-architect-545.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@gemstack/framework': minor -'@gemstack/ai-autopilot': minor ---- - -Remove the architect. A build no longer runs a turn to pick the app's stack, and no longer tells the agent what to build on: the agent reads the workspace and decides for itself, the same way it would outside The Framework. `buildPrompt` / `extendPrompt` / `scaffoldPrompt` now take just the intent and say nothing about a stack. - -Being opinionated about the stack is a hard thing to do well, and a system prompt that nudges one is worse than none at all (#545). The stack guidance we had was not designed, it accumulated. It goes rather than half-ships. - -Gone with it, because the architect was their only source: - -- the plan-approval gate ("Approve this plan?" / "Use X instead") and re-architect. The agent-authored await gates a build turn raises are unaffected: a build that stops to ask still pauses the run with Approve / Decline. -- the decisions ledger in a run, and the `DECISIONS.md` a run wrote from it. `@gemstack/ai-autopilot`'s `decisions/` module is untouched and still exported; nothing in a run feeds it now. -- the dashboard's "Stack & rationale" and "Decisions ledger" panels. Loop status, deploy, and session cards are unchanged. -- `@gemstack/ai-autopilot`: `agentArchitect`, `STACK_TRADEOFFS`, `BootstrapSteps.architect`, `BootstrapOptions.ledger`, the `architect` bootstrap event, `ArchitectPlan` / `ArchitectContext` / `ArchitectDecision` / `ArchitectAlternative`, and the `plan` field on the build / loop / deploy contexts and on `BootstrapResult`. The flow is now scope -> build -> loop -> deploy. -- `@gemstack/framework`: `driverArchitect`, `reArchitect`, `architectPrompt`, `parseArchitectPlan`, `architectPlan`, `decisionLedger`, `RunFrameworkResult.ledger`, and the `bench:architect` benchmark. diff --git a/.changeset/remove-header-stack-text.md b/.changeset/remove-header-stack-text.md deleted file mode 100644 index b99a01c6..00000000 --- a/.changeset/remove-header-stack-text.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Remove the "Vike · React · shadcn · Telefunc" tech-stack line from the dashboard header. diff --git a/.changeset/remove-meta-select-545.md b/.changeset/remove-meta-select-545.md deleted file mode 100644 index e99ebc3a..00000000 --- a/.changeset/remove-meta-select-545.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Remove AI meta-select. A run no longer spends an agent turn guessing which Open Loop domain preset, modes, and build event kind to run under; a preset is used only when you ask for one with `--preset` or `the-framework.yml`, and otherwise the plain framework flow runs. - -The routing turn injected a prompt of its own before the build started, which meant part of what the agent ran under was chosen mid-run by another model rather than by the user (#545). Removing it also makes a run's prompt knowable before it starts. - -Gone with it: the `--no-auto-preset` flag (there is nothing left to opt out of), the `autoSelectPreset` / `workspaceSummary` / `metaSelect` / `presetCatalog` / `parseMetaSelection` / `META_SELECT_*` exports, and the `bench:meta-select` benchmark. diff --git a/.changeset/remove-persona-skill-memory-547.md b/.changeset/remove-persona-skill-memory-547.md deleted file mode 100644 index 2d3442b6..00000000 --- a/.changeset/remove-persona-skill-memory-547.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@gemstack/framework': minor -'@gemstack/ai-autopilot': minor ---- - -Remove the persona, skill, and project-memory framing. A run's system prompt is now the built-in #326 prompt plus your own `SYSTEM.md`, and nothing else. Nothing is read off disk and appended when the run starts. - -A build used to append the personas and skills for its detected stack plus the full contents of the repo's memory files. On one measured 8,852-character build prompt that framing was about 5,000 characters, more than the designed prompt it was wrapping. None of that text was designed; it accumulated. Prompt text nobody reviewed is a defect, not a feature (#547). - -Two things fall out of this: - -- **The prompt preview is now exact.** The dashboard's "See actual prompt sent" (#520) had to carry a caveat that a build run appends more at run time. It no longer does, so the caveat is gone and what you read before the run is what the agent gets, for every run kind. -- **A build stops being opinionated about the stack.** #545 removed the architect turn, but the personas still hard-instructed a stack ("Default to Prisma"). With both gone, nothing tells the agent what to build on. - -Skills and project memory are worth having as designed features later. They are not worth keeping in this shape. - -Removed from `@gemstack/framework`: the `memory` / `extensions` / `composeExtensions` options on `runFramework`, the `framing` option on `composeRunSystem` (`RunSystemOptions` is now `SystemPromptOptions`), `loadRepoMemory` / `memoryFraming` / `MEMORY_FILES`, `discoverExtensions`, and the `--compose-extensions` flag. `readProjectSignals` moved to `project.js` and is still exported from the root; preset detection still runs and still narrates `Detected `. - -Removed from `@gemstack/ai-autopilot`: the `personas/` and `extensions/` modules (`definePersona`, `composePersonas`, `personaInstructions`, `personaTools`, `personaAgent`, `personaWorkers`, `personaRoster`, `stackPersonas`, `neutralPersonas`, `presetPersonas`, `defineSkill`, `SkillRegistry`, `composeSkills`, `skillInstructions`, `FrameworkExtension` and its registry). `Preset` is now `{name, framework, signals}`, a pure detector; `DomainPreset` loses `skills` and keeps its loops, prompts, and modes. - -`@gemstack/ai-skills` is untouched. It is a different thing (an on-disk `SKILL.md` loader for ai-sdk agents) and is unaffected by any of this. diff --git a/.changeset/rename-on-before-mergeable.md b/.changeset/rename-on-before-mergeable.md deleted file mode 100644 index 109d11ee..00000000 --- a/.changeset/rename-on-before-mergeable.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gemstack/framework": minor -"@gemstack/framework-dashboard": patch ---- - -Rename the "post-merge" prompt to "on-before-mergeable" (#592). It fires on `setReadyForMerge()`, before the merge, so "post-merge" was a misnomer (Rom's call in #559). Renamed end to end: the `--post-merge` flag is now `--on-before-mergeable`; `runPostMerge` / `renderPostMergePrompt` / `PostMergeContext` / `POST_MERGE_PROMPT` become their `OnBeforeMergeable` equivalents; the prompt file is `on_before_mergeable_prompt.md`; and the dashboard preference key `postMergeQuality` is now `onBeforeMergeableQuality` (a saved toggle resets to its default once). No agent-facing prompt text changed: the string "post-merge" never appeared in any prompt. The dashboard's visible "Post-merge cleanup" label is left as-is pending a copy decision. diff --git a/.changeset/rename-todo-agents-underscore.md b/.changeset/rename-todo-agents-underscore.md deleted file mode 100644 index 47e90e49..00000000 --- a/.changeset/rename-todo-agents-underscore.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Rename the flat backlog file from `TODO-AGENTS.md` to `TODO_AGENTS.md` (#674): underscore is the more standard convention (per Rom's "convention over proprietary" call). New backlogs are created at `TODO_AGENTS.md`; the brief hyphen spelling is still read as a fallback so no repo loses a backlog, alongside the existing `tickets/TODO.md` and root `TODO.md` fallbacks. Also expands the `GOAL.md` context gloss to match the revised #683. diff --git a/.changeset/research-preset-button.md b/.changeset/research-preset-button.md deleted file mode 100644 index 4dfe3a25..00000000 --- a/.changeset/research-preset-button.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -The [Research] preset (#331): `framework research [what]` and a [Research] button on the daemon dashboard run Rom's problem-variability review as a direct prompt via the new `runPrompt()` path, which honors await gates (showChoices/showMultiSelect) but skips the scope/build scaffolding. The "what" defaults to `this PR`. diff --git a/.changeset/retire-page-ts.md b/.changeset/retire-page-ts.md deleted file mode 100644 index ec5cc23e..00000000 --- a/.changeset/retire-page-ts.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Retire the legacy `page.ts` dashboard and its HTTP routes (#426, part 3). Both consumers are now on the new Vike + Telefunc dashboard (the daemon default, per-run/resume, and the relay), so `startDashboard` now serves only the prerendered SPA plus the `/_telefunc` mount (RPCs + the live-event Channel). Removed: the `dashboardHtml` and `parseStartOptions` exports, the in-process `Dashboard.push`/`Dashboard.stream` (the SPA reads `events.jsonl` over the Channel and steers over `control.jsonl`), and the now-unused `DashboardOptions` fields (`onStop`, `onChoice`, `cwd`, `dashboardMode`) and the `FRAMEWORK_DASHBOARD=legacy` escape hatch. A `--no-persist` foreground run (or an install missing the built bundle) now runs headless rather than falling back to the old page. diff --git a/.changeset/save-preferences-result.md b/.changeset/save-preferences-result.md deleted file mode 100644 index 43400ee6..00000000 --- a/.changeset/save-preferences-result.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Fix `savePreferences` rejecting the RPC when the underlying write fails. The telefunction advertises a `{ ok: false, error }` result and already returns it for the not-enabled case, but a failed disk write threw straight through, so the client saw a rejected call instead of the typed error. The write is now wrapped, so both failure modes return `{ ok: false }` and the client handles them the same way. diff --git a/.changeset/security-audit-preset-461.md b/.changeset/security-audit-preset-461.md deleted file mode 100644 index 566a8905..00000000 --- a/.changeset/security-audit-preset-461.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the [Security audit] preset (#461): an exhaustive, direct security pass over a target (defaults to `this PR`), shipped alongside [Research], [Readability], and [Maintainability]. It lists every aspect considered with a per-aspect verdict and fixes each issue in its own commit. Available as a dashboard Start-a-run button and exported as `renderSecurityAuditPrompt`. It is also the third of the post-merge quality prompts #326 fires on `setReadyForMerge()`. diff --git a/.changeset/see-system-prompt.md b/.changeset/see-system-prompt.md deleted file mode 100644 index 25ad9f8c..00000000 --- a/.changeset/see-system-prompt.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Let the user see the system prompt. Under the prompt editor, a `▶ See actual prompt sent` toggle shows the built-in prompt in full, with the `Vanilla` checkbox renamed to `Disable system prompt` (nobody knows what "Vanilla" means; the persisted `vanilla` key is unchanged). The preview renders through `composeRunSystem`, the same function a run composes with, so the toggles are shown doing what they really do. - -The event log now renders the run's `system-prompt` event in full too. That event has always carried the exact text handed to the agent, and the dashboard was reducing it to a char count and dropping the rest, so the true prompt was already reaching the browser and being thrown away. - -Reading the user's `SYSTEM.md` moves to `system-prompt-file.ts`, leaving `system-prompt.ts` free of Node imports so the composition can be imported in a browser. A test walks the compiled client barrel's import graph and fails if anything reachable from it imports `node:*`. diff --git a/.changeset/seed-run-intent.md b/.changeset/seed-run-intent.md deleted file mode 100644 index ba19c829..00000000 --- a/.changeset/seed-run-intent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Seed a run's intent (its prompt) when the run store opens, so the dashboard's Runs list labels `prompt` and `research` runs with their prompt instead of "(no prompt)". Only build runs emitted a `bootstrap` scope event carrying the intent; a direct-prompt or research run had none, so its row showed no label. A build run still refines the seeded intent via its scope event; research with no "what" seeds the same "this PR" default the log title uses. diff --git a/.changeset/select-model-628.md b/.changeset/select-model-628.md deleted file mode 100644 index df19a98d..00000000 --- a/.changeset/select-model-628.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Select the model from the dashboard (#628): a model picker sits under the prompt textarea (Default / Opus / Sonnet / Haiku) and persists as a `model` preference. It flows through as the run's `--model`, so the wrapped agent runs on the chosen model; empty means the driver's own default (no flag). A full model id set directly in the registry works too — the aliases are just the common Claude Code ones, since it is the default driver. diff --git a/.changeset/serve-multi-server-picker.md b/.changeset/serve-multi-server-picker.md deleted file mode 100644 index a5cb7692..00000000 --- a/.changeset/serve-multi-server-picker.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Serve action: pick a server in a multi-package repo (#651). The dashboard's Serve button previously ran the first `dev`/`start`/`preview`/`serve` script from the repo root, which serves nothing (or the wrong thing) in a monorepo where the apps live in workspace packages. It now lists the servable apps across the repo, the root plus each workspace package that has a serve script (resolved from `pnpm-workspace.yaml` or the package.json `workspaces` field), and offers a picker when there is more than one. The daemon remembers the last pick per project so re-serving is one click. A single-app repo is unchanged. diff --git a/.changeset/show-prompts-in-dashboard-476.md b/.changeset/show-prompts-in-dashboard-476.md deleted file mode 100644 index 6833b47d..00000000 --- a/.changeset/show-prompts-in-dashboard-476.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Show the exact prompt sent to the agent each turn. The run feed used to render a turn's start as just `> prompt sent` and drop the text; now the terminal/log formatter shows a one-line preview, and the dashboard event feed renders the full prompt in a collapsible block (click to expand) for both live runs and replays. The prompt was already carried on the driver `start` event and persisted, so this is a display-only change that surfaces it. diff --git a/.changeset/show-real-prompts-343.md b/.changeset/show-real-prompts-343.md deleted file mode 100644 index 1123c776..00000000 --- a/.changeset/show-real-prompts-343.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Show the real prompts on the dashboard (#343). The framework now emits the exact system prompt it runs the agent under as a `system-prompt` event at session start (both the direct-prompt path and the full build path). A new "Prompts sent to Claude Code" panel renders it alongside each turn's user prompt (harvested from the `driver` `start` events already in the stream), so the normally-hidden prompt is fully visible for transparency. Prompt text renders as inert text, never markup. Read-only; nothing is gated on it. diff --git a/.changeset/single-select-gate-primitive.md b/.changeset/single-select-gate-primitive.md deleted file mode 100644 index 37981e79..00000000 --- a/.changeset/single-select-gate-primitive.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): extract a shared single-select gate primitive (`requestChoices`) (#335) - -The single-select choice gate (#304) is now a reusable `requestChoices({ id, title, options, recommended })` export, the twin of `requestMultiSelect` (#332): it emits the `choice` event, parks for the pick, and falls back to the recommended option if the run is headless or aborts. It is the primitive the system prompt's `showChoices()` and the research preset need. No behavior change for existing runs. diff --git a/.changeset/single-system-assembly-501.md b/.changeset/single-system-assembly-501.md deleted file mode 100644 index d4ccec01..00000000 --- a/.changeset/single-system-assembly-501.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Assemble a run's system prompt in one place. The build path (`runFramework`) and the direct-prompt path (`runPrompt`) each inlined the same composition (the #326 prompt block, then the always-on emit protocols), and the two drifted apart, which is what dropped the #326 action layer from `--vanilla` builds (#500). Both now go through a single exported `composeRunSystem()` in `system-prompt.ts`, with unit tests pinning the order and the unconditional emit protocols so the two paths can never diverge again. diff --git a/.changeset/start-run-feedback.md b/.changeset/start-run-feedback.md deleted file mode 100644 index 54d80edd..00000000 --- a/.changeset/start-run-feedback.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Give the dashboard clear feedback when a run is started. A run is spawned detached, so there was a gap between clicking Start and the first event (and a failed launch produced nothing, so the page looked frozen). Now clicking Start shows an immediate "Starting your run..." banner; if no output arrives within ~8s it warns that the run may have failed to start; a run-launch/exit failure surfaces as an error banner; and a rejected Start (a run is already active) shows a clear "busy" banner instead of a tiny note. diff --git a/.changeset/suggest-new-tickets-preset.md b/.changeset/suggest-new-tickets-preset.md deleted file mode 100644 index ed19149a..00000000 --- a/.changeset/suggest-new-tickets-preset.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the "Suggest new tickets" preset (#462), the Agentic PM ideation prompt. Like the other presets it prefills the dashboard editor and runs as a `prompt` kind. Per #674 the prompt is a single line, "Suggest new tickets": the run-start context fragment (#683) already points the agent at the existing `tickets/**.md` and the `.the-framework/ticketing-format.md` spec (#684), so it does not need to re-teach the ticket format or spell out the flow. Per the settled #624 model the proposal is just a PR: merging accepts the tickets, closing rejects them. diff --git a/.changeset/sync-system-prompt-555.md b/.changeset/sync-system-prompt-555.md deleted file mode 100644 index e240b30e..00000000 --- a/.changeset/sync-system-prompt-555.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Sync the built-in system prompt with the #326 doc (#555). The shipped prompt was the 11-Jul draft: the doc was rewritten on 13-Jul and never synced, so every run since has been driven by a stale prompt. `prompts/system_prompt.md` is now byte-identical to the doc again. - -What the agent gets that it did not before: `## Analyze the user prompt`, which analyzes the prompt up front and records the results in an `ANLYSIS_RESULT.md`; `## Before starting changes` -> `### Session name`, which commits any dirty tree, then creates and checks out a `the-framework/` branch before the first change and calls setSessionName(); and `## After applying changes`, which calls setReadyForMerge() once the session has no work left. `## Unclear scope` is now `### Ambiguous prompt`, `## Large scope` is now `### Scope`, and `## Alternatives` moves under `## Before applying changes`. The branch step is the notable one: it previously reached the agent only as an aside in the signal protocol, so the doc's own instruction never shipped. - -`showMarkdownSecondary()` is emitted as the same `show-markdown` block as `showMarkdown()`, per the doc: for the MVP the two are equivalent. - -Also fixes the eco flags, which the sync would otherwise have broken silently (#314). They drop sections from the prompt by exact heading string, and the rewrite renames or moves every heading they matched; a missing heading is a no-op, so `--eco-auto-planning` and `--eco-auto-research` would have quietly stopped trimming anything, with no test failure to catch it. They are retargeted at `### Scope` and `### Alternatives`, the drop is now level-aware so removing a `###` stops at its sibling instead of swallowing the next `##`, and the tests assert a flag actually shortens the prompt rather than asserting a heading is absent (which passes for free once that heading is gone). - -`--eco-auto-maintenance` now drops nothing and is inert: the maintenance section left the system prompt for the post-merge prompt, so those tokens are already saved for every run. The flag stays parsed and persisted, and re-points at the post-merge prompt when that lands (#556). diff --git a/.changeset/system-prompt-326.md b/.changeset/system-prompt-326.md deleted file mode 100644 index 4be61a5d..00000000 --- a/.changeset/system-prompt-326.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -The built-in system prompt is now Rom's #326 text, verbatim, replacing the anti-lazy-pill it grew out of: unclear scope becomes a ranked `showChoices()` list, a large scope a `PLAN_.agent.md` to approve, a very large one also a `TODO_.agent.md` backlog, an alternatives pass rates problem "variability" before code is written, and edits to existing code stay minimal. The prompt is a template (#350): `${{ ... }}` JS fragments render against the run context, so `tf.params.autopilot` relaxes the maintenance stance on autopilot runs and `${{tf.prompt}}` carries the user prompt slot. New exports: `SYSTEM_PROMPT_TEMPLATE`, `renderSystemPrompt`, `renderTemplate`; the `ANTI_LAZY_PILL` export is gone (the `antiLazyPill` config key still toggles the built-in prompt). `--autopilot` now has an effect without a preset. diff --git a/.changeset/the-framework-log-run-completion.md b/.changeset/the-framework-log-run-completion.md deleted file mode 100644 index 10751a98..00000000 --- a/.changeset/the-framework-log-run-completion.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Record every finished run in the project log `.the-framework/LOGS.md` (#379). When a run ends, the CLI appends an entry with the intent/prompt title, the kind (build or prompt), the final status (done/stopped/failed), and the Claude Code session id and link. Best-effort, so a log write can never break a run. This is what makes the project DB (#378) fill itself; the run-history sidebar in #314 reads from it. diff --git a/.changeset/the-framework-logs-module.md b/.changeset/the-framework-logs-module.md deleted file mode 100644 index 8310dffc..00000000 --- a/.changeset/the-framework-logs-module.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -New `.the-framework/LOGS.md` project-log module (#378): `appendLog`/`readLogs` keep a human-readable markdown log of every loop, prompt, and build in a project, with `renderLogEntry`/`parseLogs` as the pure core over the same StoreFs seam as the run store. Parsing is forgiving: a malformed entry is skipped, never thrown. Standalone for now; the run-lifecycle wiring and dashboard UI land in follow-up issues. diff --git a/.changeset/the-framework-project-helpers.md b/.changeset/the-framework-project-helpers.md deleted file mode 100644 index fa9ed3ce..00000000 --- a/.changeset/the-framework-project-helpers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add project repo helpers (#380): `isActivated()` checks the `.the-framework/` activation marker via an injectable `ProjectFs`, and `crawlRepoFiles()` lists every tracked + untracked (gitignore-honoring) file via `git ls-files -z` behind an injectable `GitRunner`. Both forgiving: any failure reads as not-activated / an empty list. Building blocks for the #314 sidebars. diff --git a/.changeset/ticketing-format-spec.md b/.changeset/ticketing-format-spec.md deleted file mode 100644 index 73c4f430..00000000 --- a/.changeset/ticketing-format-spec.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Add the ticket-format spec (#684): `ticketing_format.md` describes the `tickets/_.md` and `.spike.md` file shapes (including the optional `priority:` and `topics:` fields). Per #674 it ships inside the package and the run-start context fragment references it by its `node_modules` path, so the format versions with the package rather than being materialized into each repo. diff --git a/.changeset/tickets-dir-629.md b/.changeset/tickets-dir-629.md deleted file mode 100644 index 165661fd..00000000 --- a/.changeset/tickets-dir-629.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Keep the flat backlog under a root `tickets/` directory (`tickets/TODO.md`) instead of the repo root, so The Framework rides on a plain, visible convention (beside `DECISIONS.md`) rather than a proprietary file (#629). New backlogs are created there, the dashboard surfaces it, and a legacy root `TODO.md` is still read so existing repos keep their backlog. Session-scoped `TODO_.agent.md` files are unchanged. diff --git a/.changeset/tiptap-prompt-editor.md b/.changeset/tiptap-prompt-editor.md deleted file mode 100644 index 44e62938..00000000 --- a/.changeset/tiptap-prompt-editor.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Replace the dashboard's Start-a-run textarea with a rich prompt editor (Tiptap). Type `/` for commands (load a preset, or insert an agent action like `showMultiSelect()`) and `@` for references (the repeated macro tags `` / `` / `` / ``, and the registered projects — a project mention also adds its repo to the run context). Tokens render as chips but serialize back to the exact plain text the agent already reads, so the run contract is unchanged. Markdown is live (StarterKit shortcuts) and round-trips faithfully, so a loaded preset comes back essentially verbatim with its tags chip-ified. diff --git a/.changeset/todo-agents-file.md b/.changeset/todo-agents-file.md deleted file mode 100644 index f76bf5cc..00000000 --- a/.changeset/todo-agents-file.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Move the flat backlog from `tickets/TODO.md` to a root `TODO-AGENTS.md` (#682), so `tickets/` holds only tickets. New backlogs are created at `TODO-AGENTS.md`; the loop, the resume-note appender, and the dashboard doc sidebar all read it, and existing `tickets/TODO.md` (and a pre-#629 root `TODO.md`) are still read as fallbacks so no repo loses its backlog. Exposes `LEGACY_TICKETS_TODO_FILE` alongside the existing `LEGACY_TODO_FILE`. diff --git a/.changeset/todo-backlog-loop.md b/.changeset/todo-backlog-loop.md deleted file mode 100644 index 1f33d4ac..00000000 --- a/.changeset/todo-backlog-loop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -The backlog loop (#323): after the build settles, the run consumes the agent's own TODO backlog (`TODO_.agent.md`, or the flat `TODO.md`) one entry per turn until it is empty. When a dashboard can answer, the loop gates before each entry ("start the next item?"), so autopilot consumes the backlog unattended and autopilot-off pauses per item. Caps make it safe overnight: the budget/Stop signal ends any turn, `--max-todo-items` bounds the run (default 25), and two no-progress items stop the loop. `--no-todo-loop` opts out. diff --git a/.changeset/transparent-mode-625.md b/.changeset/transparent-mode-625.md deleted file mode 100644 index ebf67b05..00000000 --- a/.changeset/transparent-mode-625.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -Transparent mode (#625): a coarse master off-switch that makes a run identical to plain `claude -p ` — the "only pick what you need" requirement, at its extreme. Turn it on and the wrapped agent runs fully raw: no framework system prompt, no AWAIT/SIGNAL emit protocols, no consumption guard, no dashboard, no TODO loop. - -Available at all three tiers: the `--transparent` flag, a `the-framework.yml` `transparent: true` key (per project), and a `transparent` user preference surfaced as the "Transparent" toggle in the dashboard's run options (it overrides the other option toggles, and the "Actual prompt" preview correctly shows an empty channel). - -This also closes the gap where `--vanilla` was advertised as "fully transparent" but still injected the AWAIT/SIGNAL protocols into the system channel: `--vanilla` keeps that emit contract (so the agent can still drive the dashboard's gates), and `--transparent` is the new switch that drops everything for a genuinely raw run. `composeRunSystem` now returns an empty string under transparent, the single place the whole system channel is assembled. diff --git a/.changeset/transparent-raw-prompt-path.md b/.changeset/transparent-raw-prompt-path.md deleted file mode 100644 index 7d7e8e43..00000000 --- a/.changeset/transparent-raw-prompt-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": patch ---- - -Fix transparent mode so it is actually raw Claude Code (#678). Transparent (#625) is meant to run identical to `claude -p `, but a build-kind run (a plain typed prompt, the dashboard default) still went through the full `runFramework` orchestration (scope, plan, dispatch, synthesize, production-grade pass) and sent the wrapped `extendPrompt`/`buildPrompt` text to the agent instead of the raw prompt, because run-path routing keyed only off the `research`/`prompt` subcommands. Transparent now routes any run through the raw prompt path, so the prompt runs verbatim with no build orchestration and no wrapping. Research rendering still applies only to a genuine (non-transparent) research run. diff --git a/.changeset/turn-boundary-choice-gate.md b/.changeset/turn-boundary-choice-gate.md deleted file mode 100644 index 272b0fd8..00000000 --- a/.changeset/turn-boundary-choice-gate.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): turn an agent's showChoices()+AWAIT into a live gate at the turn boundary (#337) - -The system prompt tells the agent to `showChoices()` and `AWAIT` at unclear-scope / alternatives points, but until now only framework-emitted gates (multi-select) could pause a run. Now when a build turn ends by asking the user, an `await-choices` block, the framework shows the choice on the dashboard, waits for the pick, and re-prompts the agent to continue from that decision. It is a no-op when headless and when the agent just finishes instead of asking, so existing runs are unchanged. diff --git a/.changeset/unify-disclosure-toggle-659.md b/.changeset/unify-disclosure-toggle-659.md deleted file mode 100644 index 221ff137..00000000 --- a/.changeset/unify-disclosure-toggle-659.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@gemstack/framework': patch ---- - -Give the run-form disclosures one consistent style (#659). "See actual prompt sent" and "Context" were styled differently (different triangle glyph, weight, and indent); both now use a shared `DisclosureToggle` — a chevron that rotates when open, then the label — so they read as the same control. diff --git a/.changeset/unify-the-framework-dir.md b/.changeset/unify-the-framework-dir.md deleted file mode 100644 index 84b2dc0f..00000000 --- a/.changeset/unify-the-framework-dir.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Keep everything in a single `.the-framework/` directory (#313). The transient run state (`events.jsonl`, `run.json`, `runs/`, `control.jsonl`, `daemon.json`) now lives in `.the-framework/` alongside the committed project log `LOGS.md`, instead of a separate `.framework/` directory. `install` seeds a `.the-framework/.gitignore` that ignores everything except `LOGS.md`, so the run state stays transient and only the log is committed. diff --git a/.changeset/usage-accounting-budget-cap.md b/.changeset/usage-accounting-budget-cap.md deleted file mode 100644 index 023baf4e..00000000 --- a/.changeset/usage-accounting-budget-cap.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@gemstack/framework': minor ---- - -feat(framework): track agent spend and add a budget cap (#322) - -The framework now accumulates the token + cost usage the wrapped agent reports each turn, streams a running total as a `usage` event, and shows a live spend readout on the dashboard header. Pass `--max-cost ` to stop a run once it has spent that much: the current turn finishes, then the run stops cleanly (not a failure). Useful for long autopilot runs where you only review the result at the end. diff --git a/.changeset/usage-panel.md b/.changeset/usage-panel.md deleted file mode 100644 index 825b36ca..00000000 --- a/.changeset/usage-panel.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@gemstack/framework': minor -'@gemstack/framework-dashboard': minor ---- - -Add the usage panel: what the account has left (the agent's own quota windows) and how much of it The Framework may spend before it pauses itself (the three consumption limits, each with a checkbox and a bar). Replaces the dashboard's "Usage & credits" placeholder. diff --git a/.changeset/ux-preset-472.md b/.changeset/ux-preset-472.md deleted file mode 100644 index 93fbc24b..00000000 --- a/.changeset/ux-preset-472.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add the [UX] preset (#472): a direct, interactive usability review of a target (defaults to `this PR`), shipped alongside [Research], [Readability], [Maintainability], and [Security audit]. It enumerates every finding as a categorized, reference-numbered list of choices via `showChoices()`, stops for the user to accept proposals, then works on the accepted ones. Available as a dashboard Start-a-run button and exported as `renderUxPrompt`. diff --git a/.changeset/worktree-lifecycle-module.md b/.changeset/worktree-lifecycle-module.md deleted file mode 100644 index 54386c4a..00000000 --- a/.changeset/worktree-lifecycle-module.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@gemstack/framework": minor ---- - -Add a git-worktree lifecycle module (`addWorktree` / `listWorktrees` / `removeWorktree` / `pruneWorktrees`), the foundation for running multiple tasks concurrently on one repo (#453). Each run will get its own checkout under `.the-framework/worktrees/` so concurrent runs never fight over the working tree. This slice is the isolated, unit-tested plumbing only; the daemon wiring, per-worktree concurrency, and dashboard changes land in the sibling #453 issues, so nothing changes at runtime yet. diff --git a/examples/autopilot-quickstart/CHANGELOG.md b/examples/autopilot-quickstart/CHANGELOG.md index edfed7a1..3f1275a7 100644 --- a/examples/autopilot-quickstart/CHANGELOG.md +++ b/examples/autopilot-quickstart/CHANGELOG.md @@ -1,5 +1,15 @@ # @gemstack/example-autopilot-quickstart +## 0.0.9 + +### Patch Changes + +- Updated dependencies [734da1a] +- Updated dependencies [df15f71] +- Updated dependencies [9442761] +- Updated dependencies [5e24797] + - @gemstack/ai-autopilot@0.10.0 + ## 0.0.8 ### Patch Changes diff --git a/examples/autopilot-quickstart/package.json b/examples/autopilot-quickstart/package.json index 65f54f76..8993daae 100644 --- a/examples/autopilot-quickstart/package.json +++ b/examples/autopilot-quickstart/package.json @@ -1,6 +1,6 @@ { "name": "@gemstack/example-autopilot-quickstart", - "version": "0.0.8", + "version": "0.0.9", "private": true, "description": "Runnable end-to-end quickstart for @gemstack/ai-autopilot: workers + Supervisor + runner + surfaces composed into one build-a-feature flow, offline via AiFake.", "type": "module", diff --git a/examples/bootstrap-quickstart/CHANGELOG.md b/examples/bootstrap-quickstart/CHANGELOG.md index 649a1db0..e8bf2ddf 100644 --- a/examples/bootstrap-quickstart/CHANGELOG.md +++ b/examples/bootstrap-quickstart/CHANGELOG.md @@ -1,5 +1,15 @@ # @gemstack/example-bootstrap-quickstart +## 0.0.9 + +### Patch Changes + +- Updated dependencies [734da1a] +- Updated dependencies [df15f71] +- Updated dependencies [9442761] +- Updated dependencies [5e24797] + - @gemstack/ai-autopilot@0.10.0 + ## 0.0.8 ### Patch Changes diff --git a/examples/bootstrap-quickstart/package.json b/examples/bootstrap-quickstart/package.json index dd4fadd6..725a580f 100644 --- a/examples/bootstrap-quickstart/package.json +++ b/examples/bootstrap-quickstart/package.json @@ -1,6 +1,6 @@ { "name": "@gemstack/example-bootstrap-quickstart", - "version": "0.0.8", + "version": "0.0.9", "private": true, "description": "Runnable capstone for @gemstack/ai-autopilot: preset detection + Bootstrap (scope → build → full-fledged loop → deploy) + scale mode, streamed over surfaces, offline via AiFake + FakeRunner.", "type": "module", diff --git a/examples/framework-demo/CHANGELOG.md b/examples/framework-demo/CHANGELOG.md index efbf2b27..a2e081cf 100644 --- a/examples/framework-demo/CHANGELOG.md +++ b/examples/framework-demo/CHANGELOG.md @@ -1,5 +1,170 @@ # @gemstack/example-framework-demo +## 0.0.7 + +### Patch Changes + +- Updated dependencies [68555e4] +- Updated dependencies [ca2b719] +- Updated dependencies [0faa297] +- Updated dependencies [e65e16a] +- Updated dependencies [0c922a6] +- Updated dependencies [5844526] +- Updated dependencies [aac6e5d] +- Updated dependencies [6721c0f] +- Updated dependencies [8c576df] +- Updated dependencies [be0a58c] +- Updated dependencies [4788a22] +- Updated dependencies [9e71fc8] +- Updated dependencies [b22337a] +- Updated dependencies [558bdb8] +- Updated dependencies [7a94b48] +- Updated dependencies [016fb8d] +- Updated dependencies [112c3a6] +- Updated dependencies [aac6e5d] +- Updated dependencies [87d67c8] +- Updated dependencies [76c1bfa] +- Updated dependencies [6524e0a] +- Updated dependencies [d0fe851] +- Updated dependencies [9a27125] +- Updated dependencies [cdfe508] +- Updated dependencies [e808793] +- Updated dependencies [d4fe2e5] +- Updated dependencies [f61a367] +- Updated dependencies [5646b16] +- Updated dependencies [65e27fd] +- Updated dependencies [06cb0ce] +- Updated dependencies [7ca71be] +- Updated dependencies [e0404cf] +- Updated dependencies [1dbc02a] +- Updated dependencies [dcea89b] +- Updated dependencies [f82e220] +- Updated dependencies [18de94b] +- Updated dependencies [27f522a] +- Updated dependencies [900efbb] +- Updated dependencies [4ed510f] +- Updated dependencies [a345a83] +- Updated dependencies [63b2a73] +- Updated dependencies [1bb66cf] +- Updated dependencies [48aba07] +- Updated dependencies [3091bc2] +- Updated dependencies [44988d7] +- Updated dependencies [dabdf0f] +- Updated dependencies [c26159d] +- Updated dependencies [16e86c4] +- Updated dependencies [43d4f50] +- Updated dependencies [90c15bf] +- Updated dependencies [388f3ad] +- Updated dependencies [48f25cd] +- Updated dependencies [4e43d76] +- Updated dependencies [72fb351] +- Updated dependencies [ed25ab8] +- Updated dependencies [f9add6d] +- Updated dependencies [e4b38b3] +- Updated dependencies [131f349] +- Updated dependencies [f1ff0d2] +- Updated dependencies [4a741f6] +- Updated dependencies [734da1a] +- Updated dependencies [df15f71] +- Updated dependencies [affa3d8] +- Updated dependencies [c05a186] +- Updated dependencies [1f588aa] +- Updated dependencies [5882932] +- Updated dependencies [eec009d] +- Updated dependencies [5d54b64] +- Updated dependencies [99229db] +- Updated dependencies [ee075ec] +- Updated dependencies [1f6a0d3] +- Updated dependencies [06fefbe] +- Updated dependencies [c584b16] +- Updated dependencies [b183dc0] +- Updated dependencies [aa5870e] +- Updated dependencies [28fff61] +- Updated dependencies [4aaa00a] +- Updated dependencies [f0a024c] +- Updated dependencies [4746188] +- Updated dependencies [f496a54] +- Updated dependencies [e370b41] +- Updated dependencies [79af200] +- Updated dependencies [164771a] +- Updated dependencies [4d456c2] +- Updated dependencies [c06532e] +- Updated dependencies [43bae91] +- Updated dependencies [f50f0d5] +- Updated dependencies [a743cd4] +- Updated dependencies [72533fc] +- Updated dependencies [7e1ea76] +- Updated dependencies [5709703] +- Updated dependencies [21fe373] +- Updated dependencies [89cedff] +- Updated dependencies [cfdbd59] +- Updated dependencies [5bd0489] +- Updated dependencies [721f539] +- Updated dependencies [db95caa] +- Updated dependencies [d1331a2] +- Updated dependencies [d834af8] +- Updated dependencies [c4a992a] +- Updated dependencies [b7de2a1] +- Updated dependencies [3f12815] +- Updated dependencies [4067614] +- Updated dependencies [5108aea] +- Updated dependencies [32e9d3e] +- Updated dependencies [c48af6d] +- Updated dependencies [96870d2] +- Updated dependencies [9d1951b] +- Updated dependencies [5d1653b] +- Updated dependencies [d10d515] +- Updated dependencies [18c9352] +- Updated dependencies [cbe1898] +- Updated dependencies [68d0df4] +- Updated dependencies [f736b55] +- Updated dependencies [1f1a2a3] +- Updated dependencies [1e1b4dc] +- Updated dependencies [28c3330] +- Updated dependencies [632f0df] +- Updated dependencies [734da1a] +- Updated dependencies [9442761] +- Updated dependencies [2a12ec8] +- Updated dependencies [eb1a0f1] +- Updated dependencies [5e24797] +- Updated dependencies [dac7613] +- Updated dependencies [7f9c514] +- Updated dependencies [98f44e2] +- Updated dependencies [aafbb55] +- Updated dependencies [4a70c5a] +- Updated dependencies [43d7fa0] +- Updated dependencies [b8c45a7] +- Updated dependencies [a76ace7] +- Updated dependencies [4d4d77c] +- Updated dependencies [68d53ff] +- Updated dependencies [8910ed3] +- Updated dependencies [03ca1b0] +- Updated dependencies [34d3ec2] +- Updated dependencies [c762529] +- Updated dependencies [c72d155] +- Updated dependencies [c6d005f] +- Updated dependencies [2fc612a] +- Updated dependencies [5c83bc2] +- Updated dependencies [9345476] +- Updated dependencies [59e3707] +- Updated dependencies [6b561fc] +- Updated dependencies [883d974] +- Updated dependencies [83e6a1f] +- Updated dependencies [5dcd8a4] +- Updated dependencies [3bd0478] +- Updated dependencies [d1202dc] +- Updated dependencies [e453bba] +- Updated dependencies [437618f] +- Updated dependencies [e4b518a] +- Updated dependencies [caf8a0b] +- Updated dependencies [bc3586b] +- Updated dependencies [7db5a9c] +- Updated dependencies [3302b0f] +- Updated dependencies [5417558] +- Updated dependencies [8d396f7] + - @gemstack/framework@0.9.0 + - @gemstack/ai-autopilot@0.10.0 + ## 0.0.6 ### Patch Changes diff --git a/examples/framework-demo/package.json b/examples/framework-demo/package.json index fb4ba9cf..34fa3231 100644 --- a/examples/framework-demo/package.json +++ b/examples/framework-demo/package.json @@ -1,6 +1,6 @@ { "name": "@gemstack/example-framework-demo", - "version": "0.0.6", + "version": "0.0.7", "private": true, "description": "Showable end-to-end demo of @gemstack/framework: one prompt → scope → architect → build → full-fledged loop → deploy → a real running app, offline and deterministic via the fake driver.", "type": "module", diff --git a/packages/ai-autopilot/CHANGELOG.md b/packages/ai-autopilot/CHANGELOG.md index 2f4d0c22..381cd812 100644 --- a/packages/ai-autopilot/CHANGELOG.md +++ b/packages/ai-autopilot/CHANGELOG.md @@ -1,5 +1,46 @@ # @gemstack/ai-autopilot +## 0.10.0 + +### Minor Changes + +- 9442761: Remove the architect. A build no longer runs a turn to pick the app's stack, and no longer tells the agent what to build on: the agent reads the workspace and decides for itself, the same way it would outside The Framework. `buildPrompt` / `extendPrompt` / `scaffoldPrompt` now take just the intent and say nothing about a stack. + + Being opinionated about the stack is a hard thing to do well, and a system prompt that nudges one is worse than none at all (#545). The stack guidance we had was not designed, it accumulated. It goes rather than half-ships. + + Gone with it, because the architect was their only source: + + - the plan-approval gate ("Approve this plan?" / "Use X instead") and re-architect. The agent-authored await gates a build turn raises are unaffected: a build that stops to ask still pauses the run with Approve / Decline. + - the decisions ledger in a run, and the `DECISIONS.md` a run wrote from it. `@gemstack/ai-autopilot`'s `decisions/` module is untouched and still exported; nothing in a run feeds it now. + - the dashboard's "Stack & rationale" and "Decisions ledger" panels. Loop status, deploy, and session cards are unchanged. + - `@gemstack/ai-autopilot`: `agentArchitect`, `STACK_TRADEOFFS`, `BootstrapSteps.architect`, `BootstrapOptions.ledger`, the `architect` bootstrap event, `ArchitectPlan` / `ArchitectContext` / `ArchitectDecision` / `ArchitectAlternative`, and the `plan` field on the build / loop / deploy contexts and on `BootstrapResult`. The flow is now scope -> build -> loop -> deploy. + - `@gemstack/framework`: `driverArchitect`, `reArchitect`, `architectPrompt`, `parseArchitectPlan`, `architectPlan`, `decisionLedger`, `RunFrameworkResult.ledger`, and the `bench:architect` benchmark. + +- 5e24797: Remove the persona, skill, and project-memory framing. A run's system prompt is now the built-in #326 prompt plus your own `SYSTEM.md`, and nothing else. Nothing is read off disk and appended when the run starts. + + A build used to append the personas and skills for its detected stack plus the full contents of the repo's memory files. On one measured 8,852-character build prompt that framing was about 5,000 characters, more than the designed prompt it was wrapping. None of that text was designed; it accumulated. Prompt text nobody reviewed is a defect, not a feature (#547). + + Two things fall out of this: + + - **The prompt preview is now exact.** The dashboard's "See actual prompt sent" (#520) had to carry a caveat that a build run appends more at run time. It no longer does, so the caveat is gone and what you read before the run is what the agent gets, for every run kind. + - **A build stops being opinionated about the stack.** #545 removed the architect turn, but the personas still hard-instructed a stack ("Default to Prisma"). With both gone, nothing tells the agent what to build on. + + Skills and project memory are worth having as designed features later. They are not worth keeping in this shape. + + Removed from `@gemstack/framework`: the `memory` / `extensions` / `composeExtensions` options on `runFramework`, the `framing` option on `composeRunSystem` (`RunSystemOptions` is now `SystemPromptOptions`), `loadRepoMemory` / `memoryFraming` / `MEMORY_FILES`, `discoverExtensions`, and the `--compose-extensions` flag. `readProjectSignals` moved to `project.js` and is still exported from the root; preset detection still runs and still narrates `Detected `. + + Removed from `@gemstack/ai-autopilot`: the `personas/` and `extensions/` modules (`definePersona`, `composePersonas`, `personaInstructions`, `personaTools`, `personaAgent`, `personaWorkers`, `personaRoster`, `stackPersonas`, `neutralPersonas`, `presetPersonas`, `defineSkill`, `SkillRegistry`, `composeSkills`, `skillInstructions`, `FrameworkExtension` and its registry). `Preset` is now `{name, framework, signals}`, a pure detector; `DomainPreset` loses `skills` and keeps its loops, prompts, and modes. + + `@gemstack/ai-skills` is untouched. It is a different thing (an on-disk `SKILL.md` loader for ai-sdk agents) and is unaffected by any of this. + +### Patch Changes + +- 734da1a: fix(ai-autopilot): EventStream iterators are now cancellable + + A consumer's async iterator gained a `return()` that drops its waiter from the stream and settles any pending `next()`. Previously a consumer that stopped iterating (e.g. a disconnected SSE client) left its waiter registered until the next `push`/`close`, so many short-lived consumers on an idle stream leaked. Live iteration and history replay are unchanged. + +- df15f71: FakeFs now enforces the same workspace-escape guard as the real runners. Its filesystem previously stored any path as a map key, so a `write('../evil.txt', ...)` that a real runner rejects was silently accepted. Code exercised only against `FakeRunner` never saw the escape path, then threw against Docker/Local/WebContainer. `FakeFs` now routes every path through the shared `safeSegments` guard, rejecting escapes and resolving `.`/`..` exactly as the real runners do. + ## 0.9.0 ### Minor Changes diff --git a/packages/ai-autopilot/package.json b/packages/ai-autopilot/package.json index 66e6d3a2..ccfbb154 100644 --- a/packages/ai-autopilot/package.json +++ b/packages/ai-autopilot/package.json @@ -1,6 +1,6 @@ { "name": "@gemstack/ai-autopilot", - "version": "0.9.0", + "version": "0.10.0", "description": "Orchestration for @gemstack/ai-sdk agents: a Supervisor that plans, dispatches subagents (bounded concurrency + budget guardrails), and synthesizes the result.", "keywords": [ "ai", diff --git a/packages/framework-dashboard/CHANGELOG.md b/packages/framework-dashboard/CHANGELOG.md new file mode 100644 index 00000000..4d98b749 --- /dev/null +++ b/packages/framework-dashboard/CHANGELOG.md @@ -0,0 +1,169 @@ +# @gemstack/framework-dashboard + +## 0.1.0 + +### Minor Changes + +- 3302b0f: Add the usage panel: what the account has left (the agent's own quota windows) and how much of it The Framework may spend before it pauses itself (the three consumption limits, each with a checkbox and a bar). Replaces the dashboard's "Usage & credits" placeholder. + +### Patch Changes + +- c871fb2: Stop dropping failed dashboard reads. Every panel wrote its own async effect and only the usage panel caught, so a daemon restart made each of the others an unhandled rejection every tick. They now share two hooks (`useLoaded`/`usePolled`) that keep the last value through a failed read, reset on a project switch rather than showing the previous project's data, and retire an in-flight read on unmount — including the Runs rail's `reload`, which was unguarded and could write a stale project's runs. +- dac7613: Rename the "post-merge" prompt to "on-before-mergeable" (#592). It fires on `setReadyForMerge()`, before the merge, so "post-merge" was a misnomer (Rom's call in #559). Renamed end to end: the `--post-merge` flag is now `--on-before-mergeable`; `runPostMerge` / `renderPostMergePrompt` / `PostMergeContext` / `POST_MERGE_PROMPT` become their `OnBeforeMergeable` equivalents; the prompt file is `on_before_mergeable_prompt.md`; and the dashboard preference key `postMergeQuality` is now `onBeforeMergeableQuality` (a saved toggle resets to its default once). No agent-facing prompt text changed: the string "post-merge" never appeared in any prompt. The dashboard's visible "Post-merge cleanup" label is left as-is pending a copy decision. +- Updated dependencies [68555e4] +- Updated dependencies [ca2b719] +- Updated dependencies [0faa297] +- Updated dependencies [e65e16a] +- Updated dependencies [0c922a6] +- Updated dependencies [5844526] +- Updated dependencies [aac6e5d] +- Updated dependencies [6721c0f] +- Updated dependencies [8c576df] +- Updated dependencies [be0a58c] +- Updated dependencies [4788a22] +- Updated dependencies [9e71fc8] +- Updated dependencies [b22337a] +- Updated dependencies [558bdb8] +- Updated dependencies [7a94b48] +- Updated dependencies [016fb8d] +- Updated dependencies [112c3a6] +- Updated dependencies [aac6e5d] +- Updated dependencies [87d67c8] +- Updated dependencies [76c1bfa] +- Updated dependencies [6524e0a] +- Updated dependencies [d0fe851] +- Updated dependencies [9a27125] +- Updated dependencies [cdfe508] +- Updated dependencies [e808793] +- Updated dependencies [d4fe2e5] +- Updated dependencies [f61a367] +- Updated dependencies [5646b16] +- Updated dependencies [65e27fd] +- Updated dependencies [06cb0ce] +- Updated dependencies [7ca71be] +- Updated dependencies [e0404cf] +- Updated dependencies [1dbc02a] +- Updated dependencies [dcea89b] +- Updated dependencies [f82e220] +- Updated dependencies [18de94b] +- Updated dependencies [27f522a] +- Updated dependencies [900efbb] +- Updated dependencies [4ed510f] +- Updated dependencies [a345a83] +- Updated dependencies [63b2a73] +- Updated dependencies [1bb66cf] +- Updated dependencies [48aba07] +- Updated dependencies [3091bc2] +- Updated dependencies [44988d7] +- Updated dependencies [dabdf0f] +- Updated dependencies [c26159d] +- Updated dependencies [16e86c4] +- Updated dependencies [43d4f50] +- Updated dependencies [90c15bf] +- Updated dependencies [388f3ad] +- Updated dependencies [48f25cd] +- Updated dependencies [4e43d76] +- Updated dependencies [72fb351] +- Updated dependencies [ed25ab8] +- Updated dependencies [f9add6d] +- Updated dependencies [e4b38b3] +- Updated dependencies [131f349] +- Updated dependencies [f1ff0d2] +- Updated dependencies [4a741f6] +- Updated dependencies [affa3d8] +- Updated dependencies [c05a186] +- Updated dependencies [1f588aa] +- Updated dependencies [5882932] +- Updated dependencies [eec009d] +- Updated dependencies [5d54b64] +- Updated dependencies [99229db] +- Updated dependencies [ee075ec] +- Updated dependencies [1f6a0d3] +- Updated dependencies [06fefbe] +- Updated dependencies [c584b16] +- Updated dependencies [b183dc0] +- Updated dependencies [aa5870e] +- Updated dependencies [28fff61] +- Updated dependencies [4aaa00a] +- Updated dependencies [f0a024c] +- Updated dependencies [4746188] +- Updated dependencies [f496a54] +- Updated dependencies [e370b41] +- Updated dependencies [79af200] +- Updated dependencies [164771a] +- Updated dependencies [4d456c2] +- Updated dependencies [c06532e] +- Updated dependencies [43bae91] +- Updated dependencies [f50f0d5] +- Updated dependencies [a743cd4] +- Updated dependencies [72533fc] +- Updated dependencies [7e1ea76] +- Updated dependencies [5709703] +- Updated dependencies [21fe373] +- Updated dependencies [89cedff] +- Updated dependencies [cfdbd59] +- Updated dependencies [5bd0489] +- Updated dependencies [721f539] +- Updated dependencies [db95caa] +- Updated dependencies [d1331a2] +- Updated dependencies [d834af8] +- Updated dependencies [c4a992a] +- Updated dependencies [b7de2a1] +- Updated dependencies [3f12815] +- Updated dependencies [4067614] +- Updated dependencies [5108aea] +- Updated dependencies [32e9d3e] +- Updated dependencies [c48af6d] +- Updated dependencies [96870d2] +- Updated dependencies [9d1951b] +- Updated dependencies [5d1653b] +- Updated dependencies [d10d515] +- Updated dependencies [18c9352] +- Updated dependencies [cbe1898] +- Updated dependencies [68d0df4] +- Updated dependencies [f736b55] +- Updated dependencies [1f1a2a3] +- Updated dependencies [1e1b4dc] +- Updated dependencies [28c3330] +- Updated dependencies [632f0df] +- Updated dependencies [734da1a] +- Updated dependencies [9442761] +- Updated dependencies [2a12ec8] +- Updated dependencies [eb1a0f1] +- Updated dependencies [5e24797] +- Updated dependencies [dac7613] +- Updated dependencies [7f9c514] +- Updated dependencies [98f44e2] +- Updated dependencies [aafbb55] +- Updated dependencies [4a70c5a] +- Updated dependencies [43d7fa0] +- Updated dependencies [b8c45a7] +- Updated dependencies [a76ace7] +- Updated dependencies [4d4d77c] +- Updated dependencies [68d53ff] +- Updated dependencies [8910ed3] +- Updated dependencies [03ca1b0] +- Updated dependencies [34d3ec2] +- Updated dependencies [c762529] +- Updated dependencies [c72d155] +- Updated dependencies [c6d005f] +- Updated dependencies [2fc612a] +- Updated dependencies [5c83bc2] +- Updated dependencies [9345476] +- Updated dependencies [59e3707] +- Updated dependencies [6b561fc] +- Updated dependencies [883d974] +- Updated dependencies [83e6a1f] +- Updated dependencies [5dcd8a4] +- Updated dependencies [3bd0478] +- Updated dependencies [d1202dc] +- Updated dependencies [e453bba] +- Updated dependencies [437618f] +- Updated dependencies [e4b518a] +- Updated dependencies [caf8a0b] +- Updated dependencies [bc3586b] +- Updated dependencies [7db5a9c] +- Updated dependencies [3302b0f] +- Updated dependencies [5417558] +- Updated dependencies [8d396f7] + - @gemstack/framework@0.9.0 diff --git a/packages/framework-dashboard/package.json b/packages/framework-dashboard/package.json index 159c3f6b..84ccb0df 100644 --- a/packages/framework-dashboard/package.json +++ b/packages/framework-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@gemstack/framework-dashboard", - "version": "0.0.0", + "version": "0.1.0", "private": true, "description": "The Framework dashboard (spike): Vike + React + shadcn + Telefunc, a projection of the same .the-framework files the daemon writes (#405/#406).", "license": "MIT", diff --git a/packages/framework/CHANGELOG.md b/packages/framework/CHANGELOG.md index e12c1679..eaac26d2 100644 --- a/packages/framework/CHANGELOG.md +++ b/packages/framework/CHANGELOG.md @@ -1,5 +1,285 @@ # @gemstack/framework +## 0.9.0 + +### Minor Changes + +- 68555e4: Self-heal a run whose process died without writing its `end` event (#716). A crash, `kill -9`, or the machine sleeping used to leave `.the-framework/run.json` stuck at `status: running` forever: the dashboard showed a permanently RUNNING row whose Stop was a no-op (nothing was left to consume `control.jsonl`), and it only cleared on a daemon restart. The run now records its owning pid and host in `run.json`, and `readLiveMeta` flips a `running` run to `stopped` (and archives it) on read when that owning process is gone on this host, so the dashboard clears the stuck row on the next poll. Runs whose meta predates this field are left to the existing boot-time reconcile. +- ca2b719: Resume a finished run by messaging it (#720). After a run ends (Stop, or it finishes) the dashboard used to drop the chat composer, so the conversation was a dead end. The finished-run view now keeps a composer, and sending a message spins a fresh run whose opening prompt `--resume`s the ended run's captured session id, continuing the same conversation with full prior context. New plumbing: `DriverStartOptions.resumeSessionId` seeds the Claude Code session so its very first prompt resumes (the framing is skipped, since the resumed transcript already carries it); `AwaitRoundsOptions.resume` / `RunPromptOptions.resumeSessionId` carry it through `runPrompt`; and it threads from the dashboard as `StartRunOptions.resumeSession` -> the `--resume-session ` CLI flag. A continuation is sent as a `prompt` run; a fresh run is byte-identical to before. +- 0faa297: Add the "Add project(s)" install flow to the dashboard. A `POST /api/projects` (guarded like the other state-changing routes) installs The Framework into a repo, or every git repo directly under a folder, then registers each so it shows up in the Projects list; the daemon wires it to install-core. The Projects sidebar gains an "Add" control with a small path form (single repo or "folder of repos"), shown only when the server enables adding. Also fixes `enumerateGitRepos` to detect repo roots via `git rev-parse --show-prefix` instead of comparing `--show-toplevel` to the path, which failed across a symlink (e.g. macOS `/var` -> `/private/var`) and returned no repos. +- 0c922a6: Add `--agent claude|codex`, which picks the agent that drives a run. The Codex driver shipped but nothing selected it, so it was unreachable; now both driver paths (the build itself and the auto-select routing turn before it) honor the flag, and preflight probes the agent you asked for rather than always `claude`. Default stays `claude`. + + Codex reports no price and no quota, so the spend cap and the consumption limits cannot gate it and previously would have no-opped in silence. A run now says which guards are not in force instead of letting `--max-cost` imply one, and it no longer offers a Claude Code session link for a session that isn't Claude's. + +- aac6e5d: Add an agent picker to the dashboard (#650). The Start form can now choose the coding agent that drives the run — Claude Code or Codex — alongside the model, wiring the existing `--agent` flag. It persists as a preference (`agent`, validated to the known set) and maps to a run's `--agent` (only non-default `codex` emits a flag). Agent and model share one dropdown (a submenu each), styled like the Presets menu, and the "New preset" panel spans the full width. +- 4788a22: Add a "Browser" toggle to the dashboard Start form so `--browser` (give the agent a real browser via chrome-devtools-mcp, #452) is reachable from daemon/dashboard-started runs, not just the CLI. Mirrors the Post-merge cleanup pref: a `browser` preference flows to `StartRunOptions.browser` and on to the `--browser` flag. +- 9e71fc8: Add `--browser`: give the agent a real browser during the run via chrome-devtools-mcp. When set, the driver writes a temp `--mcp-config` wiring `chrome-devtools-mcp`, so the agent can navigate pages, read console + network output, inspect the DOM, and screenshot while it works instead of flying blind on frontend changes. Off by default; host-side only (no runner change), and the MCP servers merge with the user's own rather than replacing them. The `ClaudeCodeDriver` gains an `mcpServers` option backing this. +- b22337a: Collect business knowledge in the repo (#537). Every run now puts `.the-framework/README.md`, `.the-framework/DECISIONS.md` and `.the-framework/KNOWLEDGE-BASE.md` on the `Context:` line, so the agent reads whatever the project already knows about itself, and the post-merge prompt gained a `## Business knowledge` section asking it to fold back what the session taught that the code cannot show. The docs go with the built-in system prompt: `--vanilla` still injects nothing but the user's own dirs. `--eco-auto-maintenance` now drops the post-merge prompt's `## Maintenance` section instead of skipping the whole run, which would have taken business knowledge with it. +- 558bdb8: Live chat: send more messages to a running run. The dashboard's run view gains a composer, and the run stays open after the agent goes idle to take the user's own messages (the "stay-open" lifecycle) until it is stopped. Each message continues the same agent session via `claude --resume `, so the conversation keeps full context, and rides the existing `control.jsonl` steering channel as a new `message` kind next to Stop and choice picks. Wired only for an interactive run (a live dashboard / daemon); a headless run ends when the agent stops asking, exactly as before. The Claude Code driver gains a `resume` prompt option (`DriverPromptOptions.resume`) that continues the retained session and skips the redundant system-prompt re-append. +- 016fb8d: Bare `framework` now tells you whether the CLI is up to date (#312): after the version footer it checks npm's `dist-tags.latest` (2.5s cap) and prints "Up to date" or "Update available: vX (you have vY). Run: npm i -g @gemstack/framework". Offline or on any fetch failure it prints nothing. Display only; no auto-update. +- 112c3a6: Add `CodexDriver`: The Framework can drive the Codex CLI as a second agent, on the user's own ChatGPT subscription with no API key. Generalizes the agent-CLI process handling into `runAgentCli` so a second agent reuses it rather than copying it. Codex reports no price and no quota, so it omits usage rather than claim a run was free, and the consumption limits stay Claude-only. +- 87d67c8: Turn-boundary gate for plan approval (`showMarkdown()` + AWAIT): a build turn that ends with an `await-confirmation` block (the #326 large-scope PLAN flow) now pauses the run with a green Approve and a red Decline button on the dashboard. Approve resumes the build; Decline logs "Plan declined, awaiting user instructions." and stops the run cleanly (like the budget cap), so nothing reviews or improves work the user just declined. Headless runs auto-approve, keeping programmatic runs deterministic. Try it offline with `FRAMEWORK_FAKE_AWAIT=confirmation`. +- 76c1bfa: Turn the consumption limits on for real runs. `startConsumptionGuard` composes the poller and the limits into the gate a run consults, the CLI reads the limits from the user's preferences and wires it into both run paths, and the direct prompt path gained the same pause the build path got. A driver that can't report a quota leaves the run ungated. +- 6524e0a: Let the user set the consumption limits. The preferences now carry a checkbox and a percentage per limit, and `resolveConsumptionLimits` fills any gap with the defaults. Preference sanitizing was boolean-only, so a percentage was silently dropped on both read and write; it now validates per-limit and falls back to the default rather than leaving the account unguarded. +- d0fe851: Add the consumption-limit decision layer: `ConsumptionMeter` tracks the account's weekly quota meter over time, and `consumptionStatus` reports where the session / 5h / daily limits stand and which one is reached. Handles the weekly reset, reports partial coverage honestly, and fails open when the quota can't be read. +- 9a27125: Pause a run when a consumption limit is reached. `runFramework` takes a `consumptionGate` consulted between turns; a reached limit stops the run cleanly (like the budget cap) and leaves a `Resume ` entry on the workspace's backlog, so a later run picks the work back up. An unreadable quota carries on rather than stopping the work. +- e808793: Expand the run-start context fragment (#683): alongside `DECISIONS.md` and `KNOWLEDGE-BASE.md` the agent now also sees `GOAL.md`, `tickets/**.md` (pointed at the `.the-framework/ticketing-format.md` spec from #684), and the `TODO-AGENTS.md` task queue. The set is split into `CONTEXT_DOCS` (read at start) and the `BUSINESS_KNOWLEDGE_DOCS` subset the agent also updates at merge, so the roadmap/queue pointers are read-only context. +- f61a367: Add the context selector and trust-on-add to the dashboard (#439, part of #314). The Start form gains a "Context" picker — tick the registered repos to focus the agent on, and each becomes one `Context: ` line in the run's system prompt (the agent can still reach every repo; this just narrows where it looks). Threaded through as a repeatable `--context ` CLI flag and `StartRunOptions.context`. Adding a project now asks "do you trust this repository?" first, warning about prompt-injection risk before the agent is given read access. + + Also hardens the daemon's Telefunc mount: a bare `GET /_telefunc` (which a browser tab issues on reconnect) made telefunc throw an unhandled rejection that crashed the daemon; the mount now catches it and returns 400. + +- 06cb0ce: Custom presets (#626): save your own prompts as reusable presets beside the built-in ones. A "+ Preset" button under the prompt textarea captures the current editor text (or a fresh one) under a name; saved presets render as buttons that load their prompt back into the editor, and each has a delete. They persist in the daemon preferences (`customPresets`), sanitized and capped so a hand-edited registry can't bloat the home file. For the users (Rom, nitedani) who keep hand-crafting high-signal prompts, this makes them one click to re-run. +- 7ca71be: Bare `framework` now runs the dashboard server in the foreground (#456): Ctrl+C stops it, and the server's logs and any errors it throws are visible in the terminal. `framework --daemon` does what bare `framework` used to do, running the dashboard in the background (detached) and returning after printing the convenience commands. If a background daemon is already running, bare `framework` reports its URL and defers instead of fighting for the port. +- 1dbc02a: The daemon can now serve the new Vike + Telefunc dashboard bundle (#405). Opt in with `FRAMEWORK_DASHBOARD=next` (serves the prerendered SPA at `/`, with the legacy `page.ts` at `/legacy`) or `FRAMEWORK_DASHBOARD=legacy` (mounts the Telefunc surface at `/_telefunc` while `page.ts` stays at `/`). Unset keeps today's behavior exactly. The dashboard's read + steer RPCs and the live-event Channel are served in-process at `/_telefunc` (same-origin guarded), backed by a new `@gemstack/framework/dashboard-rpc` subpath; `starting` a run over Telefunc lands next. +- f82e220: Restore the dashboard actions on the new dashboard (#433): the Start form now carries the Global options (autopilot, technical, vanilla, eco) and the run presets (Research, Readability, Maintainability), the interactive choice gate auto-accepts the recommended pick on an autopilot countdown, a Deploy card shows the chosen render + target, and projects can be added from the Projects sidebar over a new `sendAddProject` telefunction. Adds a browser-safe `deployPlan` projection and the preset builders to `@gemstack/framework/client`. +- 18de94b: Let the agent push ad-hoc markdown views into the dashboard right rail. A `show-markdown` block in a turn (non-blocking, unlike a choice gate) becomes a `view` event that renders as a first-class Views tab in the right rail, with a sticky top-nav to jump between views. Re-showing the same title updates that view in place. +- 27f522a: feat(framework): opt-in browser notifications on the dashboard for run-end and choice gates (#317) + + The localhost dashboard can now notify you when a run finishes (or fails/stops) and when a run reaches a `` gate that needs your input (e.g. a PLAN.md approval). Opt in via the header bell; it only nudges when the dashboard tab is backgrounded, so a run you are watching stays quiet. + +- 4ed510f: Dashboard control channel: the persistent daemon dashboard can now steer any run in its workspace. Its Stop button and choice picks append to `.framework/control.jsonl`; the run tails the file and aborts or resolves its parked gate. Gates now pause whenever a workspace daemon is live, not only when the run owns its own dashboard; headless behavior without a daemon is unchanged. Also fixes the fresh-workspace daemon startup: bare `framework` in a project with no `.framework/` yet used to fail and leave a zombie server on the port. +- a345a83: The new Vike + Telefunc dashboard (#405) is now what the daemon serves by default at `/`; the legacy `page.ts` dashboard moves to `/legacy`. Set `FRAMEWORK_DASHBOARD=legacy` to keep `page.ts` at `/` (the escape hatch), and if a build ever ships without the prerendered bundle the daemon falls back to `page.ts` automatically. The `release` flow now runs `bundle:dashboard` so the published package ships the dashboard assets. +- 63b2a73: feat(framework): document sidebar on the dashboard, rendering the run's PLAN.md / TODO.md (#319) + + The localhost dashboard now surfaces the `PLAN.md` and `TODO.md` the agent writes at the workspace root (via the anti-lazy-pill) in a right sidebar, rendered as markdown with a sticky tab nav to jump between them. A new `GET /api/docs` endpoint reads the surfaced docs (fixed filenames, gated on the workspace `cwd` like `/api/runs`); the sidebar polls it so a plan written mid-run appears, and stays hidden when there are no docs. + +- 1bb66cf: Add a preferred-editor dashboard preference (#727). "Open in editor" now uses a stored `editor` preference (an editor CLI such as `code`, `cursor`, or `zed`), falling back to `$FRAMEWORK_EDITOR` and then `code` as before. The Settings gear offers a picker that auto-detects the editors installed on the daemon's machine by probing their launchers on PATH (`onEditors`), plus a "Default" entry to clear the choice. A public host, which has no local checkout to open, detects nothing. +- 3091bc2: Add an Overview section to the top of the dashboard's first sidebar. It gives a cross-project glance over a new `onOverview` Telefunc read: what the agent is running right now (from each project's live run meta), the total open TODO count across all projects, and the most recently active projects. Clicking any of them selects the project. +- 44988d7: Move the cross-project Overview out of the first sidebar and into a proper dashboard page. The sidebar is now just an "Overview" nav item plus the project list, so it reads as a simple switcher. Selecting Overview (or opening the dashboard with no project picked) shows an at-a-glance landing: KPI tiles (projects, active runs, open TODOs, total runs), a two-week run-activity chart, how past runs ended, what the agent is working on now, the TODO backlog, and a projects table. It is backed by a new `onDashboard` read (a projection of the same run.json / runs/ / TODO files), so nothing new is stored. +- dabdf0f: Default dashboard port is now 4200 (was 4477): easier to remember. Pass `--port` to override. +- c26159d: Persist the dashboard's Global options (Autopilot, Technical, Vanilla, Eco) in the same `the-framework.json` as the project list, read and written daemon-side over Telefunc (`onPreferences` / `savePreferences`), so they survive restarts without localStorage (#410). The registry file becomes an object `{ projects, preferences }`; older bare-array files still read and are migrated on the next write. +- 16e86c4: Add a Project log panel to the dashboard (#384). It surfaces the committed `.the-framework/LOGS.md` history (#378/#379) for the workspace: every loop/prompt/build run with its title, status, kind, session link, and a loop's constituent prompts, newest-first. Served by a new `GET /api/logs` endpoint and refreshed on load, on run-end, and on an interval. All fields are escaped and the session link is passed through the page's safe-URL guard, since the log is agent-authored. +- 43d4f50: Add a cross-project Queue section to the dashboard's first sidebar. It aggregates the open `TODO.md` items across every registered project over a new `onQueue` Telefunc read, so the whole backlog is visible in one place instead of per-selected-project only. Clicking a project in the queue selects it. +- 90c15bf: Export `readDocs` + the `WorkspaceDoc` type from the package root, so a separate dashboard can read the same surfaced PLAN/TODO docs the daemon serves (#405 phase 2). +- 388f3ad: feat(framework): browse a project's run history in the dashboard (#303) + + The dashboard now has a left sidebar listing a project's past runs (intent, status, session link); clicking one replays that run's projection in the main view, and "Back to live" returns to the current run. Each finished run is archived under `.framework/runs/.jsonl` + `.framework/runs/.json` (a crash that skips the final flush is archived on the next run), and served over `GET /api/runs` and `GET /api/runs/`. Single project only. Closes #303. + +- 48f25cd: Add event-stream projections for the dashboard's run overview: `loopStatus` and `sessionInfo` derive the production-grade loop status and the live session from a `FrameworkEvent[]`. They plus `formatFrameworkEvent` are re-exported from a new browser-safe `@gemstack/framework/client` subpath (no Node imports), so the dashboard renders the rich run view (loop status and a human-readable event log instead of raw JSON) across the live view, past-run replay, and the relay watch view. +- 4e43d76: The new dashboard can now start a run over Telefunc (#405). A `sendStart` telefunction reaches the daemon's own `startRun` closure through the Telefunc request context, so it runs in-process with the one-run-per-project busy guard intact (a second start returns `busy`). Served at `/_telefunc` alongside the read + steer RPCs, same-origin guarded. +- 72fb351: Start runs from the daemon dashboard (#345): a prompt textarea + `POST /api/start` that spawns `framework "" --no-dashboard` as a detached child, with a one-run-at-a-time guard. The started run streams into the page via the tailed event log and is steerable (gates + Stop) through the control channel. +- f9add6d: Add a `theme` dashboard preference (#725): `system` (the default, following the OS), `light`, or `dark`. Stored in `the-framework.json` alongside the other preferences and sanitized against the known set. The dashboard applies it by toggling the `.dark` class (following live OS changes while on `system`) and exposes a system/light/dark picker in the Settings gear, replacing the previously hardcoded dark-only mode. +- e4b38b3: Per-user Discord toggle for the "needs you" notifications (#627): Discord was env-only (set `DISCORD_WEBHOOK` and it posted). Now a `notifyDiscord` preference (default off) gates the daemon watcher on top of the webhook — the webhook is _where_ to post, the preference is _whether_ to. It is checked at post time, so the new header toggle (beside the browser bell) takes effect without restarting the daemon, and the watcher keeps its baseline warm while off so flipping it on starts from now rather than blasting the open backlog. +- affa3d8: Add `#` to the dashboard prompt editor to reference a project file as run context (#504). The finer-grained sibling of `@` (which focuses a whole repo): type `#` to filter the project's files (via `git ls-files`, honoring .gitignore) and pick one, inserting a chip that adds its repo-relative path to the run Context. Backed by a new `onProjectFiles` read RPC; localhost-only, since the relay has no checkout. +- 1f588aa: Add `framework maintain` (#298): a background maintenance sweep. It walks the registered repos, and for each that has grown commits since its last review it runs the maintainability loop on them (`framework prompt`, budget-capped by `--max-cost`, bounded by `--max-repos`). A first-seen repo is baselined (recorded, not reviewed retroactively); per-repo review state lives in `.the-framework/maintenance.json`. `--dry-run` previews the plan. Also exports the maintenance API (`assessRepo`, `planMaintenanceSweep`, `maintainSweep`, review state helpers). +- 5882932: feat(framework): inject a system prompt into every prompt (anti-lazy-pill + SYSTEM.md) + + Every run is now framed with a built-in system prompt: the validated anti-lazy-pill (#297), which turns unclear scope into a ranked list, a large scope into a `PLAN.md`, and a very large one into a `TODO.md` backlog, so the agent builds a real backend and declares what it descopes instead of silently faking it. Drop a `SYSTEM.md` at the workspace root to add project-specific instructions on top, or set `antiLazyPill: false` in `the-framework.yml` to remove the built-in default. Closes #301. + +- eec009d: Thread the #314 Global options through the run engine (#370). `POST /api/start` now carries an `options` object which the daemon turns into CLI flags: `--vanilla` removes the built-in #326 system prompt entirely (raw Claude Code), and `--eco-auto-planning` / `--eco-auto-research` / `--eco-auto-maintenance` drop the matching #326 sections to save tokens (Autopilot and Technical keep mapping to modes). `system-prompt.ts` drops the Eco sections at render, so the #343 Prompts panel reflects the toggles live; the #326 template stays byte-identical. The dashboard panel that drives these lands separately (#371); all fields default off, so today's behavior is unchanged. +- 5d54b64: Add the #314 Global options panel to the dashboard (#371). Beside the Start box the daemon dashboard now shows persistent toggles: Autopilot (auto-accept, sharing its key with the choice-panel toggle so the two stay in lockstep), Technical control, Vanilla (remove all system prompts, fully transparent), and Eco with Auto planning / Auto research / Auto maintenance to trim the built-in prompt. Each persists in localStorage and rides along in the `POST /api/start` body, so flipping a toggle changes what the run gets (and, with the engine plumbing in #370, what the #343 Prompts panel shows). Vanilla disables Eco, since a removed prompt has nothing left to trim. +- 99229db: Make the "Needs you" (human intervention) notifications a real toggle (#627). It was always-on before; now it is a default-on `notifyHumanIntervention` preference, so it can be turned off like the other categories. Gates both the browser notification and the daemon's Discord delivery on the category (default on) in addition to the delivery method. +- 1f6a0d3: feat(framework): interactive choice gate + autopilot in the dashboard (#304) + + A run can now pause on a choice and wait for you: the dashboard shows a "Your call" panel with the options. Accept with the button or Ctrl+Enter, or leave the `[x] autopilot` countdown auto-accept the recommended option after 10s (moving the mouse cancels it). New `requestChoice` option on `runFramework`, `choice` / `choice-resolved` events, and a `POST /choice` dashboard route; a headless run with no handler auto-accepts the recommended option, so nothing else changes. Closes #304. + +- b183dc0: Add the `setSessionName()` and `setReadyForMerge()` lifecycle signals (#326). Both are non-blocking turn-boundary signals, the same shape as the existing `show-markdown` view: the agent emits a fenced `set-session-name` / `ready-for-merge` block and keeps working, and the framework records it and reflects it in the dashboard. `setSessionName()` labels the run with the `[a-z0-9-]` slug it chose (also its `the-framework/` branch); `setReadyForMerge()` flips the run's status from building to ready-for-review. The dashboard shows the session name and a status dot (amber while building, green once ready) in both the run overview and the cross-project "working now" list. This is the signal the post-merge quality suite will hang off. +- aa5870e: Dashboard: show the live run in the Runs rail with a RUNNING status. The in-progress run now appears as the top row of the list (pulsing dot, RUNNING badge, and the prompt), matching the history rows, instead of being hidden behind the abstract "Live" button; clicking it follows the live stream as before. `onRuns` prepends the live run (from `run.json`) when one is running, and the Start form seeds an optimistic row so the run shows the instant you click Start, before the spawned process writes its `run.json`. +- 28fff61: New [Maintainability] preset button on the dashboard (#361): prefills the deliberately minimal refactor-for-future-changes prompt ("look for maintainability red flags, and fix them") into the start textarea for review or editing; Start runs the text verbatim as a direct prompt run. The one blank, ``, defaults to `this PR`. +- 4aaa00a: Make the dashboard multi-project on the read side: `GET /api/projects` lists the registered projects (from the registry) with a per-project summary (name, activated, last activity), and `?project=` on `/api/logs`, `/api/runs`, `/api/runs/`, and `/api/docs` reads that project's data (an absent id keeps the daemon's own workspace, single-project back-compat). The daemon auto-registers its own workspace on boot when it is activated, so the Projects list is populated for the common single-project case. Live event streaming and per-project run start/stop stay single-project for now. Adds `ProjectSummary` / `ProjectsProvider` / `summarizeProject` / `defaultProjectsProvider`. +- f0a024c: Add the install-core module: `installProject(cwd)` activates a repo for The Framework by creating the `.the-framework/` marker with a seeded `LOGS.md`, committing any pre-existing dirty changes first (`[The Framework] uncommitted changes`) so the install commit (`[The Framework] install The Framework`) is clean; an already-activated repo is a no-op. Also `enumerateGitRepos(dir)` lists the immediate child directories that are their own git repo roots (for the "add a directory of repos" flow). Pure core over the existing `GitRunner` + `StoreFs` seams; any git failure surfaces as a value, never a throw. No daemon or UI wiring yet. +- 4746188: Add the multi-project registry module: reads and writes the list of projects The Framework is installed into, as a small `{id, path, addedAt}` JSON index under the user's config dir. Exposes `projectId`, `registryPath`, `listProjects`, `addProject`, `removeProject`, and an injectable `RegistryFs` seam with a `nodeRegistryFs()` adapter. No daemon or UI wiring yet. +- f496a54: Add a multi-select gate (`showMultiSelect()`): a dashboard checklist with pre-checked defaults that pauses the run and resolves to the selected subset. Built on the existing single-select choice gate (same panel and POST-back resolver), exposed as `requestMultiSelect()`; a headless run auto-accepts the default set. This is the primitive the [Research] preset uses to let the user pick which problems to deep-dive. +- e370b41: feat(framework): turn an agent's showMultiSelect()+AWAIT into a live checklist gate (#339) + + The multi twin of the single-select turn-boundary gate (#337). When a build turn ends on an `await-multiselect` block, the framework shows a checklist on the dashboard (via `requestMultiSelect`, with the agent-marked defaults pre-checked), waits for the selection, and re-prompts the agent to continue from it. This is what the research preset needs to let the user pick which problems to deep-dive. Same safety as #337: a no-op when headless and when the agent just finishes. + +- 164771a: Discord delivery for the "New activity" notifications category (#627): the daemon now also watches the run activity feed and posts to Discord when a run starts or finishes, so the default-off activity category reaches you with no dashboard open — the same path the interventions watcher uses for the "needs you" queue. Double-gated at post time so the header toggles take effect without a daemon restart: both the category (`notifyNewActivity`) and the Discord method (`notifyDiscord`) must be on, on top of a `DISCORD_WEBHOOK` being set. The runs already going when the daemon starts are folded into a baseline (no start-up blast). Completes the browser + Discord matrix for both notification categories. +- 4d456c2: "New activity" notifications (#627): a default-off notification _category_ alongside the always-on "needs you" one. Turn it on (the new Activity toggle in the header, beside the browser bell and Discord toggle) and you get a ping when a run starts and when it finishes, not just when something needs you. It is a category, not a method, so it rides whichever delivery methods are on: browser notifications when the bell is on. A cross-project `onActivity` feed (`buildActivity`) drives it, diffed the same way as the interventions queue, so the runs already going when the page loads are folded into a baseline rather than announced. +- a743cd4: Report an agent's tokens when it reports no price. `DriverUsage.costUsd` is now optional: tokens are what every agent reports, a price is what only some do. Codex reported real token counts that we were dropping on the floor, and now surfaces them; a run with no price shows `tokens: 13,570 (5 out)` rather than nothing at all, and never a `$0` that would read as free. Claude runs are unchanged and still show their spend line. + + The spend cap only ever fires on a reported price, so it stays Claude-only and the CLI says so rather than implying otherwise. We deliberately do not invent prices from a model table: that number would go stale silently, and under a subscription nobody is billed per token anyway. What a subscription actually spends is quota, which the consumption limits gate on. + +- 72533fc: Add a file tree to the dashboard's project panel (#492). It lives as the first tab in the right rail (Files · Docs · Log) and is a file-level context picker: a lazy, collapsible tree (animate-ui Files) built from `git ls-files`, where ticking a file adds it to the run Context — the same set the `#` picker and whole-repo Context selector feed. Per-file git-status dots (untracked/modified/deleted) come from a new `onProjectFileStatus` RPC, rolled up to folders. + + Also refines the project action bar: git status folds inline on the left; Open on GitHub / Open folder / Open in editor become icon-only buttons with tooltips (a small Base UI Tooltip, no Radix added); and Preview is renamed Serve — a play button that becomes a segmented Open ↗ / Stop ⏹ control while serving. + +- 7e1ea76: Per-project daemon runs + one daemon per machine (#393). Dashboard-started runs, Stop, and choice picks now carry the viewed project id, so the daemon spawns each run with that project's `--cwd`, steers it through that project's own control log, and guards one run per project. Daemon liveness moved from a per-workspace `.the-framework/daemon.json` to a single global file beside the registry (`$XDG_CONFIG_HOME/the-framework-daemon.json`), so `framework` and `framework stop` in any repo find the same daemon. Per-project live event streaming is folded in with the dashboard rebuild (#405). +- 5709703: Serve the new Vike + Telefunc dashboard for per-run foreground runs and `--resume`, not just the daemon. `framework ""` and `framework --resume` now serve the rebuilt dashboard in single-project mode, scoped to that run's workspace without touching the global registry, and the live run steers over its own `.the-framework/control.jsonl` even with no daemon running. Falls back to the legacy `page.ts` when the bundle is absent or `--no-persist` is set. Adds `singleProjectProvider` and `resolveDashboardBundle` to the public surface. +- 21fe373: feat(framework): persistent background dashboard daemon (#302) + + Bare `framework` now ensures a long-lived dashboard process for the workspace and prints its URL plus the convenience commands; `framework stop` shuts it down. The dashboard is a projection of `.framework/events.jsonl`: the detached daemon tails the log and pushes each new event to connected browsers, so it outlives any single run. The tailer also detects an in-place truncation when a fresh run rewrites the log to the same byte length (size unchanged but mtime advanced), and the daemon spawn refuses to re-exec a test entry so a `node --test` run can never fork-bomb itself. + +- 89cedff: Add the post-merge quality suite (#326): when a run signals `setReadyForMerge()`, optionally fire the maintainability, readability, and security-audit passes over the same workspace. Enabled per run by the new `--post-merge` CLI flag, or from the dashboard's Global options via a "Post-merge cleanup" toggle (persisted as the `postMergeQuality` preference, mapped to `--post-merge` on the spawned run). The three passes run **sequentially** — they edit and commit the same git tree, so concurrent writers would race on the index lock; worktree-isolated parallelism is a follow-up. Each pass is a plain `framework prompt` child carrying no `--post-merge`, so a quality pass never triggers its own suite. Off by default. +- cfdbd59: Post-merge now queues the quality follow-ups instead of running them (#556), which is what the #326 doc says and what composes with the backlog loop (#323/#538). On `setReadyForMerge()`, a `--post-merge` run used to fire maintainability, readability and security-audit as three child `framework prompt` runs back to back, on the spot. It now fires one short turn that appends "Apply preset X on the changes introduced by " entries to the session's TODO file, and lets the loop pick them up. Cheaper by a lot: a few TODO lines rather than three full preset passes serialized on the same git index. + + The readability entry is gated on Technical control, per the doc. That setting already existed as a preference, a `--technical` flag and a Global options toggle; it just never reached the prompts, so `TfContext` gains `settings.technical_control` and `session_name`. The session name is carried on run state: the agent sets it before its first change and the post-merge prompt reads it afterwards. + + `--eco-auto-maintenance` does something again. #326 moved the maintenance section out of the system prompt, which left the flag inert (#555); the post-merge prompt is exactly that section, so the flag now skips it. + + The post-merge prompt is flattened rather than verbatim from the doc, and this is the one place the prompts depart from it. The doc nests `${{ tf.session_name }}` inside the outer `${{ ... }}` and puts backticks inside a backtick template literal; the fragment regex is non-greedy, so the outer fragment closes on the inner `}}` and what is left is not valid JS. It throws `TemplateFragmentError` today, with or without the new context fields. Same branch, same output, one fragment, and a test now rejects any nested fragment so the prompt cannot regress into a shape that will not render. + + `POST_MERGE_PASSES` and `runPostMergeSuite` are replaced by `runPostMerge` and `renderPostMergePrompt`. The three preset modules are untouched: the dashboard buttons still use them. + +- 5bd0489: Post-merge TODO entries now carry the preset's `filePath` instead of a bare preset name (#326). The entry reads `Apply .the-framework/presets/.md with tf.params.what set to "changes introduced by "`, and `installProject` materializes the presets into `.the-framework/presets/*.md` so that path resolves to a real file the picked-up agent opens. Closes the fidelity gap where the queue sent a preset name and the agent had to guess the prompt. The materialized presets are gitignored (regenerated on install, tracking the framework version). New: `PRESETS`, `PRESET_DIR`, `presetFilePath`, `presetContext`, `materializePresets`. +- 721f539: Add preset-prompt param substitution (``), the foundation for prompt-preset buttons. A preset prompt template can carry `` placeholders substituted from supplied values or declared defaults; unfilled params are surfaced so a caller can ask the user to fill the blanks. +- db95caa: Standardize the preset prompts on the `${{ tf.params.what }}` fragment syntax (the same the system prompt uses) and retire the bespoke `` primitive. `renderPrompt(what)` is unchanged and produces byte-identical output; the removed exports (`renderPresetPrompt`, `PARAM_PATTERN`, `extractParamNames`, `unfilledParams`, `PresetParamError`, `PresetParam`, `PresetParamOptions`) had no other consumers. Prereq for #326's post-merge preset `filePath` entries. +- d834af8: Dashboard presets only prefill the textarea (#353): the [Research] button now loads the full rendered preset prompt for review and editing, and nothing runs until Start / Ctrl+Enter. The edited text is sent verbatim via a new `prompt` start kind and `framework prompt ` subcommand (the direct path: gates honored, no build pipeline). Clearing the box reverts Start to a normal build run. +- c4a992a: Add a dashboard **Preview** button (#475): serve a project's built result on demand, decoupled from an agent run. One click runs the project's dev script (`dev`/`start`/`preview`/`serve`) and surfaces the live localhost URL it announces, with a **Stop** to tear it down; a project with a plain `index.html` and no dev script is served by a built-in static server instead. The preview lives in the daemon (one per project, idempotent to open) and is torn down on daemon shutdown; the button rehydrates after a reload. A preview that exits on its own (a crash, a build error) is evicted so the next open restarts it rather than handing back a dead URL. Exposed as three Telefunc RPCs (`sendPreview` / `sendStopPreview` / `onPreviewStatus`) and the `startPreview` helper. +- b7de2a1: Add a git-status line to the dashboard project panel: the active branch, a clean/dirty indicator, and the linked PR (number, state, link). Backed by a new `onGitStatus` read; branch and dirty come from git, the PR is a best-effort `gh` lookup that degrades to nothing when gh is missing/unauthed or there is no PR. Hidden when the project is not a git repo. +- 3f12815: Add "Open folder" and "Open in editor" buttons to the dashboard project panel (localhost-only). The daemon spawns the OS file manager (open / xdg-open / explorer) or an editor (the `code` CLI, or `$FRAMEWORK_EDITOR`) on the project's own path. A missing command surfaces a friendly error. Safe on a public host: no local checkout to resolve, so nothing is spawned. +- 4067614: Add an "Open on GitHub" button to the dashboard project panel. When the repo has a github.com `origin` remote, the panel shows a one-click link to it (backed by a new `onGithubUrl` read that normalizes the ssh/https remote forms). Hidden when there is no GitHub remote, so it never shows empty. +- 5108aea: Add the per-project second sidebar and main view. The second sidebar now shows the selected project's loops/prompts (its `.the-framework/LOGS.md`, scoped via `?project=`) with its Runs archive below it, both following the selection. The main view shows the selected or latest loop/prompt claude.ai/code-style (kind, title, status, session link, and a loop's constituent prompts); clicking a loop in the sidebar opens it. On load the most recently active project is auto-selected, so the view is populated immediately. +- 32e9d3e: Add the Projects sidebar to the dashboard: a leftmost nav with Overview (project count plus the most recently active projects), Projects (every registered project with an activation dot and last-activity, from `/api/projects`), and Queue (the open TODO items aggregated across all projects). Selecting a project re-points the project log to `?project=`. The per-project second sidebar and main view come next. +- c48af6d: Queue "needs you" now surfaces paused runs, not just PRs (#636, part of #624): a live run that stopped mid-flight to ask a question shows up alongside open PRs in the Overview card, the sidebar badge, and the #627 browser + Discord notifications. `RunMeta` folds a `pendingChoice` from the `choice`/`choice-resolved` events, and `Intervention` gains a second `kind: 'awaiting'` — the card jumps into that project to answer, and the Discord message reads "awaiting your answer" with a link back to the dashboard. +- 96870d2: Discord notifications for the Queue's "needs you" list (#627): when `DISCORD_WEBHOOK` is set, the daemon watches the interventions queue and posts a message when a new PR lands — so you are notified even with no dashboard open. The PRs already open when the daemon starts are folded into a baseline (no start-up blast); the env var is the opt-in. Complements the in-browser notifications from the same queue. +- 9d1951b: Add the Queue's cross-project "needs you" projection (#632, part of #624): `buildInterventions` rolls up every registered project's open, non-draft PRs (via `gh pr list`, degrading to empty with no remote / no gh), newest first, and exposes them over a new `onInterventions()` dashboard read. This is the first slice of the interventions queue — proposals and finished work both surface as PRs to review or close. +- 5d1653b: Browser notifications for the Queue's "needs you" list (#627): when a new PR lands on the interventions queue, the dashboard fires a browser notification that opens the PR on click. A bell in the header toggles it and requests permission; the preference (`notifyBrowser`, on by default) persists with the others. Existing PRs at page load are folded into a baseline, so you are only told about items that appear while you are watching. (Discord delivery and the paused-run trigger are follow-ups.) +- d10d515: Serve the usage panel's numbers: an `onQuota` RPC returning the account's quota windows plus where the consumption limits stand, backed by a quota source the daemon polls for its whole life (the per-run guard dies with its run, but the panel has to show the account while nothing is running). A host with no agent to ask reports it has no reading rather than an empty one. +- 18c9352: Add `QuotaPoller`: keeps the account's quota reading fresh on a slow timer and feeds the consumption meter. Backs off when the agent's usage fetch is refused rather than retrying into the penalty window, gives up on an authoritative failure, and keeps the last good reading across a transient one. +- cbe1898: Read the account's subscription quota on demand via the agent's own `/usage` command, as `Driver.readQuota()`. Reports the percentage of each window consumed (session, week, per-model week), which is what a consumption limit needs and what the per-turn rate-limit telemetry could not give. Costs no tokens, and the CLI reaches Anthropic with its own credentials, so The Framework never handles the user's token. +- 68d0df4: Capture the agent's rate-limit telemetry. Claude Code reports where the account's subscription quota stands on every turn of its `stream-json` output, and the parser was dropping it. It now surfaces as a `rate-limit` driver event carrying the status, the quota window, and when that window resets, so it persists and reaches the dashboard like any other driver event. New `DriverRateLimit` type. +- f736b55: New [Readability] preset button on the dashboard (#360): prefills Rom's refactor-for-human-readers prompt (architectural seams, linearity/altitude pass, exhaustive per-function rating lists, one commit per refactor) into the start textarea for review or editing; Start runs the text verbatim as a direct prompt run. The one blank, ``, defaults to `this PR`. +- 632f0df: Serve the new Vike + Telefunc dashboard from the run relay (`--share`), in a read-only watch mode. The relay now serves the prerendered SPA and streams events over the same Telefunc `onEvents` Channel the daemon uses, sourced from its in-memory run instead of a file. Only the live event stream is exposed (an empty projects provider neutralizes the file/registry RPCs on the public host, and no run can be started or steered). The shareable viewer URL moves from `/r/:id/` to `/?run=:id` (old links redirect); ingest stays at `/r/:id/publish`. This removes the relay's dependency on the legacy `page.ts`. Adds `makeTelefuncMount`, `serveClientBundle`, `emptyProjectsProvider`, and the `EventsSource` type to the public surface. +- 9442761: Remove the architect. A build no longer runs a turn to pick the app's stack, and no longer tells the agent what to build on: the agent reads the workspace and decides for itself, the same way it would outside The Framework. `buildPrompt` / `extendPrompt` / `scaffoldPrompt` now take just the intent and say nothing about a stack. + + Being opinionated about the stack is a hard thing to do well, and a system prompt that nudges one is worse than none at all (#545). The stack guidance we had was not designed, it accumulated. It goes rather than half-ships. + + Gone with it, because the architect was their only source: + + - the plan-approval gate ("Approve this plan?" / "Use X instead") and re-architect. The agent-authored await gates a build turn raises are unaffected: a build that stops to ask still pauses the run with Approve / Decline. + - the decisions ledger in a run, and the `DECISIONS.md` a run wrote from it. `@gemstack/ai-autopilot`'s `decisions/` module is untouched and still exported; nothing in a run feeds it now. + - the dashboard's "Stack & rationale" and "Decisions ledger" panels. Loop status, deploy, and session cards are unchanged. + - `@gemstack/ai-autopilot`: `agentArchitect`, `STACK_TRADEOFFS`, `BootstrapSteps.architect`, `BootstrapOptions.ledger`, the `architect` bootstrap event, `ArchitectPlan` / `ArchitectContext` / `ArchitectDecision` / `ArchitectAlternative`, and the `plan` field on the build / loop / deploy contexts and on `BootstrapResult`. The flow is now scope -> build -> loop -> deploy. + - `@gemstack/framework`: `driverArchitect`, `reArchitect`, `architectPrompt`, `parseArchitectPlan`, `architectPlan`, `decisionLedger`, `RunFrameworkResult.ledger`, and the `bench:architect` benchmark. + +- eb1a0f1: Remove AI meta-select. A run no longer spends an agent turn guessing which Open Loop domain preset, modes, and build event kind to run under; a preset is used only when you ask for one with `--preset` or `the-framework.yml`, and otherwise the plain framework flow runs. + + The routing turn injected a prompt of its own before the build started, which meant part of what the agent ran under was chosen mid-run by another model rather than by the user (#545). Removing it also makes a run's prompt knowable before it starts. + + Gone with it: the `--no-auto-preset` flag (there is nothing left to opt out of), the `autoSelectPreset` / `workspaceSummary` / `metaSelect` / `presetCatalog` / `parseMetaSelection` / `META_SELECT_*` exports, and the `bench:meta-select` benchmark. + +- 5e24797: Remove the persona, skill, and project-memory framing. A run's system prompt is now the built-in #326 prompt plus your own `SYSTEM.md`, and nothing else. Nothing is read off disk and appended when the run starts. + + A build used to append the personas and skills for its detected stack plus the full contents of the repo's memory files. On one measured 8,852-character build prompt that framing was about 5,000 characters, more than the designed prompt it was wrapping. None of that text was designed; it accumulated. Prompt text nobody reviewed is a defect, not a feature (#547). + + Two things fall out of this: + + - **The prompt preview is now exact.** The dashboard's "See actual prompt sent" (#520) had to carry a caveat that a build run appends more at run time. It no longer does, so the caveat is gone and what you read before the run is what the agent gets, for every run kind. + - **A build stops being opinionated about the stack.** #545 removed the architect turn, but the personas still hard-instructed a stack ("Default to Prisma"). With both gone, nothing tells the agent what to build on. + + Skills and project memory are worth having as designed features later. They are not worth keeping in this shape. + + Removed from `@gemstack/framework`: the `memory` / `extensions` / `composeExtensions` options on `runFramework`, the `framing` option on `composeRunSystem` (`RunSystemOptions` is now `SystemPromptOptions`), `loadRepoMemory` / `memoryFraming` / `MEMORY_FILES`, `discoverExtensions`, and the `--compose-extensions` flag. `readProjectSignals` moved to `project.js` and is still exported from the root; preset detection still runs and still narrates `Detected `. + + Removed from `@gemstack/ai-autopilot`: the `personas/` and `extensions/` modules (`definePersona`, `composePersonas`, `personaInstructions`, `personaTools`, `personaAgent`, `personaWorkers`, `personaRoster`, `stackPersonas`, `neutralPersonas`, `presetPersonas`, `defineSkill`, `SkillRegistry`, `composeSkills`, `skillInstructions`, `FrameworkExtension` and its registry). `Preset` is now `{name, framework, signals}`, a pure detector; `DomainPreset` loses `skills` and keeps its loops, prompts, and modes. + + `@gemstack/ai-skills` is untouched. It is a different thing (an on-disk `SKILL.md` loader for ai-sdk agents) and is unaffected by any of this. + +- dac7613: Rename the "post-merge" prompt to "on-before-mergeable" (#592). It fires on `setReadyForMerge()`, before the merge, so "post-merge" was a misnomer (Rom's call in #559). Renamed end to end: the `--post-merge` flag is now `--on-before-mergeable`; `runPostMerge` / `renderPostMergePrompt` / `PostMergeContext` / `POST_MERGE_PROMPT` become their `OnBeforeMergeable` equivalents; the prompt file is `on_before_mergeable_prompt.md`; and the dashboard preference key `postMergeQuality` is now `onBeforeMergeableQuality` (a saved toggle resets to its default once). No agent-facing prompt text changed: the string "post-merge" never appeared in any prompt. The dashboard's visible "Post-merge cleanup" label is left as-is pending a copy decision. +- 7f9c514: Rename the flat backlog file from `TODO-AGENTS.md` to `TODO_AGENTS.md` (#674): underscore is the more standard convention (per Rom's "convention over proprietary" call). New backlogs are created at `TODO_AGENTS.md`; the brief hyphen spelling is still read as a fallback so no repo loses a backlog, alongside the existing `tickets/TODO.md` and root `TODO.md` fallbacks. Also expands the `GOAL.md` context gloss to match the revised #683. +- 98f44e2: The [Research] preset (#331): `framework research [what]` and a [Research] button on the daemon dashboard run Rom's problem-variability review as a direct prompt via the new `runPrompt()` path, which honors await gates (showChoices/showMultiSelect) but skips the scope/build scaffolding. The "what" defaults to `this PR`. +- aafbb55: Retire the legacy `page.ts` dashboard and its HTTP routes (#426, part 3). Both consumers are now on the new Vike + Telefunc dashboard (the daemon default, per-run/resume, and the relay), so `startDashboard` now serves only the prerendered SPA plus the `/_telefunc` mount (RPCs + the live-event Channel). Removed: the `dashboardHtml` and `parseStartOptions` exports, the in-process `Dashboard.push`/`Dashboard.stream` (the SPA reads `events.jsonl` over the Channel and steers over `control.jsonl`), and the now-unused `DashboardOptions` fields (`onStop`, `onChoice`, `cwd`, `dashboardMode`) and the `FRAMEWORK_DASHBOARD=legacy` escape hatch. A `--no-persist` foreground run (or an install missing the built bundle) now runs headless rather than falling back to the old page. +- 43d7fa0: Add the [Security audit] preset (#461): an exhaustive, direct security pass over a target (defaults to `this PR`), shipped alongside [Research], [Readability], and [Maintainability]. It lists every aspect considered with a per-aspect verdict and fixes each issue in its own commit. Available as a dashboard Start-a-run button and exported as `renderSecurityAuditPrompt`. It is also the third of the post-merge quality prompts #326 fires on `setReadyForMerge()`. +- b8c45a7: Let the user see the system prompt. Under the prompt editor, a `▶ See actual prompt sent` toggle shows the built-in prompt in full, with the `Vanilla` checkbox renamed to `Disable system prompt` (nobody knows what "Vanilla" means; the persisted `vanilla` key is unchanged). The preview renders through `composeRunSystem`, the same function a run composes with, so the toggles are shown doing what they really do. + + The event log now renders the run's `system-prompt` event in full too. That event has always carried the exact text handed to the agent, and the dashboard was reducing it to a char count and dropping the rest, so the true prompt was already reaching the browser and being thrown away. + + Reading the user's `SYSTEM.md` moves to `system-prompt-file.ts`, leaving `system-prompt.ts` free of Node imports so the composition can be imported in a browser. A test walks the compiled client barrel's import graph and fails if anything reachable from it imports `node:*`. + +- 4d4d77c: Select the model from the dashboard (#628): a model picker sits under the prompt textarea (Default / Opus / Sonnet / Haiku) and persists as a `model` preference. It flows through as the run's `--model`, so the wrapped agent runs on the chosen model; empty means the driver's own default (no flag). A full model id set directly in the registry works too — the aliases are just the common Claude Code ones, since it is the default driver. +- 68d53ff: Serve action: pick a server in a multi-package repo (#651). The dashboard's Serve button previously ran the first `dev`/`start`/`preview`/`serve` script from the repo root, which serves nothing (or the wrong thing) in a monorepo where the apps live in workspace packages. It now lists the servable apps across the repo, the root plus each workspace package that has a serve script (resolved from `pnpm-workspace.yaml` or the package.json `workspaces` field), and offers a picker when there is more than one. The daemon remembers the last pick per project so re-serving is one click. A single-app repo is unchanged. +- 8910ed3: Show the exact prompt sent to the agent each turn. The run feed used to render a turn's start as just `> prompt sent` and drop the text; now the terminal/log formatter shows a one-line preview, and the dashboard event feed renders the full prompt in a collapsible block (click to expand) for both live runs and replays. The prompt was already carried on the driver `start` event and persisted, so this is a display-only change that surfaces it. +- 03ca1b0: Show the real prompts on the dashboard (#343). The framework now emits the exact system prompt it runs the agent under as a `system-prompt` event at session start (both the direct-prompt path and the full build path). A new "Prompts sent to Claude Code" panel renders it alongside each turn's user prompt (harvested from the `driver` `start` events already in the stream), so the normally-hidden prompt is fully visible for transparency. Prompt text renders as inert text, never markup. Read-only; nothing is gated on it. +- 34d3ec2: feat(framework): extract a shared single-select gate primitive (`requestChoices`) (#335) + + The single-select choice gate (#304) is now a reusable `requestChoices({ id, title, options, recommended })` export, the twin of `requestMultiSelect` (#332): it emits the `choice` event, parks for the pick, and falls back to the recommended option if the run is headless or aborts. It is the primitive the system prompt's `showChoices()` and the research preset need. No behavior change for existing runs. + +- c762529: Assemble a run's system prompt in one place. The build path (`runFramework`) and the direct-prompt path (`runPrompt`) each inlined the same composition (the #326 prompt block, then the always-on emit protocols), and the two drifted apart, which is what dropped the #326 action layer from `--vanilla` builds (#500). Both now go through a single exported `composeRunSystem()` in `system-prompt.ts`, with unit tests pinning the order and the unconditional emit protocols so the two paths can never diverge again. +- c72d155: Give the dashboard clear feedback when a run is started. A run is spawned detached, so there was a gap between clicking Start and the first event (and a failed launch produced nothing, so the page looked frozen). Now clicking Start shows an immediate "Starting your run..." banner; if no output arrives within ~8s it warns that the run may have failed to start; a run-launch/exit failure surfaces as an error banner; and a rejected Start (a run is already active) shows a clear "busy" banner instead of a tiny note. +- c6d005f: Add the "Suggest new tickets" preset (#462), the Agentic PM ideation prompt. Like the other presets it prefills the dashboard editor and runs as a `prompt` kind. Per #674 the prompt is a single line, "Suggest new tickets": the run-start context fragment (#683) already points the agent at the existing `tickets/**.md` and the `.the-framework/ticketing-format.md` spec (#684), so it does not need to re-teach the ticket format or spell out the flow. Per the settled #624 model the proposal is just a PR: merging accepts the tickets, closing rejects them. +- 2fc612a: Sync the built-in system prompt with the #326 doc (#555). The shipped prompt was the 11-Jul draft: the doc was rewritten on 13-Jul and never synced, so every run since has been driven by a stale prompt. `prompts/system_prompt.md` is now byte-identical to the doc again. + + What the agent gets that it did not before: `## Analyze the user prompt`, which analyzes the prompt up front and records the results in an `ANLYSIS_RESULT.md`; `## Before starting changes` -> `### Session name`, which commits any dirty tree, then creates and checks out a `the-framework/` branch before the first change and calls setSessionName(); and `## After applying changes`, which calls setReadyForMerge() once the session has no work left. `## Unclear scope` is now `### Ambiguous prompt`, `## Large scope` is now `### Scope`, and `## Alternatives` moves under `## Before applying changes`. The branch step is the notable one: it previously reached the agent only as an aside in the signal protocol, so the doc's own instruction never shipped. + + `showMarkdownSecondary()` is emitted as the same `show-markdown` block as `showMarkdown()`, per the doc: for the MVP the two are equivalent. + + Also fixes the eco flags, which the sync would otherwise have broken silently (#314). They drop sections from the prompt by exact heading string, and the rewrite renames or moves every heading they matched; a missing heading is a no-op, so `--eco-auto-planning` and `--eco-auto-research` would have quietly stopped trimming anything, with no test failure to catch it. They are retargeted at `### Scope` and `### Alternatives`, the drop is now level-aware so removing a `###` stops at its sibling instead of swallowing the next `##`, and the tests assert a flag actually shortens the prompt rather than asserting a heading is absent (which passes for free once that heading is gone). + + `--eco-auto-maintenance` now drops nothing and is inert: the maintenance section left the system prompt for the post-merge prompt, so those tokens are already saved for every run. The flag stays parsed and persisted, and re-points at the post-merge prompt when that lands (#556). + +- 5c83bc2: The built-in system prompt is now Rom's #326 text, verbatim, replacing the anti-lazy-pill it grew out of: unclear scope becomes a ranked `showChoices()` list, a large scope a `PLAN_.agent.md` to approve, a very large one also a `TODO_.agent.md` backlog, an alternatives pass rates problem "variability" before code is written, and edits to existing code stay minimal. The prompt is a template (#350): `${{ ... }}` JS fragments render against the run context, so `tf.params.autopilot` relaxes the maintenance stance on autopilot runs and `${{tf.prompt}}` carries the user prompt slot. New exports: `SYSTEM_PROMPT_TEMPLATE`, `renderSystemPrompt`, `renderTemplate`; the `ANTI_LAZY_PILL` export is gone (the `antiLazyPill` config key still toggles the built-in prompt). `--autopilot` now has an effect without a preset. +- 9345476: Record every finished run in the project log `.the-framework/LOGS.md` (#379). When a run ends, the CLI appends an entry with the intent/prompt title, the kind (build or prompt), the final status (done/stopped/failed), and the Claude Code session id and link. Best-effort, so a log write can never break a run. This is what makes the project DB (#378) fill itself; the run-history sidebar in #314 reads from it. +- 59e3707: New `.the-framework/LOGS.md` project-log module (#378): `appendLog`/`readLogs` keep a human-readable markdown log of every loop, prompt, and build in a project, with `renderLogEntry`/`parseLogs` as the pure core over the same StoreFs seam as the run store. Parsing is forgiving: a malformed entry is skipped, never thrown. Standalone for now; the run-lifecycle wiring and dashboard UI land in follow-up issues. +- 6b561fc: Add project repo helpers (#380): `isActivated()` checks the `.the-framework/` activation marker via an injectable `ProjectFs`, and `crawlRepoFiles()` lists every tracked + untracked (gitignore-honoring) file via `git ls-files -z` behind an injectable `GitRunner`. Both forgiving: any failure reads as not-activated / an empty list. Building blocks for the #314 sidebars. +- 883d974: Add the ticket-format spec (#684): `ticketing_format.md` describes the `tickets/_.md` and `.spike.md` file shapes (including the optional `priority:` and `topics:` fields). Per #674 it ships inside the package and the run-start context fragment references it by its `node_modules` path, so the format versions with the package rather than being materialized into each repo. +- 83e6a1f: Keep the flat backlog under a root `tickets/` directory (`tickets/TODO.md`) instead of the repo root, so The Framework rides on a plain, visible convention (beside `DECISIONS.md`) rather than a proprietary file (#629). New backlogs are created there, the dashboard surfaces it, and a legacy root `TODO.md` is still read so existing repos keep their backlog. Session-scoped `TODO_.agent.md` files are unchanged. +- 5dcd8a4: Replace the dashboard's Start-a-run textarea with a rich prompt editor (Tiptap). Type `/` for commands (load a preset, or insert an agent action like `showMultiSelect()`) and `@` for references (the repeated macro tags `` / `` / `` / ``, and the registered projects — a project mention also adds its repo to the run context). Tokens render as chips but serialize back to the exact plain text the agent already reads, so the run contract is unchanged. Markdown is live (StarterKit shortcuts) and round-trips faithfully, so a loaded preset comes back essentially verbatim with its tags chip-ified. +- 3bd0478: Move the flat backlog from `tickets/TODO.md` to a root `TODO-AGENTS.md` (#682), so `tickets/` holds only tickets. New backlogs are created at `TODO-AGENTS.md`; the loop, the resume-note appender, and the dashboard doc sidebar all read it, and existing `tickets/TODO.md` (and a pre-#629 root `TODO.md`) are still read as fallbacks so no repo loses its backlog. Exposes `LEGACY_TICKETS_TODO_FILE` alongside the existing `LEGACY_TODO_FILE`. +- d1202dc: The backlog loop (#323): after the build settles, the run consumes the agent's own TODO backlog (`TODO_.agent.md`, or the flat `TODO.md`) one entry per turn until it is empty. When a dashboard can answer, the loop gates before each entry ("start the next item?"), so autopilot consumes the backlog unattended and autopilot-off pauses per item. Caps make it safe overnight: the budget/Stop signal ends any turn, `--max-todo-items` bounds the run (default 25), and two no-progress items stop the loop. `--no-todo-loop` opts out. +- e453bba: Transparent mode (#625): a coarse master off-switch that makes a run identical to plain `claude -p ` — the "only pick what you need" requirement, at its extreme. Turn it on and the wrapped agent runs fully raw: no framework system prompt, no AWAIT/SIGNAL emit protocols, no consumption guard, no dashboard, no TODO loop. + + Available at all three tiers: the `--transparent` flag, a `the-framework.yml` `transparent: true` key (per project), and a `transparent` user preference surfaced as the "Transparent" toggle in the dashboard's run options (it overrides the other option toggles, and the "Actual prompt" preview correctly shows an empty channel). + + This also closes the gap where `--vanilla` was advertised as "fully transparent" but still injected the AWAIT/SIGNAL protocols into the system channel: `--vanilla` keeps that emit contract (so the agent can still drive the dashboard's gates), and `--transparent` is the new switch that drops everything for a genuinely raw run. `composeRunSystem` now returns an empty string under transparent, the single place the whole system channel is assembled. + +- e4b518a: feat(framework): turn an agent's showChoices()+AWAIT into a live gate at the turn boundary (#337) + + The system prompt tells the agent to `showChoices()` and `AWAIT` at unclear-scope / alternatives points, but until now only framework-emitted gates (multi-select) could pause a run. Now when a build turn ends by asking the user, an `await-choices` block, the framework shows the choice on the dashboard, waits for the pick, and re-prompts the agent to continue from that decision. It is a no-op when headless and when the agent just finishes instead of asking, so existing runs are unchanged. + +- bc3586b: Keep everything in a single `.the-framework/` directory (#313). The transient run state (`events.jsonl`, `run.json`, `runs/`, `control.jsonl`, `daemon.json`) now lives in `.the-framework/` alongside the committed project log `LOGS.md`, instead of a separate `.framework/` directory. `install` seeds a `.the-framework/.gitignore` that ignores everything except `LOGS.md`, so the run state stays transient and only the log is committed. +- 7db5a9c: feat(framework): track agent spend and add a budget cap (#322) + + The framework now accumulates the token + cost usage the wrapped agent reports each turn, streams a running total as a `usage` event, and shows a live spend readout on the dashboard header. Pass `--max-cost ` to stop a run once it has spent that much: the current turn finishes, then the run stops cleanly (not a failure). Useful for long autopilot runs where you only review the result at the end. + +- 3302b0f: Add the usage panel: what the account has left (the agent's own quota windows) and how much of it The Framework may spend before it pauses itself (the three consumption limits, each with a checkbox and a bar). Replaces the dashboard's "Usage & credits" placeholder. +- 5417558: Add the [UX] preset (#472): a direct, interactive usability review of a target (defaults to `this PR`), shipped alongside [Research], [Readability], [Maintainability], and [Security audit]. It enumerates every finding as a categorized, reference-numbered list of choices via `showChoices()`, stops for the user to accept proposals, then works on the accepted ones. Available as a dashboard Start-a-run button and exported as `renderUxPrompt`. +- 8d396f7: Add a git-worktree lifecycle module (`addWorktree` / `listWorktrees` / `removeWorktree` / `pruneWorktrees`), the foundation for running multiple tasks concurrently on one repo (#453). Each run will get its own checkout under `.the-framework/worktrees/` so concurrent runs never fight over the working tree. This slice is the isolated, unit-tested plumbing only; the daemon wiring, per-worktree concurrency, and dashboard changes land in the sibling #453 issues, so nothing changes at runtime yet. + +### Patch Changes + +- e65e16a: Fix the agent-CLI runner emitting a spurious `error` event after a run is aborted. On abort the turn rejects and settles, but the killed child process still fires `close` afterward, and the close handler emitted an `error` (and would have emitted `result`) telemetry event before checking whether the turn had already settled. The dashboard event stream saw a phantom agent error after a clean Stop. The close handler now returns early once the turn has settled, so an abort produces exactly one outcome. +- 5844526: Rework the run's agent + model picker into a tree (#656, #658). The dropdown's top level is the coding agents, each showing its logo (Claude / Codex, #656); hovering an agent reveals only that agent's own models, and picking a model sets both the agent and model together — so an incompatible pair (e.g. Codex with a Claude model) can no longer be chosen. The trigger shows the current agent's logo then the model, with the agent name in the tooltip. +- 6721c0f: Untangle the two "autopilot" concepts in the dashboard (#325): the countdown text now reads "Auto accept in 10s" (and "Auto accept canceled" / "Auto accept off"), so "autopilot" is left to mean the mode preset. The checkbox that arms the countdown is labeled "Autopilot", per Rom's call on the issue. +- 8c576df: Adding a project that isn't a git repo now initializes one for you instead of failing with `fatal: not a git repository`. `installProject` detects a non-repo folder and runs `git init` before its usual commit-and-install flow, so a plain directory can be added straight from the dashboard. The install result reports `initialized: true` when it did so. +- be0a58c: Fix backlog turns dropping the agent's signals. The backlog loop prompts through the run's own driver session, so a backlog turn carries the same signal protocol as any other turn, but it only ever parsed await gates. `showMarkdown()` views never reached the dashboard rail, `setSessionName()` was ignored, and `setReadyForMerge()` never emitted `ready-for-merge`, so `--post-merge` could not fire from backlog work. The turn-signal parsing (views, session name, ready-for-merge) was duplicated verbatim in the build path and the direct prompt path and missing from the third; it is now one `createTurnSignalEmitter` used by all three, with the backlog loop sharing a single emitter so `ready-for-merge` still fires once across every item. +- 7a94b48: Fix `framework --version` (and the bare-`framework` footer) reporting `0.0.0` instead of the real package version (#312). The version is now read from the package's own `package.json` at runtime, so it always matches what is installed. +- aac6e5d: Tidy the Start-form run controls (#654): the Presets and Agent·Model dropdowns are now compact, the six Global options (Autopilot, Technical control, Disable system prompt, Eco, Post-merge cleanup, Browser) collapse into one "Options" checkbox dropdown next to Presets (with Eco's sub-drops when Eco is on), and the Agent·Model menu sits at the end of the row. +- cdfe508: Show the files picked into a run's Context (#661). Files added via a `#` mention or the right-rail file tree were counted ("Context · 1 selected") but never shown, so clearing the prompt left them selected with no way to see or remove them. They now appear inside the Context section, listed like the repo rows but with an X to remove (which also unticks the file in the tree, since they share one context set). The Context section's contents get the same bordered box as the prompt disclosure, and that disclosure is renamed to just "Actual prompt". The Context header now breaks its count down as "N projects · N files", and the right-rail Files tab badge counts only selected files (not the whole-repo entries that also live in the context set). +- d4fe2e5: Don't offer the current project as a Context focus target (#665). The Context → Projects list is for pulling _other_ repos into the agent's focus; the current project is already the run's workspace, so ticking it was redundant. It's now excluded from the list (and from the "N projects" count), with a "No other repos to add" hint when it's the only registered project. +- 5646b16: Lay out the expanded Context section as two columns (#663): a "Projects" column (repo checkboxes) beside a "Files" column (removable file rows), each under its own heading. The Files column shows a hint when nothing is picked, and the repos' "can still reach the rest" note moves to the Projects heading tooltip. +- 65e27fd: Tidy the run controls row (#668): the Global-options button becomes a gear icon with the on-count as a small corner badge (no "Options" text), the agent/model picker moves to the start of the row, and the "Start run" button sits at the end of that same row (the note/error stay below). +- e0404cf: Stop the daemon from registering its own cwd as a duplicate project. When the daemon runs from a subfolder of an already-tracked repo (e.g. the package dir the binary lives in), it created `.the-framework/` for its own state and then re-added that subfolder as a nested project on every boot. `registerHomeProject` now skips a cwd that lives inside an already-registered project. +- dcea89b: Fix `framework stop` returning before the daemon has actually exited (#514). It signalled SIGTERM and removed the state file straight away, so restarting immediately raced the old process for the port: the new daemon hit EADDRINUSE, never reported itself ("the daemon did not come up in time"), and the old one kept serving a stale bundle with no state file left to stop it by. `stopDaemon` now waits for the process to exit before returning, escalating SIGTERM to SIGKILL if a wedged shutdown outlasts the grace period. +- 900efbb: Center the dashboard's main grid in the content column. `main` had a `max-width: 1100px` cap but no horizontal centering, so on a wide window the panels hugged the left edge next to the runs sidebar. Add `margin: 0 auto` so the capped grid sits centered. +- 48aba07: Make the dashboard layout fill the viewport height. `#layout` only grew to its content height, so on a short page the runs-sidebar right border stopped partway down instead of reaching the bottom. Give `#layout` a `min-height: calc(100vh - 57px)` (matching the sidebar's existing header-height key) so the stretched sidebar runs full-height. +- ed25ab8: Keep the dashboard header and sidebar in view while scrolling. The header is now sticky at the top (with a background and z-index so content scrolls under it), and the app-running banner and the runs sidebar stick just below it. On a long page you no longer lose the title, stop button, and run list when you scroll down. +- 131f349: fix(framework): surface session-scoped PLAN/TODO docs in the dashboard sidebar (#323) + + The document sidebar now also surfaces the session-scoped `PLAN_.agent.md` / `TODO_.agent.md` files The Framework writes per run (#323/#326), not just flat `PLAN.md` / `TODO.md`. Flat files stay supported as a fallback for hand-written docs. Names are matched against the workspace root with a fixed slug pattern, so there is still no path traversal. + +- f1ff0d2: Fix the Claude Code driver reporting `costUsd: 0` when a result line carries token usage but no price. `DriverUsage.costUsd` is documented as omitted (never `0`) when there is no price, because the budget cap reads `0` as "this turn was free" rather than "the price is unknown" (#540). The driver now omits the field in that case, matching the Codex driver and the type's own contract. Claude runs that do report a price are unchanged. +- 4a741f6: `runPostMerge` now materializes the quality presets before queueing, so the post-merge TODO entries' `filePath` values always resolve (#598). Previously the presets were written only on install and are gitignored, so a repo activated before that feature shipped, or a fresh clone, had no preset files and the queued entry pointed at a path that did not exist. Best-effort: a materialize failure is reported, never fatal. +- c05a186: Harden the dashboard against cross-site abuse and event-borne XSS. The state-changing dashboard routes (`/stop`, `/choice`, `/api/start`) now reject any request whose `Origin` is a foreign site, so a page on another origin can no longer drive the localhost dashboard into spawning or steering a run (a non-browser caller that sends no `Origin` is unaffected). The client render pipeline no longer trusts event strings: link URLs (session link, preview URL, run-history link) are scheme-checked so a `javascript:` URL collapses to `#`, and the HTML escaper now escapes quotes so a relay-published event can't break out of an attribute (e.g. a choice option id like `x" autofocus onfocus=...`). +- ee075ec: Fix the #326 action-layer protocols being dropped from a build run's system prompt when the built-in prompt is off. `runFramework` nested the `AWAIT_PROTOCOL` and `SIGNAL_PROTOCOL` blocks inside the built-in-prompt branch, so a `--vanilla` build (or `antiLazyPill: false` via `the-framework.yml`) with no `SYSTEM.md` injected neither — leaving the agent with no way to emit `set-session-name` / `ready-for-merge`, so `setReadyForMerge()` and the `--post-merge` quality suite silently never fired. The protocols are now appended unconditionally, matching the direct-prompt path (`runPrompt`). +- 06fefbe: Apply Rom's #559 review to the business-knowledge docs (#537): drop `README.md` (a repo's own `README.md` already covers the overview), move `DECISIONS.md` and `KNOWLEDGE-BASE.md` to the repo root, and show each doc's one-line gloss in the injected `Context:` too, not just the post-merge prompt. The `## Business knowledge` prompt text is now his verbatim wording. +- c584b16: Fix "last activity" so it reflects runs, not just `LOGS.md`. A project's `lastActivityAt` is now the newest of its latest `LOGS.md` entry and its most recent run (live or archived), so a project with runs no longer reads "no activity yet" just because a run stopped before writing to `LOGS.md`. +- 79af200: Report a failed relay publish instead of dropping it. `relayPublisher` never checked the HTTP response, so only a thrown fetch reached `onError` and every error status was silent: `--share ` printed a shareable link and then reported nothing, forever. +- c06532e: Consolidate the dashboard header's three notification icons (browser bell, Discord, activity pulse) into one labeled "Notifications" bell that opens a popover (#676). The popover groups the toggles the way the model actually works: a "Deliver to" section (Browser, Discord) for where notifications go, and a "Notify me about" section where "Needs you" is shown as always-on and "New activity" is an opt-in toggle. The bell shows an active state and dot when a delivery method is on. Purely the header control; the underlying preferences and notification hooks are unchanged. +- 43bae91: The on-before-mergeable follow-up no longer strands its output on a branch nothing merges. It was spawned as a plain `framework prompt` run, so it inherited the #326 system prompt's `### Session name` step and committed + created + checked out a fresh `the-framework/` branch before writing anything. Its output (the queued quality TODO entries and the business-knowledge docs, `DECISIONS.md` / `KNOWLEDGE-BASE.md`) landed on that branch, which nothing merges, so the next run branched from main and could not see it. The follow-up is a follow-up to a session, not a session of its own, so it now runs `--vanilla` (no built-in prompt, hence no session-name step) and stays on the session's current branch, where its output rides to review and merge with the work. +- f50f0d5: Fix the dashboard's event tail dropping a same-length rewrite. There were two JSONL tailers: `JsonlTailer` detects an in-place truncate both by the file shrinking and by it being rewritten to the same length (mtime advanced), while `tailEvents`, which is what the dashboard Channel runs, only checked for a shrink and never read mtime. A fresh run that rewrote `events.jsonl` to the same byte length was invisible to the dashboard. The two tailers, and the two hand-rolled `fs.watch`-plus-poll drivers behind them, are now one `JsonlTailer` + one `followFile`, so the run's control tail and the dashboard's event tail share the tested behavior instead of drifting. `tailEvents` had no test of its own; it has three now. +- d1331a2: Collapse the Start-form preset controls into one "Presets" dropdown (shadcn base / Base UI). The built-in presets, the user's saved presets (each removable), and "New preset…" now live in a single menu instead of a row of buttons, keeping the prompt area compact as presets grow. +- 1f1a2a3: Reconcile orphaned runs on daemon start. A run a dead process left marked `running` (a crash, kill, or daemon restart) no longer shows as active forever with a no-op Stop: a freshly started daemon drives no in-flight run, so at boot any such run across registered projects is flipped to `stopped` (the live one archived first, keeping its history). +- 1e1b4dc: Store the multi-project registry as a single file, `.bashrc`-style: `$HOME/.the-framework.json` (or `$XDG_CONFIG_HOME/the-framework.json`) instead of a `projects.json` nested inside a `.the-framework/` directory (#390). +- 28c3330: Fix the relay's publish-body reader corrupting multibyte payloads and mis-applying its size cap. It decoded each TCP chunk independently (`body += chunk`), so a multibyte UTF-8 codepoint split across a chunk boundary decoded to replacement characters; and it compared the running string's `.length` (UTF-16 code units) against `maxBodyBytes`, so the cap was wrong for any non-ASCII body. It now accumulates raw `Buffer`s, caps on the byte count, and decodes once at the end. +- 734da1a: fix(framework): harden the run relay and workspace sandbox against resource exhaustion + + - The relay now caps how many runs it holds in memory and evicts the least-recently-used one on overflow. Because it is unauthenticated, an anonymous request to `/r//…` could previously create per-run state that was never freed; run creation is now bounded (`maxRuns`, default 200). + - A disconnected SSE viewer now cancels its stream iterator, releasing its waiter immediately instead of lingering on the stream until the next event (which may never arrive for an idle run). + - `snapshotWorkspace` checks a file's size before reading it, so a large asset in the workspace is skipped without ever being loaded into memory during a `--sandbox docker` sync. + - `relayPublisher`'s POST has a timeout, so a relay that accepts a connection but never responds can no longer hang the CLI on exit (`flush()`). + +- 2a12ec8: Remove the "Vike · React · shadcn · Telefunc" tech-stack line from the dashboard header. +- 4a70c5a: Fix `savePreferences` rejecting the RPC when the underlying write fails. The telefunction advertises a `{ ok: false, error }` result and already returns it for the not-enabled case, but a failed disk write threw straight through, so the client saw a rejected call instead of the typed error. The write is now wrapped, so both failure modes return `{ ok: false }` and the client handles them the same way. +- a76ace7: Seed a run's intent (its prompt) when the run store opens, so the dashboard's Runs list labels `prompt` and `research` runs with their prompt instead of "(no prompt)". Only build runs emitted a `bootstrap` scope event carrying the intent; a direct-prompt or research run had none, so its row showed no label. A build run still refines the seeded intent via its scope event; research with no "what" seeds the same "this PR" default the log title uses. +- 437618f: Fix transparent mode so it is actually raw Claude Code (#678). Transparent (#625) is meant to run identical to `claude -p `, but a build-kind run (a plain typed prompt, the dashboard default) still went through the full `runFramework` orchestration (scope, plan, dispatch, synthesize, production-grade pass) and sent the wrapped `extendPrompt`/`buildPrompt` text to the agent instead of the raw prompt, because run-path routing keyed only off the `research`/`prompt` subcommands. Transparent now routes any run through the raw prompt path, so the prompt runs verbatim with no build orchestration and no wrapping. Research rendering still applies only to a genuine (non-transparent) research run. +- caf8a0b: Give the run-form disclosures one consistent style (#659). "See actual prompt sent" and "Context" were styled differently (different triangle glyph, weight, and indent); both now use a shared `DisclosureToggle` — a chevron that rotates when open, then the label — so they read as the same control. +- Updated dependencies [734da1a] +- Updated dependencies [df15f71] +- Updated dependencies [9442761] +- Updated dependencies [5e24797] + - @gemstack/ai-autopilot@0.10.0 + ## 0.8.0 ### Minor Changes diff --git a/packages/framework/package.json b/packages/framework/package.json index 010a2899..30ba66e3 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -1,6 +1,6 @@ { "name": "@gemstack/framework", - "version": "0.8.0", + "version": "0.9.0", "description": "The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.", "keywords": [ "ai",