Runspace
An open-source LLM workspace — the one your team already knows how to use. Shared
channels, threads, @mentions, uploads and history — except the people you
tag are agents, and they have tools.
Ask one a question and the answer arrives as a chart, a sortable table or a row of KPI cards — not a paragraph describing one. Some of the work nobody has to ask for: a routine is a cron line and a prompt, so the morning read is filed before anyone opens the tab.
The whole thing is one YAML file. Below is a workspace that actually runs — Almanac, the demo, is about this size.
Answers that render
An agent emits a fenced block; the frontend renders it as a component. The model never sees the renderer, and a block with the wrong keys shows a visible error rather than failing quietly.
```chart — ten types, bar through sankey and treemap |
```kpi — headline figures |
```datatable — row links, expandable detail, per-row actions |
```insight — the one finding worth flagging |
```mermaid renders natively too, for when the answer is a process rather
than a number.
Bring your own runtime
Runspace is not tied to any one agent framework. Five adapters ship, and an app picks one with a single line of config:
type: |
runs |
|---|---|
agentino |
Agentino, in-process |
codex |
codex exec --json |
claude_code |
claude -p --output-format stream-json |
pi |
pi --print |
openclaw |
openclaw agent --local --json |
The four CLI adapters shell out to a binary you install, so Runspace depends on none of them — and the workspace itself never knows which one answered.
pip install "runspace[agentino,workspace,server]"
A workspace in one file
# workspace.yml
name: Acme Back Office
icon: 🗂
brand_color: '#2F5D62'
apps:
analyst:
name: Ada
role: Data analyst
soul: agents/analyst/SOUL.md
tools: agents/analyst/tools/
model: gpt-5.4-codex
max_turns: 10
python -m runspace.workspace.serve workspace.yml
That gives you chat with streaming, file upload and attachment rendering, message history, a scheduler, and a settings surface — for every agent the file declares.
A complete one is in examples/grid: a single agent over the
UK grid's carbon intensity API — free, keyless, updated every half hour — so
it runs the moment you have a model endpoint, with no data to fetch or seed.
cd examples/grid && python -m runspace.workspace.serve workspace.yml
What you get
| Chat | Server-sent event streaming, tool-call progress, attachments, history that survives a client disconnect |
| Apps | Many agents in one workspace, each with its own persona, tools and model |
| Channels | Inbound Telegram with pairing and group mention routing; outbound replies back to the same thread |
| Routines | Scheduled work declared in routines.yml, executed by a cron service |
| Widgets | Agents emit fenced ```chart, ```datatable, ```kpi, ```insight, ```form, ```file and ```mermaid blocks that the frontend renders as components |
| Runners | Replay a workload or A/B two agent variants, scored by a pluggable scorer |
| Frontend | React components published as @runspace/ui — a single-pane chat and a multi-channel team workspace |
Swappable everything
Storage, vision, transport, embeddings and the clock all sit behind
typing.Protocol definitions, selected from the environment. Tests run
against in-memory and fixture implementations; production picks real ones.
from runspace.protocols import get_store, get_vision, get_file_storage
store = get_store() # FileStore | InMemoryStore | SupabaseStore
vision = get_vision() # CodexVision | FixtureVision
files = get_file_storage() # LocalFileStorage | ...
Which backend you get is decided by environment variables, so the same image runs in a sandbox and in production without a code branch.
Three levels of control
Config only. Ship a workspace.yml and, if you need custom endpoints,
plugin modules. No Python entry point:
plugins:
- myapp.plugins.invoices
CMD ["python", "-m", "workspace.serve"]
A plugin module simply defines whatever it wants collected — router,
cron_executors, startup_hooks, shutdown_hooks, middlewares.
A little code. Call create_app() and pass extras:
from runspace.workspace import create_app
app = create_app(
workspace_yml="workspace.yml",
tenant_id="acme",
extra_routers=[my_router],
extra_startup_hooks=[warm_caches],
)
Full control. Build your own FastAPI app and wire WorkspaceGateway and
AppRegistry yourself. That is the same API the bootstrap uses.
Installing
pip install runspace # contracts, protocols, workspace
pip install "runspace[agentino,workspace,server]" # runtime + FastAPI + uvicorn
The core install stays light — pydantic, pyyaml and httpx, nothing else.
Everything beyond the contracts is an extra you opt into: [agentino] for the
agent runtime, [workspace] for the FastAPI gateway, [server] for uvicorn,
plus [redis], [documents], [scheduler] and [crawler]. [all] takes
the lot.
Runspace does not require any particular agent runtime — that is why the framework is an extra and not a dependency.
Layout
src/runspace/
contracts/ wire shapes — chat, runtime, tool, workspace.yml, scheduling
protocols/ swappable adapters: store, vision, transport, file_storage,
embeddings, transcriber, clock, prompt flattening
workspace/
backend/ gateway, app registry, runtimes, messaging, routines,
attachments, runners, scoring
ingestion/ inbound channels — Telegram polling, pairing, discovery
helpers/ session, messaging and document utilities
runspace_cli/ helper commands behind `runspace <subcommand>`
workspace/
frontend/ React components published as @runspace/ui (an npm package,
deliberately outside the Python tree)
Configuration
| Variable | Purpose |
|---|---|
AI_BASE_URL / AI_API_KEY |
The OpenAI-compatible endpoint agents call |
EMBEDDINGS_BACKEND |
openai or fixture |
EMBEDDINGS_BASE_URL / EMBEDDINGS_API_KEY |
Overrides the AI_* pair for embeddings |
VISION_API_KEY |
Credentials for the vision adapter |
STORE_BACKEND / STORAGE_BACKEND |
Which store and file-storage implementation to build |
CHAT_HISTORY_BACKEND |
sqlite to persist chat history across restarts; in-memory otherwise |
CHAT_HISTORY_DB |
Where that file lives (default .runspace/history.sqlite) |
YAML values support ${VAR:-default}, expanded at load time.
Development
pip install -e ".[dev]"
PYTHONPATH=src pytest -q # the whole suite; testpaths covers every location
ruff check . && ruff format --check .
node --experimental-strip-types workspace/frontend/shared/utils/loosePayload.test.mjs
node --experimental-strip-types --test workspace/frontend/shared/utils/describeSchedule.test.mjs
[dev] exists because the suite needs more than pytest: the protocol tests are
property-based, the document tests need agentino's libraries, and the mirror
tests patch a Supabase client. Installing pytest alone gives a checkout whose
tests cannot collect.
See CONTRIBUTING.md.
Licence
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 runspace-0.2.8.tar.gz.
File metadata
- Download URL: runspace-0.2.8.tar.gz
- Upload date:
- Size: 566.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1fb500a3c6d2467b2bdcb8f8d3db20e3cd87d7b5ff74b4cff20a473d45469efd
|
|
| MD5 |
3060398c67e0f44dbad71cb58944e70d
|
|
| BLAKE2b-256 |
83f2b82754d47e04b4619945e54e65aec2e69b886e4ed1b3b0e8291d37c2eb49
|
Provenance
The following attestation bundles were made for runspace-0.2.8.tar.gz:
Publisher:
release.yml on islavutin-oss/runspace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runspace-0.2.8.tar.gz -
Subject digest:
1fb500a3c6d2467b2bdcb8f8d3db20e3cd87d7b5ff74b4cff20a473d45469efd - Sigstore transparency entry: 2664387112
- Sigstore integration time:
-
Permalink:
islavutin-oss/runspace@a269c3d313ba8d332d5b8ccdd0f7c14b1a3e44f3 -
Branch / Tag:
refs/tags/v0.2.8 - Owner: https://github.com/islavutin-oss
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a269c3d313ba8d332d5b8ccdd0f7c14b1a3e44f3 -
Trigger Event:
release
-
Statement type:
File details
Details for the file runspace-0.2.8-py3-none-any.whl.
File metadata
- Download URL: runspace-0.2.8-py3-none-any.whl
- Upload date:
- Size: 448.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bad804abfd342f383e7949f5031e67847614106576476cc1f618de779ff18d01
|
|
| MD5 |
0049cb57b601e2c3f897e2afde7410c8
|
|
| BLAKE2b-256 |
c6643aa35e0ea9377a6089015f161f4c0adaaa07fe91843ddaac2acd21a529e7
|
Provenance
The following attestation bundles were made for runspace-0.2.8-py3-none-any.whl:
Publisher:
release.yml on islavutin-oss/runspace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runspace-0.2.8-py3-none-any.whl -
Subject digest:
bad804abfd342f383e7949f5031e67847614106576476cc1f618de779ff18d01 - Sigstore transparency entry: 2664387142
- Sigstore integration time:
-
Permalink:
islavutin-oss/runspace@a269c3d313ba8d332d5b8ccdd0f7c14b1a3e44f3 -
Branch / Tag:
refs/tags/v0.2.8 - Owner: https://github.com/islavutin-oss
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a269c3d313ba8d332d5b8ccdd0f7c14b1a3e44f3 -
Trigger Event:
release
-
Statement type: