Skip to content

docs(cef:develop): rewrite widgets.md for the cef dev loop + WidgetRuntime#6

Merged
upalinski merged 10 commits into
mainfrom
docs/widgets-end-to-end
Jul 21, 2026
Merged

docs(cef:develop): rewrite widgets.md for the cef dev loop + WidgetRuntime#6
upalinski merged 10 commits into
mainfrom
docs/widgets-end-to-end

Conversation

@upalinski

Copy link
Copy Markdown
Collaborator

Rewrites the cef:develop widget reference for real widget development, and bumps the plugin version. Keeps the plugin in sync with the SDK's widget work (CEF-AI/sdk#113 + #114), per the SDK's plugin-sync rule.

What

  • plugins/cef/skills/develop/references/widgets.md — full rewrite: the cef dev loop, the widget manifest, typed kinds (record | list | dashboard | submit | conversation | composite | custom), a worked list example using window.WidgetRuntime.query, connectAgent() + not-connected handling, and embedded vs standalone.
  • plugins/cef/.claude-plugin/plugin.json — version 0.1.0 → 0.1.1.

Public-safe: no internal names, ADRs, or private source paths.

🤖 Generated with Claude Code

…ntime

Document real widget development: the cef dev local loop, the widget
manifest, typed widget kinds, embedded vs standalone run modes,
connectAgent, and querying cubbies via window.WidgetRuntime.query. Bump
the cef plugin version to 0.1.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@upalinski
upalinski requested a review from spoluyan as a code owner July 21, 2026 10:48
upalinski added 7 commits July 21, 2026 14:44
- deploy/develop quickstarts: add the 'pnpm install' step after 'cef init'
  (init no longer installs by default).
- develop: document 'npx cef dev' (widget dev server) + the 'pnpm dev' script alias.
Where logs go, logging that surfaces the real cause (fold error text into the
message — the sandbox drops extra console args), guard handlers so a throw
can't wedge the Job, local repro with testAgent, and a common-failure table.
Linked from SKILL.md; plugin 0.1.1 → 0.1.2.
Extra console args are JSON-serialized into a separate field; an Error
collapses to {} (non-enumerable message/stack). Put the detail in arg 0.
…ample

Align engagements.md with the vault contract (SDK PR): Event is
{ type, payload, timestamp, context?, role?, eventId? }; the example handler no
longer uses event.ts/event.id (records Date.now()). Plugin 0.1.2 -> 0.1.3.
widgets.md: cef dev now live-reloads (not manual refresh); add an 'iterating
with a coding agent' note — use browser automation for the visual/console loop,
but the interactive wallet-connect + live data need a human. Plugin 0.1.3 -> 0.1.4.
…llet connect

The embed-wallet session persists across reloads, so live-reload reconnects
silently — the human gate is only the first connect, not every iteration.
…e raw SQL)

Connection + scope (endpoints/wallet/agentId/cubbyAlias) must be in the manifest
(resolved before JS); queries[] are optional — a custom widget can pass raw SQL
to WidgetRuntime.query(). The security boundary is the scope, not the SQL.
spoluyan

This comment was marked as duplicate.

… querying)

cubbyAlias is optional if the widget never reads a cubby, but query() has no
per-call cubby arg — it always targets manifest.cubbyAlias — so a querying
widget must declare its one cubby binding. Only endpoints/wallet/agentId are
strictly always-required.

@spoluyan spoluyan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review (inline): rewrite widgets.md for the cef dev loop + WidgetRuntime

High-quality rewrite. The new widgets.md is a clear upgrade — from a vague manifest/cef push framing to a concrete cef devcef buildcef push loop, typed widget kinds, a worked list example with connectAgent()/AgentNotConnectedError handling, and embedded-vs-standalone. The new troubleshooting.md is genuinely valuable (the Error{} serialization gotcha alone will save people hours). The Event<P> correction and pnpm install additions are accurate.

CI is green (Analyze, CodeQL, validate), and the diff is public-safe — no internal names, ADR refs, or private source paths leaked.

Blocking

widgets.md ends with two leaked tool-call tags — see the inline comment at the very end of the file. </content> / </invoke> are agent-write artifacts that got committed; they'll render as visible stray text at the end of the reference.

Should fix

SKILL.md's lead example still uses the removed event.ts / event.id. This PR drops ts/id from Event<P> (and updates engagements.md's example to match — see inline ✅), but the identical "shape at a glance" example in develop/SKILL.md (lines ~72-77) was unchanged context and still reads:

[Date.now(), event.payload.text, event.ts],   // ✗ event.ts no longer exists
await ctx.publish("ack", { for: event.id });  // ✗ event.id no longer exists

GitHub won't let me anchor an inline comment there (those lines aren't in this PR's diff), but it's directly contradicted by the type change in this very PR — worth a follow-up edit so the first example a reader sees matches the reference it links to.

Nits (inline)

  • The candidates example omits description though the field table still lists it as optional.
  • "Claude Code's Chrome tools" will date; consider generic phrasing.

Fix the blocker + the SKILL.md example and this is good to merge.

Comment on lines +263 to +264
can keep its query logic in the JS — `query("SELECT text, ts FROM messages …")`
— with no `queries[]` at all. Either way the boundary that matters is the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Blocking — these two lines are leaked tool-call artifacts (</content> / </invoke>), not part of the document. They're leftover from the agent write that produced the file and will render as visible stray text (or break the markdown render) at the end of the reference.

Both lines should be deleted so the file ends cleanly at:

- **`id` must be unique within the agent** and is what `cef dev [widgetId]`
  targets.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the stray </content>/</invoke> in bf5ac94; the file now ends cleanly at the id-unique bullet.

[now, event.payload.text, now],
);
await ctx.publish("ack", { for: event.id });
await ctx.publish("ack", { text: `got: ${event.payload.text}` });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Good — the corrected ack payload typechecks against the rewritten Event<P> (no more event.id, which the old { for: event.id } relied on). Same for now replacing the removed event.ts.

⚠️ Heads-up: the same example still appears verbatim at the top of develop/SKILL.md (lines ~72-77) and was not updated here — it still uses event.ts and event.id. Since this PR is the one removing those fields, that lead example now contradicts the reference. Worth updating in this PR. (Those lines weren't in the diff, so I couldn't anchor an inline comment there — see the review summary.)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the SKILL.md lead example in bf5ac94event.ts/event.id gone (records Date.now(), ack carries text), matching the corrected Event<P> this PR introduces.

timestamp: string; // ISO-8601, assigned by the vault
context?: string; // stream context (conversation / partition key)
role?: string; // publisher role, e.g. "user" | "agent"
eventId?: string; // server-assigned id (UUID v7); may be absent inbound

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice touch documenting eventId? as "server-assigned (UUID v7); may be absent inbound" — it signals to handlers not to rely on it existing inbound.

Nit: since the old example's { for: event.id } is gone, consider adding a one-liner that handlers needing correlation should carry their own id in the payload (not lean on eventId). Optional.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left as optional — the eventId? doc already signals not to rely on it inbound; correlation-in-payload is a reasonable pattern but out of scope for this doc pass.

events: ["candidate_added"], // optional: event types the widget subscribes to
dir: "./widgets/dashboard", // path (relative to cef.config.ts) to the BUILT widget dir
entry: "dashboard.html", // entry file WITHIN dir
config: { columns: ["name", "stage"] }, // kind-specific config, carried verbatim

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the field-reference table below lists both name and description as optional metadata, but this canonical candidates example sets only name. Since this is the block people will copy, either show both (description: "Lists recent candidates") or drop description from the table — keep the two consistent. Trivial.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added description: "Recent candidates" to the example in bf5ac94 so it matches the field-reference table.


### Iterating with a coding agent

If your coding agent can drive a browser (e.g. Claude Code's Chrome tools), the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "Claude Code's Chrome tools" is accurate today but will date the doc. The sentence right above already generalizes to "a coding agent can drive a browser" — consider dropping the parenthetical or making it generic (e.g. "(e.g. via Playwright / a browser MCP)"). Optional.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it generic in bf5ac94 — "(e.g. via Playwright or a browser MCP)".

…L example

- Delete leaked </content></invoke> at end of widgets.md (blocker).
- SKILL.md lead example: event.ts/event.id -> Date.now()/ack text (matches the
  corrected Event<P> this PR introduces).
- Add description to the widget example; generic browser-automation phrasing.
- Plugin 0.1.4 -> 0.1.5.
@upalinski
upalinski merged commit 11ed1dc into main Jul 21, 2026
3 checks passed
@upalinski
upalinski deleted the docs/widgets-end-to-end branch July 21, 2026 14:48
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.

2 participants