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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ghost-memory-dir-env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@anarchitecture/ghost": minor
---

Adds `GHOST_MEMORY_DIR` as a host-wrapper default for Ghost fingerprint package storage.
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ Generation uses the three core layers:
- `composition.yml` captures the patterns that make those materials feel like
one intentional product.

Checks, memory, generated cache, nested packages, and custom `--memory-dir`
locations are supporting features. They do not replace the core fingerprint
layers. Generated cache answers what exists; curated fingerprint layers answer
what the surface is trying to preserve.
Checks, memory, generated cache, nested packages, and custom host-wrapper
package locations are supporting features. They do not replace the core
fingerprint layers. Generated cache answers what exists; curated fingerprint
layers answer what the surface is trying to preserve.

Older `resources.yml`, `map.md`, `survey.json`, `patterns.yml`, and direct
`fingerprint.yml` artifacts can still inform migration or cache workflows, but
Expand Down Expand Up @@ -102,9 +102,12 @@ ghost lint .ghost
ghost verify .ghost --root .
```

Use `--with-intent`, `--with-config`, `--reference`, `--scope`, or
`--memory-dir` only when the repo needs those optional files, reference
libraries, nested product areas, or host-wrapper storage paths.
Use `--with-intent`, `--with-config`, `--reference`, or `--scope` only when the
repo needs those optional files, reference libraries, or nested product areas.
Host wrappers that need Ghost files somewhere other than `.ghost` may set
`GHOST_MEMORY_DIR=<relative-dir>` on the child `ghost` process, or pass
`--memory-dir <relative-dir>` explicitly. Explicit `init [dir]` and
`--memory-dir <relative-dir>` values win over the environment default.

Drafted fingerprint edits are just ordinary file changes until Git review
accepts them. Checked-in `fingerprint/` core files are the Ghost source of
Expand Down
8 changes: 6 additions & 2 deletions apps/docs/src/content/docs/cli-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,18 @@ The command tables below are generated from the CLI source. Run

Create a `.ghost/fingerprint/` package with a manifest, raw core layer files,
and enforcement checks. Use `--scope <path>` for nested package roots. Use
`--memory-dir <relative-dir>` when a host adapter stores Ghost package roots
under a different safe relative directory.
`GHOST_MEMORY_DIR=<relative-dir>` only when a host wrapper stores Ghost package
roots under a different safe relative directory; raw `ghost` defaults to
`.ghost`. Explicit `init [dir]` and `--memory-dir <relative-dir>` values win
over the environment default.

<CliHelp tool="ghost" command="init" hideDescription />

```bash
ghost init
ghost init --with-intent
ghost init --scope apps/checkout --with-intent
GHOST_MEMORY_DIR=.agents/ghost ghost init
ghost init --scope apps/checkout --memory-dir .design/memory
```

Expand All @@ -64,6 +67,7 @@ toward inventory readiness.
```bash
ghost scan
ghost scan --format json
GHOST_MEMORY_DIR=.agents/ghost ghost scan --format json
ghost scan --include-nested --memory-dir .design/memory --format json
```

Expand Down
20 changes: 10 additions & 10 deletions apps/docs/src/generated/cli-manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"generatedAt": "2026-06-15T13:20:23.174Z",
"generatedAt": "2026-06-16T20:57:35.926Z",
"tools": [
{
"tool": "ghost",
Expand Down Expand Up @@ -33,7 +33,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -61,7 +61,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for init --scope or default root init (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers, init --scope, and default root init (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -145,7 +145,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -181,7 +181,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for nested discovery and default scan (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers, nested discovery, and default scan (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -209,7 +209,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -348,7 +348,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for --path stack resolution (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers and --path stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -576,7 +576,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for stack resolution (default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers and stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -672,7 +672,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down Expand Up @@ -724,7 +724,7 @@
{
"rawName": "--memory-dir <relative-dir>",
"name": "memoryDir",
"description": "Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
"description": "Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
"default": null,
"takesValue": true,
"negated": false
Expand Down
4 changes: 2 additions & 2 deletions packages/ghost/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export function buildCli(): ReturnType<typeof cac> {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option("--format <fmt>", "Output format: markdown or json", {
default: "markdown",
Expand Down Expand Up @@ -229,7 +229,7 @@ export function buildCli(): ReturnType<typeof cac> {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option(
"--include-memory",
Expand Down
3 changes: 2 additions & 1 deletion packages/ghost/src/core/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import {
groupFingerprintStacksForPaths,
mapFromFingerprint,
resolveMemoryDirDefault,
} from "../scan/fingerprint-stack.js";
import {
INLINE_COLOR_LITERAL_PATTERN,
Expand Down Expand Up @@ -125,7 +126,7 @@ export async function runGhostDriftCheck(
const groups = await groupFingerprintStacksForPaths(
changedFiles.map((file) => file.path),
cwd,
{ memoryDir: options.memoryDir },
{ memoryDir: resolveMemoryDirDefault(options.memoryDir) },
);
const routedFiles: GhostDriftRoutedFile[] = [];
const findings: GhostDriftCheckFinding[] = [];
Expand Down
28 changes: 14 additions & 14 deletions packages/ghost/src/fingerprint-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
fingerprintPackageDisplayPath,
inventory,
normalizeMemoryDir,
resolveMemoryDirDefault,
scanStatus,
} from "./scan/index.js";
import { registerEmitCommand } from "./scan-emit-command.js";
Expand Down Expand Up @@ -69,7 +70,7 @@ export function registerFingerprintCommands(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.action(async (path: string | undefined, opts) => {
try {
Expand Down Expand Up @@ -140,7 +141,7 @@ export function registerFingerprintCommands(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for init --scope or default root init (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers, init --scope, and default root init (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option(
"--with-intent",
Expand Down Expand Up @@ -168,22 +169,23 @@ export function registerFingerprintCommands(cli: CAC): void {
process.exit(2);
return;
}
const memoryDir = memoryDirFromOpts(opts);
const memoryDir =
typeof opts.scope === "string" || dirArg === undefined
? memoryDirFromOpts(opts)
: undefined;
const initOptions = {
withIntent: Boolean(opts.withIntent),
withConfig: Boolean(opts.withConfig || opts.reference),
reference:
typeof opts.reference === "string" ? opts.reference : undefined,
force: Boolean(opts.force),
memoryDir,
};
const paths =
typeof opts.scope === "string"
? await initScopedFingerprintPackage(
opts.scope,
process.cwd(),
initOptions,
)
? await initScopedFingerprintPackage(opts.scope, process.cwd(), {
...initOptions,
memoryDir,
})
: await initFingerprintPackage(
dirArg ?? memoryDir,
process.cwd(),
Expand Down Expand Up @@ -242,7 +244,7 @@ export function registerFingerprintCommands(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.action(async (dirArg: string | undefined, opts) => {
try {
Expand Down Expand Up @@ -295,7 +297,7 @@ export function registerFingerprintCommands(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for nested discovery and default scan (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers, nested discovery, and default scan (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option("--format <fmt>", "Output format: cli or json", { default: "cli" })
.action(async (dirArg: string | undefined, opts) => {
Expand Down Expand Up @@ -729,9 +731,7 @@ function dirnameForFingerprintPackageDir(
}

function memoryDirFromOpts(opts: { memoryDir?: unknown }): string {
return normalizeMemoryDir(
typeof opts.memoryDir === "string" ? opts.memoryDir : undefined,
);
return resolveMemoryDirDefault(opts.memoryDir);
}

function initCommandOutput(
Expand Down
6 changes: 3 additions & 3 deletions packages/ghost/src/relay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
fingerprintStackToPackageContext,
type GhostFingerprintStack,
loadFingerprintStackForPath,
normalizeMemoryDir,
resolveMemoryDirDefault,
} from "./scan/fingerprint-stack.js";

export const RELAY_GATHER_SCHEMA = "ghost.relay.gather/v1" as const;
Expand Down Expand Up @@ -75,7 +75,7 @@ export async function gatherRelayContext(
});
}

const memoryDir = normalizeMemoryDir(options.memoryDir);
const memoryDir = resolveMemoryDirDefault(options.memoryDir);
const stack = await loadFingerprintStackForPath(target, cwd, { memoryDir });
const context = fingerprintStackToPackageContext(stack, options.name);
return gatherFromContext(context, {
Expand Down Expand Up @@ -111,7 +111,7 @@ export function registerRelayCommand(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for stack resolution (default: .ghost)",
"Relative fingerprint package directory for host wrappers and stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option(
"--name <name>",
Expand Down
3 changes: 2 additions & 1 deletion packages/ghost/src/review-packet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
fingerprintStackToPackageContext,
type GhostFingerprintStack,
groupFingerprintStacksForPaths,
resolveMemoryDirDefault,
} from "./scan/fingerprint-stack.js";
import {
type GhostPackageConfig,
Expand Down Expand Up @@ -84,7 +85,7 @@ async function buildStackReviewPacket(options: {
const groups = await groupFingerprintStacksForPaths(
changedFiles,
process.cwd(),
{ memoryDir: options.memoryDir },
{ memoryDir: resolveMemoryDirDefault(options.memoryDir) },
);
const stacks = groups.map((group) =>
reviewStackFromFingerprintStack(group.stack, group.changed_files),
Expand Down
8 changes: 3 additions & 5 deletions packages/ghost/src/scan-emit-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { resolveFingerprintPackage } from "./fingerprint.js";
import {
fingerprintStackToPackageContext,
loadFingerprintStackForPath,
normalizeMemoryDir,
resolveMemoryDirDefault,
} from "./scan/fingerprint-stack.js";

const DEFAULT_REVIEW_OUT = ".claude/commands/design-review.md";
Expand Down Expand Up @@ -52,7 +52,7 @@ export function registerEmitCommand(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for --path stack resolution (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers and --path stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option(
"-o, --out <path>",
Expand Down Expand Up @@ -120,9 +120,7 @@ async function loadEmitPackageContext(opts: {
typeof opts.path === "string" ? opts.path : ".",
process.cwd(),
{
memoryDir: normalizeMemoryDir(
typeof opts.memoryDir === "string" ? opts.memoryDir : undefined,
),
memoryDir: resolveMemoryDirDefault(opts.memoryDir),
},
);
return fingerprintStackToPackageContext(stack);
Expand Down
8 changes: 3 additions & 5 deletions packages/ghost/src/scan-stack-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
fingerprintPackageDisplayPath,
type GhostFingerprintStack,
loadFingerprintStackForPath,
normalizeMemoryDir,
resolveMemoryDirDefault,
} from "./scan/index.js";

export function registerStackCommand(cli: CAC): void {
Expand All @@ -14,14 +14,12 @@ export function registerStackCommand(cli: CAC): void {
)
.option(
"--memory-dir <relative-dir>",
"Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
"Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
)
.option("--format <fmt>", "Output format: cli or json", { default: "cli" })
.action(async (paths: string[] | string | undefined, opts) => {
try {
const memoryDir = normalizeMemoryDir(
typeof opts.memoryDir === "string" ? opts.memoryDir : undefined,
);
const memoryDir = resolveMemoryDirDefault(opts.memoryDir);
const requestedPaths = Array.isArray(paths)
? paths
: typeof paths === "string"
Expand Down
13 changes: 13 additions & 0 deletions packages/ghost/src/scan/fingerprint-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,19 @@ export function normalizeMemoryDir(
return normalized;
}

export const GHOST_MEMORY_DIR_ENV = "GHOST_MEMORY_DIR";

export function resolveMemoryDirDefault(
explicitMemoryDir?: unknown,
env: NodeJS.ProcessEnv = process.env,
): string {
return normalizeMemoryDir(
typeof explicitMemoryDir === "string"
? explicitMemoryDir
: env[GHOST_MEMORY_DIR_ENV],
);
}

export function fingerprintPackageDisplayPath(
relativeRoot: string,
memoryDir = FINGERPRINT_PACKAGE_DIR,
Expand Down
Loading
Loading