speckit-companion
CLAUDE.md104 starsChanged 26 days agoMITView on GitHub
SpecKit Companion is a VS Code extension that gives AI assistants (terminal CLIs, IDE chat, the Claude Code panel) visual spec-driven development: specs (spec/plan/tasks), steering docs, and the Companion pipeline. The repo also ships a second, independently-versioned spec-kit extension under apps/speckit-extension/. Provider list: the speckit.aiProvider enum in package.json. Five deliverables live under apps/: the VS Code extension (apps/vscode/src/, apps/vscode/webview/, its own package.json), the spec-kit extension (apps/speckit-extension/), the GitHub Copilot app canvas (apps/copilot-canvas/, an Agent Plugin whose board lives under com.github.copilot/extensions/speckit-companion/,…
In this repository32 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .github/copilot-instructions.mdCopilot instructions
- speckit-analyzeSkill
- speckit-checklistSkill
- speckit-clarifySkill
- speckit-constitutionSkill
- speckit-convergeSkill
- speckit-implementSkill
- speckit-planSkill
- speckit-specifySkill
- speckit-tasksSkill
- speckit-taskstoissuesSkill
- eval-speckit-extensionSkill
- feature-clipSkill
- release-qaSkill
- shotsSkill
- speckit-analyzeSkill
- speckit-checklistSkill
- speckit-clarifySkill
- speckit-constitutionSkill
- speckit-convergeSkill
- speckit-git-commitSkill
- speckit-git-featureSkill
- speckit-git-initializeSkill
- speckit-git-remoteSkill
- speckit-git-validateSkill
- speckit-implementSkill
- speckit-planSkill
- speckit-specifySkill
- speckit-tasksSkill
- speckit-taskstoissuesSkill
- submit-catalog-updateSkill
The file
We split this CLAUDE.md into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 65
Ask
getProjectRoot()for the project folder: Never read the first workspace folder. - Very specific: line 70
A new capture script goes on two packing lists: Add it to RUNTIME_SCRIPTS in package-manifest.py and give it a !
- Distinctive: line 108
Run the extension: F5 → Extension Development Host.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
SpecKit Companion is a VS Code extension that gives AI assistants (terminal CLIs, IDE chat, the Claude Code panel) visual spec-driven development: specs (spec/plan/tasks), steering docs, and the Companion pipeline. The repo also ships a second, independently-versioned spec-kit extension under apps/speckit-extension/. Provider list: the speckit.aiProvider enum in package.json.
Repo map
Five deliverables live under apps/: the VS Code extension (apps/vscode/src/, apps/vscode/webview/, its own package.json), the spec-kit extension (apps/speckit-extension/), the GitHub Copilot app canvas (apps/copilot-canvas/, an Agent Plugin whose board lives under com.github.copilot/extensions/speckit-companion/, loaded in this repo through .github/extensions/speckit-companion/), the Claude Code mod (apps/claude-mod/, listed by the repo-root .claude-plugin/marketplace.json; its hooks/vendor/ is bundled from the canvas's spec-rules.mjs by npm run mod:build), and the marketing site (apps/website/).
specs/— historical feature folders plus the pinned_0N_demo-*viewer fixtures.docs/— images only: the screenshots the READMEs and the site load, the architecture diagram, the walkthrough video. No prose lives here; a test fails on a new markdown file.apps/vscode/tests/— integration, eval and shared fixtures, including the VS Code mock. Unit tests live in__tests__beside the code they cover.assets/— the mascot and social art.content/media/— the clips and renders the site and README serve.tooling/scripts/— the build and capture commands that produce them..github/,.specify/,.claude/,.agents/,.codex/,.storybook/,.vscode/— committed dot-folders that arespecify initoutput and manual-testing fixtures.content/design/— Workflow Builder design-tool mockups (*.dc.htmlscreens pluscanvas.json), not a dot-folder or a fixture..serena/,.pytest_cache/, and the per-agent command mirrors in.gitignore— local caches, not source.
The example apps and bench sandboxes that used to sit here now live in the sibling speckit-sandboxes repo: one recipe per reusable test sandbox (/sandbox builds one), the seed apps they start from, the benchmark harness in its bench folder, and kept run results in its evidence folder. .claude/sandboxes-env.sh is the one place that knows where that checkout is; commands and scripts source it and never spell the path out.
Where things are documented
Behaviour is documented by the code and its tests first. User-facing reference lives on the site, under apps/website/src/content/docs/. Everything else is one of these:
- "Architecture rules" below — the cross-module rules the code cannot show.
.claude/skills/feature-clip/— how every generated image, GIF and web clip is made, and what a feature owes the media manifest. Regenerate withnpm run clips:captureon any webview UI, styling, token or fixture change; never hand-edit a generated file..claude/skills/shots/— screenshots and recordings of the real product, and the real-window and terminal checks..claude/commands/changelog-entry.md— the changelog voice and the shape of a release..claude/commands/publish.md— the release checklist.THEME.md— the marketing look (the site's Constellation colours, type, mascot and motifs) for anything promotional;DESIGN.md— the viewer's tokens and the taste rules for figures and captures..claude/review-checklist.md— webview/CSS correctness invariants review scans for (.sr-onlyvshidden, ellipsis trio, Preact string styles, etc.).apps/speckit-extension/docs/— the spec-kit extension's own notes:node-model.md(how commands are built from nodes),living-specs.md,publishing.md(its release flow).apps/vscode/docs/telemetry.mdandapps/website/docs/analytics.md— the event catalogs and how to read them in PostHog.
This repo does not keep living specs of its own; the feature it ships is unaffected.
One fact, one owner
A fact is written once, on the surface this table names. Every other surface links to it and never restates it, so a change updates the owner and nothing else. A second copy is a bug: delete it, do not sync it.
| Fact | Owner |
| A setting, its values and its default | package.json contributes.configuration, shown to users on the site's apps/website/src/content/docs/docs/reference/configuration.mdx |
| The providers | the speckit.aiProvider enum, shown in the provider table on the same page; a test holds the two together |
| Install steps | the site's install page; a README carries its own install command and nothing about the other deliverables' |
| How a feature works for a user | its one page under apps/website/src/content/docs/ |
| What changed for a user | one [Unreleased] line in the changelog of the deliverable that changed; site and docs changes get no line |
| A rule the code cannot show | this file |
A README is an intro, an install, a first run and a link to the site. It gets an edit when the install or the first run changes, not when a feature does.
A few changes carry a follow-on that is easy to miss:
- Webview UI, styling, tokens, capture stories or fixtures →
npm run clips:capture, then commit what it regenerates, includingcontent/media/web/(tracked on purpose: a deploy cannot rebuild it). - A webview component with a sibling
*.stories.tsx→ update the stories in the same change. spec-rules.mjsin the Copilot canvas →npm run mod:buildand commit the bundle the Claude Code mod reads.- Viewer CSS or its markdown renderer →
npm run canvas:buildand commit the canvas's vendored copy; CI fails on a stale one. - A new command in
apps/speckit-extension/→ add it toextension.ymlprovides.commands, or the installer skips it. - A new surface (an app, a panel, a provider, a top-level feature path) → add its path glob to
.claude/skills/release-qa/surface-map.yml. - The Get Started walkthrough → keep its step copy consistent with
contributes.viewsWelcome.
Architecture rules
docs/architecture/diagram.html draws how a command travels (generated from the JSON beside it by archify; edit the JSON, never the HTML). These are the rules it cannot show.
- The host owns the filesystem.
apps/vscode/src/reads and writes; the webview underapps/vscode/webview/src/gets state bypostMessageand never touches a file. core/imports nothing fromfeatures/orai-providers/. A test holds the two grandfathered files to an exact allowlist, so the list only shrinks.- Ask
getProjectRoot()for the project folder. Never read the first workspace folder; a test fails on a direct read. .spec-context.jsonis the one store, and only writers that keep its guarantees touch it. History only grows, writes merge, a status never moves backward, and one cross-process lock covers every writer. Deterministic writes come from the extension's buttons and the in-command hook scripts (by: extension); the assistant's journaling is best effort (by: ai).- A step closes itself as its last action. Leaving the close to the hook that follows strands the step on a provider that can only print the hook for a person to run.
- Everything a repository controls reaches a panel as text, never markup. Document text, filenames, run-record notes and version strings go through
escapeHtmlfor element content, DOM APIs for attributes andsafeUrlfor links, in the viewer, the editor and the builder alike. Fenced code and diagrams are escaped before highlighting sees them. - The pipeline's shape is derived once.
apps/speckit-extension/scripts/pipeline-graph.pyresolves it with the same code the build uses, and the Workflow Builder reads that JSON. Do not write a second derivation in TypeScript. - A new capture script goes on two packing lists. Add it to
RUNTIME_SCRIPTSinpackage-manifest.pyand give it a!rule in.vscodeignore, and import it by plain name;package-manifest.py --checkfails when either list falls behind. - The Copilot canvas and the Claude Code mod share no code with
apps/vscode/. They read the same.spec-context.jsoncontract throughspec-rules.mjs. The mod only reads. The canvas writes the record only in a project without the Companion writer, plus the one missing step finish it appends when a turn ended with the document written. - Adding a provider → implement
IAIProvider, register it inaiProviderFactory.ts, add itsPROVIDER_PATHSentry, add the enum value inpackage.json, add its row to the provider table on the site. Terminal CLIs extendcliTerminalProvider.ts; Gemini and Wibey stay outside it because both run interactively. - Retired, do not reintroduce: the
templateProfile,turboWorkflowPickerandcomplexityFastPathtoggles and thecompanion-turbopreset.speckit.companion.templateProfilesurvives only inapps/vscode/src/core/settingsMigration.ts, to migrate old values.
Gotchas
Two extensions, two sets of docs
The two extensions each have their own README, CHANGELOG, version, release flow, and tag namespace: VS Code extension = root README.md/CHANGELOG.md, package.json version, /publish → v* tag; spec-kit extension = apps/speckit-extension/README.md/CHANGELOG.md, extension.yml extension.version, /publish-speckit-ext → speckit-ext-v* tag (/publish-all runs every deliverable's flow in the safe order, with /publish-mod for the Claude Code mod and /publish-canvas for the Copilot canvas; /release-loop runs the whole release, fixes through /release-qa to publish). A change under apps/speckit-extension/ updates its docs, never the root ones (and vice-versa); overlapping entries for a feature spanning both halves are expected. Never edit .specify/extensions/companion/CHANGELOG.md — generated, gitignored, overwritten on install. The release flow owns the version bump — feature branches do not. A branch touching apps/speckit-extension/ writes under ## [Unreleased] and leaves extension.yml version, the README badge, and publishing.md alone; bumping on a branch is what produces version/changelog/badge drift.
/releases/latest resolves across both tag namespaces
Both products share one GitHub releases list, so …/releases/latest can return either — this bit the update checker (#274) and install URLs (#273). Guards: the update checker filters tags by ^v\d+\.\d+\.\d+$, and the stable spec-kit-ext download lives behind the dedicated companion-latest prerelease tag. Never reintroduce a bare /releases/latest lookup.
Screenshot filenames are load-bearing
The root README writes relative image paths and vsce rewrites them to raw.githubusercontent.com/.../main/docs/screenshots/<file> when it packages; apps/speckit-extension/README.md writes that absolute form by hand, because the Spec Kit catalog renders it from main. Either way the Marketplace serves the last published README but resolves images against current main — renaming or deleting a referenced screenshot retroactively 404s the published listing (this broke the v0.18.0 listing). Overwrite in place; never rename or delete.
escapeHtml is safe for element content only
The webview's escapeHtml (textContent→innerHTML) does NOT escape attribute quotes, so user data inside alt="${escapeHtml(x)}" can break out and inject. Never interpolate user data into an HTML attribute via innerHTML; use DOM APIs (createElement + textContent + setAttribute).
Extension isolation
The shipped extension is ONLY what's in the .vsix. .claude/**, .specify/** are user/workspace files — read-only from the extension's perspective; never implement extension features by modifying them. Extension-owned behavior lives in command handlers (apps/vscode/src/features/specs/specCommands.ts, viewer message handlers) or in the prompt text the extension builds (ai-providers/*). Exception: the committed .specify/, .claude/, .codex/, .agents/skills/, .github/{agents,prompts}/speckit.* dirs are manual-testing fixtures (specify init output) — don't delete them as an "isolation violation". One deliberate exception: when a project still carries a leftover Companion preset, activation runs specify preset remove <id> once, and the CLI deletes that preset's folder under .specify/presets/ and restores the stock .claude/skills/speckit-* bodies. Activation never adds a preset. The extension itself writes no files there.
Demo spec fixtures are a pinned baseline
specs/_00…_03_demo-* are committed fixtures, each pinned to one viewer state. Clicking through the viewer mutates their .spec-context.json — git restore those changes, never commit them (deliberate baseline migrations are the exception). Other specs/_*/ dirs are gitignored.
Conventions
- No hard-wrapped paragraphs in any
.mdfile — one logical line per paragraph. - Comments: default none, one line max, no spec/PR identifiers (
// per PR #182); strip diagnosticconsole.logs before commit. - Verify a backlog issue still reproduces on
mainbefore fixing — queued issues are frequently already fixed or dups. - Design tokens: readable content uses
--text-body/--text-primary;--text-secondary/--text-mutedare below WCAG AA on dark — metadata only (#254). The review hue marks, it does not fill:--reviewis for rules, borders and tints, and every purple word takes--review-ink, which is derived per theme. - Tests: BDD
describe/it; VS Code API mocked atapps/vscode/tests/__mocks__/vscode.ts— extend it there. Known gap: config-dependent webview paths have no config-mock harness. - Run the extension: F5 → Extension Development Host.
- Check in three levels; the whole suite runs once. After each batch of edits,
npx tsc --noEmit -p ./. After a substantial chunk works, only the related tests (npx jest --findRelatedTests <changed files>), in the background. Before the push,npm run test:allonce, in the background.test:visual:ci, the live e2e and the desktop check run before a release, not per feature. Never sit idle on a run, and never wait on CI in the chat (gh pr checks --watch): push and move on. - Edit files with the edit tool, not with a Python or shell script that rewrites them.
The block below is regenerated by the plan command and names the most recent run's plan, which is history — the repo map above is what's current.
<!-- SPECKIT START -->For additional context about technologies to be used, project structure, shell commands, and other important information, read the current plan: specs/618-foundational-wave-fanout/plan.md
<!-- SPECKIT END -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

