Skip to main content

Engineering Process

An agent-neutral, end-to-end engineering lifecycle. A consumer supplies project policy and commands; this repository supplies the same specification, planning, implementation, verification, independent-review, finding-loop, and completion gates to every project.

The enforcement boundary has three parts:

  1. Portable Agent Skills tell any compatible agent how to perform each phase.
  2. processctl owns lifecycle state, transitions, immutable evidence, and exit codes.
  3. The consumer's AGENTS.md and .process/project.json own domain policy and exact argument-array verification commands.

Publication conventions are distribution-owned as well: manual and automation branch names, Conventional Commit subjects, PR titles, the managed PR-description structure, structured requirement statuses, and draft-versus-ready semantics are validated by processctl publication .... Projects populate those sections with their own contract, impact, risk, evidence, and review details and may append stronger domain checks.

Core semantics never name a model, agent product, orchestration API, or code-indexing provider. An agent host or human workflow supplies an independent reviewer identity; processctl rejects any reviewer actor or context used by the current implementation cycle. If the host cannot attest separation, review remains blocked.

The core ships only the agent-neutral reviewer-attestation contract. Host-specific launchers and model configuration are separate integrations and are never part of a required process bundle.

This repository follows the same lifecycle it distributes. The exact public N-1 release pinned in .process/process.lock governs development of N+1; the checkout under test never supplies its own lifecycle authority. Managed N-1 skills live in .agents/skills, while editable N+1 distribution sources live in process_assets/skills. The bootstrap trust chain and evidence boundary are defined in SELF_HOSTING.md; package, schema, release, and adoption versions are governed by VERSIONING.md.

Python 3.11 or newer and Git are required. Windows command containment requires Windows 10 or Windows Server 2016 and newer so Job Object membership can be attached atomically during process creation. Lifecycle state is stored under ignored .process/runs/; completion, review, and verification are bound to a clean Git checkpoint and workspace fingerprint.

Execution architecture

Consumers use one foreground-task contract on every supported platform. The contract owns argument-array commands, non-interactive standard input, bounded output, timeout, exit status, and descendant cleanup. Platform selection occurs once inside the distribution: the POSIX backend owns a new process session/group and the Windows backend owns a kill-on-close Job Object. Consumer manifests, evidence, and exit codes do not branch by operating system. If an outer Windows Job applies incompatible nesting or UI limits, target creation fails closed instead of running uncontained.

This task boundary intentionally separates finite commands from services and interactive protocols. processctl exec, requirement probes, setup command actions, and verification checks are finite foreground tasks. Detached Docker Compose stacks, log followers, interactive shells, watchers, and stdio servers remain project-owned commands outside this executor until a separate service or interactive lifecycle is specified. They must not be placed in verification profiles or wrapped by processctl exec.

Consumer bootstrap

Add only project-owned configuration:

project/
├── AGENTS.md
├── .github/
│   └── PULL_REQUEST_TEMPLATE.md
├── .gitignore             # includes .process/runs/
└── .process/
    ├── adopt-process.py             # hash-locked adoption runner
    ├── adopt-process-windows-job.py # Windows process containment
    └── project.json                 # profiles and lifecycle baseline

Install processctl from a tagged release and create a candidate manifest from examples/project.json with the repository's real commands. Bootstrap the complete standard in one command:

python -m pip install "engineering-process==0.1.1"
processctl project init --project-root . --manifest project.json \
  --bundle core --bundle delivery --bundle product
processctl doctor --project-root .

project init validates the manifest, preflights ownership conflicts, writes the lock, installs the managed AGENTS.md and pull-request contracts, adds the ignored lifecycle-state path and canonical managed-skill Git attributes, and synchronizes the selected skills and adoption runner. It refuses to replace differing project configuration or unmanaged skills unless the conflict is resolved explicitly. sync --check and doctor detect drift in skills, the managed agent contract, the pull-request block, and the bounded process-owned .agents/.gitattributes file. That file is closer to the managed tree than project-root attributes, canonicalizes LF only for text assets under .agents/skills, and disables inherited working-tree encoding, filter, and ident transforms for those assets. A self-rule applies the same byte-stable policy to .agents/.gitattributes; binary detection remains automatic. Deeper repository attribute files are rejected by existing managed-tree ownership and content checks. External Git overrides that alter a checkout still fail byte-exact distribution attestation. A consumer never authors or maintains process skills locally.

