From 03a58c2de7461305e2af394703edd9511ea18ed0 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Sat, 3 Oct 2026 11:37:15 -0400 Subject: [PATCH 1/4] feat(session-bridge): claude-interactive triage board and plan view session-bridge meets rendered-views rule 9, and the triage board and the plan view send page actions to the session and show its replies. - Every /api/wait answer carries the untrusted-content framing contract as its data note. - lib/session-bridge/view_bridge.py is the view app: it serves a builder page, hands the token only to same-origin page script, takes actions holding only builder keys, row ids and the reader's notes, and applies the session's replies from ops.json. - view-builder --connect adds one connect-src naming the loopback origin; the validator refuses any other. view-runtime gains the session client and says when no session is connected. - work-items and planning carry the app in view-bridge/; review, debugging, discovery and harness-ops take the regenerated libraries. Closes #5868 Co-Authored-By: Claude Opus 5.5 --- docs/conventions/rendered-views/CHANGELOG.md | 9 + docs/conventions/rendered-views/README.md | 28 +- lib/session-bridge/README.md | 54 +- lib/session-bridge/session_bridge.py | 11 +- lib/session-bridge/test_view_bridge.py | 300 +++++++ lib/session-bridge/view-bridge.sh | 16 + lib/session-bridge/view_bridge.py | 346 ++++++++ lib/view-builder-sample/template.html | 5 + lib/view-builder.mjs | 38 +- lib/view-builder.test.sh | 50 +- lib/view-runtime.js | 125 ++- plugins/debugging/.claude-plugin/plugin.json | 2 +- plugins/debugging/CHANGELOG.md | 6 + plugins/debugging/lib/view-builder.mjs | 38 +- plugins/debugging/lib/view-runtime.js | 125 ++- plugins/discovery/.claude-plugin/plugin.json | 2 +- plugins/discovery/CHANGELOG.md | 6 + plugins/discovery/lib/view-builder.mjs | 38 +- plugins/discovery/lib/view-runtime.js | 125 ++- .../harness-ops/.claude-plugin/plugin.json | 2 +- plugins/harness-ops/CHANGELOG.md | 6 + plugins/harness-ops/lib/view-builder.mjs | 38 +- plugins/harness-ops/lib/view-runtime.js | 125 ++- plugins/planning/.claude-plugin/plugin.json | 2 +- plugins/planning/CHANGELOG.md | 19 + plugins/planning/lib/view-builder.mjs | 38 +- plugins/planning/lib/view-runtime.js | 125 ++- plugins/planning/prerequisites.json | 7 +- plugins/planning/reference/rendered-view.md | 44 + plugins/planning/scripts/build-view.mjs | 22 +- plugins/planning/scripts/build-view.test.sh | 17 + plugins/planning/skills/plan/SKILL.md | 2 +- .../skills/plan/templates/plan-view.html | 10 +- plugins/planning/surface/session_bridge.py | 11 +- .../planning/view-bridge/session-bridge.conf | 5 + .../planning/view-bridge/session_bridge.py | 809 ++++++++++++++++++ plugins/planning/view-bridge/view-bridge.sh | 18 + plugins/planning/view-bridge/view_bridge.py | 348 ++++++++ plugins/planning/view-bridge/wake.sh | 13 + plugins/planning/view-bridge/watch.sh | 149 ++++ plugins/review/.claude-plugin/plugin.json | 2 +- plugins/review/CHANGELOG.md | 6 + plugins/review/lib/view-builder.mjs | 38 +- plugins/review/lib/view-runtime.js | 125 ++- plugins/work-items/.claude-plugin/plugin.json | 2 +- plugins/work-items/CHANGELOG.md | 17 + plugins/work-items/lib/view-builder.mjs | 38 +- plugins/work-items/lib/view-runtime.js | 125 ++- plugins/work-items/prerequisites.json | 24 +- plugins/work-items/skills/triage/SKILL.md | 5 +- .../work-items/skills/triage/context/board.md | 45 + .../skills/triage/scripts/build-board.mjs | 18 +- .../skills/triage/templates/board.html | 33 +- plugins/work-items/tests/triage-board.test.sh | 15 + .../view-bridge/session-bridge.conf | 5 + .../work-items/view-bridge/session_bridge.py | 809 ++++++++++++++++++ plugins/work-items/view-bridge/view-bridge.sh | 18 + plugins/work-items/view-bridge/view_bridge.py | 348 ++++++++ plugins/work-items/view-bridge/wake.sh | 13 + plugins/work-items/view-bridge/watch.sh | 149 ++++ scripts/cross-plugin-source-registry.txt | 23 + scripts/shared-copies.txt | 10 + 62 files changed, 4871 insertions(+), 131 deletions(-) create mode 100644 lib/session-bridge/test_view_bridge.py create mode 100755 lib/session-bridge/view-bridge.sh create mode 100644 lib/session-bridge/view_bridge.py create mode 100644 plugins/planning/view-bridge/session-bridge.conf create mode 100644 plugins/planning/view-bridge/session_bridge.py create mode 100755 plugins/planning/view-bridge/view-bridge.sh create mode 100644 plugins/planning/view-bridge/view_bridge.py create mode 100755 plugins/planning/view-bridge/wake.sh create mode 100755 plugins/planning/view-bridge/watch.sh create mode 100644 plugins/work-items/view-bridge/session-bridge.conf create mode 100644 plugins/work-items/view-bridge/session_bridge.py create mode 100755 plugins/work-items/view-bridge/view-bridge.sh create mode 100644 plugins/work-items/view-bridge/view_bridge.py create mode 100755 plugins/work-items/view-bridge/wake.sh create mode 100755 plugins/work-items/view-bridge/watch.sh diff --git a/docs/conventions/rendered-views/CHANGELOG.md b/docs/conventions/rendered-views/CHANGELOG.md index 7b5be8c5d7..9bd22d0f1f 100644 --- a/docs/conventions/rendered-views/CHANGELOG.md +++ b/docs/conventions/rendered-views/CHANGELOG.md @@ -3,6 +3,15 @@ Notable changes to the rendered-views contract. The contract is not versioned; this log records each change to it. +## The Claude-interactive tier opens to builder pages, 2026-10-03 + +- **`session-bridge` meets rule 9, and the triage board and plan view adopt the tier (#5868).** Every wait + answer now carries the untrusted-content framing contract as its data note. The bridge's new view app + hands the token only to same-origin page script, so it never enters the page's markup, and takes page + actions holding only builder keys, row ids and the reader's notes. The builder's `--connect` adds one + `connect-src` naming the loopback origin, which the validator checks. The tier stays closed to + model-written pages. Rules 3 and 9 and View tiers record the change. + ## Post-mortem and blindspot views on the builder, 2026-10-03 - **`debugging:debug` and `discovery:blindspot` offer interactive views built by `lib/view-builder.mjs` (#5864).** diff --git a/docs/conventions/rendered-views/README.md b/docs/conventions/rendered-views/README.md index ec5f7641a0..93c46ec7db 100644 --- a/docs/conventions/rendered-views/README.md +++ b/docs/conventions/rendered-views/README.md @@ -49,9 +49,12 @@ A view sits on one of four tiers, chosen per use case from the defaults below. - **Reports may be static.** A report is read, not answered, so it may ship without script. A report may still filter, collapse, or animate; what it never carries is a loop-closure control (see Loop closure and the export obligation). -- **The Claude-interactive tier is closed to every content class.** No page, K0, K1, or - K2, uses it until `session-bridge` exists and meets interactive-profile rule 9. Until - then a page stops at client-interactive and closes the loop with a copied payload. +- **The Claude-interactive tier is open only to builder pages.** `session-bridge` meets + interactive-profile rule 9, so a page of any class reaches it when the shared builder + built it with `--connect` and the bridge's view app serves it + (`lib/session-bridge/README.md`, "The view app"). A model-written K0 or K1 page does not + use it: it stops at client-interactive and closes the loop with a copied payload. A + builder page with no live session says so and keeps its copy and save controls. - **A K2 page's payloads carry no K2 text.** Every copy, export, or download payload on a K2 page, at any tier, holds to rule 9's first bullet: what the reader entered plus ids the builder assigned, never a string taken from the data block. A K2 page @@ -127,8 +130,8 @@ came from, not by who wrote it down. the charset meta is a ``, because a meta policy does not apply to content before it. The policy is exactly `default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; - form-action 'none'`, plus one permitted addition: `connect-src` naming the - `session-bridge` origin, once the Claude-interactive tier opens. The policy caps a misclassified page: + form-action 'none'`, with no `connect-src`: the Claude-interactive tier is open to + builder pages only (see View tiers). The policy caps a misclassified page: injected script runs but cannot fetch, beacon, or submit a form. It can still navigate the page to a URL that carries data out, and CSP3 has no directive that stops navigation, so the authoring-context rule, not the policy, is what keeps K2 @@ -177,9 +180,11 @@ from the one the browser runs. It checks the runtime body by hash before any oth `form-action 'none'`, which do not fall back to `default-src`. Its content is the builder's exact policy string. It is the only `http-equiv` meta the page carries: any other, such as `refresh`, which navigates and is not blocked by the policy, fails. - Once the Claude-interactive tier opens (rule 9), a page on it adds `connect-src` - naming the `session-bridge` origin and nothing else; `session-bridge` owns that - origin, and rule 9 governs what crosses it. + A Claude-interactive page (rule 9) adds one last directive, `connect-src` naming the + `session-bridge` origin `http://127.0.0.1:` and nothing else; the builder writes + it from `--connect`, the validator refuses any other `connect-src`, and the runtime + reaches only that origin. `session-bridge` owns that origin, and rule 9 governs what + crosses it. 4. **No inline handlers, no navigation.** No `on*` attribute, no `style` attribute, no `
`, `