Skip to content

Workbench: official scenarios, declarative-lens foundation, plugin SDK v2#275

Merged
haowei2000 merged 3 commits into
developfrom
feat/workbench-scenarios-and-lens-foundation
Jul 20, 2026
Merged

Workbench: official scenarios, declarative-lens foundation, plugin SDK v2#275
haowei2000 merged 3 commits into
developfrom
feat/workbench-scenarios-and-lens-foundation

Conversation

@haowei2000

Copy link
Copy Markdown
Collaborator

Follow-up to #272. Three commits, one theme: the workbench's point is a human and an agent operating the same board — this lands the official scenarios that make that true on day one, and the architecture that will make it true on native clients.

1 — Declarative lens spec + write-back ADR (docs)

  • WORKBENCH_LENS_SPEC.md (draft): lens = YAML binding × widget (table/list/form, then chart/graph) × field types (text, enum, locator, image…). YAML-only collapses the parser axis — the markdown convention parsers existed only because the substrate was plain text. Coverage-checked against the actual source of all four official plugins; the honest gaps (codemap-style arbitrary UI; line- vs comment-preservation semantics) are recorded. Declarative lenses are data, keeping them outside App Store 4.7; HTML plugins stay as the web/desktop escape hatch.
  • WORKBENCH_WRITEBACK.md (accepted): the gateway owns both sides — fs.patch (generic set/insert/remove/move ops addressed by path) and a parsed data field on fs.read. "YAML is a storage format; the wire is JSON; the format never leaves the gateway." Spiked, not guessed: yamlpath (zizmor's tree-sitter crate) resolves paths to byte spans and we splice — everything outside the span survives by construction, and explicit ops beat the web's diff on length-changed arrays because they carry intent. All fixtures pass, including the YAML 1.1 boolean hazard.

2 — Official scenario templates + fs.read.data (server)

Four scenarios ship in the binary and seed at startup, reusing workbench_official::decide (admin deletion sticks within a release; higher version re-seeds; admin-claimed ids never overwritten; API PUT refuses official ids):

id boards
cheers-task-board Todo/Doing/Done kanban + backlog table (priority/status enums)
cheers-code-project plan kanban · issues table (severity + ref) · progress chart · todo · codemap/map.yaml seed
cheers-research-lab experiments table · metrics chart · submissions tracker
cheers-team-ops server inventory · assets/renewals · on-call board

All seed commented-YAML boards rendered by built-in lenses — CI enforces both (no plugin dependency; every viewed file must be seeded, so no official scenario opens onto an empty board). Each pins a conventions note telling the agent which file to keep updated — that pin closes the human↔agent loop immediately. Web lenses already accept YAML, so these work today.

fs.read now returns data (YAML parsed server-side to JSON; null when unparseable → editor fallback, never an error). This is what lets native iOS — zero dependencies, no YAML parser in Foundation — render lenses at all, and resolves 1.1-vs-1.2 booleans once (serde_yaml is 1.2: bare no stays a string; tested).

3 — Official plugin SDK v2 + Pages gallery (fix)

The official bundles' inlined SDK had drifted three revisions behind the reference: no open/compose, no cheers:log/error-forwarding (a broken official plugin = blank iframe), and no one-save-in-flight guard — the old copy silently overwrote pendingSave, so concurrent saves could adopt each other's results. That last one is a real bug.

checklist/kanban-md/frontmatter re-inline v2, manifest version 1→2 (seeder re-installs next release, per policy). cheers-table deliberately untouched — it duplicates builtin:table and is a deprecation candidate.

Pages: workflow now assembles official templates into their own downloads/templates/ dir (two docs examples share filenames with official templates — one dir would silently clobber); plugins.html gains an official-scenarios section; plugin-dev.html's protocol table was three messages behind the spec (open/compose/log rows added).

Verification

  • cargo test: 179 pass (embedded bundles and templates walk validation in CI — malformed official content fails the build, not some future boot). cargo fmt --check clean.
  • yamlpath spike: comment/blank-line/sibling preservation, anchors detection, sequence-element addressing, quoted-no emission — all pass.
  • Website verified by serving locally: new section renders (all four cards), three protocol rows present, both pages parse.
  • Working tree deliberately leaves another session's uncommitted notify/* work untouched; staging was by explicit file list.

🤖 Generated with Claude Code

haowei2000 and others added 3 commits July 20, 2026 09:19
Two documents that settle how workbench boards escape the HTML-plugin sandbox
and reach every client, native iOS included.

WORKBENCH_LENS_SPEC (draft): a lens = a YAML binding (path + field definitions)
x a widget (table / list / form, then chart / graph) x field types (text, enum,
locator, image, ...). Going YAML-only collapses the parser axis entirely — the
markdown convention parsers existed only because the substrate was plain text.
Coverage-checked against the actual source of all four official plugins; the
mismatches found (arbitrary UI like codemap; line- vs comment-preservation
semantics) are recorded, not papered over. Declarative lenses are data, not
code, which keeps them outside App Store guideline 4.7 — HTML plugins remain
the escape hatch on web/desktop.

WORKBENCH_WRITEBACK (accepted): the gateway owns both sides of the format.
fs.patch carries generic document ops (set / insert / remove / move) addressed
by path; fs.read grows a parsed `data` field. "YAML is a storage format; the
wire is JSON; the format never leaves the gateway." One implementation of the
subtle comment-preserving part instead of one per client — a divergence there
does not error, it silently mangles user files. Spiked, not guessed: yamlpath
(zizmor's tree-sitter crate) resolves paths to byte spans and we splice, which
beats the web's diff-based yamlDoc.ts on length-changed arrays because explicit
ops carry intent. All fixtures pass, including the YAML 1.1 boolean hazard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four scenarios now ship in the gateway binary and seed at startup, exactly like
official plugins (the seeder REUSES workbench_official::decide — admin deletion
sticks within a release, a higher manifest version re-seeds, an admin-claimed id
is never overwritten; API PUT refuses official ids the same way):

  cheers-task-board     Todo/Doing/Done kanban + backlog table (priority/status enums)
  cheers-code-project   plan kanban, issues table (severity + ref column),
                        progress chart, todo checklist, codemap/map.yaml seed
  cheers-research-lab   experiments table, metrics chart, submissions tracker
  cheers-team-ops       server inventory, assets/renewals, on-call board

All seed commented-YAML board files rendered by BUILT-IN lenses — CI enforces
both (a template may never depend on a plugin; every viewed file must be
seeded, so no official scenario can open onto an empty board). Each pins a
small conventions note telling the agent which file to keep updated: that pin
is what closes the human-agent loop on day one. The web lenses already accept
YAML, so these work today with no frontend change.

fs.read additionally returns `data`: the YAML parsed to JSON, server-side
(whole-file reads only; null when unparseable — the client falls back to the
editor, never errors). This is what lets clients with no YAML parser — native
iOS has none and a zero-dependency policy — render lenses at all, and it
resolves the YAML 1.1/1.2 boolean ambiguity once instead of per client parser
(serde_yaml is 1.2: a bare `no` stays a string; tested).

templates list() now reports origin so Settings can badge Official rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gallery

The official bundles' inlined SDK had drifted three revisions behind the
reference cheers-plugin-sdk.js:

- no open/compose — protocol abilities the reference implementations never
  demonstrated;
- no cheers:log / uncaught-error forwarding — an official plugin that broke
  showed a blank iframe with nothing in the Dev inspector;
- no one-save-in-flight guard — the old copy silently OVERWROTE pendingSave, so
  concurrent saves could adopt each other's results. A real bug, not a missing
  nicety.

checklist / kanban-md / frontmatter re-inline v2 and bump manifest version
1 -> 2 so the seeder re-installs on the next release (including rows an admin
deleted — that is the documented policy). cheers-table is deliberately NOT
updated: it duplicates builtin:table, which the new YAML scenario templates
already use, making it a deprecation candidate — no polish for what we are
about to retire.

Pages fixes:
- pages.yml assembles official scenario templates into downloads/templates/ —
  its OWN dir, because two docs examples share filenames with official
  templates (code-project, research-lab) and one dir would silently clobber;
- plugins.html gains an "Official scenario templates" section (4 cards);
- plugin-dev.html's protocol table was three messages behind the normative
  spec — cheers:open / cheers:compose / cheers:log rows added.

Verified by serving website/ locally: new section renders with all four cards,
the three protocol rows are present, both pages parse. cargo test: 179 pass
(every embedded bundle walks manifest validation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@haowei2000
haowei2000 merged commit 2419a16 into develop Jul 20, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant