Skip to content

Reincarnation: flat-corpus fingerprint, core checks, @design-intelligence#205

Merged
nahiyankhan merged 132 commits into
mainfrom
reincarnation
Jul 7, 2026
Merged

Reincarnation: flat-corpus fingerprint, core checks, @design-intelligence#205
nahiyankhan merged 132 commits into
mainfrom
reincarnation

Conversation

@nahiyankhan

@nahiyankhan nahiyankhan commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Category: improvement
User Impact: Ghost becomes one package (@design-intelligence/ghost) with one CLI, and a fingerprint is now a flat folder of plain-prose brand truths any agent can read before it generates.
Problem: The previous model — a graph-shaped fingerprint with inheritance, cross-package refs, a separate adherence binary (Haunt), and a cross-medium projection axis — shipped surface area nobody used and made authoring a fingerprint feel like configuring a system instead of writing down brand truths.
Solution: Collapse everything onto the flat-corpus model: .ghost/ is manifest.yml + glossary.md + prose nodes with materials locators. Haunt folds into the fingerprint, then the plugin abstraction is removed entirely: checks are a core opt-in capability at .ghost/checks/. ghost pull becomes the read chokepoint with a local events tape and ghost pulse. The npm scope renames to @design-intelligence, ghost-ui becomes the private vessel registry, and ghost-fleet is deleted.

