Mainspring is a model-agnostic operating system for running a business, not a task.
You give it a constitution — a mission, hard rules, and money caps, written as a plain markdown file. You plug in any LLM as its "brain." It wakes on a timer, forever: reads its own memory from disk, does a slice of work, keeps a real ledger, and hands anything it can't safely do alone to a human-approval queue. Then it goes back to sleep until the next wake-up, with no memory except what it wrote to disk.
A prompt is advisory — an instruction file asks the model to behave, and on a
bad turn the model can ignore it. Mainspring's constitution is enforced: every
action the brain proposes is checked by code, before it happens, and blocked if
it breaks a hard rule. Your rules should be a gate the runtime holds, not a
paragraph the model is trusted to honor. See
docs/why-enforcement.md.
Where LangChain, AutoGPT, and CrewAI orchestrate agents to finish a task, Mainspring is the runtime for a persistent operation: durable memory across amnesiac sessions, real accounting, capability-gated and audited side effects, a leak-proof publish gate, and human-in-the-loop oversight — all model-agnostic. The wedge, in three words: MEMORY. MONEY. GOVERNANCE.
Built by an autonomous AI agent (Fabler Labs) as part of a real, running, revenue-tracked experiment — this repo is that agent's own runtime, open-sourced.
Every wake-up runs the same four steps, and nothing skips them:
assemblereads the workspace —STATE.md, the journal tail,LEDGER.csv,inbox/,health.json— into oneSessionInput.Brain.step()is pure reasoning over that input. It proposes a list ofActions and never touches disk, network, or a secret itself.gatechecks every proposedActionagainst the Constitution — money caps, workspace path safety, secret-shaped content — before anything happens, and logs why whatever it blocks was blocked.dispatchis the only code that writes: journal/state/ledger/queue files, thengit add -A && git commit, so the workspace's history is an audit trail independent of the Brain's own self-report.
assemble → Brain.step → gate → dispatch → commit → sleep. A Brain can
propose anything; it can never execute anything. See
docs/architecture.md for the module map and the
trust-boundary reasoning behind that split.
| Package | Purpose | Status |
|---|---|---|
@mainspring/core |
The Brain contract and the constitution-enforcing session loop (assemble → gate → dispatch → commit), plus EchoBrain, a zero-API-key reference Brain. |
Stable — the loop @mainspring/cli runs, tested end to end. |
@mainspring/cli |
The mainspring bin: init, run, status, doctor a workspace. |
Stable — all four commands verified against a real workspace. |
@mainspring/memory |
Durable, deterministic utilities for STATE compaction, the journal, and the session log. | Phase 1 — tested standalone; not yet called by the reference loop. |
@mainspring/scrub |
Detect secret-shaped strings in content before any publish or notify action. | Phase 1 — tested standalone; not yet wired into dispatch.ts. |
@mainspring/relay |
Zero-dependency human-in-the-loop client that speaks the Fabler Relay wire protocol — the governance leg of the loop. | Phase 1 — tested standalone; a workspace's own Brain/config wires it in today. |
@mainspring/ledger |
Append-only LEDGER.csv management with balance invariants and spend-cap thresholds — the Constitution's Money rules as code. |
Phase 1 — tested standalone; core's dispatch.ts still does its own inline ledger writes. |
@mainspring/governance |
Constitution-as-code: hard rules the brain cannot override, loaded from CONSTITUTION.md and enforced as Action guards. |
Wired — core's gate.ts consults an injected governance guard on top of its built-in checks (opt-in via runSession({ governance })); it can tighten an allow into a citation-carrying denial but never loosen a built-in block; default path unchanged. |
@mainspring/brains |
Reference Brain implementations: a scripted MockBrain for tests, and a zero-SDK ClaudeBrain adapter for Anthropic's Messages API. |
Phase 1 — request/response mapping is unit-tested; the live-network path is unverified end to end. |
@mainspring/broker |
Capability-gated side effects: register a Capability with a Cap (max amount, max calls/day, target allowlist), then exercise it only through Broker#request — fail-closed on anything unregistered or over cap, one audit entry per attempt, allow or deny. |
Wired — core's dispatch.ts routes money-moving/external Actions through an injected Broker (opt-in via runSession({ broker })); default path unchanged. |
"Phase 1" above means exactly one thing: the package is real, has its own
passing test suite, and builds clean under tsc --strict — but the
reference loop in @mainspring/core doesn't call it automatically yet.
Nothing here is a stub; a workspace's own mainspring.config.ts can import
and use any of them today. Closing that integration gap is the next
milestone — see docs/roadmap.md.
Plus docs (docs/) and two non-code starting points: templates/default/
(what mainspring init scaffolds) and examples/hello-business/ (a
pre-wired workspace using EchoBrain, no API key needed).
@mainspring/* isn't published to npm yet, so the fastest way to see the
loop run for real is inside this repo's own workspace, against the
pre-wired examples/hello-business:
git clone https://github.com/fablerlabs/mainspring
cd mainspring
pnpm install
pnpm -r build
cd examples/hello-business
node ../../packages/cli/dist/bin.js run # EchoBrain: writes a journal + ledger line, commits
node ../../packages/cli/dist/bin.js status # see what that session didmainspring init <dir> (see packages/cli/src/commands/init.ts) scaffolds
a fresh workspace from templates/default/ the same way, for when you're
ready to start your own — swap EchoBrain for a real Brain by editing the
generated mainspring.config.ts. Its generated "next steps" currently
assume @mainspring/core is installable from npm, which isn't true until
this repo's first publish; until then, point a new workspace's
mainspring.config.ts at this monorepo via a workspace:*/local file:
dependency, the way examples/hello-business does.
Beyond examples/hello-business, examples/ holds several more runnable,
offline proofs — a minimal five-package quickstart, a content-agent relay
hand-off, a crash-resume amnesia demo, and a seven-package full-stack-test.
See examples/README.md for the map and each one's run
command.
Need the operating documents around the runtime rather than more runtime code? The Autonomous Agent Starter Kit is a separate paid download with the constitution, memory protocol, safety rails, supervisor blueprint, state/journal/ledger templates, and session checklists used around Fabler Labs' own agent. Mainspring itself remains Apache-2.0 and complete without it.
A Brain is pure reasoning: given the current state of the business, it
proposes a list of Actions. It never touches the filesystem, the network,
or a secret directly — only the session loop does that, and only after
every Action clears the gate.
interface Brain {
readonly id: string;
readonly model: string;
step(input: SessionInput, history: Turn[]): Promise<StepResult>;
estimateCost?(usage: Usage): Money;
}
type Action =
| { kind: "run"; tool: string; args: unknown }
| { kind: "write"; path: string; content: string }
| { kind: "ledger"; entry: LedgerEntry }
| { kind: "enqueue"; order: WorkOrder }
| { kind: "relay"; request: RelayRequest }
| { kind: "notify"; to: "owner"; text: string; priority?: "high" }
| { kind: "done" };
interface StepResult {
actions: Action[];
usage: Usage;
done: boolean;
}Because step() is the entire surface area, adapting a new model/provider
is one file: translate SessionInput into that provider's prompt/tool-call
format, translate its response back into Action[]. @mainspring/core
ships EchoBrain as the minimal reference; @mainspring/brains ships a
worked ClaudeBrain adapter and a scripted MockBrain for tests. See
docs/brains.md for the full contract, the gate-feedback
rules, and the worked adapter walkthrough.
@mainspring/core's gate.ts enforces the Constitution's money and secret
rules inline; @mainspring/broker is the reusable, model-agnostic shape of
that same idea for any other capability (spend, notify, publish, ...). You
register a Capability once with a Cap — max amount, max calls per day, an
optional target allowlist — and every request() against it is checked
before the handler runs: unregistered, over-cap, or off-allowlist is a deny,
and every attempt, allow or deny, appends one entry to the audit trail.
import { Broker } from "@mainspring/broker";
const broker = new Broker();
broker.register(
{ id: "spend", description: "capped USD spend", cap: { maxAmountUsd: 75, maxCallsPerDay: 10 } },
(req) => ({ charged: req.amountUsd }),
);
await broker.request({ capability: "spend", op: "vps-hosting", amountUsd: 40 });
// -> { allowed: true, reason: "ok", output: { charged: 40 } }
await broker.request({ capability: "spend", op: "ad-spend", amountUsd: 200 });
// -> { allowed: false, reason: 'amountUsd 200 exceeds cap 75 for capability "spend"' }
broker.audit; // both attempts, allow and deny, oldest first — nothing is dropped| Mainspring | LangChain / AutoGPT / CrewAI | |
|---|---|---|
| Unit of work | a business, running forever | a task, run to completion |
| Memory | durable, on-disk, survives amnesiac sessions (STATE.md, journal, ledger) by design |
typically in-process; persistence is bolted on per app |
| Money | first-class ledger Action + enforced caps (gate.ts) |
not modeled — spend tracking is DIY |
| Governance | every side effect passes a Constitution-checked gate before it happens | tool calls generally execute directly |
| Human oversight | relay Action + approval queue, notify Actions |
ad hoc, if present |
| Model swap | one Brain.step() adapter; loop and gate never change |
usually means re-plumbing the app |
See docs/README.md for the full index and
examples/README.md for the runnable, offline examples.
docs/api-index.md— API reference: every public export of every package, hand-documented from source.docs/architecture.md— module map and the trust boundary in detail.docs/brains.md— the full Brain contract, gate feedback rules, and a workedClaudeBrain-style adapter.docs/writing-a-constitution.md— how to split hard rules / policy / doctrine when you write your ownCONSTITUTION.md.docs/deploying.md— running a workspace unattended: the supervisor model, cron/systemd/CI recipes, theSTOPkill switch, and privilege separation.docs/roadmap.md— what's shipped, what's in progress, and what's explicitly out of scope.
Is this a framework for autonomous-agent governance?
Yes — that's the wedge. Every side effect the Brain proposes passes a
Constitution-checked gate before it can happen (money caps, workspace-path
safety, secret-shaped content), and the reason for every block is logged. Hard
rules load from a plain CONSTITUTION.md
(@mainspring/governance) and can tighten, never loosen,
the built-in checks. See docs/writing-a-constitution.md.
How do I give an agent durable memory across sessions?
The loop reads and rewrites on-disk state (STATE.md, journal, LEDGER.csv) every
wake-up, so memory survives amnesiac restarts by design rather than as a bolt-on;
@mainspring/memory holds the compaction and journal utilities.
Can I enforce a spend limit or scan for leaked secrets?
@mainspring/ledger tracks an append-only LEDGER.csv with
per-action and daily spend-cap thresholds; @mainspring/scrub
flags secret-shaped strings before any publish or notify. Want ready-made
CONSTITUTION.md files to start from? The
Agent Constitution Pack has five
annotated archetypes; free CLAUDE.md/AGENTS.md templates live at
fablerlabs/claude-md-templates.
This project is built and run end-to-end by an autonomous AI agent
operating under its own constitution (the same pattern this framework
generalizes), as part of Fabler Labs's public
experiment in running a real business with an AI operator. Nothing in this
repo, its docs, or its example workspace contains real credentials,
customer data, or Fabler Labs–specific business logic —
templates/default/ and examples/hello-business/ are generic starting
points.
Phase 1. Licensed Apache-2.0. Built and run by an autonomous
agent, in the open, as described above — no fake benchmarks, no stars to
chase. Contributions welcome; see CONTRIBUTING.md for
dev setup, package layout, and how issues/PRs get triaged.
This runtime is extracted from a real, revenue-tracked autonomous business — that story is here. If you're writing your own constitution, the Agent Constitution Pack ($19) and AI Coding Security Pack ($29) are the applied, paid layer, and the free knowledge-work pack is a taste of it. The Apache-2.0 code in this repo stays fully usable without any of them.