@darkhorseprojects/circuitry
v0.12.1
Published
Crystallized dataflow for portable agents.
Downloads
221
Readme
Circuitry
Crystallized dataflow for portable agents.
Circuitry makes agent workflows explicit and reusable: each call declares its input and matches its result. References determine readiness, independent calls run together, and complete generations commit atomically—even when calls execute Circuitry produced during the run.
---
in { request $request; model $model }
draft source="$model" {
(json)in {
instructions "@Instructions"
request $request
}
(json)out { answer $draft }
}
review source="./review.kdl" {
in { draft $draft; rules "@Rules" }
out { answer $answer }
}
out { answer $answer }
---
# Instructions
Answer the request in a JSON object with one `answer` field.
# Rules
Check every claim.This agent asks a model for a draft, then passes it to a nested Circuitry reviewer.
Install
npm install @darkhorseprojects/circuitryCircuitry is an ESM library for Node.js 24 and Deno.
import { parse, run } from "@darkhorseprojects/circuitry";
for await (const record of run(parse(source), {
input,
cwd: "/work",
signal,
})) {
await persist(record);
}The application supplies input and stores trace records. The execution environment supplies authority.
Flow
flowchart TD
input(["Program + input"]) --> ready["Find ready unseen calls"]
ready -->|some| run["Run generation concurrently"]
run --> settle["Await every finite result"]
settle -->|all handled| commit["Commit bindings in declaration order"]
commit --> ready
settle -->|unhandled| fail(["Discard generation · return failure"])
ready -->|none| output(["Resolve root output"])A call runs when its required references exist and its resolved invocation is new. Calls ready together form a generation and run concurrently.
Results appear in completion order. Bindings commit together in declaration order only after the generation settles. One unhandled failure discards them all. Circuitry never retries an unchanged invocation.
Use .kdl for pure KDL and .md for Markdown with KDL frontmatter.
$name required state
?name optional state
@Section required Markdown section
?@Section optional Markdown sectionSources
A call source selects one operation:
""passes its input through.- A
.kdlor.mdpath runs a nested program. (circuitry)source text compiles and runs directly.- Any other string invokes a command with its resolved arguments.
Available files, networks, environment values, and commands come from the execution environment.
Codecs
Effect boundaries use four codecs:
json: one JSON value and the default;jsonl: zero or more newline-terminated JSON values;text: one UTF-8 string;bytes: one byte sequence.
Command stdin and stdout use the declared codecs. JSONL is the only multi-record framing: each complete value appears in the trace as it arrives, while matching waits for valid EOF. JSONL captures are always arrays.
stream source="$agent-command" {
(json)in { prompt $prompt }
(jsonl)out { delta $delta }
}Composition
Nested and generated programs use the same root boundaries. A generated program can therefore act as one model tool:
action source=(circuitry)"$program" {
in { task $task }
out { result $result }
error $failure
}A matched failure becomes data, allowing a later generation to revise the source and execute a changed invocation.
Traces
Every run yields canonical JSON Lines records for its exact source, calls, provisional values, finite results, bindings, and root result.
{"at":"2026-07-14T19:20:00.000Z","input":{"name":"world"},"source":"...","trace":"019f..."}
{"at":1,"call":"greet"}
{"at":2,"value":"Hello, world!","yield":1}
{"at":3,"bindings":{"greeting":"Hello, world!"},"result":1}
{"at":3,"output":{"greeting":"Hello, world!"},"result":0}Yield records make complete values visible immediately. Call settlement determines whether they match, and generation settlement determines whether their bindings commit. The application decides where traces are stored, indexed, or viewed.
Guarantees
Calls may yield, fail, or complete in any order. Circuitry records that order, while values and bindings remain provisional until their calls and generation settle. One unhandled failure discards every binding from that generation. Declaration order resolves writes and selects the root failure.
For the same program, input, and command outcomes, timing cannot change committed state, selected root failure, or root output. Circuitry performs no implicit retries or fallback execution.
Docs
Development
npm ci
npm run test:watch
npm run verify