The major shifts

  1. Scope rename@anarchitecture/ghost@design-intelligence/ghost. Tarball/tag prefixes, install script, release workflows, and the npm publish secret (DESIGN_INTELLIGENCE_NPM_PUBLISH_TOKEN) all follow.
  2. Flat corpus — no hierarchy, no edges, no extends, no colon refs, no JSON fingerprint schema. A node is a markdown file; its kind is a filename prefix declared in the glossary. Removed unused surface: incarnation/--as, scan/signals/inventory, standalone search (folded into gather's no-match path).
  3. Core checks — the separate adherence package and second binary are gone, and so is the interim one-plugin "haunt" system that briefly replaced them (ghost haunt, haunt.yml, ghost.haunt/v1). Checks live flat at .ghost/checks/, scaffolded by ghost checks init or ghost init --with checks; ghost review emits advisory diff packets from material-backed nodes and checks; export --no-checks excludes them. validate flags stale haunts/ trees with a migration hint, and the retired word is enforced-absent from public prose by the terminology guard.
  4. Pull + pulseghost pull <id>… emits selected node bodies and appends to a local .ghost/.events tape; ghost pulse summarizes it.
  5. Packagesghost-uivessel (private shadcn registry + MCP server); ghost-fleet deleted; docs site and README rewritten around the new thesis; research references doc added.

Blast radius

  • 128 commits, 850 files, +21,121 / −58,712 (net −37k)
  • 69 changesets: 48 minor, 21 patch (no majors: @design-intelligence/ghost has never been published, so this branch has no released consumers to break; 1.0 stays a deliberate milestone)
  • Concentration: packages/vessel (266 files, mostly renames from ghost-ui), packages/ghost (239), apps/docs (197), .changeset (69)
  • The release pipeline is the highest-risk piece — first publish under the new scope exercises the renamed secret, tarball prefix, and tags. check:release-workflows, check:release-tarball, and check:packed-package all pass, but the live publish is unverified until the version PR merges.
  • The repo's own root .ghost/ is re-authored under the flat-corpus model (index, glossary, voice + BYOA-boundary principles, surface-sprawl guard, flat-corpus decision trace); ghost validate passes clean.

Validation:

  • pnpm build: pass
  • pnpm test: 130 passed, 1 skipped (12 files)
  • pnpm check: pass (biome, typecheck, package-bin, packed-package, file-sizes, terminology, docs, install-bundle, release-tarball, release-workflows, cli-manifest)

Changeset: 69 changesets accumulated on the branch (48 minor, 21 patch); Changesets will open the version PR after merge, bumping to 0.20.0 under the new scope.

Ghost Review:

  • ghost validate: 0 errors, 0 warnings on the re-authored root fingerprint. ghost review not run: no checks directory on this fingerprint yet.
File changes (grouped — 850 files)

packages/ghost/ (239 files)
The public package rebuilt around the flat corpus: node schema, glossary kind-prefix validation, gather menu + closest-id suggestions, pull chokepoint + events tape, pulse, core checks management, review packet assembly, unified skill bundle, CLI exit-code contract, ghost manifest.

packages/vessel/ (266 files, mostly R100 renames from packages/ghost-ui/)
Rename to vessel: private shadcn component registry + vessel-mcp server. Removed from public docs/exports.

packages/ghost-fleet/ (25 files, deleted)
Fleet package removed; the concept survives only as the ghost-fleet skill outside this repo.

apps/docs/ (197 files)
Docs rewritten for the flat-corpus + core-checks model: new quickstart, verb-led onboarding, constitution amendments, generated CLI manifest, removal of graph/incarnation/extends pages.

.changeset/ (69 files)
One changeset per user-visible change across the branch.

docs/, ideas/, README.md, CONTRIBUTING.md, CLAUDE.md
Thesis rewrite, research references doc, retired three-lenses vocabulary, stop-slop passes.

.github/workflows/, install/, scripts/
Release workflows and install script moved to the design-intelligence prefix and new publish secret; check scripts updated for the single-public-package shape; emit-fingerprint-schema and strip-signature removed.

schemas/fingerprint.schema.json (deleted)
The JSON schema era ends; validation is CLI-native.

.ghost/ (re-authored)
Old-model facets (intent/inventory/composition/validate YAML) replaced with a flat-corpus fingerprint: manifest, glossary, index, two principles, one guard, one decision trace. Ghost dogfooding Ghost.

Root config (package.json, pnpm-lock.yaml, tsconfig.json, biome.json, lefthook.yml, justfile, .gitignore, .agents)
Workspace bookkeeping for the renamed/removed packages.

Screenshots/Demos: N/A

Stop circling. Three notes (purposes, ghost-layers, contract-and-binding)
shared one diagnosis: the descriptive core is clean; selection/routing/merge
leaked into the artifact's shape. reset.md fixes purpose, goals, layers, and
separation of concerns, and schedules a single first cut. coordinate-space.md
is the clean-room Layer 2 design: a surface is an author-named group with an
optional description; topology is a strict containment tree plus
cascade-from-ancestors plus rare explicit shared-edges; resolution is BYOA
(Ghost emits a described menu, the agent matches); delete list covers
inventory.topology, smeared applies_to, and ghost.map/v1.

Focus pass: delete pre-redesign docs (fingerprint-format, generation-loop,
host-adapters, ghost-fleet, language-fingerprints, relay-configs-and-context,
prompt-first-relay-prd) that described the dead Relay-routing and
topology/applies_to model. Port the one durable thesis (language maps onto the
four facets) inline into the voice skill reference and fix its stale coordinate
guidance. Update README and ideas/README to the reset arc.
A real non-UI composition case showed the topology conflated two axes.
Containment (where a node lives, who owns it) is a Layer 2 strict tree with
cascade-from-ancestors. Composition (what combines to serve a request) is a
Layer 3 typed reference graph laid over the tree. The explicit edges are not a
rare exception; in composition-heavy, pathless cases they are the primary
structure. The original 'tree + rare edges' framing over-fit the in-repo UI
case and under-served the no-repo composition case. Amends the topology section,
the layer-asks, decision 3, the surface shape, read-back, and the ideas README.
First concrete cut from coordinate-space.md. Proposes a new surfaces.yml facet
(ghost.surfaces/v1) anchored by the existing manifest, expressing both axes:
parent (the containment tree) and typed edges over edge_kinds (the composition
graph). Specifies a field-by-field migration off inventory.topology, smeared
applies_to, and exemplar surface_type/scope to a single surface: placement
pointer, keeping Layer 1 prose constant and the flat facet files intact for the
first cut. Includes a worked example from this repo's own dogfood .ghost/, lint
obligations, and open forks (closed vs open edge_kinds, dotted ids, default
placement, where path->surface mapping lives). Additive and backward compatible:
absent surfaces.yml keeps single-core behavior.
Resolve two open forks into decisions. edge_kinds is a fixed, Ghost-owned,
closed set referenced (never defined) per package: opening it would make Ghost a
general-purpose graph database and lose the interface-composition focus; richer
consumers extend edges consumer-side, not by opening Ghost's set. IDs are flat,
unique slugs with no structural meaning; dotted-id-as-hierarchy is banned (lint
error) so the tree lives only in parent, one source of truth (kills Leak C).
Updates the example, field rules, lint obligations, and forks list; two forks
remain (surface default, path->surface binding).
…coped ownership

Resolve the remaining forks. Placement is explicit: defaulting un-placed nodes
to core would rebuild global-fallback (the brand-mixing failure the redesign
cures), so authoring drafts placement, lint warns-and-teaches on the gap, and
un-placed never silently means core (warning not error, matching the derivation-
ref convention).

Reframe the path->surface fork as scoped ownership: in a repo, surfaces are
owned by location (the checkout surface is realized under apps/checkout), which
is ordinary nested-package/CODEOWNERS-shaped binding, not a new subsystem. The
portable contract (surfaces.yml) carries no paths; paths live on the binding.
One sub-fork remains for its own note: nested-package-as-binding vs explicit
path declaration vs both.
Second concrete extraction. The contract (surfaces.yml) carries no paths; the
binding owns all path matching. Directory location is the default binding (a
scoped .ghost/ binds surfaces to its subtree, reframing nested-package
resolution from data-merge to binding); an explicit .ghost.bind.yml is the
escape hatch when ownership does not match the tree, and is the real home for
the deleted topology.scopes[].paths. One resolver serves prompt, path, and diff
roads, meeting at a surface id; no-repo cases need no binding. Reframes
nesting-as-ownership to retire Leak E (no silent merge override, no silently
disabled inherited critical check). Records open forks (external contract
references, core fallback, bind-vs-redeclare) and the honest caution that this
is the least proof-validated layer, so it ships smallest-first.
Plan the breaking change as eight dependency-ordered phases, each a green,
committed cut: (0) freeze/baseline, (1) ghost.surfaces/v1 schema, (2) surfaces
lint, (3) placement on nodes — the breaking line, removing topology/applies_to/
surface_type/scope, (4) delete ghost.map/v1, (5) slice resolver + menu (prompt
road), (6) one-shot migration command + migrate this repo's .ghost/, (7)
ghost.binding/v1 path/diff roads + retire child-wins-by-id (Leak E), (8) command/
skill/docs reconciliation. Measured blast radius (~38 src, ~16 map, ~20 test
files). Additive phases 1-2 land first to de-risk; least-validated binding lands
last. Records open planning decisions (relay survival, migrator permanence,
delete-list commands).
…s test

A command's desire survives if the new model serves it; its implementation
survives only if it already is that. Relay's desire (right narrow context, right
time, traceable) is realized by the Phase 5 resolver; relay's implementation
(relay-config, request_resolvers, sources, ghost.relay-request/v1) is the second
routing system on the delete list. So relay/stack/survey/diff/describe are
deleted: relay and stack absorbed into a new gather/select command shipped in
Phase 5, the rest dead. Phase 5 ships the new context command on the resolver
(not old relay plumbing); Phase 8 deletes the dead commands as execution, not
decision. Collapses three open planning decisions into one.
…odule

First implementation cut, purely additive. Specs a new ghost-core/surfaces/
module mirroring fingerprint/ (types, schema, index) plus a schema test and one
re-export in ghost-core/index.ts. Schema bans dotted ids via a dot-excluding
slug regex (the tree lives only in parent); single parent falls out of parent
being scalar; edge kinds restricted to the fixed Ghost-owned set. Draws an
explicit schema/lint boundary: graph-level checks (cycles, dangling parent/edge
refs, near-miss, reserved core) are deferred to Phase 2 lint, documented in a
test case so they are not fixed in the wrong layer. Out-of-scope and acceptance
criteria are enumerated; one commit, no changeset (no user-visible behavior).
Two regressions from the earlier docs focus pass, surfaced by running the full
test suite (the pre-commit hook runs pnpm check, not pnpm test).

Remove Ghost's own dogfood .ghost/ package and its verify test: the package
cited deleted docs as evidence (fingerprint-evidence-unreachable), and a
self-referential fingerprint has been more confusing than useful.

Scope terminology-public to genuinely shipped text (README, docs site content,
skill bundle, changesets), excluding docs/: the design notes and purposes.md now
use 'layers' and 'cascade' as the canonical vocabulary of the surface-model
redesign, which the old guard forbade.
Phase 1 of the surface-model cutover (docs/ideas/phase-1-plan.md). Purely
additive: a new ghost-core/surfaces/ module mirroring fingerprint/, changing no
existing behavior.

- schema.ts: Zod for surfaces.yml. Flat-slug ids with the dot excluded, so
  dotted-id hierarchy is rejected at the schema layer (the tree lives only in
  parent). Single scalar parent; edge kinds restricted to the fixed Ghost-owned
  set (composes, governed-by).
- types.ts: constants, interfaces, and lint report types reusing the fingerprint
  facet shape for uniformity.
- index.ts + ghost-core/index.ts: re-export under @anarchitecture/ghost/core.
- tests: schema accepts a minimal doc and a realistic tree with typed edges;
  rejects dotted ids, array parents, unknown edge kinds, unknown keys. One case
  documents that dangling edge refs pass the schema on purpose (a Phase 2 lint
  concern), so the schema/lint boundary is not crossed in the wrong layer.

Graph validation (cycles, dangling refs, reserved core) is Phase 2. No
changeset: no user-visible behavior yet.
Add the Phase 2 execution spec (lintGhostSurfaces graph validation + ghost lint
dispatch for surfaces.yml; edge cycles allowed, only parent tree-constrained).

Also adopt the pre-commit test gate: lefthook.yml now runs just test alongside
just check, closing the gap Phase 1 exposed (the check-only hook let two
regressions through). Implementation-plan and phase-2-plan process notes updated
to reflect that both gates now run automatically.
Phase 2 of the surface-model cutover (docs/ideas/phase-2-plan.md). Additive:
adds document-level graph validation and recognizes surfaces.yml in ghost lint.

- lint.ts: lintGhostSurfaces validates what the schema cannot see in isolation —
  parent references exist (with core as the implicit-root exemption), the parent
  graph is a tree (cycles and self-parent error), edge targets exist (no core
  exemption), core may not declare a parent, duplicate ids error, and near-miss
  parent/edge ids warn via a local Levenshtein. Edge cycles are allowed; only
  parent is tree-constrained.
- types.ts: add errors/warnings/info counts to the lint report so it matches the
  other facet linters and the CLI dispatch return shape.
- scan/file-kind.ts: detect surfaces.yml / surfaces.yaml and the ghost.surfaces/v1
  literal, dispatch to lintSurfacesFile, mirroring the patterns/resources path.
- exports + tests: 12 lint cases covering every rule plus the allowed edge cycle
  and the schema-failure-as-issues path.
Specs Phase 3, the breaking line: remove topology/applies_to/surface_type/scope
from the canonical fingerprint (delete the Scope and Topology schemas) and add a
single optional surface: placement per node, validated against surfaces.yml.
Maps every removed field to its replacement against the live schema, and scopes
the cut to the description facets only — check.applies_to is left for Phase 4/7
because it is coupled to map routing, and pulling it into Phase 3 would leave a
half-migrated routing layer. Enumerates the lint rework (placement validation
with cross-facet surface input, unplaced warns, near-miss reuse), the consumer
ripple (context/graph the largest, kept minimal pending Phase 5), type removals,
test migration, the major changeset stub, and explicit out-of-scope.
… test fallout

A full read of context/graph.ts shows it is two subsystems: a structure/content
graph built from refs (keep, mechanical coordinate-string swap) and an
applicability/scope selection machinery that IS the old coordinate model
(buildScopes/matchScopes/nodeMatchesTargets/applicabilityFrom*). The original
'map applicability to home surface' instruction would reimplement the selection
machinery against placement in the breaking phase only for Phase 5 to discard
it — doing the work twice. Revise to make Job 2 compile-dormant and rewrite
selection once in Phase 5/7. Also name the expected consequence: path-based
selection tests (relay/context) break, and must be migrated or marked pending
rather than propped up.
…ase 3)

