Repository development
Keep the workflow small, evidence-based, and friendly to concurrent Agents.
Repository governance
- Treat the repository as the Agent's working environment. When a recurring task
is hard to route or verify, improve its existing owner, route, or Skill instead
of adding a private workaround or another source of truth.
- Treat an Agent completion claim as a proposal. Targeted tests, independent
verification, clean CI, and—when the change crosses an external boundary—a
real integration run determine whether the change holds. Each proof is scoped
to what it actually measured.
- Move work, PRs, decisions, guardrails, and releases only through their explicit
lifecycle operations. Do not infer a state transition from phrases such as
"done" or "ship it" and do not bypass its prerequisites.
- Detect entropy aggressively: stale temporary work, expired guardrails,
duplicate tests, unused compatibility layers, and superseded abstractions.
Automatically remove only generated, cached, or explicitly expiring material;
propose reviewable candidates before deleting source, history, public
interfaces, issues, or pull requests.
- Keep one authoritative writer for each fact. Observe or reference GitHub,
Contracts, repository state, verification receipts, and NMG memory through
their owning interfaces rather than mirroring them into a competing store.
- In a shared or parallel-Agent worktree, isolate before you commit. Run
git status --short first: other Agents' uncommitted changes, or a HEAD that
moved under you, mean the tree is shared. Never git add -A or git commit -a
there; stage only your owned paths. When the worktree is actively shared,
prefer a dedicated git worktree add for your change, commit only your files,
and hand the shared tree back by reverting only your files to HEAD. A commit
that silently swallows another Agent's working tree is a coordination failure,
not a merge. When the change lands or is abandoned, remove the dedicated
worktree and its branch (git worktree remove <path> then git branch -D <name>) so used-up worktrees do not accumulate.
Before editing
Run npm run agent:context -- <target-path>. Positional paths route the
explicit scope without consulting Git. Use --changed only when dirty Git
paths should be added automatically; that mode requires working Git inspection.
Treat unknown reconciliation as missing applicable evidence, and drifted
as a request to inspect the reported declaration, snapshot, or verification
mismatch. Neither status is an architectural verdict.
Inspect git status --short; preserve unrelated changes and commit only your files.
Read the returned owning design and the exact code you will modify. Experiments are evidence,
not normative design.
State a testable outcome. For defects and lifecycle work, write the failing behavior test first.
Immediately before the first substantive file write, register one open in-flight
goal on the repo-development Task Board channel. Its content contains only
goal, approach, and scope; use one entry for the coherent task, not one
per file or step. Follow the daemon ownership rules in
nmg-memory, and retain the returned entry ID:
nmg board put repo-development \
"goal=<outcome>; approach=<intended method>; scope=<owned paths>" \
--agent <stable-agent-id> --kind goal --ttl-seconds 86400 --json
Do not publish progress updates. Writer attribution marks the initial worker;
another Agent may claim the same open entry if it must take over. If the board
is unavailable because this task is repairing NMG lifecycle or board code,
report that limitation and continue rather than making the repository
unrepairable.
Classify tests
- Safety: prevents corruption, leaks, unsafe deletion, or security regressions. Blocking and durable.
- Contract: protects a public API, protocol, package, persistence, or supported integration. Blocking and durable.
- Guardrail: temporarily blocks a known regression while the design is being repaired. Put it under
tests/guardrails/<id>/ with guardrail.yaml; record reason, review_after, and exit_criteria.
- Characterization/research: measures current behavior or hypotheses. It must not redefine product
correctness and is non-blocking in CI.
Do not turn a temporary test into permanent architecture by accident. Promote it to safety/contract,
or remove it when its exit criteria are met.
Implement and verify
- Make the smallest coherent change; keep optional infrastructure behind a narrow adapter.
- Update the owning design when behavior or process changes. A non-trivial
change also adds or updates at least one record under
docs/decisions/ in the
same commit. It is non-trivial when it alters behavior, a contract shared
across files or packages, package or module structure, process or tooling,
test strategy, or an on-disk, wire, or configuration format; formatting,
comment wording, typo fixes, and behavior-free dependency bumps are exempt.
Follow doc-maintenance.
- Run the targeted test, then
npm run agent:verify. With no arguments it
automatically detects Git changes, selects routes, executes the exact blocking
checks, and overwrites .nmg/verification/latest.json with structured evidence.
In a shared dirty worktree, pass -- <owned-path> so unrelated changes
stay outside the plan. Use --include-advisory only when research or chaos cost
is intentional.
- Use
npm run test:research only for research adapters; use npm run test:chaos for explicit lifecycle
fault testing. Neither substitutes for product tests.
- For CI, packaging, or generated-output changes, validate from a clean checkout
or use
--require-clean in an equivalent clean tree. CI automatically runs the
named verify:* package contracts on push and pull request.
- Commit one coherent change with only owned files. Leave unrelated user or Agent work untouched.
Commit messages follow the repository's conventional style
(
type(scope): summary + a body that says what changed and why, one change
per commit). A commit is a proposal, not a proof: the verification evidence
(targeted test + agent:verify) is what makes it hold, so do not claim a
check passed in the message unless it ran.
- When opening a pull request, read
.github/pull_request_template.md and
follow it as the PR prompt: fill the three description blocks (What / Why /
Changes) from the change plus 未验证项, which names the surface the change did
not exercise — a route that did not run, a platform or environment that was not
built or booted, a build mode, or a behavior with no reproducer. Write None.
only when nothing is outstanding. That declaration states scope; it never
replaces a check and a green gate never makes it unnecessary. Then self-check
every box in the completion checklist before marking the PR ready — the
checklist is the same contract
CI enforces, and it catches locally what a CI round-trip would cost. Draft
PRs and CI status are owned by the forge; the template checklist is the
submitter's own pre-flight, not a substitute for All checks passed.
- Resolve the in-flight goal after the task is completed or deliberately
abandoned. The board records that work is active, not a step-by-step history;
Git and verification evidence remain the source of actual implementation state.
Repository Control Plane beyond agent:verify
npm run agent:verify auto-discovers the contract that uniquely covers the
current scope and runs the equivalent reconcile — that is the default for
ordinary changes (see ci-cd-and-quality.md §7.11).
Use the standalone nmg-rcp CLI (node bin/nmg-rcp.mjs, contract path first)
only in the scenarios agent:verify does not cover:
- Check CI state without opening the browser:
nmg-rcp forge-status --pr <n>
reads the forge's status-check rollup (checks[] with name/conclusion). Use
it before claiming "checks pass" or deciding a PR is mergeable.
- Review what a reconcile would do before running it:
nmg-rcp plan <contract> (and nmg-rcp compile <contract> when the contract
itself changed).
- Inspect verification evidence:
nmg-rcp receipt-list /
nmg-rcp receipt-verify <receipt> / nmg-rcp receipt-scan — receipts live
under .rcp/receipts/ and are append-only.
- Retry after a failed reconcile, or run an explicit workspace-ready pass:
nmg-rcp reconcile <contract> --apply --workspace-ready [--recover-attempt].
- Bind a PR or create a draft PR through the forge provider:
nmg-rcp forge-bind <contract> --pr <n> / nmg-rcp forge-create <contract> --base main --head <branch>.
--apply never runs by default; reconcile plans unless --apply is explicit.
When a Contract's status or verification drift from the design doc, update the
owning document (this SKILL, ci-cd-and-quality.md, the RCP decision) in the
same change — an improved tool that stays undocumented is a tool agents will
not reach for.
Do not recursively scan oversized directories by default. This is an
Agent operating rule for searches, inventories, size estimation, and repository
observation—not a claim that the runtime enforces a size-based rejection.
Avoid known large dataset, benchmark, virtual-environment, and generated trees
unless the task explicitly requires them. Start with named files or narrow
paths; do not walk an entire large tree merely to estimate whether it is large.
When a large-tree scan is genuinely needed, obtain explicit authorization for
the paths and bound the scan to that scope. A broad wildcard alone is not a
substitute for that authorization.
For RCP, choose narrow contract includes before observing. Directory pruning
only avoids include-unreachable subtrees; it is not a size guard, and broad
patterns may still reach large trees. Never silently omit in-scope files to
reduce cost, since that would change observation/digest semantics. Runtime
observation behavior is owned by
ci-cd-and-quality.md §7.2.
Builds and generated artifacts
Regenerable outputs are not tracked (see the rejected decision
Track build artifacts in version control):
dist/ (root tsc build), dsh/dsh-nmg/lib/ (tsdown), and
src/prompts/nmg-prompts.generated.ts (from nmg-prompts.yaml) are
gitignored; the tree stays clean only if you never git add them.
- A change to
src/ that feeds a generated output is verified by
regeneration, not by committing the output.
Reproduce locally, in this order:
- Root package:
npm ci (or npm install when adding a dependency), then
npm run build — regenerates src/prompts/nmg-prompts.generated.ts and
dist/.
- Subpackages with their own lockfile (currently
dsh/dsh-nmg, pnpm):
cd dsh/dsh-nmg && pnpm install --frozen-lockfile && pnpm run build —
regenerates lib/. npm run verify:packages runs every subpackage from a
frozen lockfile automatically.
npm run check:lock fails when the root package-lock.json drifted from
package.json; fix with npm install --package-lock-only.
When a change touches a subpackage's src/, package.json, or its lockfile,
npm run agent:verify covers it through verify:static →
verify:packages/check:lock.
Never invoke live LLM, embedding, or full benchmark workloads unless the task explicitly calls for them.
1---2name: repo-development3description: Modify, test, and commit this repository safely. Use for any NMG code, test, CI, packaging, or repository-tooling change.4---56# Repository development78Keep the workflow small, evidence-based, and friendly to concurrent Agents.910## Repository governance1112- Treat the repository as the Agent's working environment. When a recurring task13 is hard to route or verify, improve its existing owner, route, or Skill instead14 of adding a private workaround or another source of truth.15- Treat an Agent completion claim as a proposal. Targeted tests, independent16 verification, clean CI, and—when the change crosses an external boundary—a17 real integration run determine whether the change holds. Each proof is scoped18 to what it actually measured.19- Move work, PRs, decisions, guardrails, and releases only through their explicit20 lifecycle operations. Do not infer a state transition from phrases such as21 "done" or "ship it" and do not bypass its prerequisites.22- Detect entropy aggressively: stale temporary work, expired guardrails,23 duplicate tests, unused compatibility layers, and superseded abstractions.24 Automatically remove only generated, cached, or explicitly expiring material;25 propose reviewable candidates before deleting source, history, public26 interfaces, issues, or pull requests.27- Keep one authoritative writer for each fact. Observe or reference GitHub,28 Contracts, repository state, verification receipts, and NMG memory through29 their owning interfaces rather than mirroring them into a competing store.30- In a shared or parallel-Agent worktree, isolate before you commit. Run31 `git status --short` first: other Agents' uncommitted changes, or a HEAD that32 moved under you, mean the tree is shared. Never `git add -A` or `git commit -a`33 there; stage only your owned paths. When the worktree is actively shared,34 prefer a dedicated `git worktree add` for your change, commit only your files,35 and hand the shared tree back by reverting only your files to HEAD. A commit36 that silently swallows another Agent's working tree is a coordination failure,37 not a merge. When the change lands or is abandoned, remove the dedicated38 worktree and its branch (`git worktree remove <path>` then `git branch -D39 <name>`) so used-up worktrees do not accumulate.4041## Before editing42431. Run `npm run agent:context -- <target-path>`. Positional paths route the44 explicit scope without consulting Git. Use `--changed` only when dirty Git45 paths should be added automatically; that mode requires working Git inspection.46 Treat `unknown` reconciliation as missing applicable evidence, and `drifted`47 as a request to inspect the reported declaration, snapshot, or verification48 mismatch. Neither status is an architectural verdict.492. Inspect `git status --short`; preserve unrelated changes and commit only your files.503. Read the returned owning design and the exact code you will modify. Experiments are evidence,51 not normative design.524. State a testable outcome. For defects and lifecycle work, write the failing behavior test first.535. Immediately before the first substantive file write, register one open in-flight54 goal on the `repo-development` Task Board channel. Its content contains only55 `goal`, `approach`, and `scope`; use one entry for the coherent task, not one56 per file or step. Follow the daemon ownership rules in57 [`nmg-memory`](../nmg-memory/SKILL.md), and retain the returned entry ID:5859 ```text60 nmg board put repo-development \61 "goal=<outcome>; approach=<intended method>; scope=<owned paths>" \62 --agent <stable-agent-id> --kind goal --ttl-seconds 86400 --json63 ```6465 Do not publish progress updates. Writer attribution marks the initial worker;66 another Agent may claim the same open entry if it must take over. If the board67 is unavailable because this task is repairing NMG lifecycle or board code,68 report that limitation and continue rather than making the repository69 unrepairable.7071## Classify tests7273- **Safety:** prevents corruption, leaks, unsafe deletion, or security regressions. Blocking and durable.74- **Contract:** protects a public API, protocol, package, persistence, or supported integration. Blocking and durable.75- **Guardrail:** temporarily blocks a known regression while the design is being repaired. Put it under76 `tests/guardrails/<id>/` with `guardrail.yaml`; record `reason`, `review_after`, and `exit_criteria`.77- **Characterization/research:** measures current behavior or hypotheses. It must not redefine product78 correctness and is non-blocking in CI.7980Do not turn a temporary test into permanent architecture by accident. Promote it to safety/contract,81or remove it when its exit criteria are met.8283## Implement and verify84851. Make the smallest coherent change; keep optional infrastructure behind a narrow adapter.862. Update the owning design when behavior or process changes. A non-trivial87 change also adds or updates at least one record under `docs/decisions/` in the88 same commit. It is non-trivial when it alters behavior, a contract shared89 across files or packages, package or module structure, process or tooling,90 test strategy, or an on-disk, wire, or configuration format; formatting,91 comment wording, typo fixes, and behavior-free dependency bumps are exempt.92 Follow [`doc-maintenance`](../doc-maintenance/SKILL.md).933. Run the targeted test, then `npm run agent:verify`. With no arguments it94 automatically detects Git changes, selects routes, executes the exact blocking95 checks, and overwrites `.nmg/verification/latest.json` with structured evidence.96 In a shared dirty worktree, pass `-- <owned-path>` so unrelated changes97 stay outside the plan. Use `--include-advisory` only when research or chaos cost98 is intentional.994. Use `npm run test:research` only for research adapters; use `npm run test:chaos` for explicit lifecycle100 fault testing. Neither substitutes for product tests.1015. For CI, packaging, or generated-output changes, validate from a clean checkout102 or use `--require-clean` in an equivalent clean tree. CI automatically runs the103 named `verify:*` package contracts on push and pull request.1046. Commit one coherent change with only owned files. Leave unrelated user or Agent work untouched.105 Commit messages follow the repository's conventional style106 (`type(scope): summary` + a body that says what changed and why, one change107 per commit). A commit is a proposal, not a proof: the verification evidence108 (targeted test + `agent:verify`) is what makes it hold, so do not claim a109 check passed in the message unless it ran.1107. When opening a pull request, read `.github/pull_request_template.md` and111 follow it as the PR prompt: fill the three description blocks (What / Why /112 Changes) from the change plus `未验证项`, which names the surface the change did113 not exercise — a route that did not run, a platform or environment that was not114 built or booted, a build mode, or a behavior with no reproducer. Write `None.`115 only when nothing is outstanding. That declaration states scope; it never116 replaces a check and a green gate never makes it unnecessary. Then self-check117 every box in the completion checklist before marking the PR ready — the118 checklist is the same contract119 CI enforces, and it catches locally what a CI round-trip would cost. Draft120 PRs and CI status are owned by the forge; the template checklist is the121 submitter's own pre-flight, not a substitute for `All checks passed`.1228. Resolve the in-flight goal after the task is completed or deliberately123 abandoned. The board records that work is active, not a step-by-step history;124 Git and verification evidence remain the source of actual implementation state.125126## Repository Control Plane beyond agent:verify127128`npm run agent:verify` auto-discovers the contract that uniquely covers the129current scope and runs the equivalent reconcile — that is the default for130ordinary changes (see [`ci-cd-and-quality.md` §7.11](../../docs/design/ci-cd-and-quality.md)).131Use the standalone `nmg-rcp` CLI (`node bin/nmg-rcp.mjs`, contract path first)132only in the scenarios `agent:verify` does not cover:133134- **Check CI state without opening the browser:** `nmg-rcp forge-status --pr <n>`135 reads the forge's status-check rollup (`checks[]` with name/conclusion). Use136 it before claiming "checks pass" or deciding a PR is mergeable.137- **Review what a reconcile would do before running it:**138 `nmg-rcp plan <contract>` (and `nmg-rcp compile <contract>` when the contract139 itself changed).140- **Inspect verification evidence:** `nmg-rcp receipt-list` /141 `nmg-rcp receipt-verify <receipt>` / `nmg-rcp receipt-scan` — receipts live142 under `.rcp/receipts/` and are append-only.143- **Retry after a failed reconcile, or run an explicit workspace-ready pass:**144 `nmg-rcp reconcile <contract> --apply --workspace-ready [--recover-attempt]`.145- **Bind a PR or create a draft PR through the forge provider:**146 `nmg-rcp forge-bind <contract> --pr <n>` / `nmg-rcp forge-create <contract> --base main --head <branch>`.147148`--apply` never runs by default; reconcile plans unless `--apply` is explicit.149When a Contract's status or verification drift from the design doc, update the150owning document (this SKILL, `ci-cd-and-quality.md`, the RCP decision) in the151same change — an improved tool that stays undocumented is a tool agents will152not reach for.153154**Do not recursively scan oversized directories by default.** This is an155Agent operating rule for searches, inventories, size estimation, and repository156observation—not a claim that the runtime enforces a size-based rejection.157Avoid known large dataset, benchmark, virtual-environment, and generated trees158unless the task explicitly requires them. Start with named files or narrow159paths; do not walk an entire large tree merely to estimate whether it is large.160When a large-tree scan is genuinely needed, obtain explicit authorization for161the paths and bound the scan to that scope. A broad wildcard alone is not a162substitute for that authorization.163164For RCP, choose narrow contract includes before observing. Directory pruning165only avoids include-unreachable subtrees; it is not a size guard, and broad166patterns may still reach large trees. Never silently omit in-scope files to167reduce cost, since that would change observation/digest semantics. Runtime168observation behavior is owned by169[`ci-cd-and-quality.md` §7.2](../../docs/design/ci-cd-and-quality.md#72-真相域).170171## Builds and generated artifacts172173Regenerable outputs are **not** tracked (see the rejected decision174[Track build artifacts in version control](../../docs/decisions/rejected/2026-09-02-track-build-artifacts-in-git.md)):175176- `dist/` (root tsc build), `dsh/dsh-nmg/lib/` (tsdown), and177 `src/prompts/nmg-prompts.generated.ts` (from `nmg-prompts.yaml`) are178 gitignored; the tree stays clean only if you never `git add` them.179- A change to `src/` that feeds a generated output is verified by180 regeneration, not by committing the output.181182Reproduce locally, in this order:1831841. Root package: `npm ci` (or `npm install` when adding a dependency), then185 `npm run build` — regenerates `src/prompts/nmg-prompts.generated.ts` and186 `dist/`.1872. Subpackages with their own lockfile (currently `dsh/dsh-nmg`, pnpm):188 `cd dsh/dsh-nmg && pnpm install --frozen-lockfile && pnpm run build` —189 regenerates `lib/`. `npm run verify:packages` runs every subpackage from a190 frozen lockfile automatically.1913. `npm run check:lock` fails when the root `package-lock.json` drifted from192 `package.json`; fix with `npm install --package-lock-only`.193194When a change touches a subpackage's `src/`, `package.json`, or its lockfile,195`npm run agent:verify` covers it through `verify:static` →196`verify:packages`/`check:lock`.197198Never invoke live LLM, embedding, or full benchmark workloads unless the task explicitly calls for them.