# Replay is a convention the agent author has to keep, not an enforced boundary

> chidori is a Rust agent runtime with an embedded JavaScript engine that records every side effect as a host call, so a run can be replayed with no model calls, resumed after a crash, or suspended for a human. The architecture is coherent and unusually well documented for its lint policy; what it does not do is tell you what happens when an agent reaches past the API.

**ThousandBirdsInc/chidori** — The agent framework where every run is durable, replayable, and resumable by default.

- Repository: https://github.com/ThousandBirdsInc/chidori
- Website: https://thousandbirdsinc.github.io/chidori/
- Stars: 1,365 · Forks: 59
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/thousandbirdsinc-chidori

## Durability holds only for effects that went through the API

The whole design rests on one boundary. Every side effect an agent performs, and the README names three categories, LLM calls, tool calls and HTTP requests, flows through the runtime as a recorded host call, and the claim that follows is that agents never touch the world directly so the runtime sees and records everything. Then durability is described as the default rather than a wrapper: there is nothing to annotate and no activity to define, because every `await chidori.*` is itself a durable safepoint. That is a good deal when it holds, and the dependency is entirely on the author. A direct fetch, a timer that reads a file, or a library that opens a socket behind your back does not become a host call because the runtime is watching. Nothing in the visible text says what such a call does to the call log, whether it is an error or a silent gap, and that is the question a user of this runtime most needs answered.

## Determinism is a fixed clock and a seed, which bounds the byte-identical claim

The replay guarantee is stated twice, once in the opening paragraph as replayed for byte-identical output with zero LLM calls, and again in the differences list as replay costs zero tokens and is byte-identical. The mechanism given is runtime policy consisting of a fixed clock and seeded randomness. That is the entire answer, and it is a strong one for the problems the project lists, since nondeterminism from a model or a network call is neutralised by recording the call rather than by controlling the clock. What it does not cover is everything. A clock and a seed handle time and randomness; they do not handle an unordered hash iteration, an environment variable read at run time, a dependency that reads the clock through a path the engine does not intercept, or a file read that bypassed the host-call convention entirely. The README does not enumerate the interception surface, so the honest reading of byte-identical is that it holds for programs that respect the boundary and for reasons the author has not fully specified.

## The npm package installs no runtime, and it is scoped to a different name

Three registries carry a package called Chidori and they are not interchangeable. crates.io has `chidori` and PyPI has `chidori`, both unscoped, and npm has `@1kbirds/chidori`, scoped to a name that shares nothing with the GitHub organisation `ThousandBirdsInc`. The README spends a callout on this because it is genuinely confusing:

```bash
npm i @1kbirds/chidori
```

installs nothing that runs agents. What that command gives you is an SDK, a thin optional client for driving a runtime that must already be installed separately, over HTTP, from a TypeScript or Python service that wants to embed Chidori. The distinction the README draws is sensible, since you author agents as plain `.ts` files the runtime executes directly and an SDK is only for embedding. But the failure mode for someone who searches for the package, installs it, and looks for a binary is total, and nothing in the package name signals which of the two they got.

## Three install routes, and the fastest one runs a script from the default branch

The recommended path is one line:

```bash
curl -fsSL https://raw.githubusercontent.com/ThousandBirdsInc/chidori/main/scripts/install.sh | sh
```

The binaries it fetches are properly pinned, coming from the latest GitHub release, for macOS on either architecture or Linux on x86_64 or arm64, landing in `~/.chidori/bin` with a printed PATH adjustment. The bootstrap script itself is not pinned: it is read from `main`, so it is whatever that branch holds at the moment you run it, and it is executed by `sh` rather than inspected. The two alternatives have different prerequisites again. `cargo install chidori` needs a stable toolchain at 1.95 or newer, and a checkout build relies on `rust-toolchain.toml` being picked up automatically. Three routes, three toolchain requirements, and no statement about which one the project considers supported for what.

## Two lint allows with written reasons, and every local suppression needs one

The workspace lint table is the most carefully justified file in the repository:

```toml
[workspace.lints.clippy]
type_complexity = "allow"
too_many_arguments = "allow"
```

Each allow carries a paragraph explaining it. The interpreter and runtime traffic genuinely uses wide nested generic types over handles, callbacks and journal entries, and naming every alias would cost more than it saves. A few virtual machine entry points thread many distinct parameters by design, and collapsing them into a struct is a refactor to take deliberately. Then the policy: the table is the only place blanket allows are permitted, everything else runs under `cargo clippy --workspace --all-targets -- -D warnings` in CI and in the pre-commit hook, so anything not allowed must be fixed or suppressed locally with an `#[expect(..., reason = "...")]`. Requiring a reason on every local suppression is the part that pays off, because it makes each one visible in review rather than a silent escape.

## A test262 runner is the reason default-members exists

The workspace has four crates: the CLI and runtime, a JavaScript engine crate, a WebAssembly crate, and a test262 runner. The manifest explains the fourth only as a build inconvenience:

```toml
default-members = ["crates/chidori"]
```

Because the test262-runner binary makes a bare `cargo run` ambiguous, cargo would refuse to run anything at the workspace root, and the fix is one line so that the root command means the CLI, which is the form every document uses. CI passes `--workspace` explicitly and is unaffected. What that parenthetical reveals is more interesting than what the README says anywhere: the project runs the JavaScript conformance suite against its own embedded engine, and never mentions it. The same applies to the other unexplained root entries. A WebAssembly crate sits beside a README promising one binary and no runtime dependencies. `deny.toml` is a dependency licence and advisory policy. `hk.pkl` is a Pkl configuration file in a Rust project. `mise.toml` is a task runner alongside a scripts directory. And `llm.txt` is the machine-readable documentation convention, which suggests the docs are written for agents as well as people.

## The examples cluster on human pause, not on replay

Thirteen example directories ship with the repository, and their names describe the feature set more honestly than the README does. `record-replay` is the one matching the headline. The three scenario-shaped examples, multiplayer review, standup scribe and war room, are all cases where several people and several agents contribute over time, which is the human-pause capability rather than the replay one: `chidori.input()` and named signals suspend a run to disk and a human answers minutes or days later. `branching` and `interactive-pipeline` together indicate the execution graph is not linear. `self-harness-loop` points at an agent improving its own setup, and a Python SDK demo sits beside the TypeScript ones, matching the two client packages. The quickstart has a security detail worth stating on its own: `chidori model-login` opens a browser, signs in with OpenRouter, and writes the resulting key to `~/.chidori/credentials.json` in plaintext, which is both a credential at rest on disk and a default route through a third-party aggregator rather than a first-party key.

## Conclusion

It fits someone whose agents are long running, expensive to re-run and hard to debug, and who will accept writing plain async TypeScript and routing every effect through the provided calls. It does not fit someone who expects durability to be enforced by the framework, because the guarantee depends on the agent never calling the network or the filesystem directly, and that rule is stated as a property of agents rather than as a restriction the runtime checks. Before adopting it, decide whether you can live with that convention across a codebase you do not control, and if you take the fast install, remember it fetches a shell script from the default branch rather than a tagged release.

## FAQ

### What makes a chidori run replayable?

Every side effect, meaning LLM calls, tool calls and HTTP requests, flows through the runtime as a recorded host call, so replaying a run returns recorded results with no model calls. Determinism is enforced by runtime policy using a fixed clock and seeded randomness.

### Does installing the chidori npm package install the runtime?

No. npm i @1kbirds/chidori installs an SDK, a thin HTTP client, not the runtime binary. The runtime is the chidori binary, available unscoped on crates.io and PyPI as well as from a prebuilt release.

### How do you install the chidori runtime?

Either curl the install script from the main branch and pipe it to sh, which downloads a release binary into ~/.chidori/bin, or cargo install chidori with a stable toolchain of 1.95 or newer, or build from a checkout that pins its own toolchain via rust-toolchain.toml.

### What is in the chidori Cargo workspace?

Four crates: the CLI and runtime, a JavaScript engine crate, a WebAssembly crate, and a test262 runner. default-members is set to the runtime alone so that a bare cargo run at the root is not ambiguous.

### How does chidori handle human approval?

chidori.input() and named signals suspend the run to disk, and a human or another agent answers later, so the process does not need to stay alive for hours. Three of the shipped examples, multiplayer review, standup scribe and war room, exercise that path.

## Sources

- [License: Apache-2.0](https://github.com/ThousandBirdsInc/chidori/blob/main/LICENSE)
- [Project website](https://thousandbirdsinc.github.io/chidori/)
- [README](https://github.com/ThousandBirdsInc/chidori/blob/main/README.md)
- [Releases](https://github.com/ThousandBirdsInc/chidori/releases)
- [ThousandBirdsInc/chidori on GitHub](https://github.com/ThousandBirdsInc/chidori)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/thousandbirdsinc-chidori