For an existing consumer, a published version is adopted through one Renovate draft. The managed runner installs the target authority from the complete hash lock outside the checkout and atomically updates the process lock and managed assets. If the consumer chooses or requires new project configuration, it adds .process/adoption-migrations/<target-version>.json; the installed target authority binds the source and target manifest digests, validates the complete target manifest, and updates .process/project.json in the same rollback transaction. Optional capabilities are never inferred. CI and a fresh isolated review context approve the fully materialized checkpoint; merge completes adoption and no post-merge sync runs.

The engineering-process producer repository separately owns its root .gitattributes policy so tracked text sources and distribution inputs are LF and byte-stable on every supported checkout. That producer policy is not synchronized into a consumer root; consumers receive only the bounded .agents/.gitattributes asset described above.

The single project-manifest contract includes environment profiles, project-attested read-only requirement probes, remediation, declarative managed-tool artifacts, and optional setup actions. Use the same interface in every consumer:

processctl doctor --project-root . --profile development
processctl setup --project-root . --profile development
processctl setup --project-root . --profile development --apply \
  --allow network --allow user-files --allow project-files
processctl exec --project-root . --profile development -- \
  python scripts/project.py local-dev

A portable tool is data, not a consumer-owned installer. Each project pins the version and one immutable artifact contract per supported platform, then references the tool from a managed-tool setup action:

{
  "managedTools": [{
    "id": "sample-tool",
    "version": "1.2.3",
    "artifacts": [{
      "platform": "linux-glibc-x64",
      "url": "https://publisher.example/sample-tool-1.2.3.tar.gz",
      "checksum": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
      "archiveFormat": "tar.gz",
      "stripComponents": 1,
      "maxDownloadBytes": 50000000,
      "maxExtractedBytes": 200000000,
      "maxFiles": 10000,
      "commands": {"sample-tool": "bin/sample-tool"}
    }]
  }],
  "setupActions": [{
    "id": "install-sample-tool",
    "kind": "managed-tool",
    "tool": "sample-tool",
    "timeoutSeconds": 600
  }]
}

The zero checksum above is a shape example only; a real manifest must contain the publisher artifact's verified digest and declare every supported platform explicitly.

Schema-3 Windows command entries must resolve to native .exe applications. Batch files are rejected because running .cmd or .bat requires a command shell. When a publisher exposes a script launcher, bind the stable logical command to a verified native runtime and a verified contained script instead. For example, a Windows Node artifact can preserve the portable npm command without cmd.exe:

{
  "commands": {
    "npm": {
      "executable": "node.exe",
      "script": "node_modules/npm/bin/npm-cli.js"
    }
  }
}

Managed artifact paths always use contained, relative, forward-slash syntax on every host. Schema-1 and schema-2 project manifests remain readable for lifecycle history, but a schema-2 Windows .cmd or .bat launcher is intentionally not executable by the shell-free supervisor. Migrate that entry manually to schema 3 and bind it to the publisher's trusted native runtime and contained script as above; a generic migrator cannot safely infer either file or attest that the task is foreground-only.

The report still records the logical command such as ["npm", "ci"]; the executor uses the absolute managed application and script paths internally. Unqualified Windows commands are resolved only from absolute PATH entries, so a same-named executable in the project working directory cannot shadow a verified managed tool.

doctor executes only probes explicitly attested readOnly: true and never invokes setup actions. A schema-3 environment contract must also attest foregroundOnly: true for every process-managed task. The project owner remains responsible for those attestations. setup is plan-only unless --apply is present, computes the full dependency-ordered action plan before execution, and refuses to run any action until every declared mutation scope has been approved. Supported scopes are network, project-files, user-files, and host-configuration. Commands are argument arrays executed without a shell, with bounded output, timeout, exit status, owned process-group/job cleanup, and command digest evidence. exec runs an ad-hoc project command only after the selected environment passes and injects paths for verified managed tools. After applying a plan, processctl reruns the original probes; an installer exit code alone never proves readiness.

The distribution owns detection, planning, bounded execution, HTTPS acquisition, size limits, checksum verification, safe archive extraction, atomic user-local tool installation, and exact managed command binding/PATH injection. A consumer owns only declarative environment data: exact probes, tool versions and per-platform artifacts, immutable checksums, project-native dependency commands, dependency edges, and remediation. Project source does not carry a generic downloader, archive installer, doctor, or setup lifecycle. Host prerequisites with no safe automated setup action stay blocking.

