Project Conventions

On this page

The agency standards are canonical. This page maps them onto a TypeScript/pi-extension codebase and records what is different here and why. It is the project-owned complement to the (unedited, synced) standards pages — see ADR-002 for the downstream-in-spirit posture.

Language mapping (Rust standard → this repo)

Standard (Rust) Here (TypeScript) Notes

cargo xtask task runner

node tools/task.mjs

Same principle: one typed automation entrypoint, no loose scripts.

rustfmt + clippy -D warnings

Biome (format + lint), CI-blocking

One tool for both, matching the bundled ecosystem (gotgenes stack).

cargo-nextest

vitest

fail-fast off in CI; results per package.

thiserror typed errors / no silent failure

Typed Error subclasses at public boundaries; never swallow — propagate or log with reason. // SILENT-OK: <reason> for deliberate no-ops.

Same judgment residue, TS idioms.

Newtypes over raw primitives

Branded types / dedicated interfaces for domain values (model refs, region ids, provider ids)

Compile-time arg-transposition safety where it pays.

unwrap/panic bans (clippy)

noNonNullAssertion (Biome error), strict + noUncheckedIndexedAccess tsc

The equivalent "prove it or handle it" posture.

SPDX header on .rs

SPDX header on .ts/.mjs (// SPDX-License-Identifier: AGPL-3.0-or-later)

Enforced by pre-commit (staged blobs) + task spdx.

Alpine/musl containers

N/A (no containers yet)

Revisit when CI images exist.

Conventions specific to this repo

  • Model invocation: always pi’s composed-provider path (ctx.modelRegistry.completeSimple / provider streamSimple). Never pi-ai/compat complete* — it cannot reach custom-api/ADC providers.

  • Config files: extensions ship a bundled default next to the code and read a per-user override from the agent dir ($PI_CODING_AGENT_DIR or ~/.pi/agent/…​). First-run bootstrap seeds external consumers' configs (e.g. the permission system’s config.json) only when absent.

  • peerDependencies: @earendil-works/pi-ai, @earendil-works/pi-coding-agent, typebox — provided by pi at runtime, never bundled ("*" range).

  • Commit attribution: AI-assisted commits carry Co-Authored-By: <Model Name> <noreply@dhs.ga.gov>, derived at commit time from $PI_MODEL (title-cased) — never a stale hardcoded value.

Plans use a canonical Status vocabulary, enforced by node tools/task.mjs plan-lint.

Project Overrides (dated, per the override convention)

  • 2026-08-26 — Agent context lives in AGENTS.md, not .claude/CLAUDE.md. pi loads AGENTS.md natively and the whole point of this project is model-agnostic configuration. Supersedes the template’s .claude/ layout for this repo. The genericization is phase 2’s deliverable; this override is its first step.

  • 2026-08-26 — check-docs drift gating is stubbed. This is the template’s first non-Rust downstream; the sync engine and manifest are cargo-bound and the synced coding-conventions page is Rust-specific. Standards pages are byte-copied unedited (drift-checkable later); gating activates when upstream ships a language-profile manifest. A macro-feedback issue upstream is held until this repo’s auto-mode is operational (operator instruction).

  • 2026-08-26 — Work tracking uses a parent tracking issue, not an epic (same constraint and rationale as the template’s own override: project tokens cannot create group-level epics).

  • 2026-08-26 — Docs format: AsciiDoc/Antora canonical; published packages additionally carry a thin README.md stub because npm/pi.dev render only Markdown. The stub holds no content beyond install + a docs pointer.

  • 2026-09-07 — Closing comments here carry the evidence. The shipped guidance (Template v2026.5) closes an issue with one line — the merge SHA and anything deferred — because the MR already records files, criteria and verification. This repo merges locally with --no-ff and opens no MRs, so the issue comment is the only record: it names the implementation and merge SHAs, the release, what was verified and how. Consumers follow the shipped rule; this override is about this repo’s delivery shape, not the rule.

  • 2026-09-07 — Plans authored before v2026.5 keep their per-step Status lines. The template froze plans at implementation start and reduced Status to one header value; the archived plans here were written under the earlier living-spec rule and are history. New plans follow the shipped rule. task plan-lint vocabulary-checks any line beginning Status: and requires none, so both shapes pass it; it does not distinguish a header from a step, and the bold Status: header form these plans use is not matched at all (the template’s plan-lint --done completion gate is an open item on #69).

Edit this page · latest