A small, fast, open-source home for AI coding agents.
One place for your folders, your terminal, and the right account, per project.
Download · Features · Remote access · Architecture · Development
Each work folder, with all its repos, gets a terminal, an agent, and the right account. Switch
between them like Slack workspaces.
The daemon owns the terminals, so your agents keep running when you close the window. The GUI,
whether the desktop app or the browser from your phone, is just a viewport onto them.
Grab the latest build for your platform from the
releases page:
.dmg (Apple Silicon and Intel)-setup.exe installer (or the .msi).AppImage (or the .deb / .rpm packages)Note: macOS builds are not notarized. On first launch, open System Settings >
Privacy & Security and click “Open Anyway” (or right-click Soromi and choose Open).
Soon the builds will be signed with an Apple developer account.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
The daemon owns the terminals, so any viewport that speaks the protocol can attach, including
a browser. Open Soromi from your phone or another machine and get the same live session: watch the
output stream, type into it, run a skill, and answer permission prompts with a tap.
Control is exclusive and hands off cleanly. Move to the desktop app and it takes over; come back to
the web client and it asks to take control again, so two devices never fight over the same terminal.
The web viewport is responsive: a full sidebar-and-tabs layout on desktop, and a bottom-tab layout
tuned for touch on mobile.
Remote access is off until you pair a device, and even then the link is built so nothing in the
middle can read your session:
SOROMI_RELAY_ACCESS_KEY /~/.soromi/config.json), no rebuild required. The relay is a small, separate,I built Soromi because I was tired of juggling a separate editor window for every project and
wrestling my agents into the right context. Setup was manual and fiddly, and I kept worrying
about mixing up accounts that were meant for different things.
I just wanted one place: the folders, the skills, and the terminal together, so I could jump
between projects, get a nudge when an agent needs me, keep the machine awake while it works, and
eventually glance at what it is doing from my phone.
The tools I tried were often heavier than I wanted or did far more than I needed, and left me
more confused than productive. So Soromi stays small and gets out of the way.
A provider is a coding-agent CLI Soromi can run, isolate per account, and listen to. Adding one
is a small entry in the provider registry (crates/daemon/src/config.rs).
| Provider | 🔐 Account isolation | 🔔 Event cues | 📁 Folder scoping | ⚡ Skills |
|---|---|---|---|---|
[✅] CLAUDE_CONFIG_DIR |
[✅] settings.json hooks |
[✅] --add-dir |
[✅] commands + skills | |
[✅] CODEX_HOME |
[☑️] done + /hooks |
[➖] first folder | [✅] prompts + skills | |
[✅] GROK_HOME |
[☑️] Stop hook |
[➖] first folder | [➖] not yet wired |
✅ full support · ☑️ partial, needs a trusted hook · ➖ not applicable
Notes:
soromi.space.json.Soromi is one idea repeated everywhere: the daemon is the product, and every UI is just a
viewport onto it. The daemon owns all state (PTYs, workspaces, accounts, the file tree,
notifications); viewports are stateless and interchangeable. The same protocol runs over a trusted
local socket or an end-to-end-encrypted relay, so your phone’s browser and the desktop app are the
exact same client, just a different transport.
VIEWPORTS (stateless)
┌───────────────┐ ┌───────────────┐
│ Desktop GUI │ │ Web PWA │ React + Zustand + xterm.js
│ (Electron) │ │ (phone) │ render from messages, send input
└───────┬───────┘ └───────┬───────┘
│ local WS │ relay WS (E2EE)
│ (localhost) │ XChaCha20-Poly1305
│ │
│ ┌───────┴───────┐
│ │ Relay │ content-blind pipe
│ │ │ (forwards ciphertext)
│ └───────┬───────┘
│ │ dial-out, no open ports
┌───────┴─────────────────────┴─────────┐
│ DAEMON (Rust) │ sole state authority
│ PTYs · workspaces · accounts │ one WebSocket protocol
│ file tree · status · hooks │ (single source of truth)
└───────────────────┬───────────────────┘
│ spawn + isolate + listen
┌───────────────────┴───────────────────┐
│ PROVIDERS (agent CLIs) │ one folder + one registry
│ Claude Code · Codex · Grok · … │ entry per provider
└───────────────────────────────────────┘
Principles that hold the design together:
crates/protocol) and theProvider trait, so adding an agent is a newcrates/protocol) and the TypeScript types arecrates/
protocol/ Rust: the wire protocol (serde types), the single source of truth
daemon/ Rust: PTY sessions, account resolution, status, agent hooks, WS server
packages/
protocol/ TypeScript types generated from crates/protocol (do not edit by hand)
client/ Shared viewport engine + transports (local WS, E2EE relay)
relay/ Content-blind WebSocket relay that pairs a daemon with a remote viewport
gui/ React + Zustand + xterm.js viewport (runs in the desktop app's webview)
web/ Touch-first PWA viewport for the phone/browser, on the shared engine
apps/
desktop/ Electron app that spawns the daemon and renders the gui
Each package and crate has a README describing its boundaries.
Requires Node 22+, pnpm 10, and a stable Rust toolchain.
pnpm install # install workspace deps
pnpm build # build every package + the desktop bundle (turbo)
pnpm typecheck # type-check the TypeScript packages
pnpm lint # lint with biome
pnpm test # run the vitest suite
pnpm gen:protocol # regenerate the TypeScript protocol types from the Rust crate
The Rust crates have their own gate:
cargo fmt --check
cargo clippy --all-targets
cargo test
Run it:
pnpm dev:desktop # the full app (Electron: builds the daemon + gui, then launches)
Or iterate on the two processes separately:
pnpm daemon # the Rust daemon (serves the local WebSocket)
pnpm dev # the GUI dev server against that daemon
Project rules and conventions live in CONTRIBUTING.md.
MIT, see LICENSE.