Bring your own runtime
Every agent framework asks you to marry it.
You pick one, and then you write your tools against its decorator, its schema inference, its session object, its idea of what a message is. Six months later something better ships and the cost of moving is a rewrite of everything you built. That is an uncomfortable bet in a field where the interesting thing changes every few months.
Runspace is built so you never have to make it.
The workspace is not the agent
The insight is boring and the consequences are not: almost nothing people want from an agent product is actually about the model.
Channels, threads, message history that survives a disconnect, file upload with extraction, a scheduler, gateways to Telegram and WhatsApp, a settings surface, rendering tool output as charts instead of paragraphs, tenant isolation — none of that cares which thing generated the text. It is all workspace, and the workspace is most of the work.
So Runspace draws the line there. It owns everything above the model, and it treats what executes a turn as a plug.
apps:
reviewer:
name: Rev
type: claude_code # the only line that decides who answers
soul: agents/reviewer/SOUL.md
Change claude_code to codex and the same agent, in the same channel, with
the same history and the same tools, is answered by something else. Nothing
else in the file moves.
Five, and none of them required
type: | Executes | Needs |
|---|---|---|
agentino | in-process, no subprocess | pip install agentino-framework |
codex | codex exec --json | the Codex CLI on your PATH |
claude_code | claude -p --output-format stream-json | the Claude Code CLI |
pi | pi --print | the Pi CLI |
openclaw | openclaw agent --local --json | the OpenClaw CLI |
The four CLI adapters shell out to a binary you install. That means Runspace does not depend on any of them — they are not in its dependency list, and a workspace that uses none of them installs none of them. Even Agentino, the framework written alongside Runspace, is an optional extra rather than a dependency.
There is a practical consequence worth stating plainly: if you already pay for a Claude or Codex CLI seat, those adapters use it. You can run a whole workspace without a second API bill.
And because the choice is per-app, one workspace can run a Codex-backed reviewer beside an in-process Agentino analyst. They share a channel. Neither knows the other exists.
Why it does not rot
Every project claims to be decoupled. Most are, briefly, and then someone adds an import in a hurry and nobody notices for a year — because a stray import does not break anything. It just quietly turns an optional dependency into a required one, and you find out when a user without that package files an issue about an ImportError at startup.
So the boundary is not a convention here. app_registry.py dispatches on
app.type and imports no runtime at all — it imports the adapter module,
which is a different thing. Everywhere else that touches a runtime does it
lazily, inside the function that needs it, so importing Runspace never loads
one.
The observable result, which is what actually matters: install Runspace
without the [agentino] extra, import the gateway and the registry, and
agentino is not in sys.modules. It is not merely unused — it does not
need to be installed.
A test reads the registry's own source and fails if a runtime import appears in it:
tests/test_app_registry_no_runtime_imports.py
"We intend to stay decoupled" degrades silently. A failing test does not.
That single constraint is what makes a sixth runtime a new file rather than a refactor, and it is why the claim at the top of this page is a property of the code rather than a paragraph in a README.
Writing the sixth
An adapter is one async function:
async def chat(registry, app, message: str, session_id: str) -> dict:
return {"text": ..., "tools_used": [...]}
For an in-process runtime that is nearly the whole job. For a CLI runtime, most of the work is parsing the other tool's output — and most of the maintenance is surviving the day that output changes shape without warning, because it is someone else's release schedule.
The rule that has held up: degrade rather than raise. An unparseable response should return empty text, not take a workspace down on a point release you did not ask for.
What this buys you
Not novelty. The runtimes are other people's work and the adapters are thin on purpose.
What it buys is the ability to be wrong about which runtime is best without paying for it. You can start on Agentino because there is no binary to install, move an agent to Claude Code when you want its coding behaviour, and run both in the same workspace while you decide — and the decision costs a line of YAML each time rather than a migration.
In a field moving this fast, being cheap to change your mind about is worth more than being right the first time.
Both projects are on GitHub and PyPI. Install them.