{"slug": "show-hn-l0-l1-l2-agents-leases-gates-audits-git-worktree-isolation", "title": "Show HN: L0/L1/L2 agents, leases, gates, audits, Git-worktree isolation", "summary": "Singular, a bash and Python orchestration engine, introduces a three-tier scheduling model (L0 origin loop, L1 area planners, L2 worker agents) with durable leases, state packets, gate/audit pipelines, and git-worktree isolation to drive autonomous AI coding agents in parallel against software repositories. The engine, installed once per machine and pinned per consumer repo, runs a reconcile cycle that imports task proposals, recovers stale leases, integrates completed branches, dispatches workers, and snapshots state, with detached dispatch enabled by default to minimize lock hold times.", "body_md": "## TcGUeulhd4hM0DvB5ytcng-under10.mp4\n\n**Autonomous multi-agent orchestration for software repos. One engine, many consumers.**\n\nsingular is a bash + Python orchestration engine that drives autonomous AI coding agents in parallel against a repository. It implements a three-tier scheduling model (L0 origin loop → L1 area planners → L2 worker agents) with durable leases, state packets, gate/audit pipelines, and git-worktree isolation. The engine is installed once per machine and pinned per consumer repo — improvements propagate by bumping a version pin, not by re-copying scripts.\n\n| Tier | Role |\n|---|---|\nL0 origin |\nThe single scheduler. Runs the reconcile cycle: import → recover → integrate → dispatch → snapshot. Holds the origin lock only during control work. |\nL1 area planners |\nOne planner per DAG node (area). Reads the node's context, plans a batch of L2 tasks, and stages them as proposals for L0 to import. |\nL2 workers |\nExecute a single task in an isolated git worktree on a per-task branch. Produce a state packet (owned files, changes, evidence). An auditor reviews the packet; the decider routes the outcome. |\n\nEach `singular reconcile --actuate`\n\nruns:\n\n**Import**— pull staged L1 task proposals into the DAG under the origin lock.** Recover**— reclaim stale leases whose workers have exited or timed out.** Integrate**— merge completed worker branches into the target branch under the git-op lock.** Dispatch**— pre-lease frontier tasks and spawn L2 workers.** Snapshot**— write a human-readable project state snapshot.\n\nEvery in-flight task holds a **lease** (a JSON file in `.singular-state/leases/`\n\n) that records\nownership, retry count, and expiry. When a worker finishes it writes a **state packet**\n(`state-packet.v0.schema.json`\n\n) enumerating owned files, changed files, commands, tests, and\nevidence. The auditor validates the packet; the reaper attributes outcomes on later cycles.\n\nAfter each L2 worker run the host executes the configured **gate command** (e.g. `npm test`\n\n).\nA gate result (`gate-result.v0.schema.json`\n\n) feeds the **auditor** model, which returns an\naudit verdict (`audit-verdict.v0.schema.json`\n\n). The **decider** maps the\n`(failure-class, retries-left)`\n\npair to a recovery action — retry, amend-scope, escalate, or\npark — using a deterministic fast-path table before falling back to a model round-trip.\n\nA bare command works: exit 0 passes, non-zero fails. The exit code cannot answer\ntwo questions the engine would use if it could, so a gate may optionally write a\n**gate observation** (`gate-observation.v0.schema.json`\n\n) to the path in\n`SINGULAR_GATE_REPORT_FILE`\n\n:\n\n`failures[].signature`\n\n— stable per-failure identifiers. Required for`singular gate baseline`\n\nto tell an acknowledged failure from a new one.`infrastructureFailure`\n\n/`infrastructureReason`\n\n— the gate could not**run**(missing dependencies, full disk, unreachable network). The engine reports that as`inconclusive-infrastructure`\n\ninstead of spending a task's retry budget asking a model to fix code that was never broken.\n\n`singular init`\n\nscaffolds `docs/orchestration/gates/gate.sh`\n\nas a starting point.\nThe sidecar is never required — including on `schemaVersion: v2`\n\n. Without one\nthe engine falls back to the exit code plus a deliberately narrow set of log\nsignatures (`engine/infra-patterns.tsv`\n\n) covering only environment failures that\napplication code cannot plausibly produce.\n\n**Detached dispatch is ON by default.** When `SINGULAR_DETACHED_DISPATCH=1`\n\n(the default),\n`reconcile`\n\npre-leases each frontier task and spawns the worker in its own session via\n`dispatch-wrap.sh`\n\n, then returns within seconds. The origin lock is held only for the cycle's\ncontrol work. A **reaper** (`singular_reap_dispatches`\n\n) runs at the top of every\napply/actuate cycle and attributes completions, failures, and crashes by checking dispatch\nrecords + worker exit files (pid liveness defeats pid reuse; crash detection drops from the\n60-min stale-lease window to ~one cycle).\n\nThis is what keeps import, integrate, recover, STATUS, and STOP responsive while long workers run in the background.\n\nSet `SINGULAR_DETACHED_DISPATCH=0`\n\nto restore the legacy synchronous batch path, where\n`reconcile`\n\nwaits for every worker before returning.\n\nPrerequisites:\n\n- Bash >= 4,\n`python3`\n\n, and`git`\n\n. - At least one supported runner CLI on\n`PATH`\n\n(`claude`\n\n,`codex`\n\n, or another configured runner). - macOS users may need\n`brew install bash`\n\n. Set`SINGULAR_BASH_BIN=/opt/homebrew/bin/bash`\n\nin the shell/service environment to select it without reordering`PATH`\n\n. - When multiple Codex installations exist, set\n`SINGULAR_CODEX_BIN=/absolute/path/to/codex`\n\n. Doctor and the runner use that exact executable and do not fall back when it is broken.\n\n```\n# Clone and install the engine to ~/.singular\ngit clone https://github.com/alex-reysa/singular-lite /path/to/singular-lite\ncd /path/to/singular-lite\nbash install.sh\n# -> ~/.singular/versions/<ver>/  ~/.singular/current  ~/.singular/bin/singular\n\nexport PATH=\"$HOME/.singular/bin:$PATH\"\n```\n\nSingular's launch namespace is intentionally clean: `SINGULAR_*`\n\n,\n`singular.config.json`\n\n, `.singular-version`\n\n, `.singular-state/`\n\n, and the\n`SINGULAR_HOME`\n\ninstall root (default `~/.singular`\n\n). It does not discover or\nimport the pre-launch namespace replaced by this release. Start each consumer\nwith `singular setup`\n\nand author a fresh DAG.\n\nIn each consumer repo:\n\n```\nsingular setup     # one idempotent path from \"a repo\" to a verified, STOPPED repo\n```\n\n`singular setup`\n\ncomposes the individual lifecycle verbs and contributes the\norder, the evidence, and the contract. It checks interpreter/repo/git work tree,\nresolves the engine pin (naming the winner when `.singular-version`\n\nand\n`singular.config.json`\n\n`engineVersion`\n\ndisagree), installs the pinned engine when\nit is absent — only from a matching engine checkout already on this machine,\nsince there is no download mechanism — writes `.singular-state/STOP`\n\nas its first\nrepo write, pins and scaffolds, hashes every gate result before printing and\nrunning the migration chain, verifies those historical verdicts survived, runs\ndoctor, and records a supervised regression run. Prerequisites fail before\nanything is mutated. It reports a state ladder\n(`installed → migrated → validated → stopped-ready`\n\n), never actuates, and prints\nexactly one `Next:`\n\nline. Failures carry a stable code and one recovery\ninstruction (`singular.operator-failure.v0`\n\n); evidence lands under\n`.singular-state/setup/`\n\n.\n\n```\nsingular setup --no-test      # stop at `validated`, without the regression run\nsingular setup --test-async   # start the suite detached; attach with singular test --wait\nsingular setup --json         # one singular.setup-report.v0 object on stdout\n```\n\nThe composed steps are still available on their own:\n\n```\nsingular init      # scaffold singular.config.json, docs/orchestration/, .singular-version\nsingular doctor    # check deps, engine resolution, repo config\nsingular migrate   # raise schemaVersion to the engine's (--dry-run prints the chain only)\n```\n\n`SINGULAR_BASH_BIN`\n\nis bootstrap-only and is ignored in `singular.config.json`\n\n;\nset it before invoking `singular`\n\n. `SINGULAR_CODEX_BIN`\n\nmay be supplied through\nthe normal engine environment/config layers. For the standard Codex runner,\n`singular doctor`\n\nperforms bounded `--version`\n\nand `login status`\n\nprobes against\nthe exact selected executable.\n\nDoctor is also the machine-readable preflight for unattended runs:\n\n```\nsingular doctor --json | jq '.summary, .checks[] | select(.status != \"pass\")'\nsingular doctor --repair-model-cache  # explicit: backup first, then regenerate later\n```\n\nEvery JSON check has a stable `id`\n\n, `severity`\n\n, `requiredFor`\n\n, `remediation`\n\n,\nand `dedupeKey`\n\n. Required capability failures block doctor; a missing optional\ncapability produces one warning even when several roles share it. Doctor checks\ndeployment credentials only while a deployment-capable DAG node is actually in\nthe ready frontier. It never silently deletes or rewrites Codex model cache\ndata: the repair flag moves the original to a timestamped, SHA-tagged backup.\n\nRole profiles are local-only by default. Repositories that need extra tools, MCP servers, or plugins can declare lazy profiles explicitly:\n\n```\n{\n  \"capabilityProfiles\": {\n    \"audit-core\": {\n      \"startup\": \"lazy\",\n      \"required\": [\"filesystem\", \"git\", \"schemas\", \"runner-contract\"],\n      \"optional\": [\"mcp:browser\"]\n    }\n  },\n  \"roleProfiles\": {\n    \"auditor\": \"audit-core\",\n    \"decider\": \"audit-core\"\n  }\n}\n```\n\nCapability IDs may use `mcp:NAME`\n\n, `plugin:NAME`\n\n, `executable:NAME`\n\n, or\n`file:REPO_PATH`\n\n. More specialized capabilities can be declared in the\ntop-level `capabilities`\n\nregistry with a `type`\n\nof `builtin`\n\n, `executable`\n\n,\n`file`\n\n, `mcp`\n\n, `plugin`\n\n, or `environment`\n\n.\nIn strict profiles, external skills, MCP servers, and plugins are activated\nonly by `capabilityArgs.<exact-capability>`\n\n; unrelated `providerArgs`\n\nnever\nclaim a capability. Legacy `SINGULAR_*_EXTRA_ARGS`\n\nvariables are rejected for\nstrict runs because they are not capability-bound.\n\nEach repo pins its engine version in `.singular-version`\n\n(overrides `singular.config.json`\n\n`engineVersion`\n\n). The `singular`\n\nlauncher resolves that version from `~/.singular/versions/<ver>`\n\n,\nbinds `SINGULAR_ROOT`\n\nto the current repo, loads its config, and execs the engine. Run\n`singular update <ver>`\n\nto repin.\n\n```\n# Run one reconcile/actuate cycle (import → recover → integrate → dispatch → snapshot)\nsingular reconcile --actuate\n\n# Drive a single task through L1 → L2 → audit\nsingular drive TASK-0001\n\n# Self-driving autonomy loop (wall-clock budget: SINGULAR_MAX_HOURS)\nsingular auto\n\n# Create, approve, or inspect an owner- and artifact-hash-bound human gate\nsingular human-gate request --help\nsingular human-gate approve --help\nsingular human-gate status --help\n\n# Report every contract violation in a gate-result at once. The frontier read\n# stops at the first breach (correctly — it must not act on an invalid gate),\n# which means a promoter under development learns about one violation per run.\nsingular gate validate docs/orchestration/gates/<node>.gate-result.json\n\n# The old promote-gate --operator route is schema-v2 legacy compatibility only\n\n# Block until all detached workers finish (useful in CI or clean shutdown)\nsingular reconcile --drain\n\n# Context graph (behind SINGULAR_CTX_GRAPH): project the event log into\n# context-graph.v0 JSONL, sync incrementally, and query it\nsingular graph rebuild\nsingular graph sync\nsingular graph query neighbors <node-id>\n\n# Experiment tooling (behind SINGULAR_CTX_EXPERIMENT): per-arm metrics,\n# treatment-vs-control delta, and rendered report tables\nsingular experiment-report summary\nsingular experiment-report delta\nsingular experiment-report tables\n```\n\nAll per-repo variation lives in the consumer repo, never in engine files:\n\n— declarative:`singular.config.json`\n\n`targetBranch`\n\n,`gateCommand`\n\n,`runner`\n\n,`areas{}`\n\n,`areaPrefix`\n\n,`prewarm`\n\n,`worktreeCopyPaths[]`\n\n,`modules[]`\n\n,`identity{}`\n\n,`env{}`\n\n,`provisionFiles[]`\n\n,`envAllowlist[]`\n\n,`capabilityProfiles{}`\n\n,`roleProfiles{}`\n\n,`evidence{}`\n\n,`bootstrap{}`\n\n,`resources{}`\n\n,`promoter`\n\n,`controlState{}`\n\n, and`legacyCompatibility{}`\n\n.\n\n** promoter is the one most consumers need and miss.** It names the script that\ndecides when a DAG node's gate may be promoted — a bare name resolves to\n\n`<engine>/singular-ext/<name>.sh`\n\n, a path is used as-is (repo-relative);\n`SINGULAR_PROMOTER`\n\noverrides it. The shipped default promotes only nodes in its\nown built-in registry, so a repo with its own DAG matches nothing and stalls\nafter layer 0, reporting only `promotion: no promotable frontier gates`\n\n— the\nsame line a merely not-yet-ready frontier prints. `singular doctor`\n\nnow names this\ndirectly (`graph.promotability`\n\n). `tools/promote-gate.sh`\n\nis a worked example.\nNote that evaluation nodes are governed separately, by `authority`\n\non the node:\nabsent or `operator`\n\nmeans manual promotion, `agent-review-allowed`\n\nlets a valid\n`gate-review.v0`\n\nrecord promote them.— optional shell extras (computed values, functions).`singular.config.sh`\n\n— gitignored operator overrides and secrets.`.singular-state/config.local.sh`\n\nThe starter config deliberately sets `gateCommand`\n\nto `false`\n\nso a newly\nscaffolded repo fails closed until you replace it with the command that proves\nthe repo is healthy.\n\n`worktreeCopyPaths[]`\n\nnames dependency trees to copy into every fresh worktree —\nthe worker's, the auditor's disposable one, and the deterministic acceptance\none. All three are prepared by the same code path, so a gate that passes for the\nworker is running in the same environment when the auditor re-runs it. Copies\nare copy-on-write where the filesystem supports it (macOS clonefile, GNU\nreflink), falling back to a plain recursive copy. `node_modules`\n\nis always\nincluded; the listed paths are **added** to it, so a monorepo declares only its\nnested trees:\n\n```\n\"worktreeCopyPaths\": [\"apps/web/node_modules\", \"packages/ui/node_modules\"]\n```\n\nA declared path that does not exist in the source worktree is reported and\nrecorded as a `worktree.copy_path_absent`\n\nevent rather than skipped silently.\n\nThe v2 starter profile is local-only and lazy: each runner role requires the\nfilesystem, Git, schema bundle, runner contract, and selected provider\nexecutable, while external skills, MCP servers, and plugins must be opted into\nexplicitly. Evidence composition defaults to 256 KiB, excerpts to 2 KiB,\ncumulative raw retrieval to 256 KiB, and the audit input canary to 100,000\ntokens. Worktree scheduling reserves 2 GiB, estimates 256 MiB per worktree,\nand caps the starter at three workers. Semantic control snapshots default to a\n300-second interval; set `controlState.commitIntervalSeconds`\n\nto `0`\n\nonly for\nlegacy every-cycle snapshots.\n\n`bootstrap.commands`\n\nis an ordered list of `{command, required, lockfiles}`\n\nrecords. Every declared lockfile must exist and be tracked before any command\nruns; an optional command may warn and continue, while a required failure\nblocks the worktree. The singular `bootstrap.command`\n\nfield remains a legacy\nshorthand. Shared-store links must stay under declared roots and target\ngitignored, untracked paths.\n\nSchema v2 rejects the historical, artifact-unbound `accept-waiver`\n\nand\n`promote-gate --operator --evidence`\n\npaths by default. Prefer a `human-gate`\n\nrequest and exact-hash approval. An operator may temporarily restore the old\nbehavior only by explicitly setting\n`legacyCompatibility.unboundWaivers`\n\nto `true`\n\n.\n\n`provisionFiles`\n\nentries copy repo-local, gitignored files into each worker\nworktree after `git worktree add`\n\n: `{ \"source\": \".env.local\", \"target\": \".env.local\", \"required\": true }`\n\n. The source and target must both be ignored\nor provisioning fails closed. `envAllowlist`\n\naccepts exact env names or prefix\npatterns ending in `*`\n\n; allowed values are written to\n`worktree/.singular-state/worktree-env.sh`\n\nand sourced for prewarm/gate phases.\n\n| Env knob | Default | Effect |\n|---|---|---|\n`SINGULAR_MAX_CONCURRENT` |\n`3` |\nMaximum L2 workers running concurrently (an upper bound — adaptive disk scheduling may lower it, and zero effective slots enters low-disk mode). |\n`SINGULAR_MAX_DISPATCH` |\n`5` |\nMaximum tasks dispatched per reconcile cycle. |\n`SINGULAR_DETACHED_DISPATCH` |\n`1` |\nDefault ON. Reconcile spawns workers in their own session and returns in seconds; the reaper attributes outcomes on later cycles. Set `0` for the legacy synchronous batch wait. |\n`SINGULAR_AUTO_INTEGRATE` |\n`1` |\nAutomatically integrate (merge) completed worker branches in direct `reconcile --actuate` , `singular auto` , launchd, and console-driven cycles. |\n`SINGULAR_PUSH` |\n`0` direct / `1` auto |\nPush integrated branches to the remote. Direct engine commands default local-only; `singular auto` /launchd set `1` unless overridden. |\n`SINGULAR_MAX_HOURS` |\n`12` |\nWall-clock budget for the autonomy loop (`singular auto` ). |\n`SINGULAR_MAX_RETRIES` |\n`3` |\nPer-task worker retries before the decider escalates. |\n`SINGULAR_STALE_MINUTES` |\n`60` |\nLease age (minutes) before a task without a live dispatch pid is reclaimed by the reaper. |\n`SINGULAR_PLANNER_BACKOFF_SECONDS` |\n`900` |\nWait after an ordinary planner failure before planning is attempted again. |\n`SINGULAR_PLANNER_QUOTA_BACKOFF_SECONDS` |\n`1800` |\nWait after a usage limit (429) or entitlement denial (403) — a window the account has to sit out. The loop sleeps through it without incrementing the circuit breaker. |\n`SINGULAR_PLANNER_OVERLOAD_BACKOFF_SECONDS` |\n`180` |\nWait after a provider 503/529. Overload is the provider shedding load, not a usage limit, and typically clears in seconds. It gets the same no-breaker sleep-through as quota but an order of magnitude shorter — before it had its own class one 529 bought the 1800s quota window, and because the nap skips the reconcile cycle entirely it idled the whole graph. |\n`SINGULAR_OVERLOAD_WAIT_BUDGET` |\n`3600` |\nTotal overload sleep-through before the loop writes STOP. Deliberately separate from `SINGULAR_QUOTA_WAIT_BUDGET` so a burst of 529s cannot spend the usage-limit allowance and stop the loop for a reason that was never a usage limit. |\n`SINGULAR_TARGET_BRANCH` |\n(required) |\nIntegration target branch in the consumer repo. |\n`SINGULAR_SESSION_AFFINITY` |\n`1` |\nReuse a role's prior runtime session when all staleness gates pass; `0` always runs fresh. |\n`SINGULAR_FIX_PROMPT_STRUCTURED` |\n`1` |\nStructured fix prompt on retries (authoritative findings); `0` = legacy `fix_hints` tail. |\n`SINGULAR_DECIDER_FAST` |\n`1` |\nResolve clear-cut failure classes by host policy table; `0` routes every failure through the model decider. |\n`SINGULAR_WORKER_INFRA_MAX` |\n`1` |\nExtra worker re-runs on an infra failure before surfacing `worker-infra` . |\n`SINGULAR_AUDIT_INFRA_MAX` |\n`2` |\nExtra auditor re-runs on an infra failure before surfacing `audit-infra` . |\n`SINGULAR_GATE_TIMEOUT_SEC` |\n`3600` |\nWall-clock bound on the consumer's gate command; the whole process tree is killed on expiry and the result is `inconclusive-infrastructure` , never a product failure. `0` disables. Before this existed a hung gate held a worker slot indefinitely and made cooperative STOP never fire. |\n`SINGULAR_KILL_GRACE_SEC` |\n`10` |\nSeconds a timed-out runner gets to run its EXIT trap — where the read-only restore guard lives — before the tree is SIGKILLed. |\n`SINGULAR_READONLY_GUARD_MODE` |\n`restore` |\n`restore` puts the working tree back after a read-only run; `report` logs what it would do and changes nothing; `off` disarms it. |\n`SINGULAR_READONLY_GUARD_KEEP_DAYS` |\n`30` |\nHow long `singular gc` keeps guard journals, which hold quarantined content, before removing them. |\n`SINGULAR_CONTEXT_SECTION_MAX_CHARS` |\n`4000` |\nPer-section cap on continuity content appended to prompts. |\n`SINGULAR_PREFLIGHT_REQUIRE_ACCEPTANCE` |\n`1` |\nPreflight requires non-empty `acceptanceCriteria` on a task. |\n\nRaw engine defaults stay `0`\n\n(OFF-parity is test-pinned); the **recommended\nproduction values** below follow the per-knob decisions in\n`docs/context-build-plan/experiment-report.md`\n\nand ship in this repo's own\ndock config. Raw-default flips land in 0.5 with a test-migration slice.\n\n| Env knob | Raw default | Recommended | Effect |\n|---|---|---|---|\n`SINGULAR_PLANNER_SESSION` |\n`0` |\n`1` |\nPer-node planner session persistence + resume behind fail-closed lineage/template/lease gates. |\n`SINGULAR_PLAN_CRITIQUE` |\n`0` |\n`1` |\nFresh read-only skeptic critic over staged planner batches before L0 import. |\n`SINGULAR_PLAN_REVISE_MAX` |\n`0` |\n`2` |\nBounded revise→re-critique loop for `revise` verdicts. |\n`SINGULAR_CTX_PACKET` |\n`0` |\n`1` |\nPlanner context packets (decisions/assumptions/rejected alternatives) flow into worker, fix, and audit prompts; per-run assumption ledger. |\n`SINGULAR_CTX_ROUTING` |\n`0` |\n`1` |\nExplicit 5-strategy routing (`continue/resume/fork/fresh/rehydrate` ) with reason codes, window-pressure + diff-volume gates, and structural taint on resumed sessions. |\n`SINGULAR_CTX_ARTIFACT_SCAN` |\n`0` |\n`1` |\nSecret scan over durable artifacts; hits quarantine (`.quarantined` ) and drop out of all prompt assembly. |\n`SINGULAR_PAIRED_AUDIT_PCT` |\n`0` |\n`25` |\nSampled post-acceptance paired fresh audits (bias measurement + independence spine). |\n`SINGULAR_REHYDRATE` |\n`0` |\nopt-in | Inject deterministic durable-artifact packets on refused-resume lineage steps. |\n`SINGULAR_CTX_MANIFEST` |\n`0` |\nopt-in | Authored-knowledge manifest ingestion into rehydration packets (`contextManifest` config field; fixture contract). |\n`SINGULAR_CTX_GRAPH` |\n`0` |\nopt-in | Context-graph projector/sync/query + subgraph-selected rehydration. |\n`SINGULAR_CTX_EXPERIMENT` |\n`0` |\nopt-in | Experiment aggregators, delta, renderers, and `singular experiment-report` . |\n`SINGULAR_CTX_ARMSTATE` |\n`0` |\nopt-in | Per-run knob-state provenance recording for arm-integrity audits. |\n\nKey context event types (all in `.singular-state/events.ndjson`\n\n, countable via\n`singular metrics`\n\n): `context.strategy_selected`\n\n, `context.resume_failed`\n\n,\n`ctx.arm_assigned`\n\n, `ctx.paired_audit`\n\n, `ctx.critic_recheck`\n\n,\n`ctx.artifact_secret`\n\n, `ctx.packet_malformed`\n\n, `plan.critiqued`\n\n,\n`plan.revised`\n\n, `plan.revise_parked`\n\n, `planner.backoff_active`\n\n.\n\nBetween retry attempts singular carries authoritative state forward rather than re-deriving it from a log tail:\n\n**Context capsules**— hash-stamped`implementer-capsule.json`\n\nand`reviewer-capsule.json`\n\nper attempt.**Findings ledger**—`findings-status.json`\n\nupserted from each audit verdict, with stable finding ids tracked open/resolved across retries.**Structured fix prompts**— the worker receives authoritative open findings on retry (set`SINGULAR_FIX_PROMPT_STRUCTURED=0`\n\nto revert to the legacy byte-tail).**Re-audit delta prompts**— the auditor receives prior findings + fix diff + per-id verification targets.** Attempt archive**— each attempt's artifacts are copied (never moved) under`runs/<id>/attempts/<n>/`\n\nwith an`attempts/index.json`\n\n.\n\nRole-keyed runtime session resume (`codex exec resume`\n\n, `claude -r`\n\n) behind ordered\nfail-closed staleness gates, for three roles:\n\n**Implementer/reviewer**(within one drive): defaulting ON (`SINGULAR_SESSION_AFFINITY=1`\n\n); any gate failure or runner refusal degrades silently to a fresh run within the same attempt.**Planner**(across planning runs, per DAG node): behind`SINGULAR_PLANNER_SESSION`\n\n— persisted per-node session meta, node-lineage and template-sha gates, session leases against concurrent resume, rc-86 fresh fallback. A planner session can decompose a multi-slice node across consecutive resumes.**Plan critic**(re-critique of a revised batch): the skeptic may be offered its own prior session — never an advocate's.\n\nEvery routing decision is reason-coded as a `context.strategy_selected`\n\nevent\n(`strategy`\n\n+ the exact gate reason) and countable via `singular metrics`\n\n.\n\nInvariant (evidence invariance):routing never changes what counts as evidence. Gates, red/green proofs, scope checks, and the fresh implementation auditor are identical under every strategy —`fresh`\n\nor`resume`\n\n. Outcomes MAY improve with continuity (that is the point), and the improvement is measured, not assumed: per-strategy outcomes flow into the attempts index and`singular metrics`\n\n.\n\nAdvocate/skeptic line:a session never crosses between advocate roles (planner, implementer) and skeptic roles (plan critic, auditor), in either direction. Per-role session-meta files make violations structural, not merely checked. Resumed or rehydrated sessions never satisfy an independence-required step.\n\nBehind `SINGULAR_PLAN_CRITIQUE`\n\n(default OFF; flip only with the revision loop in\nservice): staged planner batches are reviewed by a fresh, read-only plan critic\non the default runner before L0 import. Verdicts follow `plan-critique.v0`\n\n:\n`approve`\n\n→ import; `revise`\n\n→ the node's planner session is resumed with the\ncritic's structured findings (bounded by `SINGULAR_PLAN_REVISE_MAX`\n\n), records\nper-finding dispositions (accepted/rejected-observation; silent drops are\nrecorded as unaddressed), and re-enters the critic; `park`\n\n/ budget exhaustion →\ncandidates never reach import (fail closed). Critic infrastructure failure fails\nOPEN with an event — the critic is an added safety layer; the un-bypassable\nimplementation auditor remains the floor.\n\nIn schema v2, a successful revision is published as an immutable generation\nunder the node staging directory. One atomically replaced\n`.candidate-current.json`\n\nmanifest selects the authoritative generation, and\nall engine readers pin that generation before enumerating files. Direct\n`TASK-*.candidate.md`\n\nfiles are a legacy pre-migration read fallback only; new\nrevision batches are never published through sequential direct-file moves.\n\nThe generic `engine/`\n\nreferences **zero** project-specific symbols — enforced by\n`tests/test-engine-clean.sh`\n\n(the abstraction gate test). All per-project logic lives in\nopt-in modules:\n\n```\nsingular-ext/\n  storage-proof.sh    # example: durable-proof regime\n  promote-gate.sh     # example: gate promoter\n```\n\nModules are listed in `singular.config.json`\n\n→ `modules[]`\n\n. A repo that doesn't list them\nnever loads them. The `SINGULAR_MODULES`\n\nenv var is the runtime list (set by the JSON\nconfig loader).\n\nTwo versions move independently:\n\n**Engine pin**—`.singular-version`\n\nis the canonical per-repo pin (overrides`singular.config.json`\n\n`engineVersion`\n\n; if they disagree`.singular-version`\n\nwins and`singular doctor`\n\nwarns).`singular update <ver>`\n\nrewrites it.**Schema**—`SCHEMA_VERSION`\n\n(repo root) holds the data-contract version (`v2`\n\ntoday). A repo records the schema it was scaffolded against in`singular.config.json`\n\n→`schemaVersion`\n\n.`singular doctor`\n\nfails on a schema mismatch;`singular migrate`\n\nruns the shipped`migrations/<from>-to-<to>.sh`\n\nchain and rewrites`schemaVersion`\n\n. Runtime JSON schema identifiers follow the namespace`singular.orchestration.*.vN`\n\n. v2 keeps reading existing v0 records while writing the structured audit and gate v1 contracts.\n\n```\nbash tests/run.sh    # full regression suite (190+ tests)\nsingular test         # the same suite as a supervised, attachable run\nbash tests/field-report-canary.sh  # required before promoting 0.11.2, 0.12.0, or 0.13.0\n```\n\n`singular test`\n\nruns the resolved engine's own `tests/run.sh`\n\nas a supervised job\nand keeps the evidence in the current repo under\n`.singular-state/test-runs/<runId>/`\n\n(`singular.test-run.v0`\n\nmanifest, `suite.log`\n\n,\nper-test logs, `progress.jsonl`\n\n), so a result outlives the session that started\nit. A detached supervisor holds an exclusive `flock`\n\nfor its whole life:\nliveness is proved by the kernel rather than guessed from a pid, and `ps`\n\nis\nnever consulted. A second invocation attaches to the live run instead of\nstarting a duplicate — `--new-run`\n\nis the explicit override — and a supervisor\nkilled mid-run reconciles to `interrupted`\n\nwith the counts it reached (and ends\nthe run's process group, so an orphaned suite cannot keep writing into it).\n\n**The resolved engine must be a checkout.** Most tests build disposable Git\nworktrees of `HEAD`\n\n, so `tests/run.sh`\n\nopens with a source preflight that needs\nreal history — and an installed version (`~/.singular/versions/<ver>/`\n\n) is a plain\ncopy that ships no `tests/`\n\nat all. `singular test`\n\nrefuses up front there, with\n`SINGULAR_TEST_SUITE_UNAVAILABLE`\n\nor `SINGULAR_TEST_SOURCE_UNSUPPORTED`\n\nand before\nany run directory exists. To record a run for a consumer repo, point the CLI at a\ncheckout from inside that repo — evidence still lands in the repo you are in:\n\n```\nSINGULAR_ENGINE_HOME=/path/to/engine-checkout singular test\n```\n\n`--status`\n\nand `--wait`\n\nare exempt: reporting on a past run needs no suite.\n\n```\nsingular test --status [--json]  # report on the current run\nsingular test --wait             # attach to the live (or last recorded) run\nsingular test --no-wait          # start detached; the run id goes to stdout\nsingular test --rerun-failures   # re-run only the last completed run's failures\n```\n\nThe test suite uses no live state — all fixtures use a generic layer vocabulary. The\n`tests/test-engine-clean.sh`\n\ngate enforces the abstraction contract on `engine/`\n\n.\nThe promotion canary is also non-destructive: it validates the captured 26-node\nlocalization graph and composes the ten field-report regression scenarios from\ntheir focused hermetic tests. It stays outside `tests/run.sh`\n\nto avoid running\nthose same scenarios twice in an ordinary development pass.\n\nRun `bash tests/run.sh`\n\nbefore opening a PR. Keep `engine/`\n\ngeneric: project-specific\nrules belong in opt-in modules under `singular-ext/`\n\nor in a consumer repo's config.\nDo not commit `.singular-state/`\n\n, `.worktrees/`\n\n, `.singular-evidence/`\n\n, local env\nfiles, or generated run artifacts.\n\nsingular executes repo-configured shell commands and launches local coding\nagents in git worktrees. Review `singular.config.json`\n\n, `singular.config.sh`\n\n, and\ntask files before running it in an untrusted repo. Report vulnerabilities through\nGitHub's private vulnerability reporting for this repository; if that is\nunavailable, open a minimal public issue asking for a private channel and do not\ninclude exploit details.\n\nLicensed under GPL-3.0 — see [LICENSE](/alex-reysa/singular-lite/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-l0-l1-l2-agents-leases-gates-audits-git-worktree-isolation", "canonical_source": "https://github.com/alex-reysa/singular-lite", "published_at": "2026-08-27 22:56:17+00:00", "updated_at": "2026-08-27 23:18:59.030144+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "mlops"], "entities": ["Singular"], "alternates": {"html": "https://wpnews.pro/news/show-hn-l0-l1-l2-agents-leases-gates-audits-git-worktree-isolation", "markdown": "https://wpnews.pro/news/show-hn-l0-l1-l2-agents-leases-gates-audits-git-worktree-isolation.md", "text": "https://wpnews.pro/news/show-hn-l0-l1-l2-agents-leases-gates-audits-git-worktree-isolation.txt", "jsonld": "https://wpnews.pro/news/show-hn-l0-l1-l2-agents-leases-gates-audits-git-worktree-isolation.jsonld"}}