Skip to content

Commit a0afc58

Browse files
PerishCodeLooper
andauthored
[codex] centralize daemon data directory docs (#4222)
* docs: centralize daemon data directory contract * fix(e2e): allow slower artifact consistency navigation Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * docs: localize daemon data directory pointers Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com>
1 parent 076bf33 commit a0afc58

73 files changed

Lines changed: 365 additions & 484 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

β€ŽAGENTS.mdβ€Ž

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ This file is the single source of truth for agents entering this repository. Rea
2929
## Inactive or placeholder directories
3030

3131
- `apps/nextjs` and `packages/shared` have been removed; do not recreate or reference them.
32-
- `.od/`, `.tmp/`, Playwright reports, and agent scratch directories are local runtime data and must stay out of git.
32+
- Local runtime data, `.tmp/`, Playwright reports, and agent scratch directories must stay out of git. For daemon-managed data paths, read and follow **Daemon data directory contract** below; do not restate or improvise path conventions elsewhere.
3333

3434
# Development workflow
3535

@@ -55,6 +55,81 @@ This file is the single source of truth for agents entering this repository. Rea
5555
- Ports are governed by `tools-dev` flags: `--daemon-port` and `--web-port`.
5656
- `tools-dev` exports `OD_PORT` for the web proxy target and `OD_WEB_PORT` for the web listener; do not use `NEXT_PORT`.
5757

58+
## Daemon data directory contract
59+
60+
This section is the only repository-wide source of truth for daemon-managed
61+
data paths. Every README, guide, deployment note, and operational handoff that
62+
mentions daemon data paths must point here instead of restating the rules.
63+
64+
This boundary is strict. Do not introduce concrete filesystem examples for the
65+
daemon data directory, recommended data directory, shared data directory,
66+
deployment mount, or example data directory. If existing code exposes a legacy
67+
fallback, treat it as implementation detail or a known escape candidate, not as
68+
a documentation pattern to copy. If a change needs a data-path rule that is not
69+
covered here, request a core-maintainer decision in the PR instead of inventing
70+
a new convention.
71+
72+
The daemon has one active data-root truth source:
73+
74+
- On daemon startup, `apps/daemon/src/server.ts` resolves `OD_DATA_DIR` into
75+
`RUNTIME_DATA_DIR`.
76+
- All daemon-owned data paths must derive from `RUNTIME_DATA_DIR` or from a
77+
constant derived from it, such as `PROJECTS_DIR` or `ARTIFACTS_DIR`.
78+
- `PROJECTS_DIR` is the managed-project root. Imported-folder projects are the
79+
explicit exception: they use `metadata.baseDir` for the user-selected
80+
external workspace.
81+
- `ARTIFACTS_DIR`, SQLite, app config, memory, MCP config/tokens, automation
82+
state, plugin state, connector credentials, generated files, logs owned by
83+
sandbox mode, and agent runtime homes are daemon data and must remain under
84+
the resolved daemon data root unless this file names a specific exception.
85+
- Agent subprocesses receive the resolved daemon data root as `OD_DATA_DIR`.
86+
They must inherit the daemon's truth source instead of guessing their own
87+
data path.
88+
89+
Development propagation:
90+
91+
- `tools-dev` owns sidecar runtime/log/ipc namespacing.
92+
- `tools-dev --namespace <name>` does not, by itself, define daemon data
93+
isolation.
94+
- A development run that needs an isolated daemon data root must pass
95+
`OD_DATA_DIR` into the daemon process environment. After that, the daemon
96+
resolves it once and all daemon data paths flow from `RUNTIME_DATA_DIR`.
97+
98+
Packaged propagation:
99+
100+
- `tools-pack` / `apps/packaged` own packaged channel and namespace layout.
101+
- Packaged code resolves the final namespace-scoped daemon data root before
102+
spawning the daemon.
103+
- The packaged daemon receives that final data root as `OD_DATA_DIR`; daemon
104+
code must not infer packaged data paths from app names, Electron `userData`,
105+
ports, channel names, or namespace names.
106+
107+
Sanctioned exceptions:
108+
109+
- `OD_MEDIA_CONFIG_DIR` is a narrow override for `media-config.json` only. It
110+
is not a second daemon data root.
111+
- `OD_LEGACY_DATA_DIR` is a migration source for legacy data import only. It is
112+
not an active daemon data root.
113+
- External tool homes such as `CODEX_HOME` are integration inputs, not daemon
114+
data roots. The daemon must not describe them as Open Design runtime data.
115+
- Agent/project-cwd skill staging aliases are not daemon data roots.
116+
- Manifest metadata keys and CSS identifiers are semantic namespaces, not
117+
filesystem path conventions.
118+
119+
Known escape candidates that must not be reused:
120+
121+
- Module-level defaults that point at a cwd-relative legacy data directory.
122+
- Helper defaults such as `defaultRegistryRoots()` that recompute a data root
123+
from `process.env.OD_DATA_DIR` or a cwd fallback instead of receiving
124+
`RUNTIME_DATA_DIR`.
125+
- `openDatabase(projectRoot)` calls that rely on its fallback instead of
126+
passing the resolved data root.
127+
- Script help text or examples that suggest concrete legacy data directories.
128+
129+
Do not extend these escape patterns. When a fix is obvious, route the path
130+
through `RUNTIME_DATA_DIR` or an explicit data-root argument. When it is not
131+
obvious, block the PR and request core-maintainer guidance.
132+
58133
## Root command boundary
59134

60135
- Keep root scripts reserved for true repo-level checks and tools control-plane entrypoints: `pnpm guard`, `pnpm typecheck`, `pnpm tools-dev`, `pnpm tools-pack`, and `pnpm tools-serve`.
@@ -266,15 +341,6 @@ Desktop queries runtime status through sidecar IPC. The web URL comes from `tool
266341

267342
`@open-design/sidecar-proto` owns Open Design app/mode/source constants, namespace validation, stamp fields/flags, IPC message schema, status shapes, and error semantics. `@open-design/sidecar` provides only generic bootstrap, IPC transport, path/runtime resolution, launch env, and JSON runtime files. `@open-design/platform` provides only generic OS process stamp serialization, command parsing, and process matching/search primitives, consuming the proto descriptor.
268343

269-
## Where is data written?
270-
271-
The daemon writes `.od/` by default: SQLite at `.od/app.sqlite`, agent CWDs under `.od/projects/<id>/`, saved renders under `.od/artifacts/`, and credentials at `.od/media-config.json`. Two env vars override the storage root, in order:
272-
273-
1. `OD_DATA_DIR=<dir>` β€” relocates *all* daemon runtime data to `<dir>` (used by Playwright for test isolation, and by the packaged daemon and the Home Manager / NixOS modules to point the daemon at a writable directory when the install root is read-only). The path is resolved with `~/` expansion and relative paths anchored to `<projectRoot>`.
274-
2. `OD_MEDIA_CONFIG_DIR=<dir>` β€” narrower override that relocates *only* `media-config.json`. Same resolution semantics. Most installs do not need this; it exists for setups that want to keep API credentials in a different location from the rest of the runtime data.
275-
276-
Default precedence is OD_MEDIA_CONFIG_DIR > OD_DATA_DIR > `<projectRoot>/.od`.
277-
278344
## When is `pnpm install` required?
279345

280346
Run `pnpm install` after changing package manifests, workspace layout, command entrypoints, bin/link-related content, or after adding/removing workspace packages.

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,11 +453,11 @@ A memory-plus-UI release: **auto-memory store** carries agent context across run
453453
- **`od plugin events snapshot/stats` + tail filters (Phase 4).** Extends Β§3.II1 with: `GET /api/plugins/events/snapshot` for non-SSE one-shot reads (dashboards that don't want a live connection); `GET /api/plugins/events/stats` returns a `summarisePluginEvents()` rollup (counts byKind, byPluginId β€” skipping empty ids β€” plus oldest/newest at + id range); `--kind <k>` and `--plugin-id <id>` filter flags work on both `od plugin events tail` (client-side post-render) and the new `od plugin events snapshot` subcommand. CLI pretty-prints the stats rollup with sorted-key counts for byte-determinism.
454454
- **More plugin event producer hooks (Phase 4).** Extends Β§3.II1 with: `installPlugin` accepts `eventKind: 'installed' | 'upgraded'` so the upgrade route distinguishes the operation in the live tail; `POST /api/plugins/:id/trust` emits `plugin.trust-changed`; `POST /api/applied-plugins/prune` emits `plugin.snapshot-pruned` when anything was actually removed; `POST /api/marketplaces/:id/refresh` emits `plugin.marketplace-refreshed`. Each hook is best-effort and never blocks the underlying mutation if the ring buffer throws.
455455
- **Plugin event ring buffer + SSE tail (Phase 4).** New `apps/daemon/src/plugins/events.ts` ships an in-memory FIFO ring buffer (capped at 1000 entries, monotonic ids, fan-out subscribers) for plugin lifecycle events: `plugin.installed` / `.upgraded` / `.uninstalled` / `.trust-changed` / `.applied` / `.snapshot-pruned` / `.marketplace-refreshed`. Producer hooks landed on the installer (install + uninstall). New `GET /api/plugins/events` SSE route emits the backlog on connect (with optional `?since=<id>` trim) then forwards live events. CLI: `od plugin events tail [-f] [--since <id>] [--json]` β€” non-follow mode drains backlog + exits; `-f` keeps the stream open for ops dashboards.
456-
- **`od plugin doctor --strict` + verify strict propagation (Phase 4).** New `--strict` flag on `od plugin doctor` promotes warnings to failures (exit 4 distinguishes 'strict failed' from doctor errors at exit 1). The `verifyPlugin()` orchestrator gains a matching `strict: true` config knob that flows through `.od-verify.json` so plugins can lock 'no warnings allowed' as a one-line CI policy.
456+
- **`od plugin doctor --strict` + verify strict propagation (Phase 4).** New `--strict` flag on `od plugin doctor` promotes warnings to failures (exit 4 distinguishes 'strict failed' from doctor errors at exit 1). The `verifyPlugin()` orchestrator gains a matching `strict: true` config knob that flows through the plugin verify config file so plugins can lock 'no warnings allowed' as a one-line CI policy.
457457
- **`od daemon db verify` SQLite integrity check (Phase 5).** New `verifySqliteIntegrity()` pure helper wraps PRAGMA `integrity_check` (or `quick_check` with `--quick`) + PRAGMA `foreign_key_check`. Returns a structured `{ ok, mode, issues[], elapsedMs, generatedAt }` report with issues tagged `kind='integrity' | 'foreign_key'`. Loopback-only `POST /api/daemon/db/verify` route + `od daemon db verify [--quick]` CLI subcommand β€” exit 0 on ok=true, 4 on any issue, so CI can wire it into a pre-deploy check.
458458
- **`od daemon db vacuum` (Phase 5).** New loopback-only `POST /api/daemon/db/vacuum` runs SQLite VACUUM and reports before/after sizes + reclaimed bytes + elapsed ms. Useful after large delete batches (snapshot prune, plugin uninstall) shrink rows but leave space allocated to the file. CLI: `od daemon db vacuum [--json]`.
459459
- **`od daemon db status` SQLite inventory (Phase 5).** New `inspectSqliteDatabase()` pure helper + `GET /api/daemon/db` route returns a structured report: `kind` ('sqlite'), file location, size on disk (primary + WAL + SHM), schema version (`user_version` PRAGMA), and per-table row counts (system tables excluded, lexicographic order). CLI: `od daemon db status [--json]` lets ops sanity-check deployments at a glance + compare expected-vs-actual table rosters across daemon upgrades.
460-
- **`od plugin verify <id>` CI meta-command (Phase 4).** New `verifyPlugin()` pure orchestrator aggregates `doctor` + `simulate` + `canon --check` into one pass/fail report. Reads `<plugin-folder>/.od-verify.json` (or `--config <path>`) so plugin authors commit their CI checks into their repo. Each check resolves to `passed | failed | skipped | unsupported`; aggregate passes iff every enabled check is passed or skipped (`unsupported` bubbles up as a fail to keep CI honest). One-liner CI workflow: `od plugin verify my-plugin` β€” exit 0 on pass, 4 on fail, 2 on CLI/config error.
460+
- **`od plugin verify <id>` CI meta-command (Phase 4).** New `verifyPlugin()` pure orchestrator aggregates `doctor` + `simulate` + `canon --check` into one pass/fail report. Reads the plugin verify config file (or `--config <path>`) so plugin authors commit their CI checks into their repo. Each check resolves to `passed | failed | skipped | unsupported`; aggregate passes iff every enabled check is passed or skipped (`unsupported` bubbles up as a fail to keep CI honest). One-liner CI workflow: `od plugin verify my-plugin` β€” exit 0 on pass, 4 on fail, 2 on CLI/config error.
461461
- **`od plugin simulate <id>` pipeline dry-run (Phase 4).** New `simulatePipeline({ pipeline, signals, iterationCap? })` pure helper walks every stage in a plugin's pipeline against caller-supplied signals (constant snapshot OR per-iteration generator function) and reports `outcome ∈ { single | converged | cap | unparsable }` per stage plus aggregate `outcome ∈ { all-converged | all-single | mixed | cap-hit | unparsable }`. Companion `parseSignalKv()` parses repeatable `-s key=value` CLI flags into the closed `UntilSignals` vocabulary with typo guards. CLI: `od plugin simulate <pluginId> [-s key=value ...] [--cap <n>] [--json]` β€” exit 4 on cap-hit/unparsable so CI can hook this into a pipeline check.
462462
- **`od plugin stats` inventory health report (Phase 4).** New `pluginInventoryStats()` + `snapshotInventoryStats()` pure helpers aggregate installed-plugin counts (by `sourceKind` / `trust` / `taskKind`, bundled vs. third-party split, plugins with elevated capabilities β€” `fs:write` / `subprocess` / `bash` / `network` / `connector:*`) and snapshot health (status breakdown, project / run linkage, oldest / newest applied timestamps). New `GET /api/plugins/stats` route + `od plugin stats [--json]` CLI subcommand for at-a-glance fleet audit.
463463
- **`od plugin canon --check <expected-file>` byte-equality fixtures (Phase 4).** New `--check` mode on `od plugin canon` compares the canon output against an on-disk fixture and exits 4 on mismatch with a per-line diff preview. Lets plugin authors commit `renderPluginBlock()` regression fixtures into their own `tests/` without writing a fresh test harness.
@@ -649,7 +649,7 @@ A connectivity-and-iteration release: Open Design becomes a fully bidirectional
649649

650650
#### MCP & connectors
651651
- MCP install snippet survives daemon port changes. ([#846])
652-
- Pin `OD_DATA_DIR` in `/api/mcp/install-info` env so the macOS-packaged MCP server stops EPERM'ing on `.od/projects`. ([#857])
652+
- Pin the daemon data directory in `/api/mcp/install-info` env so the macOS-packaged MCP server stops failing on managed project storage. ([#857])
653653
- Reserve clearance for the MCP server Copy button so it stops overlapping the snippet. ([#847])
654654
- Give the MCP server Copy button a solid surface so it reads against the code block. ([#840])
655655
- Stable curated tool count in the connector card badge. ([#767])
@@ -866,7 +866,7 @@ A minor release focused on iteration: live-data dashboards graduate to a first-c
866866

867867
### Documentation
868868

869-
- Documented `OD_DATA_DIR` and migration from `.od/` to the Desktop app. ([#570])
869+
- Documented daemon data directory migration to the Desktop app. ([#570])
870870
- Added Chinese (Simplified) QUICKSTART. ([#578])
871871
- Backported missing zh-TW README sections from the English README. ([#586])
872872
- Synced and improved the Korean README. ([#619])

β€ŽCONTRIBUTING.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ Beyond that:
244244
## Commits & pull requests
245245

246246
- **One concern per PR.** Adding a skill + refactoring the parser + bumping a dep is three PRs.
247-
- **Title is imperative + scope.** `add dating-web skill`, `fix daemon SSE backpressure when CLI hangs`, `docs: clarify .od layout`.
247+
- **Title is imperative + scope.** `add dating-web skill`, `fix daemon SSE backpressure when CLI hangs`, `docs: clarify storage contract`.
248248
- **Use the PR template.** Fill every section of [`.github/pull_request_template.md`](.github/pull_request_template.md) β€” Why, What users will see, Surface area, Screenshots (if UI), Bug fix verification (if bug fix), Validation. Empty sections earn a "please fill in" reply.
249249
- **Body explains the why.** "What does this do" is usually obvious from the diff; "why does this need to exist" rarely is.
250250
- **Reference an issue** if there is one. If there isn't and the PR is non-trivial, open one first so we can agree the change is wanted before you spend the time.

β€ŽQUICKSTART.mdβ€Ž

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -153,25 +153,9 @@ OD_API_TOKEN=
153153

154154
## Persistent Storage
155155

156-
Open Design stores projects and SQLite data inside a Docker volume:
157-
158-
```text
159-
open_design_data
160-
```
161-
162-
The volume is mounted to:
163-
164-
```text
165-
/app/.od
166-
```
167-
168-
Data persists across container restarts and image updates.
169-
170-
Inspect the volume:
171-
172-
```bash
173-
docker volume inspect open-design_open_design_data
174-
```
156+
Before documenting, changing, or choosing any persistent daemon storage path,
157+
you MUST read the root `AGENTS.md` section **Daemon data directory contract**.
158+
This Quickstart MUST NOT restate that contract or define storage paths.
175159

176160
---
177161

@@ -198,7 +182,7 @@ For the desktop shell and all managed sidecars in the background:
198182
pnpm tools-dev # starts daemon + web + desktop in the background
199183
```
200184

201-
On first load, the app detects your installed code-agent CLI (Claude Code / Codex / Devin for Terminal / Gemini / OpenCode / Cursor Agent / Qwen / Qoder CLI), picks it automatically, and defaults to `web-prototype` skill + `Neutral Modern` design system. Type a prompt and hit **Send**. The agent streams into the left pane; the `<artifact>` tag is parsed out and the HTML renders live on the right. When it finishes, click **Save to disk** to persist the artifact under `./.od/artifacts/<timestamp>-<slug>/index.html`.
185+
On first load, the app detects your installed code-agent CLI (Claude Code / Codex / Devin for Terminal / Gemini / OpenCode / Cursor Agent / Qwen / Qoder CLI), picks it automatically, and defaults to `web-prototype` skill + `Neutral Modern` design system. Type a prompt and hit **Send**. The agent streams into the left pane; the `<artifact>` tag is parsed out and the HTML renders live on the right. Before documenting or changing any artifact storage path, you MUST read `AGENTS.md` β†’ **Daemon data directory contract**.
202186

203187
The **Design system** dropdown ships with 71 built-in systems β€” 2 hand-authored starters (Neutral Modern, Warm Editorial) and 69 product systems imported from [`awesome-design-md`](https://github.com/VoltAgent/awesome-design-md), grouped by category (AI & LLM, Developer Tools, Productivity, Backend, Design Tools, Fintech, E-Commerce, Media, Automotive). Pick one to skin every prototype in that brand's aesthetic, and another set of 57 design skills sourced from [`awesome-design-skills`](https://github.com/bergside/awesome-design-skills).
204188

@@ -357,10 +341,6 @@ open-design/
357341
β”‚ └── …129 systems # 2 starters Β· 70 product systems Β· 57 design skills
358342
β”œβ”€β”€ scripts/sync-design-systems.ts # re-import from upstream getdesign tarball
359343
β”œβ”€β”€ docs/ # product vision + spec
360-
β”œβ”€β”€ .od/ # runtime data (gitignored, auto-created)
361-
β”‚ β”œβ”€β”€ app.sqlite # projects / conversations / messages / tabs
362-
β”‚ β”œβ”€β”€ artifacts/ # one-off "Save to disk" renders
363-
β”‚ └── projects/<id>/ # per-project working dir + agent cwd
364344
β”œβ”€β”€ pnpm-workspace.yaml # apps/* + packages/* + tools/* + e2e
365345
└── package.json # root quality scripts + `od` bin
366346
```

0 commit comments

Comments
Β (0)