Probe readOnly, foreground-only execution, and command-action mutation scopes are project-owner attestations, not an operating-system sandbox: processctl cannot infer arbitrary subprocess side effects. Commands must not daemonize, start a detached session, or leave background work behind. The runner owns a POSIX process group and a Windows Job Object, but no portable POSIX primitive can contain a deliberately detached process. Managed-tool actions are stronger—the distribution constrains them to HTTPS, declared size/checksum/archive/path boundaries and derives their approvals as network plus user-files. Use a command action only for project-native package managers or domain preparation that cannot be represented by the managed-tool primitive, and declare every possible scope truthfully. New consumers use project-manifest schema 4. Schema 1 (without an environment contract), schema 2 (the original environment contract), and schema 3 remain readable for backward compatibility; they are not relabeled as newer shapes. Schema 3 introduced foreground-only task execution and managed script bindings. Portable impact declarations and quality extensions are additive optional schema-3 capabilities; schema 4 adds resource bounds to previously published fields without tightening those historical readers. New integrations receive the complete environment contract instead of creating a project-local doctor or setup lifecycle.

To migrate a live project manifest from schema 3 to 4, keep the same field meanings and first reduce it to at most 64 profiles, 256 checks per profile, 1,024 checks in total, and 256 arguments per check, probe, or command setup action; then change schemaVersion and run processctl contract validate --kind project. Historical schema-3 artifacts do not need rewriting. Plan schema 1 follows the same policy: new plans use schema 2, with at most 256 work/mapping/risk/decision entries and 64 verification profiles per mapping.

Affected-check selection

Schema 3 and schema 4 optionally declare the same portable impact graph. Components own canonical forward-slash glob patterns and list downstream components in affects; profile checks list the components that can invalidate them. The distribution discovers the committed diff from an exact Git merge base and combines staged, unstaged, and untracked paths, then computes the transitive component closure and runs only the selected checks.

{
  "impact": {
    "baseRefs": ["origin/main", "main"],
    "unmatchedPaths": "all-scoped-checks",
    "components": [
      {
        "id": "api-contract",
        "paths": ["openapi.json"],
        "affects": ["frontend"]
      },
      {
        "id": "frontend",
        "paths": ["frontend/**"],
        "affects": []
      }
    ]
  },
  "profiles": {
    "development": [
      {
        "id": "frontend-unit",
        "run": ["node", "node_modules/vitest/vitest.mjs", "run"],
        "timeoutSeconds": 900,
        "components": ["frontend"]
      }
    ]
  }
}

A check without components is deliberately always-run. A manifest without an impact object deliberately runs its complete profile through the same runner; this is suitable for small repositories and is not a legacy execution engine. Any changed path that matches no component selects every component-scoped check, so an incomplete graph fails toward broader verification instead of silently omitting evidence.

Standalone verification tries impact.baseRefs in order or accepts an explicit --base-ref. Lifecycle verification ignores those defaults and binds selection to the registered change contract's immutable comparisonBase. Inspect a plan without probing tools or executing checks:

processctl verify --project-root . --profile development --plan-only
processctl verify --project-root . --profile development --plan-only \
  --base-ref origin/main --json

Evidence records the resolved base and merge-base commits, changed and unmatched paths, direct and transitive components, and a reason for every selected or skipped check. A selected project command can read that exact immutable scope from the JSON file named by ENGINEERING_PROCESS_IMPACT_FILE. This is intended only for bounded domain analyzers, such as selecting affected MSBuild projects; changed-path discovery, component closure, check routing, and evidence remain distribution-owned.

Select capability bundles from bundles.json: every consumer starts with core, then adds only capabilities it actually owns. For example, a web product commonly adds delivery, product, api, frontend, docs, and publication. Add cross-repo only when independently versioned repositories participate in one public-contract change. Re-run project init ... --replace with the intended bundle set when deliberately changing the pin; version remains unchanged during an unpublished development iteration.

During process development, pass --process-root /path/to/engineering-process; consumer manifests never store that local path.

project.json.lifecycle.requiredProfiles is the minimum evidence for every change. Individual change contracts may add profiles but cannot remove the baseline. Every new contract also applies production-v1 to the ten portable quality dimensions. Projects may add declared project-* dimensions but cannot remove or weaken the shared minimum. The same contract governs this repository through its public N-1 self-hosting boundary. Agents enter non-trivial delivery through the synchronized run-change skill; phase skills are internal owners, not a workflow each project must reconnect.

Canonical lifecycle

Create a change contract from examples/change.json and a plan from examples/plan.json. The plan's contractDigest is returned by change start.

processctl change start --contract change.json \
  --actor worker --context worker-session --actor-kind agent

processctl change plan --change-id issue-123 --plan plan.json \
  --actor worker --context worker-session --actor-kind agent

processctl change implement --change-id issue-123 \
  --actor worker --context worker-session --actor-kind agent

