Skip to content

About

Owner-centered development pipeline for Codex, Claude Code, and Cursor

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

dev-pipeline

dev-pipeline is an experimental, owner-centered software-development pipeline. One native owner session, run by Codex, Claude Code, or Cursor, owns the path from prepared requirements to implementation evidence. Independent agents are intended for bounded review and verification, not a mandatory document handoff chain.

The CLI starts a new owner attempt, genuinely continues its recorded native owner session, or explicitly starts a linked new attempt over existing artifacts. It provides compact scenario, architecture, walking-skeleton, and vertical-increment gates, routed convention packs, and bounded review contracts. Application-specific adapters remain outside the public core.

The discoverable $dev-pipeline skill provides a compact owner-runtime invocation guide. The CLI and package documentation remain the canonical workflow and schema authority.

Requirements

  • Python 3.11 or later
  • an installed and authenticated owner CLI: Codex, Claude Code for --owner-runtime claude, or the Cursor CLI for --owner-runtime cursor
  • a prepared instruction file and target Git repository

Install

An editable install is a contributor convenience only: use it in an isolated development virtual environment where source edits are intentionally live. A consumer runtime or service must install an exact reviewed Git revision from its lock file and verify the installed PEP 610 commit identity before work.

python -m venv .venv
.venv/bin/pip install -e .

Choose an assurance level

An installation may select one honest verification promise: cross_provider, isolated_same_provider, or live_acceptance_only. They do not provide equal assurance. Preflight reports installed executables and driver-owned capabilities, and refuses an unavailable or unsupported promise without falling back to another strategy:

dev-pipeline assurance preflight \
  --config /path/to/assurance.json \
  --owner-runtime codex

Pass the same file as --assurance-config to owner start, owner resume, or owner retry. owner resume follows the durable phase: before assurance it continues the recorded author session, while a waiting review or rework phase advances through the configured reviewer or recorded author respectively. A successful assured owner run records assurance_pending; it does not complete the attempt. For a model-review strategy, also pass the exact digest-bound packet as --review-packet. The owner entrypoint atomically claims and starts the configured provider driver in a fresh read-only session as soon as author execution succeeds. A rework verdict resumes the same author session, refreshes only the repaired subject digest, and starts a fresh re-review.

After a provider outage, an ordinary owner resume or the lower-level handoff entrypoint can idempotently advance the durable next phase without selecting a role:

dev-pipeline handoff resume \
  --task-ref issue-123 \
  --state-dir /path/to/existing-attempt-state \
  --config /path/to/assurance.json \
  --repo /path/to/repository \
  --owner-runtime codex

The stage refuses a wrong provider relationship, reused author session, unavailable driver, missing capability, changed configuration, stale candidate, or candidate digest change during review. An outage remains waiting, a material finding records rework, an integrity failure is distinctly refused, and only an exact approved verdict completes the attempt. The generic stage selects Codex, Claude, or Cursor from configuration; it does not call the separately retained Codex-specific agent command. The explicit review execute command remains available, but uses the same atomic claim and cannot launch beside an already claimed phase. Running that explicit low-level command against a completed or already claimed phase is an operator error with a visible message and non-zero exit.

Codex review children are raised, before exec, to the measured 26 GiB virtual address-space floor when the caller's soft RLIMIT_AS is lower and its hard limit permits the raise. This applies only to the read-only reviewer launch; it does not change owner-process limits. If the reviewer still cannot read the repository or named evidence, the result is review_waiting with review_outcome=subject_unreadable and no candidate decision. The notification therefore asks for reviewer availability and the original author is not sent to rework. A genuine reviewer blocked decision keeps its external-decision semantics.

A crash or host restart after a phase claim is recoverable through ordinary handoff resume. The claim holds a namespace-independent advisory lock in the state directory and also records diagnostic process identity; when the process is gone, the command durably returns the phase to waiting and retries the same configured reviewer or recorded author session. A live claimant remains an idempotent no-op. Automatic review/rework has no round-count limit. A legacy max_review_rounds field remains readable for schema-1.0 migration but is ignored. If author rework leaves the candidate digest unchanged, the attempt records a concrete rework_no_progress refusal before another reviewer is launched; it never spends a reviewer call on the same subject twice.

A supervising runner may call dev-pipeline handoff request-stop --task-ref ... --state-dir ... before interrupting a live review or rework. That command binds the reason to the exact phase lock for diagnostics; recovery uses the same ordinary resume path whether termination was planned or unexpected.

Historical claims without the advisory lock are treated as interrupted and reopened through the same durable waiting transition.

For live_acceptance_only, no reviewer is started. Record exactly the configured scenarios and their real-path evidence with dev-pipeline assurance accept-live; all must pass before completion. Existing commands without a configuration remain compatible. See Installation assurance for the schema, examples, evidence shape, and exact guarantees.

Start an owner attempt

dev-pipeline owner start \
  --task-ref issue-123 \
  --instruction-file /path/to/prepared-instruction.md \
  --artifact /path/to/contract.json \
  --repo /path/to/target-repository \
  --state-dir /path/to/caller-owned-state

The command emits neutral lifecycle JSONL to stdout and stores events.jsonl plus an atomically replaced state.json in the caller-selected state directory. The task reference is opaque. Paths are caller values: this package does not discover a task index, prescribe task filenames, or import transport/application policy.

The first attempt always has attempt_origin=new_owner_session; the first run always has run_operation=native_session_start. A successful start requires a native session identity from the owner runtime: a thread.started event from Codex, or the assigned session ID echoed by Claude. The pipeline never fabricates a native session ID from a process ID or filename.

The owner prompt preserves adjacent production behavior unless the accepted contract explicitly changes it. It applies the no-code-first order—do nothing, remove/disable, configure/reuse, simplify, then write the smallest necessary code—and asks the owner to justify the last step. The independent review prompt treats avoidable code or complexity as a defect. Compatibility, fallback, parsing, persistence, or delivery-policy expansion requires a concrete blocker rather than an inferred assumption. Task/review/evidence artifacts remain outside the target repository in the caller-owned artifact directory; evidence checkpoints reject absolute or escaping artifact paths.

Continue or retry

Continue the same attempt and opaque Codex session with a new instruction:

dev-pipeline owner resume \
  --task-ref issue-123 \
  --instruction-file /path/to/continuation.md \
  --repo /path/to/target-repository \
  --state-dir /path/to/existing-attempt-state

If native state is deliberately abandoned, retry is a separate explicit operation. By default it appends a linked attempt to the same task-local store; the ledger preserves the predecessor events immutably:

dev-pipeline owner retry \
  --task-ref issue-123 \
  --instruction-file /path/to/prepared-instruction.md \
  --artifact /path/to/contract.json \
  --repo /path/to/target-repository \
  --state-dir /path/to/task-lifecycle-state \
  --retry-reason intentional_replacement

Resume first tries the recorded native session. Definitive unavailability emits native_resume_unavailable with a canonical condition (missing_session_id, archived, not_found, or identity_mismatch), then appends and starts a linked replacement attempt in the same store when the attempt is active and its digest-bound original instruction/artifact context was recorded and remains intact. Catch-all runtime failures and a missing emitted identity do not prove session loss and require an explicit retry. Owner start captures caller-supplied artifacts into read-only, digest-bound lifecycle input snapshots, so later caller-path edits cannot change replacement context. The replacement claim atomically requires that the predecessor is still active and receives both the original instruction and the continuation. A completed attempt may still continue its recorded native session, but native unavailability does not replace that completed attempt implicitly. Failed, changed, or older context-less attempts fail closed and point to explicit owner retry. Raw owner output remains localized in diagnostics. Deliberately replacing an available session still requires --retry-reason intentional_replacement; --previous-state-dir remains available when the predecessor uses a separate legacy store.

Claude usage exhaustion is a resumable run outcome, not native-session unavailability. When the structured stream reports a rejected rate limit with an exact reset timestamp, the core records run_waiting_for_quota and keeps the attempt/session identity active. It never derives quota from prose or converts the attempt to another runtime.

Historical conditionless unavailability events remain readable as legacy/unclassified append-only history, but cannot authorize automatic retry or condition-specific behavior. Every newly appended event requires a canonical condition.

Scenario and architecture checkpoints

Checkpoint artifacts are canonical English JSON objects with schema version 1.0. Apply a scenario checkpoint to an existing owner attempt with:

dev-pipeline checkpoint scenario \
  --task-ref issue-123 \
  --state-dir /path/to/existing-attempt-state \
  --input /path/to/scenario-checkpoint.json \
  --next-step "Run bounded scenario review"

Use checkpoint architecture for the architecture delta. Scenario records require actors, triggers, expected outcomes, behavioral acceptance, failure modes, assumptions, and explicit blocking questions. Architecture records require the production path, owning layer, reuse plan, deletion plan, forbidden parallel mechanism, verification path, and a digest link to the scenario artifact.

Before accepting an increment, use checkpoint evidence with the current task contract. The checkpoint inventories mandatory scenarios, failure modes and production branches; binds exact argv-style commands, representative fixtures, real production entrypoints and digest-verified artifacts; and rejects weak, stale, aggregate-only, mock/stub/fake/harness-only evidence. Product work also declares intended jobs and a generic capability matrix covering input, processing environment, dependency policy, output, multi-artifact delivery, validation/completeness and safety. Unsupported capabilities are explicit constraints or blockers, never silent omissions.

When an increment creates or changes infrastructure, apply checkpoint deployment before claiming deployed evidence. The deployment artifact binds the exact increment, evidence checkpoint and source revision; declares every supported resource, update, readiness and rollback category applicable or not applicable; and requires tracked bootstrap, disposable clean-environment evidence, drift detection and durable-root backup/restore integrity. A live smoke on an already-mutated host is not reproducible deployed evidence. increment accept --deployment-checkpoint ... is mandatory for an increment whose achieved evidence level is deployed.

An unresolved material question emits blocked_on_user_decision, persists an active blocker, and exits with status 3 without completing the checkpoint. A complete contract emits checkpoint_completed with its artifact digest. The command validates owner artifacts; it does not infer product semantics from prose.

Build a bounded review packet with dev-pipeline review packet. For increment closure, pass both --task-contract and --evidence-checkpoint; their SHA-256 digests become closure bindings. Programmatic callers may also bind evidence_attachments. The exact candidate bytes remain digest-bound and embedded, while the isolated reviewer receives read-only directory grants for the named live evidence files and inspects their current bytes directly. Attachment digests record handoff discovery but do not freeze lifecycle artifacts that legitimately advance while review starts. Only the reviewed artifact is subject to the 1 MiB inline limit. The command also binds the review question, constraints, target instructions, exclusions, artifact version, and reviewed-artifact digest. Validate the reviewer’s single structured envelope with dev-pipeline review decision; its schema_version is the JSON string "1.0", and only approved, rework_required, blocked, and rejected are accepted. findings is an array of objects whose id, severity, summary, and evidence_ref are non-empty strings; blocking_questions and evidence_checked are arrays of non-empty strings. An approved envelope has no findings or blocking questions, while a blocked envelope has at least one blocking question. A stale artifact digest or a structurally inconsistent envelope is rejected. Non-approved decisions exit with status 4.

Walking skeleton and vertical increments

Submit the first observable increment after scenario and architecture checkpoints:

dev-pipeline increment submit \
  --task-ref issue-123 \
  --state-dir /path/to/existing-attempt-state \
  --input /path/to/increment-1.json

The first increment must be walking_skeleton; later increments must be vertical_increment. Each maps named scenarios and failure modes to required evidence, records source/deletion deltas, and identifies temporary seams. Stubs and temporary adapters are permitted only at a new_boundary or unavailable_external boundary. Each has a stable ID and later replacement increment; advancement at that milestone requires recorded removal backed by passed real-entrypoint evidence.

Legacy seam-bearing artifacts without those canonical fields are rejected without inference or rewriting. Historical seam-free increment artifacts remain compatible.

Evidence levels are ordered structural, unit, skeleton, integrated, live, and deployed. Structural and unit evidence may support development but cannot satisfy an increment gate. The walking skeleton requires at least real-entrypoint skeleton evidence; vertical increments require at least integrated evidence. Every named scenario and failure mode must be covered by passing required evidence.

Submission records increment_ready_for_review. Build an increment review packet for that exact artifact. A configured installation may produce its digest-bound envelope with review execute; then accept it with the approved envelope:

dev-pipeline increment accept \
  --task-ref issue-123 \
  --state-dir /path/to/existing-attempt-state \
  --input /path/to/increment-1.json \
  --packet /path/to/increment-review-packet.json \
  --decision /path/to/increment-review-decision.json \
  --task-contract /path/to/task-contract.json \
  --evidence-checkpoint /path/to/evidence.json \
  --next-step "Build vertical increment 2"

A rework, blocked, rejected, stale, or mismatched decision cannot complete the increment. The next increment cannot be submitted until the preceding one has approved review, and a completed increment cannot be reopened through resubmission.

Routed conventions and selective agents

Owner start/resume accepts one --gate and repeated explicitly triggered --risk values. The default owner context is the compact core pack only. It never aggregates the frozen legacy analyst/architect/planner/developer prompts.

dev-pipeline context builds one digest-bound English context for a bounded scout, scenario_review, architecture_review, diff_review, or live_verification. dev-pipeline agent explicitly runs that one packet through Codex, normally read-only. These commands do not create a scheduler or mandatory role chain. See Routed conventions.

Scope and trust boundary

The pipeline invokes the selected owner runtime with the requested access mode and working repository. Review that runtime's authentication, configuration, sandbox, and approval setup before use. Lifecycle state does not store prompts or raw model events, but caller-supplied paths and runtime identifiers are operational metadata and should be protected accordingly.

