ADLC
Integrations

pi

Native ADLC extension for the pi coding agent: in-session rail, scope, and suppression enforcement with git-diff revert, plus five phase skills.

ADLC in pi

A native pi TypeScript extension plus five skills. pi intentionally skips built-in orchestrators, so ADLC slots in through pi's Extension API: the extension enforces rails in-session while the skills route each phase to the deterministic adlc gates.

What you get

  • Proactive rail gate (tool_call). Blocks write/edit/bash before it touches disk when the target is a frozen rail, out of the ticket's scope, or the ADLC trust roots. Bash writes are gated here: redirects, tee, rm/mv/cp, in-place sed/perl, mutating git subcommands, and interpreter file-write APIs are recognized and rail-checked.
  • Reactive revert gate (tool_result). After any write/edit/bash, computes added lines against a pre-tool snapshot (never HEAD, so your own uncommitted edits are never destroyed); a rail violation restores the snapshot and replaces the tool result with a GATE FAILED error. Added lines are also scanned for undeclared suppression markers (@ts-ignore, eslint-disable, .skip(, # noqa, …) and reverted unless the ticket allows them. Operative-vs-inert classification is delegated to @adlc/rails-guard.
  • Build-gate + flail backstops. A degraded (context-rot) session on a high-risk ticket is denied its build until an audited override is recorded; repeated errors, scope churn, and oversized session logs surface as advisories.
  • Ticket doctrine injection (before_agent_start). The active ticket's scope, rails, and spec are appended to the system prompt every turn (sanitized; the ticket body is fenced as untrusted), which defends against premature satisfaction and context rot.
  • Native agent tools. adlc_prosecute runs the deterministic P5 review loop in-session (fan-out → verify → loop-until-dry over write-disabled child sessions); adlc_gate runs the LLM-backed gates keyless through your session model. A TICKET-DONE listener nudges prosecution at ticket completion.
  • Commands + footer status pill: /ticket, /adlc-ticket, /adlc-init, /adlc-approve-spec, /adlc-accept, /adlc-rollback, and a live pill showing the active enforcement context.
  • Skills: adlc (phase router), adlc-spec (P0–P2), adlc-rail-build (P3–P4), adlc-prosecute (P5–P6), adlc-distill (P7). Each wraps the deterministic adlc CLIs; hooks are assistive, adlc rails-guard is the proof.

Install

npm install -g @adlc/cli                       # the gate toolkit the skills wrap

# Per-project (lands in .pi/, auto-installs for every teammate on trusted startup):
pi install -l npm:@adlc/pi

# …or helper one-liner via npx:
npx adlc-pi install

# …or user-global (available in every repo you open):
pi install npm:@adlc/pi

Then run /adlc-init inside pi to finish the repo scaffold. @adlc/pi is published on npm, so pi install -l npm:@adlc/pi and npx adlc-pi install work today. Developing against a checkout? Load the extension directly instead:

pi --extension /path/to/adlc/plugins/adlc-pi/index.ts

Requires Node ≥ 22.19 (the pi floor). Peer dependency: @earendil-works/pi-coding-agent (manifest pins "*"; verified against 0.80.3, with a weekly version-matrix smoke tracking the latest published build).

Enforcement model

Enforcement is opt-in by activating a ticket: set ADLC_TICKET or write .adlc/current-ticket.json (tickets file overridable via ADLC_TICKETS). With no active ticket the extension is inert. Once a ticket id resolves, the extension fails closed: an unreadable or unparseable tickets file, or an unknown ticket id, blocks all tool calls until fixed (with a red status pill telling you why). Unlike the sibling integrations, this plugin does not use ADLC_P4_ENFORCEMENT; the active ticket is the switch.

.adlc/tickets.json and .adlc/current-ticket.json are unconditionally blocked from edits regardless of rails, so the agent can't rewrite its own constraints. An empty ticket scope means unrestricted; .adlc/ and .omo/ stay writable for evidence.

The commit-time backstop is the same harness-agnostic CI gate as every other integration: scripts/rails-guard-ci.mjs reads the frozen rail set from the trusted base ref and rejects any PR that edits a rail, however the edit was made. Make it a required check.

Context-rot handoff

pi is an enforcing tier for the context-rot handoff, and the only harness with a real context-fill signal: ctx.getContextUsage().percent is a live reading of the window, not a transcript-size proxy. It feeds the band join directly as pct.

The deny-set from @adlc/context-handoff is evaluated on every tool_call, before every other gate, and — unlike everything else in this extension — it is not scoped to an active ticket. An open deny record is a fact about the session, so it holds whether or not a ticket is selected.

Once a session passes the handoff band a deny record is written for it under .adlc/handoffs/denies/. While any such record is open and unauthorized, the session loses structured edits, bash wholesale, and third-party tools — including attempts to run adlc handoff write|resume|bypass|repair|unlock from the agent's own shell. Structured writes to the deny store, resume-auth caches, model-ok stamps, and lock files are refused whether or not a deny is active. A shell command naming one of those paths — in any literal spelling: relative, dot-relative, absolute, symlinked, or a parent directory that holds them — is refused too, deny-set or not — there is no CI backstop for them, because .adlc/* is gitignored and a deletion never reaches a diff. That check reads literal paths only: it cannot see through a variable, an expansion, or an interpreter one-liner, so it raises the cost of the obvious attempt rather than closing the class. Read-only tools keep working.

Because the handoff band (60%) sits below the build gate's own context threshold (80%), a percent high enough to trip the build gate now trips the handoff deny first. The build gate still fires on the compaction signal, which degrades a session without moving the percent — but note that its ADLC_BUILD_GATE_BYPASS override does not clear a deny-set: resume in a fresh session, or repair the record from a terminal.

Session identity is pi's own ctx.sessionManager.getSessionId(). A context that exposes no session manager falls back to the session_start event and then to a per-instance mint, which names the extension rather than the session — a last-resort identity that still fails closed when unusable.

Clearing a deny needs ADLC_MANIFEST_KEY in the harness's environment: adlc handoff resume signs a resume-auth cache, and the adapter can only honour it by verifying that signature. Without the key the gate still fails closed — it just cannot be re-opened in-session, and says so (resume_auth_unverifiable:no_manifest_key).

Formal ADLC coverage

Phasepi surface
P0–P2 Triage → Decomposeadlc-spec skill (parallax, spec-lint, premortem, coldstart, merge-forecast, model-router); ticket resolution on session_start; prompt templates (/adlc-spec, /adlc-decompose)
P3–P4 Rail & Buildthe extension: proactive tool_call block + reactive tool_result snapshot-scoped revert + operative-only suppression gate + build-gate + flail advisory + evidence rail + custom-tool coverage
P5 Prosecutenative adlc_prosecute tool: in-session fan-out → verify → loop-until-dry over write-disabled child sessions; TICKET-DONE completion nudge; plus the adlc-prosecute skill (prosecute, behavior-diff, adlc run p5)
P6 Integratenative adlc_gate tool + /adlc-accept command + rollback path; adlc behavior-diff / adlc run p6
P7 Distilladlc-distill skill (lesson-foundry, rejection-mining, skill-rot, model-ratchet); scheduled runs via CI cron

Command surface: /ticket, /adlc-ticket, /adlc-init, /adlc-approve-spec, /adlc-accept, /adlc-rollback, plus the adlc-* prompt templates. The footer widget renders the active ticket and last gate verdict.

Remaining gaps (design intent, not yet shipped): a session_shutdown auto-capture for P6 (accept is command-driven today), and an in-harness P7 scheduler (pi has no /schedule; CI cron is the substrate). @adlc/pi is published on npm, so the pi install one-liner above works today. A weekly version-matrix smoke tracks upstream pi drift.

Go deeper

Source: plugins/adlc-pi/ · design plan: docs/integrations/pi.md.

The rail-freeze gate this extension enforces in-session: Tests Are the Spec.

On this page