Skip to content

Publish the official Dispatch plugin for Claude Code and Codex - #952

Merged
selfcontained merged 3 commits into
mainfrom
agt_786ebdc45489/build-dispatch-plugin-claude-codex
Aug 13, 2026
Merged

Publish the official Dispatch plugin for Claude Code and Codex#952
selfcontained merged 3 commits into
mainfrom
agt_786ebdc45489/build-dispatch-plugin-claude-codex

Conversation

@selfcontained

Copy link
Copy Markdown
Owner

Makes this repo a plugin marketplace for both Claude Code and Codex, shipping eleven narrow skills that teach agents to use Dispatch's own capabilities.

Closes the dispatch-usage-skills-bundle idea. Manual install only — stale-version detection, auto-attach, and marketplace submission stay deferred per Brad's decision.

What ships

.claude-plugin/marketplace.json # Claude Code marketplace
.agents/plugins/marketplace.json # Codex marketplace
plugins/dispatch/
├── .claude-plugin/plugin.json # Claude Code manifest
├── .codex-plugin/plugin.json # Codex manifest
├── skills/<name>/SKILL.md # 11 skills, shared by both platforms
├── evals/ # 4 ablation cases
└── README.md
TierSkills
Migration — existing doc-tool payloads become skill bodieswhiteboard, personas
Extraction — the conditional launch-guidance blocksreview-workflow, ui-validation
Discovery — "agents don't know it's an option"sharing, brain, subagents, repo-tools
Discovery, low-frequencyjobs, templates, personalities

Install:

claude plugin marketplace add selfcontained/dispatch && claude plugin install dispatch@dispatch
codex plugin marketplace add selfcontained/dispatch && codex plugin add dispatch@dispatch

Verified end-to-end on both CLIs

Against claude 2.1.231 and codex-cli 0.147.0, using throwaway CLAUDE_CONFIG_DIR / CODEX_HOME roots — not the machine's real config.

Claudeclaude plugin validate passes on both the marketplace and the plugin (clean under --strict too). After marketplace add + install, claude plugin details dispatch@dispatch reports:

Component inventory
Skills (11) brain, jobs, personalities, personas, repo-tools, review-workflow,
sharing, subagents, templates, ui-validation, whiteboard
Agents (0) Hooks (0) MCP servers (0) LSP servers (0)
Projected token cost
Always-on: ~592 tok added to every session

Codexcodex plugin marketplace add + codex plugin add both exit 0 non-interactively and install 0.1.0 from the Codex-native manifest. codex debug prompt-input shows all eleven reaching the model prompt inside <skills_instructions>, namespaced dispatch:<name> with the right descriptions — so this is confirmed model-visible, not just installed.

Design

The description is the product. Descriptions load into every session unconditionally; bodies load only on a match. So they're written as symptom triggers rather than feature labels — an agent that doesn't know a capability exists will never match its name, but will match a description of the situation it's currently in. Total always-on cost is 2,258 chars (~592 tokens), under the 2,891 chars launch guidance already injects.

Narrow skills, not mega-skills. Eleven short descriptions always-on, exactly one body loaded on a match. A single "automations" skill would load four unrelated bodies whenever one of them fired.

Dual manifests. Codex does fall back to reading .claude-plugin/, but that's undocumented by OpenAI, so the Codex-native manifests are carried explicitly rather than relying on it.

Explicit version in both manifests — Claude uses it as the update cache key, so routine commits to main don't register as a plugin update. Omitting it would resolve the version to the commit SHA and make every push look like a new release.

Purely additive. Launch guidance is not trimmed and the documentation-bearing MCP tools (whiteboard_howto, persona_templates) stay in place; content lives in two places for now. Deleting either would regress any repo that hasn't installed the plugin. Both trims are follow-ups gated on a real soak period.

Deliberately not skills:dispatch_event, pin discipline, and session naming. Skills only load on a task match, so always-relevant protocol obligations can't move out of launch guidance.

The vitest guard

apps/server/test/plugin-manifest.test.ts checks the manifests agree on name/version/source shape and that every SKILL.md's frontmatter parses.

This isn't speculative. claude plugin validate caught a real defect mid-build: an unquoted colon in the personalities description broke its YAML frontmatter, and the failure mode is silent — the skill still installs, it just loads with empty metadata and never fires. CI has no claude/codex CLI to catch that. Confirmed the guard fails on the reintroduced bug and passes once fixed.

It also asserts the always-on description budget stays under the 2,891-char launch-guidance ceiling, so the plugin can't quietly grow past the thing it augments.

Evals

Four ablation cases (sharing, brain, subagents, repo-tools) in the documented prompt.md + graders/criteria.md layout, aimed at --ablation with-without so the no-plugin baseline arm gives a score delta.

They have not been executed.claude plugin eval is in early access and refuses to run on 2.1.231 — every invocation returns `plugin eval` is currently in early access and exits. plugins/dispatch/evals/README.md says so plainly; treat the criteria as a first draft to tune once the runner is available, not as a passing suite.

sharing is the sharpest case in the set: the rule it encodes already exists in two always-on places (launch guidance and CLAUDE.md) and still gets ignored, so a measurable delta there would be evidence that arriving at the moment of action beats more background text.