BREAKING: remove topology, applies_to, surface_type, and scope from the
canonical fingerprint; coordinates are now a single optional surface: placement
per node, validated against surfaces.yml.

Schema/types: delete GhostFingerprintScope/Topology/TopologyScope and the
topology subtree; add surface: to situations, principles, experience_contracts,
patterns, exemplars.

Lint: replace topology-ref checking with checkPlacement — unplaced nodes warn
(fingerprint-node-unplaced), unknown placements error (fingerprint-surface-
unknown) with near-miss suggestions; surface ids are passed in via a new
GhostFingerprintLintOptions.surfaceIds (cross-facet, mirroring validate lint).

graph.ts: keep the structure/content graph (Job 1, mechanical surface swap);
make the path/scope selection machinery (Job 2) compile-dormant — rebuilt
against surfaces in Phase 5/7 rather than reimplemented against placement now.

Consumers: comparable-fingerprint, package-context, package-review-command,
fingerprint-contribution, fingerprint-package-layers, fingerprint-stack updated;
map-derived check routing (mapFromFingerprint) and check scope/surface_type
grounding made dormant pending Phase 4/7.

ghost-ui: migrate the reference bundle to surfaces.yml; drop topology.

Tests: migrate fixtures to surface:; rewrite topology/grounding assertions to
the dormant behavior; skip path-selection suites (relay, context-entrypoint) and
two cli relay cases pending Phase 5/7. Full suite green (410 passed, 31 skipped).
Specs Phase 4: delete the map.md coordinate/routing layer made dormant in
Phase 3. Key finding from a full read — the map module is two tangled concerns:
the routing layer (MapFrontmatter, getEffectiveMapScopes, MAP_FILENAME, the
map.md schema/lint) to delete, and inventory-output types (GitInfo,
InventoryOutput, LanguageHistogramEntry, TopLevelEntry) that merely live in
map/types.ts and must be relocated, not deleted, since scan/inventory.ts needs
them. Plan: relocate the types first as a safe sub-commit, then delete routing
and rewire consumers (fingerprint-stack, checks/lint+routing+types, core/check,
scope-resolver, file-kind, lint-map, scan-status, fingerprint-package). check
routes on applies_to.paths alone; surface-based routing is deferred to Phase 7.
Flags reachability checks for scope-resolver and routeGhostValidateForPath
before delete-vs-reduce.
…(Phase 4)

BREAKING: remove the map.md / ghost.map/v1 coordinate-and-routing system made
dormant in Phase 3.

- Delete ghost-core/map/ (schema, scopes, the map half of types) and scan/
  lint-map.ts. Relocate the inventory-output types (GitInfo, InventoryOutput,
  LanguageHistogramEntry, TopLevelEntry) that merely lived in map/types.ts to
  ghost-core/scan-types.ts; scan/inventory.ts is unaffected.
- routeGhostValidateForPath now routes on applies_to.paths alone (no map scope
  resolution); drop routeGhostPathToScopes, matched_scopes, and the options.map
  check-scope grounding. Surface-based routing is rebuilt in Phase 7.
- core/check.ts routes by paths; remove mapFromFingerprint, parseMap,
  map.md reading, and the map field on the check package/stack types.
- Delete dead legacy: core/scope-resolver.ts and scan/fingerprint-set.ts (both
  unreachable map-scope fingerprint loaders) and their re-exports.
- scan-status: drop --include-scopes / scope reporting (map-driven). file-kind:
  drop the map DetectedFileKind and dispatch.

Pull ghost-fleet out of the workspace: a private, map-native relic of a past
idea, to be reintroduced later on the surface model. Removed from the root
tsconfig references and the cli-manifest dump; package deleted (recoverable
from history).

Tests: delete map-scopes and scope-resolver tests; retarget checks routing
tests to path-only. Full suite green (383 passed, 31 skipped).
…olver

Specs Phase 5, the first additive phase: rebuild the dormant selection road on
the surface model and ship it as a new gather command (relay's desire done
right). Four pieces: a surfaces loader (reads surfaces.yml into the package
model — never built; Phases 1-2 did schema+lint only), a deterministic slice
resolver (own placed nodes + cascaded ancestors + one-hop typed-edge
contributions with provenance, no LLM), a menu emitter (surfaces + descriptions
for the host agent to match against), and the gather command (surface to slice,
no/unknown surface to menu). Ambiguity returns the menu, never a whole-tree
dump. Replaces entrypoint.ts Job 2 (matchScopes/globalFallbackRefs/CAPS).
Scoped to the prompt road; path/diff routing is Phase 7. Re-expresses the
Phase 3 selection skips against gather. Minor changeset (additive).
Phase 5 — the first additive phase. Rebuilds the dormant selection road on the
surface model and ships it as a new gather command (relay's desire done right).

- Surfaces loader: read surfaces.yml into the package model (the disk-read step
  deferred since Phase 1). loadFingerprintPackage now parses it onto
  LoadedFingerprintPackage.surfaces; FingerprintPackagePaths gains surfaces.
- resolveSurfaceSlice (ghost-core/surfaces/resolve.ts): deterministic, no I/O,
  no LLM. Composes own placed nodes + cascaded ancestors (down-tree only) +
  one-hop typed-edge contributions, each tagged with provenance (own /
  ancestor:<id> / edge:<kind>:<id>). Unplaced nodes resolve as core. Checks are
  excluded — they route by paths (Phase 7), not surface placement.
- buildSurfaceMenu (surfaces/menu.ts): deterministic id+description+parent+edges
  list, always including the implicit core, for the host agent to match against.
- gather command: ghost gather <surface> emits the slice (markdown or json);
  no surface emits the menu (exit 0); unknown surface emits the menu (exit 2).
  Net-new, not built on relay-config/request-resolution.

Tests: resolver (own/cascade/edge/unplaced/empty/no-doc), menu shape, and
gather CLI (slice + menu + unknown). Full suite green (397 passed, 31 skipped).
Minor changeset (additive).
Specs Phase 6: a one-shot ghost migrate command that moves a legacy .ghost/
onto the surface model. Scope correction — the plan's 'migrate this repo's
dogfood .ghost/' no longer applies (deleted in the reset; ghost-ui was
hand-migrated in Phase 3), so Phase 6 is only the command + tests, for external
users. Key constraint: the current schema rejects legacy fields, so the migrator
operates on raw parsed YAML, not the package loader. Derives surfaces.yml from
topology.scopes; places single-scope nodes via surface:; drops surface_type
(no placement concept) and reports applies_to.paths (Phase 7 binding concern).
Core discipline: report-don't-guess — ambiguous/multi-scope nodes are surfaced
for human review, never auto-placed. Additive, minor changeset.
Phase 6 — additive. A one-shot migration of a legacy .ghost/ onto the surface
model.

- migrateLegacyPackage (scan/migrate-legacy.ts): pure transform over raw parsed
  YAML (the schema rejects legacy fields, so the loader cannot read a legacy
  package). Derives surfaces.yml from inventory.topology.scopes; places nodes
  via surface: from a single scope (explicit exemplar scope, or a lone
  applies_to.scopes entry); strips applies_to/surface_type/scope. Report,
  don't guess: multi-scope, surface_type-only, and bare nodes are left unplaced
  and recorded in a MigrationReport, never auto-placed. paths are reported, not
  converted (binding is Phase 7). Does not mutate input.
- looksLegacy: detect a legacy package by topology / node coordinate fields.
- ghost migrate [dir] command: --dry-run (print plan + report, write nothing),
  --force (rewrite in place), --format cli|json. Refuses non-legacy packages.

Tests: 11 transform unit tests (surface derivation, single-scope placement,
exemplar placement, multi-scope/type-only/bare reporting, topology drop,
no-mutation, migrated package passes lint) + 2 CLI round-trip tests (migrate →
lint clean → gather places correctly; refuses non-legacy). Full suite green
(410 passed, 31 skipped). Minor changeset.
…roads)

Specs Phase 7, the largest and least proof-validated cut. Surfaces the core
structural tension from reading fingerprint-stack.ts: the current model is
merge-centric (loadFingerprintStackForPath walks root-to-leaf, mergeFingerprints
unions facets child-wins-by-id, consumers read stack.merged.*). Binding replaces
'merge layers into one fingerprint' with 'resolve path to binding to surface to
composed slice' (the Phase 5 resolver output, not a facet union) — the
load-bearing reframe to get right before touching consumers.

Four steps: binding schema+loader (ghost.binding/v1, .ghost.bind.yml), the
path-to-surface resolver (nearest binding wins, explicit beats directory-implied,
multi-surface directory requires explicit — report don't guess), wiring the path
road (gather --path) and diff road (check/review union of surfaces), and
retiring the merge (delete mergeFingerprints/mergeChecks/mergeById and
child-wins-by-id, keeping layer discovery as binding discovery). Consumers
measured: check (biggest), review-packet, scan-stack, scan-emit; relay left for
Phase 8 deletion. Scoped to in-repo contract: . only; external references and
relay rewire deferred.
The additive, format-neutral half of Phase 7: turn a filesystem path into a
surface, the substrate any check routing needs underneath.

- ghost.binding/v1 (ghost-core/binding/): schema, lint, types for .ghost.bind.yml.
  contract is in-repo '.' only (external refs deferred); paths live on the
  binding, never the surface. Lint enforces the supported contract and rejects
  double-bound surfaces.
- resolvePathToSurface: pure path-to-surface resolver. Nearest binding wins;
  explicit beats directory-implied at the same level; a single directory-implied
  entry binds unconditionally; a multi-entry binding requires a path match
  (report, don't guess); unbound resolves to core when a root contract exists,
  else returns null (caller emits the menu).
- discoverBindingsForPath (scan/): walk root-to-leaf, collect directory-implied
  (scoped surfaces.yml) and explicit (.ghost.bind.yml) candidates.
- .ghost.bind.yml file-kind detection + lint dispatch.
- gather --path <file>: resolve a repo path to its surface via binding, then
  compose the slice. Verified end-to-end.

14 new tests (7 resolver, 7 schema/lint). Full suite green (424 passed).
Minor changeset. Diff road + merge retirement deferred (see phase-7b note).
…unded checks

After reading how checks are actually authored (markdown + frontmatter,
agent-evaluated, LLM-filtered for relevance), the 'add surface: to Ghost's
deterministic detector' sketch is wrong. Settles three decisions: Ghost does not
run checks; mimic the established markdown check format rather than compete with
it; the differentiator is grounding — when a check flags something, Ghost
supplies the why (principles/contracts) and what-to-change (patterns/exemplars)
from the surface's gather slice. Ghost owns deterministic path-to-surface
routing (the relevance filter, better than an LLM guess) and fingerprint
grounding; it never owns the check engine. ghost.validate/v1's regex detector
becomes legacy. Leaves four open questions for the 7b build (check placement,
grounding emit shape, validate/v1 deprecation, and the still-owed merge
retirement), explicitly not improvised here.
Sequences the governance build into four independent cuts: (1) retire the
child-wins-by-id merge (Leak E) — the one piece with no dependency on the
check-format question, riskiest and most independent, done first and alone;
(2) ghost.check/v1 as markdown + frontmatter (name/description/severity/tools/
turn-limit + surface:), mirroring the established agent-check format, parsed
and linted but never executed; (3) surface-routed relevance — a diff resolves
paths to surfaces (Phase 7a) and selects checks governing those surfaces and
ancestors, reusing the Phase 5 cascade and replacing path-glob routing;
(4) fingerprint grounding built on review — each flagged surface emits why
(principles/contracts) + what (patterns/exemplars). ghost.validate/v1 detector
kept parseable but demoted from the governance path; full removal and check
migration deferred. Cut 1 first and alone; 2-4 in order.
…tract (7b Cut 1)

Retires the fingerprint merge (Leak E). A nested .ghost/ no longer carries its
own fingerprint merged into the parent by id — instead a path resolves to the
single root contract, used as-is, and nesting binds paths to that contract's
surfaces (ghost.binding/v1). One contract, many bindings.

- buildFingerprintStack: the root-most layer is the contract; no mergeFingerprints
  / mergeChecks. stack.merged → stack.contract (the root's fingerprint + checks).
- Deleted mergeFingerprints/mergeIntent/mergeInventory/mergeComposition/
  mergeBuildingBlocks/mergeSummary/mergeChecks/mergeById/mergeByKey/mergeStrings
  and the child-wins-by-id provenance.
- Consumers rewired: core/check.ts, review-packet.ts, scan-stack-command.ts,
  fingerprintStackToPackageContext. relay left for Phase 8 deletion (minimal
  compile fix only).
- Public check-report/v1, review, and stack JSON expose  (not
  ) and drop .

Fixes Leak E directly: the prior nested fixture had a child disabling an
inherited critical check via merge — now the root contract's active check
governs and the diff correctly fails. Tests rewritten to the bind-only model.
Full suite green (424 passed).
Adds the Ghost check format: markdown + frontmatter, agent-evaluated, never run
by Ghost. Mirrors the established .agents/checks format plus a Ghost surface:
placement that routes the check.

- ghost-core/check/: types, parse (frontmatter splitter), lint, and a typed
  loader. Frontmatter: name, description, severity (high|medium|low), optional
  tools / turn-limit, optional surface (flat slug; absent governs core).
- lintGhostCheck validates required frontmatter, known severity, flat-slug
  surface, and a non-empty body; warns when unplaced. No detector, no execution.
- file-kind: a markdown file under a checks/ directory lints as a check
  (detected by location, since the format has no schema: field).

9 tests (parse, lint paths, typed load). Full suite green (433 passed).
Minor changeset. Surface-routed relevance (Cut 3) and grounding (Cut 4) next.
Specs Cut 3: the deterministic relevance filter where 7a binding, the Phase 5
cascade, and Cut 2 markdown checks compose. selectChecksForSurfaces (pure)
selects checks governing a diff's touched surfaces and their ancestors, reusing
ancestorChain from the slice resolver (one cascade for context and governance).
Diff road: changed paths to surfaces (binding) to relevant checks. Surfaces the
key decision — markdown checks route by surface, legacy validate/v1 detectors
keep their path-glob router; add surface routing beside it, do not rip out the
legacy path (deprecate by addition). Recommends a checks/ dir loader and a new
additive command rather than disturbing check. No grounding (Cut 4), no
execution, no validate/v1 removal.
…7b Cut 3)

The deterministic relevance filter — where 7a binding, the Phase 5 inheritance,
and Cut 2 markdown checks compose.

- Extracted ancestorChain/buildParentMap into surfaces/cascade.ts; the slice
  resolver and check routing now share one inheritance definition (context and
  governance resolve the same way).
- selectChecksForSurfaces (ghost-core/check/route.ts): pure, no LLM. Selects
  checks governing a diff's touched surfaces and their ancestors; unplaced
  checks govern core (apply everywhere); provenance tags own vs. ancestor.
- loadChecksDir (scan/): reads <package>/checks/*.md, lints each, skips invalid
  with a reason.
- ghost checks --diff: resolve changed paths to surfaces (binding), union,
  select; prints relevant checks per surface (markdown + json). Additive; the
  legacy validate/v1 detector path and its router are untouched.

13 tests. Full suite green (440 passed). Minor changeset. Grounding (Cut 4) next.
The audit tense of the same substrate review uses (plan:
notes/haunt-integrity.md). Review grades a change; integrity grades the
whole inventory: does what we own still cohere with what we said, and
with itself?

- haunt integrity [--package --ghost-dir --json]: no diff input;
  partitions git-tracked files by inventory paths and emits a
  deterministic per-material packet. Fingerprint required (shared
  exit-2 on-ramp, now also used by review).
- The packet is a map, not a payload: authored prose only; paths are
  glob pointers with verified match counts, no embedded file lists.
  Siblings are pointers (id + description + paths) so the agent grades
  each material relationally, pulling code depth itself (BYOA).
- Two baselines in the preamble: the fingerprint's stated truths, and
  the inventory's own latent pattern - on-pattern vs outlier, with
  outlier findings required to name the pattern they break. Five sprawl
  axes ship as orientation, not grading instructions.
- Gaps: dead-paths (globs matching zero tracked files - rot) and
  unreferenced-material (no check references it - unguarded).
- Shared baseline resolver extracted from review-packet (verbatim,
  review behavior pinned by existing tests); init's example check is
  now sprawl-flavored; skill bundle and README teach the two tenses.

10 test files, 39 haunt tests (+12).
CLAUDE.md and docs/purposes.md still taught the retired
directory-tree-is-the-graph model (path inheritance, relates edges,
checks inside .ghost/). Rewrite both against what the code implements:
a flat corpus of <kind>.<slug>.md nodes plus a glossary, menu-driven
selection, checks living in Haunt and binding via references. Strip the
fossil embedding-API env vars and delete the dead context-sandbox test
suite (skipped, referencing a removed relay CLI).
…nse seam

The review packet rendered 'Offered via:' for fingerprint-only checks,
implying a mechanical diff->inventory match that never happened. Add
offered: "matched" | "always" to OfferedCheck and render the two
honestly.

Document the mixed-check semantics the code already had: a local
reference scopes a check to its material at review (trigger + baseline);
whole-system drift outside a material's paths is haunt integrity's job,
on a cadence the consumer chooses (manual, cron, signal-driven). One
truth, two tenses — review stays strict and quiet, integrity carries
the advisory 'fyi' net.
One front door: `ghost` stays the primary bin and grows git-style
external-subcommand dispatch — `ghost haunt <command>` execs the
`ghost-haunt` binary when installed (PATH first, node_modules/.bin
fallback), with a friendly install hint and exit 2 when absent.

Haunt's bin renames haunt -> ghost-haunt, making the family visible in
every invocation. `ghost-haunt init` now scaffolds a missing .ghost/
fingerprint first (reusing the fingerprint package's own scaffold) with
a loud notice that an unauthored fingerprint grades nothing.

Following yarn/yarnpkg, the public package also ships a
`ghost-fingerprint` alias bin for machines where another tool owns the
`ghost` name (notably the Ghost blog CLI).
…unt/

One dotdir, one anchor. Haunt's on-disk package moves from a standalone
.haunt/ to the reserved haunt/ subtree inside .ghost/ — a plugin that
piggybacks on the fingerprint completely. The fingerprint's manifest is
the only package anchor: haunt's own manifest.yml, schema, --package and
--id flags are deleted, and its location is derived (<ghost-dir>/haunt),
never configured. Packets drop packageId (it would always equal
fingerprintId).

Fingerprint side: 'haunt' joins the reserved root entries; the retired
checks/ reservation and loadChecksDir export are removed. The reserved
list is now closed by constitution (docs/purposes.md): new entries must
pass the leak test and ship with a schema version; reserved subtrees
never travel with a fingerprint export.

A legacy top-level .haunt/ next to .ghost/ gets a migration warning
from ghost-haunt validate rather than silent breakage.
Three curation-pass findings from authoring the docs-site fingerprint,
folded into one schema pass:

- manifest.yml gains an optional plugins key declaring which reserved
  plugin subtrees the package uses; ghost-haunt init declares
  plugins: [haunt], and validate warns on present-but-undeclared or
  unknown plugins. Reservation stays unconditional — the key is
  hygiene, not gating.
- ghost gather serves the haunt plugin's inventory as a Materials
  section after the node menu: generation may lean on the repo's
  building blocks, while checks remain feed-back only and are never
  gathered.
- The index.md → core id mapping is gone: one uniform rule, id = path
  minus .md. The entrypoint node's documented job is the human-curated
  front door; the glossary is taught as a dictionary of every term
  with defined meaning, including bare-node terms like voice.
…index front door

Three amendments tracking the schema pass:

- gather's projection now includes the haunt inventory as a materials
  section — the feed-forward/feed-back seam runs through the plugin
  itself (inventory grounds building, checks grade output, checks are
  never gathered).
- the manifest's plugins list is the declared register of reserved
  subtrees in use; validate warns on present-but-undeclared.
- the entrypoint node is index.md with id index (uniform id rule), and
  its job is named: the human-curated front door, never a generated
  listing. The glossary is defined as the author's dictionary — every
  term with defined meaning, including bare-node terms.
Delete docs/ideas/ and ideas/ (superseded graph-era models and removed
commands — code and git history are the record; docs/purposes.md remains
the sole internal model doc). Rewrite both READMEs from the skill-bundle
canon in plain language: flat corpus, glossary kinds, condition-in-prose,
real CLI commands only. Patch Haunt README (pointer example, gitignored
notes/ links) and getting-started (haunt/ in the reserved list, front-door
phrasing). Clean stale code comments pointing at deleted idea docs.
…local history tape

Add `ghost pull <id> [<id>…]`: emit the named nodes' full prose bodies
(markdown or json) and append each selection as one line to .ghost/.pulls —
a gitignored, disposable history tape. The point is the iterating loop:
tune a node's description, re-run the task, tail the tape to see whether
the agent reached for the truth. Ghost never reads the tape back; it is
scratch, never canonical state. Unknown ids exit 2 with a closest-id hint
and append nothing; --no-history skips the append.

ghost init now seeds .ghost/.gitignore covering the tape. The skill bundle
(SKILL.md, recall, brief) teaches agents to pull instead of reading node
files directly. Also commits the two pending changesets from the previous
docs/skill commit.
…ocal pulse

Retire the separate packages/haunt package and its second binary. Capabilities
now attach as haunts under .ghost/haunts/<id>/ (managed by ghost haunt
add|remove|list or ghost init --with), with checks as the first haunt. Nodes
carry optional materials locators; ghost review assembles advisory diff
packets from material-backed nodes and checks. Add local gather/pull event
tracing (.ghost/.events) and a ghost pulse report. Vessel picks up stack,
surface, and text primitives plus an agent-safety audit script.
- New Checks And Review guide: haunts, check authoring, review packets,
  coverage gaps as tuning signal
- CLI reference: haunt and review commands, exit codes, validate scope,
  init --with checks, haunts/ in the package shape
- Getting started / authoring: feed-forward vs feed-back framing,
  materials frontmatter, haunts/ reserved name, cross-links
- Homepage thesis and hero: retire the node-graph/inheritance model for
  the flat corpus, gather-as-menu, and haunts
- Tools pages and command palette: ghost scan -> ghost gather, real
  review framing, dead anchors removed
- install.sh: describe the actual skill bundle and loop, not the
  retired intent.yml/lint/verify era
- Source: validate help text and stale comments describe current
  validation scope; no ghost migrate pointer; changeset for the
  user-visible help text fix
Replace the legacy intent/inventory/surfaces yml package (and its
extraction-era history.jsonl) with a current-format fingerprint distilled
from the Phase 0 invariants doc:

- index + principle.reference-not-brand: the reference-body seam
- principle.named-decisions: agent-safety discipline
- asset.tokens / asset.registry: material-backed contracts
- condition.escape-hatches / condition.upstream-sync: situational truths
- checks haunt: four review assertions wired to ghost review

Validates clean; gather/pull/review smoke-tested with zero coverage gaps
on token+component diffs. Vessel's .ghost now doubles as a living
exemplar of the format. README updated to point at it.
- Rename the public scope to @decentralized-design across packages,
  docs, workflows, and release scripts
- Order ghost pull packets for steering and extract Skeletons last;
  add probe execution to ghost review and concreteness to pulse
- Move steering starter templates into scan/steering-template.ts
- Add node prose stances and a scored drafting gate to the capture
  recipe, wired into both authoring recipes
- Refresh skill bundle prose, README, CLAUDE.md, and docs content
- @decentralized-design/* -> @design-intelligence/* across packages,
  lockfile, workflows, release tag/tarball prefix, and guard scripts
- Replace the scope-name manifesto with a Thesis section: agents changed
  the unit of design work; the work that compounds is architectural
- check-packed-package: strip inherited npm_config_* env and pin
  packageManager in the temp consumer so the check passes under pnpm run
…I scores

Intent / inventory / composition stop being a named Ghost concept. Authoring
surfaces now teach three drafting questions — why (stance), with what
(materials), how it is assembled (patterns) — each mapped to the dimension the
machinery already scores: stance prose reads first and steers weakest alone,
materials drive concreteness/pull ordering/review matching, Skeleton fences are
extracted and emitted dead last.

- Rename references/inventory.md to references/blocks.md; declare "block node"
  as recipe shorthand up front and show the glossary declaration the block.*
  worked examples require, so copying them cannot fail ghost validate.
- Rewrite the lens sections in capture.md, authoring-scenarios.md, SKILL.md,
  docs/purposes.md, CLAUDE.md, both docs-site .mdx pages, two nav cards, and
  the ghost-core types.ts comment onto the same vocabulary.
- Counterweight "weakest steering" so authors do not under-invest in stance.
- Update install/manifest.json and cli.test.ts for the rename.
Maps each claim in agent-readable-brand-steering.md to verified literature
with honest evidence tiers (Established / Adjacent / Prior), a list of
claims we deliberately do not cite, and open experiments for untested
priors.
* main:
  chore: version packages (#188)
  fix: honor GHOST_PACKAGE_DIR in drift, ack, history, and review-command paths

# Conflicts:
#	packages/ghost/package.json
#	packages/ghost/src/context/package-review-command.ts
#	packages/ghost/src/core/evolution/history.ts
#	packages/ghost/src/drift-command.ts
#	packages/ghost/src/evolution-commands.ts
The one-plugin plugin system (ghost haunt add|remove|list, haunt.yml,
ghost.haunt/v1, KNOWN_HAUNTS) is gone. Checks are a core capability in a
flat .ghost/checks/ directory: scaffold with ghost checks init or
ghost init --with checks; export --no-checks replaces --no-haunts.
validate flags stale haunts/ trees with a migration hint. The word is
purged from all public prose and added to the terminology guard. The
repo's own nested fingerprints (apps/docs, vessel) are migrated and
their glossaries fixed to the current kinds: schema.
@nahiyankhan nahiyankhan changed the title Reincarnation: flat-corpus fingerprint, haunts, @design-intelligence Reincarnation: flat-corpus fingerprint, core checks, @design-intelligence Jul 7, 2026
@design-intelligence/ghost has never been published; the first release
under the new name has no consumers to break, and the retired
@anarchitecture/ghost name never receives this code. Majors here would
only force an accidental 1.0.0 — that milestone should be declared
deliberately.
@nahiyankhan nahiyankhan marked this pull request as ready for review July 7, 2026 18:55
@nahiyankhan nahiyankhan merged commit 0f94bb9 into main Jul 7, 2026
4 checks passed
@nahiyankhan nahiyankhan deleted the reincarnation branch July 7, 2026 18:55
@github-actions github-actions Bot mentioned this pull request Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant