@turmind/halo
v2.0.7
Published
Halo — multi-agent collaborative workspace. CLI + TUI + HTTP/WS server in one package.
Maintainers
Readme
Halo
Throw in an idea. A team of agents builds it.
A self-hosted AI agent team that works in your project folder. Bring your own model key and drive it from a browser, Slack, Telegram or the terminal. A primary agent breaks the work down and fans it out to sub-agents that run in parallel; every tool call shows up live, and you can interrupt, redirect or take over at any point. Everything the team knows and produces is plain files in the workspace — no hidden memory, no opaque state.

https://github.com/user-attachments/assets/45f86359-2d83-4c61-b937-0747b184340e
Install
Halo runs on Linux (x64 / arm64), macOS and Windows, and needs Node.js 22+. Ubuntu 24.04's own nodejs package is 18 and won't work (halo refuses to start on it), so get 22 first:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs # Ubuntu / Debian
brew install node@22 # macOS (keg-only: add it to PATH as brew prints)
nvm install 22 # with nvm (or: fnm install 22)npm install -g @turmind/halo # one binary, all subcommands
halo setup # interactive: password / port / model keys / optional skills
halo server start # → open http://localhost:9527Bring any one model key — Anthropic, OpenAI (or any OpenAI-compatible endpoint), Gemini, DeepSeek, Kimi, Qwen… An AWS account is not required; Bedrock is just one of the providers (and can use your AWS credential chain instead of a key).
sudo: with a system-wide Node (apt / NodeSource),npm install -gneedssudo; with nvm / fnm it doesn't.- In
halo setup: at Configure model provider keys now? pick Configure… (the default). Pick your provider and paste the key, choose ── Done (the last row; ↑ wraps to it), then press Enter on Switch default agent to …. - On a remote box: run
halo server start -d(plainstartstays in the foreground and dies with your SSH session; on Linux with systemd,-dinstalls a user service that starts at boot), tunnel withssh -L 9527:localhost:9527 user@host, and openhttp://localhost:9527on your machine. Don't open 9527 in a security group — see Status & Limitations. - Linux sandbox: the
workspace/readonlyaccess levels needsudo apt install bubblewrap, and on Ubuntu 23.10+ / 24.04 also an AppArmor profile. Without it the server warns at startup with the fix,/api/healthshowssandbox: null, and non-full sessions can't run shell. - Upgrade:
halo upgrade && halo server restart. A server under systemd restarts throughsystemctl; a system unit (deploy.md Option C) may needsudo systemctl restart halo. Bundled docs, agents and skills refresh on the next start. - Docker / CI:
halo setup --non-interactivewithHALO_DEFAULT_PROVIDER=deepseekandDEEPSEEK_API_KEYset binds the built-in agents and writes the key's<<DEEPSEEK_API_KEY>>placeholder (never the key) into~/.halo/secrets/settings.yaml; keep the variable set for the server too (deploy.md).HALO_PASSWORDis the admin password only. - From source:
pnpm install && pnpm build(pnpm 11).
Desktop app: GitHub releases carry a Windows x64 .exe and a macOS Apple Silicon .dmg (not every release has both) that bundle the server, admin and their own Node runtime — no npm, same ~/.halo/ data, so you can switch later. They're unsigned (macOS "damaged" → sudo xattr -dr com.apple.quarantine /Applications/Halo.app; Windows SmartScreen may warn).
[!IMPORTANT] First message fails with
Could not load credentials from any providers? The built-in agents ship pointing at AWS Bedrock, and the "Bind the default agent to a provider you just configured?" step inhalo setupwas skipped. Re-runhalo setup— it rebinds every built-in agent, the internal/evoones included — or switch the model provider under Agents → default.On EC2 / ECS with an instance role there is no error: an unbound install quietly uses Bedrock Claude on that AWS account instead. Check which model answers in the footer of
halo cli -v "hi", or under Agents → default.
Why Halo
🧬 It rewrites its own prompts — and you review the diff
Halo learns from its own conversations. Run /evo (or let pre-compact trigger it): an internal evolution agent analyzes the session, drafts a patch to the workspace's own prompt files, dry-runs the patched agent in a sandbox against the original scenario, and a scoring agent grades the outcome. You approve or reject in the Evolution tab; approved patches merge back into the workspace. Real file diffs reviewed by you — not silent fine-tuning.

📁 The whole agent team is one folder
Personas, skills, knowledge, session history — the entire agent team lives under .halo/ as plain files:
my-project/
├─ .halo/
│ ├─ agents/ # who's on the team — persona, model, tools per agent
│ ├─ skills/ # what they can do — markdown, injected on demand
│ ├─ docs/ # what they've learned — knowledge they read & write
│ ├─ memory/ # dated decision notes
│ └─ sessions/ # every conversation, replayable
└─ src/ … # your actual projectCommit .halo/ with your code and whoever clones it gets the same agents, skills and knowledge — the real files, not an export (they bring their own model key); /workspace share zips the config without sessions, memory or secrets. Initializing the repo from Halo's Source Control panel writes a .gitignore for sessions, logs, tmp/ and databases; in an existing repo, add those yourself, and keep real keys out of .halo/settings.yaml (use <<ENV>> placeholders).
There's no vector database: .halo/INDEX.md is injected into the prompt every turn, and agents open the docs it points to when they need them. Halo is built the same way — this repo's own .halo/ holds its dev, release and reviewer agents and the docs they work from, and most of its commits were made through Halo itself (they carry the Co-Authored-By: halo trailer).
🌐 One workspace, every screen
Kick off a build in the browser, check progress from WeChat on the metro, drop a follow-up in Telegram or Slack, finish in the terminal. Every channel connects to the same workspace — channels are doors, the workspace is the room — and a full-access account can /session switch to pick up a conversation started elsewhere.
👁 Watch it think
The primary agent's reasoning, every tool call (sub-agents' included) and every file change stream in real time; a sub-agent's full log opens from the Sessions tab and keeps updating while it runs. Interrupts are graceful (conversation repair, not a hard kill), and sub-agents report back when done. You stay in the loop instead of running and praying.

Also in the box
- Per-agent models — each agent picks its own provider and model: the built-ins ship with Claude Opus for the primary agent and Claude Sonnet for the executors it fans out, and routine sub-tasks can go to a cheap model. No code changes.
- IDE-grade admin — chat + Monaco editor + file explorer + git panel + terminal (xterm.js) in one browser tab, in four themes.
- Skills and agents are files — a skill is markdown injected on demand; an agent is a persona plus an
agent.yaml. Workspace-scoped or global, no code required. - Extensions — installable viewers and small apps from halo-hub: 3D models, draw.io, Excalidraw, Jupyter notebooks, a meeting recorder and more. Besides opening files in the editor, an extension can add a page to the activity bar (Halo City) or a button to the chat input toolbar (voice input). Install with
/extension install <id>or a zip under Settings → Extensions (design). - Voice input —
/extension install voice-inputadds a mic to the chat toolbar: click to record, click again to stop, and the text lands at the cursor; it never sends. Speech is transcribed on your own Halo server (SenseVoice-Small + Silero VAD via sherpa-onnx) in Mandarin, English, Cantonese, Japanese or Korean, with Mandarin written in Simplified characters. Audio never leaves your server and no cloud API is involved; the server downloads the ~240 MB model once, when the extension is installed or first used (design). - An optional face — the ✨ button in the chat toolbar pins a particle face (
.halo/canvas/self.html) in the editor, and the agent drives it with hidden markers in its replies: words, pictures and gestures alongside what it says. Off until you turn it on (design). - Cron tasks — scheduled agent runs (recurring or one-shot) whose output fans out to your chat channels.
- Access levels —
full/workspace/readonlyper session, enforced by an OS sandbox (bubblewrap on Linux, Seatbelt on macOS); a sub-agent never gets more access than its parent (how levels are set, limits). - Structured sessions — hierarchical parent ↔ child sessions with async coordination and auto-reports on completion.
- Beyond one workspace — relay work to another workspace on the same server, talk A2A v1.0 with other agent servers, or run headless as an Amazon Bedrock AgentCore Runtime with
halo agentcore. - Observability — set one OTLP endpoint and traces, metrics and logs (GenAI semantic conventions) go to any OpenTelemetry collector;
/api/metricsserves Prometheus gauges (design).
Models
Configured per-agent through one provider-agnostic runtime. AWS Bedrock Claude is the primary target; the rest are first-class. /extension models pulls updated provider configs from the hub without a Halo release.
| Provider | Notes | |---|---| | AWS Bedrock Claude | Primary — Bedrock Invoke API | | AWS Bedrock Mantle | OpenAI GPT-class models via Bedrock | | AWS Bedrock OpenAI-compatible | GPT, Grok, Kimi and GLM models via the bedrock-runtime OpenAI Responses API | | Anthropic | Direct API | | OpenAI | Direct / any OpenAI-compatible endpoint | | DeepSeek | | | Kimi (Moonshot AI) | | | MiniMax | | | Mimo (Xiaomi) | Anthropic-compatible gateway, 1M context | | Qwen (Aliyun) | | | Hunyuan (Tencent) | | | Doubao (Volcengine) | | | Zhipu AI (GLM) | GLM-5.3 family; vision on the Flash models | | Google Gemini | Gemini API (OpenAI-compatible endpoint) — 3.8 Flash, 3.5 Flash-Lite |

