Require explicit material file paths and dedupe pull inlining - #254
Merged
Conversation
nahiyankhan
marked this pull request as ready for review
August 10, 2026 13:24
chailandau
approved these changes
Aug 10, 2026
| /** | ||
| * Inline each distinct file once per pull. Nodes are already in output order, | ||
| * so the first node that carries a file inlines it; every later declaration of | ||
| * the same resolved path becomes a pointer at the copy already in context. |
Merged
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.
Category: improvement
User Impact: Ghost packages now name every material file explicitly, so a pull can never sweep unintended repository files into an agent's context.
Problem:
materialsaccepted glob patterns, and in a live repo a glob expands against whatever the repo happens to contain. A four-node pull from the vessel-light starter delivered 308 KB, including gitignored eval baseline HTML — the exact median output the package exists to refuse — inlined as brand material. Shared files liketokens.csswere also inlined once per declaring node, diluting the pull with duplicates.Solution: Glob patterns are removed from the material contract entirely: node validation rejects them with a clear message, and the glob matching machinery (
glob.ts, expansion, the 12-file cap) is deleted from transport, review matching, and inspection. All shipped packages (vessel-light.ghost, vessel-react.ghostandfingerprint) now declare explicit file paths, and docs/recipes teach the convention. Separately,ghost pullnow inlines each distinct file once per pull; later nodes that declare the same file get a pointer at the copy already in context. The same vessel-light pull is now 28.7 KB with zero unintended files.Validation:
pnpm build: passpnpm vitest run packages/ghost/test: 163 passed, 1 skippedpnpm check: pass (biome, typecheck, terminology, packed-package, file sizes, release tarball/workflows, vessel-light closure)ghost validateon vessel-light: 0 errors, 0 warnings; vessel-react packages: only pre-existingcover-undeclared--no-verify: the only failing test is the pre-existing steering-controlspawnSync /Users/nahiyan/Library/Application ENOENTenvironment issue (path-with-space splitting inarms.mjs), unrelated to this branchChangeset: added — one
minor(glob removal is a public behavior boundary) and onepatch(pull dedupe)ghost Review: not run — this change touches the material transport contract and starter packages, not UI generation or fingerprint semantics; deterministic validation above covers it
Notes for reviewers:
ghost reviewjurisdiction matching is now exact-path. A node that previously claimed**/*.cssno longer auto-claims new CSS files; it claims only the files it names.description→contextretrieval field rename); test fixtures and docs usecontextaccordingly.content inlined above under node <id>pointers with honest inlined/omitted counts.File changes
.changeset/vessel-materials-explicit-files.md, .changeset/pull-dedupes-shared-materials.md
Release notes: minor for the explicit-files contract, patch for pull dedupe.
packages/ghost/src/ghost-core/materials.ts
validateMaterialLocatorrejects*,?,{in local locators — the enforcement point for the whole change.packages/ghost/src/ghost-core/glob.ts, packages/ghost/src/review/glob.ts
Deleted: the glob matcher and its re-export.
packages/ghost/src/ghost-core/material-transport.ts
expandLocalMaterialLocator(multi-match, capped) replaced byresolveLocalMaterialFile(one locator → at most one file); glob cap and walk-filtering removed;walkFilesretained only for bundled-materials listing.packages/ghost/src/ghost-core/index.ts
Export surface updated: glob helpers removed,
resolveLocalMaterialFileadded.packages/ghost/src/embed/inspect.ts
Single-file resolution; the "matched multiple files" branch is gone because it is now impossible.
packages/ghost/src/embed/pull.ts
New
dedupeInlinedMaterialspost-pass: first carrier in output order inlines, later duplicates become pointers, counts adjusted.packages/ghost/src/scan/fingerprint-package-lint.ts
Dead-locator lint uses the single-file resolver; glob locators now surface as
node-invalidschema errors instead.packages/ghost/src/ghost-core/node/types.ts
Doc comment: materials are explicit file paths; globs fail validation.
packages/ghost/src/skill-bundle/SKILL.md, references/schema.md, references/capture.md, references/adapting-a-starter.md
Recipes teach the explicit-files convention and the post-vendoring locator verification step (
material-locator-deadwarnings name stale paths).CLAUDE.md, README.md, docs/purposes.md
Root docs updated to the same convention.
packages/vessel-light/.ghost/*.md
Repo-wide
**/*.css/**/*.htmlglobs removed from six grammar nodes;materials/fonts/*.woff2expanded to the seven explicit font files.packages/vessel-react/fingerprint/.md, packages/vessel-react/.ghost/.md
All globs replaced with explicit
packages/vessel-react/src/...paths (each verified to exist);index.mdprose says "materials paths".packages/ghost/test/cli.test.ts, embed.test.ts, fingerprint-package.test.ts, ghost-core/node-schema.test.ts
Fixtures converted to explicit paths; glob-cap test replaced with explicit-inlining tests; new tests for glob rejection and cross-node dedupe pointers.
Screenshots/Demos: N/A