Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/expression-canonical-artifact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ghost-drift": major
---

Rename the public fingerprint artifact and APIs to expression, default CLI reads to expression.md, and replace adopt/parent tracking with track/tracks.
45 changes: 23 additions & 22 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pnpm --filter ghost-drift exec ghost <command>

Ghost's CLI is deterministic — no API key required for any verb.

- `OPENAI_API_KEY` / `VOYAGE_API_KEY` — optional, consumed only by `computeSemanticEmbedding` (library function; used when a host writes a fingerprint.md and wants an enriched 49-dim vector for paraphrase-robust comparison).
- `GITHUB_TOKEN` — optional, for `resolveParent` fetching a parent fingerprint from GitHub (avoids rate limits).
- `OPENAI_API_KEY` / `VOYAGE_API_KEY` — optional, consumed only by `computeSemanticEmbedding` (library function; used when a host writes an expression.md and wants an enriched 49-dim vector for paraphrase-robust comparison).
- `GITHUB_TOKEN` — optional, for `resolveTrackedExpression` fetching a tracked expression from GitHub (avoids rate limits).

The CLI auto-loads `.env` and `.env.local` from the working directory.

Expand Down Expand Up @@ -51,10 +51,10 @@ Engine layout (lives under `packages/ghost-drift/src/core/`):

- `core/compare.ts` — embedding-based comparison (pairwise + composite)
- `core/embedding/` — 49-dim vector computation, optional semantic embedding via OpenAI/Voyage
- `core/fingerprint/` — parse/compose/diff/lint `fingerprint.md`
- `core/evolution/` — history, ack manifest, composite analysis, parent resolution
- `core/expression/` — parse/compose/diff/lint `expression.md`
- `core/evolution/` — history, ack manifest, composite analysis, tracked-expression resolution
- `core/context/` — artifact generators (review-command, context-bundle, tokens.css)
- `core/reporters/` — output formatters for compare/composite/temporal/fingerprint
- `core/reporters/` — output formatters for compare/composite/temporal/expression

CLI glue sits alongside under `packages/ghost-drift/src/` (`bin.ts`, `cli.ts`, `emit-command.ts`, `evolution-commands.ts`, `target-resolver.ts`, `skill-bundle.ts`). The `./core/index.js` barrel is the single library export; `./cli` is the CLI subpath export.

Expand All @@ -64,28 +64,29 @@ What was removed in the BYOA migration: the Claude Agent SDK profiling loop (`sr

| Package | Published? | Description |
|---------|-----------|-------------|
| `packages/ghost-drift` | ✅ `ghost-drift` on npm | Merged engine + CLI — deterministic primitives (compare, embedding, fingerprint parse/lint, evolution, reporters) plus the cac-based CLI and the `ghost-drift` agentskills.io skill bundle under `src/skill-bundle/` |
| `packages/ghost-drift` | ✅ `ghost-drift` on npm | Merged engine + CLI — deterministic primitives (compare, embedding, expression parse/lint, evolution, reporters) plus the cac-based CLI and the `ghost-drift` agentskills.io skill bundle under `src/skill-bundle/` |
| `packages/ghost-ui` | ❌ private | Reference component library — 49 UI primitives + 48 AI elements + theme + hooks, distributed via the shadcn `registry.json`, not npm. Also ships the `ghost-mcp` bin (`src/mcp/`, built via `tsconfig.mcp.json` → `dist-mcp/`) — an MCP server re-exposing the registry to AI assistants (5 tools, 2 resources). |
| `apps/docs` | ❌ private | The deployed docs site (`ghost-docs`) — home, drift tooling docs, design language foundations, live component catalogue. Consumes `ghost-ui`. |

## CLI Commands

Six deterministic primitives. Everything else (profile, review, verify, generate, discover) is a skill recipe the host agent executes.
Seven deterministic primitives. Everything else (profile, review, verify, generate, discover) is a skill recipe the host agent executes.

| Command | Description |
|---------|-------------|
| `ghost-drift compare [...fingerprints]` | Pairwise (N=2) or composite (N≥3: pairwise matrix, centroid, clusters) over fingerprint embeddings. `--semantic`, `--temporal`. |
| `ghost-drift lint [fingerprint.md]` | Validate schema + body/frontmatter coherence |
| `ghost-drift ack` | Acknowledge drift; records stance in `.ghost-sync.json` (reads local `fingerprint.md`) |
| `ghost-drift adopt <fingerprint.md>` | Adopt a new parent baseline |
| `ghost-drift compare [...expressions]` | Pairwise (N=2) or composite (N≥3: pairwise matrix, centroid, clusters) over expression embeddings. `--semantic`, `--temporal`. |
| `ghost-drift lint [expression.md]` | Validate schema + body/frontmatter coherence |
| `ghost-drift describe [expression.md]` | Print section ranges and token estimates for selective loading |
| `ghost-drift ack` | Acknowledge drift; records stance in `.ghost-sync.json` (reads local `expression.md`) |
| `ghost-drift track <expression.md>` | Track another expression as this repo's reference |
| `ghost-drift diverge <dimension>` | Declare intentional divergence on a dimension |
| `ghost-drift emit <kind>` | Derive artifacts from `fingerprint.md` — `review-command`, `context-bundle`, or `skill` (the agentskills.io bundle). Run `ghost-drift emit skill` to install the `ghost-drift` skill into your host agent. |
| `ghost-drift emit <kind>` | Derive artifacts from `expression.md` — `review-command`, `context-bundle`, or `skill` (the agentskills.io bundle). Run `ghost-drift emit skill` to install the `ghost-drift` skill into your host agent. |

**Workflows the CLI does not do** — these are recipes the host agent follows (all under `packages/ghost-drift/src/skill-bundle/references/`):
- **Profile** (write `fingerprint.md` from a project) — `profile.md`
- **Profile** (write `expression.md` from a project) — `profile.md`
- **Review** (flag drift in PR changes) — `review.md`
- **Verify** (generate → review loop) — `verify.md`
- **Generate** (produce UI from fingerprint) — `generate.md`
- **Generate** (produce UI from expression) — `generate.md`
- **Discover** (find public design languages) — `discover.md`

## Target Types
Expand All @@ -99,11 +100,11 @@ The `resolveTarget()` function in `packages/ghost-drift/src/core/config.ts` acce
- `https://...` — URL
- `.` — current directory

Used by `resolveParent` (parent fingerprint resolution) and legacy library consumers. The profile flow itself no longer consumes targets — the host agent explores whatever directory is relevant.
Used by `resolveTrackedExpression` (tracked expression resolution) and legacy library consumers. The profile flow itself no longer consumes targets — the host agent explores whatever directory is relevant.

## Fingerprint format
## Expression format

The canonical fingerprint artifact is **`fingerprint.md`** — a human-readable, LLM-editable Markdown file with YAML frontmatter (machine layer) and a three-section prose body (Character → Signature → Decisions). See `docs/fingerprint-format.md` for the full spec; a condensed reference ships inside the skill bundle at `packages/ghost-drift/src/skill-bundle/references/schema.md`.
The canonical expression artifact is **`expression.md`** — a human-readable, LLM-editable Markdown file with YAML frontmatter (machine layer) and a three-section prose body (Character → Signature → Decisions). See `docs/expression-format.md` for the full spec; a condensed reference ships inside the skill bundle at `packages/ghost-drift/src/skill-bundle/references/schema.md`.

## Releasing & Changesets

Expand All @@ -123,15 +124,15 @@ Guidance on the bump level:

- **`patch`** — bug fixes, doc fixes, non-breaking internal refactors. The default; when in doubt, pick this.
- **`minor`** — new CLI verb, new flag, new library export, new capability. Anything a user might want to reach for.
- **`major`** — removed/renamed CLI verb, removed/renamed library export, changed default behavior, breaking fingerprint schema change, changed exit codes. **Always flag this explicitly in the PR description and ask the user to confirm — do not `major`-bump unreviewed.**
- **`major`** — removed/renamed CLI verb, removed/renamed library export, changed default behavior, breaking expression schema change, changed exit codes. **Always flag this explicitly in the PR description and ask the user to confirm — do not `major`-bump unreviewed.**

Skip the changeset entirely for: CI/workflow-only changes, test-only changes, changes scoped to `packages/ghost-ui` or `apps/docs` (both private — not published). The Changesets config ignores those packages.

The slug should be short and descriptive: `add-temporal-flag.md`, `fix-palette-lint-crash.md`. Avoid dates or PR numbers — Changesets consumes and deletes the file at version time.

## Key Conventions

- Each fingerprint carries a 49-dimensional embedding vector (palette [0–20], spacing [21–30], typography [31–40], surfaces [41–48]; see `packages/ghost-drift/src/core/embedding/embedding.ts`). The canonical on-disk form is `fingerprint.md`.
- `compare` takes **file paths** to `fingerprint.md`, not target strings. Mode auto-detects from N and flags: `--semantic` / `--temporal` require N=2; N≥3 returns a composite fingerprint.
- `ack` / `adopt` / `diverge` read the local `fingerprint.md`. The host agent is responsible for regenerating `fingerprint.md` (via the profile recipe) before acknowledging drift.
- `lint` takes a single fingerprint.md and reports schema/partition violations. Use as the success gate when writing a fingerprint.
- Each expression carries a 49-dimensional embedding vector (palette [0–20], spacing [21–30], typography [31–40], surfaces [41–48]; see `packages/ghost-drift/src/core/embedding/embedding.ts`). The canonical on-disk form is `expression.md`.
- `compare` takes **file paths** to `expression.md`, not target strings. Mode auto-detects from N and flags: `--semantic` / `--temporal` require N=2; N≥3 returns a composite expression.
- `ack` / `track` / `diverge` read the local `expression.md`. The host agent is responsible for regenerating `expression.md` (via the profile recipe) before acknowledging drift.
- `lint` takes a single expression.md and reports schema/partition violations. Use as the success gate when writing an expression.
18 changes: 9 additions & 9 deletions INVARIANTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ No CLI verb calls an LLM. No CLI verb takes an API key as a required input. Outp

---

## 2. fingerprint.md is the single canonical artifact.
## 2. expression.md is the single canonical artifact.

One on-disk format per fingerprint. No parallel JSON/YAML/TOML/DTCG representations. No compiled variants. Readers parse `fingerprint.md` directly.
One on-disk format per expression. No parallel JSON/YAML/TOML/DTCG representations. No compiled variants. Readers parse `expression.md` directly.

**Why:** Fingerprints are meant to be read by humans, edited by LLMs, and diffed in PRs. Multiple formats fracture all three. The artifact lives where design decisions already live — in the repo, versioned with code.
**Why:** Expressions are meant to be read by humans, edited by LLMs, and diffed in PRs. Multiple formats fracture all three. The artifact lives where design decisions already live — in the repo, versioned with code.

**Override:** Never for storage. Ephemeral runtime artifacts (composite centroids, cached embeddings) may exist in memory but must not be checked in or loaded as fingerprints.
**Override:** Never for storage. Ephemeral runtime artifacts (composite centroids, cached embeddings) may exist in memory but must not be checked in or loaded as expressions.

---

## 3. The frontmatter / body partition is strict.

Frontmatter holds the machine layer: identity, tokens, dimension slugs, evidence paths. Body holds the prose layer: Character, Signature, decision rationale. Prose does not leak into frontmatter; structured data does not leak into prose.

**Why:** The partition is what makes fingerprints simultaneously human-readable and machine-comparable. Blurring it forces one audience to do the other's work. The linter enforces it at the boundary; this invariant enforces it in spirit.
**Why:** The partition is what makes expressions simultaneously human-readable and machine-comparable. Blurring it forces one audience to do the other's work. The linter enforces it at the boundary; this invariant enforces it in spirit.

**Override:** Never. New fields are placed by layer, not by convenience.

Expand All @@ -48,11 +48,11 @@ Profile, review, verify, generate, and discover are recipes the host agent execu

---

## 5. Fingerprints evolve by deliberate act, not by schedule.
## 5. Expressions evolve by deliberate act, not by schedule.

A fingerprint changes when a human or agent deliberately edits it — in a design PR, an `adopt`, or a `diverge`. There is no background re-profile. There is no drift-triggered auto-update.
An expression changes when a human or agent deliberately edits it — in a design PR, an `track`, or a `diverge`. There is no background re-profile. There is no drift-triggered auto-update.

**Why:** A fingerprint that silently re-profiles is no longer a contract. The whole point of `adopt` / `ack` / `diverge` is that drift becomes *a visible act with a stance*. Automatic updates hide the act and collapse governance into noise.
**Why:** An expression that silently re-profiles is no longer a contract. The whole point of `track` / `ack` / `diverge` is that drift becomes *a visible act with a stance*. Automatic updates hide the act and collapse governance into noise.

**Override:** Never. Tooling may suggest re-profiling (e.g., after a major refactor), but the act itself is always explicit and human-authored.

Expand All @@ -62,6 +62,6 @@ A fingerprint changes when a human or agent deliberately edits it — in a desig

Each verb does one thing. No verb subsumes another. No `--mode` flag swaps a verb to a different conceptual operation.

**Why:** A small orthogonal surface is a product; a large overlapping surface is an accumulation. The current surface (`compare`, `lint`, `ack`, `adopt`, `diverge`, `emit`, `describe`) is a principled minimum — any addition must justify itself against merging with an existing verb.
**Why:** A small orthogonal surface is a product; a large overlapping surface is an accumulation. The current surface (`compare`, `lint`, `ack`, `track`, `diverge`, `emit`, `describe`) is a principled minimum — any addition must justify itself against merging with an existing verb.

**Override:** New verbs are fine when they capture a genuinely new operation. New flags are fine when they refine behavior within the same operation. Rule of thumb: if explaining the flag requires "if X, the verb actually does Y," it's a new verb.
Loading
Loading