Application integrations belong outside this repository. An adapter may resolve application-specific tasks and project selected lifecycle events into its own status artifacts, but only this core interprets owner-runtime events and transitions attempt/run state.

The neutral adapter-facing vocabulary covers meaningful run start, checkpoint or increment completion, a structured blocked_on_user_decision, failure, and completion. Transport credentials and destination policy remain outside the core.

See Architecture, Lifecycle schema, Checkpoint contracts, Increment lifecycle, Routed conventions, Contributing, and Security.

Runtime support

This product supports the Codex, Claude Code, and Cursor owner runtimes. Command construction and native event parsing are localized per runtime in dev_pipeline.codex, dev_pipeline.claude, and dev_pipeline.cursor; the lifecycle, event vocabulary, and CLI semantics stay neutral. --owner-runtime selects one, defaulting to codex, and --codex-bin/--claude-bin/--cursor-bin locate the executable. The runtime is recorded on the attempt, and a resume refuses to continue an attempt recorded under a different runtime.

The three boundaries are deliberately separate modules rather than a shared protocol, because the runtimes differ in substance: Codex discovers an opaque session ID from its event stream while Claude accepts an assigned one; Codex takes a sandbox mode while Claude combines native permission and OS sandbox controls; a Claude session is stored per working directory, so it can only be resumed from the repository it started in. Claude maps read-only to only Read, WebFetch, and WebSearch under non-interactive dontAsk (no Bash, whose sandbox always grants cwd writes); workspace-write to accept-edits plus the native cwd-confined sandbox, and danger-full-access to intentional permission bypass plus /opt/projects. Restricted Linux modes require bubblewrap and socat, disable unsandboxed retries, and fail closed if sandboxing is unavailable. A root-launched owner explicitly uses Claude's documented weaker nested mode, which preserves bwrap filesystem confinement while exposing the host /proc view. A fork targeting a further runtime should add another such module and map its real session guarantees into lifecycle outcomes; no drop-in runtime protocol is promised.

Cursor discovers its chat identity from the stream like Codex, but its continuation cannot refuse on its own: cursor-agent --resume <unknown-id> exits successfully and silently starts a fresh chat under that identifier. The Cursor boundary therefore establishes continuability before launch, against the local chat record at ~/.cursor/chats/<workspace>/<chat-id>/meta.json, and reports not_found when no such conversation exists or identity_mismatch when it belongs to another workspace. This runs before the address-space check, so a missing chat is still classified as not_found under an address-space limit the runtime could not have started under. Its access mapping is likewise a measured one rather than a nominal one: --sandbox enabled is a real filesystem boundary that denies writes outside the workspace even for a root-launched owner, but --force overrides it, so no bounded mode passes --force. workspace-write is the sandbox alone, read-only adds Cursor's ask execution mode, which refuses edits and non-read-only shell commands, and danger-full-access disables the sandbox explicitly and adds /opt/projects. The Cursor CLI also reserves a very large virtual region for its WebAssembly heap before it parses its own arguments. Measured against version 2026.08.04, it aborts under an RLIMIT_AS of 25 GiB and starts at 26 GiB, so that limit cannot express a memory bound for this runtime: the smallest value that lets it run is several times a normal host's physical memory. The abort is also unreportable, because the runtime dies writing megabytes of bundle source to a pipe and Node discards the queued tail. The boundary therefore refuses a too-small limit before launch instead of returning an opaque non-zero exit.

That refusal is decided by the installed CLI, not by the recorded measurement. Under a finite RLIMIT_AS the boundary runs cursor-agent --version — the same entrypoint the wall was measured with, and it hits the same reservation because the reservation precedes argument parsing — and refuses only if it exits non-zero. A version number is not consulted, so an upgrade that needs less address space starts and one that needs more is still refused. An unlimited RLIMIT_AS skips the probe, a probe that does not finish is treated as unstartable, and an unusable binary is reported by the launch itself rather than as an address-space claim. Set DEV_PIPELINE_CURSOR_PROBE_TIMEOUT_SECONDS to change the probe timeout; it defaults to 60 seconds, against a probe measured at about one second.

Read-only Claude launches select no user, project, or local settings sources, so independent reviewers cannot inherit permissions, hooks, plugins, or other command-bearing customization; OAuth authentication remains available as runtime state. Workspace-write Claude owners continue to load only the project settings source and fail before launch if .claude/settings.json contains command-bearing settings, plugins, non-read permission allow rules, added directories, excluded commands, extra write paths, filesystem disablement, proxy/network allowances, or Unix sockets that could widen execution.

Development

python -m pip install -e '.[test]'
pytest

This project is licensed under the MIT License.

About

Owner-centered development pipeline for Codex, Claude Code, and Cursor

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages