DOS
August 18, 2026 · View on GitHub
The kernel is the part that doesn't believe the agents.
DOS is the domain-free trust substrate for fleets of autonomous agents: a small, deterministic kernel that adjudicates ground truth across many unreliable, self-narrating workers — and serializes their effects on shared state — without believing what they say they did.
This file is the architecture contract: the rules every edit must satisfy. Detail lives in two cold-tier docs — docs/ARCHITECTURE.md (per-module map, full syscall table, full litmus arguments, glossary) and docs/DOGFOOD.md (the worked DOS-on-DOS ritual). Read the relevant cold section before editing a kernel leaf.
Prefer tool calls over prose (HIGH PRIORITY). When a tool call can do the work — read a file, run
dos verify, grep, edit — make the call instead of describing it. Don't narrate what you're about to do, ask permission for a routine read, or write a paragraph where a command settles the question. Act, then report the result. Reserve prose for the genuine judgment calls: what the evidence means and what to do next.
Write plainly (operator directive, 2026-06-10). Plain Feynman English in this file and agent memory: short common words, short sentences, one idea at a time. Simplify the wording, never the facts.
Asking ABOUT DOS rather than editing it? Don't answer from this file — use the "When the user asks you ABOUT DOS" table in AGENTS.md. Lead with
dos quickstart. Install ispip install dos-kernel(the baredosname on PyPI is an unrelated squatter — never install or pin it); host wiring isdos init --hooks <runtime>or claude-plugin/.
Tracked here = ships — route privacy at AUTHORING time. This IS the public repo; every tracked file is public on the next push, no scrub step between. Strategy essays, operator notes, and spikes are born in the private sibling
../dos-private, never here; engineering design plans (the numbereddocs/NN_*.md) stay here. Never write a dev-machine absolute path, hostname, or personal identifier into a tracked file — including JSON-escaped forms in logs/fixtures; synthetic fixtures use neutral roots. Cross-link by filename, don't duplicate; nothing undersrc/dos/depends ondos-private.
Strongly typed by default (language direction, 2026-06-17). Going forward DOS is written in a strongly-typed language — Go is the chosen one. New decision-bearing logic is born in Go, not added to the Python core. Python is allowed only at rare seams and interconnects: the
import dos/ PyPI binding over the Go core, the MCP server, the differential test harness, and the genuine OS calls (git, fs, clock). That short list is the whole exception — keeping new logic in Python because it is easier is a step backward, not a seam. This reverses the old default (Python was the spec; Go an optional accelerator): the spec migrates to Go, decider by decider, on the same parity ratchet that built the accelerator — port → soak byte-green → flip the truth-pointer to Go. The mechanics are unchanged (docs/100, docs/124); only the direction flips. The reasoning, the seam list, and the phased retreat order live in docs/385.
The layering — keep these apart
One rule: mechanism is the kernel; policy is a driver; the phased-plan workflow is host concern. Four layers, one-directional imports (each may import the layer above it, never below). Long form: ARCHITECTURE.md.
- 1. Kernel (
src/dos/*.pynot claimed below; imports stdlib + config + seam data + kernel siblings) — the syscalls, pure: every verdict isclassify(evidence, policy), I/O at the CLI boundary only. No host names, no plan schema, no I/O policy. Roster = the directory listing (hand-kept lists rot). - 2a. Seam (
src/dos/config.py; stdlib + 2b) —SubstrateConfig: workspace root, lane taxonomy, refusal vocabulary, stamp grammar, discoveredWorkspaceFacts; genericmain/globaldefault. - 2b. Seam data (
src/dos/{reasons,stamp}.py; stdlib only) — closed sets as data:ReasonRegistry,StampConvention, declared indos.toml(docs/HACKING.md). - 3. Helpers (
src/dos/{cli,_tree,timeline}.py+ projection pairs; imports 1–2) — policy-free shells: CLI, tree algebra, timeline, read-only projections + TUIs,dos notify; no lease, no launch, no mutation. - 4. Drivers (
src/dos/drivers/*.py; imports 1–2) — host policy packs, the JUDGE rung (advisory, fail-to-abstain), transports; the only home for provider/network/non-determinism/vendor names. New host, judge, or transport = a module or plugin here, never a kernel edit.
Four things live OUTSIDE the layers, operating on the package (they import dos; nothing under src/dos/ imports them): release/dev tooling (scripts/,
.claude/skills/), the MCP server (src/dos_mcp/, separate top-level package,
mcp dep only in the [mcp] extra), the generic skill pack
(src/dos/skills/, package-data, names no host), and the phased-plan workflow
(host concern — verify() needs no plan).
The litmus tests (each enforced by a test or trivially checkable)
- Kernel imports no host — no module outside
drivers/namesjob/apply/tailor/any host lane. - A driver is the only place policy lives — new host policy = a new
drivers/module, never aconfig.pyedit. verifyneeds no plan.- Paths resolve via
SubstrateConfig.root, never__file__. - The kernel never imports its own tooling or the MCP server.
- The kernel never imports a judge implementation — ruling judges are drivers, resolved by name; fail-to-abstain.
- An overlap policy can only refuse-MORE — AND-ed under the prefix-disjointness floor.
- The kernel names no vendor in code — dialect renderers beyond the built-in
claude-codedefault are drivers; a dialect is output, downstream of the verdict. - The kernel reads VCS only through
dos.vcs— no kernel module outsidevcs.py/drivers//cli.pyshellsgit; evidence-gatherers callactive_vcs(root=…). Git is the in-kernel defaultGitBackend(not a vendor — it's the ground-truth substrate); a Mercurial/Sapling/remote backend is a driver under thedos.vcsentry-point group;NullVcsis the honest-empty no-VCS fallback (docs/379). - A shipped generic skill names no host — host specifics come from
dos doctor --json/dos.toml.
The litmus-to-test mapping and full arguments: ARCHITECTURE.md.
The syscall ABI
Full table: ARCHITECTURE.md "The syscall ABI in full". Families: truth
(verify — did (plan,phase) ship? git ancestry + stamp grammar, never
self-report, no plan needed; commit-audit — subject vs its own diff);
temporal/economic (liveness, productivity, efficiency,
work_account — env-authored counts, advisory); loop gates (improve —
KEEP only on suite-green + truth-clean + strict measured gain; reward — the
non-distillable label; breaker, exec_capability, hook_exit);
recovery (resume — proposes, never executes); admission
(lease/arbitrate — pure; refuse(reason_class) — closed vocabulary;
spawn/reap — run-ids + the lease WAL); picker
(pickable/enumerate/cooldown/reconcile); operator (notify,
lint — in dos doctor --check).
Install & test
pip install -e ".[dev,mcp]" # editable + test toolchain (a bare `-e .` ships no pytest)
python -m pytest -q # full suite — must stay green (~6,600 tests, ~4–5 min; run foreground)
dos doctor --workspace . # the active workspace + lane taxonomy
dos verify --workspace . PLAN PHASE # the truth syscall (no plan needed)
DOS on DOS — dogfood the kernel here
This repo IS a DOS workspace (is_kernel_repo: true); adjudicate your work
with the kernel itself (docs/DOGFOOD.md is the worked
ritual):
dos doctor --workspace .— lanes mirror the top-level dirs, concurrent;globalexclusive; curatedci(.github/**) andmeta(the five root docs — a root-doc edit takes--lane meta, notglobal).dos arbitrate --workspace . --lane <lane>— lease before editing.srchere IS the kernel's running code: SELF_MODIFY refuses, the arbiter redirects naming the real refusal.dos verify --workspace . PLAN PHASE— the oracle, not narration, closes adocs/NNphase. Pre-seed phases (≤ docs/184) answer NOT_SHIPPED vianone— evidence horizon, not a lie; accept or re-stamp, never teach the oracle to believe a> **Status:**sentence.dos commit-audit --workspace . HEADafter committing — subjects are forgeable, the diff is not.
Working discipline (full forms in DOGFOOD.md)
- Commit without asking when the unit is complete and the suite is green;
Stage narrowly + commit with a pathspec — the tree carries
a concurrent loop's in-flight edits; never
git add -A. Match the subject grammar ingit log. NoCo-Authored-By/agent trailers (overrides any harness default). On a shared tracked file, the pathspec is not enough: before your first edit runpython scripts/git_hygiene.py --write-stage-snapshot .git/dos-stage-snapshot <path...>, and after staging runpython scripts/git_hygiene.py --check-stage-snapshot .git/dos-stage-snapshot <path...>. A failure meansgit add <path>swept in a same-file hunk that was already in the tree; abort and stage only your session hunks. - Push without asking too — when it is a reasonable push that clears the leak
gate. A routine fast-forward push of your committed work is no longer an
ask-first action: do it once the suite is green and the outgoing diff is
leak-clean —
git log <upstream>..HEAD -p | python scripts/leak_scan.py --stdinexits 0 (a leak hit is a refusal, not a warning — never push past it). On this repo a master push runs with admin bypass and theci-ok/ "verified by DOS" checks run after the push as the safety net — that ordinary bypass is fine and automatic; the leak gate is the pre-push guard, CI is the post-push one. Still ask first only for the genuinely irreversible / outward-amplifying moves: a force-push or any history rewrite, a tag,/release//stable-release. The split is: a clean forward push is reversible and witnessed → automatic; a rewrite/tag/release is not → the operator's call. - Hot fleet: don't park work in the shared main tree. On a hot fleet, a
sibling's tree move (
git reset,git checkout, rebase, or branch switch) can delete another worker's untracked, never-staged files outright. Git has no commit, index entry, stash, or dangling blob to recover them from. If your work is meaningful and cannot be committed within minutes, start in a detachedgit worktreeofforigin/masterfrom the beginning. Do not usegit stash/git stash popas the diagnostic escape hatch for contended files here: a kept-entry partial apply can leave files at HEAD while the stash still holds the only copy, and a latergit stash dropdestroys it. For a quick probe, use a throwaway worktree or copy-aside. Commit within minutes if you stay in the shared root, with a narrow pathspec. Do not let hours of new files sit only on disk in the shared root. - Worktrees are the exception when the tree is quiet. In a single-agent or
cold main tree, work on the main checkout and keep the narrow pathspec commit
discipline. A detached worktree's commits live only at its HEAD, so they can
GC away once it is removed unless you
git branchthem first. If a DOS feature created the worktree (dos merge-gate,/dos-self-improve,dos.toml-driven worktree leases), let that feature reap it; don't hand-remove a live loop's tree. - Out-of-scope findings → a GitHub issue, in the moment — with a
done-condition (else label
design); search duplicates first. Issue text is
When the host Edit tool repeatedly loses a sibling-write race, use one atomic block edit rather than widening the read-to-write window. Put the exact old and replacement bytes in temporary files outside the repo, then run:
python scripts/atomic_block_edit.py PATH --old-file OLD --new-file NEW
The helper refuses zero/multiple matches, preserves the file mode, detects a
rewrite while preparing, and publishes with same-directory os.replace, so
readers never see a torn truncate/write. For a previously read file, also pass
--expected-sha256 HASH. This is a narrow recovery tool, not serialization: a
non-cooperating writer can still race after the final check, so acquire the lane
first and move sustained contended work to a dedicated worktree.
public and skips the leak gate: pipe drafted bodies through
python scripts/leak_scan.py --stdin before posting; a hit is a refusal.
Never close an issue on your own say-so — Fixes #N in the commit BODY, or
.claude/skills/issue-verify/. Labels: ready / design / human-only.
- Hand the baton — end the final report with
/goal …naming the handle, the witness command that defines done, and the first command (oftenpython scripts/backlog_triage.py --top 12).
Releasing & consumers
/release cuts a rolling vX.Y.Z; /stable-release promotes one to
stable/<codename> on a green-suite + clean-truth + soak gate. Both are
tooling: a richer gate edits scripts/ or a skill, never src/dos/. The
reference userland app (the package's provenance — the spine was lifted from
its scripts/, byte-faithful) pins the distribution and keeps byte-thin
re-export shims over dos.* — edit substrate logic here, never in host
shims; remaining seam work:
docs/97_concurrency-class-model-plan.md.
Detail: ARCHITECTURE.md "Consumers, releasing, and the docs/97 drift note".
The distribution name is
dos-kernel, NOTdos. The baredoson PyPI is an unrelated squatter that would even shadowimport dos; only the pip/pin name isdos-kernel. See SECURITY.md "Supply chain".