Architecture
Empirical 0.29 is a TypeScript library, Node.js CLI, stdio MCP server, one explicit global Init skill, and a repository-local automatic workflow over one Schema 5 model.
Boundaries
protocol.tsdefines strict shared schemas, canonical JSON, digests, authorizations, impacts, receipts, and completion derivation.operations.tsis the single frozen registry for MCP names, internal verbs, summaries, workflows, modes, and the single skill.core.tsowns workflow transitions, exact revisions, phase gates, routing, receipt use, and orchestration.storage.tsowns safe paths, atomic projections, locks, journal recovery, and Schema-5 invariants.journal.tsowns hash chains, snapshot verification, transactional compaction, and interrupted-compaction recovery.migration.tsperforms the one supported atomic Schema 4 → 5 transform.runtime.tsexecutes exact argument arrays without a shell and captures bounded output.review.tsowns reviewer readiness, exact committed/remote diff packets, canonical criterion-complete results, reviewer credential scoping/redaction, and aggregate/latest GitHub approval reduction.evidence.tscreates and verifies executed and collected receipts.qa.tsderives risk/capability/surface verification matrices and creates or validates bounded QA attempts, retries, platform provenance, and exact full-CI promotion receipts.specialists.tsowns the frozen specialist registry, derives required consults from risk floor and criterion surfaces, and parses advisories. Consults are derived rather than persisted, bounded to a context slice narrower than the phase packet, and advisory unless a blocking verdict carries a critical or high finding inside the specialist's own domain.coordination.tsowns Git-common-dir identity, capability claims, base replay, candidate validation, projection rollback, and integration receipts.delivery.tsowns protected draft GitHub source/evidence PR review and merge convergence plus explicit publication planning.release.tsowns the repository release candidate, structural changelog and migration validation, immutable observation/plan model, and monotonic retry reports.release-runtime.tssupplies strict Git, GitHub, npm, pack, and PR adapters;scripts/release.tsis the workflow and offline-dry-run entrypoint.tracking.tsowns the unconfigured/disabled/configured setup state, provider discovery/preview and semantic mapping, optional Tracker Policy v1/v2, strict change-type/profile ticket rules, ensure/manual/off binding, target-bound feature bindings, per-effect durable pending operations, safe receipt artifacts, and GitHub, Linear, and Jira adapters.knowledge.tsowns Manifest v2 fingerprints and fresh-by-default retrieval.doctor.tsperforms read-only cross-subsystem diagnostics, including exact repository activation artifact states, nested discovery blockers, and global skill collisions. It never equates current files with proof that a host session loaded them.cli.ts,mcp.ts, andintegrations.tsare registry-backed adapters, not alternate workflow implementations. Integrations install a setup-only globalempirical-init, marker-owned repository dispatchers and local workflow skills, and project MCP bridges. Global uninstall reuses integration containment and ownership checks, thenlifecycle.tsremoves the npm package last through an exact shell-free argv.
Legacy discovery, decision, agent handoff, selector, setup, and worktree modules remain focused owners of those boundaries.
Ownership model
Git common directory
└── capability claims shared by all linked checkouts
repository checkout
├── Schema-5 config + Policy v2 + Manifest v2
├── marker-owned automatic workflow dispatchers and local skills
├── optional disabled setup record or secret-free Tracker Policy v1/v2
├── living capability projections
├── discovery records
└── selected feature
├── spec + design + decisions + plan + impact + deltas
├── optional tracker binding + durable transition/comment/artifact ledger
├── immutable evidence/integration/delivery receipts
└── state projection + hash journal + terminal snapshot
Checkout selection lives in the checkout's absolute Git directory. Claims live under the common directory. This separation prevents two linked worktrees from selecting each other's workflow state while still serializing changes to the same living capability.
Transition integrity
A workflow transition acquires an ownership-aware feature lock, verifies the exact revision and immutable artifacts, prepares any rollback-capable effect, appends a linked event, writes the state projection atomically, and releases only its own lock. Terminal paths compact the chain to a verified snapshot and boundary. Stale-lock recovery checks age, process liveness, inode/device identity, and ownership token.
Migration stages, markers, and backups use reserved top-level names. Before a marker exists, candidate transform/validation failure removes the exact owned stage. After a marker exists, recovery alone controls stage/backup promotion. Knowledge, evidence hashing, and source overlays exclude these transaction trees; Doctor reports unmarked survivors without deleting them.
Integration adds a second transaction boundary. It verifies Git repository
identity, replays deltas from captured bases, temporarily projects candidates
into a different worktree, overlays committed feature changes since the merge
base plus bounded working changes, detects independent target divergence, runs
every exact Policy command there, restores the
target, then promotes source capability projections with rollback and records a
receipt. The feature is not integrated until that receipt and state transition
both succeed.
External tracking is a separate one-way projection boundary. Every workflow transition commits its local journal and state projection first. A later tracker sync resumes durable pending work or snapshots that committed revision into a checksummed pending record. A pure resolver combines the existing request change classifier with the persisted workflow profile. Required work validates a request reference, performs complete stable-marker reconciliation, and creates only on one proven zero-match path; optional unreferenced work and off work branch before authentication. It then converges provider state, append-only milestone comments, and receipt-approved evidence through individually acknowledged deterministic effects before advancing the binding. Policy v2 Linear updates never include description content. Binding target drift, incomplete pagination, marker ambiguity, or unsafe evidence fails closed; provider failure cannot roll back, demote, or block the local state machine.
Tracker Policy v2 can explicitly change that last availability choice for
required work with enforcement: strict. The provider still has no inbound
state authority: a pure gate is derived from locally configured policy,
deterministic ticket requirement, validated binding, current/acknowledged
revision, and durable pending effects. The same gate drives action packets and
core mutation guards. Initial identity state remains local-first for exact
idempotency; every later revision closes the gate until sync. Terminal journals
can be synchronized by exact feature id, and Begin performs a bounded local
preflight so a crash cannot hide an unresolved strict final projection.
The preflight uses a sticky secret-free per-feature obligation marker, so
enabling strict later does not retroactively gate historical best-effort work.
Authentication remains outside that durable projection. A trusted host OAuth resolver provides an ephemeral typed credential and, when needed, a validated secret-free URL handoff. MCP uses the handoff only for explicitly negotiated URL-mode elicitation. Resolution then falls back atomically to injected host environment values and a guarded per-user secrets file; none of those values enter policy, workflow state, tool results, or chat. Jira's typed request context keeps OAuth Bearer/cloud API traffic distinct from tenant-origin Basic fallback traffic across every adapter path.
Delivery and publication
Delivery requires Policy v2, repository-bound authorization, a verified integration, an exact target branch, and declared checks. It converges a draft source PR, returns an exact remote review packet, accepts only a canonical current-head bot or fresh-context result, makes an approved head ready, and merges it without admin or force. It then creates a source-merge binding and repeats the draft/review gate for the evidence PR. Request changes keep the PR draft and route at most two repair rounds before a human is required. Both merge commits and command receipts are digested in the delivery receipt.
Publication is intentionally outside the workflow's inferred path. A caller must explicitly provide an exact package, semantic version, dist-tag, merged commit, literal approval, and an authorization bound to that exact request. Empirical independently inspects and then re-inspects remote Git, GitHub, and npm state. Conflicting tags, releases, versions, or dist-tags stop instead of being replaced.
Repository release automation preserves that invariant with a different,
explicit authorization source. Ordinary source/evidence delivery targets
develop. A read-only Release Gate runs on the exact GitHub merge candidate for
the sole develop to main release PR and validates branch provenance,
versions, packed contents, changelog/migration structure, remote state, clean
CI, and a clean tracked tree. An unchanged exact protected merge with no
effective CHANGES_REQUESTED review then supplies narrow authorization for that
PR number, merge commit, derived version/tag/notes, package integrity, and
latest; it does not alter the generic Empirical publish operation or make
arbitrary main pushes publishable.
The ordinary authorizer exhaustively paginates GitHub's review history and reduces each reviewer's latest decisive state. Failed pagination, malformed records, duplicate identities, or an effective change request fail before immutable effects; comments cannot clear a prior change request.
An administrator-only emergency branch remains disabled unless an exact
repository Actions variable is enabled and the protected npm environment has
admitted the workflow run. It adds an explicit incident audit boundary: a
short-lived canonical receipt binds actor, open incident, PR, protected
two-parent merge, version, integrity, required checks, justification, and nonce.
The adapter proves those live facts, denies CHANGES_REQUESTED and historical
v0.29.0, and writes pre/post audit comments. Closed-PR events and ordinary
dispatches cannot select this branch implicitly.
The existing trusted-publisher identity, .github/workflows/publish.yml, owns
the complete remote sequence so it does not depend on a GitHub Release created
with GITHUB_TOKEN recursively starting a second workflow. Its jobs recompute
the same candidate at the exact commit and split permissions:
merged release PR / exact manual retry
├── ordinary authorize (protected merge + contents/PR read + clean CI)
└── explicit emergency authorize (npm environment + policy + admin/incident/check receipt)
└── exact authorization selector (no permissions)
└── GitHub prefix (contents write, no OIDC)
├── annotated v<version> tag
└── non-draft Release with exact changelog body
└── npm preflight (read-only, complete clean CI, no OIDC)
└── authorized-SRI tarball publish (minimal read + OIDC)
└── provenance verification (read-only, no OIDC)
└── emergency incident outcome audit (issues write only)
Remote state is the retry journal. The deterministic planner accepts only
absent-all, exact tag, exact tag-plus-Release, or fully converged states. Every
effect is re-observed after a success or error, so a lost response becomes an
existing exact prefix rather than a duplicate request. Gaps, conflicts,
malformed observations, missing provenance, or divergent latest stop without
delete, edit, force, replacement, or token-based repair. Manual dispatch names
only the original PR and merge SHA; all release identity is re-derived.
Knowledge and diagnostics
Manifest v2 records normalized source fingerprints and generated-page source
sets. Retrieval returns only fresh, semantically refined pages. Managed or exact
legacy placeholder topics in a nonempty repository are reported through
refinementRequired and withheld from usable context. After source-changing
Implement work, the state machine conditionally inserts Context: the host agent
refreshes inventory, refines topics from inspected evidence, removes managed
markers, and refreshes again before Verify or Done. Doctor reports stale,
missing, invalid, and refinement-required knowledge without mutation. For a
completed Schema 5 setup it also reports missing, drifted, or unsafe project
integrations; explicit Init performs the ownership-aware repair and Doctor then
verifies readiness.
Package surface
The supported exports are the main library, ./protocol, ./mcp, and
./integrations. The build emits Node-compatible ESM and declarations. CI
tests supported Node lines 22, 24, and 26 and enforces distribution, consumer,
registry-consistency, aggregate coverage, and per-module coverage gates.
The public lifecycle CLI exposes Install, Update, and Uninstall. Uninstall owns
only catalog-derived global skill paths, valid owner-stamped selection metadata,
and the global package. Repository discovery and project .empirical or MCP
mutation are outside that command's authority.
The installed global skill is empirical-init, which is explicit-only where a
host supports invocation policy metadata and narrowly setup-scoped everywhere
else. Initialization writes the detailed empirical workflow into project
skill directories and short dispatchers into supported repository instruction
files. Those dispatchers activate only for change requests when Schema 5 config
is valid and setup is complete; read-only requests and uninitialized
repositories stay outside the state machine.