Skip to content

Commit 5ac368d

Browse files
authored
Merge pull request #5 from pashifika/docs/operator-documentation
docs: write the operator and authority documentation
2 parents 5b5b82c + 03a364d commit 5ac368d

4 files changed

Lines changed: 578 additions & 507 deletions

File tree

CLAUDE.md

Lines changed: 213 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,22 @@
11
# Repository Guidelines
22

3-
## Authority
3+
## Authority and scope
4+
5+
`omp-codebase-memory` distributes `codebase-memory-mcp` (CBM) as an installable
6+
OMP extension: it owns the executable's lifecycle, wires one MCP server entry,
7+
and ships context artifacts harvested from that executable. It is TypeScript on
8+
Bun, has no npm runtime dependencies, and commits its bundled entry points at
9+
`dist/index.js` and `dist/augment.js`. `README.md` states what the package does
10+
for an operator; this file does not restate it.
411

512
`rasen/specs/` contains the accepted capability specifications and outranks
613
change proposals. `rasen/changes/` records design decisions and their rationale;
7-
do not duplicate that rationale here.
8-
9-
When implementation changes a normative decision, update the affected
10-
specification in the same change.
14+
do not duplicate that rationale here. When implementation changes a normative
15+
decision, update the affected specification in the same change.
1116

12-
## Project boundaries
13-
14-
`omp-codebase-memory` distributes `codebase-memory-mcp` (CBM) as an installable
15-
OMP extension. It is TypeScript on Bun, has no npm runtime dependencies, and
16-
commits its bundled entry points at `dist/index.js` and `dist/augment.js`.
17-
18-
The following boundaries are fixed:
19-
20-
- Consume CBM release artifacts; contributing changes to
21-
`DeusData/codebase-memory-mcp` is out of scope.
22-
- Adopt an existing `codebase-memory-mcp` on `PATH` and never replace it. Put a
23-
package-managed copy under a package-owned root outside the plugin tree. Never
24-
write `~/.local/bin` or modify an executable this package did not install.
25-
- Own exactly the `codebase-memory-mcp` key under `mcpServers` in the active OMP
26-
agent directory's `mcp.json`. Upsert it idempotently, fail closed on an
27-
unparseable file or foreign `command`, and remove it only while it still
28-
matches the package-owned entry.
29-
- Never create or modify an operator's OMP agent-directory `AGENTS.md` or
30-
`RULES.md`.
31-
- Never register a `tool_call` handler. Augment successful output through
32-
`tool_result`, append rather than replace prior content, and fail open.
33-
- Never use platform timer globals. Use the handler context's managed timers
34-
through `src/scheduler.ts`.
35-
- Never set an account-wide CBM configuration key for the operator.
36-
- Never duplicate an action already exposed through CBM's MCP tools, including
37-
indexing.
38-
- Never hand-edit generated context artifacts; regenerate them from the CBM
39-
executable.
40-
- Never place verification scratch inside a directory the operator owns, and
41-
never delete a directory this package or its verification did not create. A
42-
project-local plugin root belongs in a temporary directory, not under the
43-
repository's `.omp/`, which holds the operator's own project-local skills and
44-
configuration.
45-
46-
This package owns only the executable it downloaded and its MCP entry. CBM owns
47-
the graph, indexing, watcher, cache root, and updates to a system installation.
48-
Windows and changes to any other operator file are out of scope.
17+
This file is the authority for repository guidance. `AGENTS.md` is a tracked
18+
symbolic link to it, so both agent tool families read one text; do not create a
19+
second copy of these rules anywhere.
4920

5021
## Repository layout
5122

@@ -55,70 +26,228 @@ The working tree contains two independent Git repositories:
5526
`test/`, `dist/`, `package.json`, and `.omp-plugin/`.
5627
- `rasen/` tracks planning artifacts in its own repository and remote.
5728

58-
`rasen/` is ignored by the outer repository. Commit its work with
29+
`rasen/` is ignored by the outer repository, so `git status` at the root never
30+
reports its state and it has to be inspected on its own. Commit its work with
5931
`git -C rasen`; never stage planning and implementation in the same repository.
6032

6133
## Git workflow
6234

63-
`main` and release tags are protected by the committed rulesets under
64-
`.github/rulesets/`. Before implementation, create a short-lived topic branch
65-
named `<type>/<short-slug>`.
66-
67-
Use Conventional Commits and land changes through pull requests. The ruleset
68-
permits merge commits only; do not squash. Unresolved review threads block the
69-
merge.
70-
71-
Treat the committed rulesets as authoritative. Change and reimport those files
72-
rather than editing protection through the web interface.
35+
Never commit implementation to the default branch. Cut a short-lived topic
36+
branch from it before implementation begins, and name it `<type>/<short-slug>`
37+
using the Conventional Commits type that dominates the change. Branches already
38+
landed this way: `feat/graph-context-and-agents`,
39+
`docs/repository-guidelines`, `chore/commit-ruleset-payloads`.
40+
41+
The default branch and release tags are protected by the rulesets committed
42+
under `.github/rulesets/`. This paragraph and the list below it state two things
43+
and no more. First, the shape of that protection: the facts whose change would
44+
change the sequence of steps by which work lands here — what a contributor must
45+
do, which button merges, whether a branch must be current first. Second, the two
46+
literals a ruleset shares with a workflow: the required check name `ci`, which
47+
`main.json` requires and which is the gate job's own name in `ci.yml`, and the
48+
tag pattern `v*`, which `tags.json` protects and which `release.yml` triggers
49+
on. Nothing reads either ruleset file, so neither agreement is checked anywhere;
50+
that is why those two are stated here at all. (The third pairing, between a
51+
pushed tag and `.omp-plugin/marketplace.json`'s `source.ref`, is checked — the
52+
release version gate fails on a mismatch — so it lives in `CONTRIBUTING.md`
53+
with the procedure, not here.)
54+
55+
A value that only tunes a threshold inside a step that stays the same is a
56+
parameter and stays in the rulesets: the actor and bypass lists, the
57+
review-dismissal and code-owner switches, the exemptions. Read those there
58+
rather than trusting a value repeated in prose. The approval count is zero
59+
today, so there is no approval step to describe; were it to change, the list
60+
below would gain one. The shape:
61+
62+
- The default branch rejects deletion and non-fast-forward pushes.
63+
- Landing a change requires a pull request whose review threads are resolved.
64+
- The merge commit is the only permitted merge method.
65+
- Exactly one status check, named `ci`, is required, under a strict policy — so
66+
a branch must be current with the default branch before it can merge.
67+
- Release tags matching `v*` reject deletion and non-fast-forward pushes.
68+
69+
Change protection by editing those files and reimporting them, never through the
70+
web interface. A rule changed in the browser is invisible to review and is
71+
overwritten by the next import.
72+
73+
The merge-only restriction is pinned rather than preferred. A squash rewrites
74+
the commits a dependent pull request still carries, so every downstream diff
75+
re-inflates with changes that already landed and each dependent branch needs a
76+
rebase per merge. Preserving the commits is what makes a dependent pull-request
77+
chain cheap here: a branch stacked on another stays mergeable while its parent
78+
lands.
79+
80+
Commit messages follow Conventional Commits. Choose commit boundaries for
81+
coherence — one reviewable decision per commit — rather than by file count or
82+
by when the work happened.
7383

7484
## CI and release
7585

7686
Branch protection requires one status check named `ci`. It is the gate job in
77-
`.github/workflows/ci.yml`, runs under `if: always()`, fails when it aggregates
78-
no jobs, and accepts only successful dependencies.
79-
80-
- Update the gate's `needs` whenever a required runtime job changes. Do not add
81-
runtime job names to the ruleset.
82-
- Keep `install-check` outside the gate because it cannot install a pull
83-
request's merge ref.
84-
- Pin every external `uses:` to a full 40-character commit SHA followed by a
85-
version comment.
86-
- Default to `permissions: contents: read`, use
87-
`persist-credentials: false`, and grant `contents: write` only to the release
88-
publish job.
89-
- Do not apply `paths` filters to jobs required by the gate.
87+
`.github/workflows/ci.yml`: it runs under `if: always()`, fails when it
88+
aggregates no jobs, and accepts only successful dependencies. `always()` is
89+
load-bearing, because a skipped required check blocks a pull request instead of
90+
failing it.
91+
92+
- Runtime job names never appear in a ruleset. Adding, removing, or
93+
restructuring a runtime job means editing the gate's `needs` and nothing else.
94+
Renaming the gate job silently blocks every merge, with no failing job to
95+
point at.
96+
- Keep `install-check` outside the gate because it installs by ref and a pull
97+
request's merge ref does not exist on the remote as an installable ref.
98+
- Every `uses:` reference is pinned to a full 40-hex commit SHA followed by a
99+
trailing version comment. The `hygiene` job enforces both halves and fails
100+
when it finds no references to check.
101+
- Default to `permissions: contents: read`, use `persist-credentials: false`,
102+
and grant `contents: write` only to the release publish job.
103+
- Do not apply `paths` filters to jobs the gate requires.
90104
- Pin Bun and its matching `@types/bun` version exactly. Install with
91105
`--frozen-lockfile`.
92106
- Run checks through package scripts and print toolchain versions with results.
93107
- Do not add a Node job; Node is not a supported runtime.
94108

