## Release monorepo v1.66.1
**Scope:** `monorepo` | **Bump:** `patch`
---
### How this release process works
1. **This PR was created automatically** by the "release / create-pr"
workflow.
It bumped the `monorepo` packages to `1.66.1`
and generated AI-enhanced release notes.
2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
must pass before merging. This is the review gate.
3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.
4. **When this PR is merged**, the `release / publish` workflow
automatically:
- Builds all packages
- Publishes the `monorepo` packages to npm at version `1.66.1`
- Creates git tag `monorepo/v1.66.1`
- Creates a GitHub Release with the final release notes
### Before merging
- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)
---
> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
## Release channels v0.7.1
**Scope:** `channels` | **Bump:** `patch`
---
### How this release process works
1. **This PR was created automatically** by the "release / create-pr"
workflow.
It bumped the `channels` packages to `0.7.1`
and generated AI-enhanced release notes.
2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
must pass before merging. This is the review gate.
3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.
4. **When this PR is merged**, the `release / publish` workflow
automatically:
- Builds all packages
- Publishes the `channels` packages to npm at version `0.7.1`
- Creates git tag `channels/v0.7.1`
- Creates a GitHub Release with the final release notes
### Before merging
- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)
---
> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
Adds a skin to `examples/showcases/reskinnable-demo`: **Keel**
(`/keel`), the internal knowledge and operations desk of Harbor Point
Health, a fictional nine-hospital health system.
The product is one sentence: **an answer you can trust, that turns into
work that actually happens.**
## Why this skin
The shipped skins bracket the `Skin` contract — `airline` is in-memory
with four optional slots, `banking` is REST-backed with nearly all of
them, and #6302's `logistics` proves a server-enforced authority gate. A
further skin earns its place only by demonstrating something none of
them do. Keel introduces **two substrates the app has never had**:
1. **Grounded retrieval.** A server-side `search_knowledge` tool over a
nine-document policy corpus, returning cited passages. Every existing
tool in this app pushes client state *up* to the agent; this inverts the
flow — the agent reaches for something the user has not seen and brings
it back.
2. **Long-running stateful process.** Runs whose steps advance on a
900ms ticker and halt at human approval gates. Banking's HITL is a
single approval; airline's mutations are instantaneous. Neither has
duration — state that changes while you are not looking.
It is also the first skin with **parameterized routes**
(`knowledge/<docId>`, `runs/<runId>`), so `resolvePage` actually
destructures the segment array rather than using a flat lookup.
## The demo arc
| Beat | What happens |
| --- | --- |
| *"What's our policy on giving a contractor access to patient
records?"* | `search_knowledge` → grounded answer + `showSources` citing
POL-114 and POL-302 |
| Click a citation | Routes to
`/keel/knowledge/phi-access-policy#minimum-necessary`, scrolls,
highlights |
| *"Set that up for Priya Raman"* | `showPlaybook` → `startRun` HITL
plan preview (6 steps · 1 gate · 5 roles) |
| Run ticks | `RUN-1045` advances, then halts **blocked** on Privacy
Officer sign-off |
| Switch persona → *"approve it"* | `approveStep` card carrying the
policy citation as the reason the gate exists |
**The citation resolving into the real app is the load-bearing beat.**
Most AI-knowledge demos show a footnote; few make the footnote drive the
app.
## Two details that are load-bearing, not stylistic
**`showSources` cannot render a fabricated citation.** It accepts only
`(docId, sectionId)` pairs — never citation text — and resolves the ref,
heading, and snippet from the real corpus client-side. A citation the
model invents fails to resolve and is dropped, rather than rendering as
a convincing fake. Grounding is structural here, not prompt-dependent.
**The ticker cannot thrash the agent's context.** A 900ms timer plus a
`useAgentContext` readable is a token-cost hazard. The readables memoize
on a `summaryKey` derived only from `(runId, status, currentStepId)`
tuples — never from elapsed time — so context is rewritten on meaningful
transitions and never on a raw tick. The interval is also cleared
whenever nothing is running.
## What it exercises
- **In-memory substrate** — seed-backed `useData` with a pure reducer
(`tick` / `startRun` / `approveStep` / `rejectStep` / `cancelRun`) and a
stale-approval race guard.
- **Identity triad** — `RuntimeProviders` (persona above the provider) +
`useRuntimeProperties` + a server-safe `identifyUser`, scoping memory
per persona. A gate is actionable only when its `approverRole` matches
the active persona; otherwise it renders "waiting on <role>".
- **a2ui canvas** — an ops report from a deterministic op-builder; no
figures travel in the ops, every number binds client-side.
- **OGUI sandbox** — four functions projecting to allowlisted DTOs.
- **Theme** — deep pine on warm neutrals at `--radius: 0.5rem`, the
tightest in the app, with `--brand-violet` re-valued as the amber
awaiting-approval accent (the shared vocabulary has no warning token,
and a skin may not invent token names). Pure token re-valuing; no
component edits, no `globals.css` change. Dark-capable via the
`--nw-dark-capable` opt-in.
Deliberately omits `chatHeaderActions` and `onSuggestionSelect` (they
exist in banking only to serve its PDF-attachment beat) and `Providers`
(nothing needs to mount below the provider).
## The most valuable file in the diff
`src/skins/keel/data/seed.test.ts` asserts that **every one of the 23
playbook-step `policyRef`s resolves to a real `docId` + `sectionId`** in
the corpus. That invariant is what fuses the two substrates — a dangling
reference means an approval card cites a document that does not exist.
It has already earned its keep: it caught a citation to `POL-208
§documentation` that did not exist (`documentation` belongs to POL-121),
which had been written into the design spec and propagated into the
implementation plan before any code was generated.
That test was also **mutation-tested** rather than trusted: deliberately
breaking one `policyRef` turns it red, so its green result reflects a
real check and not one of its fallback paths silently no-opping.
## Verification
Keel's own suite: **16 test files / 105 tests** (`npx vitest run
src/skins/keel`). Whole app after merging `main`: **38 files / 215
tests** — the larger number includes logistics' 65 tests, which arrived
with the merge and are not this PR's. `pnpm lint` 0 issues · `npx tsc
--noEmit -p .` exit 0 · `pnpm build` compiles.
`main` is merged in (resolving the append-only registry conflict
predicted below), so the branch is mergeable and all four skins —
banking, airline, logistics, keel — are registered under the same id in
both the client and server registries.
**No CI job exercises this app, so green checks here are not evidence.**
`.github/workflows/static_quality.yml` carries `paths-ignore:
["examples/**"]` on both its `push` and `pull_request` triggers, and no
workflow in the repo references `reskinnable-demo` at all. The passing
checks on this PR are unrelated legacy example demos plus binary/config
checks. The local gates above are the only real signal — worth knowing
before reading a green tick as coverage.
**Not verified: the chat agent itself.** No API key was available, so
gen-UI, both HITL cards, the citation deep-link, the ticker's live
advance, persona switching, dark mode, and OGUI are unexercised at
runtime. A live smoke test of those paths is the main thing a reviewer
should add — it is also where the `pointer-events-auto` fix and the
context-churn guard would actually be observed working.
## Review pass
The skin went through a four-round unbiased review (16 reviewers per
round, non-leading prompt) plus a fix cycle per finding. Findings landed
as six thematic commits on top of the feature commits:
| Commit | Closes |
| --- | --- |
| `fix(keel): make engine mutations honest and single-path` | Lost
updates from non-functional `setRuns`, a stale render-time read, gates
that could enter `awaiting_approval` without `startedAt`, a rejector
mislabelled as approver, and a mutation reporting success for a commit
that did not happen |
| `fix(keel): make retrieval deterministic and citations grounded` |
Locale-dependent tiebreak ordering (breaking the documented
byte-identical guarantee), order-dependent transitive synonym expansion,
phrase synonyms matching across word boundaries, duplicate citation
keys, and a second citation into the same document silently failing to
re-scroll |
| `fix(keel): guard prototype access on untrusted lookup keys` |
`/keel/constructor` and friends resolving `Object.prototype` members
past a `?? null` guard and being handed to React as a component; same
class in the persona lookup, where the key arrives from client-forwarded
properties |
| `fix(keel): pin date/time formatting and fix in-chat interactivity` |
Hydration mismatches from ambient-locale formatting, and policy links
dead in chat because CopilotKit paints `useComponent` renders with
`pointer-events: none` |
| `fix(keel): anchor seeded runs to a per-call now` | Seed timestamps
anchored to fixed calendar dates while the app compares them to
`Date.now()` — a ~6.7-day cycle time poisoning the median KPI, and the
mid-flight ticking run arriving already resolved on remount |
| `fix(keel): harden report surface, catalog, and remaining chrome` |
Duplicate a2ui component ids colliding React keys, and a failed report
surface latching so the canvas never self-healed |
Each fix carries a red-green proof (test written, source broken to
confirm red, restored to confirm green). Two were structural rather than
per-instance: the prototype-safe lookup uses a `Map` so inherited keys
cannot exist, and a single `ChatSurface` wrapper now carries
`pointer-events-auto` so exactly one such literal remains in the skin.
**Caveat worth stating plainly: the final six fixes did not themselves
get an unbiased review round.** The review was stopped deliberately
after round four. Earlier rounds are the calibration — round one's 16
fixes introduced 3 regressions (~19%), round three's introduced zero —
so the risk is real but bounded, and it is concentrated in these six
commits rather than spread across the diff.
## Relationship to #6302
**Resolved: #6302 (`logistics` / Meridian) has merged, and keel landed
second.** The predicted conflict materialised exactly as described —
both PRs append to the same two registry lines — and is resolved
keep-both in the merge commit on this branch. Worth noting that until
that merge, GitHub created *no* CI runs for this PR at all: it does not
evaluate `pull_request` workflows for a branch whose mergeable state is
`CONFLICTING`, because it cannot compute the merge ref those events run
against. A conflicting PR therefore looks like "CI hasn't started"
rather than "CI failed".
Worth deciding before either merges whether these ship as two skins or
Keel's retrieval half folds into Meridian. Keel adds grounded retrieval,
duration, and parameterized routes; it also re-proves approval gates,
maximal contract coverage, and an a2ui canvas that Meridian already
demonstrates. Keel's canvas (`canvas-surface.tsx` + `ops-report.ts`) was
deliberately built as cleanly separable scope for exactly this reason —
nothing imports it except the agent and the skin object.
## Known follow-ups (non-blocking)
- In the `adverse-event` playbook, both the `rca-decision` and `close`
steps cite `POL-208 §root-cause-analysis`. POL-208 has no section that
fits "Document and close" better, so this is the least-bad mapping
rather than a clean one; a new corpus section would resolve it properly.
- `seed.test.ts`'s live-corpus check retains two fallback paths (`catch
{ return }` and `if (!docs) return`) that would let it pass silently if
the corpus import ever broke. It genuinely runs today (verified by
mutation), but the escape hatches are a latent hazard worth removing now
that the corpus is guaranteed present.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
Resolves the append-only registry conflict this PR's description predicted:
#6302 (logistics / Meridian) landed first and took the same two lines, so
keel takes the trivial conflict. Both edits are additive, so the resolution
is keep-both in both registries — logistics first (it landed first), keel
second.
Why the merge was necessary rather than optional: GitHub does not create
pull_request workflow runs for a PR whose mergeable state is CONFLICTING,
because it cannot compute the merge ref those events run against. The push
of the review fixes therefore produced ZERO CI runs — verified over 12
minutes of polling the Actions API by head SHA, and corroborated by Actions
being healthy repo-wide at the same time. Not a timing artifact, and not a
path filter: test_e2e-legacy-v1 and auto_merge_showcases both trigger on
pull_request with paths: examples/**, and synchronize is a default activity
type.
Scope of the drift: main is 127 commits ahead of the merge-base, but within
reskinnable-demo it added only logistics' own files (48 skin + 17 API route
+ 2 reskin-skill docs) plus +7 append-only lines across exactly the two
registry files. No globals.css change, no skin-contract.ts change, no
skins-config.ts change — so the shared token vocabulary and the frozen Skin
contract are untouched, and keel's isolation claim still holds against a
four-skin registry.
All four skins are now registered under the same id in both registries
(banking, airline, logistics, keel), which is the invariant the two-registry
split exists to maintain.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
Remaining fixes across the ops-report builder, the a2ui canvas surface,
the catalog, agent wiring, suggestions, and the knowledge/playbooks pages:
correct the report surface output and its catalog registration so the
canvas renders the intended report, and tighten the surrounding chrome so
these entry points behave consistently. Tests cover the report builder and
canvas surface.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
Seed data used a fixed or module-load timestamp, so seeded run timelines
drifted out of a plausible window as time passed and could not be
reproduced deterministically in tests. This anchors every seeded run
relative to a `now` passed in at seed time, keeping the demo's timeline
coherent whenever it is generated and making the seed testable. A test
pins the relative anchoring.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
Dates and times were formatted with the runtime's ambient locale and
timezone, so server and client rendered different strings and React
hydration mismatched; several call sites also built ad-hoc formatters that
drifted from one another. This centralizes formatting behind pinned
locale/timezone formatters — one per format — so output is stable across
environments. It also fixes the ChatSurface pointer-events boundary so
interactive controls rendered inside the chat transcript (playbook,
approval, and run cards) actually receive clicks. Tests cover the pinned
formatters.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
URL route segments and client-forwarded runtime properties were used
directly as object keys, so a crafted value like "__proto__" or
"constructor" could resolve to an inherited Object.prototype member
instead of a real entry — misrouting a page or silently matching a bogus
user identity. This constrains both lookups to own, real keys so untrusted
input can no longer reach the prototype chain. Tests cover the malicious
key cases for page resolution and user identification.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
Search results depended on the runtime locale for tie-breaking, synonym
expansion chained transitively into unrelated terms, and phrase matching
hit partial tokens, so the same query could return different or wrong
results across environments. Citations could also duplicate and fail to
land on their source document. This pins result ordering to a
locale-independent comparison, bounds synonym expansion to direct
(non-transitive) matches, matches phrases on whole-token boundaries,
deduplicates citations, and makes a citation click land on the correct
document. Tests lock in the deterministic ordering and citation targeting.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
The data engine could report success for mutations that changed nothing
and exposed multiple divergent write paths, so callers could not trust a
returned status or reason about a gate from one place. This routes every
mutation through one shared commit path, returns values that reflect what
actually happened, and tightens the gates so a no-op or a rejected change
can no longer be misrepresented as applied. Types and the seed-backed data
hook are updated to match, with tests covering the corrected return
contract and persona-scoped access.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkMi54kqfNwAoUB3M3CBp3
## Summary
- add an opt-in featured treatment to the existing docs `Accordion`
component
- use that treatment for the coding-agent starter prompts at the top of
both the Slack and Microsoft Teams Channels overview pages
- replace the easily missed accordion label with a branded prompt panel,
a terminal icon, platform-specific supporting copy, and a prominent
**Open & copy prompt** action
- preserve the existing native `details` interaction and code-block copy
control inside the expanded prompt
- update the Channels documentation regression test for the new featured
markup and provider-specific descriptions
## Why
The existing “copy this prompt” accordion looked like ordinary
supporting content and was easy to skip at the top of the overview
pages. This change gives the starter prompt a clear visual hierarchy and
action without changing the prompt content or introducing a new
navigation concept.
The visual treatment deliberately uses a terminal icon rather than a
generic sparkle so it reads as a developer workflow for a coding agent.
## User impact
People landing on either Channels overview page can now immediately
recognize that there is a ready-to-use setup prompt. Slack and Teams
retain their own provider-specific instructions, while the interaction
remains familiar:
1. Open the featured prompt.
2. Review the provider-specific setup instructions.
3. Use the existing copy control on the prompt code block.
Unrelated accordions retain their current appearance because the new
treatment is opt-in.
## Implementation notes
- reuses the existing CopilotKit docs design tokens for color, spacing,
borders, radii, focus states, and dark mode
- keeps the native `details`/`summary` semantics and keyboard behavior
- adapts the header and action layout at narrower widths
- changes the action label to **Close prompt** while expanded
- leaves the published Slack and Teams prompt bodies unchanged apart
from replacing two em dashes with colons for readability
- adds no new dependencies
## Validation
- `npm test -- src/lib/__tests__/channels-docs.test.ts --maxWorkers=1
--no-file-parallelism` — 29 tests passed
- `npm run typecheck`
- `pnpm exec oxfmt --check
showcase/shell-docs/src/components/mdx-components.tsx
showcase/shell-docs/src/content/docs/channels/index.mdx
showcase/shell-docs/src/lib/__tests__/channels-docs.test.ts`
- `git diff --check`
- pre-commit lint and commit-message hooks passed
- Impeccable design detector returned no findings
- manually reviewed Slack and Teams in collapsed and expanded states,
light and dark themes, and a narrower responsive viewport
- confirmed no browser console errors during local review
## Scope
This PR is intentionally limited to the shared opt-in accordion
treatment, the two Channels overview prompt instances, and their focused
regression coverage. It does not restyle existing documentation
accordions or alter the underlying setup guidance.
Corrects the repo-local `reskin` skill (`.claude/skills/reskin/`), which
in several places teaches guidance that produces a broken or subtly
defective skin when followed literally.
Docs only — no application source changes.
## Why now
The `logistics` skin (#6302) was built by following this skill and then
debugged against a live app. Every fix below is a defect that build
actually surfaced, or that an audit of the skill against the three
shipped skins turned up. Where the skill and `src/skins/logistics/**`
disagreed, the skill was the one that was wrong.
## The two that shipped a visibly broken skin
**The layout template taught `min-h-screen`.** That is a *minimum*, so
on any page taller than the viewport the container grows, the whole
document scrolls, and the pinned nav scrolls away with it — and
`<main>`'s `overflow-y-auto` goes inert, because its parent is
unbounded. Now `h-screen overflow-hidden` on the root plus `h-full` on
the `<aside>`.
**The template never published `--nw-nav-inset-left` /
`--nw-nav-inset-right`.** Every shipped skin does. Without them the
shell's floating skin selector docks on top of the new skin's nav.
Added, including the cleanup that removes both — a missing cleanup leaks
the inset into whatever skin the user switches to next.
## The one that is invisible to every gate
**No mention of the dependency array** on `useComponent` /
`useFrontendTool` / `useHumanInTheLoop`. Omit it and the render closure
captures whatever the data was at registration time — for a REST-backed
skin, the empty array from before the first fetch — permanently.
This is the nastiest bug in the app because it **compiles, lints, and
passes every test**. The symptom is the agent narrating confidently over
a broken surface:
```
agent: "PO-88213 trade-offs are on screen."
UI: "No shipment matches that reference."
```
Banking already documented the trap in a code comment; the skill never
did. Every template registration now closes with its deps array.
## Also fixed
- **Meta-utility strip** — new section documenting that the presenter
reset / theme toggle / help controls are *skin-authored*, not
shell-provided. Covers the `usePresenterReset()` gate, that
`ThemeToggle` is a shared component (fair to import) while
`useAskCopilot` must be *ported* (a skin may not import from another
skin), and that the skin's own `dev/reset` route must gate on
`presenterResetEnabled() || NODE_ENV !== "production"` so the button and
the endpoint agree.
- **`--nw-dark-capable`** — previously unmentioned. A skin that ships a
`.dark .theme-<id>` block but omits the flag stays stuck in light,
because the shell's reconciler forces it. Documented as an explicit
opt-in, and paired with the note that a theme toggle without a dark
palette is a dead control.
- **a2ui surface ops must be emitted from a server `defineTool`** —
previously silent. A client `useFrontendTool` result never produces the
in-stream `TOOL_CALL_RESULT` the a2ui middleware needs, so the canvas
stays permanently blank. This one cost real debugging time on #6302.
- **Parameterized `useComponent` render signature** — receives the
schema output *directly*, not wrapped in `{ args }`, unlike HITL /
frontend-tool renders. Airline has no parameterized example to learn
from, so the skill now shows one and contrasts the two.
- **`nav` is not the segment validator** — the skill claimed it was "the
source of truth for which segments are valid"; the frozen contract says
the opposite and names `resolvePage`. Following the skill got you a 404.
- **Airline `useData` contradiction** — SKILL.md listed `data/` among
the slots airline omits; airline sets it, and templates.md already said
so.
- Two nits: the `tools.tsx` template would NPE for a no-data skin
(`useSkinData` returns `undefined`), and `skin.tsx` left a dangling
`use<Id>Data` import for skins that omit the slot.
## Verification
Every code sample was diffed against the corresponding real file in
`src/skins/logistics/`, and every API-signature claim against the
installed types in `packages/react-core/dist/`. Markdown only, so no
build/lint/test surface changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The reskin authoring skill taught several patterns that ship a broken skin when
followed literally. Corrected against the debugged logistics skin (the frozen
contract wins on conflict):
- layout: h-screen overflow-hidden (not min-h-screen) + h-full aside, so the nav
stays pinned and <main> scrolls inside it
- layout: publish --nw-nav-inset-left/right with cleanup, so the floating skin
selector never docks on the nav and the inset does not leak between skins
- layout: document the meta-utility strip (Reset/ThemeToggle/Help) as
skin-authored chrome, with the reset-route gating coupling
- theme: document --nw-dark-capable as the dark-mode opt-in + a .dark .theme-<id>
example
- tools: every useComponent/useFrontendTool/useHumanInTheLoop registration must
close with a deps array, or the closure captures empty pre-fetch data forever
- tools: a parameterized useComponent render receives the schema output directly,
not { args }
- a2ui: a CanvasSurface must be fed by a server defineTool, never a client
useFrontendTool
- contract: nav is display-only; resolvePage is the sole segment validator
- fix airline useData contradiction; NPE-safe no-data tools shape; skin.tsx
dangling-import note
Co-Authored-By: Claude <noreply@anthropic.com>
Adds a third skin to `examples/showcases/reskinnable-demo`: **Meridian**
(`/logistics`), a supply-chain control tower built at the **maximal**
end of the frozen `Skin` contract.
## Why a third skin
The two shipped skins bracket the contract — `airline` is in-memory with
four optional slots, `banking` is REST-backed with nearly all of them. A
third earns its place only if it demonstrates something, so this one
runs a **different domain rule** through the same machinery.
Banking's most valuable property isn't the HTTP (its store is a
module-scope object seeded from JSON). It's that a **server-side rule
the client cannot bypass** rejects a write, returns a symptom, and
forces the agent to learn the failure and route around it. Meridian
reproduces that shape with **role-scoped approval authority** instead of
a policy budget.
## The headline beat, verified end-to-end over HTTP
| Attempt | Result |
| --- | --- |
| Rosa (authority $5,000) expedites `PO-88213` at $8,400 | `403
OVER_AUTHORITY` |
| Same request, body claims `costUsd: 1` | `403` — server recomputes;
client cost is never trusted |
| `PATCH {weightKg: 1}` then expedite | `422 FORBIDDEN_FIELD` — pricing
inputs are not writable |
| Approve a **non-justifying** escalation, then expedite | `403` — still
blocked |
| Approve `LINE_DOWN_RISK`, then expedite | `200`, logged at $8,400 |
| Director expedites with no escalation | `200` |
`PATCH` is an **allow-list** (`status`, `etaCurrent`) rather than a
deny-list, precisely so no pricing input becomes a side channel around
the gate. There is a named regression test for that bypass.
## What it exercises
- **REST substrate** — `/api/logistics/v1/*` over a seeded store, with
the authority gate and a two-step escalation recovery under a closed
code catalogue.
- **Identity triad** — `RuntimeProviders` (auth above the provider) +
`useRuntimeProperties` + a server-safe `identifyUser`, scoping runs per
planner.
- **a2ui canvas** — a Decision Brief from a deterministic op-builder; no
figures travel in the ops, every number binds client-side.
- **OGUI sandbox** — five functions, each projecting to an allowlisted
DTO so no internal field reaches iframe-authored JS.
- **Theme** — warm signal-amber on graphite at a tight radius, against
banking's violet and airline's teal. Pure token re-valuing; no component
edits, no `globals.css` change.
Deliberately omits `chatHeaderActions` and `onSuggestionSelect` (they
exist in banking only to serve its PDF-attachment beat) and `useData`
(components read REST directly, like banking).
## Verification
`pnpm test:unit` 22 files / 110 tests · `pnpm lint` 0 issues · `pnpm
build` compiles.
Driven in a real browser: all four routes render; theme applies; the
exception board sorts worst-first on real data; switching skins restores
banking with no theme or nav-inset leak.
**Not verified:** the chat agent itself — no API key was available, so
gen-UI, the HITL cards, `renderBrief` on the canvas, and OGUI are
unexercised at runtime. A live smoke test of those paths is the main
thing a reviewer should add.
## Known follow-ups (non-blocking)
Unused parameter in two private lane helpers · duplicate enum selections
in `buildBriefOps` could emit two components sharing an id ·
`getMitigationOptions` returns its type raw while the other four sandbox
handlers project · `req.json()` unguarded (malformed body → 500 not 400)
· `ModeSplitChart` uses two tones across four modes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The shell root used `min-h-screen`, which is a MINIMUM: on a page taller
than the viewport the container grew with the content, so the whole
document scrolled and the sidebar scrolled away with it. It also left
`<main>`'s own `overflow-y-auto` inert, because an unbounded parent gives
it no height to overflow against.
Switch the root to `h-screen overflow-hidden` and give the aside `h-full`,
mirroring banking's layout. The shell is now exactly one viewport tall, the
nav stays pinned, and `<main>` scrolls internally.
Measured on /logistics/lanes at a 700px viewport: document scrollHeight
700 (page no longer scrolls), aside top 0 / bottom 700, main scrollHeight
1472 vs clientHeight 700, and the aside stays at top 0 after scrolling
main by 700px.
Port banking's sidebar-footer utility controls into Meridian: a Reset
(presenter-gated), the shared ThemeToggle, and a copilot Help shortcut, placed
directly above the existing "On duty" planner switcher. Give the skin a warm-
graphite dark palette (--nw-dark-capable + a .dark .theme-logistics block) so
the theme toggle is a live control. Port useAskCopilot into the skin (no cross-
skin import) and widen the reset endpoint's gate to allow presenter/booth
deployments (presenterResetEnabled OR non-production).
Co-Authored-By: Claude <noreply@anthropic.com>
Applies the final whole-branch review wave for the logistics skin.
- renderBrief: move from a client useFrontendTool to a server defineTool on the
BuiltInAgent (mirrors banking's render_report). A client frontend-tool result
never yields an in-stream TOOL_CALL_RESULT, so the a2ui middleware never
emitted the a2ui-surface activity and the brief canvas stayed blank. Tool name
kept exactly "renderBrief". build-brief-ops + catalog/definitions confirmed
server-safe (plain Zod, no React/.tsx), so agent.ts stays server-safe.
- createDecisionRecord: implement the missing tool (globally registered) to log
a decision NOT executed through commitMitigation, wiring the previously-dead
fileDecision + POST /decisions path. Harden the route: require/resolve
plannerId, derive decidedBy/role server-side (never from body), 404 unknown
shipmentId, clamp costUsd. Client forwards plannerId only. Prompt + toolLabels
updated. Adds a decisions route test (planner-derived identity vs body decoys,
404, 400).
- greeting: drop the wrong "six lanes / three shipments" figures (seed has 10
lanes, 4 exception shipments); quantitative claims bind to data, not prose.
Co-Authored-By: Claude <noreply@anthropic.com>
## Summary
- add provider-aware coding-agent entry points to the Channels overviews
at `/slack` and `/teams`
- present both onboarding flows in the site’s existing collapsed
`Accordion` pattern, with fenced text blocks that provide the standard
`Copy Text` control
- make each prompt start from an empty directory instead of assuming an
existing CopilotKit agent
- use the Slack onboarding skill as the Slack provider source of truth
and the published Teams documentation as the Teams provider source of
truth
- add regression coverage for provider scoping, onboarding order, safety
requirements, and end-to-end verification gates
## User experience
Both Channels overview routes now open with **Start building with your
coding agent — copy this prompt**. The row stays collapsed until
selected, keeping the existing overview readable while giving builders a
complete prompt they can copy into a local coding agent.
The prompts share the same start-from-scratch foundation:
1. Read `copilotkit-setup` for new-application and managed-Intelligence
onboarding.
2. Read `copilotkit-channels` for the CLI-scaffolded Channel declaration
and long-running host.
3. Stop when a required generic skill is unavailable and direct the user
to `npx copilotkit@latest skills install`.
4. Use the CopilotKit CLI through `npx copilotkit@latest`; neither
prompt assumes or requires a global CLI installation.
5. Run `npx copilotkit@latest create`, asking the user for the project
name and framework rather than silently choosing them.
6. Select managed Intelligence, since Channels are unavailable in
self-hosted SSE mode.
7. Preserve the CLI-generated `channel-host.mts` and `channels.mts` as
the code half instead of creating a duplicate Channel declaration or
placing it in a serverless route.
8. Inspect actual browser capabilities and either drive the browser with
confirmation before consequential live-account changes or guide the user
one step at a time.
9. Keep credentials out of the conversation and report success only
after the provider installation, managed runtime, and real-message path
are verified.
## Slack prompt
The `/slack` prompt additionally:
- reads `setup-slack-channel` before planning
- delegates the Slack app, managed provider connection, and workspace
verification to that skill
- verifies Node.js 20 or newer
- protects Slack tokens, signing secrets, and Intelligence API keys
- requires all three `setup-slack-channel` gates before reporting
success
## Microsoft Teams prompt
The `/teams` prompt mirrors the complete start-from-scratch flow without
inventing or requiring a Teams-specific onboarding skill. It instead:
- treats `https://docs.copilotkit.ai/teams` as the provider source of
truth, following the documentation-based prompt pattern already used by
the docs-root Channels CTA
- tells the agent to select the user’s backend in the docs and follow
the linked Intelligence configuration and Teams connection pages in
order
- rejects substituting Slack setup instructions or relying on remembered
Azure Bot and Teams app setup
- verifies Node.js 22 or newer, matching the published managed Teams
runner requirement
- requires confirmation before consequential Azure, Intelligence, and
Teams account changes
- protects tokens, client secrets, and API keys
- requires the app to be installed in the intended Teams scope, the
Intelligence Channel to be Online, and a real Teams message or mention
to receive a reply before reporting success
## Provider scoping
The Channels overview source is shared by both routes. Separate
`FrontendOnly` blocks ensure that:
- `/slack` receives only the Slack skill-driven prompt
- `/teams` receives only the Teams documentation-driven prompt
- neither route leaks the other provider’s onboarding source or
instructions
## Research basis
The final flow follows responsibilities and requirements already
documented in the repository:
- `copilotkit-setup` owns new-project and managed-Intelligence
onboarding
- `copilotkit-channels` owns the generated Channels runtime and warns
against duplicate/manual Channel wiring
- `setup-slack-channel` owns the Slack provider flow and its three
success gates
- the docs-root Channels CTA already produces provider-specific
coding-agent prompts that point to the selected Shell Docs guide URL
- the Teams guide documents Node.js 22+, managed Intelligence
configuration, Azure Bot setup, installation in Teams, Online runtime
status, and real-message verification
- the CLI docs consistently use `npx copilotkit@latest`; they do not
require a global installation
- `npx copilotkit@latest skills install` is the documented skill
installer, and `npx copilotkit@latest create` is the documented
new-project scaffold
## Scope
This PR intentionally changes only:
- `showcase/shell-docs/src/content/docs/channels/index.mdx`
- `showcase/shell-docs/src/lib/__tests__/channels-docs.test.ts`
It does not add a component, alter navigation, change either provider
tutorial, modify the Intelligence browser setup flow, or claim a
Teams-specific onboarding skill exists.
The branch is intentionally presented as one commit:
- `docs(channels): add copyable onboarding prompts`
## Validation
- full shell-docs suite: `npm test -- --maxWorkers=1
--no-file-parallelism`
- full Vitest suite confirmation: `npx vitest run --maxWorkers=1
--no-file-parallelism --reporter=dot`
- focused Channels docs suite: 29 tests passed
- `pnpm exec oxfmt --check
showcase/shell-docs/src/lib/__tests__/channels-docs.test.ts
showcase/shell-docs/src/content/docs/channels/index.mdx`
- `git diff --check`
- rendered Slack verification at `http://localhost:3003/slack`: one
provider-specific prompt with `setup-slack-channel`, no Teams docs URL,
and one `Copy Text` control
- rendered Teams verification at `http://localhost:3003/teams`: one
provider-specific prompt with the Teams docs URL, no
`setup-slack-channel` reference, and one `Copy Text` control
- pre-commit and commit-message hooks passed
All test runs used one worker with file parallelism disabled to keep
memory use bounded.