@gonrocca/nodd

Non-negotiable Organic Driven Development — the ODD protocol as runtime mechanism for pi: blocking gates, observed evidence, and promotion to /forge.

Packages

Package details

extension

Install @gonrocca/nodd from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@gonrocca/nodd
Package
@gonrocca/nodd
Version
0.8.4
Published
Sep 23, 2026
Downloads
3,364/mo · 3,364/wk
Author
gonrocca
License
MIT
Types
extension
Size
700.1 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./extensions/nodd-kernel.ts",
    "./extensions/nodd-gates.ts",
    "./extensions/nodd-allow.ts",
    "./extensions/nodd-models.ts",
    "./extensions/nodd-agents.ts",
    "./extensions/nodd-promote.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README


ODD tells the model to delegate. NODD does not let it not delegate.

ODD le pide al modelo que delegue. NODD no lo deja no delegar.

EN — ODD writes its rules into the prompt and trusts the model to follow them; its own notes admit the gap: "non-delegation is invisible". NODD makes it visible. Six gates run on tool_call and refuse the write before it happens.

ES — ODD escribe sus reglas en el prompt y confía en que el modelo las cumpla; el propio ODD admite el agujero: "non-delegation is invisible". NODD lo hace visible. Seis gates corren en tool_call y rechazan la escritura antes de que ocurra.

ODD NODD
Rules live in / Las reglas viven en the prompt tool_call
Non-compliance is / Incumplir es invisible refused + remedy
Done when / Hecho cuando the model says so NODD saw the runner pass
56 ODD clauses / 56 cláusulas 56 prose 44 mechanized + 10 prose

The 10 stay prose on purpose: "did I explore enough?" is not observable, and forcing it into a number would be the very sin NODD accuses prose of.

Esas 10 quedan como prosa a propósito: "¿exploré lo suficiente?" no es observable, y mecanizarlo sería el mismo pecado que NODD le critica a la prosa.

Quick start

pi install npm:@gonrocca/nodd

Nothing to configure — every gate is on. / Nada que configurar: todos los gates arrancan prendidos.

nodd_declare  slug: dark-mode  intent: change  route: tracked
              runner: "npm test"
→ .nodd/dark-mode/feature.md created

 write src/theme.ts  → blocked: no route declared     (before the declaration)
 write src/theme.ts  → allowed                         (after it)
 check T1            → blocked: no observed run of `npm test`

Source / Código: github.com/gonzalonicolasr/nodd — MIT.

Jump to / Ir a: Install · Using it · The gates · Commands · Parity matrix

Full reference / Referencia completa: docs/reference.md — enforcement scope, the bash gate, model slots, flags and the kill switch, deliberate divergence from ODD, and known limitations.


Credit / Créditos

EN — The workflow, the seven canonical steps, the delegation thresholds and the 56 clauses this project measures itself against all come from ODD, by Gentleman-Programming. NODD contributes one thing: the enforcement. Without ODD there is no rule to enforce.

ES — El workflow, los siete pasos canónicos, los umbrales de delegación y las 56 cláusulas contra las que este proyecto se mide salen todas de ODD, de Gentleman-Programming. NODD aporta una sola cosa: que se cumplan. Sin ODD no hay regla que imponer.

ODD's failure was promising compliance while shipping delivery. This file is where NODD refuses to repeat it: everything below states what is mechanized, what is only advice, and what is not carried at all.

test/readme-contract.test.ts holds part of that line mechanically: it fails if the README names a gate, a module or a command that does not exist, drops a canonical step, quotes a matrix total that disagrees with the matrix, or lets the bash, enforcement-scope, resume and kill-switch sections stop stating their limits. It does not parse English: a newly written sentence promising more than the code does will not turn it red. Prose added next to a fix is therefore the known way this document can drift ahead of the product, and the defence is review, not the suite. Round 3 found three such sentences and closed them.

Install

pi install npm:@gonrocca/nodd

Global installation is the path enforcement is verified on. A pi-subagent child process does its own ambient discovery and finds installed packages, so gates also run inside delegated work — see Enforcement scope for what that does and does not cover. pi -e npm:@gonrocca/nodd runs the package for one session without installing it, and in that mode children do not load it: the parent is gated and delegated work is not.

Install into one project instead of the whole account with -l, which writes .pi/settings.json. Remove with pi remove npm:@gonrocca/nodd.

Nothing is configured after install: every gate is on, the flags are documented under Flags, the kill switch and the escape hatch, and model slots keep pi's defaults until /nodd-models is run.

Using it

NODD runs on its own. A normal session looks like this:

Read-only work stays read-only. Ask a question and nothing changes. Declare intent read-only and a write is refused by gate-authorize.

Substantial work is declared before the first write. The agent calls nodd_declare with the slug, the route, the files and — this is the part worth caring about — the runner: the command a checkoff will be measured against.

nodd_declare  slug: dark-mode  title: "Dark mode"  summary: "Theme the editor"
              intent: change  route: tracked
              runner: "npm test"  tdd: strict  files: [src/theme.ts]
→ .nodd/dark-mode/feature.md created with 0 tasks

Until that file exists, the first write is refused. The refusal says what to do about it.

Tasks are checked off with observed runs, not with claims. nodd_task marks an item done only when gate-evidence finds four facts lined up: a success, of the declared runner, after the task's last write, with a RED before it under strict TDD. A model writing "all tests pass" changes nothing — the evidence line in the document is rendered from the observed tool result, never from prose.

When a gate is wrong, turn it off. /nodd-gates disable track disables it entirely and stays disabled; /nodd-allow track grants exactly one override. Neither is argued with.

When the work outgrows NODD, promote it. /nodd-promote dark-mode writes .sdd/dark-mode/requirements.md and /forge --continue dark-mode starts at its plan phase with the finished work as context.

To watch it work on something disposable, run pi in an empty git repo and ask for a two-file change: the declaration is demanded before the first write, and the first checkoff without a real test run is refused.

The seven canonical steps

authorizeexploreresolve-uncertaintyclassifytrackimplementclose.

Four of them — authorize, classify, track and close — are mechanism steps: they run no model and cannot be assigned one. /nodd-models shows them as mecanismo · sin modelo and refuses an assignment. The other three are the steps where a model actually does work.

The gates

gate fires on refuses when
gate-authorize writes, mutating bash, delegation to a writer intent was declared read-only
gate-classify the first write nothing was declared at all
gate-track the first source write on a tracked/forge route no feature doc exists yet
gate-delegate writes and mutating bash the mapping, writer or long-session threshold fired and nothing was delegated
gate-evidence checking a task off the declared runner was not observed succeeding after the task's last write
gate-promotion writes the work diverged from what was declared

Every refusal names what was observed, the action that unblocks it, and a one-shot /nodd-allow <gate> escape hatch. A gate that blocks without naming the exit is a dead end, so src/gates/policy.ts makes the remedy a required field rather than an encouraged one.

The M/P/F parity matrix

Every clause of ODD's guidance surface is classified as exactly one of:

  • (M) mechanized — a gate or module enforces it;
  • (P) forwarded prose — kept as injected text, with a stated reason why it cannot be mechanized;
  • (F) out of scope — not carried, with a stated reason.

The full row-by-row matrix lives in .sdd/nodd/requirements.md under REQ: odd-parity-matrix. Its (P) rows are implemented as data in src/odd-prose.ts — one entry per row, tagged with the canonical step it belongs to — and a test asserts the two stay in correspondence.

A (P) reason may never be "we did not get to it." A clause with no stated obstacle is a mechanism someone skipped, and a test rejects that wording.

The two most load-bearing (P) clauses:

  • The preparation trigger (routing.go:81). Reading that prepares a write should be delegated too — but intent-to-write is not visible in a read event. NODD ships no prepare gate, and a test asserts no gate id contains prepar: a mechanism here would have to guess intent, and a gate that guesses is worse than prose that admits it.
  • The ~400-line advisory (routing.go:95), with its full anti-gaming sentence. A line count measures typing, not correctness. Mechanizing it would make the number an objective to optimize against — which is exactly what the clause forbids. A test asserts no gate consults a line count.

Not carried from ODD

clause why not
Engram/Cortex memory mirror out of scope by decision; NODD's durable truth is .nodd/<slug>/ on disk
gentle-ai review assess tiers, consent ceremony, preflight STATUS depends on the gentle-ai binary, which is deliberately not copied. A test asserts no code path invokes it. NODD's analogue is forge's veredicto phase
push / PR creation / merge these remain the user's decisions. No gate and no tool in NODD pushes, opens a PR or merges, and a test asserts no code path runs them

Commands

command does
/nodd-gates [status|on|off] [<gate>] inspect and set gate flags
/nodd-allow <gate> grant a one-shot override
/nodd-models [<slot>=<provider>/<model>|profile …] assign models per slot; no argument opens the picker
/nodd-promote <slug> hand a feature to /forge

/nodd-promote writes exactly one file, .sdd/<slug>/requirements.md, and deliberately emits no design.md and no tasks.md so forge's resume lands on no-plan and restarts at its plan phase. It refuses to overwrite an existing requirements.md, and it is the only module in the package permitted to write under .sdd/ — a test scans every other source file to keep it that way.

Forge is an optional dependency. When it is absent, the artifact is still written and the exact command to run by hand is reported.