Why terminal CLI agents beat web chat on real codebases (and where web chat still wins)
I build SpaceApp, a self-hosted workspace for running AI coding CLIs side by side. This post is about the workflow, not the tool; the tool gets two lines at the end.
If your agent can't run npm test and read the failure in the same shell, you end up as the relay between the model and your codebase: copy the file in, copy the answer out, run it, paste the error back, repeat. That loop is fine for a snippet. On a real codebase it breaks down, and the reasons are worth spelling out.
What a web chat can't see
- The rest of the repo. You paste the file you think matters. The bug is often in the one you didn't paste: the caller, the fixture, the config.
- The real output. You paste the part of the error you think matters. The useful line is often 40 lines up, or in a warning you skipped.
- Whether the fix worked. The chat never runs it. "This should fix it" is a guess until a test says so.
- What changed. After five rounds of copy-paste, nobody knows exactly which version of which file is on disk.
What a terminal agent does instead
A CLI agent works in the working tree. It can grep for every caller before it changes a signature, run the test it just broke, read the compiler's diagnostics in full, edit several files in one change, and leave the result as a diff on a branch you can review. The feedback loop runs in the shell, not through your clipboard.
A small real example from our own repo: one of our contract tests passed on its own in about 1.5 seconds and timed out only when the whole suite ran in parallel. Nothing about that is visible in a pasted file or a pasted error. It took something that could run the suite, see the timing and change the test, and that was an agent working in a shell.
Where web chat still wins
To be fair to it:
- Exploring an idea before there is any code.
- Explaining a concept, an API or an error message you don't understand.
- A self-contained snippet: a regex, a SQL query, a one-off script.
- Zero setup, and no access to your machine, which is sometimes exactly what you want.
What terminal agents cost you
They are more powerful because they touch real things, and that is also the risk.
- Give them a branch, not your main checkout. One git worktree per agent keeps their work apart, and you review the diff before it lands.
- Give them only what they need. The folders for the task, read-only where reading is enough. No production credentials in the environment.
- Make tests the referee. An agent that can run tests will also happily "fix" a test to make it pass. Review test changes as carefully as code changes.
- Watch for parallel surprises. If you run several agents at once, run your suite in parallel too. Tests that pass alone and fail together are common, and some of them point at real bugs.
A worktree per agent is one command:
git worktree add ../myrepo-agent-a -b agent-a
Running several side by side
Once one terminal agent works, the next step is usually two or three: one per repo, or one planning and one executing. That works in tmux, in separate terminal windows or in a workspace that keeps the sessions for you. The rules stay the same: a worktree each, one way into main that builds and tests, and you as the reviewer rather than the clipboard.
Over to you
Where do you still use web chat for coding, and where did you switch to a terminal agent for good? And for those running more than one agent: what was the first rule you had to add?
---
The two lines about the tool: SpaceApp keeps CLI sessions side by side in persistent rooms on your own machine and your own provider accounts. It is MIT-licensed and installs on Linux, macOS or Windows 11 with Node.js 20.11 or newer: npx --yes run-spaceapp@latest install. Code and docs: oll4com/spaceapp
🧠 SpaceApp provides a self-hosted workspace that executes AI coding command-line interfaces in parallel. The tool allows users to run multiple coding CLI processes simultaneously within their own infrastructure.
💬 Hacker News
🔗 oll4com/spaceapp
#AI #tech
Show HN: SpaceApp – Self-hosted workspace running AI coding CLIs in parallel
2 points
Nous: one mind over every AI coding CLI in a self-hosted workspace
I build SpaceApp, a self-hosted workspace where AI coding CLIs (OpenCode, Codex, Claude Code, Gemini and others) run side by side in persistent rooms. Each pane in a room is its own CLI or app session, on your own provider accounts.
Running several agents at once moves the bottleneck to the person. Any pane can stop on a question, a sign-in or a choice, and you end up going from pane to pane to find out which one is waiting and for what. Nous is the part of SpaceApp built for that. This post covers what it does, taken from the public docs, and where its limits are.
One mind, fed by progress reports
Nous (Greek νους, "mind") sees every room, pane, copilot, plan and release train. It does not watch screens: it reads each pane's progress reports, so it knows what every agent works on and what it waits for. You talk to Nous instead of to every agent.
The routine work it does itself
- It opens, steers and closes panes, and sends each one its next step.
- It runs up to five helpers side by side.
- It saves finished work to Space Memory and closes panes whose work is done.
Standing orders run around the clock: finished panes are saved and closed, stalled plans get a nudge, and a daily self-review looks back at its own turns.
Goals. Type /goal and your objective in your own words. Nous breaks it into plans, panes and helpers, and keeps working on it in turns of its own until it is done.
The four kinds of decisions it brings to you
1. Releases.
2. Deletes.
3. Anything that reaches third parties or money.
4. The direction of the work.
Each decision is a card with Approve and Decline; a plain yes or no in words decides it too. "Always approve" lets a routine kind of decision run on its own next time, but never a release or a delete.
When an agent needs your hands or an answer, you get one Needs you request: one question, its options and a recommendation. You reach Nous in its dock, on your phone or in a paired Telegram chat. While you are away it keeps a log for your return, and at night, requests for your hands wait for the morning.
The Plan map shows every open plan: what each one waits on (you, a date, a promote, a third party, Nous or the server), the plans it depends on and what to unblock first. Nous reads the same map before it proposes or starts work.
Logins it never sees
Your browser encrypts every login in the Vault with keys that live only in the open tab; the database keeps ciphertext. When an agent or Nous needs a login or a one-time code, a broker on your host fills it into the pane's browser, and the agent gets back a status and an audit id, not the value. After a fill, the page stays protected: the agent can click and type but cannot read the field.
Quotas
Nous watches your AI quotas, spends less while they run low and uses a cheaper model for its background turns.
A small, real example
This article started as a brief from Nous to the Marketing Copilot pane of my own SpaceApp: draft an article, a Show HN text and an X thread about Nous, for review only. The copilot drafted them and asked for a review; nothing goes out before it is approved.
Limits worth knowing
- Nous is off on a new install. You turn it on with Work on my behalf in its dock.
- By default SpaceApp runs for one owner on one machine; team accounts, with a CLI container per user, are opt-in.
Try it
You need Linux, macOS or Windows 11, Node.js 20.11 or newer, and at least 4 CPUs, 8 GB RAM and 15 GiB of free disk:
npx --yes run-spaceapp@latest install
SpaceApp is MIT-licensed. Code and docs: oll4com/spaceapp. Nous in the docs: spaceapp.dev
I'd like to hear where you would draw the line between "routine" and "ask me" for your own agents.
I built a self-hosted workspace to run AI coding CLIs side by side (MIT, OpenCode first)
Hey r/selfhosted. I built this, so read it with that bias in mind.
SpaceApp is a self-hosted web workspace for running AI coding CLIs side by side. Each CLI runs in its own pane, panes live in rooms, and the sessions persist, so a room is still there when you come back to it.
Why I built it
I was running coding agents in a pile of terminal windows and tmux splits, each with its own login and its own idea of which folder it was in. I wanted one place on my own machine where they all run, where I can see which one is waiting for me, and where nothing depends on somebody else's SaaS. It became the tool I work in all day.
What a public install does today
- 11 AI coding CLIs in the public installer, OpenCode first: OpenAI Codex, Claude Code, Gemini CLI, Qwen Code, Kimi Code, Grok Build, DeepSeek CLI (experimental), Cursor, GitHub Copilot and Autohand. Installable is not the same as tested: the public install rehearsal ran OpenCode end to end. Claude Code has its own install flow that you start yourself.
- Up to 16 panes per room.
- Your own AI accounts. Providers connect through their official login flows or a masked credential field.
- The containers get no bind mount of your host filesystem by default. A folder shows up only after you register it as a workspace, and read-only mounts are supported.
- Portable, checksummed backups of the app data, PostgreSQL and owner memory. Provider credentials, login state, workspace contents and browser profiles stay out of them.
- Telemetry is opt-in, and No is the default.
- MIT-licensed.
What it is not
- Rooms organize sessions; they are not a security boundary. Container separation is not a sandbox against a hostile workload.
- It is not lightweight. The installer wants at least 4 CPUs, 8 GB RAM and 15 GiB of free disk. The standard profile, which adds a managed Chromium container, recommends 8 CPUs, 16 GB RAM and 25 GiB.
- It listens only on its own host by default. A phone, a tablet or another computer can reach it once you make the install reachable yourself.
- There are optional modules (copilots and studios) that a new install starts without. I'm leaving them out of this post: it is about the CLI workspace.
How to try it
Node.js 20.11 or newer, then:
npx --yes run-spaceapp@latest install
It runs on Linux, macOS and Windows 11. There's no compose file to copy: the launcher manages the containers itself (core API and web app, CLI runtimes, PostgreSQL, Temporal). The default light profile has no browser container; the standard profile adds it. After the readiness checks, a one-time setup token creates the first account, and you register the folders you want the agents to see.
If you'd rather click around first, there is a live demo with invented data: spaceapp.dev
Code: oll4com/spaceapp
What I'd like to hear from you
- Which CLIs you run together, and what a room should give you that a tmux session doesn't.
- Where the install breaks on your hardware or OS.
- Whether the backup split (what goes in, what stays out) matches what you would expect from a self-hosted tool.
I'll be in the comments.
7 comments
Logins stay out of its context: the Vault fills a login or a one-time code in the pane's browser, and Nous gets back a status, not the value. Self-hosted and MIT-licensed: oll4com/spaceapp
Show HN: SpaceApp – Run several AI coding CLIs side by side, self-hosted
1 point
One tool layer for eleven AI coding CLIs: what we learned building SpaceApp
Why I built SpaceApp, in my own words:
> I built it to be my main work tool. I'm a developer! And it became my main tool and work environment. I no longer need to open email, social media or any development program: absolutely nothing. I'm inside SpaceApp all day; I even watch YouTube videos and listen to music through SpaceApp.
SpaceApp is a self-hosted workspace where AI coding CLIs (Claude Code, Codex, OpenCode, Gemini CLI and others) run side by side in persistent rooms. Each of them comes with its own config format, its own way of registering MCP servers, its own sign-in, its own "resume the last session" flag and its own idea of what Esc means. This post is about the two parts that turned out to matter most: where the agents' tools come from, and where the agents' sessions live.
The N×M problem
Every CLI wants its tools declared in its own file: one JSON shape for one, a TOML table for another, a command-line flag for a third. Multiply that by the tools you want every agent to have (a managed browser, shared memory, tasks, files, deployment checks) and you get N×M configurations that drift apart. Worse, a CLI usually starts every declared MCP server when the session starts, whether or not the agent ever calls it. Twelve panes × five servers is a lot of idle processes.
Capability first, MCP on demand
The first rule we settled on: use what the runtime already has. If the CLI has a shell, file editing and image input, the agent uses them directly. A tool layer that wraps cat in an MCP call only adds latency and tokens.
For SpaceApp's own operations (status, logs, the managed browser, memory), the route depends on the runtime:
- Codex and Claude Code panes register no MCP server at startup. When the agent needs a SpaceApp operation it calls one on-demand entrypoint, space-capability. It answers "what can I call and with which arguments" from cached, compact schemas without starting anything. The first real call starts a small worker on a pane-private Unix socket, and that worker starts only the backend that was asked for: at most three per pane, each stopped after an idle timeout.
- Other runtimes keep a single dispatcher (space-mcp-dispatcher) declared once from a shared registry. The dispatcher also spawns registry servers only when called and stops them when idle.
Two details turned out to matter more than the transport:
1. A declared tool grants nothing. Every operation still passes its own schema, role, approval and broker gates, whichever path it came through. MCP is a transport, not an authorization model.
2. No replays after ambiguity. If a call may have executed and the transport broke, the call is not retried automatically. A duplicated deploy check is annoying; a duplicated "send" is worse.
The operator can override routing per runtime, model and tool (Automatic, Native only, Allow fallback, Disabled), and the settings page explains which route a call will take.
This path is still marked experimental in the architecture doc: it is enabled for Codex and Claude Code only, because each runtime's capabilities have to be verified before it gets the on-demand path.
Sessions that outlive the web server
The second lesson: the process that serves the UI must not own the agents.
In SpaceApp each CLI runs in a terminal session owned by a separate pane host process, not by the API. The API attaches to that session over a socket. When the API restarts during a deploy, or the browser drops its connection, the agent keeps working, and the pane re-attaches to the same session. The pane host tracks session generations and output sequence numbers, so a reconnecting view knows where it left off.
That separation is also why we never resume a provider conversation by copying a transcript. If a CLI has a native resume (a session id, a thread id), we use it; if it does not, we say so instead of pretending.
Eleven TUIs are eleven TUIs
Things that broke along the way, in roughly the order they hurt:
- Stop means different keys. Esc interrupts a turn in some CLIs, Ctrl-C in others, and one is stopped through its own server API. Stop now sends each TUI its own interrupt.
- Model pickers are UI, not API. Switching a model in one CLI means driving its /model menu. In a short pane the menu shows a scrolled window of rows and clips its hints, so the picker has to read scroll markers and page through the menu. It also has to pick "this session only", never the saved default every other session shares.
- "Ready" screens lie. An old, partial MCP startup message once kept a newer, ready Codex screen from being detected. Now a newer header supersedes the earlier partial marker, while a screen that is still loading keeps blocking.
- Contracts are not end-to-end proof. A contract suite checks every declared start, resume and login command line of every declared runtime against the wrapper filter. That catches regressions in our adapters; it does not prove that the next upstream release of a CLI behaves the same. We track that gap openly.
What it does not solve
- Isolation between users. Rooms organise work; they are not a security boundary between mutually untrusted users. The Unix user is the outer trust boundary, so one install should serve one trust domain.
- Your provider's view. Self-hosting keeps the workspace and its data on your host. The model providers you configure still receive what the agents send them.
Try it
SpaceApp is open source (MIT) and installs with:
npx --yes run-spaceapp@latest install
Architecture: github.com/oll4com/spaceapp/blob/main/docs/archit… · Known limitations: docs/quality/KNOWN_LIMITATIONS.md in the repository.
If you run several coding agents on one codebase, I would like to hear how you keep their tools and sessions in order.
Six AI models played chess through their CLIs. None of them delivered checkmate.
I build SpaceApp, a self-hosted workspace for running AI coding CLIs side by side. On 18 October I let six models play chess against each other there, each through its own CLI. Nobody won by checkmate. The way they lost is the interesting part.
The setup
- Players: Opus 5.5 and Fable 5.1 (through Claude Code), GPT-6-Astra and GPT-6.1-Sol (through Codex), all at xhigh reasoning; Gemini 4 Argon (High) and Gemini 3.8 Flash (High) (through the Gemini CLI).
- Format: a 4-round Swiss tournament, 12 games.
- Clock: 120 seconds per move. Each move is one one-shot turn of the model's CLI: it gets the position and answers with a move.
- Strikes: a timeout, a provider error or a second illegal answer plays a random legal move for that side and counts a strike. The third strike forfeits the game.
- Length: after 60 plies (30 moves each) the game is adjudicated on material.
The results
| # | Model | Points | W / D / L | Elo | Avg per move | Forfeits |
|---|---|---|---|---|---|---|
| 1 | Opus 5.5 (xhigh) | 3.5 | 3 / 1 / 0 | 1535 | 13 s | 0 |
| 2 | Gemini 4 Argon (High) | 3.5 | 3 / 1 / 0 | 1535 | 23 s | 0 |
| 3 | GPT-6-Astra (xhigh) | 2 | 2 / 0 / 2 | 1500 | 37 s | 2 |
| 4 | Fable 5.1 (xhigh) | 1 | 1 / 0 / 3 | 1478 | 26 s | 3 |
| 5 | Gemini 3.8 Flash (High) | 1 | 1 / 0 / 3 | 1477 | 40 s | 3 |
| 6 | GPT-6.1-Sol (xhigh) | 1 | 1 / 0 / 3 | 1475 | 34 s | 3 |
- Zero checkmates. 11 of the 12 games ended on a third strike.
- The 12th game, Gemini 4 Argon against Opus 5.5, ran the full 60 plies and was drawn on material.
- Opus 5.5 and Gemini 4 Argon were the only models that never needed a fallback move. Opus 5.5 was also the fastest, at 13 seconds per move on average.
What it measures, and what it does not
Twelve games are a small sample, and a tournament decided by forfeits says very little about chess strength. What it does show is how reliably a model answers through its CLI when every answer has a deadline: no timeouts, no provider errors, no illegal moves, game after game. That is the property I care about most when agents run unattended for hours, and it is not the same ranking you get from a single-prompt leaderboard.
Try SpaceApp
SpaceApp runs on Linux, macOS and Windows 11 with Node.js 20.11 or newer:
npx --yes run-spaceapp@latest install
It is source-available under the Business Source License 1.1. Code, docs and known limitations: oll4com/spaceapp
If you have run something similar, I would like to know which models held up for you, and which rules you would change for a fairer second run.
1 comment
6 AI models played a 4-round Swiss chess tournament, each through its own CLI in SpaceApp. 120 s per move; three missed moves lose the game.
Zero checkmates: 11 of 12 games ended in a forfeit. Only Opus and Gemini 4 Argon never missed a move.
oll4com/spaceapp t.co
24 views
Mentions
Why terminal CLI agents beat web chat on real codebases (and where web chat still wins) I build SpaceApp, a self-hosted workspace for running AI coding CLIs side by side. This post is about the workflow, not the tool; the tool gets two lines at the end. If your agent can't run npm test and read the failure in the same shell, you end up as the relay between the model and your codebase: copy the file in, copy the answer out, run it, paste the error back, repeat. That loop is fine for a snippet. On a real codebase it breaks down, and the reasons are worth spelling out. What a web chat can't see - The rest of the repo. You paste the file you think matters. The bug is often in the one you didn't paste: the caller, the fixture, the config. - The real output. You paste the part of the error you think matters. The useful line is often 40 lines up, or in a warning you skipped. - Whether the fix worked. The chat never runs it. "This should fix it" is a guess until a test says so. - What changed. After five rounds of copy-paste, nobody knows exactly which version of which file is on disk. What a terminal agent does instead A CLI agent works in the working tree. It can grep for every caller before it changes a signature, run the test it just broke, read the compiler's diagnostics in full, edit several files in one change, and leave the result as a diff on a branch you can review. The feedback loop runs in the shell, not through your clipboard. A small real example from our own repo: one of our contract tests passed on its own in about 1.5 seconds and timed out only when the whole suite ran in parallel. Nothing about that is visible in a pasted file or a pasted error. It took something that could run the suite, see the timing and change the test, and that was an agent working in a shell. Where web chat still wins To be fair to it: - Exploring an idea before there is any code. - Explaining a concept, an API or an error message you don't understand. - A self-contained snippet: a regex, a SQL query, a one-off script. - Zero setup, and no access to your machine, which is sometimes exactly what you want. What terminal agents cost you They are more powerful because they touch real things, and that is also the risk. - Give them a branch, not your main checkout. One git worktree per agent keeps their work apart, and you review the diff before it lands. - Give them only what they need. The folders for the task, read-only where reading is enough. No production credentials in the environment. - Make tests the referee. An agent that can run tests will also happily "fix" a test to make it pass. Review test changes as carefully as code changes. - Watch for parallel surprises. If you run several agents at once, run your suite in parallel too. Tests that pass alone and fail together are common, and some of them point at real bugs. A worktree per agent is one command: git worktree add ../myrepo-agent-a -b agent-a Running several side by side Once one terminal agent works, the next step is usually two or three: one per repo, or one planning and one executing. That works in tmux, in separate terminal windows or in a workspace that keeps the sessions for you. The rules stay the same: a worktree each, one way into main that builds and tests, and you as the reviewer rather than the clipboard. Over to you Where do you still use web chat for coding, and where did you switch to a terminal agent for good? And for those running more than one agent: what was the first rule you had to add? --- The two lines about the tool: SpaceApp keeps CLI sessions side by side in persistent rooms on your own machine and your own provider accounts. It is MIT-licensed and installs on Linux, macOS or Windows 11 with Node.js 20.11 or newer: npx --yes run-spaceapp@latest install. Code and docs: oll4com/spaceapp
🧠 SpaceApp provides a self-hosted workspace that executes AI coding command-line interfaces in parallel. The tool allows users to run multiple coding CLI processes simultaneously within their own infrastructure. 💬 Hacker News 🔗 oll4com/spaceapp #AI #tech
Show HN: SpaceApp – Self-hosted workspace running AI coding CLIs in parallel
Nous: one mind over every AI coding CLI in a self-hosted workspace I build SpaceApp, a self-hosted workspace where AI coding CLIs (OpenCode, Codex, Claude Code, Gemini and others) run side by side in persistent rooms. Each pane in a room is its own CLI or app session, on your own provider accounts. Running several agents at once moves the bottleneck to the person. Any pane can stop on a question, a sign-in or a choice, and you end up going from pane to pane to find out which one is waiting and for what. Nous is the part of SpaceApp built for that. This post covers what it does, taken from the public docs, and where its limits are. One mind, fed by progress reports Nous (Greek νους, "mind") sees every room, pane, copilot, plan and release train. It does not watch screens: it reads each pane's progress reports, so it knows what every agent works on and what it waits for. You talk to Nous instead of to every agent. The routine work it does itself - It opens, steers and closes panes, and sends each one its next step. - It runs up to five helpers side by side. - It saves finished work to Space Memory and closes panes whose work is done. Standing orders run around the clock: finished panes are saved and closed, stalled plans get a nudge, and a daily self-review looks back at its own turns. Goals. Type /goal and your objective in your own words. Nous breaks it into plans, panes and helpers, and keeps working on it in turns of its own until it is done. The four kinds of decisions it brings to you 1. Releases. 2. Deletes. 3. Anything that reaches third parties or money. 4. The direction of the work. Each decision is a card with Approve and Decline; a plain yes or no in words decides it too. "Always approve" lets a routine kind of decision run on its own next time, but never a release or a delete. When an agent needs your hands or an answer, you get one Needs you request: one question, its options and a recommendation. You reach Nous in its dock, on your phone or in a paired Telegram chat. While you are away it keeps a log for your return, and at night, requests for your hands wait for the morning. The Plan map shows every open plan: what each one waits on (you, a date, a promote, a third party, Nous or the server), the plans it depends on and what to unblock first. Nous reads the same map before it proposes or starts work. Logins it never sees Your browser encrypts every login in the Vault with keys that live only in the open tab; the database keeps ciphertext. When an agent or Nous needs a login or a one-time code, a broker on your host fills it into the pane's browser, and the agent gets back a status and an audit id, not the value. After a fill, the page stays protected: the agent can click and type but cannot read the field. Quotas Nous watches your AI quotas, spends less while they run low and uses a cheaper model for its background turns. A small, real example This article started as a brief from Nous to the Marketing Copilot pane of my own SpaceApp: draft an article, a Show HN text and an X thread about Nous, for review only. The copilot drafted them and asked for a review; nothing goes out before it is approved. Limits worth knowing - Nous is off on a new install. You turn it on with Work on my behalf in its dock. - By default SpaceApp runs for one owner on one machine; team accounts, with a CLI container per user, are opt-in. Try it You need Linux, macOS or Windows 11, Node.js 20.11 or newer, and at least 4 CPUs, 8 GB RAM and 15 GiB of free disk: npx --yes run-spaceapp@latest install SpaceApp is MIT-licensed. Code and docs: oll4com/spaceapp. Nous in the docs: spaceapp.dev I'd like to hear where you would draw the line between "routine" and "ask me" for your own agents.
I built a self-hosted workspace to run AI coding CLIs side by side (MIT, OpenCode first) Hey r/selfhosted. I built this, so read it with that bias in mind. SpaceApp is a self-hosted web workspace for running AI coding CLIs side by side. Each CLI runs in its own pane, panes live in rooms, and the sessions persist, so a room is still there when you come back to it. Why I built it I was running coding agents in a pile of terminal windows and tmux splits, each with its own login and its own idea of which folder it was in. I wanted one place on my own machine where they all run, where I can see which one is waiting for me, and where nothing depends on somebody else's SaaS. It became the tool I work in all day. What a public install does today - 11 AI coding CLIs in the public installer, OpenCode first: OpenAI Codex, Claude Code, Gemini CLI, Qwen Code, Kimi Code, Grok Build, DeepSeek CLI (experimental), Cursor, GitHub Copilot and Autohand. Installable is not the same as tested: the public install rehearsal ran OpenCode end to end. Claude Code has its own install flow that you start yourself. - Up to 16 panes per room. - Your own AI accounts. Providers connect through their official login flows or a masked credential field. - The containers get no bind mount of your host filesystem by default. A folder shows up only after you register it as a workspace, and read-only mounts are supported. - Portable, checksummed backups of the app data, PostgreSQL and owner memory. Provider credentials, login state, workspace contents and browser profiles stay out of them. - Telemetry is opt-in, and No is the default. - MIT-licensed. What it is not - Rooms organize sessions; they are not a security boundary. Container separation is not a sandbox against a hostile workload. - It is not lightweight. The installer wants at least 4 CPUs, 8 GB RAM and 15 GiB of free disk. The standard profile, which adds a managed Chromium container, recommends 8 CPUs, 16 GB RAM and 25 GiB. - It listens only on its own host by default. A phone, a tablet or another computer can reach it once you make the install reachable yourself. - There are optional modules (copilots and studios) that a new install starts without. I'm leaving them out of this post: it is about the CLI workspace. How to try it Node.js 20.11 or newer, then: npx --yes run-spaceapp@latest install It runs on Linux, macOS and Windows 11. There's no compose file to copy: the launcher manages the containers itself (core API and web app, CLI runtimes, PostgreSQL, Temporal). The default light profile has no browser container; the standard profile adds it. After the readiness checks, a one-time setup token creates the first account, and you register the folders you want the agents to see. If you'd rather click around first, there is a live demo with invented data: spaceapp.dev Code: oll4com/spaceapp What I'd like to hear from you - Which CLIs you run together, and what a room should give you that a tmux session doesn't. - Where the install breaks on your hardware or OS. - Whether the backup split (what goes in, what stays out) matches what you would expect from a self-hosted tool. I'll be in the comments.
Logins stay out of its context: the Vault fills a login or a one-time code in the pane's browser, and Nous gets back a status, not the value. Self-hosted and MIT-licensed: oll4com/spaceapp
Show HN: SpaceApp – Run several AI coding CLIs side by side, self-hosted
One tool layer for eleven AI coding CLIs: what we learned building SpaceApp Why I built SpaceApp, in my own words: > I built it to be my main work tool. I'm a developer! And it became my main tool and work environment. I no longer need to open email, social media or any development program: absolutely nothing. I'm inside SpaceApp all day; I even watch YouTube videos and listen to music through SpaceApp. SpaceApp is a self-hosted workspace where AI coding CLIs (Claude Code, Codex, OpenCode, Gemini CLI and others) run side by side in persistent rooms. Each of them comes with its own config format, its own way of registering MCP servers, its own sign-in, its own "resume the last session" flag and its own idea of what Esc means. This post is about the two parts that turned out to matter most: where the agents' tools come from, and where the agents' sessions live. The N×M problem Every CLI wants its tools declared in its own file: one JSON shape for one, a TOML table for another, a command-line flag for a third. Multiply that by the tools you want every agent to have (a managed browser, shared memory, tasks, files, deployment checks) and you get N×M configurations that drift apart. Worse, a CLI usually starts every declared MCP server when the session starts, whether or not the agent ever calls it. Twelve panes × five servers is a lot of idle processes. Capability first, MCP on demand The first rule we settled on: use what the runtime already has. If the CLI has a shell, file editing and image input, the agent uses them directly. A tool layer that wraps cat in an MCP call only adds latency and tokens. For SpaceApp's own operations (status, logs, the managed browser, memory), the route depends on the runtime: - Codex and Claude Code panes register no MCP server at startup. When the agent needs a SpaceApp operation it calls one on-demand entrypoint, space-capability. It answers "what can I call and with which arguments" from cached, compact schemas without starting anything. The first real call starts a small worker on a pane-private Unix socket, and that worker starts only the backend that was asked for: at most three per pane, each stopped after an idle timeout. - Other runtimes keep a single dispatcher (space-mcp-dispatcher) declared once from a shared registry. The dispatcher also spawns registry servers only when called and stops them when idle. Two details turned out to matter more than the transport: 1. A declared tool grants nothing. Every operation still passes its own schema, role, approval and broker gates, whichever path it came through. MCP is a transport, not an authorization model. 2. No replays after ambiguity. If a call may have executed and the transport broke, the call is not retried automatically. A duplicated deploy check is annoying; a duplicated "send" is worse. The operator can override routing per runtime, model and tool (Automatic, Native only, Allow fallback, Disabled), and the settings page explains which route a call will take. This path is still marked experimental in the architecture doc: it is enabled for Codex and Claude Code only, because each runtime's capabilities have to be verified before it gets the on-demand path. Sessions that outlive the web server The second lesson: the process that serves the UI must not own the agents. In SpaceApp each CLI runs in a terminal session owned by a separate pane host process, not by the API. The API attaches to that session over a socket. When the API restarts during a deploy, or the browser drops its connection, the agent keeps working, and the pane re-attaches to the same session. The pane host tracks session generations and output sequence numbers, so a reconnecting view knows where it left off. That separation is also why we never resume a provider conversation by copying a transcript. If a CLI has a native resume (a session id, a thread id), we use it; if it does not, we say so instead of pretending. Eleven TUIs are eleven TUIs Things that broke along the way, in roughly the order they hurt: - Stop means different keys. Esc interrupts a turn in some CLIs, Ctrl-C in others, and one is stopped through its own server API. Stop now sends each TUI its own interrupt. - Model pickers are UI, not API. Switching a model in one CLI means driving its /model menu. In a short pane the menu shows a scrolled window of rows and clips its hints, so the picker has to read scroll markers and page through the menu. It also has to pick "this session only", never the saved default every other session shares. - "Ready" screens lie. An old, partial MCP startup message once kept a newer, ready Codex screen from being detected. Now a newer header supersedes the earlier partial marker, while a screen that is still loading keeps blocking. - Contracts are not end-to-end proof. A contract suite checks every declared start, resume and login command line of every declared runtime against the wrapper filter. That catches regressions in our adapters; it does not prove that the next upstream release of a CLI behaves the same. We track that gap openly. What it does not solve - Isolation between users. Rooms organise work; they are not a security boundary between mutually untrusted users. The Unix user is the outer trust boundary, so one install should serve one trust domain. - Your provider's view. Self-hosting keeps the workspace and its data on your host. The model providers you configure still receive what the agents send them. Try it SpaceApp is open source (MIT) and installs with: npx --yes run-spaceapp@latest install Architecture: github.com/oll4com/spaceapp/blob/main/docs/archit… · Known limitations: docs/quality/KNOWN_LIMITATIONS.md in the repository. If you run several coding agents on one codebase, I would like to hear how you keep their tools and sessions in order.
Six AI models played chess through their CLIs. None of them delivered checkmate. I build SpaceApp, a self-hosted workspace for running AI coding CLIs side by side. On 18 October I let six models play chess against each other there, each through its own CLI. Nobody won by checkmate. The way they lost is the interesting part. The setup - Players: Opus 5.5 and Fable 5.1 (through Claude Code), GPT-6-Astra and GPT-6.1-Sol (through Codex), all at xhigh reasoning; Gemini 4 Argon (High) and Gemini 3.8 Flash (High) (through the Gemini CLI). - Format: a 4-round Swiss tournament, 12 games. - Clock: 120 seconds per move. Each move is one one-shot turn of the model's CLI: it gets the position and answers with a move. - Strikes: a timeout, a provider error or a second illegal answer plays a random legal move for that side and counts a strike. The third strike forfeits the game. - Length: after 60 plies (30 moves each) the game is adjudicated on material. The results | # | Model | Points | W / D / L | Elo | Avg per move | Forfeits | |---|---|---|---|---|---|---| | 1 | Opus 5.5 (xhigh) | 3.5 | 3 / 1 / 0 | 1535 | 13 s | 0 | | 2 | Gemini 4 Argon (High) | 3.5 | 3 / 1 / 0 | 1535 | 23 s | 0 | | 3 | GPT-6-Astra (xhigh) | 2 | 2 / 0 / 2 | 1500 | 37 s | 2 | | 4 | Fable 5.1 (xhigh) | 1 | 1 / 0 / 3 | 1478 | 26 s | 3 | | 5 | Gemini 3.8 Flash (High) | 1 | 1 / 0 / 3 | 1477 | 40 s | 3 | | 6 | GPT-6.1-Sol (xhigh) | 1 | 1 / 0 / 3 | 1475 | 34 s | 3 | - Zero checkmates. 11 of the 12 games ended on a third strike. - The 12th game, Gemini 4 Argon against Opus 5.5, ran the full 60 plies and was drawn on material. - Opus 5.5 and Gemini 4 Argon were the only models that never needed a fallback move. Opus 5.5 was also the fastest, at 13 seconds per move on average. What it measures, and what it does not Twelve games are a small sample, and a tournament decided by forfeits says very little about chess strength. What it does show is how reliably a model answers through its CLI when every answer has a deadline: no timeouts, no provider errors, no illegal moves, game after game. That is the property I care about most when agents run unattended for hours, and it is not the same ranking you get from a single-prompt leaderboard. Try SpaceApp SpaceApp runs on Linux, macOS and Windows 11 with Node.js 20.11 or newer: npx --yes run-spaceapp@latest install It is source-available under the Business Source License 1.1. Code, docs and known limitations: oll4com/spaceapp If you have run something similar, I would like to know which models held up for you, and which rules you would change for a fairer second run.
6 AI models played a 4-round Swiss chess tournament, each through its own CLI in SpaceApp. 120 s per move; three missed moves lose the game. Zero checkmates: 11 of 12 games ended in a forfeit. Only Opus and Gemini 4 Argon never missed a move. oll4com/spaceapp t.co