95-
`dist/index.js` and the feature entry `dist/augment.js` are committed. CI must
96-
read the bundle list from `package.json`'s extension entries, build from
97-
source, and compare each result byte-for-byte with its tracked bundle.
109+
`dist/index.js` and the feature entry `dist/augment.js` are committed. CI reads
110+
the bundle list from `package.json`'s extension entries, builds from source, and
111+
compares each result byte-for-byte with its tracked bundle.
98112

99-
A release tag must match `package.json`'s version and both the version and source
100-
ref in `.omp-plugin/marketplace.json`. Create releases only from verified tags.
113+
A release tag must match `package.json`'s version and both the version and
114+
source ref in `.omp-plugin/marketplace.json`. Create releases only from verified
115+
tags. `CONTRIBUTING.md` holds the procedure.
101116

102117
## Testing and verification
103118

104-
Add deterministic tests for changed behavior. Cover the package boundaries
105-
affected by the change: release selection and checksums, archive validation,
106-
executable resolution, MCP-entry ownership, transport security, scheduler
107-
behavior, and handler fail-open paths.
119+
Add deterministic tests for changed behavior. Cover the package boundaries the
120+
change touches: release selection and checksums, archive validation, executable
121+
resolution, MCP-entry ownership, transport security, scheduler behavior, and
122+
handler fail-open paths.
123+
124+
Where a new test belongs:
108125

109-
`test/unit` must not require a CBM executable or network access. Use recorded
110-
fixtures under `test/fixtures` and helpers in `test/support`. `test/packaging`
111-
may build and load the bundle and touch the filesystem. Checks that require a
112-
real executable or network access belong in a separate job.
126+
- `test/unit` by default. It must not require a CBM executable or network
127+
access. Use recorded fixtures under `test/fixtures` and helpers in
128+
`test/support`.
129+
- `test/packaging` when the test needs a build or a real load of the bundle. It
130+
may touch the filesystem.
131+
- A CI job of its own when the check needs a real executable or the network, as
132+
`harvest` and `install-check` do. Neither suite may acquire either.
113133

114134
Report the commands and revision used for verification. State which relevant
115135
checks were not run and why; never claim an unexecuted check passed.
116136