processctl change verify --change-id issue-123 --profile development \
  --actor worker --context worker-session --actor-kind agent

processctl change verify --change-id issue-123 --profile review \
  --actor worker --context worker-session --actor-kind agent

After the phase becomes verified, a separate reviewer context registers its assignment:

processctl change review start --change-id issue-123 \
  --actor reviewer --context isolated-review-session --actor-kind agent \
  --method isolated-context --attested-by agent-host \
  --attestation-evidence "Host-created isolated read-only context"

processctl change review submit --change-id issue-123 --report review.json

changes-requested returns to change implement, which starts a new cycle and invalidates prior verification and approval. approved can advance only while the source still matches:

processctl change finish --change-id issue-123 \
  --actor worker --context worker-session --actor-kind agent
processctl change status --change-id issue-123

One worker owning specification, planning, implementation, and verification is the default topology. Bounded helpers are optional optimizations, not required roles; only review requires a separate actor and context.

Open and deferred findings remain completion-blocking until a later review records them as resolved or false-positive with evidence. Schema-1 lifecycle state is loaded through a fail-closed migration that replays immutable review artifacts to reconstruct pending findings before any transition is allowed.

Completion does not imply commit creation, push, merge, release, or deployment. Those remain separately authorized project workflows.

Completed local evidence can be moved across machines or attached to a release as a bounded receipt. Export and validate it before any explicit prune:

processctl evidence export --project-root . --change-id issue-123 \
  --output issue-123-evidence.json
processctl evidence validate issue-123-evidence.json
processctl evidence prune --project-root . --change-id issue-123 \
  --receipt issue-123-evidence.json
processctl evidence prune --project-root . --change-id issue-123 \
  --receipt issue-123-evidence.json --apply

The first prune command is a preview. --apply is accepted only for a completed run whose current state matches the validated external receipt. Active, failed, unexported, mismatched, or tampered evidence remains fail-closed. A partial deletion failure remains under an explicit .pruning-* quarantine and must be recovered from the retained validated receipt; it is never presented again as a complete local run.

Publication contract

Validate common metadata before creating or updating a review object:

processctl publication validate-branch --branch feat/short-description
processctl publication validate-commit --subject "feat(scope): describe the change"
processctl publication validate-range --project-root . \
  --branch feat/short-description --range origin/main..HEAD
processctl publication validate-pr --title "feat(scope): describe the change" \
  --branch feat/short-description --state draft --body-file pr.md
processctl contract validate --kind release release.json
processctl publication validate-release --project-root . \
  --tag v0.2.0 --release-name v0.2.0 \
  --commit <checkpoint> --main-ref origin/main

Manual branches use {type}/{kebab-description}. Automation uses the provider-neutral automation/{owner}/{description} namespace. Commit subjects and PR titles use Conventional Commit syntax and are limited to 72 characters. Draft PRs may retain explicitly pending checklist items; every ready PR, including automation, must satisfy them. The managed template owns the ordered shared sections and immutable standard checklist meaning. An optional extension after its closing marker uses only ## Project-specific requirements plus one-line **Project-specific: Label** checklist items; arbitrary headings, prose, HTML, and code fences are rejected, and reserved core-policy phrases are rejected anywhere in an extension item. These checks prevent structural shadowing; independent review remains responsible for the semantic truth of project-specific evidence. Raw HTML is outside the supported grammar for both managed AGENTS.md contracts and pull-request descriptions; use visible CommonMark instead.

Trust boundary

The CLI proves structural separation: reviewer actor id and context id must both be unused by implementation, every review assignment in the project must use a fresh context id, and the review must match the verified checkpoint. The agent host or human organization owns the truth of the identity attestation. A host adapter should create a read-only isolated context with no inherited implementation or prior-review conversation, pass stable identities to change review start, and preserve its evidence. A stable reviewer actor or role may be reused with a fresh context; merely renaming retained context does not satisfy the process.

change review submit may be invoked by a coordinator transporting the assigned reviewer's exact report. The CLI validates that artifact against the assignment and carried findings; the attesting host or human boundary, not local process state, authenticates who produced it.

