Skip to content

Commit 2e7c606

Browse files
authored
Merge pull request #151 from block/chai/add-storage-config
Add Ghost directory config option
2 parents c7bfd40 + 8da59ab commit 2e7c606

15 files changed

Lines changed: 170 additions & 56 deletions

File tree

.changeset/ghost-memory-dir-env.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@anarchitecture/ghost": minor
3+
---
4+
5+
Adds `GHOST_MEMORY_DIR` as a host-wrapper default for Ghost fingerprint package storage.

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ Generation uses the three core layers:
3737
- `composition.yml` captures the patterns that make those materials feel like
3838
one intentional product.
3939

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

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

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

109112
Drafted fingerprint edits are just ordinary file changes until Git review
110113
accepts them. Checked-in `fingerprint/` core files are the Ghost source of

apps/docs/src/content/docs/cli-reference.mdx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,18 @@ The command tables below are generated from the CLI source. Run
4141

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

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

4951
```bash
5052
ghost init
5153
ghost init --with-intent
5254
ghost init --scope apps/checkout --with-intent
55+
GHOST_MEMORY_DIR=.agents/ghost ghost init
5356
ghost init --scope apps/checkout --memory-dir .design/memory
5457
```
5558

@@ -64,6 +67,7 @@ toward inventory readiness.
6467
```bash
6568
ghost scan
6669
ghost scan --format json
70+
GHOST_MEMORY_DIR=.agents/ghost ghost scan --format json
6771
ghost scan --include-nested --memory-dir .design/memory --format json
6872
```
6973

apps/docs/src/generated/cli-manifest.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"generatedAt": "2026-06-15T13:20:23.174Z",
2+
"generatedAt": "2026-06-16T20:57:35.926Z",
33
"tools": [
44
{
55
"tool": "ghost",
@@ -33,7 +33,7 @@
3333
{
3434
"rawName": "--memory-dir <relative-dir>",
3535
"name": "memoryDir",
36-
"description": "Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
36+
"description": "Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
3737
"default": null,
3838
"takesValue": true,
3939
"negated": false
@@ -61,7 +61,7 @@
6161
{
6262
"rawName": "--memory-dir <relative-dir>",
6363
"name": "memoryDir",
64-
"description": "Relative fingerprint package directory for init --scope or default root init (flag name retained; default: .ghost)",
64+
"description": "Relative fingerprint package directory for host wrappers, init --scope, and default root init (env: GHOST_MEMORY_DIR; default: .ghost)",
6565
"default": null,
6666
"takesValue": true,
6767
"negated": false
@@ -145,7 +145,7 @@
145145
{
146146
"rawName": "--memory-dir <relative-dir>",
147147
"name": "memoryDir",
148-
"description": "Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
148+
"description": "Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
149149
"default": null,
150150
"takesValue": true,
151151
"negated": false
@@ -181,7 +181,7 @@
181181
{
182182
"rawName": "--memory-dir <relative-dir>",
183183
"name": "memoryDir",
184-
"description": "Relative fingerprint package directory for nested discovery and default scan (flag name retained; default: .ghost)",
184+
"description": "Relative fingerprint package directory for host wrappers, nested discovery, and default scan (env: GHOST_MEMORY_DIR; default: .ghost)",
185185
"default": null,
186186
"takesValue": true,
187187
"negated": false
@@ -209,7 +209,7 @@
209209
{
210210
"rawName": "--memory-dir <relative-dir>",
211211
"name": "memoryDir",
212-
"description": "Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
212+
"description": "Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
213213
"default": null,
214214
"takesValue": true,
215215
"negated": false
@@ -348,7 +348,7 @@
348348
{
349349
"rawName": "--memory-dir <relative-dir>",
350350
"name": "memoryDir",
351-
"description": "Relative fingerprint package directory for --path stack resolution (flag name retained; default: .ghost)",
351+
"description": "Relative fingerprint package directory for host wrappers and --path stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
352352
"default": null,
353353
"takesValue": true,
354354
"negated": false
@@ -576,7 +576,7 @@
576576
{
577577
"rawName": "--memory-dir <relative-dir>",
578578
"name": "memoryDir",
579-
"description": "Relative fingerprint package directory for stack resolution (default: .ghost)",
579+
"description": "Relative fingerprint package directory for host wrappers and stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
580580
"default": null,
581581
"takesValue": true,
582582
"negated": false
@@ -672,7 +672,7 @@
672672
{
673673
"rawName": "--memory-dir <relative-dir>",
674674
"name": "memoryDir",
675-
"description": "Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
675+
"description": "Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
676676
"default": null,
677677
"takesValue": true,
678678
"negated": false
@@ -724,7 +724,7 @@
724724
{
725725
"rawName": "--memory-dir <relative-dir>",
726726
"name": "memoryDir",
727-
"description": "Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
727+
"description": "Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
728728
"default": null,
729729
"takesValue": true,
730730
"negated": false

packages/ghost/src/cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export function buildCli(): ReturnType<typeof cac> {
173173
)
174174
.option(
175175
"--memory-dir <relative-dir>",
176-
"Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
176+
"Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
177177
)
178178
.option("--format <fmt>", "Output format: markdown or json", {
179179
default: "markdown",
@@ -229,7 +229,7 @@ export function buildCli(): ReturnType<typeof cac> {
229229
)
230230
.option(
231231
"--memory-dir <relative-dir>",
232-
"Relative fingerprint package directory for stack discovery (flag name retained; default: .ghost)",
232+
"Relative fingerprint package directory for host wrappers and stack discovery (env: GHOST_MEMORY_DIR; default: .ghost)",
233233
)
234234
.option(
235235
"--include-memory",

packages/ghost/src/core/check.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import {
2121
groupFingerprintStacksForPaths,
2222
mapFromFingerprint,
23+
resolveMemoryDirDefault,
2324
} from "../scan/fingerprint-stack.js";
2425
import {
2526
INLINE_COLOR_LITERAL_PATTERN,
@@ -125,7 +126,7 @@ export async function runGhostDriftCheck(
125126
const groups = await groupFingerprintStacksForPaths(
126127
changedFiles.map((file) => file.path),
127128
cwd,
128-
{ memoryDir: options.memoryDir },
129+
{ memoryDir: resolveMemoryDirDefault(options.memoryDir) },
129130
);
130131
const routedFiles: GhostDriftRoutedFile[] = [];
131132
const findings: GhostDriftCheckFinding[] = [];

packages/ghost/src/fingerprint-commands.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
fingerprintPackageDisplayPath,
3939
inventory,
4040
normalizeMemoryDir,
41+
resolveMemoryDirDefault,
4142
scanStatus,
4243
} from "./scan/index.js";
4344
import { registerEmitCommand } from "./scan-emit-command.js";
@@ -69,7 +70,7 @@ export function registerFingerprintCommands(cli: CAC): void {
6970
)
7071
.option(
7172
"--memory-dir <relative-dir>",
72-
"Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
73+
"Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
7374
)
7475
.action(async (path: string | undefined, opts) => {
7576
try {
@@ -140,7 +141,7 @@ export function registerFingerprintCommands(cli: CAC): void {
140141
)
141142
.option(
142143
"--memory-dir <relative-dir>",
143-
"Relative fingerprint package directory for init --scope or default root init (flag name retained; default: .ghost)",
144+
"Relative fingerprint package directory for host wrappers, init --scope, and default root init (env: GHOST_MEMORY_DIR; default: .ghost)",
144145
)
145146
.option(
146147
"--with-intent",
@@ -168,22 +169,23 @@ export function registerFingerprintCommands(cli: CAC): void {
168169
process.exit(2);
169170
return;
170171
}
171-
const memoryDir = memoryDirFromOpts(opts);
172+
const memoryDir =
173+
typeof opts.scope === "string" || dirArg === undefined
174+
? memoryDirFromOpts(opts)
175+
: undefined;
172176
const initOptions = {
173177
withIntent: Boolean(opts.withIntent),
174178
withConfig: Boolean(opts.withConfig || opts.reference),
175179
reference:
176180
typeof opts.reference === "string" ? opts.reference : undefined,
177181
force: Boolean(opts.force),
178-
memoryDir,
179182
};
180183
const paths =
181184
typeof opts.scope === "string"
182-
? await initScopedFingerprintPackage(
183-
opts.scope,
184-
process.cwd(),
185-
initOptions,
186-
)
185+
? await initScopedFingerprintPackage(opts.scope, process.cwd(), {
186+
...initOptions,
187+
memoryDir,
188+
})
187189
: await initFingerprintPackage(
188190
dirArg ?? memoryDir,
189191
process.cwd(),
@@ -242,7 +244,7 @@ export function registerFingerprintCommands(cli: CAC): void {
242244
)
243245
.option(
244246
"--memory-dir <relative-dir>",
245-
"Relative fingerprint package directory for --all and default package lookup (flag name retained; default: .ghost)",
247+
"Relative fingerprint package directory for host wrappers, --all, and default package lookup (env: GHOST_MEMORY_DIR; default: .ghost)",
246248
)
247249
.action(async (dirArg: string | undefined, opts) => {
248250
try {
@@ -295,7 +297,7 @@ export function registerFingerprintCommands(cli: CAC): void {
295297
)
296298
.option(
297299
"--memory-dir <relative-dir>",
298-
"Relative fingerprint package directory for nested discovery and default scan (flag name retained; default: .ghost)",
300+
"Relative fingerprint package directory for host wrappers, nested discovery, and default scan (env: GHOST_MEMORY_DIR; default: .ghost)",
299301
)
300302
.option("--format <fmt>", "Output format: cli or json", { default: "cli" })
301303
.action(async (dirArg: string | undefined, opts) => {
@@ -729,9 +731,7 @@ function dirnameForFingerprintPackageDir(
729731
}
730732

731733
function memoryDirFromOpts(opts: { memoryDir?: unknown }): string {
732-
return normalizeMemoryDir(
733-
typeof opts.memoryDir === "string" ? opts.memoryDir : undefined,
734-
);
734+
return resolveMemoryDirDefault(opts.memoryDir);
735735
}
736736

737737
function initCommandOutput(

packages/ghost/src/relay.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
fingerprintStackToPackageContext,
1414
type GhostFingerprintStack,
1515
loadFingerprintStackForPath,
16-
normalizeMemoryDir,
16+
resolveMemoryDirDefault,
1717
} from "./scan/fingerprint-stack.js";
1818

1919
export const RELAY_GATHER_SCHEMA = "ghost.relay.gather/v1" as const;
@@ -75,7 +75,7 @@ export async function gatherRelayContext(
7575
});
7676
}
7777

78-
const memoryDir = normalizeMemoryDir(options.memoryDir);
78+
const memoryDir = resolveMemoryDirDefault(options.memoryDir);
7979
const stack = await loadFingerprintStackForPath(target, cwd, { memoryDir });
8080
const context = fingerprintStackToPackageContext(stack, options.name);
8181
return gatherFromContext(context, {
@@ -111,7 +111,7 @@ export function registerRelayCommand(cli: CAC): void {
111111
)
112112
.option(
113113
"--memory-dir <relative-dir>",
114-
"Relative fingerprint package directory for stack resolution (default: .ghost)",
114+
"Relative fingerprint package directory for host wrappers and stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
115115
)
116116
.option(
117117
"--name <name>",

packages/ghost/src/review-packet.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
fingerprintStackToPackageContext,
1414
type GhostFingerprintStack,
1515
groupFingerprintStacksForPaths,
16+
resolveMemoryDirDefault,
1617
} from "./scan/fingerprint-stack.js";
1718
import {
1819
type GhostPackageConfig,
@@ -84,7 +85,7 @@ async function buildStackReviewPacket(options: {
8485
const groups = await groupFingerprintStacksForPaths(
8586
changedFiles,
8687
process.cwd(),
87-
{ memoryDir: options.memoryDir },
88+
{ memoryDir: resolveMemoryDirDefault(options.memoryDir) },
8889
);
8990
const stacks = groups.map((group) =>
9091
reviewStackFromFingerprintStack(group.stack, group.changed_files),

packages/ghost/src/scan-emit-command.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { resolveFingerprintPackage } from "./fingerprint.js";
1010
import {
1111
fingerprintStackToPackageContext,
1212
loadFingerprintStackForPath,
13-
normalizeMemoryDir,
13+
resolveMemoryDirDefault,
1414
} from "./scan/fingerprint-stack.js";
1515

1616
const DEFAULT_REVIEW_OUT = ".claude/commands/design-review.md";
@@ -52,7 +52,7 @@ export function registerEmitCommand(cli: CAC): void {
5252
)
5353
.option(
5454
"--memory-dir <relative-dir>",
55-
"Relative fingerprint package directory for --path stack resolution (flag name retained; default: .ghost)",
55+
"Relative fingerprint package directory for host wrappers and --path stack resolution (env: GHOST_MEMORY_DIR; default: .ghost)",
5656
)
5757
.option(
5858
"-o, --out <path>",
@@ -120,9 +120,7 @@ async function loadEmitPackageContext(opts: {
120120
typeof opts.path === "string" ? opts.path : ".",
121121
process.cwd(),
122122
{
123-
memoryDir: normalizeMemoryDir(
124-
typeof opts.memoryDir === "string" ? opts.memoryDir : undefined,
125-
),
123+
memoryDir: resolveMemoryDirDefault(opts.memoryDir),
126124
},
127125
);
128126
return fingerprintStackToPackageContext(stack);

0 commit comments

Comments
 (0)