diff --git a/.changeset/rename-retrieval-field-to-for.md b/.changeset/rename-retrieval-field-to-for.md new file mode 100644 index 00000000..81e3aca8 --- /dev/null +++ b/.changeset/rename-retrieval-field-to-for.md @@ -0,0 +1,5 @@ +--- +"@design-intelligence/ghost": minor +--- + +The node retrieval frontmatter field is `for`: the situation or activity the guidance is for. `context` and `description` are rejected at validation with a pointer to `for`; gather/pull output, the embed API, coverage reporting (`withoutFor`), and the lint rule (`node-for-missing`) all use `for`. diff --git a/CLAUDE.md b/CLAUDE.md index 278dd21f..e91a8c84 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,9 +50,9 @@ glossary.md # the author's category vocabulary + what each kind means checks/ # optional review assertions; never a node source ``` -The **corpus is flat**. A node is a markdown file: a `context` in -frontmatter (the retrieval payload), optional `materials`, and brand guidance in -the prose body. A node's identity is its filename minus `.md`; its kind is the +The **corpus is flat**. A node is a markdown file: a `for` payload in +frontmatter (the retrieval payload: the situation or activity the guidance is +for), optional `materials`, and brand guidance in the prose body. A node's identity is its filename minus `.md`; its kind is the filename prefix before the first dot, declared in the glossary. There is no hierarchy, no inheritance, no edges; nesting into folders is a browsing convenience only. diff --git a/README.md b/README.md index 25ae41a3..29fa5f83 100644 --- a/README.md +++ b/README.md @@ -107,13 +107,13 @@ repeatable commands for scaffolding, validation, retrieval, and review. The package is a **flat set of nodes**. The optional `cover:` in `manifest.yml` may name any node; `ghost gather` inlines it before the menu. The default skeleton calls that node `brand`, but the filename is not reserved. -A node is one markdown file: a `context` in frontmatter, optional -`materials`, and brand guidance in the prose body. `description` remains a -deprecated read alias for one release, and `ghost validate` warns on its use. +A node is one markdown file: a `for` payload in frontmatter (the situation or +activity the guidance is for), optional `materials`, and brand guidance in the +prose body. ```markdown --- -context: Placing, sizing, or choosing a logo lockup or glyph. +for: Placing, sizing, or choosing a logo lockup or glyph. materials: - brand/logo-lockup.svg - brand/logo-glyph.svg diff --git a/apps/docs/.ghost/anti-goal.generic-ai-product.md b/apps/docs/.ghost/anti-goal.generic-ai-product.md index 3a433817..b0460f22 100644 --- a/apps/docs/.ghost/anti-goal.generic-ai-product.md +++ b/apps/docs/.ghost/anti-goal.generic-ai-product.md @@ -1,5 +1,5 @@ --- -context: Any visual surface at risk of generic AI-product spectacle or card chrome. +for: Any visual surface at risk of generic AI-product spectacle or card chrome. materials: - apps/docs/src/pages/index.astro - apps/docs/src/styles/marked-doc.css diff --git a/apps/docs/.ghost/brand.md b/apps/docs/.ghost/brand.md index f349ee39..11b9a4bf 100644 --- a/apps/docs/.ghost/brand.md +++ b/apps/docs/.ghost/brand.md @@ -1,5 +1,5 @@ --- -context: Any expression of the ghost brand. +for: Any expression of the ghost brand. materials: - apps/docs/src/styles/marked-doc.css - apps/docs/src/pages/index.astro diff --git a/apps/docs/.ghost/composition.md b/apps/docs/.ghost/composition.md index ef483057..621d8060 100644 --- a/apps/docs/.ghost/composition.md +++ b/apps/docs/.ghost/composition.md @@ -1,5 +1,5 @@ --- -context: Composing any ghost page or adapting its layout across viewport sizes. +for: Composing any ghost page or adapting its layout across viewport sizes. materials: - apps/docs/src/components/DocSection.astro - apps/docs/src/components/SectionWrapper.astro diff --git a/apps/docs/.ghost/docs-site.md b/apps/docs/.ghost/docs-site.md index 0aebd592..8103d52f 100644 --- a/apps/docs/.ghost/docs-site.md +++ b/apps/docs/.ghost/docs-site.md @@ -1,5 +1,5 @@ --- -context: Translating the ghost visual expression into another surface or medium. +for: Translating the ghost visual expression into another surface or medium. materials: - apps/docs/src/pages/index.astro - apps/docs/src/components/Hero.astro diff --git a/apps/docs/.ghost/mark.md b/apps/docs/.ghost/mark.md index c025dd64..8d2d2075 100644 --- a/apps/docs/.ghost/mark.md +++ b/apps/docs/.ghost/mark.md @@ -1,5 +1,5 @@ --- -context: Using yellow, selection, intervention, or active-choice states. +for: Using yellow, selection, intervention, or active-choice states. materials: - apps/docs/src/styles/marked-doc.css - apps/docs/src/components/docs/gather-demo.tsx diff --git a/apps/docs/.ghost/pattern.motion.md b/apps/docs/.ghost/pattern.motion.md index a2dca7b0..000559be 100644 --- a/apps/docs/.ghost/pattern.motion.md +++ b/apps/docs/.ghost/pattern.motion.md @@ -1,5 +1,5 @@ --- -context: Anything that moves, transitions, reveals in sequence, or changes position or emphasis. +for: Anything that moves, transitions, reveals in sequence, or changes position or emphasis. materials: - apps/docs/src/components/docs/gather-demo.tsx - apps/docs/src/styles/marked-doc.css diff --git a/apps/docs/.ghost/pattern.specimen.md b/apps/docs/.ghost/pattern.specimen.md index e7489b61..a5b17d29 100644 --- a/apps/docs/.ghost/pattern.specimen.md +++ b/apps/docs/.ghost/pattern.specimen.md @@ -1,5 +1,5 @@ --- -context: A reader needs to inspect an example, table, code sample, comparison, palette, diagnostic, or interactive result. +for: A reader needs to inspect an example, table, code sample, comparison, palette, diagnostic, or interactive result. materials: - apps/docs/src/pages/index.astro - apps/docs/src/components/docs/gather-demo.tsx diff --git a/apps/docs/.ghost/principles.md b/apps/docs/.ghost/principles.md index fd7521e5..6e3f3954 100644 --- a/apps/docs/.ghost/principles.md +++ b/apps/docs/.ghost/principles.md @@ -1,5 +1,5 @@ --- -context: Any ghost visual expression, independent of surface, medium, or implementation. +for: Any ghost visual expression, independent of surface, medium, or implementation. materials: - apps/docs/src/pages/index.astro - apps/docs/src/components/DocSection.astro diff --git a/apps/docs/.ghost/visual-system.md b/apps/docs/.ghost/visual-system.md index 9461ade7..fece6c7b 100644 --- a/apps/docs/.ghost/visual-system.md +++ b/apps/docs/.ghost/visual-system.md @@ -1,5 +1,5 @@ --- -context: Choosing or implementing color, typography, spacing, shape, elevation, interaction, or accessibility for ghost. +for: Choosing or implementing color, typography, spacing, shape, elevation, interaction, or accessibility for ghost. materials: - apps/docs/src/styles/marked-doc.css - apps/docs/src/styles/docs.css diff --git a/apps/docs/src/components/docs/gather-demo.tsx b/apps/docs/src/components/docs/gather-demo.tsx index 58cf7ef6..467d7ff4 100644 --- a/apps/docs/src/components/docs/gather-demo.tsx +++ b/apps/docs/src/components/docs/gather-demo.tsx @@ -1,21 +1,21 @@ import { useEffect, useMemo, useRef, useState } from "react"; const nodes = [ - { id: "brand", context: "any task that should express this brand" }, - { id: "voice", context: "anything with words" }, - { id: "motion", context: "anything that moves on screen" }, + { id: "brand", for: "any task that should express this brand" }, + { id: "voice", for: "anything with words" }, + { id: "motion", for: "anything that moves on screen" }, { id: "email.transactional", - context: "money moved and the reader is checking", + for: "money moved and the reader is checking", }, { id: "layout.spacing", - context: "laying out a page", + for: "laying out a page", }, - { id: "never.ai-defaults", context: "any first-draft visual surface" }, + { id: "never.ai-defaults", for: "any first-draft visual surface" }, { id: "logo.usage", - context: "placing or sizing the mark", + for: "placing or sizing the mark", }, ] as const; @@ -118,7 +118,7 @@ export function GatherDemo() { >
{node.id}
- {node.context} + {node.for} {node.id === "brand" ? ( {" "} diff --git a/apps/docs/src/pages/index.astro b/apps/docs/src/pages/index.astro index ccad19e6..4ad44d2b 100644 --- a/apps/docs/src/pages/index.astro +++ b/apps/docs/src/pages/index.astro @@ -29,7 +29,7 @@ const steeringDiagnoses = [ signal: "delivery gap", read: "the relevant guidance existed but did not reach the task", repair: - "add the node, sharpen its description, or inspect why it was skipped", + "add the node, sharpen its `for` payload, or inspect why it was skipped", }, { signal: "correction gap", @@ -44,7 +44,7 @@ const guidanceExamples = [ label: "visual decision", path: "pattern.crop-with-intent.md", body: `--- -description: Photography. Gather when a composition uses a photo. +for: Photography. Gather when a composition uses a photo. materials: - brand/photography/** --- @@ -60,7 +60,7 @@ Reject cautious full-object framing and collages that avoid choosing a focal poi label: "product pattern", path: "condition.blocked-progress.md", body: `--- -description: Blocked progress. Gather when someone cannot continue a task. +for: Blocked progress. Gather when someone cannot continue a task. materials: - src/components/error-state/** --- @@ -76,7 +76,7 @@ If the person cannot resolve the problem, state what happens next. Do not end on label: "exact material", path: "asset.color-roles.md", body: `--- -description: Exact color roles and values. Gather before assigning color. +for: Exact color roles and values. Gather before assigning color. materials: - src/styles/brand-tokens.css --- @@ -245,12 +245,12 @@ Ink carries content. Signal marks selection. Correction marks review.

Gather shows the complete menu before the agent chooses. If useful guidance does not reach the work, you can see whether the node was - missing, its description was unclear, or the agent skipped it. + missing, its for payload was unclear, or the agent skipped it.

efficiency

- Gather represents every node with a compact ID and description. + Gather represents every node with a compact ID and for payload. Pull loads the full prose and materials only for the selected nodes. The agent sees the shape of the whole brand while keeping generation context small and free of unrelated instructions. diff --git a/docs/purposes.md b/docs/purposes.md index 144d16c5..23fa624e 100644 --- a/docs/purposes.md +++ b/docs/purposes.md @@ -38,7 +38,7 @@ into folders is a browsing convenience only. | `manifest.yml` | Schema version and package id; the package's anchor. | | `glossary.md` | The author's dictionary: every term with defined meaning in the corpus. ghost ships no fixed vocabulary. | | Prose nodes (`..md`, `.md`) | Durable brand guidance; each body answers why (the stance), with what (the materials), or how it is assembled (the patterns). Altitude lives in prose; narrower guidance names its condition. | -| Node frontmatter | `context` (retrieval payload) and optional `materials` (explicit repo-relative file paths or supported external locators, with optional retrieval notes; see the schema reference for the supported schemes). | +| Node frontmatter | `for` (retrieval payload) and optional `materials` (explicit repo-relative file paths or supported external locators, with optional retrieval notes; see the schema reference for the supported schemes). | | `checks/` | Optional review assertions binding to nodes with `references`. Never a node source and never generation input. | One resolution mechanism, read-only: @@ -78,7 +78,7 @@ Two rules keep the reservation honest: 1. **Retrieval needs pushed into the shape.** When selection feels imprecise, the temptation is to encode routing in data: proliferating filename kinds until they become destinations, or turning the glossary into a dispatch table. - *Fix: `context` is the retrieval payload; sharpen contexts, show the + *Fix: `for` is the retrieval payload; sharpen `for` payloads, show the menu, let the agent pick.* 2. **Filing by destination.** A node authored as `for-emails.md` smuggles a diff --git a/packages/context-control/README.md b/packages/context-control/README.md index 6c67d860..d72c5117 100644 --- a/packages/context-control/README.md +++ b/packages/context-control/README.md @@ -6,9 +6,9 @@ measures whether the right guidance even makes it into context. Selection is the unit. No generation, ever. `ghost gather` does no filtering: the menu is always the whole catalog, and -selection happens in the model's head against each node's `context`. -So what this bench actually tests is whether contexts are good enough -retrieval payloads — a node with a vague context is invisible at +selection happens in the model's head against each node's `for` payload. +So what this bench actually tests is whether `for` payloads are good enough +retrieval payloads — a node with a vague `for` is invisible at selection time no matter how good its body is. ## Run @@ -30,15 +30,15 @@ else `ghost` on PATH). ## Screens **package** — the catalog rendered as the selection surface the model -sees: id, kind, context, material count, coverage line. Click a node to -see its real `ghost pull` output in a drawer. Review contexts as -retrieval payloads, not file contents; a node with no context is flagged +sees: id, kind, `for` payload, material count, coverage line. Click a node to +see its real `ghost pull` output in a drawer. Review `for` payloads as +retrieval payloads, not file contents; a node with no `for` is flagged as invisible. **bench** — type an ask (or run the whole asks suite), fire N single-shot selection trials, and read the heatmap: nodes × asks, each cell the fraction of trials that selected the node. Solid column = confident -context. Speckled = coin-flip. Empty row = dead node. Blue outline = +`for` payload. Speckled = coin-flip. Empty row = dead node. Blue outline = the ask's expected set. Scores above the map: consistency (mean pairwise Jaccard), mean per-trial precision and recall, poison-selection rate, unknown ids, and nodes ever selected. diff --git a/packages/context-control/lib/model.mjs b/packages/context-control/lib/model.mjs index ac00c733..f5336ea9 100644 --- a/packages/context-control/lib/model.mjs +++ b/packages/context-control/lib/model.mjs @@ -60,7 +60,7 @@ export function fakeModel() { const selected = []; for (const entry of menu) { const nodeTokens = tokens( - [entry.id.replaceAll(/[.-]/g, " "), entry.kind, entry.context] + [entry.id.replaceAll(/[.-]/g, " "), entry.kind, entry.for] .filter(Boolean) .join(" "), ); @@ -101,7 +101,7 @@ function selectUser(ask, menu, cover) { const flags = [entry.materials ? `${entry.materials} materials` : null] .filter(Boolean) .join(", "); - return `- ${entry.id}${entry.kind ? ` [${entry.kind}]` : ""}${flags ? ` (${flags})` : ""}: ${entry.context ?? "(no context)"}`; + return `- ${entry.id}${entry.kind ? ` [${entry.kind}]` : ""}${flags ? ` (${flags})` : ""}: ${entry.for ?? "(no for payload)"}`; }); const coverLine = cover ? `Cover already in context: ${cover.id}\n\n${cover.body}\n\n` diff --git a/packages/context-control/ui/index.html b/packages/context-control/ui/index.html index af6e1401..327ee9ef 100644 --- a/packages/context-control/ui/index.html +++ b/packages/context-control/ui/index.html @@ -126,7 +126,7 @@

context-control · selection is the unit

Each column is one ask; each cell is the fraction of trials that selected the node. - Solid = confident context. Speckled = coin-flip. Empty row = invisible node. + Solid = confident `for` payload. Speckled = coin-flip. Empty row = invisible node. Blue outline = in the ask's expected set. The cover is already in context and is not part of the menu. Selection runs the ghost skill's recall protocol; live agents additionally carry task @@ -168,12 +168,12 @@

context-control · selection is the unit

const c = data.coverage; $("#coverage").textContent = `${c.nodes} nodes · ${c.concrete} concrete` + - (c.withoutContext ? ` · ${c.withoutContext} without context` : ""); + (c.withoutFor ? ` · ${c.withoutFor} lack for` : ""); $("#menuRows").innerHTML = state.menu.map((n) => ` ${n.id}${n.materials ? `${n.materials} mat` : ""} ${n.kind ?? ""} - ${n.context ?? 'no context — invisible at selection time'} + ${n.for ?? 'no for payload — invisible at selection time'} `).join(""); document.querySelectorAll("tr.node").forEach((row) => { row.onclick = () => openDrawer(row.dataset.id); @@ -189,7 +189,7 @@

context-control · selection is the unit

const node = data.nodes?.[0]; drawer.innerHTML = `

${id}

` + (node - ? `

${node.context ?? ""}


${escapeHtml(node.body)}` + ? `

${node.for ?? ""}


${escapeHtml(node.body)}` : `

pull returned nothing (${escapeHtml(JSON.stringify(data))})

`); drawer.querySelector(".close").onclick = () => drawer.classList.add("hidden"); } diff --git a/packages/ghost/src/commands/gather-command.ts b/packages/ghost/src/commands/gather-command.ts index 054f5950..7091334d 100644 --- a/packages/ghost/src/commands/gather-command.ts +++ b/packages/ghost/src/commands/gather-command.ts @@ -100,8 +100,8 @@ function menuCoverageLine(menu: GhostGatherResult): string { `${coverage.nodes} nodes`, `${coverage.concrete} carry payloads (${payloadParts.join(", ")})`, ]; - if (coverage.withoutContext > 0) { - parts.push(`${coverage.withoutContext} lack context`); + if (coverage.withoutFor > 0) { + parts.push(`${coverage.withoutFor} lack \`for\` payloads`); } return parts.join(" · "); } @@ -125,7 +125,7 @@ function formatMenuMarkdown(menu: GhostGatherResult): string { if (menu.ask) { lines.push( "Complete, unfiltered, unranked list from the ghost package. ghost has not selected nodes for this ask.", - "Pull every node whose context indicates its stated situation applies and whose guidance, material, structure, or refusal governs the work. Skip inapplicable nodes. Topic overlap alone is not applicability. Do not add nodes for completeness or omit applicable nodes to meet a count.", + "Pull every node whose `for` payload indicates its stated situation applies and whose guidance, material, structure, or refusal governs the work. Skip inapplicable nodes. Topic overlap alone is not applicability. Do not add nodes for completeness or omit applicable nodes to meet a count.", "Next: `ghost pull […]`.", "If nothing applies, name the package's silence, follow the cover silence posture, and do not invent ghost-backed guidance.", "", @@ -147,7 +147,7 @@ function formatMenuMarkdown(menu: GhostGatherResult): string { for (const entry of menu.nodes) { const kind = entry.kind ? ` _(${entry.kind})_` : ""; lines.push(`- \`${entry.id}\`${kind}`); - if (entry.context) lines.push(` - ${entry.context}`); + if (entry.for) lines.push(` - ${entry.for}`); if (entry.materials !== undefined) { lines.push(` - materials: ${entry.materials}`); } diff --git a/packages/ghost/src/commands/pull-command.ts b/packages/ghost/src/commands/pull-command.ts index 42a34237..8d695fb7 100644 --- a/packages/ghost/src/commands/pull-command.ts +++ b/packages/ghost/src/commands/pull-command.ts @@ -113,9 +113,7 @@ function formatPullJson( nodes: result.nodes.map((node) => ({ id: node.id, ...(node.kind !== undefined ? { kind: node.kind } : {}), - ...(node.context - ? { context: node.context, description: node.context } - : {}), + ...(node.for ? { for: node.for } : {}), ...(node.declaredMaterials !== undefined ? { materials: inlineMaterials @@ -134,7 +132,7 @@ function formatPullMarkdown(result: GhostPullResult): string { for (const node of result.nodes) { const kind = node.kind ? ` _(${node.kind})_` : ""; const lines = [`# \`${node.id}\`${kind}`]; - if (node.context) lines.push("", `> ${node.context}`); + if (node.for) lines.push("", `> ${node.for}`); lines.push("", node.body.trim()); if (node.materials !== undefined && node.materials.length > 0) { lines.push("", "Materials:"); diff --git a/packages/ghost/src/embed/gather.ts b/packages/ghost/src/embed/gather.ts index dc4c4121..bf4c347f 100644 --- a/packages/ghost/src/embed/gather.ts +++ b/packages/ghost/src/embed/gather.ts @@ -62,7 +62,7 @@ export function gatherContract(ask: string | undefined): GhostGatherContract { selection: { basis: "applicability", instruction: ask - ? "Pull every node whose context indicates its stated situation applies and whose guidance, material, structure, or refusal governs the work; skip inapplicable nodes." + ? "Pull every node whose `for` payload indicates its stated situation applies and whose guidance, material, structure, or refusal governs the work; skip inapplicable nodes." : "Bare gather is catalog inspection. Do not treat the menu as task grounding until an ask is supplied; when grounding a task, pull every applicable node and skip inapplicable nodes.", topicOverlapAloneIsApplicability: false, addForCompleteness: false, @@ -76,8 +76,8 @@ export function gatherContract(ask: string | undefined): GhostGatherContract { export function menuCoverage( menu: readonly CatalogMenuEntry[], ): GhostGatherCoverage { - const withoutContext = menu.filter( - (entry) => !entry.context || entry.context.trim().length === 0, + const withoutFor = menu.filter( + (entry) => !entry.for || entry.for.trim().length === 0, ).length; return { nodes: menu.length, @@ -87,8 +87,7 @@ export function menuCoverage( fencedExamples: menu.filter((entry) => entry.hasFencedExample).length, skeletons: menu.filter((entry) => entry.hasSkeleton).length, }, - withoutContext, - undescribed: withoutContext, + withoutFor, }; } diff --git a/packages/ghost/src/embed/pull.ts b/packages/ghost/src/embed/pull.ts index 08d9b66d..b80e4200 100644 --- a/packages/ghost/src/embed/pull.ts +++ b/packages/ghost/src/embed/pull.ts @@ -67,9 +67,7 @@ export async function pullGhostNodes( nodes: pulledNodes.map(({ node, materials }) => ({ id: node.id, ...(node.kind !== undefined ? { kind: node.kind } : {}), - ...(node.context - ? { context: node.context, description: node.context } - : {}), + ...(node.for ? { for: node.for } : {}), ...(node.materials !== undefined ? { declaredMaterials: [...node.materials] } : {}), diff --git a/packages/ghost/src/embed/types.ts b/packages/ghost/src/embed/types.ts index d6432ff8..91797a02 100644 --- a/packages/ghost/src/embed/types.ts +++ b/packages/ghost/src/embed/types.ts @@ -59,9 +59,7 @@ export interface GhostGatherCoverage { fencedExamples: number; skeletons: number; }; - withoutContext: number; - /** @deprecated Use `withoutContext`. */ - undescribed: number; + withoutFor: number; } export interface GhostGatherContract { @@ -110,9 +108,7 @@ export interface GhostPulledSkeleton { export interface GhostPulledNode { id: string; kind?: string; - context?: string; - /** @deprecated Use `context`. Mirrors the resolved context for one release. */ - description?: string; + for?: string; declaredMaterials?: readonly GhostMaterial[]; materials?: readonly TransportedMaterial[]; body: string; diff --git a/packages/ghost/src/ghost-core/catalog/assemble.ts b/packages/ghost/src/ghost-core/catalog/assemble.ts index 1bc57fed..cf518a7f 100644 --- a/packages/ghost/src/ghost-core/catalog/assemble.ts +++ b/packages/ghost/src/ghost-core/catalog/assemble.ts @@ -35,7 +35,6 @@ export function assembleCatalog(input: AssembleCatalogInput): GhostCatalog { for (const placed of input.placedNodes ?? []) { const fm = placed.doc.frontmatter; - const context = fm.context ?? fm.description; const concrete = carriesConcreteMaterial({ materials: fm.materials, body: placed.doc.body, @@ -44,10 +43,7 @@ export function assembleCatalog(input: AssembleCatalogInput): GhostCatalog { id: placed.id, ...(placed.kind !== undefined ? { kind: placed.kind } : {}), slug: placed.slug ?? placed.id.split("/").pop() ?? placed.id, - ...(context !== undefined ? { context, description: context } : {}), - ...(fm.description !== undefined - ? { usesDeprecatedDescription: true as const } - : {}), + ...(fm.for !== undefined ? { for: fm.for } : {}), ...(fm.materials !== undefined ? { materials: fm.materials } : {}), concrete, hasFencedExample: hasSubstantialFencedExample(placed.doc.body), diff --git a/packages/ghost/src/ghost-core/catalog/closest.ts b/packages/ghost/src/ghost-core/catalog/closest.ts index d50b3889..58127d24 100644 --- a/packages/ghost/src/ghost-core/catalog/closest.ts +++ b/packages/ghost/src/ghost-core/catalog/closest.ts @@ -5,7 +5,7 @@ * routing to nothing. This is that hint: deterministic, LLM-free, bounded. * * It is not a search engine. An inexact `gather ` shows the node menu - * and lets the agent re-pick by context; this only nominates the few ids a + * and lets the agent re-pick by `for` payload; this only nominates the few ids a * typo most likely meant. */ diff --git a/packages/ghost/src/ghost-core/catalog/menu.ts b/packages/ghost/src/ghost-core/catalog/menu.ts index 3d31d88a..76f0e1fa 100644 --- a/packages/ghost/src/ghost-core/catalog/menu.ts +++ b/packages/ghost/src/ghost-core/catalog/menu.ts @@ -1,18 +1,16 @@ import type { GhostCatalog } from "./types.js"; /** - * One entry in the gather menu: a node presented as `id` + `kind` + `context`, + * One entry in the gather menu: a node presented as `id` + `kind` + `for`, * the retrieval payload the agent selects against. The agent matches a - * natural-language ask against these and pulls applicable nodes; ghost does no - * NLP and no selection. + * natural-language ask against these and pulls applicable nodes; ghost does + * no NLP and no selection. */ export interface CatalogMenuEntry { id: string; /** The node's kind (filename prefix), when it declares one. */ kind?: string; - context?: string; - /** @deprecated Use `context`. Mirrors the resolved context for one release. */ - description?: string; + for?: string; /** Count of material locators available after pulling this node. */ materials?: number; /** True when this entry carries a material locator, fenced example, or Skeleton. */ @@ -24,9 +22,9 @@ export interface CatalogMenuEntry { } /** - * Build the gather menu: every authored node, with its kind and context, - * sorted by id for stable output. A flat catalog with no anchor or hierarchy; - * the agent selects from it. + * Build the gather menu: every authored node, with its kind and `for` + * payload, sorted by id for stable output. A flat catalog with no anchor or + * hierarchy; the agent selects from it. */ export function buildCatalogMenu(catalog: GhostCatalog): CatalogMenuEntry[] { const entries: CatalogMenuEntry[] = []; @@ -35,9 +33,7 @@ export function buildCatalogMenu(catalog: GhostCatalog): CatalogMenuEntry[] { entries.push({ id: node.id, ...(node.kind !== undefined ? { kind: node.kind } : {}), - ...(node.context - ? { context: node.context, description: node.context } - : {}), + ...(node.for ? { for: node.for } : {}), ...(node.materials !== undefined && node.materials.length > 0 ? { materials: node.materials.length } : {}), diff --git a/packages/ghost/src/ghost-core/catalog/types.ts b/packages/ghost/src/ghost-core/catalog/types.ts index c2fb6aea..c1236f88 100644 --- a/packages/ghost/src/ghost-core/catalog/types.ts +++ b/packages/ghost/src/ghost-core/catalog/types.ts @@ -12,12 +12,8 @@ export interface GhostCatalogNode { kind?: string; /** Filename slug: bare name, or the part after the first dot. */ slug: string; - /** Retrieval payload shown in gather: the condition under which this node applies. */ - context?: string; - /** @deprecated Use `context`. Mirrors the resolved context for one release. */ - description?: string; - /** Whether the authored frontmatter used the deprecated `description` key. */ - usesDeprecatedDescription?: true; + /** Retrieval payload shown in gather: the situation or activity this guidance is for. */ + for?: string; /** Optional bare or annotated material locators carried by the authored node. */ materials?: GhostMaterial[]; /** True when the node carries a material locator, substantial fence, or Skeleton. */ diff --git a/packages/ghost/src/ghost-core/node/schema.ts b/packages/ghost/src/ghost-core/node/schema.ts index 6590de77..64ab798b 100644 --- a/packages/ghost/src/ghost-core/node/schema.ts +++ b/packages/ghost/src/ghost-core/node/schema.ts @@ -40,16 +40,22 @@ const AnnotatedMaterialSchema = z * * Validates a node in isolation. Identity and containment are not here: they * come from the node's file path. Kind is the filename prefix, never a - * frontmatter field. `description` is accepted as a deprecated read alias for - * `context`; consumers resolve `context` first when both are present. + * frontmatter field. */ export const GhostNodeFrontmatterSchema = z .object({ - context: z.string().min(1).optional(), - description: z.string().min(1).optional(), + for: z.string().min(1).optional(), materials: z .array(z.union([MaterialLocatorSchema, AnnotatedMaterialSchema])) .optional(), + // The retrieval payload field is `for`. Reject near-miss keys that would + // otherwise ride along silently and leave the node invisible to gather. + context: z + .never({ message: "`context` is not a node key; use `for`" }) + .optional(), + description: z + .never({ message: "`description` is not a node key; use `for`" }) + .optional(), // `relates` (and all typed edges) were removed. Reject it with a message // that names the key so authors get a clear signal. relates: z diff --git a/packages/ghost/src/ghost-core/node/serialize.ts b/packages/ghost/src/ghost-core/node/serialize.ts index 12a9bc66..142b75cc 100644 --- a/packages/ghost/src/ghost-core/node/serialize.ts +++ b/packages/ghost/src/ghost-core/node/serialize.ts @@ -1,7 +1,7 @@ import { stringify as stringifyYaml } from "yaml"; import type { GhostNodeDocument, GhostNodeFrontmatter } from "./types.js"; -const FRONTMATTER_KEY_ORDER = ["context", "materials"] as const; +const FRONTMATTER_KEY_ORDER = ["for", "materials"] as const; function shouldSerializeFrontmatterValue(value: unknown): boolean { return value !== undefined; @@ -9,38 +9,28 @@ function shouldSerializeFrontmatterValue(value: unknown): boolean { /** * Serialize a node back to its `---\n\n---\n` markdown form. Known - * keys are emitted first in a stable order (context, materials), followed by - * any free-form descriptive keys in alphabetical order so round-trips and - * diffs are deterministic. The deprecated `description` alias is written as - * `context`, which makes serialize a safe migration boundary. Identity and kind - * are not serialized; they come from the node's file path and optional filename - * prefix. Undefined fields are omitted; a node with no frontmatter fields emits - * an empty block. + * keys are emitted first in a stable order (for, materials), followed + * by any free-form descriptive keys in alphabetical order so round-trips and + * diffs are deterministic. Identity and kind are not serialized; they come + * from the node's file path and optional filename prefix. Undefined fields are + * omitted; a node with no frontmatter fields emits an empty block. */ export function serializeNode(node: GhostNodeDocument): string { const fm = node.frontmatter as Record; - const normalized: Record = { - ...fm, - ...(fm.context === undefined && fm.description !== undefined - ? { context: fm.description } - : {}), - }; - delete normalized.description; - const ordered: Record = {}; const emitted = new Set(); for (const key of FRONTMATTER_KEY_ORDER) { - const value = normalized[key]; + const value = fm[key]; if (shouldSerializeFrontmatterValue(value)) { ordered[key] = value; emitted.add(key); } } - for (const key of Object.keys(normalized).sort()) { + for (const key of Object.keys(fm).sort()) { if (emitted.has(key)) continue; - const value = normalized[key]; + const value = fm[key]; if (shouldSerializeFrontmatterValue(value)) ordered[key] = value; } diff --git a/packages/ghost/src/ghost-core/node/types.ts b/packages/ghost/src/ghost-core/node/types.ts index 73e133dd..fda84bea 100644 --- a/packages/ghost/src/ghost-core/node/types.ts +++ b/packages/ghost/src/ghost-core/node/types.ts @@ -12,14 +12,12 @@ export interface GhostNodeFrontmatter { /** Free-form descriptive properties parsed from node frontmatter. */ [key: string]: unknown; /** - * Retrieval payload shown by gather: the observable condition under which - * this node applies. Together with the node's id, it is how an agent decides - * applicability. Optional, but strongly encouraged on any node worth - * anchoring a task at. + * Retrieval payload shown by gather: the situation or activity this + * guidance is for, never an audience. Together with the node's id, it is + * how an agent decides applicability. Optional, but strongly encouraged on + * any node worth anchoring a task at. */ - context?: string; - /** @deprecated Use `context`. Accepted as a read alias for one release. */ - description?: string; + for?: string; /** * Optional locators for the concrete materials this guidance is about: * explicit repo-relative file paths and supported external locators. Glob diff --git a/packages/ghost/src/init-payloads/median/cliche.median.md b/packages/ghost/src/init-payloads/median/cliche.median.md index 887590ac..302393f7 100644 --- a/packages/ghost/src/init-payloads/median/cliche.median.md +++ b/packages/ghost/src/init-payloads/median/cliche.median.md @@ -1,5 +1,5 @@ --- -context: Any greenfield visual surface or first-draft copy. +for: Any greenfield visual surface or first-draft copy. --- This is the model's median, not your brand. Each rule is reject→replace. diff --git a/packages/ghost/src/init-payloads/skeleton/brand.md b/packages/ghost/src/init-payloads/skeleton/brand.md index 8ead1673..647d45f2 100644 --- a/packages/ghost/src/init-payloads/skeleton/brand.md +++ b/packages/ghost/src/init-payloads/skeleton/brand.md @@ -1,5 +1,5 @@ --- -context: Any task that should express this brand. +for: Any task that should express this brand. --- This cover is unwritten. ghost gather always places this page in an agent's diff --git a/packages/ghost/src/init-payloads/skeleton/context.conversation.md b/packages/ghost/src/init-payloads/skeleton/context.conversation.md index c5b5f339..b1247769 100644 --- a/packages/ghost/src/init-payloads/skeleton/context.conversation.md +++ b/packages/ghost/src/init-payloads/skeleton/context.conversation.md @@ -1,5 +1,5 @@ --- -context: Chat threads, agent consoles, and prompt composers. +for: Chat threads, agent consoles, and prompt composers. --- In this context: AI conversation threads, agent consoles, review assistants, diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.color.md b/packages/ghost/src/init-payloads/skeleton/foundation.color.md index 65c407ab..274d1ca0 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.color.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.color.md @@ -1,5 +1,5 @@ --- -context: Choosing or applying color. +for: Choosing or applying color. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.composition.md b/packages/ghost/src/init-payloads/skeleton/foundation.composition.md index 4617f092..d3e576d3 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.composition.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.composition.md @@ -1,5 +1,5 @@ --- -context: Assembling any view. +for: Assembling any view. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.controls.md b/packages/ghost/src/init-payloads/skeleton/foundation.controls.md index 62755c7b..42a2485c 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.controls.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.controls.md @@ -1,5 +1,5 @@ --- -context: Any view with actions or inputs. +for: Any view with actions or inputs. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.layout.md b/packages/ghost/src/init-payloads/skeleton/foundation.layout.md index 415a265f..e7a2ff50 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.layout.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.layout.md @@ -1,5 +1,5 @@ --- -context: Laying out any view. +for: Laying out any view. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.motion.md b/packages/ghost/src/init-payloads/skeleton/foundation.motion.md index acf2aabd..8759b8c4 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.motion.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.motion.md @@ -1,5 +1,5 @@ --- -context: Any transition, animation, or hover treatment. +for: Any transition, animation, or hover treatment. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.type.md b/packages/ghost/src/init-payloads/skeleton/foundation.type.md index b0597bed..1d1c5594 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.type.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.type.md @@ -1,5 +1,5 @@ --- -context: Any view containing text. +for: Any view containing text. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/init-payloads/skeleton/foundation.voice.md b/packages/ghost/src/init-payloads/skeleton/foundation.voice.md index a1ea83b5..ede2e9a8 100644 --- a/packages/ghost/src/init-payloads/skeleton/foundation.voice.md +++ b/packages/ghost/src/init-payloads/skeleton/foundation.voice.md @@ -1,5 +1,5 @@ --- -context: Writing or editing any copy. +for: Writing or editing any copy. --- Starter guidance the brand owner has not yet reviewed. Cite it as provisional diff --git a/packages/ghost/src/review/baseline.ts b/packages/ghost/src/review/baseline.ts index 11772a8e..19912b89 100644 --- a/packages/ghost/src/review/baseline.ts +++ b/packages/ghost/src/review/baseline.ts @@ -8,7 +8,7 @@ export interface BaselineProse { ref: string; nodeId: string; heading?: string; - context?: string; + for?: string; body: string; warning?: string; } @@ -25,7 +25,7 @@ export function resolveBaseline( return { ref: raw, nodeId: ref.nodeId, - ...(node.context !== undefined ? { context: node.context } : {}), + ...(node.for !== undefined ? { for: node.for } : {}), body: node.body, }; } @@ -34,7 +34,7 @@ export function resolveBaseline( ref: raw, nodeId: ref.nodeId, heading: ref.heading, - ...(node.context !== undefined ? { context: node.context } : {}), + ...(node.for !== undefined ? { for: node.for } : {}), body: section ?? node.body, ...(section === null ? { diff --git a/packages/ghost/src/review/review-packet.ts b/packages/ghost/src/review/review-packet.ts index a78dcabc..182225eb 100644 --- a/packages/ghost/src/review/review-packet.ts +++ b/packages/ghost/src/review/review-packet.ts @@ -22,7 +22,7 @@ export type { BaselineProse }; export interface PacketMaterialNode { id: string; kind?: string; - context?: string; + for?: string; prose: string; materials: GhostMaterial[]; matchedMaterials: string[]; @@ -112,7 +112,7 @@ function materialNodeFromMatch( return { id: node.id, ...(node.kind !== undefined ? { kind: node.kind } : {}), - ...(node.context !== undefined ? { context: node.context } : {}), + ...(node.for !== undefined ? { for: node.for } : {}), prose: node.body, materials: node.materials ?? [], matchedMaterials: matched.locators, @@ -142,7 +142,7 @@ export function formatReviewPacket(packet: ReviewPacket): string { for (const node of packet.materialNodes) { const kind = node.kind ? ` _(${node.kind})_` : ""; out.push(`### \`${node.id}\`${kind}`); - if (node.context) out.push(`_${node.context}_`, ""); + if (node.for) out.push(`_${node.for}_`, ""); out.push(node.prose, ""); out.push("Matched materials:"); for (const locator of node.matchedMaterials) { diff --git a/packages/ghost/src/scan/fingerprint-package-lint.ts b/packages/ghost/src/scan/fingerprint-package-lint.ts index 7fe07417..c772af76 100644 --- a/packages/ghost/src/scan/fingerprint-package-lint.ts +++ b/packages/ghost/src/scan/fingerprint-package-lint.ts @@ -80,7 +80,7 @@ export async function lintGhostPackage( await lintGlossary(paths.glossary, issues); lintCover(manifest.cover, catalog, issues); await lintKindPrefixes(paths, catalog, issues); - lintNodeContexts(catalog, issues); + lintNodeForPayloads(catalog, issues); lintSkeletonSections(catalog, issues); await lintMaterialLocators(paths, catalog, issues, cwd); lintCheckReferences(catalog, checks, issues); @@ -187,28 +187,20 @@ async function lintKindPrefixes( } /** - * `context` is a node's entire retrieval payload: `gather` lists it as the text - * the agent selects against. A node without one renders as a bare id and cannot - * show when it applies, so `validate` makes that loud. `description` remains a - * read alias for one release and produces a migration warning. + * `for` is a node's entire retrieval payload: `gather` lists it as the text + * the agent selects against. A node without one renders as a bare id and + * cannot show when it applies, so `validate` makes that loud. */ -function lintNodeContexts(catalog: GhostCatalog, issues: LintIssue[]): void { +function lintNodeForPayloads(catalog: GhostCatalog, issues: LintIssue[]): void { for (const node of catalog.nodes.values()) { - if (node.usesDeprecatedDescription) { - issues.push({ - severity: "warning", - rule: "node-description-deprecated", - message: - "node uses deprecated `description`; rename it to `context` (the retrieval payload shown by `gather`)", - path: `${node.id}.md.description`, - }); + if (node.for !== undefined && node.for.trim().length > 0) { + continue; } - if (node.context !== undefined && node.context.trim().length > 0) continue; issues.push({ severity: "warning", - rule: "node-context-missing", + rule: "node-for-missing", message: - "node has no `context`, so `gather` lists it as a bare id without applicability context; add one line naming the observable condition under which this node applies", + "node has no `for`, so `gather` lists it as a bare id without applicability context; add one line naming the situation or activity this guidance is for", path: `${node.id}.md`, }); } diff --git a/packages/ghost/src/skill-bundle/SKILL.md b/packages/ghost/src/skill-bundle/SKILL.md index c3eac0e4..74b24b5b 100644 --- a/packages/ghost/src/skill-bundle/SKILL.md +++ b/packages/ghost/src/skill-bundle/SKILL.md @@ -36,7 +36,7 @@ it applies, and an agent reads the relevant guidance before building. ## The model in one breath -- A **node** is a markdown file: `context`, optional `materials`, and prose brand guidance. `description` is a deprecated compatibility alias for one release. +- A **node** is a markdown file: a `for` payload, optional `materials`, and prose brand guidance. - `materials` is one list of locators for the concrete stuff the guidance is about: explicit repo-relative file paths or supported external locators (see [schema.md](references/schema.md)); name each file rather than diff --git a/packages/ghost/src/skill-bundle/references/ground.md b/packages/ghost/src/skill-bundle/references/ground.md index 45792f8e..e02a109f 100644 --- a/packages/ghost/src/skill-bundle/references/ground.md +++ b/packages/ghost/src/skill-bundle/references/ground.md @@ -14,7 +14,7 @@ Run `ghost gather ` with the real task, not a generic label. The cover is inlined by gather, so do not pull it separately. `gather` presents every available node; it does not filter or rank. Judge each -node's `context` against the actual task and pull what applies. When you are +node's `for` payload against the actual task and pull what applies. When you are uncertain whether a node applies, pull it. Under-pull is silent and unrecoverable; over-pull is mild dilution. Skip only clear non-matches. Topic overlap alone is not applicability. diff --git a/packages/ghost/src/skill-bundle/references/making.md b/packages/ghost/src/skill-bundle/references/making.md index 3e058fe5..61b5bdc2 100644 --- a/packages/ghost/src/skill-bundle/references/making.md +++ b/packages/ghost/src/skill-bundle/references/making.md @@ -17,7 +17,7 @@ judges, repairs, and reviews in the same session. ## Ground Follow [ground.md](ground.md), which ends with the anchor: gather with the real -ask, select against `context`, pull with an over-pull bias, and inspect decisive +ask, select against each node's `for` payload, pull with an over-pull bias, and inspect decisive materials before generating. Use this triage for material inspection: diff --git a/packages/ghost/src/skill-bundle/references/nodes.md b/packages/ghost/src/skill-bundle/references/nodes.md index e7cc9325..a1340a82 100644 --- a/packages/ghost/src/skill-bundle/references/nodes.md +++ b/packages/ghost/src/skill-bundle/references/nodes.md @@ -14,9 +14,10 @@ A node is one coherent decision with one applicability. Split only when a body contains another decision that should be gathered in a different situation. Do not split by destination or component name. -Use `context` as retrieval payload, not summary. State the observable situation -in which the node applies. Read it alone: if it fits every brand or almost every -task, it will not help selection. Put what to do and why in the body. +Use `for` as retrieval payload, not summary. State the situation or activity +the guidance is for, never an audience. Read it alone: if it fits every brand +or almost every task, it will not help selection. Put what to do and why in +the body. Altitude lives in prose: @@ -67,7 +68,7 @@ replacement. ```markdown --- -context: Building or reviewing a performance dashboard. +for: Building or reviewing a performance dashboard. --- Not rounded cards, celebratory gradients, and a wall of equal metrics. @@ -109,7 +110,7 @@ Before curation, ask: | Dimension | Question | | --- | --- | | Testimony | Can you name the human words or evidence behind this? | -| Discrimination | Does the context select a real situation rather than a topic? | +| Discrimination | Does the `for` payload select a real situation rather than a topic? | | Force | Does the body decide something and reject a plausible alternative? | | Altitude | Is it universal on purpose, or conditioned? | | Residue | Is it free of starter prose, API mirroring, and brand-deck filler? | @@ -121,7 +122,7 @@ canonical; human curation does. | If the agent keeps... | Author... | | --- | --- | -| missing guidance | sharper `context`; universal guidance may belong on the cover | +| missing guidance | sharper `for` payload; universal guidance may belong on the cover | | inventing values | a material-backed node with exact vocabulary | | producing generic output | replacement anti-goal plus a well-explained example | | choosing the wrong structure | bound/open pattern and, when needed, a Skeleton | @@ -134,5 +135,5 @@ canonical; human curation does. - Never write a node the human neither said, showed, nor accepted. - Never make a node a container for observations or implementation inventory. - Never duplicate API documentation unless the API itself is the guidance. -- Never use a broad context to compensate for unrelated decisions in one body. +- Never use a broad `for` payload to compensate for unrelated decisions in one body. - Never ship a blacklist-only anti-goal. diff --git a/packages/ghost/src/skill-bundle/references/schema.md b/packages/ghost/src/skill-bundle/references/schema.md index a2350b50..ceb501fd 100644 --- a/packages/ghost/src/skill-bundle/references/schema.md +++ b/packages/ghost/src/skill-bundle/references/schema.md @@ -38,7 +38,7 @@ segment. A bare filename has no kind. Undeclared kind prefixes warn. ```markdown --- -context: Placing, sizing, or choosing a logo lockup or glyph. +for: Placing, sizing, or choosing a logo lockup or glyph. materials: - brand/logo-primary.svg - https://figma.com/file/example?node-id=logo-lockups @@ -49,9 +49,8 @@ materials: Use the full lockup when recognition matters. ``` -- `context` is the retrieval payload shown by `ghost gather`. -- `description` remains a deprecated read alias for one release; validation - warns until it is renamed. +- `for` is the retrieval payload shown by `ghost gather`: the situation or + activity the guidance is for, never an audience. - `materials` accepts explicit repo-relative file paths and external locators using `https:`, `mcp:`, `figma:`, or `github:`. - Glob patterns are invalid. Each local file must be named explicitly. diff --git a/packages/ghost/src/skill-bundle/references/steering-audit.md b/packages/ghost/src/skill-bundle/references/steering-audit.md index 3003892d..fc34f1e8 100644 --- a/packages/ghost/src/skill-bundle/references/steering-audit.md +++ b/packages/ghost/src/skill-bundle/references/steering-audit.md @@ -30,13 +30,13 @@ Report first: - **Pull rate by concreteness:** concrete-material exposure/pull rate vs prose-only exposure/pull rate. In markdown this is the `Concrete material` row. This is the tuning instrument: if concrete nodes are not pulled when applicable, - contexts or task selection are failing. + `for` payloads or task selection are failing. ## Corpus-level table | Row | Status | Evidence | Next move | | --- | --- | --- | --- | -| Retrieval | strong / weak | contexts, ids, cover | sharpen contexts or move universal guidance to the cover | +| Retrieval | strong / weak | `for` payloads, ids, cover | sharpen `for` payloads or move universal guidance to the cover | | Concreteness | strong / thin | materials, fenced examples, Skeletons | add concrete locators, examples, or opening structures | | Anti-goals | present / missing / vague | `anti-goal.*`, review packet | write not-X-instead-Y replacements and material locators | | Consistency | clean / conflicting | guidance vs concrete material | update or remove stale material | diff --git a/packages/ghost/test/cli-exit.test.ts b/packages/ghost/test/cli-exit.test.ts index 09498a88..3c833c84 100644 --- a/packages/ghost/test/cli-exit.test.ts +++ b/packages/ghost/test/cli-exit.test.ts @@ -156,12 +156,12 @@ async function writeLargePullFixture(dir: string): Promise { "", ].join("\n"), ), - writeFile(join(ghost, "index.md"), "---\ncontext: Cover.\n---\n\nCover.\n"), + writeFile(join(ghost, "index.md"), "---\nfor: Cover.\n---\n\nCover.\n"), writeFile( join(ghost, "principle.long.md"), [ "---", - "context: Large pull body.", + "for: Large pull body.", "---", "", "x".repeat(2 * 1024 * 1024), diff --git a/packages/ghost/test/cli.test.ts b/packages/ghost/test/cli.test.ts index 649c947a..c8e3152a 100644 --- a/packages/ghost/test/cli.test.ts +++ b/packages/ghost/test/cli.test.ts @@ -32,11 +32,11 @@ async function writeBareTestPackage(dir: string): Promise { ), writeFile( join(packageDir, "index.md"), - "---\ncontext: Test package cover.\n---\n\nTest package.\n", + "---\nfor: Test package cover.\n---\n\nTest package.\n", ), writeFile( join(packageDir, "cliche.median.md"), - "---\ncontext: Test cliche floor.\n---\n\nAvoid generic defaults.\n", + "---\nfor: Test cliche floor.\n---\n\nAvoid generic defaults.\n", ), ]); } @@ -595,8 +595,7 @@ describe("ghost CLI", () => { nodes: 9, concrete: 0, payloads: { materials: 0, fencedExamples: 0, skeletons: 0 }, - withoutContext: 0, - undescribed: 0, + withoutFor: 0, }); }); @@ -746,15 +745,15 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - missing.css\n---\n\nUse exact tokens.\n", + "---\nfor: Tokens.\nmaterials:\n - missing.css\n---\n\nUse exact tokens.\n", ); await writeFile( join(dir, ".ghost", "principle.rule.md"), - "---\ncontext: Rule.\n---\n\nPlain rule.\n", + "---\nfor: Rule.\n---\n\nPlain rule.\n", ); await writeFile( join(dir, ".ghost", "anti-goal.generic.md"), - "---\ncontext: Generic replacement.\n---\n\nNot vague; instead exact.\n", + "---\nfor: Generic replacement.\n---\n\nNot vague; instead exact.\n", ); // The seeded cover (`index`) is inlined above the menu, not counted in it. @@ -764,17 +763,16 @@ describe("ghost CLI", () => { nodes: 4, concrete: 1, payloads: { materials: 1, fencedExamples: 0, skeletons: 0 }, - withoutContext: 0, - undescribed: 0, + withoutFor: 0, }); const markdown = await runCli(["gather"], dir); expect(markdown.stdout).toContain( "4 nodes · 1 carry payloads (1 with materials, 0 with substantial fenced examples, 0 with Skeletons)", ); - // No withoutContext nodes: the coverage line stays quiet about them. - expect(markdown.stdout).not.toContain("lack context"); + // No nodes lacking `for`: the coverage line stays quiet about them. + expect(markdown.stdout).not.toContain("lack `for` payloads"); - // A node without context is invisible to selection — the coverage + // A node without a `for` payload is invisible to selection — the coverage // line says so, and validate warns on it. await writeFile( join(dir, ".ghost", "principle.mute.md"), @@ -782,11 +780,10 @@ describe("ghost CLI", () => { ); const gatherMute = await runCli(["gather"], dir); expect(gatherMute.stdout).toContain( - "5 nodes · 1 carry payloads (1 with materials, 0 with substantial fenced examples, 0 with Skeletons) · 1 lack context", + "5 nodes · 1 carry payloads (1 with materials, 0 with substantial fenced examples, 0 with Skeletons) · 1 lack `for` payloads", ); const gatherMuteJson = await runCli(["gather", "--format", "json"], dir); - expect(JSON.parse(gatherMuteJson.stdout).coverage.withoutContext).toBe(1); - expect(JSON.parse(gatherMuteJson.stdout).coverage.undescribed).toBe(1); + expect(JSON.parse(gatherMuteJson.stdout).coverage.withoutFor).toBe(1); const steering = await runCli( ["pull", "principle.rule", "asset.tokens"], @@ -812,7 +809,7 @@ describe("ghost CLI", () => { join(dir, ".ghost", "asset.tokens.md"), [ "---", - "context: Token material.", + "for: Token material.", "materials:", " - materials/tokens.css", "---", @@ -825,7 +822,7 @@ describe("ghost CLI", () => { join(dir, ".ghost", "copy.md"), [ "---", - "context: Copy sample.", + "for: Copy sample.", "---", "", "```txt", @@ -840,7 +837,7 @@ describe("ghost CLI", () => { join(dir, ".ghost", "pattern.card.md"), [ "---", - "context: Card pattern.", + "for: Card pattern.", "---", "", "## Skeleton", @@ -891,11 +888,11 @@ describe("ghost CLI", () => { await writeBareTestPackage(dir); await writeFile( join(dir, ".ghost", "pattern.card.md"), - "---\ncontext: Card pattern.\n---\n\nPattern prose.\n\n## Skeleton\n\n```tsx\n
{children}
\n```\n\nAfter skeleton should be stripped.\n", + "---\nfor: Card pattern.\n---\n\nPattern prose.\n\n## Skeleton\n\n```tsx\n
{children}
\n```\n\nAfter skeleton should be stripped.\n", ); await writeFile( join(dir, ".ghost", "pattern.bad.md"), - "---\ncontext: Bad skeleton.\n---\n\n## Skeleton\n\nNo fence here.\n", + "---\nfor: Bad skeleton.\n---\n\n## Skeleton\n\nNo fence here.\n", ); const pull = await runCli(["pull", "pattern.card"], dir); @@ -936,7 +933,7 @@ describe("ghost CLI", () => { join(dir, ".ghost", "pattern.safe.md"), [ "---", - "context: Fence safety.", + "for: Fence safety.", "materials:", " - brand/example.md", "---", @@ -987,7 +984,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.hostile.md"), - "---\ncontext: Hostile material.\nmaterials:\n - brand/hostile.md\n---\n\nRead the material.\n", + "---\nfor: Hostile material.\nmaterials:\n - brand/hostile.md\n---\n\nRead the material.\n", ); const pull = await runCli(["pull", "asset.hostile"], dir); @@ -1009,7 +1006,7 @@ describe("ghost CLI", () => { await writeFile(join(dir, "brand", "mark.png"), Buffer.from([0, 1, 2])); await writeFile( join(dir, ".ghost", "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - brand/mark.png\n---\n\nInspect the blessed mark.\n", + "---\nfor: Logo.\nmaterials:\n - brand/mark.png\n---\n\nInspect the blessed mark.\n", ); const md = await runCli(["pull", "asset.logo"], dir); @@ -1031,11 +1028,11 @@ describe("ghost CLI", () => { await runCli(["init"], dir); await writeFile( join(dir, ".ghost", "principle.trust.md"), - "---\ncontext: Trust at the payment moment.\n---\n\nNear payment, reduce felt risk.\n", + "---\nfor: Trust at the payment moment.\n---\n\nNear payment, reduce felt risk.\n", ); await writeFile( join(dir, ".ghost", "voice.md"), - "---\ncontext: The brand voice.\n---\n\nPlain words. No hype.\n", + "---\nfor: The brand voice.\n---\n\nPlain words. No hype.\n", ); const gather = await runCli( @@ -1079,7 +1076,7 @@ describe("ghost CLI", () => { expect(pull.stdout).toContain("Near payment, reduce felt risk."); expect(pull.stdout).toContain("Plain words. No hype."); - // JSON format carries id, kind, context, and body. + // JSON format carries id, kind, for, and body. const json = await runCli( ["pull", "principle.trust", "--format", "json"], dir, @@ -1090,7 +1087,7 @@ describe("ghost CLI", () => { expect(payload.nodes[0]).toMatchObject({ id: "principle.trust", kind: "principle", - context: "Trust at the payment moment.", + for: "Trust at the payment moment.", }); expect(payload.nodes[0].body).toContain("reduce felt risk"); @@ -1174,7 +1171,7 @@ describe("ghost CLI", () => { await writeFile(join(dir, "brand", "large.txt"), "x".repeat(8 * 1024 + 1)); await writeFile( join(dir, ".ghost", "asset.materials.md"), - "---\ncontext: Materials.\nmaterials:\n - locator: materials/tokens.css\n note: Canonical token values\n - brand/voice.txt\n - brand/mark.bin\n - brand/large.txt\n - https://example.com/brand-kit\n - locator: mcp://brand-assets/brand-kit\n note: Approved source artwork\n---\n\nRead these materials.\n", + "---\nfor: Materials.\nmaterials:\n - locator: materials/tokens.css\n note: Canonical token values\n - brand/voice.txt\n - brand/mark.bin\n - brand/large.txt\n - https://example.com/brand-kit\n - locator: mcp://brand-assets/brand-kit\n note: Approved source artwork\n---\n\nRead these materials.\n", ); const md = await runCli(["pull", "asset.materials"], dir); @@ -1235,7 +1232,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nToken prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nToken prose.\n", ); const md = await runCli(["pull", "asset.tokens", "--no-materials"], dir); @@ -1266,7 +1263,7 @@ describe("ghost CLI", () => { await writeFile(join(dir, "brand", "voice.txt"), "Plain.\n"); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n - brand/voice.txt\n - locator: mcp://brand-assets/tokens\n note: Canonical token source\n---\n\nToken prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n - brand/voice.txt\n - locator: mcp://brand-assets/tokens\n note: Canonical token source\n---\n\nToken prose.\n", ); const json = await runCli( @@ -1307,7 +1304,7 @@ describe("ghost CLI", () => { await writeFile(join(dir, "brand", "samples", "b.txt"), "sample b\n"); await writeFile( join(dir, ".ghost", "asset.samples.md"), - "---\ncontext: Samples.\nmaterials:\n - brand/samples/a.txt\n - brand/samples/b.txt\n---\n\nSample prose.\n", + "---\nfor: Samples.\nmaterials:\n - brand/samples/a.txt\n - brand/samples/b.txt\n---\n\nSample prose.\n", ); const json = await runCli( @@ -1345,11 +1342,11 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.first.md"), - "---\ncontext: First.\nmaterials:\n - materials/shared.css\n---\n\nFirst prose.\n", + "---\nfor: First.\nmaterials:\n - materials/shared.css\n---\n\nFirst prose.\n", ); await writeFile( join(dir, ".ghost", "asset.second.md"), - "---\ncontext: Second.\nmaterials:\n - materials/shared.css\n---\n\nSecond prose.\n", + "---\nfor: Second.\nmaterials:\n - materials/shared.css\n---\n\nSecond prose.\n", ); const json = await runCli( @@ -1383,7 +1380,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nToken prose.\n\n## Skeleton\n\n```css\n:root { }\n```\n\nStrip me.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nToken prose.\n\n## Skeleton\n\n```css\n:root { }\n```\n\nStrip me.\n", ); const snapshot = await loadGhostSnapshot( @@ -1408,7 +1405,7 @@ describe("ghost CLI", () => { ); expect(cliPull.nodes[0]).toMatchObject({ id: embedPull.nodes[0].id, - context: embedPull.nodes[0].context, + for: embedPull.nodes[0].for, body: embedPull.nodes[0].body, }); expect(cliPull.nodes[0].materials).toEqual( @@ -1428,7 +1425,7 @@ describe("ghost CLI", () => { await runCli(["init"], dir); await writeFile( join(dir, ".ghost", "principle.trust.md"), - "---\ncontext: Trust.\n---\n\nBody.\n", + "---\nfor: Trust.\n---\n\nBody.\n", ); const partial = await runCli( @@ -1502,11 +1499,11 @@ describe("ghost CLI", () => { await writeBareTestPackage(dir); await writeFile( join(dir, ".ghost", "principle.trust.md"), - "---\ncontext: Trust.\n---\n\nBody.\n", + "---\nfor: Trust.\n---\n\nBody.\n", ); await writeFile( join(dir, ".ghost", "voice.md"), - "---\ncontext: Voice.\n---\n\nPlain.\n", + "---\nfor: Voice.\n---\n\nPlain.\n", ); await runCli(["gather", "checkout"], dir); @@ -1682,7 +1679,7 @@ describe("ghost CLI", () => { await mkdir(checksDir, { recursive: true }); await writeFile( join(dir, ".ghost", "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - brand/logo.svg\n - https://example.com/logo\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - brand/logo.svg\n - https://example.com/logo\n---\n\nLogo prose.\n", ); await writeFile( join(checksDir, "secret-check.md"), @@ -1744,7 +1741,7 @@ describe("ghost CLI", () => { await runCli(["init", "--with", "checks"], dir); await writeFile( join(dir, ".ghost", "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - locator: brand/logo.svg\n note: Use the approved clearspace source\n - brand/icon.svg\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - locator: brand/logo.svg\n note: Use the approved clearspace source\n - brand/icon.svg\n---\n\nLogo prose.\n", ); await writeFile( join(dir, ".ghost", "checks", "logo-clearspace.md"), @@ -1805,7 +1802,7 @@ describe("ghost CLI", () => { await runCli(["init", "--with", "checks"], dir); await writeFile( join(dir, ".ghost", "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - brand/logo.svg\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - brand/logo.svg\n---\n\nLogo prose.\n", ); await writeFile( join(dir, ".ghost", "checks", "logo-clearspace.md"), @@ -1849,7 +1846,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, packageDir, "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nTokens prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nTokens prose.\n", ); await mkdir(join(dir, packageDir, "checks"), { recursive: true }); await writeFile( @@ -1891,7 +1888,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "anti-goal.generic-logo.md"), - "---\ncontext: Replace generic marks.\nmaterials:\n - brand/logo.svg\n---\n\nNot a stock spark; instead use the wordmark and measured clearspace.\n", + "---\nfor: Replace generic marks.\nmaterials:\n - brand/logo.svg\n---\n\nNot a stock spark; instead use the wordmark and measured clearspace.\n", ); await writeFile( join(dir, ".ghost", "checks", "unrelated.md"), @@ -1925,7 +1922,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n - https://example.com/tokens\n - mcp://brand-assets/tokens\n---\n\nToken prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n - https://example.com/tokens\n - mcp://brand-assets/tokens\n---\n\nToken prose.\n", ); const out = join(dir, "brand.tgz"); @@ -1984,7 +1981,7 @@ describe("ghost CLI", () => { await writeFile(join(dir, "brand", "voice.txt"), "Plain.\n"); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n - brand/voice.txt\n - https://example.com/tokens\n - figma://file/abc\n---\n\nToken prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n - brand/voice.txt\n - https://example.com/tokens\n - figma://file/abc\n---\n\nToken prose.\n", ); const result = await runCli(["export", "--format", "json"], dir); @@ -2024,7 +2021,7 @@ describe("ghost CLI", () => { await writeBareTestPackage(dir); await writeFile( join(dir, ".ghost", "asset.remote.md"), - "---\ncontext: Remote material.\nmaterials:\n - mcp://brand-assets/tokens\n - figma://file/abc\n - github:acme/brand-assets\n---\n\nRemote prose.\n", + "---\nfor: Remote material.\nmaterials:\n - mcp://brand-assets/tokens\n - figma://file/abc\n - github:acme/brand-assets\n---\n\nRemote prose.\n", ); const result = await runCli(["export", "--strict"], dir); @@ -2048,7 +2045,7 @@ describe("ghost CLI", () => { await writeBareTestPackage(dir); await writeFile( join(dir, ".ghost", "asset.voice.md"), - "---\ncontext: Voice.\nmaterials:\n - brand/voice.txt\n---\n\nVoice prose.\n", + "---\nfor: Voice.\nmaterials:\n - brand/voice.txt\n---\n\nVoice prose.\n", ); const result = await runCli(["export", "--strict"], dir); @@ -2067,7 +2064,7 @@ describe("ghost CLI", () => { ); await writeFile( join(dir, ".ghost", "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nToken prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/tokens.css\n---\n\nToken prose.\n", ); const out = join(dir, "portable.tgz"); await runCli(["export", "--out", out], dir); @@ -2254,15 +2251,15 @@ async function writeGatherPackage(dir: string): Promise { // Directories are a browsing convenience only; ids are paths minus .md. await writeFile( join(ghost, "index.md"), - "---\ncontext: Brand voice.\n---\n\nWarm and concise.\n", + "---\nfor: Brand voice.\n---\n\nWarm and concise.\n", ); await writeFile( join(ghost, "email", "index.md"), - "---\ncontext: Email surface.\n---\n\nEmail.\n", + "---\nfor: Email surface.\n---\n\nEmail.\n", ); await writeFile( join(ghost, "email", "marketing", "index.md"), - "---\ncontext: Marketing email.\n---\n\nMarketing may use urgency.\n", + "---\nfor: Marketing email.\n---\n\nMarketing may use urgency.\n", ); await writeFile( join(ghost, "checkout", "clarity.md"), diff --git a/packages/ghost/test/embed.test.ts b/packages/ghost/test/embed.test.ts index b19eb41c..cc06086b 100644 --- a/packages/ghost/test/embed.test.ts +++ b/packages/ghost/test/embed.test.ts @@ -45,7 +45,7 @@ async function writePackage(dir: string): Promise { ); await writeFile( join(dir, ".ghost", "cover.md"), - "---\ncontext: Cover.\n---\n\nSilence posture.\n", + "---\nfor: Cover.\n---\n\nSilence posture.\n", ); await writeFile(join(dir, ".ghost", "materials", "tokens.css"), ":root{}\n"); await writeFile(join(dir, "brand", "voice.txt"), "Plain.\n"); @@ -57,7 +57,7 @@ async function writePackage(dir: string): Promise { join(dir, ".ghost", "asset.tokens.md"), [ "---", - "context: Tokens.", + "for: Tokens.", "materials:", " - materials/tokens.css", " - brand/voice.txt", @@ -81,7 +81,7 @@ async function writePackage(dir: string): Promise { ); await writeFile( join(dir, ".ghost", "principle.rule.md"), - "---\ncontext: Rule.\n---\n\nRule prose.\n", + "---\nfor: Rule.\n---\n\nRule prose.\n", ); await mkdir(join(dir, ".ghost", "checks"), { recursive: true }); await writeFile( @@ -150,8 +150,7 @@ describe("embed contract", () => { nodes: 2, concrete: 1, payloads: { materials: 1, fencedExamples: 0, skeletons: 1 }, - withoutContext: 0, - undescribed: 0, + withoutFor: 0, }); expect(result.kinds).toContainEqual({ name: "asset", @@ -418,11 +417,11 @@ describe("embed contract", () => { await writePackage(dir); await writeFile( join(dir, ".ghost", "asset.traversal.md"), - "---\ncontext: Traversal.\nmaterials:\n - ../outside.txt\n---\n\nTraversal prose.\n", + "---\nfor: Traversal.\nmaterials:\n - ../outside.txt\n---\n\nTraversal prose.\n", ); await writeFile( join(dir, ".ghost", "asset.absolute.md"), - `---\ncontext: Absolute.\nmaterials:\n - ${join(dir, "brand", "voice.txt")}\n---\n\nAbsolute prose.\n`, + `---\nfor: Absolute.\nmaterials:\n - ${join(dir, "brand", "voice.txt")}\n---\n\nAbsolute prose.\n`, ); const baseSnapshot = await loadGhostSnapshot( resolveGhostPackage(undefined, dir), @@ -493,7 +492,7 @@ describe("embed contract", () => { ); await writeFile( join(dir, ".ghost", "asset.escape.md"), - "---\ncontext: Escape.\nmaterials:\n - brand/escape.txt\n---\n\nEscape prose.\n", + "---\nfor: Escape.\nmaterials:\n - brand/escape.txt\n---\n\nEscape prose.\n", ); try { const snapshot = await loadGhostSnapshot( diff --git a/packages/ghost/test/fingerprint-package.test.ts b/packages/ghost/test/fingerprint-package.test.ts index 2b35a432..c8264a27 100644 --- a/packages/ghost/test/fingerprint-package.test.ts +++ b/packages/ghost/test/fingerprint-package.test.ts @@ -58,7 +58,7 @@ describe("ghost package", () => { await mkdir(join(dir, "checkout"), { recursive: true }); await writeFile( join(dir, "checkout", "principle.trust.md"), - "---\ncontext: Trust at the payment moment.\n---\n\nReduce felt risk near payment.\n", + "---\nfor: Trust at the payment moment.\n---\n\nReduce felt risk near payment.\n", ); const loaded = await loadGhostPackage(resolveGhostPackage(dir)); @@ -66,7 +66,7 @@ describe("ghost package", () => { // id is the path; kind/slug come from the filename. const authored = loaded.catalog.nodes.get("checkout/principle.trust"); expect(authored?.body).toBe("Reduce felt risk near payment."); - expect(authored?.context).toBe("Trust at the payment moment."); + expect(authored?.for).toBe("Trust at the payment moment."); expect(authored?.kind).toBe("principle"); expect(authored?.slug).toBe("trust"); }); @@ -78,7 +78,7 @@ describe("ghost package", () => { // while loading, but must not vanish silently. await writeFile( join(dir, "features", "index.md"), - "---\ncontext: All feature UI.\nrelates:\n - to: core\n---\n\nFeature prose.\n", + "---\nfor: All feature UI.\nrelates:\n - to: core\n---\n\nFeature prose.\n", ); const loaded = await loadGhostPackage(resolveGhostPackage(dir)); @@ -131,7 +131,7 @@ Replacement rule. await writeGlossary(dir, ["principle"]); await writeFile( join(dir, "principle.density.md"), - "---\ncontext: Density stance.\n---\n\nUse density deliberately.\n", + "---\nfor: Density stance.\n---\n\nUse density deliberately.\n", ); const report = await lintGhostPackage(dir); @@ -149,7 +149,7 @@ Replacement rule. await writeGlossary(dir, ["principle"]); await writeFile( join(dir, "voice.md"), - "---\ncontext: Voice.\n---\n\nSpeak plainly.\n", + "---\nfor: Voice.\n---\n\nSpeak plainly.\n", ); const report = await lintGhostPackage(dir); @@ -162,7 +162,7 @@ Replacement rule. ); }); - it("warns when a node has no context", async () => { + it("warns when a node has no for payload", async () => { await writeManifest(dir); await writeGlossary(dir, ["principle"]); await writeFile( @@ -173,71 +173,60 @@ Replacement rule. const report = await lintGhostPackage(dir); expect(report.errors).toBe(0); - // Undeclared cover + missing context. + // Undeclared cover + missing `for`. expect(report.warnings).toBe(2); expect(report.issues).toContainEqual( expect.objectContaining({ severity: "warning", - rule: "node-context-missing", + rule: "node-for-missing", path: "principle.density.md", }), ); }); - it("reads deprecated description as context and warns to migrate", async () => { + it("rejects the context key and points to `for`", async () => { await writeManifest(dir); await writeGlossary(dir, ["principle"]); await writeFile( join(dir, "principle.density.md"), - "---\ndescription: Density stance.\n---\n\nUse density deliberately.\n", - ); - - const loaded = await loadGhostPackage(resolveGhostPackage(dir)); - expect(loaded.catalog.nodes.get("principle.density")?.context).toBe( - "Density stance.", + "---\ncontext: Density stance.\n---\n\nUse density deliberately.\n", ); const report = await lintGhostPackage(dir); - expect(report.errors).toBe(0); - expect(report.issues).toContainEqual( - expect.objectContaining({ - severity: "warning", - rule: "node-description-deprecated", - path: "principle.density.md.description", - }), - ); - expect(report.issues).not.toContainEqual( - expect.objectContaining({ rule: "node-context-missing" }), - ); + expect(report.errors).toBeGreaterThan(0); + expect( + report.issues.some((issue) => issue.message.includes("use `for`")), + ).toBe(true); }); - it("prefers context when context and deprecated description coexist", async () => { + it("rejects the description key and points to `for`", async () => { await writeManifest(dir); await writeGlossary(dir, ["principle"]); await writeFile( join(dir, "principle.density.md"), - "---\ncontext: Canonical context.\ndescription: Legacy context.\n---\n\nUse density deliberately.\n", + "---\ndescription: Density stance.\n---\n\nUse density deliberately.\n", ); - const loaded = await loadGhostPackage(resolveGhostPackage(dir)); - expect(loaded.catalog.nodes.get("principle.density")?.context).toBe( - "Canonical context.", - ); + const report = await lintGhostPackage(dir); + expect(report.errors).toBeGreaterThan(0); + expect( + report.issues.some((issue) => issue.message.includes("use `for`")), + ).toBe(true); }); - it("does not warn about context when every node has one", async () => { + it("does not warn about for payloads when every node has one", async () => { await writeManifest(dir); await writeGlossary(dir, ["principle"]); await writeFile( join(dir, "principle.density.md"), - "---\ncontext: Density stance.\n---\n\nUse density deliberately.\n", + "---\nfor: Density stance.\n---\n\nUse density deliberately.\n", ); const report = await lintGhostPackage(dir); expect(report.errors).toBe(0); expect(report.issues).not.toContainEqual( - expect.objectContaining({ rule: "node-context-missing" }), + expect.objectContaining({ rule: "node-for-missing" }), ); }); @@ -246,7 +235,7 @@ Replacement rule. await writeGlossary(dir, ["principle"]); await writeFile( join(dir, "principles.density.md"), - "---\ncontext: Density stance.\n---\n\nUse density deliberately.\n", + "---\nfor: Density stance.\n---\n\nUse density deliberately.\n", ); const report = await lintGhostPackage(dir); @@ -270,7 +259,7 @@ Replacement rule. await writeManifest(dir); await writeFile( join(dir, "principles.density.md"), - "---\ncontext: Density stance.\n---\n\nUse density deliberately.\n", + "---\nfor: Density stance.\n---\n\nUse density deliberately.\n", ); const report = await lintGhostPackage(dir); @@ -287,7 +276,7 @@ Replacement rule. await writeManifest(dir); await writeFile( join(dir, "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - brand/logo.svg\n - https://example.com/logo\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - brand/logo.svg\n - https://example.com/logo\n---\n\nLogo prose.\n", ); const loaded = await loadGhostPackage(resolveGhostPackage(dir)); @@ -303,7 +292,7 @@ Replacement rule. await mkdir(join(dir, "materials"), { recursive: true }); await writeFile( join(dir, "materials", "asset.logo.md"), - "---\ncontext: Bundled material.\n---\n\nNot a node.\n", + "---\nfor: Bundled material.\n---\n\nNot a node.\n", ); const loadedFiles = await loadNodeFiles(dir); @@ -328,7 +317,7 @@ Replacement rule. await writeFile(join(dir, "materials", "orphan.txt"), "orphan\n"); await writeFile( join(dir, "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - materials/claimed.txt\n - missing/logo.svg\n - https://example.com/logo.svg\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - materials/claimed.txt\n - missing/logo.svg\n - https://example.com/logo.svg\n---\n\nLogo prose.\n", ); const report = await lintGhostPackage(dir, dir); @@ -362,7 +351,7 @@ Replacement rule. await writeFile(join(dir, "materials", "tokens.css"), ":root {}\n"); await writeFile( join(dir, "asset.tokens.md"), - "---\ncontext: Tokens.\nmaterials:\n - materials/*.css\n---\n\nToken prose.\n", + "---\nfor: Tokens.\nmaterials:\n - materials/*.css\n---\n\nToken prose.\n", ); const report = await lintGhostPackage(dir, dir); @@ -386,7 +375,7 @@ Replacement rule. await writeManifest(dir); await writeFile( join(dir, "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - /absolute/logo.svg\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - /absolute/logo.svg\n---\n\nLogo prose.\n", ); const report = await lintGhostPackage(dir); @@ -402,7 +391,7 @@ Replacement rule. await writeManifest(dir); await writeFile( join(dir, "asset.logo.md"), - "---\ncontext: Logo.\nmaterials:\n - brand/logo.svg\n---\n\nLogo prose.\n", + "---\nfor: Logo.\nmaterials:\n - brand/logo.svg\n---\n\nLogo prose.\n", ); await writeChecks(dir, [ [ @@ -447,12 +436,12 @@ Replacement rule. await writeManifest(dir); await writeFile( join(dir, "index.md"), - "---\ncontext: The package cover and coverage map.\n---\n\nFront door prose.\n", + "---\nfor: The package cover and coverage map.\n---\n\nFront door prose.\n", ); await mkdir(join(dir, "email"), { recursive: true }); await writeFile( join(dir, "email", "index.md"), - "---\ncontext: Email surface.\n---\n\nEmail.\n", + "---\nfor: Email surface.\n---\n\nEmail.\n", ); const loaded = await loadGhostPackage(resolveGhostPackage(dir)); diff --git a/packages/ghost/test/ghost-core/node-schema.test.ts b/packages/ghost/test/ghost-core/node-schema.test.ts index 5272154b..fe9156ae 100644 --- a/packages/ghost/test/ghost-core/node-schema.test.ts +++ b/packages/ghost/test/ghost-core/node-schema.test.ts @@ -43,41 +43,30 @@ describe("ghost.node/v1 schema", () => { expect(lintGhostNode(node("audience: enterprise")).errors).toBe(0); }); - it("accepts context (the retrieval payload)", () => { - expect(lintGhostNode(node("context: Lifecycle email.")).errors).toBe(0); + it("accepts for (the retrieval payload)", () => { + expect(lintGhostNode(node("for: Lifecycle email.")).errors).toBe(0); }); - it("accepts description as a deprecated read alias", () => { - const parsed = parseNode(node("description: Lifecycle email.")); - expect(parsed.report.errors).toBe(0); - expect(parsed.node?.frontmatter.description).toBe("Lifecycle email."); - }); - - it("serializes the deprecated description alias as context", () => { - const serialized = serializeNode({ - frontmatter: { description: "Lifecycle email." }, - body: "Send only when useful.", - }); - expect(serialized).toContain("context: Lifecycle email."); - expect(serialized).not.toContain("description:"); + it("rejects the context key and points to `for`", () => { + const report = lintGhostNode(node("context: Lifecycle email.")); + expect(report.errors).toBeGreaterThan(0); + expect( + report.issues.some((issue) => issue.message.includes("use `for`")), + ).toBe(true); }); - it("prefers context when both keys are present", () => { - const serialized = serializeNode({ - frontmatter: { - context: "Canonical retrieval payload.", - description: "Legacy retrieval payload.", - }, - body: "Body.", - }); - expect(serialized).toContain("context: Canonical retrieval payload."); - expect(serialized).not.toContain("Legacy retrieval payload."); + it("rejects the description key and points to `for`", () => { + const report = lintGhostNode(node("description: Lifecycle email.")); + expect(report.errors).toBeGreaterThan(0); + expect( + report.issues.some((issue) => issue.message.includes("use `for`")), + ).toBe(true); }); it("round-trips through serialize/parse (frontmatter is properties only)", () => { const original: GhostNodeDocument = { frontmatter: { - context: "Near payment, reduce felt risk.", + for: "Near payment, reduce felt risk.", }, body: "Near payment, reduce felt risk.", }; @@ -90,7 +79,7 @@ describe("ghost.node/v1 schema", () => { it("round-trips complete frontmatter through serialize/parse", () => { const original = { frontmatter: { - context: "Checkout trust signals.", + for: "Checkout trust signals.", materials: [ "src/components/checkout/trust-signals.tsx", "https://example.com/logo.svg", @@ -181,7 +170,7 @@ describe("ghost.node/v1 schema", () => { const serialized = serializeNode({ frontmatter: { stage: "purchase", - context: "Checkout trust signals.", + for: "Checkout trust signals.", audience: "enterprise", materials: ["src/components/checkout/**"], }, @@ -190,7 +179,7 @@ describe("ghost.node/v1 schema", () => { expect(serialized).toMatchInlineSnapshot(` "--- - context: Checkout trust signals. + for: Checkout trust signals. materials: - src/components/checkout/** audience: enterprise diff --git a/packages/vessel-light/.ghost/anti-goal.median.md b/packages/vessel-light/.ghost/anti-goal.median.md index 887590ac..302393f7 100644 --- a/packages/vessel-light/.ghost/anti-goal.median.md +++ b/packages/vessel-light/.ghost/anti-goal.median.md @@ -1,5 +1,5 @@ --- -context: Any greenfield visual surface or first-draft copy. +for: Any greenfield visual surface or first-draft copy. --- This is the model's median, not your brand. Each rule is reject→replace. diff --git a/packages/vessel-light/.ghost/anti-goal.tells.md b/packages/vessel-light/.ghost/anti-goal.tells.md index 52e42655..d3e5bc6d 100644 --- a/packages/vessel-light/.ghost/anti-goal.tells.md +++ b/packages/vessel-light/.ghost/anti-goal.tells.md @@ -1,5 +1,5 @@ --- -context: Any work applying this brand's signature. +for: Any work applying this brand's signature. --- These are the near-misses of Vessel's own signature: outputs that got close diff --git a/packages/vessel-light/.ghost/grammar.color-roles.md b/packages/vessel-light/.ghost/grammar.color-roles.md index 4963c748..29d0280c 100644 --- a/packages/vessel-light/.ghost/grammar.color-roles.md +++ b/packages/vessel-light/.ghost/grammar.color-roles.md @@ -1,5 +1,5 @@ --- -context: Choosing or applying color. +for: Choosing or applying color. materials: - materials/tokens.css --- diff --git a/packages/vessel-light/.ghost/grammar.conversation.md b/packages/vessel-light/.ghost/grammar.conversation.md index ad8cb2f4..253b5ba2 100644 --- a/packages/vessel-light/.ghost/grammar.conversation.md +++ b/packages/vessel-light/.ghost/grammar.conversation.md @@ -1,5 +1,5 @@ --- -context: Any AI thread, agent console, review assistant, or prompt composer. +for: Any AI thread, agent console, review assistant, or prompt composer. materials: - materials/examples/composition.conversation.html --- diff --git a/packages/vessel-light/.ghost/grammar.deletion.md b/packages/vessel-light/.ghost/grammar.deletion.md index e314c7e4..bd5ed3bc 100644 --- a/packages/vessel-light/.ghost/grammar.deletion.md +++ b/packages/vessel-light/.ghost/grammar.deletion.md @@ -1,5 +1,5 @@ --- -context: The final pass over any composition, or whenever a view feels crowded, busy, or dressed up. +for: The final pass over any composition, or whenever a view feels crowded, busy, or dressed up. --- Restraint is not a mood; it is a test every element has to pass. Before a diff --git a/packages/vessel-light/.ghost/grammar.hierarchy.md b/packages/vessel-light/.ghost/grammar.hierarchy.md index 456b1ca2..63a9b57b 100644 --- a/packages/vessel-light/.ghost/grammar.hierarchy.md +++ b/packages/vessel-light/.ghost/grammar.hierarchy.md @@ -1,5 +1,5 @@ --- -context: Any view containing text or actions. +for: Any view containing text or actions. materials: - materials/primitives.css - materials/examples/composition.form.html diff --git a/packages/vessel-light/.ghost/grammar.job.md b/packages/vessel-light/.ghost/grammar.job.md index 35476030..fc6d3d51 100644 --- a/packages/vessel-light/.ghost/grammar.job.md +++ b/packages/vessel-light/.ghost/grammar.job.md @@ -1,5 +1,5 @@ --- -context: Any new view before its structure or register is chosen. +for: Any new view before its structure or register is chosen. materials: - materials/examples/composition.form.html - materials/examples/composition.table.html diff --git a/packages/vessel-light/.ghost/grammar.motion.md b/packages/vessel-light/.ghost/grammar.motion.md index 3d4b280f..141e0770 100644 --- a/packages/vessel-light/.ghost/grammar.motion.md +++ b/packages/vessel-light/.ghost/grammar.motion.md @@ -1,5 +1,5 @@ --- -context: Any transition, animation, or hover treatment. +for: Any transition, animation, or hover treatment. materials: - materials/tokens.css --- diff --git a/packages/vessel-light/.ghost/grammar.rhythm.md b/packages/vessel-light/.ghost/grammar.rhythm.md index 100672bb..2cc4c92e 100644 --- a/packages/vessel-light/.ghost/grammar.rhythm.md +++ b/packages/vessel-light/.ghost/grammar.rhythm.md @@ -1,5 +1,5 @@ --- -context: Laying out any view. +for: Laying out any view. materials: - materials/primitives.css --- diff --git a/packages/vessel-light/.ghost/grammar.surfaces.md b/packages/vessel-light/.ghost/grammar.surfaces.md index aa19a13c..0393d2f1 100644 --- a/packages/vessel-light/.ghost/grammar.surfaces.md +++ b/packages/vessel-light/.ghost/grammar.surfaces.md @@ -1,5 +1,5 @@ --- -context: Any card, popover, modal, dialog, scrim, or bordered container. +for: Any card, popover, modal, dialog, scrim, or bordered container. materials: - materials/primitives.css - materials/examples/composition.overlay.html diff --git a/packages/vessel-light/.ghost/index.md b/packages/vessel-light/.ghost/index.md index 37b9a371..d94320e9 100644 --- a/packages/vessel-light/.ghost/index.md +++ b/packages/vessel-light/.ghost/index.md @@ -1,5 +1,5 @@ --- -context: Any task using the complete Vessel design language. +for: Any task using the complete Vessel design language. materials: - materials/tokens.css --- diff --git a/packages/vessel-light/.ghost/register.data-density.md b/packages/vessel-light/.ghost/register.data-density.md index 8994dfeb..b45808a4 100644 --- a/packages/vessel-light/.ghost/register.data-density.md +++ b/packages/vessel-light/.ghost/register.data-density.md @@ -1,5 +1,5 @@ --- -context: Tables, dashboards, logs, monitoring, or other data-dense consoles. +for: Tables, dashboards, logs, monitoring, or other data-dense consoles. materials: - materials/examples/composition.table.html - materials/primitives.css diff --git a/packages/vessel-light/.ghost/register.editorial.md b/packages/vessel-light/.ghost/register.editorial.md index 9074b6ee..6eecb702 100644 --- a/packages/vessel-light/.ghost/register.editorial.md +++ b/packages/vessel-light/.ghost/register.editorial.md @@ -1,5 +1,5 @@ --- -context: Heroes, marketing pages, pull quotes, or full-bleed dark moments. +for: Heroes, marketing pages, pull quotes, or full-bleed dark moments. materials: - materials/examples/composition.editorial.html - materials/tokens.css diff --git a/packages/vessel-light/.ghost/register.email.md b/packages/vessel-light/.ghost/register.email.md index 8c9f720e..37681aa3 100644 --- a/packages/vessel-light/.ghost/register.email.md +++ b/packages/vessel-light/.ghost/register.email.md @@ -1,5 +1,5 @@ --- -context: Transactional email only. +for: Transactional email only. materials: - materials/examples/email.html --- diff --git a/packages/vessel-light/.ghost/signature.palette.md b/packages/vessel-light/.ghost/signature.palette.md index b3e4549f..90229b6f 100644 --- a/packages/vessel-light/.ghost/signature.palette.md +++ b/packages/vessel-light/.ghost/signature.palette.md @@ -1,5 +1,5 @@ --- -context: Color beyond the base roles, in any register. +for: Color beyond the base roles, in any register. materials: - materials/tokens.css --- diff --git a/packages/vessel-light/.ghost/signature.shape.md b/packages/vessel-light/.ghost/signature.shape.md index 790cbd65..0e752096 100644 --- a/packages/vessel-light/.ghost/signature.shape.md +++ b/packages/vessel-light/.ghost/signature.shape.md @@ -1,5 +1,5 @@ --- -context: Choosing or implementing any radius or corner treatment. +for: Choosing or implementing any radius or corner treatment. materials: - materials/tokens.css - materials/primitives.css diff --git a/packages/vessel-light/.ghost/signature.temperature.md b/packages/vessel-light/.ghost/signature.temperature.md index 5c2e32d3..92e67053 100644 --- a/packages/vessel-light/.ghost/signature.temperature.md +++ b/packages/vessel-light/.ghost/signature.temperature.md @@ -1,5 +1,5 @@ --- -context: Writing any copy or choosing the character of motion. +for: Writing any copy or choosing the character of motion. materials: - materials/tokens.css --- diff --git a/packages/vessel-light/.ghost/signature.type.md b/packages/vessel-light/.ghost/signature.type.md index e7a83023..14aab8c6 100644 --- a/packages/vessel-light/.ghost/signature.type.md +++ b/packages/vessel-light/.ghost/signature.type.md @@ -1,5 +1,5 @@ --- -context: Any text, hero, landing page, or editorial moment. +for: Any text, hero, landing page, or editorial moment. materials: - materials/tokens.css - materials/fonts/HKGrotesk-Black.woff2 diff --git a/packages/vessel-react/.ghost/asset.registry.md b/packages/vessel-react/.ghost/asset.registry.md index f198288c..19e7f820 100644 --- a/packages/vessel-react/.ghost/asset.registry.md +++ b/packages/vessel-react/.ghost/asset.registry.md @@ -1,5 +1,5 @@ --- -context: Changing registry distribution, registry metadata, or copy-and-own component delivery. +for: Changing registry distribution, registry metadata, or copy-and-own component delivery. materials: - packages/vessel-react/registry.json - packages/vessel-react/public/r/registry.json diff --git a/packages/vessel-react/.ghost/asset.tokens.md b/packages/vessel-react/.ghost/asset.tokens.md index 57806b4a..39c2e575 100644 --- a/packages/vessel-react/.ghost/asset.tokens.md +++ b/packages/vessel-react/.ghost/asset.tokens.md @@ -1,5 +1,5 @@ --- -context: Changing tokens, semantic roles, or the Tailwind utility bridge. +for: Changing tokens, semantic roles, or the Tailwind utility bridge. materials: - packages/vessel-react/src/styles/main.css - packages/vessel-react/src/styles/font-faces.css diff --git a/packages/vessel-react/.ghost/condition.escape-hatches.md b/packages/vessel-react/.ghost/condition.escape-hatches.md index 2f9bc996..039697b7 100644 --- a/packages/vessel-react/.ghost/condition.escape-hatches.md +++ b/packages/vessel-react/.ghost/condition.escape-hatches.md @@ -1,5 +1,5 @@ --- -context: Component work needs className, inline style, arbitrary values, or a local primitive fork. +for: Component work needs className, inline style, arbitrary values, or a local primitive fork. materials: - packages/vessel-react/scripts/audit-agent-safety.mjs --- diff --git a/packages/vessel-react/.ghost/condition.upstream-sync.md b/packages/vessel-react/.ghost/condition.upstream-sync.md index 6d8ba26b..a16230d6 100644 --- a/packages/vessel-react/.ghost/condition.upstream-sync.md +++ b/packages/vessel-react/.ghost/condition.upstream-sync.md @@ -1,5 +1,5 @@ --- -context: Reconciling Vessel with upstream shadcn or evaluating an upstream change. +for: Reconciling Vessel with upstream shadcn or evaluating an upstream change. --- Condition: you are syncing Vessel components against newer upstream shadcn diff --git a/packages/vessel-react/.ghost/index.md b/packages/vessel-react/.ghost/index.md index 7775510b..b66ee4cb 100644 --- a/packages/vessel-react/.ghost/index.md +++ b/packages/vessel-react/.ghost/index.md @@ -1,5 +1,5 @@ --- -context: Any task changing the Vessel workspace. +for: Any task changing the Vessel workspace. --- Vessel is ghost's reference body: an agnostic, agent-safe shadcn-compatible diff --git a/packages/vessel-react/.ghost/principle.named-decisions.md b/packages/vessel-react/.ghost/principle.named-decisions.md index 1e3a539b..4de957d8 100644 --- a/packages/vessel-react/.ghost/principle.named-decisions.md +++ b/packages/vessel-react/.ghost/principle.named-decisions.md @@ -1,5 +1,5 @@ --- -context: Authoring or reviewing components, tokens, variants, or agent-safety checks. +for: Authoring or reviewing components, tokens, variants, or agent-safety checks. materials: - packages/vessel-react/scripts/audit-agent-safety.mjs --- diff --git a/packages/vessel-react/.ghost/principle.reference-not-brand.md b/packages/vessel-react/.ghost/principle.reference-not-brand.md index c2df66ce..e1d47a0a 100644 --- a/packages/vessel-react/.ghost/principle.reference-not-brand.md +++ b/packages/vessel-react/.ghost/principle.reference-not-brand.md @@ -1,5 +1,5 @@ --- -context: Any Vessel change that could encode product-specific brand truth. +for: Any Vessel change that could encode product-specific brand truth. --- Vessel provides a coherent implementation vocabulary — tokens, primitives, AI diff --git a/packages/vessel-react/fingerprint/anti-goal.median.md b/packages/vessel-react/fingerprint/anti-goal.median.md index 5da949aa..374a7693 100644 --- a/packages/vessel-react/fingerprint/anti-goal.median.md +++ b/packages/vessel-react/fingerprint/anti-goal.median.md @@ -1,5 +1,5 @@ --- -context: Any build using the vendored component set. +for: Any build using the vendored component set. --- These are not aesthetic opinions. They are the measured convergence of 300 diff --git a/packages/vessel-react/fingerprint/contract.theming.md b/packages/vessel-react/fingerprint/contract.theming.md index 84e192a3..b54cf06d 100644 --- a/packages/vessel-react/fingerprint/contract.theming.md +++ b/packages/vessel-react/fingerprint/contract.theming.md @@ -1,5 +1,5 @@ --- -context: Creating or changing a theme, token binding, font stack, radius, shadow, or gray ramp. +for: Creating or changing a theme, token binding, font stack, radius, shadow, or gray ramp. materials: - packages/vessel-react/src/styles/main.css --- diff --git a/packages/vessel-react/fingerprint/contract.tokens.md b/packages/vessel-react/fingerprint/contract.tokens.md index 0ccca950..baaafe78 100644 --- a/packages/vessel-react/fingerprint/contract.tokens.md +++ b/packages/vessel-react/fingerprint/contract.tokens.md @@ -1,5 +1,5 @@ --- -context: Changing tokens, component styles, semantic roles, or the Tailwind utility bridge. +for: Changing tokens, component styles, semantic roles, or the Tailwind utility bridge. materials: - packages/vessel-react/src/styles/main.css - packages/vessel-react/src/components/ui/button.tsx diff --git a/packages/vessel-react/fingerprint/index.md b/packages/vessel-react/fingerprint/index.md index 0d4e3c11..8827e175 100644 --- a/packages/vessel-react/fingerprint/index.md +++ b/packages/vessel-react/fingerprint/index.md @@ -1,5 +1,5 @@ --- -context: Any task using or changing the vendored component set. +for: Any task using or changing the vendored component set. materials: - packages/vessel-react/src/styles/main.css --- diff --git a/packages/vessel-react/fingerprint/pattern.conversation.md b/packages/vessel-react/fingerprint/pattern.conversation.md index c42c9159..7a6e5ec3 100644 --- a/packages/vessel-react/fingerprint/pattern.conversation.md +++ b/packages/vessel-react/fingerprint/pattern.conversation.md @@ -1,5 +1,5 @@ --- -context: Any AI conversation, prompt input, reasoning display, or tool output. +for: Any AI conversation, prompt input, reasoning display, or tool output. materials: - packages/vessel-react/src/components/ai-elements/conversation.tsx - packages/vessel-react/src/components/ai-elements/message.tsx diff --git a/packages/vessel-react/fingerprint/primitive.composition.md b/packages/vessel-react/fingerprint/primitive.composition.md index 32fdd9b6..f02717f4 100644 --- a/packages/vessel-react/fingerprint/primitive.composition.md +++ b/packages/vessel-react/fingerprint/primitive.composition.md @@ -1,5 +1,5 @@ --- -context: Composing layout, surfaces, text hierarchy, spacing, cards, separators, or loading states. +for: Composing layout, surfaces, text hierarchy, spacing, cards, separators, or loading states. materials: - packages/vessel-react/src/components/ui/stack.tsx - packages/vessel-react/src/components/ui/surface.tsx diff --git a/packages/vessel-react/fingerprint/primitive.controls.md b/packages/vessel-react/fingerprint/primitive.controls.md index be682e3c..517e57ed 100644 --- a/packages/vessel-react/fingerprint/primitive.controls.md +++ b/packages/vessel-react/fingerprint/primitive.controls.md @@ -1,5 +1,5 @@ --- -context: Any view with buttons, inputs, forms, labels, or field errors. +for: Any view with buttons, inputs, forms, labels, or field errors. materials: - packages/vessel-react/src/components/ui/button.tsx - packages/vessel-react/src/components/ui/button-group.tsx