137+
## Prohibitions
138+
139+
Each entry carries the mechanism that makes it a rule. A prohibition whose
140+
reason reduces to "it breaks things" is removed by the next contributor who
141+
finds it inconvenient.
142+
143+
**Never replace an executable this package did not install.** Adopt an existing
144+
`codebase-memory-mcp` from `PATH` or `~/.local/bin` as it is. Place a managed
145+
copy only under this package's own root, `~/.omp/codebase-memory/bin/<version>/`
146+
(`src/paths.ts`), which is outside both the plugin tree and the agent directory
147+
— OMP replaces version-qualified plugin directories on reinstall, so an
148+
executable stored inside one is discarded and re-downloaded by a routine plugin
149+
upgrade. System installations win because CBM resolves one canonical per-account
150+
cache root and refuses to run when a process is configured against a different
151+
root while any CBM session is active: two executables of different versions
152+
sharing that root produce mismatched index generations. `~/.local/bin` is CBM's
153+
own installer's directory and CBM's `update` owns the file there.
154+
155+
**Own exactly the `codebase-memory-mcp` key under `mcpServers` in the active
156+
agent directory's `mcp.json`, and nothing else in that file.** Upsert it
157+
idempotently, and remove it only while it still matches the package-owned entry.
158+
OMP's own `/mcp add` writes the same file with no lock shared with this package,
159+
so the write is a read-modify-write against observed content that fails closed on
160+
a shape it does not recognise: a lost update degrades to a missing entry the next
161+
session start rewrites, rather than a corrupted file. A `command` under that key
162+
that this package did not write means another installer owns the name, so the
163+
file is left untouched and both paths are reported.
164+
165+
**Never create or modify an operator's OMP agent-directory `AGENTS.md` or
166+
`RULES.md`.** Both are single-slot: the reader takes one file per slot, so
167+
writing either does not add to the operator's instructions, it silently
168+
suppresses them. In the agent directory `AGENTS.md` is the one surviving
169+
user-level context file, and `RULES.md` occupies the single slot reserved for the
170+
operator's sticky rules. This scopes to the operator's runtime directory. It is
171+
explicitly not about this repository's own root `CLAUDE.md` and `AGENTS.md`,
172+
which are project context discovered from a checkout and claim neither slot — a
173+
reader who conflates the two will read the rule as contradicting the file it is
174+
written in.
175+
176+
**Never delete `.omp/`, at either location.** `.omp/` is an OMP directory that
177+
belongs to the operator: `~/.omp/` holds their account configuration, and this
178+
repository's own `<project>/.omp/` holds their project-local `config.yml` and
179+
skills root. Neither may be deleted, and neither becomes deletable because a
180+
verification step is what materialized it. Cleaning up verification scratch
181+
removes exactly the paths that step created, named one by one — never a
182+
containing directory. The loss is silent by mechanism: a global ignore excludes
183+
`/.omp/`, so the directory is untracked, `git status` never reports it missing,
184+
and nothing fails until a later session reads what is no longer there.
185+
186+
The incident behind that entry: verifying an install with `enabledFeatures: []`
187+
needs a plugin root carrying that selection, and one was created under
188+
`<project>/.omp/plugins/`. Cleaning it up took the operator's `config.yml` and
189+
project-local skills root with it, and the loss surfaced a session later as a
190+
skill registry advertising roughly sixty skills while resolving five. The
191+
placement that avoids it is a temporary directory — `mktemp -d`, which is what
192+
CI already uses for a scratch `HOME` — never a path under `<project>/.omp/` or
193+
`~/.omp/`.
194+
195+
**Never register a `tool_call` handler.** OMP treats a handler that throws or
196+
blocks there as a refusal of the tool call, so one slow graph query would deny
197+
the operator's `grep`. Augment successful output through `tool_result`, where a
198+
failure is caught and the run continues; append rather than replace prior
199+
content, and fail open.
200+
201+
**Never call the platform timer globals.** Use the handler context's managed
202+
timers through `src/scheduler.ts`. A raw `setTimeout` callback that throws
203+
escapes handler dispatch entirely and surfaces as a process-level
204+
`uncaughtException`, which OMP's postmortem handler treats as fatal and tears
205+
down the whole session. The context's timers run the callback with handler
206+
isolation, are `unref`'d, and are cleared on `session_shutdown`.
207+
208+
**Never set an account-wide CBM configuration key for the operator.** CBM 0.10.8
209+
exposes six keys through `codebase-memory-mcp config set``auto_index`,
210+
`auto_index_limit`, `auto_watch`, `ui-lang`, `ui_enabled`, `ui_port` — and every
211+
one is account-wide; none is scoped to a project or to a client. That store is
212+
shared with every CBM client on the machine, so a key written here silently
213+
changes what another editor's CBM session does. A read-before-write does not
214+
make it reversible: nothing records that this package wrote the key, and another
215+
client may set the same key meanwhile, so the value to put back is not knowable.
216+
217+
**Never duplicate an action CBM's MCP tools already expose, indexing included.**
218+
The model already holds `index_repository`, and a second path through this
219+
package would take its own arguments and defaults — the two diverge, and the
220+
operator cannot tell which one ran.
221+
222+
**Never hand-edit a generated context artifact.** Regenerate with
223+
`bun run harvest`. The source of these artifacts is embedded in the CBM
224+
executable and changes with it, so a hand edit is a second, diverging statement
225+
of the same contract until the next regeneration overwrites it. A unit test
226+
re-runs every build guard against the committed files, and the `harvest` CI job
227+
regenerates and diffs them.
228+
229+
Contributing changes to `DeusData/codebase-memory-mcp` is out of scope; this
230+
package consumes CBM release artifacts. This package owns only the executable it
231+
downloaded and its MCP entry. CBM owns the graph, indexing, the watcher, the
232+
cache root, and updates to a system installation. Windows and changes to any
233+
other operator file are out of scope.
234+
117235
## Documentation
118236

119237
`README.md` is operator-facing and must be created or rewritten through the
120-
`readme-creator` skill and its quality checklist. If that skill is unavailable,
121-
stop rather than editing the README by hand.
122-
123-
This file is the authority for repository guidance. `AGENTS.md` must remain a
124-
tracked symbolic link to `CLAUDE.md`; do not create another copy of these rules.
238+
`readme-creator` skill, following its phases and scored against its quality
239+
checklist. If that skill cannot be resolved by name, stop; do not edit the README
240+
by hand. `CONTRIBUTING.md` holds only procedures that need maintainer
241+
credentials and links here for every rule.
242+
243+
`AGENTS.md` must remain a tracked symbolic link to `CLAUDE.md`, with `CLAUDE.md`
244+
as the regular file. Both names are needed and neither reader finds the other's
245+
file: Claude Code reads the root `CLAUDE.md`, while OMP's `claude` provider
246+
reads `.claude/CLAUDE.md` and discovers a root `AGENTS.md` through its
247+
standalone provider. Two regular files would satisfy both readers and diverge on
248+
the first one-sided edit.
249+
250+
Do not add `.omp/AGENTS.md`. This repository's `.omp/` is non-empty, so a native
251+
project context file there would win the depth-0 scope and shadow the root file
252+
that both readers already find — replacing one text with a second that only OMP
253+
sees, for no gain.

0 commit comments

Comments
 (0)