Running list of follow-ups, so nothing gets lost between sessions. Open work is ordered by priority (P1 = next build → P6 = gated release); completed work lives in Completed at the bottom. Status: ✅ done · 🔄 in progress · ⬜ todo · 🔒 blocked.
Spec-honesty is now a non-bypassable required check. Next build is P2.
- ✅ Web-scaffold quality tasks (prerequisite).
fmt/fmt:check(Oxfmt) +lint(Oxlint) mise tasks in the web scaffold, scoped toapp/;pnpmpinned in[tools]..oxfmtrc.json+.oxlintrc.jsonmirror the Vite+ reference (tanstack-react-start-contacts): Oxfmt withtabWidth 4/printWidth 100/arrowParens avoid/ perfectionist import sort /sortTailwindcss/sortPackageJson/ jsonc+.vscodeoverrides; Oxlint with type-aware rules +jsPlugins(perfectionist, prefer-let) +import/extensions. Deps:oxlint oxfmt oxlint-tsgolint eslint-plugin-perfectionist eslint-plugin-prefer-let. Green-on-arrival verified for real (oxfmt --check+oxlint+tsgoall exit 0 on a freshly rendered scaffold with the full dep set). - ✅ The gate Action +
ci.yml. Composite actiongate/action.yml(markmals/speckit/gate@v1) + reusable workflow.github/workflows/gate.yml; the scaffold'sgithub/subtree drops a thin-caller.github/workflows/ci.ymlvia the newscaffold.RenderGitHub(skip-existing) wired intotarget add. Two jobs:quality(mise tasks) +verify(the gate; runs the suite, so no double-run). Gate emits CI annotations via the newspecify gate … --format github(mirrorsoxlint --format github). Deviation from the design doc, with rationale: the CI sequence isscan → gate firewall → verify → parity --gate;gate generated/gate scopeare git hooks, not PR checks —verifylegitimately rewrites committed locks on green (ageneratedPR check would false-positive), andscopevalidates a single commit subject. - ✅ Branch-protection recipe — documented
ghruleset fallback in docs/ci-gating.md (required contextsquality+verify / verify, PR required, force-push blocked).specify-native provisioning rides on the gh-extension auth (P2).
Needs a live PR to validate (can't run an Actions runner locally): the mise/pnpm
toolchain setup + trust in CI, the firewall --against base-SHA diff, and the
@v1/go install …@v1 references (dormant until the first release tag, P6).
Fast-follows (richer annotations — captured under P4): line-level firewall annotations
(bindingsInContent is regex-only, no line numbers today); and --format github on
verify/parity so unjoinable scenarios, dangling bindings, and drifted specs also
annotate to file:line — needs the report structs to carry the spec/test file path.
Design: docs/design/github-integration.md.
The pivot's heart. Architecture: a portable spec-integrity core (engine works offline,
never needs GitHub for correctness) + a GitHub-native workflow shell; the engine
projects repo truth onto GitHub. Determinism line: specs/locks/parity/agent-memory
stay in the repo; defects/work/gating are ephemeral on GitHub. The whole GitHub
surface lives in internal/github, imported only by cmd/specify — never by the engine,
so the offline guarantee holds structurally.
- ✅ GitHub foundation + gh-auth inheritance. New
internal/githubpackage: a lean REST + GraphQL client that inheritsgh's token (gh auth token, env fallback) with zero plumbing and contains its own GraphQL queries (the gh-projects approach, our queries — nogo-ghdep, no external extension). Repo auto-detected viagh repo view; no config block.gh ≥ 2.94.0+oppinned inmise.toml(repo + web scaffold). Fully unit-tested (httptest). Deferred to release (P6): the actualgh extension install markmals/specifydistribution (running asgh specify) — the binary + commands are ready; only the release-tagged install path is dormant. - ✅ Pillar 2 — Issues as ephemeral defect intake.
specify issues list|create|close(confirmation-gated,--json); thegithub/scaffold subtree now drops the full per-target.github/(PULL_REQUEST_TEMPLATE.md,ISSUE_TEMPLATE/defect.ymlstampingtype: Bug+ label fallback,config.yml,CODEOWNERSfor/features/specs). Dependency updates moved off Dependabot to a single repo-global Renovate gate wired into the mise-monorepo root (mise run deps/check,renovate.json+scripts/deps-check.sh; advisory dry-run, never opens PRs — one ecosystem-agnostic gate for all members). No durable issue↔scenario link (GitHub cross-refs). Close-on-green is the discipline. - ✅ Pillar 3 — Projects board (Beads-informed).
specify work ready|claim|move|discoveron the inlined Projects v2 GraphQL client (resolve project/fields/options, add item, set single-select, list items, atomic self-claim,discovered-fromlabel + #N backlink). "ready" is a Status column (a--columnflag, not a computed field). Column names are flags that default to the confirmedAPL-Innovation-Lab/projects/1set — Backlog → Ready → In Progress → On Hold → Cancelled → Closed (actionable = Ready; "On Hold" is the blocked signal, skipped for free sincereadylists only the actionable column). 🔄 Remaining (minor):blocked-by/epics (sub-issue) helpers exist in the client but have no dedicatedworksubcommand yet. - ✅ Agent memory (per-agent
memory/).MemoryDir()on the adapter →.claude/memory/·.agents/memory/·.github/memory/;initseedsMEMORY.md(skip-if-exists, so re-init never clobbers), wires loading (Claude@import; AGENTS.md/copilot directive), ships themanaging-memoryskill. Engine ignores it. Goldens updated; dogfooded → this repo's.claude/memory/+ a rootCLAUDE.md. Design: docs/design/agent-memory.md. - ✅ Deploy workflows (optional, none required).
specify deploy add <kind> [target]rendersdeploy.ymlforcloudflare-workers-ssr/cloudflare-workers-spa/railway/github-pages-spa(templates use[[ ]]delims so${{ }}survives) and records the per-target manifest. Per-target (decided). (init --deploysugar still TODO.) - ✅ Secrets via 1Password (
op). Manifest holds onlyop://references (validated; raw values rejected atdeploy add+scan).specify secrets syncresolves via localopand pipes intogh secret set(CI) +wrangler secret put(cloudflare runtime, via stdin — never argv/log); railway runtime via argv (CLI limitation, noted).--dry-runprints the plan without resolving. Default =gh secret setsync (decided); runtime-load via1password/load-secrets-actionremains a documented upgrade. - ✅ Branch-protection provisioning (
specify protect). Codifies thedocs/ci-gating.mdruleset (requirequality+verify / verify, require a PR, block force-push) via the GitHub API; re-runnable (updates an existing same-named ruleset in place).
Resolved open decisions (from the design doc): no github config block (auto-detect via
gh); GitHub commands un-namespaced; deploy is per-target; default secret mode is the
gh secret set sync; memory frontmatter is optional; the Pillar 3 column set is
confirmed (Backlog → Ready → In Progress → On Hold → Cancelled → Closed, actionable =
Ready) and baked in as specify work's defaults.
- 🔄 Web scaffold — flesh out to the full default. Approach: prototype-first / resolve-by-running
(build the real app green, then templatize), grounded in inspecting the reference apps (trove ·
tangerine-dashboard · contacts main+convex). Engine decision: plain Vite + oxc + Mise (not
vite-plus), confirmed with Mark — matches scaffolds/web.md.
- ✅ Slice 1 — default app, green-on-arrival (verified for real). TanStack Start SSR +
Router (virtual file routes,
app/routes.ts→routes.gen.tsviatsr generate) + Query; React 19 + React Compiler (@rolldown/plugin-babel+reactCompilerPreset()); Tailwind v4; the React-Aria +cva+ Motion foundation recipe (app/components/foundation/); Zod;#/*subpath imports; Mise tasks (dev/test/build/fmt:check/lint/typecheck +routescodegen,mise truston install); the binding harness preserved. Freshspecify target add web→verifygreen +fmt:check/lint/typecheck/buildall pass. - 🔄 Slice 2 —
--datalayers. Scaffold-manifestdatavariants + a--dataflag (scaffold.RenderDataoverwrites shared base files likerouter.tsx; per-variant deps + codegen scripts phase-ordered after the base install).- ✅
--data convex(the default) +--data none, both green-on-arrival, verified for real. Convex is green offline via an anonymous local deployment —CONVEX_AGENT_MODE=anonymous pnpm exec convex dev --oncegeneratesconvex/_generated/with no account/login;pnpm-workspace.yaml dangerouslyAllowAllBuildsclears pnpm 11's native-build gate. Client/provider wiring from the contacts@convex delta. - ⬜
--data drizzle(D1) — folds into the Cloudflare runtime slice below (D1 is reached viacloudflare:workers, so it needs that runtime).
- ✅
- ✅ Slice 3 — runtime axis + Drizzle+D1. A
--runtimeflag + a generalized variant mechanism (scaffold.Variant,RenderVariant, cross-axisrequiresRuntime). Cloudflare SSR is the default (per web.md):@cloudflare/vite-plugin+cloudflare()+wrangler.jsonc+wrangler typescodegen;--runtime nodeis the lighter (no-Cloudflare) variant.--data drizzleis runtime-adaptive (drizzle-orm@rc): aVariant.RuntimeFilesoverlay ships the D1 db module +d1_databasesbinding on--runtime cloudflareand thenode:sqliteadapter (drizzle-orm/node-sqlite) on--runtime node— sharedschema/drizzle.config+drizzle-kit generate. All of{cloudflare,node}×{convex,drizzle,none}verified green-on-arrival. ⬜ Deferred: the--ssr/--serverspa/static modes (refs are all SSR). - ✅ Slice 4 —
--with clerk. The--withFeature mechanism now carries deps + scripts (parallel to Variant), and features render LAST. Clerk feature (from tangerine): adds@clerk/tanstack-react-start,app/start.ts(clerkMiddleware), and wrapsroot.tsxwithClerkProvider. Green-on-arrival without live keys (typecheck + build pass; auth resolves at runtime). - ✅ Slice 4b —
--with tiptap. A purely additive feature (the first non-provider one): adds@tiptap/react/@tiptap/starter-kit/@tiptap/pm(v3) + anapp/components/foundation/editor.tsxRichTextEditor(StarterKit,immediatelyRender: falsefor SSR, cva/Tailwind-styled). Overwrites no shared file, so it composes with clerk and any data/runtime variant — render-tested + green-on-arrival verified for real (fmt:check/lint/typecheck/test/build +specify verifyall pass on a freshtarget add web --with tiptap). - ✅ Slice 4c — provider composition seam +
--with posthog. Resolves the provider-stacking fork (Mark's call: use TanStack Router'sWrap). A new baseapp/providers.tsx(a Go template) is the single place client-side providers compose, via an accumulator (tree = <X>{tree}</X>) gated by{{if .Features.<name>}}; both the base and the convexrouter.tsxdelegate theirWrapto<Providers>. So providers stack deterministically without fighting over a shared file — clerk (root.tsx) is orthogonal and composes for free. posthog is the first provider:add: posthog-js- a conditional
PostHogProviderblock (apiKey form, SSR-safe, env viaVITE_PUBLIC_POSTHOG_KEY/_HOST); it carries no files (the wiring lives in the base seam). Also fixed: a basepnpm-workspace.yaml(dangerouslyAllowAllBuilds) so node+none can add build-script deps (posthog → core-js) — previously the one combo without it. Verified green-on-arrival for real across 6 combos: node×{none,convex}×{±posthog}, cloudflare+convex (default), and node+none+clerk+posthog (both providers wired at once).
- a conditional
- ✅ Slice 4d —
--with email(Resend + React Email). Additive: shipsapp/emails/welcome.tsx(a React Email template) +app/server/send-email.tsx(a server-only Resend send helper, key viaprocess.env.RESEND_API_KEY), overwriting no shared file. Depsresend+react-email(v6) +@react-email/render— note the standalone@react-email/componentsis EOL/deprecated; v6 consolidated the components into thereact-emailumbrella (clean, zero deprecated transitives). Green-on-arrival verified for real (fmt:check/lint/typecheck/test/build +specify verify).⚠️ resendis a Node SDK; on the Cloudflare Workers runtime a user wiring the helper into a Worker may need node-compat (the helper is additive/unimported, so the scaffold itself stays green). - ✅ Slice 4e —
--with stripe. Additive: shipsapp/server/stripe.ts(a server-only Stripe client +createCheckoutSessionhelper, key viaprocess.env.STRIPE_SECRET_KEY) +app/lib/stripe.ts(a clientloadStripeviaVITE_STRIPE_PUBLISHABLE_KEY), overwriting no shared file. Depsstripe+@stripe/stripe-js(Stripe SDK 22 makesapiVersionoptional). Green-on-arrival verified for real (fmt:check/lint/typecheck/test/build +specify verify). Same Workers caveat as email (Node SDK; additive/unimported so the scaffold stays green). - ⬜ Remaining
--withadd-ons: sentry (now unblocked: client provider rides the sameWrap/providers.tsxseam; note it also adds a vite plugin, which touchesvite.config.ts— the runtime axis — so handle that overlap), then tanstack-db (intersects the--dataaxis) / electron (a bigger shell change). - ✅ Slice 4f — foundation extras (trove parity). Added
lucide-react(icons) +tw-animate-css(animation utilities) to the base web foundation — both actually used in trove. tailwind.css imports tw-animate-css; the example route exercises a lucide icon (so neither is a dead dep). Green-on-arrival verified. (Deferred@clerk/themes: would be a dead dep without an opinionated theme choice.) - ✅ Replaced the hand-rolled foundation with racket-ui via the official shadcn CLI. racket-ui
(
github.com/markmals/racket-ui) is a shadcn/ui-compatible registry on React Aria + Tailwind v4 + cva + Tabler. Templatized shadcn-native:@/*→member-root via tsconfigpaths+ Vite 8resolve.tsconfigPaths;components/ui+lib/cva.tsat root,app/for routes/entry/globals.css;import/extensions: off; a newcomponents.jsonwith the@racket-uiregistries map (per-item GitHub raw); phase-0shadcn add @racket-ui/base @racket-ui/button; foundation +styles/cva.ts+tailwind.cssremoved; lucide→Tabler;#/·#db→@/·@/db; tiptap editor →app/components/editor.tsx. Precondition (the real blocker, not just the missingregistry.json): racket-ui's per-item distributionpublic/r/*.jsonwas gitignored, so the namespaced@racket-ui/cvadep 404'd — fixed + merged in racket-ui#1. Verified green-on-arrival for real across node+none, cf+convex (default), cf+drizzle, node+drizzle, and node+clerk+posthog+tiptap+email+stripe (fmt:check/lint/typecheck/test/build +specify verify). Recipe + gotchas in.claude/memory/rac-ui-shadcn.md. (Superseded Slice 4f's lucide; tw-animate-css stays — racket-ui's globals imports it.) - ✅ Slice 5 —
.vscode+ pack refresh (Varlock deferred). Ships.vscode/{settings,extensions}.jsonin the base scaffold (adapted from trove): oxc as the formatter + lint/fix-on-save, tsgo as the type checker (useTsgo+ the native-preview tsdk), Tailwind IntelliSense forcva/cx, and recommended extensions (oxc · tailwindcss · native-preview · todo-highlight). web-development pack refreshed to rac-ui (the stack table + the "UI components come from rac-ui via shadcn" idiom; dropped the Tailwind Plus reference). Varlock deferred — the reference apps don't wire it; env stays Vite-native.env.local(design doc updated)..vscodeis inert to the build (outsideapp/); render-tested + a full combo stays green.
- ✅ Slice 1 — default app, green-on-arrival (verified for real). TanStack Start SSR +
Router (virtual file routes,
- ⬜ Library / non-app coverage — add a product
kind: app | library(relax the "actor is human" rule for libraries;story+domain+errorapply, UI kinds don't) and the stacksswift-package,swift-cli,npm-package,vscode-extension. Engine unchanged (joins scenario↔test regardless). Design: library-products.md. Roster is evidence-based (web · website · apple · android · go-cli · node-cli · swift-package · swift-cli · npm-package · vscode-extension; dropped rust-cli/windows/linux/browser-extension).npm-packageshipped 2026-06-27 — the node-family single-TS-library stack (tsdown + Vitest junit + scoped bindings), the node twin ofswift-package. - ✅
go-servicescaffold (Tier-2 structural, trove's daemon). A new stack: a runnable Go HTTP daemon (net/http ServeMux + graceful shutdown + a scenario-bound httptest) that's green-on-arrival via the Tier-1 gotest format + Go leading-comment bindings + scoped mode (dogfoods Tier 1:verify→ 2 passed · 1 locked · drift clean). Introduces stack-aware member placement (the manifest'smemberDir):target add … --stack go-servicelands incmd/<name>(web staysapps/), the first piece of incremental member-add (Mark's monorepo call). Also plumbedtarget.bindingsmanifest→config.- ✅ Shared root
go.mod(monorepo composition) (shipped via #27). go-service is nowsharedModule: members compose into ONE repo-rootgo.mod(each acmd/<name>sharinginternal/, trove's shape) instead of a self-contained module per member.target addcreates the rootgo.modif the repo isn't a module yet (module path from the git origin remote →host/owner/repo, else the dir base name) and a second member just joins it; members render nogo.modof their own. Verified: two members compose,go build ./...sees both, eachverifygreen. (scaffold.SharedModule+cmd/specifyensureRootGoMod/deriveModulePath.) - ✅
--with openapi(contract-first via oapi-codegen) (shipped via #27). troved's defining pattern: the feature overwritesmain.go/greeting.go/greeting_test.gowith the strict-server wiring, shipsopenapi.yaml(the contract, with anx-spectrace) +oapi-codegen.yaml, and adds phase-ordered install scripts (go getthe runtime + theoapi-codegentool directive → generateinternal/api/api.gen.go→go mod tidy). Members import the generated package by full module path (needsData.Module=resolveModulePath). A conditionalmise run generatetask regenerates from the contract. Verified green-on-arrival:target add … --with openapi→go build/fmt:check/vet/testspecify verify(2 passed · 1 locked), module path from the git remote. (Also fixed: the default basemain.goshipped a literal unrendered{{kebab .Name}}in its package comment.)
- ✅
--with sqlite(store + migrations + flag/env config) (shipped via #27). Additive (like the web email/stripe features — overwrites no shared file, so it composes with the base AND--with openapi): ships a member-privateinternal/storepackage (pure-Go glebarez SQLite — busy_timeout + single conn; embeddedmigrations/*.sqlapplied once via a_migrationstable; a settings KV + a roundtrip test) and aconfig.goflag/env helper (loadConfigwithenvStr/envIntfallbacks). Feature files are.tmpl(so speckit'sgo build ./...doesn't compile them — they import glebarez); deps via ago getscript, tidied by the base phase-5go mod tidy. Verified green-on-arrival: base+sqlite AND openapi+sqlite (17 files, both deps) →go build/fmt:check/vet/specify verify(2 passed · 1 locked; the untagged store test runs + passes, out of scenario scope underbindings: scoped). - ✅
--with client(external-service client + httptest idiom) (shipped via #27). Additive, pure stdlib (no deps/scripts): a member-privateinternal/servicespackage — trove's pattern — with a boundedhttp.Client(DefaultTimeout), aGetJSONhelper, a typedAPIErrorfor non-2xx,SanitizeURLError(strips the*url.ErrorURL so a key in a query string never logs), an exampleClient(project only consumed fields), and afakeServer(t, routes)httptest harness + tests. Plain.go(no template vars), so speckit's owngo build/go testcompile + run it (free validation). Verified green-on-arrival: base+client AND the full openapi+sqlite+client stack (internal/{api,services,store}) →go build/fmt:check/vet/test/specify verify(2 passed · 1 locked) all green. - ✅ trove-parity series complete — all four bundles (root
go.mod· openapi · sqlite · client) compose into one troved-shaped green-on-arrival service. ⬜ Still later: pnpm-workspace membership + repo-rootinternal/sharing land with the broader monorepo slice; the protocolx-speccoverage reader.
- ✅ Shared root
- 🟡 Per-stack scaffold builds — apple in progress (scaffolds/apple.md):
- ✅ Slice 1 — headless Core harness —
specify target add <name> --stack applerenders a self-contained SwiftPM package (apps/<name>/Core, a@Observableview-model + a pure domain type), theSpecTraits.swiftbinding harness, an example bound story, and theswift-format target wiring (swift test --event-stream-output-path … --event-stream-version 0). Verify target is the headless Core — no Tuist, Xcode project, simulator, or signing — so it's green-on-arrival with only the Xcode Swift toolchain. Verified end-to-end on a Mac:scanclean ·verify(2 passed · 1 locked) ·swift build·swift format lint --strictall green. The.scenario()trait is the canonical binding (decided 2026-06-14); the engine'sswiftBindRe+ event-stream parser already join it. Swift files are.tmplonly for substitution (speckit's Go CI never compiles them — the inverse of the go-service rule). - ✅ Slice 2 — Tuist app surface —
Project.swift(macOS AppKit.app+ unit-test target, signing off,bundleId com.example.<name>) +macOS/{Info.plist,Sources/App,Tests}(programmatic@maindelegate + a window controller reading the Core's@Observablemodel), misegenerate/build/launch:macos/test:app(Tuist pinned). Verify still points at Core; the app build is a Mac-only secondary. Proven on macOS:mise run build(BUILD SUCCEEDED) ·test:app(passed) ·verifygreen · lint clean. Gotchas: Tuist anchors on the repo.gitroot; the Core needs a.libraryproduct for the app to consume; a silent post-renderswift formatpass normalizes the name-dependentAppKit/<Name>Coreimport order. - 🟡 Slice 3 —
--withfeatures (go-service-shaped):swiftdata✅ — a<Name>Persistencetarget (SwiftData@Model+ a store mapping the domainTodo, strict-memory-safety off) + a bound persistence test (headless temp-file reopen).--with swiftdata→ verify 3 passed · 1 locked + app build + lint, base unaffected. Established two patterns: thePackage.swiftcomposition seam ({{if .Features.x}}blocks; features ship only additive files) and one test target (swift test --event-stream-output-pathclobbers across multiple test targets → feature tests live inCoreTests; the.spec/.scenariotraits moved to a sharedTestSupporttarget).openapi✅ —--with openapi: a contract-first<Name>APItarget via the Swift OpenAPI Generator build-tool plugin (codegen at build time) + a publicTodoAPIClientfacade + a fake-ClientTransporttest (offline-verifiable).--with openapi→ verify 3 passed;--with swiftdata --with openapi→ 4 passed + app build. (Seam gotcha: SPM needsdependenciesafterproducts.)dist✅ as a deploy kind —app-store-connect(specify deploy add app-store-connect): a macOS release workflow (xcodebuild archive/-exportArchive→ TestFlight/App Store on av*tag) + ASC-API-key/cert secrets as op:// refs; release belongs at root.github/, which--withcan't reach.push(APNs) deferred — mostly config, thin testable kernel, gourmand (local app) has no server. Slice 3's verifiable + gourmand-relevant features (swiftdata, openapi) + dist done. - ✅ Slice 4 — the apple stack pack — the
applepack (templates/packs/apple/) gains the AppKit skill suite adapted from mac-dev-skills (Mark's own, MIT): 14 conciseSKILL.md(appkit-design flagship + setup/dev-workflow/hig/code-review/ui-testing/packaging/migration/private-apis/app-inspector/modern-input/ launch-continuity/liquid-glass/session-report) beside the existing ios-development + ios-simulator-control (16 total). Projects viatarget add --stack apple/specify packs. Zero Go changes (directory-driven), zero golden drift (packs aren't ininit);TestProjectPacksasserts the suite. Adapted not vendored (point at first-party docs + sdk-api/sdk-search; no HIG dump / tool binaries). No agent + no MCP projection (the agent's grounding mandate folds into appkit-design; Xcode MCP stays per-machine, documented in-skill). ✅ Pack auto-projection fixed (all stacks):specify init --integration <agent>now seedsagentin.speckit/specs.json(viaconfig.SetAgent, called fromproject.Init), sotarget add/packsproject the pack without hand-editing;AddTargetpreserves it. Golden trees gained.speckit/specs.json;TestInitRecordsAgentcovers it. - ✅ Pack DEPTH + agent + offline HIG (2026-06-15) — rescued the stranded enhanced-pack work
(whole-directory pack projection + deep references).
loadPack/ProjectPacksnow project a skill's whole directory (SKILL.md +references/), keyed by relpath; three appkit skills gained hand-written deep references (app-inspector·design·private-apis, 19 files). Reverses two earlier Slice-4 calls (Mark's call): packs may now carry a per-stack agent (agents/appkit-dev.md→ the adapter'sAgentsDir(), Claude-only; codex/generic/copilot skip it), andapple-hig(wasappkit-hig) bundles the complete offline Apple HIG (~172 md, 2.4MB, snapshot 2026-06-10) — embeds into the binary (pack ≈2.9MB).loadPackkeeps the packless-stack handling;TestProjectPackscovers references + agent + packless; binary e2e green (specify packs→ 208 files, agent + HIG corpus land). The generated AppKit slice is checked against an externalmac-dev-skillscheckout byscripts/generate-apple-pack.sh --checkin CI; do not hand-edit the generated AppKit pack copy. Deferred follow-ups: deepening the other ~11 appkit skills withreferences/. - ✅
swift-package/swift-cli(apple-platform-tools' shape) — two sibling library stacks (memberDir: packages, swift event-stream format, scoped bindings) that reuse Slice 1's headless harness (theSpecTraits.spec/.scenariotraits + the event-stream test task) with zero engine changes.swift-packageis a flat reusable library (module named after the member over a staticSources/Libraryviapath:; example: a pureSemanticVersion).swift-cliis a library Core + a thin swift-argument-parser executable shell (<Name>CoreoverSources/Core+ a<name>executableTarget overSources/CLI; the behaviour is proven through the library soswift testverifies it headlessly — no binary run). Both proven green-on-arrival on a Mac:swift build·swift test·swift format lint --strict·specify verify(2 passed · 1 locked), and the swift-cli binary runs (greet-tool Ada --shout→HELLO, ADA!). Render-tested in Go CI (internal/scaffold/swift_{package,cli}_test.go). Also fixed: a packless valid stack no longer breaksspecify packs—loadPacktreats a missing pack dir as "no pack" for a real scaffold (still errors on a genuinely unknown stack). No pack/MCP/features for these (factor later if needed). - Then the rest one at a time, each gated on a tooling preview. node-cli already spec'd (scaffolds/node-cli.md).
- ✅ Slice 1 — headless Core harness —
- ⬜ Feature-folder templates (minor) —
NARRATIVE/story/model/view-model/error templates under.speckit/templates/feature/so the commands scaffold faster (today they point atspecs/CONVENTIONS.md, which works).
- 🔄 Trove adoption — Tier 1 (engine readiness, in review). Makes the engine able to scan +
verify a real Workbench-shaped repo (trove, the first conversion). Validated end-to-end against
~/Developer/Projects/trove:scanclean (was 46 findings),verifyjoins trove's Go bindings (4 scenarios passed, 0 dangling/unbound, 2 honestly unjoinable cross-target). Changes:protocolkind — a contract kind (protocol.<producer>.<op>, dirspecs/protocol/, no scenarios) ininternal/specmodel; cleared trove's 17 I2s. Thex-spec/OpenAPI binding reader for protocol coverage stays deferred (Tier-1 leaves protocol specs scanning clean + drift-tracked).- Filename rule accepts both the id-tail stem (
engine.scan.md) and the full-id stem (story.engine.scan.md) — cleared trove's 29 I1s; backward-compatible. - Scenario headings at any level —
parseScenariosnow also reads nested### Scenario N:under## Acceptance Criteria(trove's form; an audit miss — bindings were dangling until this). - Go + generic
// [scenario.id]binding reader —.goadded tosourceExts; a line-oriented leading-comment reader binds the tag to the nextfunc Test…(Go) orit/test(…)title (TS). gotestreport format — parsesgo test -json(top-level funcs; subtests rolled up; skips omitted).bindings: scoped(decision-for-mark) — opt-in per-target relaxation so a partially-bound suite (untagged unit tests) verifies what it does bind; default staysstrict(untagged = unbound D12 violation), so the scaffold + SpecKit's own repo are unchanged.⚠️ This softens the documented "every untagged test is a hard error" philosophy only when opted in — confirm the name/shape. ⬜ Tier-1 follow-ups: protocolx-speccoverage reader (still deferred). ✅ go-service stack/scaffold (shipped, with the trove-parity feature set). ✅ onboarding an existing repo —specify target register <name> --stack <s>records an existing member as a target in.speckit/specs.jsonwithout scaffolding/installing (seeds the wiring from the stack's scaffold manifest when it has one — web, go-service — else takes--format/--command/--report/--source/--bindingsflags; flags override manifest defaults). Smoke-tested on real trove: registeredtroved(go-service) + a TS package,scanclean. The next step (converting trove) is the target decomposition — which scenarios/tests scope to which target (trove's bound tests spancmd/troved+internal/), reconciling scenario ids, and the per-member wiring — plus the deferred protocolx-specreader + product-rollup render.
- ✅ Richer CI annotations (P1 fast-follow).
--format githubnow extends past the firewall:verifyannotates unjoinable scenarios at their spec line + dangling bindings at the test line;parityannotates each non-conforming cell at its spec line; the firewall points at the exactit(...)/@Testline.bindingsInContentcarries file+line,specmodel.Scenariocarries its line, andengine.SpecLocationsmaps scenarios → spec file:line. The gate action runsverify/parity --format github. (Verified: a repro with an unjoinable scenario + a dangling binding emits the expected::error file=…,line=…::.) - 🔄 Scanner — multi-framework bindings. ✅ generic
// [scenario.id]leading comment (Go + JS/TS) shipped with Tier 1. ⬜ Still unread: MSTest[TestProperty("scenario", …)], kotlin@Tag("scenario:…"). (Today: Swift traits, Vitest titles, and the leading-comment form.) - ⬜ Product-rollup render —
cover/paritygrouping + per-product verdict.ProductTargets()exists; lands with the multi-target slice. - ⬜ triaging-defects skill — reframe around GitHub Issues (Pillar 2 supersedes the old
DEFECTS.md-ledger blocker): triage an issue → scenario/regression test → close on green. - ⬜ Hooks (claude-pack overlay) —
format-on-edit,spec-reconcile,stop-lint,notify-long-task,user-prompt-context+ codegen hooks (convex/openapi/tuist).gatealready mechanizes the enforcement ones (firewall/generated/scope) — decide which hooks remain vs. folded intogate. - ⬜ codex/copilot review subagents — equivalents to the claude-pack reviewers; their delegation models differ from Claude's dispatch (open question).
- ⬜ VS Code extension — codelens on
// SPEC:(jump scenario ↔ bound test), drift gutter, a parity tree, run the gate, a board view. The developer-native complement to the CLI.
- ✅ Harness & usage guides (
docs/). Shipped the onboarding surface, linked from the README's new Guides section. Both axes, fact-checked against theinternal/projectadapters + the golden init manifests (the source of truth, kept in lockstep):- Per harness —
docs/harnesses/{claude,codex,generic,copilot}.md: whatinitprojects for each agent (exact paths for commands/skills/rules/subagents/memory/+ the orientation file and its loading mechanism), how the/speckit.*commands are invoked there, and the per-agent differences (Claude: user-invocable skills + the 5 review subagents +CLAUDE.mdnative@import; Codex/Generic: the shared.agents/+AGENTS.mdread-at-start projection, byte-identical to each other, no subagents; Copilot: dual.github/agents+.promptscommand projection under.github/). - With vs. without GitHub —
docs/usage/offline.md(the engine alone:scan/verify/lock/drift/cover/parity/gate+ git hooks, determinism line as the spine, nogh/network) anddocs/usage/github.md(the optional shell: PR gate +protect, Issues/taskstoissues, theworkboard,deploy/secrets— every command marked optional). Reflects the shipped P2 surface.
- Per harness —
- ⬜ Decision — historical-doc vocab.
FORK.md/FORK-PLAN.mdstill use engine-keyplatform(~100× in FORK-PLAN) as dated planning records. Migrate totarget, or leave as pinned artifacts? (Untouched for now.) - ⬜ Decision —
init --platforms/extension addvstarget add --stack. Thefeatures/0002-initextension stories spec a surface that overlaps the shippedtarget add+packs. Reconcile, or relabel as a deferred Phase-4 design. - ⬜ Legacy whole-file templates.
plan-template.md/tasks-template.md/checklist-template.mdstill use the upstreamspec.md/plan.md/tasks.mdmodel + unrendered__SPECKIT_COMMAND_*__tokens — at odds with the feature-folder model. - ⬜
render.goPLATFORM header — the cover/parity/gate state table prints aPLATFORMcolumn; rename toTARGET. - ⬜ Discussions (maybe) — spec RFCs before they're committed. Take it or leave it. Not pursuing: GitHub MCP toolset, GitHub Agentic Workflows.
- ⬜ The first release (
v0.1.0tag) activates brew + mise. On tag: goreleaser publishes archives and dispatchesspecify-releaseto the tap; the tap bumps + bottles. Checklist inpackaging/homebrew/README.md. Do not tag or push to the tap without confirmation.
- ✅ Engine & config —
.speckit/specs.json(plain JSON: version/agent/paths/targets, verify wiring inline); the engine keys on target (platform→targetrename through code, specs, and docs);scanvalidates the config. The full engine (scan/verify/lock/drift/cover/parity/gate) andinitare implemented + tested. - ✅ Commands & skills — all 9
/speckit.*commands reworked to the fork's reality (.speckit/, thespecifyengine, no scripts) synthesizing Workbench discipline + spec-kit rigor; 7 universal process/authoring skills + 13 platform-pack skills ported and wired to the commands; the feature-folder data model (features/<NNNN>/…, scenario sub-IDs,// SPEC:pointers) resolved as canonical. - ✅ Rules pack —
code-quality·commit-discipline·spec-conventions·enforcement-hierarchyported from Workbench to the fork's reality (target,specify gate/verify, the engine mechanizes the sync invariants) and projected byinitinto each agent's rules dir (.claude/rules/·.agents/rules/·.github/rules/), referenced from the orientation file (@importfor Claude; a directive for AGENTS.md / copilot-instructions.md). - ✅ Subagents (claude-pack) —
spec-reviewer·test-gap-finder·drift-hunter·handoff-builder·visual-verifierported and projected into.claude/agents/. - ✅ Stack scaffolding (machinery + web) — Part A (
config.AddTarget/Save, theinternal/scaffoldtext/template renderer,specify target add … --stack); Part B (the web scaffold green end-to-end:target add web→pnpm add→mise run test→verifygreen + locked); the create-sprinkles resolve-by-running alignment (phasedscripts,pnpm addpins versions, no hardcoded"latest"); tsgo fix (@typescript/native-preview+tsgotypecheck task). web + node-cli stacks spec'd. - ✅ Distribution — Homebrew from-source bottling (
specify.rb+ tap auto-bump + cross-repo dispatch); deploy gated on the first release (P6). - ✅ Docs & design — repo-wide prose currency sweep (
platform→target, de-upstreamed the inherited GitHub community files, removed dead upstream.github/config);spec-driven.mdrewritten to the fork's model; design docs landed for GitHub integration, agent memory, stack scaffolding, and library products; mise task naming convention set to colons (fmt:check).