Distribution contracts

  • project.json declares baseline profiles and exact argument-array checks.
  • process.lock pins the process version, selected skills, and a digest covering the runtime, canonical exact runtime/build/development dependency locks, schemas, templates, bundle catalog, and complete selected skill resources. Startup fails when installed runtime dependency versions differ from that lock.
  • requirements/process.in owns the direct authority pin. Renovate uses the pip-compile manager to update its complete binary-only hash lock, then the managed .process/adopt-process.py runner rejects symlink, junction, or reparse input in every supplied path component, snapshots one bounded stable copy outside the checkout, binds every path component against concurrent retargeting, and uses that exact digest for installation and processctl adoption apply. POSIX process groups and a managed Windows kill-on-close Job Object contain every child. The resulting draft contains the new lock, managed contracts, skill snapshots, and any target-version consumer-owned project migration; after CI and fresh-context independent review, merge is the end of adoption.
  • Versioned JSON schemas define change, plan, verification, review, lifecycle, completion-related artifacts, release-change fragments, and the release classification contract. The generated Release PR gate binds that contract to the exact SemVer increment, package version, latest reachable prior tag, reviewed head, identical merge tree, immutable checkpoint, and main ancestry.
  • Remote matrix jobs publish one bounded supplemental-verification schema-1 bundle per platform/runtime. Its manifest binds the exact source and workflow checkpoints, automation actor/context, run URL, platform/runtime identity, selected impact, configured timeouts, output byte counts/digests, truncation state, and the hashes of its schema-2 profile reports. GitHub's artifact id and digest complete the immutable remote reference; this supplements rather than replaces N-1 lifecycle evidence.
  • New lifecycle work uses bounded plan schema 2. Selective-impact consumers may add the optional capability on project schema 3, while new integrations use bounded project schema 4. Plan schema 1 and the pre-existing fields of project schemas 1-3 retain their published validation behavior instead of being tightened in place.
  • release.json is the single release-identity owner. Governed GitHub tag and title are both exactly v<SemVer>; package metadata, runtime version, artifact names, authorization evidence, and later consumer locks must match it. Public-impact PRs add bounded release-changes/<id>.json fragments; automation aggregates them into one reviewed Release PR and never writes a chosen version directly to protected main. Recorded bootstrap history transitions once through a separately typed bootstrap-authority bundle, then all later releases require a public N-1 lifecycle receipt.
  • VERSIONING.md owns package-versus-schema classification and the explicit Renovate-assisted adoption boundary. processctl publication prepare-release derives and materializes the only permitted next package version from the complete fragment set.
  • Project commands run without a shell and inherit the caller environment. Never put secrets in manifests, arguments, or reports.
  • Consumer skill roots are distribution-owned: unmanaged SKILL.md files or catalog files fail sync and doctor. Project-specific policy belongs in AGENTS.md, product contracts, source, and the manifest's command bindings.
  • Host-specific launchers, agent role files, and model settings are optional external integrations. They are neither bundled into the core nor required in consumer repositories.
  • The managed pull-request template and publication validators are shared process policy. Consumer repositories may append project-specific requirements after the managed block but do not copy or redefine the common convention.

Development

python -m venv .venv
.venv/bin/python -m pip install -e '.[dev]'
.venv/bin/python -m unittest discover -s tests -p 'test_*.py'
.venv/bin/python processctl.py skills validate --root process_assets/skills
.venv/bin/python processctl.py digest

Version 0.x remains a compatibility pilot. A 1.0 release requires publishing the CLI, running consumer CI through the published artifact, and completing forward tests on representative agent hosts. Portable evaluation fixtures live in evals/cases.json. Automated Release PR authorization, repository controls, recovery rules, and the secretless PyPI publisher identity are defined in RELEASING.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

engineering_process-0.2.0.tar.gz (249.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

engineering_process-0.2.0-py3-none-any.whl (215.2 kB view details)

Uploaded Python 3

File details

Details for the file engineering_process-0.2.0.tar.gz.

File metadata

  • Download URL: engineering_process-0.2.0.tar.gz
  • Upload date:
  • Size: 249.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for engineering_process-0.2.0.tar.gz
Algorithm Hash digest
SHA256 92d9b01b2dff77a854ea2fe1c393538effba2e28b5c1c86c3f8bcda82df7d267
MD5 de6c87aecaf807a71436dddeae29f264
BLAKE2b-256 f5b7f43a01043fd42927958c26ac8fac0368d3ab5ce96afb2c75455703bac1ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for engineering_process-0.2.0.tar.gz:

Publisher: publish.yml on phuongnse/engineering-process

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file engineering_process-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for engineering_process-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 200589a56b977e552c3969c2aa0227d536fb1c92a3b877327af697d3fa3db7b3
MD5 2b95034ab25e6197f543f9361b110614
BLAKE2b-256 892abf30a463938d9b6dc683169ceedae2b506cce69fb20c184348c02373b8d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for engineering_process-0.2.0-py3-none-any.whl:

Publisher: publish.yml on phuongnse/engineering-process

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.6.1

2 files

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page