Project
Development rules
These are the rules for writing code in this repository. They apply to people and to AI agents alike. Each rule is an instruction, the reason for it, and the check that catches a break: a guard test, a CI workflow, or "review only" when a reviewer has to catch it.
A guard that fails names its rule. Fix the cause and leave the guard alone. Several guards keep a list that may only shrink. To grow one, put [ratchet +N: why] in a commit message and get a reviewer's yes (preflight R1).
The rules come from the spec (principles, security floor, engineering rules), the ADRs in docs/adr/, the guard tests in test/, scripts/team/preflight.mjs, and the owner's standing rulings. When this file and the code disagree, open an issue. One of them is wrong.
When you add, change or retire a rule, change it here in the same commit as its guard. A rule here with neither a guard nor "review only" is a bug.
Groups: Architecture, Security, UI and design, Data and records, Flows, Agents and prompts, Writing, Tests and CI, Releases, Git and commits.
Architecture
- Route every action on people, records, secrets and models through the kernel. One place decides who may do what. Check:
kernel/contracts/contracts.test.js,kernel/size.test.js,test/boundaries.test.js. - Call other parts through the registry and events. Do not import their files. Anyone may import the kernel (
core/config, store, events, modules, presence, daemon) andlib/<name>. A lib imports only the kernel and other libs. This keeps any module removable. Check:test/boundaries.test.js. - Build every part as a module with a
module.jsonand an entry file: core services, harness pieces, surfaces and third-party additions. One loader means one set of checks. Check:test/module-sdk.test.js,test/module-sdk-conform.test.js,test/module-api-compat.test.js,test/modules-boot.test.js. - Define a tool once. The definition becomes the MCP tool, the HTTP route and the CLI command, and anything the app does the
vyreCLI does too. Surfaces then cannot drift apart. Check:test/mcp-server-tools.test.js,test/app-tool-names.test.js(every tool name a screen sends exists). - Declare every event a module emits under
watches.emits. The loader refuses an undeclared event, but only when the line runs. Check:test/events-declared.test.js(theKNOWNlist shrinks only). - Declare every input a tool reads. The registry refuses undeclared keys from non-module callers, so an undeclared input passes a unit test and fails over the wire. Do not name an input
approval, the envelope key of a held act's retry. Check:test/declared-inputs.test.js,test/approval-reserved.test.js. - Declare
projectArgorcwdArgon any tool that takes a project or folder. The registry then checks the agent's grant once. Without it the tool has no grant check. Check:test/project-arg.test.js. - Keep a read free of writes. A tool that declares
effect: "read"writes nothing, emits nothing and calls no write tool. A tool that must write declareseffect: "write"and says who may call it. Check:test/reads-are-reads.test.js(KNOWN_WRITERSshrinks only). - State what each raw route does. Declare whether it reads or which methods write, and answer only those. Any page can send a GET, so a route with a side effect must refuse GET. Check:
test/route-declared.test.js. - Let the registry set the origin of a relayed call. A module that queues work for later keeps
ctx.origin()and replays it withctx.withOrigin. Otherwise a relay turns a model's call into the box's own. Check:test/module-origin.test.js. - Only append to a module's migration list. Do not move, edit or remove a released step. An upgraded box has already run the earlier ones. Check:
test/migrations-append-only.test.js(hashes intest/migrations.released.json). - Use the one mechanism for each job, and extend it before you add another. Two answers to one question cause security bugs. Check, by owner:
test/one-mechanism.test.js(role list, secret detector, grant model, approval path),test/one-role-list.test.js,test/one-person-surfaces.test.js,test/one-identity.test.js,test/one-registry.test.js,test/ids-single.test.js(lib/id.js),test/scrub-single.test.js(lib/scrub.js),test/http-single.test.js(lib/http.js),test/netguard-single.test.js(lib/netguard.js),test/cron-single.test.js(lib/cron.js),test/ws-single.test.js(lib/ws.js),test/bytes-single.test.js(lib/bytes.js,kernel/core/canonical.js),test/credential-shapes-single.test.js(lib/credential-shapes.js). Anything else: review only. - Read a list from its owner. Do not copy it into a surface. This covers tool names, role ids, AI providers, model names and tool-policy sets. A copy goes stale the day the owner changes. Check:
test/a5-no-copies.test.js,test/cohesion-drift.test.js(both lists shrink only). Where a copy cannot importlib/, generate it withscripts/sync-copies.mjsand leave the output alone:test/generated-copies.test.js. - Store business data as a record type. A module's own database holds private operating state only: tokens, caches, per-computer rows, queues, rebuildable indexes. A record type is shared and permissioned. A private table is neither. Check:
test/private-stores.test.js(a module that opens SQLite states why its data is operational). - Split a source file before it passes 2,000 lines. Files that large stop getting reviewed. A listed file may not grow. Check:
test/file-size.test.js(test/file-size.json). Added kernel lines need[kernel +N: why]after the lead's ruling (preflight K1), and the trusted base has a cap (kernel/size.test.js). - Justify a new dependency in one line in
ALLOWED-NEW.md, and say in the changelog why it is worth having. The codebase stays small and readable. Check:test/dependency-guard.test.js(test/allowed-dependencies.json). - Write plain JavaScript: Node 22.5 or newer, ES modules, JSDoc types with
// @ts-check,node:sqlite,node:test, no build step for the core. Anyone can read it. Check:test/dependency-guard.test.jsfor dependencies, review only for the rest. - Race a promise against a clock with
lib/within.js. A hand-rolled race with an unref'd timer once let the event loop drain with the call still pending. Check:test/within-hygiene.test.js. - Attach an error listener to a child's stdin before you write to it or end it. An unhandled EPIPE takes vyred down, and try/catch does not see it. Check:
test/stdin-hygiene.test.js. - Keep idle cheap. vyred idles under 0.9 percent of one core (p95) and under 1.8 percent sustained (5-sample mean), holds under 60 MB of heap after a full GC, and sets no recurring timer faster than 60 seconds. Heavy work runs at low priority. Vyre runs all day on the person's machines. Resident size is reported but does not gate on Node 24. Check:
npm run perf-check(scripts/perf-check,BUDGET) in CI (perf-idle.yml),test/bundle-size.test.jsfor the web bundle. - Use public Claude Code surfaces only: the plugin system and documented CLI flags. Read transcripts only in
core/transcripts, and fall back to "no history" when that fails. An undocumented behavior can change without notice. Check:test/provider-adapters.test.jskeeps a provider's formats, flags and files insidecore/sessions/drivers/<provider>(its list shrinks only). The rest: review only. - Give every setting a reader. If nothing reads a key declared in
module.json, wire it or remove it. A toggle that does nothing misleads the person. Check:test/settings-have-readers.test.js(DEADshrinks only). - Read behavior switches through
devSwitch()(kernel/devbuild.js), so a release build ignores the environment. Use the loopback seam inlib/http.jsin tests only. Check: preflight S1,test/http-seam.test.js. - Write an ADR in
docs/adr/for any decision a later contributor would question: a trade-off, a boundary, a path you rejected. Number it next in sequence and add it todocs/nav.json. The reasoning outlives the author. Check:scripts/docs-checkfor the nav, review only for the content.
Security
- Refuse when you cannot tell who is calling. If the chain or a definition is unreadable, refuse. Do not fall back to a broader reading. A fallback caused advisory GHSA-32h6-gq86-772f. Check:
test/peer-race.test.js, the golden tests inkernel/golden/. The principle itself: review only. - Hold every outward act at the Gate until the person has seen the final words. Mark each outward tool in its
module.json(outward: trueor a Gate kind). When unsure, mark it outward. The outward moment reads that flag and nothing else. Check:test/outward-flags.test.js(each exception carries a reason),test/presence-bypass.test.js,test/one-yes-floor.test.js. - Treat
mcpandharness, in any form, as model callers. They are never the person. Asklib/caller.js(isPerson,modelKey) and write no local helper. An unnamedmcponce became the person in chrome, hands and memory. A model, agent, hook or guest never approves its own held act. Check:test/model-is-never-person.test.js(FROZENshrinks only),test/person-only-guard.test.js,test/stage-gate-model-paths.test.js,test/thread-label-hygiene.test.js,test/person-label-hygiene.test.js. - Take the actor from the kernel's chain, not from a call's input. A field that names a person (
created_by,owner,as,approver) is a target or a lookup, and a reviewer signs off on it. A forged field would forge an identity. Check:test/identity-from-input.test.js. - Write
reachon every tool. An "anyone" entry names the guard that limits it, and a person-only tool says so in the registry as well as in presence. A forgotten line is an open door. Check:test/reach-explicit.test.js,test/reach-registry.test.js,test/reach-anyone.test.js,test/reach-anyone-behaviour.test.js,test/reach-person-only.test.js,test/reach-person-split.test.js,test/reach-classes.test.js,test/agent-reach-classes.test.js,kernel/retrofit/agent-reach.test.js. - Block a plain model session from write and outward tools. Refuse the call, hold it for the person, or list the tool with a reason. A model's shell can claim any caller label. Check:
test/plain-session-writes.test.js(test/plain-session-writes.json). - Keep sealed fields and vault values away from models, agents, logs and events. Reveal a value only to a person who just proved presence on their own device, for that one value. Check: the tests under
kernel/seal/,test/vault-model-item.test.js,test/vault-thread-gate.test.js,test/vault-member-gate.test.js,test/relay-never-reads.test.js. - Store a reference to a credential. Do not store the key. Flows, kits, skills, drafts and configs name
vault://itemor a Connection, because stored definitions get copied, shared and read by models. Check:test/references-not-values.test.js. - Define each vendor credential shape once, in
lib/credential-shapes.js. A new vendor key is one row. Two detectors disagree. Check:test/credential-shapes-single.test.js,test/credential-pins.test.js. - Keep added modules away from pairing and setup. No added module can pair, admit or drop a device, or set the server up, because those change who can reach the server. Check:
test/added-module-never.test.js,test/names-reach.test.js. - Reserve account changes and history rewrites for the person. Adding or removing accounts and rewriting session history are reach person and PERSON_ONLY (ruling of 13 Oct 2026). Check:
core/modules/account-tools-person-only.test.js. - Send security code to trust before it lands, and tag the branch
[reviewed: trust](or[reviewed: lead]). That code is the floor. Check: preflight R2. - Keep third parties out of the product. The relay reads no client content, and nothing shipped loads from a public CDN, font host or analytics host. Vendor files, pinned and hashed. Vyre keeps nothing about people on its own servers. Check:
test/relay-never-reads.test.js,test/no-cdn.test.js, preflight S2 (scripts/team/cdn-hosts.mjs). - Run no command from a folder someone else can write through vyred's git. A planted hook or filter driver would run. Check:
test/safe-git.test.js. - Keep a vyred on a temp home away from real boxes. It does not look for them or pair with them. A stress run once paired with a live box. Check:
test/link-guard.test.js. - Make every refusal say what to do next. A literal message names a real tool, says who decides, or gives an instruction. Give every error code a person can meet an entry in
lib/error-catalogue.js, so no caller guesses. Check:test/errors-teach.test.js,test/error-catalogue.test.js(baseline shrinks only). - Ship no other VPN product. The built-in network is Wink (owner ruling of 4 Oct 2026). Check: the VPN guard in
test/. Its file name and ratchet carry the other product's word, which this file cannot. The ratchet shrinks only.
UI and design
- Take every component from
@vyre/ui(apps/app/ui). Screens import no other UI library. The look stays one look. Check:apps/app/scripts/check-ui-imports.mjs(npm run lint:uiinapps/app), which bans@radix-ui,lucide-react,nativewindand the rest outsideui/. - Change the library component when a screen needs a change. Do not copy it into the screen. A copy forks the look, and the next fix misses it. Check:
test/design-rules.test.js(second-primitivefails an import of a second Button, Card, Row, IconButton, Banner, Icon, Avatar, List or Tag; baselineapps/app/scripts/design-rules.baseline.jsonshrinks only). - Add a component to
@vyre/uiwhen none covers the need, then use it from there. The library grows from real needs and stays the one place. Check: review only.test/design-rules.test.jscounts hand-built layouts (StyleSheet.create), so a bypass shows. - Take colour, type and layout from tokens. Set no colour literal,
fontSize,fontFamily,fontWeight,lineHeightorletterSpacingin a screen. A space's look, the paper scheme and a person's contrast choice reach screens only through tokens. Check:test/design-rules.test.js(raw-colour,type-literal),apps/app/src/theme/raw-colours.test.js,test/theme-defaults.test.js,test/tokens.test.js. - Keep the retired first accent colour retired. The owner picked Bone on 30 Sep 2026: no accent hue, cream on dark, ink on paper. Check: the colour guard in
test/(its file name carries the retired colour's word, which this file cannot). - Draw Vyre's own screens from blocks. A new route under
apps/app/app/ureachesBlockScreen, ortest/key-screens.test.jslists it as hand-written with a reason. That forces a decision for each new screen. Check:test/key-screens.test.js. - Use a button where you would show a terminal command. No string a person reads contains a
vyre ...command. People should not need a shell. Check:test/design-rules.test.js(command-line). - Format time with
lib/time, in a zone the caller names: the viewer's clock, and the space's. Times follow the person's zone and the space's. Set notoLocaleTimeString,toLocaleDateString,getHoursorgetMinutesin a screen. Check:apps/app/src/time/show.test.js("no screen formats a time by itself"; form inputs and the hidden Glass are exempt). - Keep internal words off screens. Write "Vyre", "the box" and "the Vyre app". Do not write "vyred", "switchboard", "no such tool", "Deck" or "as Claude Code does". When a literal must carry one, end its line with
// internal-word: <why>. Check:test/no-internal-words.test.js,test/site-words.test.js,test/no-deck.test.js. - Hold the web bundle to its budget. The first load stays under the ceiling and grows no more than 10 percent over the recorded baseline. A heavy first load is a slow product. Check:
test/bundle-size.test.js(.github/scripts/bundle-size.mjs).
Data and records
- Give each record type one keeper.
kernel/gateway/ownership.jsholds the one rule for which module keeps a type and who may write a project, seat or task. Check:kernel/gateway/ownership.test.js. - Write nothing for one industry. Code, schema, defaults and copy stay neutral across trades. Templates and kits carry the specifics. Vyre is one product for any team. Check: review only.
test/hygiene.test.jskeeps real businesses out of shipped code. - Permission records at the kernel. A protected type is read through no route that lets a member reach another person's records. Check: the tests in
kernel/gateway/(for exampleaggregate-visibility.test.js,attr-filter.test.js). - Delete when a person says forget. The record, its events, its history and any task text derived from it are gone, including after a restart. Check:
test/records-forget.test.js. - Keep placeholders out of stored data. No record, task or logged event holds "[object Object]" or the text "undefined" where a value belongs. A task once carried
flow: "[object Object]". Check:test/flows-data-hygiene.test.js. - Mint record ids with
lib/id.js. Ids sort by time. Keep secrets, tickets, nonces and passwords as random bytes with no time in them. Check:test/ids-single.test.js. - Read a person's identity from
spaces.identity.id. Pairing and install derive no id of their own, since two ids split one person's data. Check:test/one-identity.test.js,test/identity-one.test.js,test/one-registry.test.js.
Flows
- Guard every tool a Flow may run. A tool listed under
flow.stepsinmodule.jsonchecks the person's chain itself, andtest/flow-step-guards.jsonnames that guard. The Flows runner does not consult the kernel's action table, so a read tool has no other gate. Check:test/flow-step-guards.test.js(a stale line fails too). - Do not republish a change the Flows host published. A task change that re-enters the bus loops forever, and stop() once never returned. Check:
test/flows-publish-once.test.js. - Name credentials by reference in a Flow. See Security rule 8. Check:
test/references-not-values.test.js. - Parse cron in
lib/cron.jsonly, so a watcher and a Flow with the same schedule fire together. Check:test/cron-single.test.js. - Keep a model out of a stage gate. When a person must do a gate's task, no path through a model skips it. Check:
test/stage-gate-model-paths.test.js.
Agents and prompts
- Keep one instructions file per agent and per project:
AGENTS.md. A session starts in its project folder and reads it on start. Add no second file. Check: review only.vyre module newscaffolds one. - Give the person's assistant the person's reach, minus listed exceptions with a reason.
core/modules/agent-reach.jsclassifies tools as open or person-only, and no tool sits in both. Check:test/agent-reach-classes.test.js,kernel/retrofit/agent-reach.test.js. - Keep a tool description near 25 words. Every listed tool costs every session tokens. Long legacy ones sit in a baseline that shrinks; a new tool meets the cap. Check:
test/description-lint.test.js(test/description-baseline.json). - Keep the always-offered tools within about 30 tools and 6,000 tokens. Everything else goes through
tools_findandtools_call. Check:test/tools-budget.test.js,test/tools-find-quality.test.js. - Name tools by the one grammar. Names are an interface for models, and the rename table must stay sound. Check:
test/tool-names.test.js,test/tool-names-gates.test.js,test/tools-text-names.test.js. - Write
docs/agentsshort, true and for agents. Each page states a token budget and awhen, no human page links to one, and the site does not publish them. Generated blocks match the code (scripts/gen-agent-docs.mjs). An agent pays for each token it reads. Check:test/agent-docs.test.js. - Run a woken or lent agent inside the reach of the person it acts for. An agent is never the person. Check:
test/one-yes-floor.test.js,test/agent-change-daemon.test.js, thetest/reach-*.test.jsset. - Call models through the one inference door (
model.call,kernel/contracts/model.d.ts), and take model names fromsessions.models. Do not hardcode a model name in a surface. Check:test/cohesion-drift.test.js.
Writing
- Do not write an em dash or the section-sign character. Use a colon, a comma or two sentences. Write "Section 5.1". Check:
scripts/docs-check(thecharacterscheck inscripts/lib/docs/check.js, run bytest/docs-check.test.js) covers published docs and their includes. Code, commit messages and this file: review only. - Put no personal brand, real name, real business or secret in the repo. That covers code, docs, tests, fixtures and commits. Use the sample world: the user alex, Juniper Studio, Northwind Bakery, the agents juno and kit, and
example.com. Vyre is a product, not a portfolio. Check:test/hygiene.test.jsandscripts/lib/hygiene.js, whichscripts/docs-checkshares and extends to emails and IP addresses outside the example and documentation ranges. - Write plain product words, free of any industry. Use the second person, short paragraphs and fenced commands. Skip marketing adjectives, "simply" and "seamless". The reader could be on any team. Check: review only, plus the sample-world and word checks above.
- Say Personal, My Cloud and Cloud for spaces. Never "Basic" or "Pro" in text people read. Private chats are encrypted to the people in them, times follow the person's zone and the space's, and replies quote in the same timeline. These are the 0.2.9 docs rulings. Check:
test/docs-rulings.test.js. - Ship a doc page with each feature, in the same change. The page has front matter and a place in
docs/nav.json, and its links and anchors resolve. A feature without a page does not exist for users. Check:npm run docs:check,test/docs-check.test.js,test/docs-build.test.js. - Name only commands, tools, config keys and variables that exist. A stale hint misleads more than no hint. Check:
test/docs-index.test.js(the terms index inscripts/lib/docs/terms.js) and thestalecheck in docs-check. - Regenerate generated pages. Do not edit them. Run
npm run docs:ref,scripts/gen-architecture-map.mjsandscripts/gen-agent-docs.mjs. Hand edits get overwritten. Check:test/architecture-map.test.js,test/agent-docs.test.js, preflight G1. - Keep the architecture map a 30-minute read that names every top-level folder, kernel folder and module. Check:
test/architecture-map.test.js. - Say "the Vyre app" in docs people read, not "the Deck". History, ADRs and release notes are exempt. Check:
test/no-deck.test.js. - Apply the same word list to the app, the site and
llms.txt. Check:test/no-internal-words.test.js,test/site-words.test.js,test/installer-copy.test.js.
Tests and CI
- Write the test that would have caught the bug, and confirm it fails without your fix. A test that never failed proves nothing. Tag a behavior-free change
[refactor]. Check: preflight T5. - Put tests next to their code, run by
node --test, with cross-module tests intest/. Get a tempVYRE_HOMEfromtempHomeand make folders only underSCRATCH(test/scratch.mjs). Tests must never touch a real~/.vyre, real transcripts or the screen. Check:test/tmp-guard.test.js(the leak guardtest/tmp-guard.mjsruns before and afternpm test),test/temp-home-claude.test.js. - Import the Mac guard in every test file (
scripts/mac-test-guard.mjs), so a test never runs on a person's Mac. A test once reached a live machine. Check:test/mac-test-guard.test.js,scripts/check-test-guard.mjs. - Place every test file under a glob the runner reads (
scripts/test-counts.mjs). A file outside every glob is a green that never saw it. A file that runs elsewhere appears inEXTERNALwith the workflow that runs it. Check:test/every-test-runs.test.js. - Run every test a file recorded. Fewer tests than declared, or than the last recorded run, fails (
test/test-counts.json). A crash that skips the rest looks green otherwise. Check:test/test-counts.test.jsand the runner. - Skip nothing. Do not add
test.skip,test.todo,it.skiporskip: true. A test of one platform's own behavior runs on that platform's CI. Tests listed intest/must-run.jsonfail on a skip whenVYRE_MUST_RUN=1. A skip hides a red. Check: preflight T1,scripts/test-counts.mjs. - Release with zero failing tests. Keep no list of known failures. Fix a red; do not carry it. App type errors count wherever they appear (owner ruling of 10 Oct 2026). Check: preflight T2 and T3, the
node.ymlshards,test-sweep.yml. - Delete a test, guard or piece of test machinery only with
[delete: why]. A merge once dropped the headless Chrome helper. Check: preflight D1. - Run anything that talks to Claude Code or a network against the real thing once before merge. A fake proves the logic, not the integration. Point fakes through
VYRE_CLAUDE_BIN,VYRE_SSH_BIN,VYRE_OPEN_BINandVYRE_HANDS_BIN. Check: review only. - Run daemon tests on a test box or a runner, not on a Mac. Preflight refuses to run tests on macOS and offers
--staticthere. Check: preflight P1. - Fix the cause when a guard fails. Do not loosen it. A ratchet list shrinks only. Check: preflight R1 (
scripts/team/ratchets.mjs),test/ratchets.test.js. - Refresh the golden decisions in CI. The
golden-refreshworkflow writeskernel/golden/golden.json,allow.jsonandpresence.jsonwhen you push a commit containing[golden-update]. A test box gives other answers than CI. A widening needs a written ruling. Check:kernel/golden/allow.test.js,kernel/golden/golden.test.js,test/golden-widenings.test.js,.github/workflows/golden-refresh.yml. - Give each seam a contract test. Every file in
test/contractsguards both sides of its seam. Check: preflight runs them all. - Measure performance in CI. Run
npm run perf-check. Check:.github/workflows/perf-idle.yml,runner-perf.yml.
Releases
- Sign each release with the key in the
releaseenvironment and check the pinned public key and the lineage. An update must come from us. Before approving the environment, read the diff of any signing file. Check:test/release-key.test.js,test/sign-manifest.test.js,test/release-lineage.test.js,test/release-verify-workflow.test.js,test/release-workflow.test.js,.github/workflows/release.yml,release-verify.yml. - Build the release from what the tests proved. Check the dist and the served files. The package holds what the box and the image need, including the golden dump. Check:
test/check-release-dist.test.js,test/check-served.test.js,test/package-files.test.js,test/golden-pack.test.js,test/box-pack-covers-dockerfile.test.js. - Use the bump script and the release counter. Do not hand-edit versions. Check:
test/release-counter.test.js,test/bump-version.test.js,test/patch-release.test.js. - Freeze released migrations. After a release, record them with
node scripts/record-migrations.mjs. See Architecture rule 11. Check:test/migrations-append-only.test.js. - Ship with zero failing tests and list no known failures in the notes. See Tests and CI rule 7. Check: preflight T2 and T3.
- File every bug as a GitHub issue in
vyre-ai/vyre, with thebuglabel and a milestone. Send a security bug to a private advisory, not a public issue. One list shows what is broken, and nothing sensitive goes public. Check: review only. - Write down what the release does not do in
docs/known-gaps.md, and keep the roadmap true. The README and docs must tell the truth. Check:scripts/docs-checkfor links and stale mentions, review only for the content. - Prove the install on a real machine before calling a release ready: a fresh machine, the real installer, the real onboarding. Green unit tests missed a failed first install. Check:
.github/workflows/install-proof.yml,packaged-boot.yml,matrix.yml,journeys.yml.
Git and commits
- Write conventional commits, one concern each:
feat:,fix:,refactor:,docs:,test:, plusci:andsecurity:where history uses them. A readable history helps every later reader. Check: review only. - Add a line to
CHANGELOG.mdin the same commit as any code change, under## Unreleased, in plain sentences that say what changed and why. A new dependency says why it is worth having. The changelog is the release notes. Check: review only. - Commit by path:
git commit -m "..." -- <paths>. Parallel sessions then never sweep up each other's files. A pathspec protects the index but not a shared append-only file such asCHANGELOG.md. Check: review only. - Credit the repository owner only. Leave out
Co-Authored-By: Claude, "Generated with Claude" lines and session trailers in commits, merges, pull requests and release notes. Check: preflight G3. - Do not use
git stash, force-push, amend a pushed commit or pass--no-verify. The stash stack is shared across worktrees, and the others rewrite history that other people rely on. Use a WIP commit or a second worktree. Check: review only. - Leave generated files out of your commits. The merge queue regenerates them. Leave no conflict markers. Check: preflight G1 and G2.
- Tag a ruling in the commit that needs it:
[kernel +N: why]for kernel growth,[ratchet +N: why]for a growing list,[reviewed: trust]for security paths,[delete: why]for removed test machinery,[refactor]for a behavior-free change,[golden-update]to refresh the golden decisions in CI. Check: preflight K1, R1, R2, D1, T5. - Land work through the queue. Run
node scripts/team/preflight.mjson a test box before you queue (only--staticruns on a Mac). When you edit another team's paths (scripts/team/owners.json), talk to that team first. Check: preflight,.github/workflows/merge-queue.yml.