@jwilger/pi-development-system
A pi extension package representing a seasoned approach to software development using a full AI SDLC.
Package details
Install @jwilger/pi-development-system from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@jwilger/pi-development-system- Package
@jwilger/pi-development-system- Version
7.0.0- Published
- Oct 29, 2026
- Downloads
- 20.3K/mo · 1,970/wk
- Author
- jwilger
- License
- MIT
- Types
- extension, skill, prompt
- Size
- 1.2 MB
- Dependencies
- 4 dependencies · 5 peers
Pi manifest JSON
{
"skills": [
"./skills"
],
"prompts": [
"./prompts"
],
"extensions": [
"./extensions/development-system.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-development-system
A pi extension package representing my seasoned approach to software development using a full AI SDLC: work is sized, planned in proportion, built test-first in small slices, reviewed by fresh-context reviewers and delivered by trunk-based commits. Guards enforce what must hold; the rest is guidance with a recorded way out.
Install
pi install npm:@jwilger/pi-development-system
Then /reload. To move to a newer release use
pi install npm:@jwilger/pi-development-system@<version>.
Jev, the classifier behind the judgements, is optional. Without a credential configured, the checks
that rest on a judgement do not run or fall back to a default: the motive behind a test change, whether a
diff needs an ADR, the quality of a commit rationale and whether a commit mixes changes, the intent
nudges, the verifier's check of the agent's own claims, and the lens and severity choices in review.
The status line shows jev offline when that is so. Everything deterministic holds without Jev: the
hard stops, the delivery mode, the review streak, red-first and the slice life cycle.
Replaces pi-subagent-manager
This package vendors pi-subagent-manager (MIT, see src/subagents/VENDORED.md)
and adds per-spawn model and thinkingLevel. Remove the original from the
packages list in ~/.pi/agent/settings.json (the npm:pi-subagent-manager
entry), then /reload; otherwise both register agent_spawn and pi refuses the
duplicate.
You do not need the slash commands
Everything the system offers is reachable without remembering a command. Describe the work in
plain words: when a prompt asks for new work, a fix or a review, the system adds a guideline
naming the tool to use (devsys_intake, devsys_review_start). A devsys tool always shows
what the current phase expects. When you say a slice is finished with no review round recorded,
it tells you to start one. The slash commands (/devsys-start, /devsys-plan, /devsys-review,
/devsys-lens-review, /devsys-adr, /devsys-event-model) are shortcuts to the same tools.
Skills cover the habits behind the gates: tdd-canon, behaviour-tests, semantic-types,
typed-errors, functional-core-imperative-shell, strict-lints, delivery-discipline, delegation,
code-review, the language profiles (profile-rust, profile-typescript), profile-design-system for UI
work (tokens, then components; build from the design system's materials and log a snowflake),
threat-modelling (proportional; a document only when the risk earns it) and the planning skills below.
Product planning has a skill (product-planning: brief, decision register, follow-ups,
terminology, journeys). devsys_lens_review plans a review of the brief by five product lenses and
writes the packets to docs/product/reviews/; devsys_adr_new creates the next numbered ADR, and
a commit that shapes the architecture without one is stopped by the soft gate adr.missing.
A reviewer subagent hands over its result with devsys_submit_review (typed arguments; a result that
contradicts itself or is for the wrong round is refused with an error id), and devsys_review_record
reads it. A markdown packet is still accepted (ADR 0006).
Event modelling has a skill (event-modelling: three slice patterns, Given/When/Then, completeness).
devsys_event_model_check validates a directory of slice files (schema v1) and renders the swimlane
Markdown or a Mermaid diagram; each profile's gwt-tests reference turns scenarios into failing tests.
A dedicated extension that offers event_model_validate, or event_model.provider in
.development-system.toml, replaces the builtin tool (contract).
A slice has a life cycle: implementing → reviewing (when a review round starts) → delivering
(review satisfied) → idle. Editing production source while delivering reopens implementing,
and red-first stays on throughout. A push of a clean tree closes the local slice context by itself
(a commit in local-only mode; CI is not awaited), and devsys_finish_slice closes it explicitly or,
with a reason, abandons it. This does not establish PR delivery or whole-issue completion.
Consolidate preparatory steps into usable increments; the approved plan is not a requirement for
one handoff or release per step. After a local slice closes, the next increment starts with devsys_intake.
devsys_intake does not interrupt autonomous work: Jev's size is used when Jev is at least 50%
confident, and the user is asked to pick only when it is less sure (or unavailable). A size decided up
front, such as in a goal's planning, is passed as size and skips the sizing question entirely.
Fix-sized work retains independent review; intake never offers to waive it. The default is
one substantive clean independent review of the current diff, with real findings resolved
and fixes reviewed. Explicit stronger settings and in-flight review requirements remain.
Task checks validate structure; subjective readiness is advisory, not permission to code. Do not rewrite until a classifier says ready or split a capability just because it needs multiple tests. Implement directly when context is sufficient; delegate independent work or focused expertise with a named integration check. After two process-only attempts without new implementation or acceptance evidence, simplify to the next behavioral test or escalate one concrete blocker. The push timer asks for this diagnosis; it does not measure planning activity or justify bypassing any gate. See the bounded-flow effect evidence for action traces, harmless controls and classifier limitations.
With codemode enabled ("defaultTools": ["+codemode"] in pi settings), rarely used tools are
reached through scripts. With tool_search instead, search activates them on demand. Without either
discovery tool, the rarely used tools are declared directly. This fallback is refreshed before each
model turn; enabling discovery withdraws only declarations added by the fallback, preserving tools
that were independently active. The judge_* Jev wrappers remain registered for scripts or explicit
search activation, never automatically added to the direct fallback. Sessions from before 1.7.0 lack
fallback ownership records: their existing rare-tool selections are preserved on upgrade. Explicitly
deactivate those selections if you want them available only through discovery.
Configuration
.development-system.toml at the repository root (version 1). Every key is optional; an unknown
key is an error that names it. /devsys-models writes the [models] table for the models this
machine can use.
| Table | Keys | Meaning |
|---|---|---|
[delivery] |
mode (trunk, pull-request, local-only), trunk, remote |
Where work lands; the push guard follows it. local-only blocks every push. |
[review] |
required_clean_rounds (1), min_rounds (1), thinking_level (high), guidance (paths; default []) |
Independent review of the current diff and configured guidance; explicit higher round requirements remain supported. |
[tracker] |
kind (repo-files, github; jira and linear are not implemented), repo, optional GitHub project_id |
Backlog for devsys_work_item; opt-in Project observations and explicit enrollment. |
[workflow] |
guidance (repository-relative file paths; default []) |
Explicit repository-owned workflow content for root and SDK child requests. |
[profiles] |
override |
Languages to apply (rust, typescript, elixir); empty means detect. |
[models] |
one ordered candidate list per slot | See Model tiers below. |
[routing] |
"<difficulty>/<risk>" = ["<slot>", "<thinking level>"] |
What devsys_route_task recommends for a subagent. |
[verifier] |
max_per_session (6) |
Cap on Jev checks of the agent's own claims. |
[cadence] |
push_minutes (60) |
Minutes without a push before the cadence nudge. |
[event_model] |
provider (builtin) |
Another provider replaces the builtin validator. |
Machine-local models (an Ollama host only this machine reaches, say) do not belong in the committed
file. Put them in development-system.toml in pi's agent directory (~/.pi/agent/, or
PI_CODING_AGENT_DIR). That file may hold only version and [models]; each slot's candidates
there go ahead of the repository's on this pi, and /devsys-models shows them but never writes them
to the repository (ADR 0010).
version = 1
[models]
fast = ["my-ollama/qwen3-coder*"]
Repository-owned workflow references
[workflow]
guidance = ["docs/workflow.md", "docs/delivery-policy.md"]
These explicit references transport local instructions; devsys does not interpret a universal workflow schema. Before every root or SDK child request (including independent children and resumed sessions), devsys loads current content with source paths, SHA-256 hashes and a snapshot identity. This is model guidance, not enforcement of arbitrary local policies; it does not automatically reach external agent runtimes.
Files must be tracked by Git, repository-contained regular UTF-8 files. Absolute paths, parent traversal, symlink escapes, untracked/missing files and invalid configuration refuse preparation with repair advice. Limits are 32 KiB per file and 64 KiB combined; there is no silent truncation or recursive link/include loading. Configured guidance also refuses a full-system-prompt override, which would bypass section refresh; repair the overriding extension to use named prompt sections instead. An empty list adds no local workflow content. Review-specific guidance has its own contract; this setting does not change typed review submission or grant permission to provision tracker resources.
Repository-specific review concerns
[review]
guidance = ["docs/review-concerns.md"]
Fresh reviewer tasks, including the Markdown fallback, receive the configured workflow and review sources with paths, content hashes and one review input identity. The same tracked/contained UTF-8 rules apply, with one combined 64 KiB budget across both categories and 32 KiB per file. Missing or invalid configured sources refuse preparation; an empty review list invents no repository concerns.
Keep local concerns specific to the repository. They supplement engineering review; they do not override hard stops, prove obedience or automatically enforce arbitrary product policy. Conflicts or inaccessible sources require owner clarification rather than silently choosing a policy. External reviewer runtimes must receive the returned task explicitly; they do not inherit the parent conversation automatically.
For configured guidance, preserve reviewInputIdentity from review start in typed
submission and record calls, or in the requested fallback packet and record arguments.
Submissions are bound to the pending round's identity and range. Changes to the diff
or source content require a fresh review; stale asynchronous judgments cannot record
clean credit. Removing the final source also invalidates old credit. Commit checks
reject changed guidance before any staged-file subset exception. Unconfigured legacy
review flows remain compatible; explicit round requirements and finding severities
are unchanged. These are fresh local observations, not an atomic lock on future edits.
See the review effect fixtures for bounded SDK behavior checks, model/hash provenance, controls and limitations. Ordinary tests remain offline.
Discovering or defining the local workflow
Load the project-workflow skill when adopting devsys, replacing an existing
factory, or reconciling policy and automation. It inventories authorized sources
read-only, separates intent/configuration/execution, and escalates contradictions
or access gaps to the owner before operational changes. It proposes discoverable
version-controlled workflow/review documents, pointers and explicit integration
configuration without prescribing universal queue states or provisioning a board.
This is model guidance, not enforcement. See the effect-eval evidence and opt-in runner for tested behaviors, failed controls and limits. The ordinary test suite never calls a live provider for these cases.
GitHub Issues-only setup
With [tracker] kind = "github", issue lifecycle is projected as open/done,
and an existing in-progress label marks active open issues. This is a compatibility
convention, not a Project workflow or proof of delivery. Ordinary tracker operations
never create or recolor labels.
Before using status = "in-progress", an authorized repository owner must explicitly
review this convention and ensure the label exists in the target repository. For
example, after checking existing labels:
gh label list --repo OWNER/REPO
gh label create in-progress --repo OWNER/REPO
These are manual setup commands, not actions performed by devsys_work_item. Do not
force an existing label's settings. If an update fails, its original GitHub error is
returned; missing setup is only one possible cause (permissions or another edit may
have failed). Inspect the error, re-read the issue and repository setup, and retry
explicitly after resolving the cause. A failed edit does not trigger issue closure
or reopening; GitHub edits are not promised to be transactional. Repo-file tracking
requires no label setup. Project integration is not provided by this convention.
Optional GitHub Project inspection
Issues remain work descriptions. To inspect an existing Projects v2 board, explicitly configure its opaque GraphQL node id; neither its title nor its number is a global id:
[tracker]
kind = "github"
repo = "OWNER/REPO"
project_id = "PVT_REPLACE_WITH_ACTUAL_NODE_ID"
Call devsys_work_item {action:"inspect"} for the configured Project's owner login,
number, title, URL, field ids/types and single-select option ids/names. An optional
fieldId asserts that a field belongs to this Project; names never choose a field.
The returned capabilities describe currently implemented tool actions, not a workflow.
Without project_id, inspection returns project:null with no Project network call;
repo-file tracking works the same way. The option is invalid for non-GitHub trackers.
The read uses existing gh authentication and requires access to the Project, including
organization/SSO authorization where applicable. Classic tokens need read:project;
fine-grained tokens need the relevant organization/user Projects read permission.
Private issue access may require additional repository permissions for later operations.
No credential is stored by this extension, and inspection never provisions labels,
fields, options or membership. It does not select or claim issues or change board state.
All field pages are read (100 per page, maximum 100 pages). Missing/repeated cursors, duplicate identities, malformed results, GraphQL partial errors and permission failures return explicit errors, not a usable partial board. Correct access/configuration and re-read before proceeding. Pages are observations, not an atomic snapshot or a lock; humans can change the board concurrently. This metadata API introduces no canonical status mapping and does not replace the Issues-only compatibility convention above. Live smoke checks are optional: only invoke inspection after explicitly choosing a Project you are authorized to read. Ordinary tests use fake process responses and need no GitHub credentials.
Read-only Project issue observations
devsys_work_item({ action: "project-items" }) observes a configured Project's
repository issues. It requires both tracker.repo and tracker.project_id above;
repo-file and Issues-only tracking keep their existing behavior. Optional lifecycle
is open or closed and filters GitHub issue lifecycle only. To filter a single-select
value, supply both fieldId and optionId using identities returned by inspect:
{"action":"project-items","lifecycle":"open","fieldId":"PVTSSF_example","optionId":"example-option"}
The result separates issue lifecycle, item archive status and raw Project values. It
includes issue/item node identities, number/title/URL and observed single-select,
text, number and date values. Other field values are explicitly unsupported with
their API type, not coerced into workflow states. A missing value does not prove a
workflow state. Field/option filters are validated against the configured Project;
legacy status is refused rather than silently interpreted as a Project filter.
Both archived and non-archived items are requested explicitly. Archived issues remain
observations with diagnostics; no item is selected, claimed, enrolled or unarchived.
Drafts, pull requests and foreign-repository issues are excluded with diagnostics.
Redacted/inaccessible content makes eligibility unknown, not an empty eligible
queue. Otherwise eligibility is unassessed: repositories decide their own criteria.
Returned API order is only an observation, not priority, rank or saved-view ordering.
All item pages and each relevant item's field-value pages are exhausted (100 per page,
maximum 100 pages per connection). Missing/repeated cursors, duplicate identities,
stale field/option identities, malformed/partial responses, process failures and
permission errors discard partial observations and return repair/re-read advice.
The metadata and item reads are not an atomic snapshot and do not reserve work.
Large boards can require many read requests; reaching the bound is an error, not
successful truncation. Correct permissions/configuration, then re-read. Existing gh
authentication and Project/private-issue read permissions apply as above. No board
writes or live credentials are needed by the ordinary tests; live smoke checks remain
explicitly chosen and opt-in. The API request shape is documented in GitHub's
Projects GraphQL reference.
Explicit Project membership and enrollment
With both tracker.repo and tracker.project_id configured, the tool advertises
project-member and project-enroll. Both require an explicit positive safe integer
issue number as id; URLs, switches, zero and fractional numbers are refused.
{"action":"project-member","id":"7"}
This read resolves the issue in the configured repository and scans the complete
Project using the same validated item/field observations as project-items. The JSON
contains projectId, repository, the issue identity, and membership.kind:
present includes actual item fields and archive facts; absent means a complete
scan proved no match; unknown includes redaction diagnostics and is a tool error.
Duplicate or inconsistent matching identities are errors, never usable membership.
The action never writes, selects work or interprets a workflow state.
{"action":"project-enroll","id":"7"}
Enrollment always re-reads first. Existing nonarchived membership returns
kind:"not-attempted", outcome:"already-member" successfully without an add.
Archived or unknown membership, invalid identities, missing configuration and failed
preflight reads return kind:"not-attempted", outcome:"blocked" as tool errors,
without writes. Only proven absence permits one addProjectV2ItemById mutation,
with explicit Project and issue node ids passed as GraphQL argv variables. It uses
existing gh authority: Project write access (classic token project scope or the
relevant fine-grained Projects write permission), repository access and any required
organization/SSO authorization must already be granted. No credentials are read or
logged by this module, and it never provisions permissions or other resources.
A valid acknowledgement and fresh read confirming the intended Project/item/issue
and nonarchived membership yield kind:"confirmed", outcome:"enrolled". Every
outcome includes a message and an observation (or null when unavailable).
Timeouts, process failures, nonzero exits, partial GraphQL errors, malformed or
mismatched acknowledgements and failed verification after dispatch instead return
kind:"uncertain", outcome:"unknown" as tool errors. An included preflight
observation is not proof that the mutation had no effect.
After uncertainty, explicitly call project-member to re-read before deciding on a
retry. A later explicit project-enroll also re-reads first: if the timed-out add
actually succeeded, it reports already-member and sends no second add. There is
no automatic retry, rollback, removal, unarchive, field write or implicit issue
closure. These reads are complete but not atomic snapshots; preflight is not
compare-and-swap, and a concurrent human edit can race the add or verification.
Enrollment does not reserve or claim work. Ordinary tests use an in-memory Exec
remote, not live GitHub credentials or downstream repositories.
Explicit single-select set and clear
With the same explicit repository and Project configuration, project-set changes
only a named single-select field on a named, existing nonarchived issue membership:
{"action":"project-set","id":"7","fieldId":"PVTSSF_example","optionId":"example-option"}
{"action":"project-set","id":"7","fieldId":"PVTSSF_example","clear":true}
Specify exactly one of optionId or clear:true. The tool reads actual field/option
identities and membership before dispatch; foreign options, unsupported field types,
absent/unknown/archived membership and invalid inputs cannot authorize a write. It
never enrolls or unarchives implicitly. An already-satisfied value is a verified
no-op. Otherwise it sends one explicit set/clear mutation using the existing Project
write authority, then verifies acknowledgement, membership and field metadata.
The JSON includes kind, message, before and after. confirmed means a verified
no-op or fresh matching readback; not-attempted is a refusal; uncertain means a
write was dispatched but its intended effect could not be confirmed. Refusals and
uncertainty are tool errors. An included before snapshot is not evidence that a
write failed. Re-read membership and metadata before any explicit retry; there is
no automatic retry, rollback, schema provisioning, assignment, lifecycle or other
field update. Option names have no built-in workflow meaning. Preflight/readback
cannot eliminate concurrent human races or provide an exclusive claim.
Explicit issue assignment
With tracker.repo configured, assign adds or removes only explicitly named
GitHub logins. A Project is not required:
{"action":"assign","id":"7","operation":"add","assignees":["alice"]}
Use operation:"remove" to remove the named assignees. Empty or duplicate lists,
@me, switches and invalid identities are refused. The tool verifies issue identity
and complete current assignees before an edit. Already-satisfied requests are verified
no-ops. Otherwise it sends one assignee-only edit and re-reads the issue to confirm
requested membership and preservation of unrelated assignees. Existing gh
repository access and Issues write permission must already be available.
Results contain kind, message, before, after and ownership:"not-exclusive".
Preflight refusals are not-attempted; dispatched failures, invalid acknowledgements
and failed readback are uncertain. Both are tool errors. Re-read before deciding
on an explicit retry; there is no automatic retry or rollback. Assignment neither
reserves work nor changes Project fields, labels or issue lifecycle. Concurrent human
changes can race these observations; even confirmed assignment is not an atomic or
exclusive claim.
PR observations and whole-issue completion
delivery-check reads explicit PR references without writing or polling:
{"action":"delivery-check","refs":[{"repository":"o/r","number":11}],"conditions":{"requireMerge":true,"targetBase":"main","requiredChecks":["CI"]}}
The result reports only those requested conditions: satisfied, pending, failed,
blocked, unknown or unassessed. Auto-merge being armed is not a merge. Missing,
old-head, incomplete or unsupported evidence never passes a required condition.
Manual requirements stay unknown; there is no universal CodeRabbit, deployment,
merge or priority policy. These are bounded observations, not an atomic snapshot.
For resumable repository-owned completion, opt in explicitly:
[tracker]
kind = "github"
repo = "o/r"
[delivery.evidence]
manifest_dir = "docs/delivery"
require_manifest = true
require_merged = true
base = "main"
required_checks = ["CI"]
Author and track docs/delivery/7.json with the complete required PR set:
{"version":1,"issue":{"repository":"o/r","number":7},"pullRequests":[{"repository":"o/r","number":11},{"repository":"o/r","number":12}],"manualRequirements":[]}
Manifests contain references, not cached workflow/status/credential data. They must be Git-tracked regular UTF-8 files within the repository, at most 32 KiB; symlinks, unknown versions/fields, malformed or duplicate refs, escapes and wrong issue identity are refused. Existing invalid files are not ignored. Optional absent manifests may use explicit refs, but explicit refs cannot replace a present manifest's declared set. Nothing writes or provisions manifests automatically.
{"action":"delivery-check","id":"7"} evaluates configured policy using the
current manifest. {"action":"complete","id":"7","scopeConfirmed":true} requires
explicit confirmation of the whole issue scope, fresh configured evidence and
unchanged local manifest/config before sending one issue close and verifying it.
The tool cannot prove that the declared PR set or a scope assertion covers all work;
the repository owner remains responsible for that declaration. An uncertain close
is an error requiring re-read before any explicit retry, never automatic rollback.
With evidence configured, legacy update status:"done" refuses before title, label
or lifecycle edits; use complete. Caller conditions cannot weaken configured
completion policy. require_manifest alone does not imply merge; an empty policy is
unassessed, not a hidden default. With no evidence configuration, legacy behavior is
unchanged and complete says delivery is unconfigured/not evaluated. Completion
changes issue lifecycle only, never a Project terminal field or other local workflow.
GitHub PR/check reads and issue-write permissions must already exist; Project scopes
are needed only for separate Project operations. External gh, UI and automation
writes are outside this guard.
See the product PR workflow, research/local workflow, finite adoption effects and limitations, and Simulac adoption recipe. The same primitives support both examples without upstream workflow code changes.
Elixir and Phoenix
A tracked or untracked repository mix.exs marker detects the elixir profile;
explicit [profiles].override retains precedence and profiles survive session replay.
The profile-elixir skill follows repository instructions, module boundaries and
exact configured commands rather than importing Rust/TypeScript syntax or defaults.
It uses tagged tuple errors and a pure domain core, ExUnit/property testing for
appropriate invariants, LiveViewTest for relevant server UI behavior and browser
coverage only when browser-dependent acceptance requires it. It does not mandate
new libraries, an architecture, event sourcing or a universal Phoenix test stack.
Compiler warnings, formatting, Credo and Dialyzer follow the repository's actual configuration; a missing tool is not a passing check. See the Elixir effect evidence for finite actual-SDK plan/command-selection checks and retained failures. Synthetic commands in those fixtures were NOT EXECUTED; they do not verify a real Elixir application or substitute for its Mix, ExUnit, LiveView or browser checks.
Model tiers
Models are asked for by slot, never by id. Three capability tiers (frontier, strong, fast)
and role slots built on them (planning, advisor, implementer, reviewer, lens,
researcher, jev). A slot is an ordered list of candidates: provider/id, a family pattern
such as provider/gpt-*-sol (the newest available id wins) or a slot reference such as @strong.
The first candidate this machine has credentials for is used, so one committed file works across
accounts. When routing a task or a spawn, a candidate whose known context window is too small is
skipped: the estimated request (8K tokens of overhead plus the task text and named files) must be at
most 60% of the window (ADR 0009). This lets a small local model come first in a slot and still
fall back to a cloud model for large work; devsys_route_task says which models it skipped. Pin an exact id to stop it rolling forward. devsys_models shows what each slot
resolves to, and the system recommends a model for a phase but never switches yours.
Enforcement tiers
- Hard stops fire for the non-negotiables (
principles/NON-NEGOTIABLES.md): rewriting published history, force-pushing, deleting remote branches, discarding work (reset --hard,checkout/restoreof the whole tree,clean -f),--no-verify, forbidden commit trailers, committing a credential, pushing onto a red trunk, breaking the delivery mode. Only the user can approve one, once, and only with a UI: a headless run refuses. - Soft gates guard the defaults (
principles/DEFAULTS.md): weakening tests, commit rationale, mixed commits, red-first, lint suppression, an unreviewed slice, a missing ADR. A soft gate is passed by recording a departure withdevsys_record_departure(what, why, cost if wrong, how long it applies). Scope drift and the model for the phase are softer still: the system nudges or advises. A skipped planning artifact is recorded when the agent records it;devsys_begin_worklists the recommended ones that have neither a file nor a recorded skip, and does not block. - Guidance covers everything else: skills and the phase guide, never enforced.
What the tiers do not cover, so you can decide what to trust:
- Not every non-negotiable is a hard stop. Rewriting history, force-pushing,
--no-verify, trailers, a red trunk and the delivery mode are stopped by code. A false claim of "done" is checked by a Jev turn verifier that nudges (and only with Jev), an architecture decision without an ADR is a soft gate (also Jev), and an evidence check on model-visible text is a CI test. - The secret stop reads known formats, not every secret. A commit that adds a private key, a
GitHub, AWS, Stripe, Google, Slack, GitLab or npm token, a JSON web token, a password inside a URL,
a quoted literal assigned to a
secret/token/password/api_keyname, or a file such as.envor*.pemis a hard stop (commit.secret) that the user can approve once, for a test fixture that merely looks like a credential. Anagent_spawntask carrying one is refused outright, with no approval, because a task is text the agent writes and can reword. A secret in another shape passes. Only content the commit adds is read; an untracked file is read only when the command stages it, and only when it is a regular file under 200 KB (a larger one is still checked by name). The scan runs before the command does, so a file the same command creates, or a repository it initialises withgit init, is not seen. - Reviewer effort is configured, not judged. Review and lens subagents run at the
[review]thinking_level(defaulthigh) on thereviewerandlensslots; it is not routed by risk.devsys_route_taskroutes the implementer, and the coordinator must pass its result on. A plainagent_spawnwith nomodelgets the model of the agent type's slot when the project configured that slot in[models], passing over models whose context window the task text would already crowd; an unconfigured slot leaves the agent type's own list in force. - Subagents run unguarded. A child session is started without extensions, so none of the guards runs inside it. The coordinator commits, pushes and delivers; a subagent's prompt tells it not to, and the coordinator reviews what it produced.
- The red-trunk stop needs
gh. It reads CI through an authenticatedgh; whereghis missing or offline the trunk reads as unknown and the push is not stopped on that ground. - A departure is the agent's own call.
devsys_record_departurewaives a soft gate (also with no UI) and is written to the decision log; it is never available for a hard stop. - Gating starts at
devsys_intake. With no slice open, the review and red-first gates are off. - Command shape is read, not run. The git guards classify the command text: aliases and
git configthat redirect a later command, shells reading stdin, andpython -cornode -ethat mention git are all treated as unclassifiable, so the user decides (headless: refused). A command the classifier cannot see into at all (a script file, another tool) is not covered. Commit messages are checked again at push time against what the remote lacks, so a commit made by-C,--fixup,commit-treeor an alias cannot carry an AI trailer or skip the rationale; a push in the same call as such a commit is refused, because the commit does not exist yet when it is checked. - A push source the shell builds is checked loosely.
git push origin "$(cat sha)":refs/heads/xchecks every local branch for AI trailers, not the unnamed commit the expression may name (one made withcommit-treeand on no branch). The unclassified-command prompt is the only stop there. - A push after a ref moves in the same call is checked against the refs as they were.
git merge --ff-only feature && git push origin mainpublishes commits onfeaturethat the push check read before the call ran. Make the merge, switch or reset in one call and push in the next. - Editing gate configuration is not guarded (
biome.json, hooks, CI files); review catches it.
Decision log
Every departure and approval is appended to docs/decisions/YYYY-MM.md in the repository, so the
reasons survive compaction and are reviewable. Architecture-shaping decisions get an ADR in
docs/adr/ (devsys_adr_new); product decisions go in the decision register that the
product-planning skill describes.
Commands
All of them are shortcuts to tools; none is required.
| Command | Does |
|---|---|
/devsys-start |
Size the work and propose the artifacts it needs. |
/devsys-plan |
Plan a capability or product, then begin work once approved. |
/devsys-review |
Run a fresh-context review round. |
/devsys-lens-review |
Five product lenses review the brief. |
/devsys-adr |
Create the next ADR. |
/devsys-event-model |
Validate and render an event model. |
/devsys-models |
Write the model matrix for this machine (--check to verify). |
/devsys-ci |
Watch CI for the pushed commit. |
/devsys-status |
Phase, slice, review streak, departures and Jev status. |
/agents |
The vendored subagent manager. |
Agents
Spawn with agent_spawn; devsys_route_task picks the model and thinking level. advisor gives
read-only decision support, implementer, coder and tasker build (one task record each),
reviewer reviews a diff in fresh context and submits through devsys_submit_review,
researcher reads and cites, architect and writer design and draft, and the five lens-*
agents (Cagan, Torres, Pichler, Perri, Rumelt) review a product brief.
Changelog
CHANGELOG.md is generated from the commit history by npm run changelog. A release is the commit that
changes the version, so run it after that commit exists; the file lists what has been committed so far.
Development
The development lockfile and compatibility regression suite target pi 1.4.0. Host-provided pi packages remain wildcard peers, as pi's package contract requires; that declaration is not a claim that every older or future host release is tested. TypeBox follows the version supplied by the tested pi host rather than an independently upgraded copy.
nix develop
npm ci
npm run typecheck
npm test
npm run lint
npm run lint:knip
npm run lint:md