Skip to content

Commit ab26fd6

Browse files
authored
feat(canvas): two-way decision write-back (#352)
Turn canvas pages into a decision surface. The agent declares a decision with canvas_decision_open; the operator answers in the browser via activated <choice>/<approve> controls; the answer flows back into the live session through canvas_decision_await, a bounded long-poll with an event-bus fast path over a durable, restart-surviving inbox using a first-wins claim for exactly-once delivery. Adds an authenticated decision/submit route, the canvas-decision skill, a canvas doctrine rewrite, and a develop decision_surface preference (feature-config Question 8) honored at the design and plan approval gates. Activates the Approve and Choice shortcodes in the admin SPA with plain-text free-text echo and wires the CanvasDecisionProvider. Co-authored-by: elijahr <153711+elijahr@users.noreply.github.com>
1 parent dc625fb commit ab26fd6

51 files changed

Lines changed: 5005 additions & 566 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gemini/config.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Gemini Code Assist app config — exclude large generated lockfiles from review diffs.
2+
have_fun: false
3+
code_review:
4+
disable: false
5+
comment_severity_threshold: MEDIUM
6+
pull_request_opened:
7+
summary: true
8+
code_review: true
9+
ignore_patterns:
10+
- "package-lock.json"

.gemini/styleguide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Flag as **high severity** if the version bump or changelog entry is missing. Fla
2020
## General Review Focus
2121

2222
- Python code should follow PEP 8 and use type hints
23-
- All MCP tool functions must have `@mcp.tool()` and `@inject_recovery_context` decorators
23+
- All MCP tool functions must have the `@mcp.tool()` decorator
2424
- Silent `except Exception: pass` blocks should log the exception
2525
- Prefer top-level imports over function-level imports unless there is a circular dependency
2626

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.72.1
1+
0.73.0

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- **Canvas two-way decisions.** Canvas pages become a decision surface: the
13+
agent declares a decision (`canvas_decision_open`), the operator answers in
14+
the browser via activated `<choice>`/`<approve>` controls, and the answer
15+
flows back into the live session (`canvas_decision_await` — a bounded
16+
long-poll with event-bus fast path over a durable inbox with first-wins
17+
claim and exactly-once delivery, surviving daemon restarts). Adds a new
18+
authenticated submit endpoint, the `canvas-decision` skill (when-to-use
19+
boundary, main-context-only), a canvas skill doctrine rewrite, and a develop
20+
`decision_surface` preference (feature-config Question 8, default `terminal`)
21+
honored at the design and plan approval gates.
1222
- **`/dedupe` Stage 5.5 — structural template floor.** New
1323
`skills/dedupe/references/template-headings.md` allowlist short-circuits
1424
intra-bucket pairs whose `bucket_key` matches a slot in spellbook's

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ Reusable workflows for structured development:
193193
| **Code Quality** | [enforcing-code-quality], [code-review], [advanced-code-review], [adversarial-review], [auditing-green-mirage], [fixing-tests], [fact-checking], [finding-dead-code], [distilling-prs], [requesting-code-review]|
194194
| **Feature Dev** | [develop], [reviewing-design-docs], [reviewing-impl-plans], [reviewing-prs], [devils-advocate], [dispatching-sub-orchestrators] *(deprecated)*, [merging-worktrees], [resolving-merge-conflicts], [creating-issues-and-pull-requests] |
195195
| **Autonomous Dev** | [autonomous-roundtable], [gathering-requirements], [dehallucination], [reflexion], [analyzing-domains], [assembling-context], [designing-workflows], [deep-research], [fractal-thinking] |
196-
| **Specialized** | [async-await-patterns], [using-lsp-tools], [managing-artifacts], [polish-repo], [security-auditing], [generating-diagrams], [shared-references], [tooling-discovery], [canvas], [dedupe], [estimating-tickets], [rounding-up-worktree-sessions] |
196+
| **Specialized** | [async-await-patterns], [using-lsp-tools], [managing-artifacts], [polish-repo], [security-auditing], [generating-diagrams], [shared-references], [tooling-discovery], [canvas], [canvas-decision], [dedupe], [estimating-tickets], [rounding-up-worktree-sessions] |
197197
| **Meta** | [using-skills]†, [writing-skills]†, [writing-commands], [instruction-engineering], [sharpening-prompts], [optimizing-instructions], [dispatching-parallel-agents]†, [smart-reading], [project-encyclopedia] *(deprecated)*, [analyzing-skill-usage], [documenting-tools], [documenting-projects], [testing-strategy], [opportunity-awareness], [branch-context], [permissions-from-transcripts] |
198198
| **Session** | [fun-mode], [tarot-mode], [emotional-stakes], [session-mode-init], [session-resume], [audio-notifications], [agent2agent] |
199199

@@ -258,6 +258,7 @@ Reusable workflows for structured development:
258258
[branch-context]: https://axiomantic.github.io/spellbook/latest/skills/branch-context/
259259
[agent2agent]: https://axiomantic.github.io/spellbook/latest/skills/agent2agent/
260260
[canvas]: https://axiomantic.github.io/spellbook/latest/skills/canvas/
261+
[canvas-decision]: https://axiomantic.github.io/spellbook/latest/skills/canvas-decision/
261262
[dedupe]: https://axiomantic.github.io/spellbook/latest/skills/dedupe/
262263
[permissions-from-transcripts]: https://axiomantic.github.io/spellbook/latest/skills/permissions-from-transcripts/
263264
[distilling-prs]: https://axiomantic.github.io/spellbook/latest/skills/distilling-prs/

commands/feature-config.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,26 @@ Options:
328328
- Work-item level: Tokens gate work item start/complete only
329329
- Gate level (Recommended): Each quality gate requires a token
330330
- Every step: Every phase transition requires a token
331+
332+
### Question 8: Decision Surface
333+
Header: "How should I ask you to decide?"
334+
Question: "When I hit a turning point that needs your direction — a design
335+
approval, a fork between approaches, a blocker — and there's real context to
336+
weigh (several options, trade-offs, a diagram that helps), where do you want to
337+
make the call?"
338+
339+
Options:
340+
- Terminal questions (Recommended): I ask right here with a multiple-choice
341+
prompt. Fast, no context-switch. Best when the choice is quick to grasp.
342+
- Interactive canvas page: I open a browser page that lays out the options with
343+
explanations and diagrams, and you submit your decision there; it flows back
344+
to me automatically. Best when a decision benefits from seeing it visually.
345+
(I still ask in the terminal for quick yes/no gates regardless.)
331346
```
332347

333-
Store all preferences in `SESSION_PREFERENCES`.
348+
Store all preferences in `SESSION_PREFERENCES`. Question 8 stores
349+
`SESSION_PREFERENCES.decision_surface ∈ {"terminal", "canvas"}`, default
350+
`"terminal"`.
334351

335352
**Coupling rule:** If `worktree == "per_parallel_track"`, automatically set `parallelization = "maximize"`.
336353

commands/feature-design.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,20 @@ Task:
153153

154154
### 2.3 Approval Gate
155155

156+
**Decision surface (honors `SESSION_PREFERENCES.decision_surface`):** the
157+
design-approval prompt below is presented via `AskUserQuestion` when
158+
`decision_surface == "terminal"` (default). When `decision_surface == "canvas"`
159+
AND this approval meets the boundary in the "When to Use (testable boundary)"
160+
section of the canvas-decision skill (context-heavy: multiple options with
161+
non-obvious trade-offs, prose/diagram aids, or a hard-to-reverse design
162+
choice), invoke the `canvas-decision` skill instead — render the approval as a
163+
canvas page and await the operator's submission. This wraps the gate; it does
164+
NOT change it: the never-auto-proceed contract holds, and quick yes/no
165+
acknowledgments stay terminal even under `canvas`. Map the submitted decision
166+
to the gate's outcomes — the approve/affirmative value → APPROVE (proceed);
167+
declined/reject value → ITERATE (return to 2.1/2.2); a cancelled or
168+
never-answered decision HOLDS the gate (never auto-proceed).
169+
156170
```python
157171
def handle_review_checkpoint(findings, mode):
158172
if mode == "autonomous":

commands/feature-implement.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,20 @@ Task (or subagent simulation):
106106

107107
### 3.3 Approval Gate
108108

109+
**Decision surface (honors `SESSION_PREFERENCES.decision_surface`):** the
110+
plan-approval prompt is presented via `AskUserQuestion` when
111+
`decision_surface == "terminal"` (default). When `decision_surface == "canvas"`
112+
AND this approval meets the boundary in the "When to Use (testable boundary)"
113+
section of the canvas-decision skill (context-heavy: several plan options or
114+
trade-offs, a diagram that aids the call, or a hard-to-reverse plan
115+
commitment), invoke the `canvas-decision` skill instead — render the
116+
plan/one-pager approval as a canvas page and await the operator's submission.
117+
This wraps the gate; it does NOT change it: the never-auto-proceed contract
118+
holds, and quick yes/no acknowledgments stay terminal even under `canvas`. Map
119+
the submitted decision to the gate's outcomes — the approve/affirmative value →
120+
APPROVE (proceed); declined/reject value → ITERATE (return to 3.1/3.2); a
121+
cancelled or never-answered decision HOLDS the gate (never auto-proceed).
122+
109123
**Interactive mode:** Present findings to user. Ask: APPROVE (proceed to 3.4.5) or ITERATE (return to 3.1/3.2).
110124
**Autonomous mode:** If findings are critical/important → fix automatically (dispatch executing-plans subagent). If minor → proceed.
111125

0 commit comments

Comments
 (0)