{"slug": "poly-a-human-readable-programming-language-for-coding-agents", "title": "Poly – A human readable programming language for Coding Agents", "summary": "The Poly project published draft v0.6 of its specification, a human-readable programming language and runtime for stateful software written by coding agents, after five reviews; no code exists yet. Poly programs are sets of declared state machines with contracts, invariants, effects and obligations that a compiler checks exhaustively over declared finite domains before execution, with every construct lowering to artifacts read by existing Poly stack engines such as SAM v2, polygraph, Polyaxion and polyflow. In the specification's turnstile example, `poly check` reports a PL3201 DEADLOCK finding over coins in 0..3 and 7 states because a full coin box locks the gate forever, and in an order example it reports a PL4001 PATH_PROPERTY violation showing two Pay calls emit two payment.charge effects.", "body_md": "**A programming language and runtime for the stateful core of software written by coding agents.**\n\nA poly program is a set of declared state machines. Each machine carries its contract, its invariants, its effects and the obligations that govern it. The compiler checks the program exhaustively over declared finite domains before it may run. The runtime executes the same program durably, gates every effect, and writes a ledger that replays exactly.\n\npoly adds no new checking, simulation or governance engine. It is a compiler, a toolchain and one runtime integration over the Poly stack. Every construct lowers to an artefact an existing engine already reads:\n\n| Stage | Engines | \n|---|---|\n| Model and check | SAM v2, polygraph, polyrun, polyvers, polynv | \n| Govern | Polyaxion, polycheck | \n| Workflows | polyflow, polycrew | \n| Learn | Polyx, polyness | \n| Simulate (v2) | Polytrion | \n\nStatus: specification, draft v0.6 (after five reviews). No code yet.\n\nA turnstile. Put a coin in, it unlocks; push it, it locks.\n\n```\nmodule hello\n\ntype Mode = Locked | Unlocked\n\nmachine Gate {\n  state {\n    mode  : Mode = Locked\n    coins : 0..3 = 0\n  }\n  action Coin()\n  action Push()\n\n  on Coin {\n    require coins < 3 else reject \"coin-box-full\"\n    coins' = coins + 1\n    mode' = Unlocked\n  }\n  on Push {\n    require mode is Unlocked else reject \"locked\"\n    mode' = Locked\n  }\n\n  invariant locked-when-empty: coins == 0 implies mode is Locked\n}\nbash\n$ poly check hello.poly\nhello.poly:5  PL3201 DEADLOCK  Gate\n  no action is accepted in a reachable non-terminal state\n  witness (4 steps):\n    Coin()   Locked/0   -> Unlocked/1\n    Coin()   Unlocked/1 -> Unlocked/2\n    Coin()   Unlocked/2 -> Unlocked/3\n    Push()   Unlocked/3 -> Locked/3      then Coin: coin-box-full, Push: locked\nverdict: FINDINGS (exit 1)  over coins ∈ 0..3; 7 states\n```\n\nThe invariant holds. What `poly check` finds is that a full coin box locks the turnstile forever. Add an operator action and it is clean:\n\n```\n  action Empty()\n  on Empty {\n    require mode is Locked else reject \"unlocked\"\n    coins' = 0\n  }\n```\n\nRunning it from TypeScript takes three lines:\n\n``` js\nconst rt = await load('./.poly/build')\nconst gate = await rt.create('hello.Gate')\nawait rt.dispatch(gate.id, 'Coin', {}, { actionId: 'coin-1' })   // { stepKind: 'accepted', state: { mode: 'Unlocked', coins: 1 } }\n```\n\nHandlers are pure functions of the pre-state: a primed field is written, never read. That is why the order of lines inside a handler cannot change what it does. The same machine can also be written as TypeScript with the embedded surface (technical specification, PT2.5).\n\n```\nmachine Order {\n  state {\n    status : Status = Draft\n    items  : 0..3   = 0\n    paid   : bool   = false\n  }\n  action AddItem()\n  action Place()\n  action Pay(amount: int check { 10, 20 })\n\n  on Place {\n    require status == Draft else reject \"not-draft\"\n    require items > 0      else reject \"empty-order\"\n    status' = Placed\n  }\n  on Pay(amount) {\n    require status == Placed else reject \"not-placed\"\n    emit charge(amount)\n  }\n\n  invariant shipped-was-paid: status == Shipped implies paid\n  path property charge-at-most-once: count(\"payment.charge\") <= 1\n\n  effect charge(amount: int) {\n    kind \"payment.charge\"\n    labels { egress:external }\n    class irreversible\n    ok -> PaymentOk()\n    failed -> PaymentFailed(code: \"declined\")\n  }\n}\n```\n\n`poly check` finds that two `Pay` calls emit two charges, and says why they can:\n\n```\norders.poly:17  PL4001 PATH_PROPERTY  charge-at-most-once\n  witness (4 steps):\n    AddItem()      Draft/0  -> Draft/1\n    Place()        Draft/1  -> Placed/1\n    Pay(10)        Placed/1 -> Placed/1   emits payment.charge\n    Pay(10)        Placed/1 -> Placed/1   emits payment.charge   <- count = 2\n  test:  poly witness sha256:3be1… --test   (fails on this program)\n  fixes: [enter-charging-status]  add status Charging, entered by Pay, left by PaymentOk / PaymentFailed\norders.poly:16  PL4002 EMIT_WITHOUT_STATE_CHANGE  Pay\n  Pay emits payment.charge and leaves the state unchanged, so it can repeat its effect without limit\n  witness (4 steps):\n    AddItem()      Draft/0  -> Draft/1\n    Place()        Draft/1  -> Placed/1\n    Pay(10)        Placed/1 -> Placed/1   emits payment.charge\n    Pay(10)        Placed/1 -> Placed/1   emits payment.charge\n  fixes: [enter-charging-status]  record the emission in the state\nverdict: FINDINGS (exit 1)  over items ∈ 0..3, amount ∈ {10, 20}\n```\n\nEach call is allowed; the sequence is not. The second finding names the cause: a step that emits and changes nothing can always be taken again. That is the bug the Poly stack was built to find, reported before the program can run. The snippet is abridged; the full example is in the technical specification, PT4.5.\n\nMachines hold addresses, not each other's state, and talk only by `send`. A **configuration** checks several of them together, with messages arriving in any order. In the checkout example (technical specification, PT7a), an inventory and each order are safe on their own. If the order confirms as soon as it hears \"available\", two orders can both be confirmed against the last unit:\n\n```\ncheckout.poly:33  PL5401 CONFIGURATION_INVARIANT  confirmed-within-stock\n  witness: Place@order[0], Place@order[1], Query(order[0]) -> inv, Query(order[1]) -> inv,\n           Available(1) -> order[0], Available(1) -> order[1]\n```\n\nNo per-machine check can see this. The defect lives in the arrival order between machines.\n\n| Document | What it covers | \n|---|---|\n| [`docs/01-functional-spec.md`](https://github.com/cognitive-fab/poly/blob/main/docs/01-functional-spec.md) | The problem, users, goals, non-goals, functional requirements ( `PF` ), acceptance criteria and risks | \n| [`docs/02-architecture.md`](https://github.com/cognitive-fab/poly/blob/main/docs/02-architecture.md) | Layers, the lowering map, the check pipeline, the certificate, the runtime and the gate, one ledger, the agent interface and architectural decisions ( `PA` ,`AD` ) | \n| [`docs/04-semantics.md`](https://github.com/cognitive-fab/poly/blob/main/docs/04-semantics.md) | What a poly program means: states, steps, rejected steps, behaviours, the five kinds of property, fairness and liveness, composition, three-valued policies, lowering correctness, kernel assumptions and operator precedence ( `PS` ). The other documents defer to it. | \n| [`docs/03-technical-spec.md`](https://github.com/cognitive-fab/poly/blob/main/docs/03-technical-spec.md) | Grammar, types and domains, step semantics, invariants, effects, policies, the gate integration, diagnostics, commands, host API, ledger, layout, implementation plan and the first experiment ( `PT` ) | \n| [`docs/research/primitive-inventory.md`](https://github.com/cognitive-fab/poly/blob/main/docs/research/primitive-inventory.md) | The design-time and runtime primitives of every engine, read from source | \n| [`docs/reviews/review-2026-09-29-blunt.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/review-2026-09-29-blunt.md) | The v0.1 peer review | \n| [`docs/reviews/response-2026-09-29.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/response-2026-09-29.md) | The response to the review, item by item, and what changed in v0.2 | \n| [`docs/reviews/review-2026-09-29-formal.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/review-2026-09-29-formal.md) | The v0.2 formal review | \n| [`docs/reviews/response-2026-09-29-formal.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/response-2026-09-29-formal.md) | The response to the formal review, and what changed in v0.3 | \n| [`docs/reviews/review-2026-09-29-functional.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/review-2026-09-29-functional.md) ,[`response`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/response-2026-09-29-functional.md) | The v0.3 functional-programming review and its response (v0.4) | \n| [`docs/reviews/review-2026-09-29-actors.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/review-2026-09-29-actors.md) ,[`response`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/response-2026-09-29-actors.md) | The v0.4 actor-model review and its response (v0.5) | \n| [`docs/reviews/review-2026-09-29-final.md`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/review-2026-09-29-final.md) ,[`response`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/response-2026-09-29-final.md) | The final formal review of v0.5 and its response (v0.6) | \n| [`docs/reviews/evidence/`](https://github.com/cognitive-fab/poly/blob/main/docs/reviews/evidence) | Independent explorations of every example model; the first acceptance tests of poly-ref | \n| [`docs/research/landscape-2026-09.md`](https://github.com/cognitive-fab/poly/blob/main/docs/research/landscape-2026-09.md) | The current landscape: model-checkable languages, verification languages, languages for agents, durable runtimes, agent governance, and evidence on how coding agents fail | \n\n1. \n**The semantics is the definition.** 04-semantics says what a program means; every`poly check` validates the lowering against it.\n0a.**One program, three interpreters.** The same machine is checked (all inputs), simulated (sampled inputs, v2) and run (real inputs). Only the environment changes.\n0b.**Machines talk only by messages.** Addresses are values,`send` is the only way to affect a peer, and interacting machines are checked together as configurations.\n2. \n**The engines check single machines; poly checks how machines relate.** Safety, governance, simulation and mining stay in the engines. poly's own model checker, poly-ref, checks the lowering, deadlock, liveness and configurations.\n3. \n**The checked program is the running program, over its check domains.** A certificate binds the source, the artefacts and the check results by digest. Out-of-domain inputs are rejected (`strict` ) or journaled as drift (`disclosed` ).**Domains refuse by default (S400, PT3.4a).** A check domain on an action's parameter is a constraint: an integer range, an enum, a`bool` or a`check { … }` clause refuses a value outside it at dispatch, with the reason`outside-check-domain` , before the handler runs. Write`disclosed` after a`check` clause (`amount: int check { 1, 2 } disclosed` ) to accept values outside the domain and only report them; such a value is then outside what was checked.\n4. \n**One source per machine.** Every engine artefact is derived.\n5. \n**No silent clean.** Every check reports clean, findings, refused, underpowered or inconclusive.\n6. \n**No model call on a check or decision path.**\n7. \n**The journal is the corpus.** Runtime journals feed replay, versioning, mining and simulation unchanged.\n\nThe Poly stack already holds the primitives a coding agent needs to write stateful code that holds. poly makes them one language. The first milestone is a lowering that reproduces the field-study results from poly source. The third is an experiment, run before any runtime is built, that measures escaped defects and cost against the host language alone. The runtime work depends on its result.\n\n| Term | Meaning | \n|---|---|\n| **SAM** | State-Action-Model. The pattern every poly machine lowers to, in its v2 strict profile. | \n| **Machine** | A sealed state, a set of actions and one handler per action. The unit of checking and of execution. | \n| **Handler** | `on Action { … }` . Requires first, then writes. It either accepts or rejects with a named reason. | \n| **Check domain** | The finite set of values a field or parameter takes during checking. Narrower than the runtime type when declared so, and strict unless written disclosed (S400). | \n| **Invariant** | A predicate on states that holds in every reachable state. | \n| **Step property** | A predicate on every accepted step `(pre, action, data, post)` . | \n| **Reject property** | A predicate on every step, whatever its verdict. | \n| **Path property** | A prefix-closed predicate on the effects emitted along a path, such as `count(k) <= 1` . | \n| **Liveness** | A property that something eventually happens, stated with the weak-fairness assumption it needs; its counterexample is a lasso. | \n| **Deadlock** | A reachable non-terminal state in which no action is accepted. Checked for every machine. | \n| **Checked instance** | The finite set of inputs and states a verdict covers. Every verdict is printed with it. | \n| **poly-ref** | poly's model checker: a reference interpreter written from 04-semantics, used for translation validation, deadlock, liveness, configurations and obligation consistency. | \n| **Possibility property** | A property that a good path exists (such as a mandate being dischargeable), as opposed to a property of all behaviours. | \n| **Trust scope** | The governance scope an instance belongs to. Messages that cross a trust scope pass the gate. | \n| **Tagged union** | A type whose values are one of several constructors, each with its own payload. Makes invalid states unrepresentable. | \n| **Tri** | The three-valued truth type of policy expressions (true, false, unknown). Machine expressions are `Bool` . | \n| **Capability** | An object passed to a handler that grants exactly the authority its effect's labels and targets declare. | \n| **Interpretation** | One of three ways to feed the same machine: check (all inputs), simulate (sampled inputs) or run (real inputs). | \n| **Embedded surface** | poly written as valid TypeScript with the `poly/embed` combinators; it produces the same AST as the standalone syntax. | \n| **Ref** | The address of an instance ( `Ref<M>` ). It can be stored and passed in messages, but not dereferenced. | \n| **Configuration** | A finite set of instances checked together, with messages in transit delivered in any order within a declared bound. | \n| **Attached / detached child** | An attached child shares its parent's atomic cascade and kernel shard. A detached child is a separate actor that communicates by messages. | \n| **Delivery guarantee** | Every message sent is eventually received: part of the semantics, implemented by the runtime (obligation R1). | \n| **Dischargeable** | A mandate is dischargeable when some path reaches its discharge state without a deny under all obligations together. | \n| **Kernel assumption** | A property of the runtime (K1 to K8) that a guarantee about running programs depends on. | \n| **Witness** | The shortest concrete sequence that violates an invariant or reaches a forbidden region. It can be exported as a trace and as a test. | \n| **Effect** | A declared side effect emitted by an accepted step. It carries labels and a class, and passes the gate before it runs. | \n| **Label** | A term from a closed vocabulary (for example `egress:external` ) that describes what an effect touches. | \n| **Obligation** | A rule, machine, invariant or recalled text inside a `policy` , enforced by the Polyaxion gate. | \n| **Effect gate** | The Polyaxion guarded merge that decides allow, deny or escalate before an effect or tool call executes. Distinct from the polycheck runtime guard and the polygents gate. | \n| **Strict / disclosed** | The two modes of a check domain. `strict` rejects out-of-domain input at dispatch;`disclosed` accepts it and journals it as drift. | \n| **Admission** | Passing the check pipeline. Only admitted programs load. | \n| **Certificate** | The signed record of what was checked: source digest, artefact digests, check results, domains, stages not run and accepted exceptions. | \n| **Ledger** | The signed record of steps, proposals, verdicts, effects, observations and advice, hash-chained per run. | \n| **Anchor** | A signed Merkle root over the heads of all runs, published periodically, proving no run was dropped from a period. | \n| **Work order** | An effect of a workflow machine, handed to an agent or a person to claim, run and report. | \n| **World** | A set of machines, responders and drivers that Polytrion runs against a virtual clock. Deferred to v2. | \n| **Lowering** | Compiling a poly construct into the artefact an existing engine reads. |", "url": "https://wpnews.pro/news/poly-a-human-readable-programming-language-for-coding-agents", "canonical_source": "https://github.com/cognitive-fab/poly", "published_at": "2026-10-23 09:57:19+00:00", "updated_at": "2026-10-23 10:12:12.863670+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Poly", "SAM v2", "polygraph", "Polyaxion", "polyflow", "Polytrion", "TypeScript"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/poly-a-human-readable-programming-language-for-coding-agents", "markdown": "https://wpnews.pro/news/poly-a-human-readable-programming-language-for-coding-agents.md", "text": "https://wpnews.pro/news/poly-a-human-readable-programming-language-for-coding-agents.txt", "jsonld": "https://wpnews.pro/news/poly-a-human-readable-programming-language-for-coding-agents.jsonld"}}