Contributing to Ndigo
Thanks for contributing! This document is the contract for working in this repository: how to install, validate, change a package, and prepare a release.
Repository shape
Section titled “Repository shape”- Monorepo: pnpm workspaces (
packages/*,apps/*) with Nx task orchestration. Every package is@ndigo/<name>underpackages/ndigo-<name>. - Packages are strictly typed: TypeScript
strictis enabled in every package (see Task 9 remediation). Public API changes must keep declarationsany-free where the contract is public. - Package boundaries are enforced (see
docs/plans/2026-09-04_REPOSITORY_REMEDIATION.md):@ndigo/bootis platform-neutral — never import@ndigo/platform-nodeor@ndigo/platform-webfrom its runtime source (enforced bypackages/ndigo-boot/test/platform-boundary.spec.ts).- Isomorphic core packages must not import
node:builtins or DOM globals.
- One license: ISC (root
LICENSE). Every publishable package manifest conforms toscripts/check-manifests.mjs(ISC,exportsmap,type: module,sideEffects,~0.0.1ndigo workspace protocol).
Prerequisites
Section titled “Prerequisites”- Node.js ≥ 24 (runtime; CI uses 24)
- pnpm ≥ 12 (corepack recommended:
corepack enable && corepack prepare pnpm@12 --activate)
Install
Section titled “Install”corepack enable # oncepnpm install # installs all workspace packagesValidate before you push
Section titled “Validate before you push”Run the whole lane locally with one command:
pnpm hooks:install # once per clone: worktree guard + pre-push lanepnpm preflight # every gate below, fail-fast order (~5 min on a dev box)pnpm preflight:fast # format, lint, links, typecheck onlypreflight mirrors .github/workflows/ci.yml and is what the pre-push hook
runs. GitHub-hosted runner minutes are a hard monthly budget (2,000 on the free
tier), so a push carries its own proof and CI is the backstop, not the first
run. git push --no-verify skips the hook; PREFLIGHT=fast git push runs the
fast gates only.
Every gate individually:
pnpm build # all library packages (tsc -b per package)pnpm test # unit + integration suites (per package)pnpm typecheck # per-project tsc -b + the spec lane (tsconfig.spec.json checks src AND test files, TST-A)pnpm lint # Oxlint — must report ZERO warningspnpm format:check # oxfmt over maintained files onlypnpm docs:links # relative-link integrity (docs + package/app READMEs)pnpm guides:check # guide contract: titles, metadata, fences, indexpnpm doc:coverage # zero-tolerance TSDoc depth gatepnpm audit --prod # production advisories — must be cleanpnpm manifest:check # package manifest conformancepnpm doc # TypeDoc — must emit 0 errors, 0 warningsCI cost is itself a tracked gate: pnpm ci:usage replays the run history and
reports billable minutes per workflow, job, and day (issue #276).
Format the code you touched:
pnpm exec oxfmt <changed files>Changing a package
Section titled “Changing a package”- Read the package README and the repo graph first:
graft map/graft ask "<question>"give exactfile:linespans — re-ask freely, it is cheap. - Follow existing conventions:
#privatefields, executornew Promise,definePropertyfor readonly public fields, barrel-controlled exports. - Run the package’s own loop while working:
pnpm --filter @ndigo/<name> build:lib && pnpm --filter @ndigo/<name> test - For behavior changes, add or update a test in the package’s
test/— tests defend observable behavior, boundaries, transitions, and real errors. - Sequential-await loops: if a loop must stay sequential (ordering is
contractual), add a line-scoped
oxlint-disable-next-line no-await-in-loopwith a reason — never silently parallelize ordering-sensitive code. - Run the full validation list above before opening a PR.
READMEs
Section titled “READMEs”Every README.md in this repo is scaffolded on the standard template via the
readme generator — pnpm exec nx generate @ndigo/generators:readme --name <package> —
then filled in: lead with value, show a runnable example, and keep it focused on a
new user. Never include internal tracking IDs (AD-##, D##), plan or
decision-record links, commit notes, or descriptions of removed features — those
belong in docs/. Scaffold or update the affected README whenever you add or
change a package or app.
Plans and decision records
Section titled “Plans and decision records”Plans (docs/plans/) and ADRs (docs/decisions/) are reviewable engineering
artifacts with the same verification bar as code. Model the structure of the
recent ADR/plan pairs (e.g. AD-26): Date/Status header first, then Problem,
Decisions (D-N), Risks, Sequencing (waves with per-wave gates), Verification.
Minimum requirements before a plan is ready to build:
- Every code claim cites an exact span —
package/path:linetaken from the repo graph (graft ask/graft skeleton/graft grep), never from memory. No span, no claim: mark it unverified. - Every named API is one of three kinds: existing (span cited), new (marked “new”/“adds”), or shelved idea (marked “never implemented”). Never present a nonexistent API as shipped.
- Acceptance criteria are mechanically possible. Each “spec asserts” must
trace to an existing primitive or to a prerequisite change named in the same
wave (e.g. “Wave 2 lands the DataBinder change before the
instanceofgate”). A gate the current code cannot satisfy means the plan is still a proposal — say so. - Verification runs the CI lane, not a subset. Wave gates list the
commands CI runs, starting with
pnpm build— an Nx dependency cycle fails there before any test executes, so a green test run alone is not evidence. - Lifecycle is tracked:
Proposal→ review (record findings and fixes in the doc) →Accepted(ADR recorded) →Implemented(status header updated, gap-analysis rows refreshed, index entry moved indocs/plans/README.md). - Links are bidirectional: companion decision ↔ plan, superseded docs, prerequisite docs.
Naming: YYYY-MM-DD_DESCRIPTION.md (docs/README.md).
Dependency changes
Section titled “Dependency changes”- Do not add vulnerable transitive deps. After changing any manifest, run
pnpm audit --prodandpnpm manifest:check. - Security overrides live in
pnpm-workspace.yaml(overrides). Prefer a real upgrade in the owning package over an override; document overrides. - Workspace ndigo dependencies use the
~0.0.1protocol — do not introduceworkspace:protocols (seescripts/check-manifests.mjs).
Generated files
Section titled “Generated files”lib/,dist/,coverage/,.tscache/are generated and gitignored. Do not commit them.- Documentation is committed. The per-package API references
(
packages/<name>/api/) and the rootAPI.mdindex are generated bypnpm doc:apiand tracked — CI fails when they drift (pnpm doc:check). - TypeDoc reads from built
lib/*.d.ts— after changing a public doc comment, rebuild the lib (pnpm --filter @ndigo/<name> build:lib) before runningpnpm doc.
Keeping the repo graph (graft/) fresh
Section titled “Keeping the repo graph (graft/) fresh”The repo is indexed by graft/ (a local, gitignored context graph). When the
graph goes stale you lose symbol/call-site accuracy — queries answer from the
last build.
-
During editing: the graft MCP server auto-refreshes the tier-1 wiring graph before every query, so small edits stay visible without any action.
-
After large changes (a PR-sized batch, a re-architecture, deleting or moving many files): refresh the deep tier once at a natural boundary (task/PR completion — not mid-edit):
Terminal window pnpm graft:build # = graft build --deep --allow-partial--allow-partialtolerates environments where the deep summarizer can’t run (e.g. no model available); the structural graph is still fully rebuilt. -
CI runs
graft build(tier-1, deterministic, $0) +graft checkon every PR;graft checkfailing means a fingerprint/wiring regression.
Agent configuration (.opencode/, .omp/)
Section titled “Agent configuration (.opencode/, .omp/)”The repository’s AI-agent definitions are generated, not hand-edited.
- Source of truth: the neutral store in
development-agents(agents, skills, per-harness shims) plus this repo’sagent-local/(repo-specific overrides, e.g. thegraftskill). - Regenerate:
pnpm agents:sync— renders agents per harness, skills once into the shared.agents/skills/, plus the.agent-gen.jsonsha256 manifest. - Validate:
pnpm agents:check— manifest + structural invariants (CI-gated). - Edit
development-agents/oragent-local/and regenerate; never edit generated files under.opencode/agents,.omp/agents,.agents/skills. - Repo-owned deployment files (
opencode.json,.opencode/plugins/,AGENTS.md) are authored in-repo but carry editor code-execution reach, so they sit under the same drift gate: hashes live in.agent-local.json, refreshed withnode scripts/agents-check.mjs --updateafter any edit to those files (commit the manifest alongside). - Models: not part of the deployment — agents inherit the session model
(OpenCode
model, OMPmodelRoles, configured outside the store).
Releases
Section titled “Releases”Release process is per-package via npm. Before publishing:
- All validation gates green (above).
pnpm pack --dry-runfor the package and import it from a clean consumer to verify the exports map resolves.- Version bumps are semver — breaking changes require a major bump.
Reporting issues
Section titled “Reporting issues”- Bugs and security issues: see
SECURITY.mdfor the responsible-disclosure process. - Feature requests: open an issue with the affected package(s).