Checks

  • pnpm run check — passes
  • pnpm run test — 3,635 passed, 9 skipped across all three suites
  • pnpm run format — clean
  • pnpm run test:e2e — run locally before pushing (to avoid colliding with CI's stack)
  • No apps/web/ changes, so finalize:web doesn't apply

The plugin-format spec work in #951 was pulled into this directly rather than linked; that PR can be closed without merging.

🤖 Generated with Claude Code

selfcontainedand others added 3 commits August 13, 2026 08:48
This repo now doubles as a plugin marketplace. Eleven narrow skills teach
agents to use Dispatch's own capabilities — the Brain, subagents,
.dispatch/tools.json, artifact sharing, the review workflow, the whiteboard,
jobs, templates, personas, personalities, and UI validation.
Dual manifests, one tree: `.claude-plugin/marketplace.json` +
`.agents/plugins/marketplace.json` at the root, and both plugin manifests under
`plugins/dispatch/`, sharing a single `skills/` directory. Codex does fall back
to reading `.claude-plugin/`, but that behavior is undocumented by OpenAI, so
the Codex-native manifests are carried explicitly.
The skill description is the product: descriptions load into every session
unconditionally while bodies load only on a match, so they are written as
symptom triggers rather than feature labels. Total always-on cost is ~2.3 KB
(~592 tokens by `claude plugin details`), below the 2,891 chars Dispatch's own
launch guidance already injects.
Purely additive — launch guidance is not trimmed and the documentation-bearing
MCP tools (`whiteboard_howto`, `persona_templates`) stay in place. Trimming
either is a follow-up gated on how adoption actually goes.
Adds a vitest guard for the manifests and skill frontmatter: CI has no
claude/codex CLI, and a SKILL.md whose YAML frontmatter fails to parse still
installs cleanly — it just loads with empty metadata and never fires. That
exact bug (an unquoted colon in a description) was caught during this work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- brain: `brain_list_remove` takes `index` or `where {field, equals}`, not a
`match` param. Documents the object shape and that indexes shift on removal.
- brain: narrow the description so it no longer overlaps `subagents` on live
handoff — it now reads as durable storage that survives the session, leaving
coordination to `subagents`.
- repo-tools: the mtime cache applies to hooks, not tools. Measured against a
live server: `handleMcpRequest` rebuilds per request and `loadRepoTools` has
no cache, so an edited description and a newly added tool both appeared in the
next tools/list with no restart. The real constraint is client-side — the CLI
holds the tool list it fetched at session start.
- Root README: state the unsigned/unsandboxed/full-privileges warning above the
install commands rather than only behind a link.
- Plugin README: the "entire contents" claim was literally false (README and
evals/ also exist). Scope it to runtime-relevant components and give the exact
commands to verify, plus `claude plugin details`' component inventory.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Per Claude Code's docs, installing from a marketplace is explicitly a two-step
process and the shell `claude plugin install` doesn't take effect in a running
session — plugins load on next start or via `/reload-plugins`. The README
omitted that, so a shell installer would expect the skills immediately.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@selfcontained
selfcontained merged commit fe8a46b into mainAug 13, 2026
1 check passed
@selfcontained
selfcontained deleted the agt_786ebdc45489/build-dispatch-plugin-claude-codex branch August 13, 2026 15:23
selfcontained added a commit that referenced this pull request Aug 15, 2026
The official plugin (#952) shipped with a README section and nothing else —
no in-app docs section and no ambient tip, so the only place a user learns
it exists is the GitHub README.
- New docs-pane section "Plugin" covering trust (unsigned/unsandboxed, no
executable components, how to verify), the two-step marketplace + install
flow on Claude Code and Codex, the eleven skills and what each fires on,
and update mechanics (Codex has no update subcommand).
- Ambient tip pointing at plugin#plugin-install, since 0.34.1 (the plugin
landed after the v0.34.0 release commit).
- README's plugin blurb named 8 skills; the tree has 11 — personas,
personalities and ui-validation were missing. Same fix in
plugins/dispatch/README.md's intro paragraph.
- README's "user-facing documentation" list was missing browser feedback,
service resources and the new plugin section, and said "jobs" where the
section is templates and jobs.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
selfcontained added a commit that referenced this pull request Aug 16, 2026
* Trim launch guidance to the plugin's skills, behind a setting
The Dispatch plugin (PR #952) ships 11 skills, three of which cover
ground launchGuidance already covers unconditionally: ui-validation and
sharing for the Playwright rule, review-workflow for create_pr and the
Autonomous Review block. A skill's body only loads when its description
matches the situation, so anything that must fire before a task exists —
the no-task guardrail, session naming, dispatch_event, pin surfacing —
cannot become a skill and is never trimmed.
Adds a server-wide setting (Settings → Agents → Launch guidance, off by
default) that switches buildLaunchGuidance between the full ruleset and a
trimmed one. It's a user assertion, not detection: Dispatch cannot see
whether the CLI has the plugin installed, so the copy says what turning
it on without the plugin costs, and only Claude Code and Codex agents —
the plugin's platforms — are ever trimmed.
The two tool-routing lines keep a short always-on nudge even when
trimmed. dispatch_share was already stated in two always-on places and
still got skipped, so moving those habits entirely onto a match-triggered
skill is the riskiest part of the trim and is the thing to watch during
the soak. The job-run branch is untouched — every rule there is a runtime
protocol obligation with no task-shaped trigger.
Measured live on a dev stack, same endpoint, autoReview on:
2678 chars full -> 2162 trimmed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Address review: job-run guard, unknown-state gate, a11y, copy
- manager.ts: skip the settings read for job runs. Their ruleset is never
trimmed, so an unchanged launch path shouldn't gain a dependency on a
query that can fail (DB outage, or the pre-migration settings window).
- Checkbox stays disabled until the GET lands, and after a failed one. An
unread value must not render as a confirmed "off" — the wrong belief
here silently drops guidance from every agent launched afterwards.
- Explicit short aria-label plus aria-describedby, so the accessible name
isn't the whole ~170-word detail block.
- Chain the POSTs. Sequence-guarding local state left two quick toggles
able to land out of order at the server.
- Lead the description with the consequence of asserting an install you
don't have, instead of burying it after the implementation caveats.
Verified live: with the trim on, a job-run agent still gets the untouched
620-char job ruleset (read from its own process argv); disabled/enabled
gating, aria wiring, and last-write-wins confirmed in Playwright.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Shorten Autonomous Review for everyone, not just behind the toggle
Two thirds of the old 830-char block was reactive — "after feedback
arrives, call X", "ask the reviewer to verify", "a clean approval needs
no action" — and Dispatch already re-injects each of those at the moment
it applies (buildLaunchPersonaResponseText, reviews/injection-prompts.ts).
Carrying them at launch is strictly worse: the agent holds all of it for
a flow that may never start. That redundancy comes from the injection
system, which every user has, not from the plugin — so gating it behind
the toggle would hide a broadly-correct cleanup behind a flag most people
won't turn on.
What survives is the part nothing can inject: the gate the agent has to
know before it decides it is done. Nothing can deliver "before you emit
done, do X" at the right moment, because the moment is the agent's own
judgment — which is also why it can't become a skill.
The toggle now gates only what genuinely needs a skill to replace it: the
Playwright methodology and the create_pr routing line. The short
dispatch_share nudge stays in both states — that habit already failed
when stated in two always-on places, so it is not what this experiment
should be risking.
Measured live, same endpoint, autoReview on:
2678 on main -> 2193 default (-485 for everyone) -> 2098 trimmed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Keep a durable review-recovery pointer in the launch guidance
Review injection is best-effort: sendPromptBestEffort swallows the
failure when the parent agent has no live session, and nothing replays it
on the next launch. Under the shortened rule an agent could then be left
knowing reviews block done, but not how to find one submitted while it
was down.
Adds "if a review prompt never arrived, check with
dispatch_review_list_feedback" — 55 chars against the 485 the shortening
saves, and it restores the self-recovery path the old block provided.
Persisting and replaying dropped injections is the real fix and is a
separate change.
Verified in the live process argv: the rule is 422 chars and carries the
pointer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Trim the rules the MCP tool schemas already document
The first pass only trimmed what a plugin skill replaced, which left the
verbose rules untouched and made the toggle nearly a no-op. The bigger
duplication is with the tool schemas: dispatch_pin's own description
already lists every pin type, explains shortcut/confirm/disabled, and
says to pair a blocking shortcut with waiting_user; dispatch_event's
enumerates the status types. Restating them in launch guidance repeated a
description the agent already has, in every session, whether or not the
flow ever comes up.
Trimmed now means short pointers: name the session, report status, and
surface data or ask questions with pins — one line each, with the two pin
rules folded into one. Kept the two things no schema states: that blocked
means genuinely stuck rather than an error you're about to fix, and that
reported status is verified and auto-corrected. The no-task guardrail
stays verbatim; nothing else states it anywhere.
Note this half doesn't actually depend on the plugin — the tool schemas
ship to every agent. Only the browser-validation and pull-request rules
need the skills, so the setting copy now separates the two.
Measured live, same endpoint, autoReview on: 2590 -> 1336 chars (-48%).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Pin the "setting off is inert" property with a test
Diffed the whole option matrix against the branch point to answer how
confident we are that an untouched setting changes nothing: 48 of 64
combinations are byte-identical, and all 16 that differ are autoReview=true
with the Autonomous Review rule as the only changed line. Every job-run
combination is identical.
This test guards the half of that which stays true forever: trimmedGuidance
false and undefined must produce identical guidance, for every agent type
and both branches. (The other half — that the deliberate Autonomous Review
change is the only remaining difference — is a one-time property of this
PR, not an invariant.)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Cut the launch-guidance setting copy down to a checkbox
Two rounds of review feedback each asked for something to be said more
prominently, and the result was a bordered box nested inside the section,
holding a ~170-word paragraph nobody would read. Brad called it: no nested
container, one short sentence.
Now a two-sentence section description and a plain checkbox row. The
plugin requirement survives as a requirement rather than a warning
paragraph; the rest of the explanation belongs in the PR, not the
settings pane. Dropping the long detail block also removes the need for
the aria-describedby wiring — the accessible name is now just "Use short
startup rules".
Behavior is unchanged: still disabled until the GET lands, still chains
writes, still an explicit user assertion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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

@selfcontained