What this piece is, and what it deliberately is not
Clone it, install it editable, run one example, no API key required. Fifteen minutes from empty terminal to a working agent that produced a real report and audited its own output for fabricated citations. That's the whole arc below, in order: clone, install, doctor, run.
This piece assumes you either already know why sovereign-agent is built the way it is, or don't care yet — you want a working agent on your machine, fast. If you want the why (sessions as directories instead of a database, why the executor parses JSON defensively, the real six-hour debugging session that forced several of those decisions), this site already has six lessons for that: 27 through 32 in the Tools, Memory, and Multi-Agent Systems course. That story is already told there, and told better than a second pass here would tell it.
sovereign-agent's own chapters/README.md names the distinction between those two things better than I can improve on: two dominant patterns exist for teaching a library alongside its code. The Raschka pattern, after Sebastian Raschka's Build a Large Language Model From Scratch, puts the tutorial and the production code in the same tree, so you learn by rebuilding pieces of the real thing. That's what chapters/ in the repo does, and it's also the shape of the six course lessons on this site: rebuild the reasoning, understand the bug each decision removes.
The Howard pattern, after Jeremy Howard's fastai library plus its separate course, treats the library as a sealed box you bring in and use. You don't rebuild the planner. You import it, call one function, and watch an agent complete a task. That's this article.
Install: why a bare pip install will not work for this tutorial
Run pip install sovereign-agent and you get the library. You do not get examples/, chapters/, tests/, or lessons/. That's not an oversight. pyproject.toml excludes them from the wheel explicitly:
[tool.setuptools.packages.find]
where = ["."]
include = ["sovereign_agent*"]
exclude = ["tests*", "chapters*", "lessons*", "examples*"]Reasonable choice for a production dependency. Ships you the library, not four other directories of tutorial scaffolding you didn't ask for. But it means the README's own quickstart, and this tutorial's plan to run a real example, needs the source tree, not just the package. So the install step here is a clone plus an editable install, not a bare pip install.
git clone https://github.com/zeroemployeeorg/sovereign-agent
cd sovereign-agentYou need Python 3.12 or newer. pyproject.toml declares requires-python = ">=3.12", which pip enforces at install time, and sovereign-agent doctor (below) checks your interpreter version first and reports it if it's too old, though the check itself only warns rather than blocking anything by itself.
pip install -e .Editable install means the sovereign_agent package resolves to the files in this clone, and examples/ sits right next to it in the same tree, both importable, both on disk, no wheel exclusion in the way. If you want the optional extras (evidently, otel, voice, docker), install pip install -e ".[all]" instead. The core dependencies either way are openai>=1.40, typer>=0.12, croniter>=2.0, and python-dateutil>=2.8.2.
sovereign-agent doctorThis is the pip-installed CLI's own preflight command, lighter than the contributor-only make doctor, but it checks the things that actually break a first run. Read what it checks before you run anything that calls an LLM.
python -m examples.research_assistant.runNo API key needed. This is the part that proves the install worked.
Run doctor before you run anything that calls an LLM
Here's the order that actually matters, and it's the opposite of what most quickstarts teach. Most READMEs tell you to run the example first and let the error teach you what's missing. sovereign-agent ships a command whose entire job is to tell you what's missing before you hit the error.
sovereign-agent doctor checks, in order: Python version, whether Config.from_env() loads without raising, whether your LLM API key environment variable is actually set, free disk space in your sessions directory (it warns under 1GB free), the mount allowlist, and Config.validate()'s own self-check. Pass --skip-llm and it stops there. Without that flag, and with a key present, it does one more thing. It sends the model a real round-trip message, literally "Reply with just the word OK.", and prints what comes back.
If your API key isn't set, doctor's own output says so plainly: "LLM API key not set. Export {cfg.llm_api_key_env} and retry." That's the whole failure, caught before you've written a line of your own code.
The error you'll hit if you skip doctor and go straight to the README's quickstart
The README's own first example is run_task("What's the weather in Edinburgh?"). It's a good demo of the surface area, and it will fail for anyone who hasn't set an API key, because run_task calls out to a real LLM by default. Here's the actual check, from sovereign_agent/_internal/llm_client.py:
key = api_key or os.environ.get(api_key_env)
if not key:
raise ExternalError(
code="SA_EXT_AUTH_EXPIRED",
message=(
f"LLM API key not available. Set env var {api_key_env!r} "
"or pass api_key= explicitly."
),
retriable=False,
)LLM API key not available. Set env var 'NEBIUS_KEY' or pass api_key= explicitly.
NEBIUS_KEY is the default provider environment variable, for Nebius, chosen per the repo's own .env.example because their free-tier credits cover every example in this repo. If you already ran sovereign-agent doctor first, you saw this coming: its API-key check is the same condition, caught before run_task ever runs.
The fix, once you have a key: export NEBIUS_KEY=sk-... (or pass api_key= directly to the client). But you don't need a key at all for the next section, which is why it's the better first run.
The example that actually works with zero setup: research_assistant
examples/research_assistant/run.py is the simplest complete example in the repo, and it's deliberately safe to run cold. By default it uses a FakeLLMClient, a scripted, deterministic stand-in that drives the same trajectory a real model would, so you can see the full loop without an API key, a network connection, or a bill:
python -m examples.research_assistant.runRun it with a real model instead, once you have a key set:
NEBIUS_KEY=... python -m examples.research_assistant.run --realEither way, the shape is the same: a planner produces a subgoal, an executor calls a tool (web_lookup, scripted in the offline run), the tool result gets written to a file in the session's workspace, and the run completes. What makes this example worth running rather than just reading about is what happens after completion. It prints a dataflow integrity audit.
Every run also leaves a directory behind you can inspect directly, no viewer or query language needed:
session.json holds the forward-only state machine. workspace/report.md is the file the audit checks against web_lookup's actual output. logs/tickets/ is the append-only record of every operation, and logs/trace.jsonl, its sibling under the same directory, is what you'd cat to see exactly which tool got called, in what order, with what result. None of this is specific to the research-assistant example. It's what every scenario in the repo produces, because it's how the session directory works underneath any of them.
Why "it ran successfully" is not the same claim as "it worked"
The repo's own README names the failure mode this audit exists to catch: a framework can have every ticket green, every manifest verified, and still have shipped an LLM's complete fabrication, because tickets and manifests prove the pipeline ran, not that the content is true. The full story behind that lesson, including the actual fabricated code review that forced the fix, is lesson 30 on this site. It is worth reading in full and this piece will not retell it.
What matters here is what the dataflow audit at the end of research_assistant.run actually checks: not "did a tool get called," but "does every claim in the final report trace back to something a tool actually returned." Concretely, it counts how many web_lookup calls happened, how many results came back, and then cross-checks every arXiv ID that shows up in the written report against the IDs web_lookup actually returned. If the model invents a citation that was never in a tool result, the audit flags it: a failing mark next to the fabricated ID, not a silent pass.
The public API surface: what you'd actually import to build your own
Everything in sovereign_agent.__all__, 67 symbols as of v0.2.0, is covered by an explicit semver contract documented in docs/API.md, titled "The 67 public symbols (v0.2.0)," under what the doc itself calls "Contract version: 1." That distinction matters more than it sounds like it should: anything in __all__ is stable within the 0.2.x series, and anything under sovereign_agent._internal, including the llm_client.py module the pitfall above quotes from, can change on any release, including a patch. If you're writing code against this library, import from the public surface, not from _internal, or accept that your integration is pinned to an exact version.
You won't touch all 67 symbols on a first build. The ones that actually come up when you're wiring together your own agent:
run_task: the one-function entry point. It's what the README's quickstart calls; internally it wraps anOrchestrator.register_tool: the decorator that adds a function to the tool registry, the same mechanism the README'sget_weatherexample uses.Config, loaded viaConfig.from_env(): the same calldoctormakes first, and the one that fails loudly if your environment isn't set up right.Session,create_session,load_session: the session/state layer. A session is a directory; these are how you create or reattach to one.Planner/DefaultPlannerandExecutor/DefaultExecutor: the two halves of the loop you can swap out or subclass if the defaults don't fit your task.ToolRegistry,ToolResult,global_registry,make_builtin_registry: the tool layer underneathregister_tool, useful once you want to build a registry scoped to one scenario instead of the global default.OrchestratorandTaskResult: whatrun_taskis a convenience wrapper around, and what you'd reach for directly if you need more control than one function call gives you.
That's the shape underneath the README's four-line example. run_task is the door; Orchestrator is the room; Planner, Executor, and ToolRegistry are what's actually furnishing it. Once you outgrow the one-liner, this is the order you start reading source in.
Questions that come up once you've run it once
Where to go from here
If you got the offline example running and read the audit output, you've done the Howard-pattern version: used the library as a black box, seen a working loop, and know which 67 names are safe to build on. That's a starting point for a scenario of your own. Register a tool, call run_task, read the session directory it wrote.
If you want the Raschka-pattern version, rebuilding the planner, the queue, the ticket state machine yourself, with tests that only pass once your implementation matches the production module, that's chapters/ in the repo: five chapters, five to eight hours of focused work. And if you want the decisions behind why any of this is built this way, rather than just how to call it, that's the six lessons this piece deliberately didn't repeat.
Sessions as directories, forward-only state, SHA-256 manifests, atomic-rename IPC, and the rest, with the production code and the bugs each one removes.

