context-manager is part of the Connectome ecosystem (agent-framework, membrane, chronicle, connectome-host). These conventions describe how work actually lands here — they codify existing practice rather than aspiration. When in doubt, recent merged PRs are the best reference.
Everything below applies to every change however it lands — external PR or maintainer direct push — and to human and AI authors identically. There is no separate rulebook for either.
- External contributions come as PRs against
main, from a fork or a repo branch. Maintainers also land small changes directly onmain; don't be surprised by history that never saw a PR. - Branch names:
feat/<kebab-case>,fix/<kebab-case>,docs/,chore/. Including the issue number is welcome (fix/23-budget-descent). - PRs are merged as true merge commits — no squash, no rebase-merge. Because nothing is squashed, keep individual commits coherent.
- To update a stale branch, rebase onto
mainor mergemainin; both are accepted. - Stacked PRs and cross-repo companion PRs are fine, but declare them in the body with merge-order guidance ("stacked on #7 — review that first"; "safe to merge in either order because …"). This package sits on chronicle and membrane and is consumed by agent-framework and connectome-host, so companion PRs are common; say which side is safe to land first and what happens if only one does.
Body shape (the PR template mirrors this): Problem / Changes / Tests, plus, when applicable, Not verified, Out of scope, and Companion PRs. The conventions that matter:
- Evidence over assertion. State the test baseline numerically:
"
npm test: N pass / M fail, failure count identical tomainbaseline." A claim like "all tests pass" without the count will be re-verified anyway, so save the reviewer the trip. - Say what you did NOT verify. Compression behavior is emergent and hard to unit-test honestly: a strategy change that passes the suite can still degrade on a real store. Say whether you ran it against a real store, at what size, and what you did not exercise. A silent gap that review uncovers is not respected; an honest one is.
- Tests accompany behavior changes. Review scrutinizes test substance, not mere presence — a test that can't fail on the unfixed code will be called out, and a compression test whose fixture is too small to trigger the path it claims to cover is the local specialty of that failure.
- Changelog entry under
## Unreleasedfor anything behavior-affecting (see below).
Conventional-commit-style titles (feat(strategy): …, fix(compression): …)
are the house default; plain descriptive titles are accepted.
- Review arrives as ordinary PR comments, not GitHub review approvals — the comment thread is the gate. Reviews are frequently AI-generated and explicitly labeled as such, with a severity verdict and itemized findings.
- The reviewer will typically run your branch (typecheck, test suite, often a compile against a real store to see the token curve) and paste transcripts. Claims are checked, not trusted.
- Respond by pushing fix commits and replying per finding — "Addressed in
<sha>" — rather than force-pushing a rewritten branch. A re-review then flips the verdict. - Maintainers may push small review fixes directly to your branch to keep things moving. Say so in the PR body if you'd rather they didn't.
- PRs are never closed silently: a closed PR gets a one-line disposition comment (usually supersession by another PR).
AI-written code is the norm in this ecosystem, welcome from everyone, and held to exactly the same evidence standards as anything else. Declare it the way we do:
- the
🤖 Generated with [Claude Code](https://claude.com/claude-code)footer (or equivalent for your tooling) in the PR body, and - a
Co-Authored-By:trailer naming the model in commits.
What earns an automated contribution a changes-requested review is not being AI-generated — it's arriving without the suite having been run, with tests that don't fail on unfixed code, or with claims the branch itself disproves.
CHANGELOG.md keeps a standing ## Unreleased section with
### Breaking / ### Added / ### Changed / ### Fixed subsections
(loosely Keep a Changelog).
- The entry lands with the change — same commit, or at least the same
PR. This binds direct pushes to
mainjust as much as PRs. On PRs, CI enforces it softly: touchingsrc/without touchingCHANGELOG.mdfails thechangelogcheck unless theno-changeloglabel is applied. - What needs an entry: anything a host or strategy author would notice — strategy behavior and option types, compression triggers and thresholds, token budgeting and holdback, pinning, cache-breakpoint placement, what a compile emits, public exports, defaults. Internal refactors, test-only, and docs-only changes don't.
- Breaking entries are audience-scoped. Name the audience in the heading
(
### Breaking (host operators only)) and cover: who needs to act, migration, and unchanged (what readers might fear broke but didn't). Config that becomes required is the sharpest case here — an option that starts throwing when unset breaks every recipe that omitted it, and that is exactly what the "who needs to act" line is for. - Keep one
## Unreleasedheading. Add entries under the existing one; don't open a second. Only the first is cut at release time, so entries filed under a later heading are silently never released — the release script refuses to run if it finds more than one. - Releases (maintainers):
npm version <patch|minor|major>does the whole cut — theversionhook retitlesUnreleasedto## X.Y.Z — YYYY-MM-DD(keeping a freshUnreleasedabove it, and refusing to release when there are no entries), then npm commits and tags.git push --follow-tagstriggers CI, which refuses a tag with no matching changelog section, publishes@animalabs/context-managerto npm, and creates the GitHub release with that section as its notes. The two release jobs are independent: some consumers run github-clone checkouts, so release notes must exist even when npm publish fails. Version bumps are a maintainer release-time action, not part of feature PRs.
npm ci # strict lockfile install (see below)
npm run build # tsc; tests run from dist/, so build first
npm test # node --test dist/test/*.test.js dist/test/adaptive/*.test.js
npx tsc --noEmit # typechecknpm test runs the compiled output, so a stale dist/ will happily test
code you no longer have — always build before testing, and after switching
branches.
Push-time CI (ci.yml) builds, typechecks and tests every push and PR on
ubuntu and macos, installing with npm ci. The lockfile is committed and
strict: npm install on npm >= 11 will quietly re-resolve platform packages
missing from the lock, so only npm ci fails loudly on a lock that is broken
or out of sync. If you change dependencies, commit the regenerated lock — and
note that a lock regenerated over an existing node_modules tree records
only your platform's native binaries, which is why CI installs on both.
bench/ and playground/ hold the harnesses for looking at real compression
behavior rather than fixtures; docs/ carries the design notes behind the
strategies.