A zero-infrastructure runtime that makes agent systems reproducible, testable, and capability-safe — a durable, replayable state machine orchestrating AI agents as lightweight threads.
Project description
Jaros
A zero-infrastructure runtime that makes agent systems reproducible, testable, and capability-safe by construction — a durable, replayable state machine that orchestrates AI agents as lightweight computing threads, not bloated microservices.
Jaros is the runtime you reach for the day your agent leaves the demo — when non-determinism has made it impossible to reproduce, and ambient power has made it unsafe to ship. It delivers that without a server, a database, or a broker: just files and threads.
It works by decoupling non-deterministic AI reasoning from deterministic system execution. The LLM is an interchangeable application that may only propose inert, serializable Decision data; a deterministic execution plane decides whether and how each decision runs — and may reject it. This is the system's Prime Directive; every part of the codebase exists to serve it.
What sets Jaros apart
Most agent frameworks let the model drive: a tool call is a side effect. Jaros inverts it — the model writes recommendations on slips of paper; a deterministic clerk decides what actually happens. Four properties fall out of that design:
- 🐝 Reproducible & accountable swarms — every accepted
Decisionis recorded in one ordered, hash-chained log tagged with its source agent, so replaying re-executes the whole hive to byte-identical state with zero model calls and attributes any failure to the exact agent and decision. - 🔁 Reproducible by replay — the only non-determinism is the model's output, recorded before any effect; replaying the log reconstructs the run to byte-identical state with no model call. Crash recovery is just replay.
- 🔒 Capability-safe by construction — agents hold only the scoped handles the harness grants; a bug or bad decision cannot reach what it was never given, and every mediated action is audited.
- 📦 Zero-infrastructure — no server, no database, no broker. The control plane is the file system; agents are threads in one process. A
check_zero_infraguardrail fails the build if any code even imports a DB driver or broker.
One command replays a hive and names the culprit — and the agents really let the model decide (accept → DONE, reject → FAILED), yet replay reconstructs whatever the model chose with zero model calls:
→ The full story, with the model-driven decisions, the graduation-layer comparison, and the honest "is / is not": docs/why-jaros.md.
Quickstart
Install from PyPI and scaffold a ready-to-run node in two commands:
pip install jaros
jaros init --with-examples # scaffolds ./.jaros-data with bundled example agents, tools, evals, schedules
jaros init --with-examples drops a library of example agents and tools straight into the data dir, so the daemon — and the console — have something to run immediately. Boot the node, then drive it from another shell; work enters only through the shared file system:
# boot the node (the OS) + the web console — discovers ./.jaros-data by default
jaros serve
# Jaros node up.
# data dir : .jaros-data
# model : default
# console : http://localhost:5500 (starting…)
# Ctrl-C to stop. The log below shows events as they happen.
jaros serve brings up the web console by default (--no-console to skip) and stays quiet after the banner — it logs only meaningful events (a job completing or failing, a schedule firing), not a per-tick heartbeat.
# from another terminal: submit work + watch results, all over the shared FS
jaros submit system-health # a bundled example agent
jaros submit advance --input '{}' # the built-in agent
jaros watch # change-only: reprints status when it changes, one line per new result
Then the payoff — reconstruct the entire run from the recorded decisions, with no model call:
jaros replay
# replayed 3 recorded decisions (3 applied) - model calls: 0
# reconstructed state : DONE
# byte-identical : yes
# reproducible: the recorded decisions reconstruct the run exactly, with no model call.
The whole loop from the CLI — submit work, check status, replay it byte-identically, and run the eval suite (real output, nothing faked):
Every command discovers the data dir automatically (./.jaros-data, or $JAROS_DATA_DIR, or --data-dir DIR to override). For the full day-one-to-production path (first agent → schedule → eval → replay → console → distributed Docker), see docs/getting-started.md.
Hacking on Jaros itself? Clone the repo and
pip install -e ".[dev]"instead — every command works the same against a checkout, andpytestruns the suite plus the architecture guardrails.
Want to build your own agents? Point your coding agent (e.g. Claude Code) at agent-kit/, tell it to read what's there, and it learns the whole system and writes + verifies new Jaros agents for you. See Build an agent.
Web console
A TypeScript + React administrative and monitoring interface lives in console/ — submit jobs, install agents and custom tools, watch live status, browse the durable decision log, and replay it to byte-identical state from the browser. It's a host-side companion (a thin file-system bridge + SPA); the Jaros node itself stays serverless.
It ships in the wheel — no Node required. pip install jaros bundles a prebuilt SPA and a pure-stdlib server, so jaros serve brings the console up for you and prints the URL — open http://localhost:5500. Run it standalone with jaros console, set the port with --console-port, or skip it with jaros serve --no-console:
jaros serve # node + console (default)
jaros console --console-port 8080 # just the console, on a port you pick
The Overview is a glanceable NOC view with a live get-started checklist; every other page (State Machine, Reproducibility, Harness, Jobs, Agents, Schedules, Evaluations) introspects the real runtime over the file system.
The bundled server is the Python twin of the TypeScript bridge under
console/. For console development (React hot-reload), runcd console && npm install && npm run dev; everyday use needs neither.
The full page gallery and a walkthrough of every page (with pictures) live in docs/console.md and the console README.
Build an agent
An agent is a ReasoningBoundary: data in → Decision data out, no side effects, no handles. Drop the module into the shared-FS agents/ folder and the daemon registers it at runtime.
import uuid
from jaros.core import create_decision
KIND = "greeter" # the agent kind the daemon registers
class GreeterBoundary:
def __init__(self, llm):
self._llm = llm
def decide(self, context) -> list:
name = context.get("name", "world") if isinstance(context, dict) else "world"
# Propose an inert decision; the executor (not the agent) acts on it.
return [create_decision(
id=f"greet-{uuid.uuid4().hex}",
source="greeter",
kind="advance", # built-in handler drives the state machine
payload={"events": ["start", "complete"], "note": f"hello {name}"},
)]
def build(llm): # agent factory the daemon calls
return GreeterBoundary(llm)
To bound an agent, restrict its capability grant at spawn time — a role is just a named bundle of capabilities. A custom tool extends what the system can do: drop a class exposing NAME, validate(), and execute() into tools/. See examples/tools/greet_tool.py and the full guide in docs/building-agents.md.
Or let a coding agent build it. Jaros is made to be extended by coding agents. Point yours — Claude Code, Cursor, or similar — at AGENTS.md → agent-kit/ and have it read what's there: the mental model, a skill per artifact, accurate API reference, and runnable templates that pass jaros eval unmodified. Tell it "read agent-kit/ and build me an agent that does X," and it will.
Run on Docker
The container is the boundary for the whole Jaros node; agents run as threads inside it — never one container per agent.
docker build -t jaros .
docker run -d --name jaros_os -v ${PWD}/.jaros-data:/data jaros # one daemon = one node
jaros submit advance --input '{}' # submit from the host, over the shared FS
Because the control plane is files only, scheduling needs no broker: any host-side cron can jaros submit, and several daemons can share one directory — each job is claimed by an atomic inbox → claimed rename (exactly-once in the happy path, at-least-once under failure via lease reclaim). The distributed walkthrough is in docs/getting-started.md.
Learn more
- docs/getting-started.md — the full day-one path, first agent → distributed Docker.
- docs/why-jaros.md — what sets Jaros apart, in depth, plus where it fits and what it is not.
- docs/architecture.md — the two planes, the guardrails, the subsystem map, and the project layout.
- docs/building-agents.md — write agents and custom tools by hand.
- docs/console.md — a visual guide to every console page.
agent-kit/— hand it to your coding agent to build Jaros agents the way you'd use them..jarify/PRIME-001/intent.md— the Prime Directive every part of the system serves.
Jaros is developed spec-first under .jarify/: the Prime Directive holds the system intent, each EXT-00x spec decomposes one tenet into requirements/design/tasks, and code is traced back to requirements via index.json.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jaros-0.4.0.tar.gz.
File metadata
- Download URL: jaros-0.4.0.tar.gz
- Upload date:
- Size: 2.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d566bac143918b636f256cb8397071e327f88b16e7c2c09d8c2c762dd7c9f1af
|
|
| MD5 |
7045df39567b73e1fc5ebb708582e799
|
|
| BLAKE2b-256 |
fd4596886178bf0d74ed26de6b25e9dba44fc609efd621c07874c2397011d778
|
File details
Details for the file jaros-0.4.0-py3-none-any.whl.
File metadata
- Download URL: jaros-0.4.0-py3-none-any.whl
- Upload date:
- Size: 2.8 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e689a753b0d521c95449a250c60aa90b3a5dcc414ae8a650bcc004246c67abd0
|
|
| MD5 |
e585781a9188a5d7328d567d23bec9ef
|
|
| BLAKE2b-256 |
a087caba9e1b4c9af8a8df1715a9b8b08dc51caa9fe43c71302819e23d56866a
|