Most agent frameworks ship a DSL or a YAML schema. Chidori runs ordinary TypeScript, with a fixed set of host functions on the chidori object for every side effect. Because each call is logged and replayed from a checkpoint, any past run reproduces its output for free.
Agents are plain async TypeScript: native control flow, typed inputs, imports, and editor tooling. No YAML, no template DSL, no graph builder.
export async function agent(
input: { question: string },
chidori: Chidori,
) {
const qs = await chidori.prompt(
"3 queries for: " + input.question,
{ type: "json" },
);
return chidori.parallel(
qs.map((q) => () => chidori.tool("search", { q })),
);
}Durable runs use fixed Date and seeded Math.random. Every side effect goes through a host function on the chidori object the runtime logs, caches, and replays.
// every side effect is a host call:
// chidori.prompt(), chidori.tool(),
// chidori.parallel(), chidori.input()
//
// each logged with a seq number,
// inputs, and result — so replay
// returns cached results, no LLM spend.Save a session's call log to disk and replay it later for identical output — zero LLM spend. Debug production locally without burning a token.
$ chidori run agent.ts \
--replay session.json
[cache] prompt hit
[cache] tool hit
[cache] prompt hit
→ identical output · $0.00chidori.input() pauses execution and persists the run. When the human responds, the agent resumes from the saved state at the point it paused — no special state machine.
const answer = await chidori.input(
"Approve resume from 0x4a1?",
{ type: "approval", choices: ["yes", "no"] },
);
if (answer !== "yes") {
return { status: "rejected" };
}Any .ts file is an agent, and any agent can call another with chidori.callAgent(). Sub-agents share the session and call log, and stream their own labelled spans — compose specialists without inventing a DAG.
const draft = await chidori.callAgent(
"writer.ts",
{ topic: question, notes: results },
);
const review = await chidori.callAgent(
"critic.ts",
{ draft, bar: "rigorous" },
);
return { draft, review };chidori.execJs / execPython / execWasm run agent-written code inside a sandbox with strict time and memory limits. Let an LLM write and run code without letting it touch your box.
// agent writes + runs code safely
const result = await chidori.execPython(
await chidori.prompt("Write python to…"),
{ timeoutMs: 2000 },
);
// sandboxed · no net · no fsEvery host function call — prompt, tool, callAgent, exec — is emitted as an OpenTelemetry span. Point it at Tael, Jaeger, Tempo, or Honeycomb by setting one env var.
OTEL_EXPORTER_OTLP_ENDPOINT=\
http://localhost:4317
# every prompt/tool/agent/exec
# arrives as a span.
# zero extra config.An agent is a .ts file that exports async function agent(input, chidori). The input is your typed payload; the return value is JSON output. Prompts, tools, parallel fan-out, and human input are ordinary calls on the chidori object.
// agents/researcher.ts
import type { Chidori } from "chidori";
export async function agent(
input: { question: string },
chidori: Chidori,
) {
const queries = await chidori.prompt(
"3 search queries for: " + input.question,
{ type: "json" },
);
const answer = await chidori.parallel(
queries.map((q) => () =>
chidori.tool("web_search", { query: q })),
);
return { answer, queries };
}chidori run executes once from the CLI. chidori serve turns the same file into an HTTP server — every incoming request becomes an event passed to agent(event, chidori). Webhooks, chat, alerts — same primitive.
$ chidori run agents/researcher.ts \
--input question="OTel SDK choice"
$ chidori serve agents/researcher.ts --port 8080
$ curl -X POST localhost:8080/sessions \
-d '{"input": {"question": "..."}}'Every run produces a session log — an ordered record of every host function call with its inputs and result. Feed it back in and the agent re-runs with cached results. Zero tokens, identical output.
# save a live session
$ curl localhost:8080/sessions/<id>/checkpoint \
> session.json
# replay later — zero LLM spend
$ curl -X POST localhost:8080/sessions \
-d @session.json
→ identical output · cost: $0.00No dashboards. No browsers. Tael ingests OpenTelemetry over OTLP, stores it in an embedded columnar database, and returns JSON by default — so your agents can query, monitor, and annotate production telemetry themselves.
$ tael anomalies --since 1h --format json | jq[
{
"service": "researcher-agent",
"metric": "latency.p95",
"baseline_ms": 1180,
"current_ms": 4210,
"severity": "high",
"first_seen": "14:02:31Z",
"trace_ids": ["0x4a1c2e", "0x4a2f11"]
},
{
"service": "writer-agent",
"metric": "errors.rate",
"baseline": 0.003,
"current": 0.041,
"severity": "medium",
"sample_trace": "0x5b8a03"
}
]$ tael correlate --trace 0x4a1c2e→ 14 spans · 3 logs · 2 metric series → hand off to chidori agent? [y/N]
You already have the hardest part — the goal, the context, the judgment. The bottleneck is how much you can hold at once. Agents extend your reach: delegate to AI that remembers its work, recovers from failures, and tells you exactly what it did.
Chidori and Tael are the building blocks. Open source. Deterministic. Built to be boring, so the agents running on top of them can afford to be interesting.