Why Polydeukes?
Polydeukes is a development discipline framework for people working with an AI coding partner, or applying the same practices to their own commits. It makes selected promises explicit, judges the evidence a connected surface can observe, and records what happened. Its purpose is to reduce the supervision needed to verify work, not to claim that every action is visible or every generated change is correct.
The problem is unverifiable completion
Section titled “The problem is unverifiable completion”An agent saying “done, tests pass” is not the same as evidence that the relevant tests ran. A prompt can describe a good practice, but the instruction alone does not show whether it was followed. A useful development system must distinguish a passing check, a detected violation, a check that could not run, and work that never entered its observation boundary.
This distinction came from developing Polydeukes itself. A file edit could be refused while a script produced the same contents outside the observed tool path. A supposedly safe test probe could miss routing entirely. An overly broad path comparison could reject legitimate operations. These were different defects, not interchangeable examples of a successful block.
The response is to make narrower, testable claims: which path was observed, what evidence was available, which comparison ran, and which result was recorded. More blocking is not necessarily better verification.
What exists now
Section titled “What exists now”The project provides the Rust pdks judge, two separate host adapters, a memory extension, and TypeScript, Rust, and Python SDKs. Two observation surfaces serve different purposes:
- The session surface judges one call before it runs — an input IR on stdin. Claude Code and Codex have installers, and a program reaches the same surface through the TypeScript, Rust, or Python SDK; what history and witness each host can prove differs. An adapter uses stable host events to assemble that evidence rather than treating an undocumented transcript format as a contract.
- The change-set surface judges a unified diff read from stdin — a staged diff piped by a pre-commit hook, or any diff a tool produces. It works without an AI agent. A project may connect either or both surfaces according to its needs.
A discipline is written in one of three config lists, and the list follows from what its declaration
reads. disciplines holds what both surfaces can judge — declarations reading only the changed
file. sessionDisciplines holds what only a live call carries — the command line, the conversation
history, the actor. changeSetDisciplines holds what only a finished change set carries. The loader
refuses an entry written in a list whose surface cannot observe its channels, so the config file
itself says where each discipline stands, and pdks explain prints the same placement per surface.
A discipline is configuration data with extraction steps and relations. Seven relations and seventeen mechanisms form the vocabulary. Mechanisms constrain declaration shape; surfaces determine available evidence. Added-only tolerates existing matches, while pairing compares selected key sets.
See how judgment works, write disciplines, and the configuration reference.
pdks memory invokes the separate pdks-memory executable, computing sections and links from current
Markdown. Documents are the record and changes appear on the next query. Unresolved links do not
prevent reading; pdks memory lint reports them with exit 1. Query history is a separate local log.
See the memory walkthrough.
Principles and their limits
Section titled “Principles and their limits”Shared covenants
Section titled “Shared covenants”A covenant is a promise the developer accepts too, not a restriction imposed only on an AI. Configured protection applies to the observed action, regardless of who initiated it. It does not prevent every possible edit outside connected surfaces. Protecting the discovered config file is a built-in behavior; protecting other source files depends on the configured paths.
A human witness can allow a blocking judgment without rewriting the policy. In a supported session,
the token must stand alone on the first line of a human message and remain within its TTL. The
change-set surface has no prompt: the valve is the session surface’s TTL witness, and the change-set
surface only emits an exit code that the user’s hook consumes. The valve is consulted after judgment
and does not repair a broken assembly. An SDK call is judged as a call with no person in it: the
SDK’s IR verb passes --unattended, so caller-supplied session.userMessages text never reaches a
declaration as a user message — it opens no witness valve, and a discipline using the userTexts
step records skipped. The SDK’s caller is a program, the judge cannot distinguish SDK input from
adapter input, and only an adapter can distinguish a human message from other text.
Deterministic judgment, explicit enforcement
Section titled “Deterministic judgment, explicit enforcement”The judge evaluates supplied data without opening files or making network requests. Reproducing a verdict requires the same declaration and supplied evidence, not merely the same path name. The two surfaces need not produce the same result when their observations differ.
An ordinary discipline defaults to advise. Promotion to block is the author’s decision after
exercising both valid and violating cases. A surface’s level and an entry’s level compose with the
lenient side winning. Assembly errors remain failures; telemetry write failures do not change a
verdict. A declaration that cannot compile makes the whole configuration invalid, because an entry
that loads but can never judge reads as installed while it protects nothing. Missing evidence
follows the declared supply policy rather than an invented empty source.
One call leaves one row, and one component writes it. An agent adapter translates a host’s payload into the judge’s input and hands it over; it decides nothing and records nothing. That holds on the failure path too: when an adapter cannot build the input, it sends the reason to the judge instead of recording the failure itself, so the writer never changes with the outcome.
A shared layer structure does not imply identical evidence. The three language SDKs call the executable and return values for the same four operations. The two host adapters own event translation, registration, and responses; the common runtime invokes the judge through the same executable. Execution and failure handling are shared while each host supplies only what it can prove. An unknown prompt origin is not promoted to a human message to make capabilities match.
When the judge cannot start, every host refuses the file-changing or shell call about to run, and nothing else stops. A missed judgment would let a protected write through with no row to show it, so that call is refused; a refused prompt or session end would lock a session that cannot be repaired from inside, so those events go on.
Evidence with a stated boundary
Section titled “Evidence with a stated boundary”passed, blocked, witnessed, advised, and skipped describe judgment outcomes.
unattributed records a baseline finding, not a verdict. An empty observation, a skipped
registration, or a successful command exit is not proof that the whole project meets its promises.
Arbitrary child-process writes are not individually observed as session tool calls. Baseline comparison can reveal unexplained protected changes afterward, but cannot reconstruct the missing judgment. Logs and baseline files are local state; a Git clone does not transfer the history. Instructions read by an agent are also not proof that a host invokes the installed hook.
What the measurements say
Section titled “What the measurements say”These are historical observations from this repository, not a benchmark of other projects or a measurement of the current release.
| Period | Recorded observations |
|---|---|
| First self-use ticket | 133 rows: 75 passes, 2 blocks, 56 valve openings. |
| v0.1 milestone | 1,020 verdicts across three tickets: 455 passes, 13 blocks, 552 valve openings. The milestone audit also found five path-matching escapes to repair. |
| Five rounds before the advisory-default decision | No measured case of a real-time block preventing a bad edit; 93% of human valve openings concerned repairs to the judging chain. These are findings within those rounds, not proof that blocking is always useless. |
| Through 2026-08-26, five weeks | 7,446 rows: 6,438 passed, 686 skipped, 173 blocked, 88 advised, 47 unattributed, 14 witnessed. |
| v0.5.0 advisory round | 73 of 735 advised rows, or 9.9%, had a later pass on the same target in the same session. One read-first discipline reached 77%; another reached 0% across 292 rows. |
| v0.5.0 blocking observations | 88% of 162 blocks protected the judging chain; no false-block reports were filed. An assembly failure refused and recorded eight calls in 71 seconds. |
The advisory denominator counts calls, not independent decisions. An ignored advisory may recur. A later pass is the measurement’s operational definition of consumption, not proof that advice caused improvement. No false-block reports is not proof that no false blocks occurred.
There is also selection bias: an agent may reshape a call before submitting it to avoid a predicted
refusal. In the project’s interpretation, passed is an upper bound on compliance and blocked a
lower bound on intended violations. Neither count measures unsubmitted actions. The earlier
aspiration of “90-plus” predictability is a design goal, not an achieved rate.
The measurements motivated advice by default, a time-limited witness, and more explicit observation records. They do not establish that the current delivery of advice is sufficient. In the recorded host probe, stderr advice did not reach the model; the generated skill therefore asks the agent to read telemetry at task boundaries. Host behavior must be checked rather than assumed.
Decisions the measurements forced
Section titled “Decisions the measurements forced”Five incidents changed a mechanism rather than a number. They are listed here because the current design is hard to explain without them.
- A banned word that edits respected and a shell heredoc did not. The tool axis refused an edit carrying a banned word. The same content inside a heredoc reached the repository without a row, because the call never reached judgment. The shell axis gained heredoc-aware analysis and write detection for redirects.
- A token that opened the valve from the middle of a sentence. The witness token was matched anywhere in a human message, so asking when the witness would expire extended the window. The rule became first line, alone.
- A request accepted as evidence. The first
precedentjudgment counted a call that had merely been issued, soecho "npm view yaml"satisfied it more cheaply than running the check. Evidence now means a call that ran and reported success. - One file protected through its ancestors. Protecting a single path by ancestry made the whole
home directory protected;
cdinto it was refused for two weeks before anyone noticed. That path is now judged by full-path equality, and anything above the project root is out of scope. - Two hosts that agreed, and a third that did not. Routing a call to the covenants that might judge it read the tool’s arguments, while the judgment itself read the proven file change. Two hosts name their target in both places, so the disagreement stayed invisible until a third arrived whose edits carry a patch text and no path argument: its calls were routed nowhere and recorded as passed. Routing now reads the proven change as well. Passing on two hosts said they spell a path twice, not that the layer beneath them was right.
What remains a plan
Section titled “What remains a plan”A verifiable ledger and adversarial verification are roadmap components, not shipped services. Of local memory, search and show over the project’s documents, the links between them, the obligations carried over to a key, and the chain of replaced records ship. Telemetry is not the future ledger, documentation search is not a memory system, and running a test suite is not an implemented adversarial review service.
Polydeukes is not an agent runtime or a sandbox. It complements linters and tests: some declarations compare file contents, others require observed process evidence. It does not execute a fresh benchmark during judgment or prove that a natural-language explanation is true.
The name’s story is in STORY.md. To try the implemented system, follow the first-judgment tutorial. For current limits and recovery, see troubleshooting. The project’s claims should be read with those limits, not as a promise of complete supervision-free development.
Observing shell commands and file contents
Section titled “Observing shell commands and file contents”Protected-path mentions in shell commands are judged conservatively even when the command looks read-only: a shell string and a direct file tool provide different evidence. When a shell write cannot supply file contents, content disciplines record a skipped observation. Judge the finished diff on the change-set surface to inspect its content. Connecting both surfaces lets a project check the process and the resulting changes at their respective observation boundaries.