BYOA refactor: fingerprint.md + deterministic primitives + ghost-drift skill#35
Merged
nahiyankhan merged 24 commits intomainfrom Apr 20, 2026
Merged
BYOA refactor: fingerprint.md + deterministic primitives + ghost-drift skill#35nahiyankhan merged 24 commits intomainfrom
nahiyankhan merged 24 commits intomainfrom
Conversation
Introduces a Markdown+YAML fingerprint file (expression.md) with a new Values layer (Do/Don'ts) cited by ghost review. Legacy .ghost-fingerprint.json still reads with a deprecation warning; CLI, action, and parent resolution all route through loadExpression(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Positions Ghost as pipeline infrastructure for AI UI generation: expression.md grounds the generator, ghost review gates the output. - `ghost context` emits SKILL.md / prompt.md / full bundle from an expression for grounding any downstream generator. - `ghost generate` is the reference generator — loads expression, prompts the LLM, extracts HTML, self-reviews via ghost review, and retries with drift feedback (cap 3). - `ghost verify` runs generate→review across a bundled 18-prompt standard suite, aggregates per-dimension drift (tight/leaky/ uncaptured) and recommends where the expression under-specifies. Each three-layer expression layer now has a concrete job in the loop: Character→prompt, Signature→score, Decisions→lookup, Values→hard gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dev pages (ghost-ui) and the root README still reflected the pre-expression pipeline — no comply/discover/review/context/generate/verify, --emit writing .ghost-fingerprint.json, scan-first getting-started flow. - CLI reference: all 15 commands grouped by Profiling / Comparison & Compliance / Generation Loop / Evolution & Intent / Visualization - Getting Started: zero-config profile → expression.md → review/compare/comply flow up front, config-driven scan moved to Advanced - Concepts: added Generation Loop chapter, updated artifact grid to expression.md, retitled closing to "Fingerprint. Ground. Review. Repeat." - Docs index + self-hosting: updated copy and connect-to-Ghost flow - README: three-layer fingerprint section, generation-loop diagram, updated commands table, corrected package layout (cac, new command files, ghost-review skill, docs/) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make the YAML frontmatter the single source of truth for every fingerprint field — the body becomes a human-readable mirror rendered by the writer and parsed only for diagnostic use. Gets rid of three conflicting precedence rules across summary/traits/decisions/values, and makes the spec's "frontmatter alone is enough for deterministic tools" claim actually true. Contract changes (schema 1 files rejected, regenerate required): - parseExpression reads every field from frontmatter; body never merges in - writer emits all narrative fields (observation, decisions, values) to YAML - `values` added to FINGERPRINT_KEYS so it round-trips via frontmatter - `source: "unknown"` replaces silent "llm" default; type union extended - loadExpression returns ParsedExpression (fingerprint + meta + body) - EXPRESSION_SCHEMA_VERSION = 2 enforced on read with regenerate hint - Zod FrontmatterSchema validates shape with field-path errors - Line-oriented frontmatter scanner replaces regex (robust against hrules) - `# Observation` prose and `# Prompt guide` parsing paths removed New capabilities: - `ghost lint [path]` — schema validity, body/frontmatter sync, broken evidence citations, unused palette colors; --strict / --off rule controls - `ghost expr-diff <a> <b>` — semantic diff over decisions (by dimension), values, palette (by role), scalar tokens; complements vector `compare` - `extends:` composition — child inherits from parent, decisions merged by dimension, palette by role; cycles detected; noExtends escape hatch - `decisions/*.md` fragment auto-assembly — large systems can split rules across files, merged by dimension at load time - schemas/expression.schema.json published for IDE autocomplete - toJsonSchema() exported for consumers; regenerate via scripts/ Context bundle API: - `--format skill|prompt|bundle` replaced with `--no-tokens` / `--readme` / `--prompt-only` flags; legacy format still honored one release - tokens.css emitted by default with generator/source/timestamp header Tests: 166 passing (from 133). New coverage for frontmatter authority, schema gate, zod validation, body-sync lint, evidence citation lint, semantic diff, extends composition (incl. cycles), decision fragments, frontmatter scanner robustness against body hrules. Docs: docs/expression-format.md rewritten to match shipped reality — removes false "body wins" and "frontmatter-alone round-trip" claims, documents extends/fragments/lint/diff, drops cut sections. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ata bag Splits the 49-dim vector out of the root frontmatter into a sibling `embedding.md` fragment referenced by ordinary markdown links in the body — the same progressive-disclosure model agent skills use. The index stays thin; the vector is cacheable but optional, recomputed from the structural blocks when missing. Also introduces a loose `metadata:` passthrough bag so LLMs can append novel observations (e.g. `tone: magazine`) without a schema bump, while the structural blocks (palette/spacing/typography/surfaces) stay `.strict()`. Loader resolution for embedding: inline frontmatter → body link → conventional sibling → recompute via computeEmbedding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce a `roles[]` field on `DesignFingerprint` — the bridge from
abstract tokens to renderable output. A role names a semantic slot
("h1", "card", "button", "list-row") and binds tokens from the
existing dimensions (typography, spacing, surfaces, palette). This
closes the gap where fingerprints described which values *exist*
without saying *where they go*, which is the information a renderer
needs to treat an expression as generative input.
Roles live in the frontmatter alongside other machine-facts. Each
token sub-block is zod `.strict()` — unknown keys reject, keeping the
schema disciplined as it grows. The fingerprint agent's three-layer
prompt now carries a Layer 4 asking it to read component files and
emit slot bindings with evidence.
`extends:` composition merges roles by `name` (child wins per-slot,
parent-only roles preserved), mirroring how decisions and palette
roles already merge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce `ghost emit` and the underlying `emitReviewCommand` stage: a deterministic generator that reads an `expression.md` and writes a project-fitted design-review slash command (Markdown, ready to drop into `.claude/commands/design-review.md`). The generator is pure over the fingerprint — same expression, same output. Scope is drift-only: off-palette hex, off-ramp spacing, non-canonical radii and weights. Accessibility and universal review live elsewhere. Output is styled after the Rams `/rams` command: role prompt, per-dimension rule tables derived from this system's actual tokens, output template, and guidelines. Wires: - `emitReviewCommand` stage + `EmitReviewInput` exported from core - `registerEmitCommand` hooked into the CLI Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collapse overlapping verbs into unified commands, keeping library APIs stable so the GitHub Action and @ghost/core consumers are unaffected. - `compare` now handles pairwise, fleet (N≥3 or --cluster), --semantic, --temporal, and --components (local vs registry). Subsumes the former `fleet`, `expr-diff`, and `diff` verbs. - `review` now dispatches on scope (files | project | suite) from the first positional. Subsumes the former `comply` and `verify` verbs. - `emit` now handles `review-command` and `context-bundle` kinds. Subsumes the former `context` verb. - Delete legacy `scan` command + scan-only reporters (formatCLIReport, formatJSONReport) + orphaned types (DriftReport, DriftSummary, DesignSystemReport). - Drop `--emit-legacy` flag from profile and the corresponding emitFormat option from ProfileOptions. Legacy .ghost-fingerprint.json stays read-only — writing it is no longer supported. No deprecation aliases: hard break consistent with pre-1.0 iteration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Concepts page still framed drift detection around the deleted `scan` verb
and used merged command names in the generation loop grid.
- Retitle Chapter 3 "The Scan" → "The Review". Reframe the three-lens
tab component around `review`'s three scopes (files / project / suite)
with fresh visuals per scope.
- Chapter 6 generation loop grid: replace `ghost context` with
`ghost emit context-bundle` and `ghost verify` with `ghost review suite`.
- Closing artifact grid: fix ghost.config.ts description ("How to scan
(optional)" → "Parent reference for component diff").
- Drift docs index: fix card copy (CLI verb list, getting-started hook).
Content only — no CLI or library changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pull the pure decision logic out of the compare and review command handlers so it can be tested without spawning processes or mocking cac. Locks in the behavior of the Phase 1–3 consolidation. - New `packages/ghost-cli/src/compare-mode.ts` with `selectCompareMode`: returns ok/error discriminated union picking components | fleet | semantic | temporal | pairwise. bin.ts compare action dispatches off the result. - Export `parseScope` from review-command.ts for testing. - Expand vitest config to discover tests in all workspace packages. - 26 new tests (12 parseScope, 14 selectCompareMode) — 188 → 214 total. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prerequisite for Option A split (packages/ghost-ui becomes library-only; apps/catalogue and apps/docs consume it). The SPA build is untouched so the existing /tools, /ui routes keep working during migration. - `src/index.ts` — public API: 49 UI primitives, 48 AI elements, theme primitives (ThemeProvider, ThemeControls, ThemeToggle, presets, utils), hooks, and cn. - `vite.lib.config.ts` — Vite lib mode, ESM output to `dist-lib/`, preserve-modules so consumers tree-shake per-import, externalize every non-relative import (React, Radix, etc. stay as peerDependencies at consumer level). - `tsconfig.lib.json` — emits .d.ts to `dist-lib/` via tsc. Excludes app-only sources (App.tsx, main.tsx, app/**, components/docs, components/theme-panel). - `package.json` — drops `private`, adds `main`/`module`/`types`/`exports` (root + styles.css + tokens.css + fonts.css + registry.json subpaths), `files` allowlist, `sideEffects: ["**/*.css"]`, `build:lib` script. - `.gitignore` — exclude `dist-lib/`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Option A step 2 of 3. @ghost/ui becomes library-only; apps/catalogue owns the Vite SPA that consumes it. Drift docs (/tools/drift/*) ride along in the catalogue for now — step 3 will migrate them to a dedicated apps/docs. Moved to apps/catalogue/src/: - App.tsx, main.tsx, app/ (all routes) - components/docs/ (catalogue-specific demos, layouts, bento cards) - components/theme-panel/ (runtime dev tool) - components/theme/ThemeControls.tsx (panel wrapper; ThemeProvider + ThemeToggle stay in lib) - contexts/, store/, types/ - lib/component-docs.ts, component-registry.ts, component-source.ts (registry metadata — catalogue-only) - styles/dev-fonts.css (Cash Sans CDN — catalogue runtime only) Left in packages/ghost-ui/src/ (library surface): - components/ui/ (49 primitives) - components/ai-elements/ (48 AI elements) - components/theme/ThemeProvider, ThemeToggle - hooks/ (5 shared hooks) - lib/utils (cn + helpers), theme-defaults, theme-presets, theme-provider, theme-utils - styles/main.css, font-faces.css (exported via @ghost/ui/styles.css) - fonts/ Mechanical rewrites in 177 catalogue files: - @/components/ui/* → @ghost/ui - @/components/ai-elements/* → @ghost/ui - @/components/theme/ThemeProvider|ThemeToggle → @ghost/ui - @/lib/utils, theme-defaults, theme-presets, theme-provider, theme-utils → @ghost/ui - @/hooks/use-* → @ghost/ui - Duplicate @ghost/ui imports merged by biome Plumbing: - pnpm-workspace.yaml now includes apps/* - justfile dev/build-ui/build-registry point at @ghost/catalogue + @ghost/ui - biome override adds apps/catalogue to the linter-disabled list - apps/catalogue/vite.config.ts reads DEPLOY_BASE env (github pages portability) - ghost-ui gains scripts/resolve-dts-paths.mjs to rewrite @/ aliases in emitted .d.ts files to relative paths (replaces tsc-alias; artifactory was flaky) - ghost-ui/package.json drops dev/build/preview (SPA-only scripts); ThemeControls removed from @ghost/ui index exports - getComponentName, copyToClipboard, getRandomIndex now exported from @ghost/ui/lib/utils Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Option A step 3 of 3. The drift-tooling docs (getting-started, cli, self-hosting + overview) are now markdown authored in a dedicated VitePress app. The concepts page — heavy JSX + GSAP chapters, interactive scan tabs, stance bubbles, fleet constellation — stays in apps/catalogue because its value lives in the animation, not the prose. Pages ported to apps/docs/ (markdown): - index.md (drift engine overview → VitePress `home` layout) - getting-started.md - cli.md - self-hosting.md Pages kept in apps/catalogue/: - app/docs/concepts/page.tsx — route path stays /tools/drift/concepts Catalogue route behaviour: - /tools/drift (overview) → redirects to apps/docs `/` - /tools/drift/getting-started → redirects to apps/docs `/getting-started` - /tools/drift/cli → redirects to apps/docs `/cli` - /tools/drift/self-hosting → redirects to apps/docs `/self-hosting` - /tools/drift/concepts → still rendered by the catalogue Redirect target is configurable via VITE_DOCS_BASE_URL; defaults to `/docs/` (GitHub Pages layout) and is used by `<DocsRedirect>`. VitePress config: - `base` derived from DEPLOY_BASE env: "/" locally, "/ghost/docs/" under Pages, any subpath on Vercel. Catalogue owns the root. - sidebar links the Concepts page cross-app so users can still reach it. - `ignoreDeadLinks: [/\/tools\//]` — cross-app hrefs aren't checkable. Deploy plumbing: - justfile adds `dev-docs`, `build-docs`, and `build-pages` (the Pages stitcher — catalogue at /, docs at /docs/, 404.html for SPA fallback). - .github/workflows/deploy-pages.yml rewritten: builds library, registry, catalogue (DEPLOY_BASE=/ghost/), docs (same base), stitches into dist/, uploads. Replaces the old packages/ghost-ui SPA build. - main.tsx: BrowserRouter basename now reads Vite's built-in BASE_URL instead of a custom VITE_BASE_PATH. - .npmrc pins `registry=https://registry.npmjs.org/` so installs work off-VPN; kept the @Anthropic-AI scoped override. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On GH Pages the catalogue lives at /ghost/ and docs at /ghost/docs/. Default DocsRedirect was pointing at /docs/ (root-absolute), which would 404 under a sub-path deploy. Derive the default from Vite's BASE_URL so it tracks the catalogue's actual base; VITE_DOCS_BASE_URL still overrides for a separate-project deploy (e.g. Vercel). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The VitePress split (522445e + 8aa88be) lost visual fidelity — the default theme shares nothing with the Ghost design language — and the DocsRedirect plus legacy /docs/* Navigate redirect created an infinite loop between the two origins. Not worth the markdown-source upside. Undo: - Restore the four JSX drift docs pages (page, getting-started, cli, self-hosting) into apps/catalogue/src/app/docs/ from 522445e^. - App.tsx: remove DocsRedirect, wire /tools/drift/* directly to the restored components. - Delete apps/docs/ (VitePress app, config, four markdown files). - Revert justfile: drop dev-docs/build-docs; simplify build-pages to a single catalogue build. - Revert deploy-pages.yml: single catalogue upload, no stitching. Architectural gain retained: drift docs live in an app (apps/catalogue), not a library (packages/ghost-ui). That was the real concern. Moving to a separate docs framework was a bridge too far. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The app is a docs site that includes the component catalogue as one section, not a catalogue-first app. `apps/docs` reads truer. - git mv apps/catalogue apps/docs - package.json: @ghost/catalogue → @ghost/docs - justfile, deploy-pages.yml, biome.json, ghost-ui/src/index.ts, ghost-ui/vite.lib.config.ts: update references - README project-structure diagram rebuilt to reflect the current layout (apps/docs entry, reduced packages/ghost-ui to library-only, updated CLI file list to the 11-verb surface, removed dead scan/drift scanner references) - CLAUDE.md packages table adds apps/docs and corrects ghost-ui's role The word "catalogue" still names the components feature inside the site (/ui/components) — it's no longer the app's name. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Naming was fractured across five layers — file (expression.md), type
(DesignFingerprint), CLI verb (profile), dir (src/fingerprint/), and
marketing ("fingerprint"). Pick one noun per layer and make "fingerprint"
disappear as a pervasive concept:
- type : DesignFingerprint → Expression (plus sibling renames:
EnrichedFingerprint, FingerprintComparison, FingerprintHistoryEntry,
FingerprintValidation, FingerprintAgent → Expression*)
- dir : packages/ghost-core/src/fingerprint/ → embedding/ (vector math)
- dir : packages/ghost-core/test/fingerprint/ → test/embedding/
- files : agents/fingerprint{,-agent}.ts → agents/expression{,-agent}.ts
- files : llm/validate-fingerprint.ts → llm/validate-expression.ts
- skill : skills/ghost-fingerprint/ → skills/ghost-profile/
- field : fingerprintPath → expressionPath
- flag : `ghost review -f, --fingerprint <path>` → `-e, --expression <path>`
- prose : CLAUDE.md, README, docs/, apps/docs/*, skills/, MCP tool text
"Fingerprint" survives only as the lucide-react icon import on the docs
landing page, which is a library name not a Ghost concept.
Delete legacy .ghost-fingerprint.json reader entirely (not yet adopted, no
migration path needed):
- Remove LEGACY_FINGERPRINT_FILENAME constant and dual-format dispatch
from expression/index.ts, review/pipeline.ts, evolution/parent.ts,
action/index.ts
- loadExpression() now asserts .md and throws a clear migration error
- Drop the "parses .json files via legacy passthrough" test; add one that
asserts the .md requirement instead
CLI dispatch coverage: parseEmitKind extracted from emit-command.ts and
covered by test/emit-kind.test.ts (6 tests). parseScope (12) and
selectCompareMode (14) were already tested — emit was the gap.
File-size exceptions updated for the renamed paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit accidentally included `.claude/scheduled_tasks.lock`. Remove from tracking and gitignore the local harness state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three follow-ups to close the renaming/CLI work on this branch: 1. Complete the `fingerprint` → `expression` rename. Prior commit left half the domain model under the old name. Rename core exports (`compareFingerprints` → `compareExpressions`, old semantic `compareExpressions` → `diffExpressions`, `formatFingerprint` → `formatExpression`, `fingerprintFromRegistry` → `expressionFromRegistry`, `describeFingerprint` → `describeExpression`, `emitFingerprint` → `emitExpression`, `validateFingerprint` → `validateExpression`, `FINGERPRINT_TOOLS` → `EXPRESSION_TOOLS`), move `reporters/fingerprint.ts` → `reporters/expression.ts`, rename shared field names (`ParsedExpression.fingerprint`, `FleetMember.fingerprint`, `ExpressionHistoryEntry.fingerprint`, `ComplianceInput.fingerprint`, `ReviewReport.fingerprint`, `Director.profile().fingerprint` → all `.expression`), and scrub the word from LLM prompts, CLI help strings, viz UI copy, MCP tool params, and the GitHub Action input. Leaves `refactor/fingerprint` branch name and lucide-react `Fingerprint` icon import untouched. 2. Bump expression.md schema 4 → 5. Move decision evidence from YAML frontmatter into the body under each `### Dimension` as a `**Evidence:**` bullet list. Frontmatter `decisions[]` keeps only `dimension` + optional `embedding`. Eliminates the visible overlap between the YAML `decisions:` block and the `# Decisions` prose — body is now authoritative for everything human-readable per dimension. Writer backticks citations; parser strips them for round-trip safety. Lint rules simplified (`orphan-dimension` replaces `missing-rationale`/`orphan-prose`; stray-evidence check retired). Migrate `packages/ghost-ui/expression.md`. 3. Split two flag-multiplexed subcommands back into their own verbs. `ghost compare --components` → `ghost drift` (local vs registry; takes no expression args, different mental model). `ghost review suite` → `ghost verify` (one expression in, aggregate out, different cost profile). Keep `compare` for N expressions across pairwise/fleet/semantic/temporal; keep `review files|project` unified. Net: 11 verbs → 13, but each verb has a single coherent input shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove DesignValues (Do/Don't) from the model and every emitter (types, parser, writer, diff, review/generate/context prompts, docs, reference expression.md). - Delete Director (202 lines, 3 callers) — inline extract + ExpressionAgent in profileMultiTarget, review-command runProject, and bin.ts discover. - Remove the vestigial --ai CLI flag; profile has been AI-only for a while and the flag was never read. - Add compare(expressions, opts) as the one comparison entry point — discriminated union over pairwise/fleet with optional semantic/temporal enrichment. Delete compare-mode.ts (63-line dispatcher) and the no-op --cluster flag (fleet triggers on N>=3). Net: -636 lines, 206 tests passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Collapse ExpressionAgent class + custom tool loop into runExpressionAgent (Agent SDK, Read/Glob/Grep). profileMultiTarget merges into profileTargets via a single staging dir (symlink per source). - Flatten stages/: comply → review/, emit-review → context/, delete compare and the StageResult wrapper ceremony. - Cut unused verbs: drift, viz, lint, generate. Drop profile --registry (shadcn-specific). Hide discover as experimental. - Rewrite DiscoveryAgent as a plain function; BaseAgent and agents/tools both deleted. LLM chat types relocate to llm/types.ts. 54 files, +210 / -6,382. Tests green (185), typecheck + biome clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI runs pnpm test without a prior build, so @ghost/core's main: ./dist/index.js can't resolve. Point vitest at the source entry directly — tests no longer depend on a build artifact, and runs are faster. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rename expression.md → fingerprint.md and all Expression* types/functions
to Fingerprint* — the artifact Ghost leaves behind.
Delete the in-process LLM stack: src/{agents,review,generate,verify,llm}/,
the GitHub Action, legacy skills/*/, and Anthropic/OpenAI deps. Judgement
work (profile, review, verify, generate, discover) moves to host agent
harnesses via the ghost-drift skill bundle (agentskills.io spec) shipped
by `ghost emit skill`.
Final CLI: six deterministic primitives — compare, lint, ack, adopt,
diverge, emit. No API key required for any verb. Schema versioning
removed — strict zod is the only gate.
Also trims ghost-mcp to registry-only (drops review_files tool).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5425043 to
6ccca5a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Long-running
refactor/fingerprintbranch brought to a clean landing. After many intermediate shapes (expression.md, single-agent profile loop, 9-verb CLI), the branch ends on a BYOA (bring-your-own-agent) architecture. Three through-lines:fingerprint.mdis the canonical artifact. YAML frontmatter (49-dim embedding across palette/spacing/typography/surfaces) plus a three-layer prose body (Character → Signature → Decisions → Values). Final rename fromexpression.md→fingerprint.mdlands in this branch; allExpression*types/functions becomeFingerprint*. Strict zod is the only schema gate — version field gone.src/agents/,src/review/,src/generate/,src/verify/,src/llm/, the GitHub Action, the Anthropic/OpenAI deps, and the legacyskills/*/directories. No CLI verb calls an LLM; no API key is required to run any command.ghost-mcpis trimmed to registry lookups only (dropsreview_files).ghost-drift) that ships insidepackages/ghost-cli/src/skill-bundle/. Host agents (Claude Code, Codex, Cursor, Goose, …) install it viaghost emit skilland drive the deterministic primitives themselves.Final CLI surface — 6 verbs:
compare [...fingerprints]--semantic/--temporal) or fleet (N≥3)lint [fingerprint.md]ack.ghost-sync.jsonadopt <fingerprint.md>diverge <dimension>emit <kind>review-command,context-bundle, orskillartifact fromfingerprint.mdAlso in this branch (pre-BYOA work that survived):
packages/ghost-uiwith a separate library build (dist-lib/+ shadcnregistry.json).apps/docs(VitePress).@ghost/mcppackage exposes the UI registry to MCP clients.Net diff vs main: 351 files, +9,857 / −13,362. The BYOA cut-down commit alone deleted ~5.5K LOC while adding ~2K (mostly the skill bundle + docs rewrite).
Test plan
pnpm install && pnpm buildsucceeds from a clean clonepnpm test— vitest suite passespnpm check— biome + typecheck + file-size cleanghost --helpshows exactly 6 verbs (no profile/review/verify/generate/discover)ghost lint fingerprint.mdon a valid file exits 0; on a malformed one surfaces zod errorsghost compare a.md b.mdpairwise +--semantic+--temporalall renderghost compare a.md b.md c.mdtriggers fleet mode (matrix + clusters)ghost ack/ghost adopt parent.md/ghost diverge paletteupdate.ghost-sync.jsonghost emit review-commandwrites a.claude/commands/*.mdslash commandghost emit context-bundlewrites the context bundleghost emit skillinstalls theghost-driftagentskills.io bundle into the host agent@anthropic-ai/sdkoropenai(grep -rinpackages/ghost-cliandpackages/ghost-core)OPENAI_API_KEY/ANTHROPIC_API_KEYto run (onlycomputeSemanticEmbeddinglibrary function should read them)🤖 Generated with Claude Code