CLAUDE.md · diff
git:20260615.ddd1c77 to git:20260615.99032a4
1 added, 1 removed. Audit A to A.
<!-- OPENSPEC:START -->
## OpenSpec Instructions
These instructions are for AI assistants working in this project.
Always open `@/openspec/AGENTS.md` when the request:
- Mentions planning or proposals (words like proposal, spec, change, plan)
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
- Sounds ambiguous and you need the authoritative spec before coding
Use `@/openspec/AGENTS.md` to learn:
- How to create and apply change proposals
- Spec format and conventions
- Project structure and guidelines
Keep this managed block so 'openspec update' can refresh the instructions.
<!-- OPENSPEC:END -->
## Code Conventions
- **TypeScript only**: Do not create raw `.js` or `.mjs` files unless they serve a config purpose (e.g., `vite.config.mjs`, `eslint.config.mjs`). All project code, scripts, and utilities must be written in TypeScript.
- **Nx-native automation**: Release process automation must use Nx extension points (e.g., `VersionActions`, `preVersionCommand`), not npm lifecycle scripts or standalone scripts.
- **Agent assets — edit source, then sync**: Agent docs, skills, commands, references, and other agent-related files have their **source of truth in `packages/agents/`**. ALWAYS edit them there, then run `nx run cli:update` to write the changes out to the local project's `.ocr/` directory. Never hand-edit the generated `.ocr/` copies directly — they will be overwritten on the next sync and your edits will drift from source.
- - **Shared layers live in `packages/shared/*`, apps never depend on apps**: `cli` and `dashboard` are application packages and MUST NOT depend on one another. Code both apps need (persistence, domain/state, config, cross-platform utilities) lives in dedicated library packages under `packages/shared/*` that each app depends on directly. The current shared packages are `@open-code-review/platform` (cross-platform/runtime utilities), `@open-code-review/persistence` (the `node:sqlite` adapter `db` + workflow `state` lifecycle + `test-support` + `vendor-resume` + the `node:sqlite` runtime precondition `runtime-checks` — kept in **one** package because `db` and `state` have a mutually-recursive *type* cycle (`db/types.ts` ↔ `state/types.ts`); a package boundary between them would form a dependency cycle. The single-module-instance connection-cache singleton is a *consequence* of that co-location, not its root cause), and `@open-code-review/config` (`runtime-config` + `team-config` + `models`).
+ - **Shared layers live in `packages/shared/*`, apps never depend on apps** (CI-enforced): `cli` and `dashboard` are application packages and MUST NOT depend on one another. This DAG is enforced by `@nx/enforce-module-boundaries` (root `eslint.config.mjs`, keyed off each project's `scope:*` tag) and gated in CI via `nx run-many -t lint` — an accidental `dashboard → cli` (or `shared → app`) import fails the build, not just review. Code both apps need (persistence, domain/state, config, cross-platform utilities) lives in dedicated library packages under `packages/shared/*` that each app depends on directly. The current shared packages are `@open-code-review/platform` (cross-platform/runtime utilities), `@open-code-review/persistence` (the `node:sqlite` adapter `db` + workflow `state` lifecycle + `test-support` + `vendor-resume` + the `node:sqlite` runtime precondition `runtime-checks` — kept in **one** package because `db` and `state` have a mutually-recursive *type* cycle (`db/types.ts` ↔ `state/types.ts`); a package boundary between them would form a dependency cycle. The single-module-instance connection-cache singleton is a *consequence* of that co-location, not its root cause), and `@open-code-review/config` (`runtime-config` + `team-config` + `models`).
- **Shared packages are source-only, private, and inlined — never published**: each `packages/shared/*` package mirrors `platform` exactly — `private: true`, `version 0.0.0`, every `exports` condition (`types`/`source`/`default`) points at `./src/*.ts` (no `build.mjs`, no `dist`), and it is declared by its **consumers** as a `devDependency: workspace:*` (consumer-side rule). A shared package still declares its own runtime third-party deps in its `dependencies` — they are inlined into the consumer's bundle, so they must resolve at build time. esbuild inlines the `.ts` source into each app's published bundle, so these packages are **excluded from the release set** (`!packages/shared/*` in `nx.json`) and do not join the fixed `cli`+`agents` release group. Do NOT give a shared package a `build` target or a `dist` — that machinery was removed in the cutover and must not return.
- **Graduation is by cause, not by count**: a slice graduates from an app package into a `packages/shared/*` package the moment it is consumed across a package boundary (by the other app, an e2e package, or another shared package) rather than only by its owning app's own code. There is no subpath-count trigger. A genuinely app-internal module stays in its app; the goal is to keep the dependency graph a DAG of `app → shared → shared`, never `app → app`.
## Release Process (GitHub + npm)
Releases are cut **locally from `main` with `nx release`**; npm publishing happens **only in CI**, gated by a cross-platform install verification. Versioning is conventional-commits driven; `cli` + `agents` are a fixed release group (always bump together — `dashboard`, `shared/*`, and `*-e2e` are excluded from releasing, see `release` in `nx.json`).
1. **Preconditions**: the work is merged to `main`; you are on `main`, pulled, with a clean tree; and the **push-triggered** CI run on `main` is green. (PR CI runs the e2e matrix on ubuntu only — macOS/Windows e2e run on push to `main`, so a green PR does NOT imply a green `main`.)
2. **Preview the bump** (no writes):
```bash
pnpm nx release --skip-publish --dry-run
```
Conventional commits since the last `v*` tag decide the specifier (`feat` → minor, `fix` → patch, `BREAKING CHANGE` → major). Sanity-check the computed version and the changelog preview.
3. **Cut the release**:
```bash
GITHUB_TOKEN="$(gh auth token)" pnpm nx release --skip-publish
```
This single command: bumps every manifest (including the synced copies in `packages/agents/.claude-plugin/plugin.json` and `packages/agents/skills/ocr/SKILL.md`), updates the lockfile, writes `CHANGELOG.md`, commits `chore(release): {version}`, tags `v{version}`, **pushes the commit + tag**, and **publishes the GitHub release**. Notes: the `GITHUB_TOKEN` env var is required for the GH-release step; `--yes` is mutually exclusive with `--skip-publish` (the latter already auto-answers the only prompt).
4. **npm publish happens in CI, never locally**: the `v*` tag push triggers `.github/workflows/release.yml`, which packs the real tarballs and **install-verifies them on 3 OS × 2 Node versions** (pnpm 10 with scripts blocked + npm; `ocr doctor --engine-only --probe-write` + a real on-disk state command) **before** running `nx release publish`. Plain `vX.Y.Z` tags publish to dist-tag `latest`; `vX.Y.Z-rc*` tags publish to `next`. The workflow can also be run via manual dispatch (with a dry-run option that skips publishing). **npm auth is OIDC trusted publishing — there is no `NPM_TOKEN` secret.** Both packages are configured on npmjs.com with this repo + `release.yml` as a GitHub Actions trusted publisher; if publishing ever fails with "not logged in", check that config (and that the publish step runs **pnpm ≥ 11** — pnpm 10 ships no OIDC trusted-publishing code at all; that wrong assumption produced exactly this ENEEDAUTH failure on the first v2.2.1 publish attempt) rather than hunting for a token.
5. **Verify**: watch the Release run to completion (`gh run watch`), then confirm the registry:
```bash
npm view @open-code-review/cli version && npm view @open-code-review/agents version
```
Never `npm publish` by hand, never tag without going through `nx release`, and never bypass the verify-install gate — it exists because 2.0.0 shipped an install break that only a real published-tarball install could catch.
<!-- OCR:START -->
## Open Code Review Instructions
These instructions are for AI assistants handling code review in this project.
Always open `.ocr/skills/SKILL.md` when the request:
- Asks for code review, PR review, or feedback on changes
- Mentions "review my code" or similar phrases
- Wants multi-perspective analysis of code quality
- Asks to map, organize, or navigate a large changeset
Use `.ocr/skills/SKILL.md` to learn:
- How to run the 8-phase review workflow
- How to generate a Code Review Map for large changesets
- Available reviewer personas and their focus areas
- Session management and output format
Keep this managed block so `ocr init` can refresh the instructions.
<!-- OCR:END -->