Channels
Telegram, Slack, Feishu, WeCom and WeChat all connect outbound — no public URL or open port needed. New channel accounts start at readonly; each onboarding guide says who can reach the bot.
| Channel | Transport | Notes |
|---|---|---|
| Admin | WebSocket | Full-featured browser UI |
| Web | HTTP + SSE | Token-authenticated API, independently deployable — see curl example |
| CLI / TUI | local | Standalone terminal client, embedded agent loop (no server required) |
| Telegram | Bot API | Long polling |
| Slack | Socket Mode | No public webhook required |
| Feishu / Lark | Long-connect | appId + appSecret |
| WeCom | Long-connect | botId + secret (智能机器人, no HTTP send API) |
| WeChat | QR bind | Scan to bind, mobile access |
| ACP adapter | stdio JSON-RPC | halo acp bridges ACP editors (Zed, JetBrains IDEs) onto the Web channel — guide |

Talk to it from curl
The Web channel is a token-authenticated HTTP + SSE endpoint for your own UI or scripts. In the admin, open Channels → Web → Add Account, pick a workspace and access level, and copy the token (shown once). Then:
curl -N -H "x-token: $TOKEN" -H "Content-Type: application/json" \
-d '{"message":"What files are in this workspace?"}' \
http://localhost:9527/api/web/chatThe response is SSE frames — session / thinking / tool_call / stream / complete — full protocol in .halo/docs/guide/channels/web.md.
Halo City
A read-only pixel city that visualizes a live halo server: each workspace is a building, each session an animal citizen — at a desk when working, grabbing coffee or hitting the arcade when idle. Click any citizen to inspect the real thing: live session log, delegation chain, last tool call, token usage. Pure client-side canvas on a single polling endpoint — zero model tokens burned. Since 1.6.5 it installs as a halo-hub extension: /extension install halo-city adds a Halo City entry to the activity bar that opens straight into the city on your admin login (no token to paste), and ⛶ at the top right goes fullscreen — see the design notes.

Tech Stack
- Monorepo: pnpm workspace (
core,server,admin,cli,desktop,acp-adapter) - Backend: Hono + WebSocket, single Node.js 22+ process on port 9527 (ESM, TypeScript strict)
- Frontend: Next.js 15 static export, served directly by Hono
- Agent: custom orchestration loop, provider-agnostic
ModelRuntimeinterface - Storage: SQLite + Drizzle ORM — no external services to stand up
Docs
.halo/INDEX.md— project overview + doc index.halo/docs/guide/— user guide.halo/docs/requirements/overview.md— product concept.halo/docs/design/architecture.md— backend architecture.halo/docs/design/evolution.md— self-evolution design.halo/docs/guide/channels/— per-channel onboarding guides.halo/docs/dev/deploy.md— deployment (systemd / Nginx).halo/docs/dev/env.md— env vars, build commandsCHANGELOG.md— what changed in each releaseCLAUDE.md— development instructions for Claude Code
Status & Limitations
Halo is young — treat it as an early-stage project:
- The sandbox guards writes and credentials, not the network. In
workspace/readonlysessions, bubblewrap (Linux) or Seatbelt (macOS) limits writes to the workspace and temp dirs (readonly: temp dirs only) and hides~/.halo/secrets,~/.ssh,~/.awsand similar paths; the rest of the host stays readable and outbound connections work. The threat model is accidental damage and path escape by a trusted agent — not containing a malicious skill or extension, or a prompt-injected session sending out what it can read. - Windows hosts have no sandbox. There a
workspacesession is effectivelyfull, andreadonlycan read any path the halo process can — don't hand out non-fullchannel tokens on a Windows host expecting isolation (dev/tools.md). - The admin is single-tenant, on plain HTTP, on all interfaces. One password (5 failed logins lock that IP out for 15 minutes); whoever holds the admin cookie controls the server — every workspace, shell as the server user, every channel credential. Keep port 9527 behind a firewall, VPN or SSH tunnel, or a reverse proxy with TLS (deploy.md §10), and give other people channel accounts with their own access levels instead of the admin login.
- No MCP support. Agents can't use MCP servers as tools, and Halo doesn't serve MCP itself. To reach an MCP server, wrap it in a skill whose script calls it — the bundled
aws-knowledgeskill does this for the AWS Knowledge MCP server. - Tests are unit/regression-level. CI runs them on every push and PR to
main; there's no end-to-end or integration suite yet. - APIs and on-disk formats may still change between versions. Expect rough edges while things stabilize.
If you hit something broken or surprising, please open an issue — early feedback is genuinely useful right now. Security reports go through SECURITY.md.
Contributing
PRs and issues are welcome — CONTRIBUTING.md has the build / test / commit conventions and the two packaging gotchas worth knowing before you start. Everyone participating is expected to follow the Code of Conduct.
License
MIT
