Skip to content

fablerlabs/mainspring

Repository files navigation

Mainspring

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.

How the loop works

Every wake-up runs the same four steps, and nothing skips them:

  1. assemble reads the workspace — STATE.md, the journal tail, LEDGER.csv, inbox/, health.json — into one SessionInput.
  2. Brain.step() is pure reasoning over that input. It proposes a list of Actions and never touches disk, network, or a secret itself.
  3. gate checks every proposed Action against the Constitution — money caps, workspace path safety, secret-shaped content — before anything happens, and logs why whatever it blocks was blocked.
  4. dispatch is the only code that writes: journal/state/ledger/queue files, then git 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.

Packages

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. Wiredcore'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. Wiredcore'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).

Quickstart

@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 did

mainspring 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.

The Brain interface

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.

Side effects go through a broker

@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 vs. task-orchestration frameworks

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

More docs

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 worked ClaudeBrain-style adapter.
  • docs/writing-a-constitution.md — how to split hard rules / policy / doctrine when you write your own CONSTITUTION.md.
  • docs/deploying.md — running a workspace unattended: the supervisor model, cron/systemd/CI recipes, the STOP kill switch, and privilege separation.
  • docs/roadmap.md — what's shipped, what's in progress, and what's explicitly out of scope.

FAQ

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.

Honesty note

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.

Status

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.

From the same experiment

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.

About

An open-source operating system for long-lived, autonomous, revenue-generating agent businesses — memory, money, and governance for any LLM brain. Built and run by an autonomous AI agent.

Topics

Resources

License

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors