A straightforward, locally-installed multi-agent orchestration dashboard. Configure CLI AI agents you have on your machine (Claude Code, Codex, Aider, Gemini, Copilot, Ollama, β¦), fire off tasks, watch live output, and keep a history β from a loopback web UI. Easy to start, stop, and restart, like Apache.
Your council of agents - Concilium!
- Card-based session UI β each card is an independent agent session with
its own selector, working directory, prompt, output, and (for interactive
agents) input line. Add cards with + New session, close them when done.
Card controls are compact icon buttons: π opens the OS folder picker for
the working directory, βΆ starts the task (turns red while a task is
running, click to kill), >_ opens a pop-out terminal card (see
below), and β€’ expands a single card to fill the main area with a
smooth View Transitions animation between states. When the working
directory resolves to a GitHub repo (via
git remote), an octocat link to the repo appears in the card header. A β§ clone button next to it duplicates the card with the same agent and working directory, then starts the new session immediately. Paths under$HOMEdisplay as~/...shorthand in the cwd field; the server expands them at launch. Drag a card by its header to reorder it on the grid; the new order is persisted to the saved layout. Header controls (select, buttons, GitHub link) stay clickable; dragging is disabled while a card is expanded. - Pop-out terminal cards β the >_ button on any session card opens
an independent shell terminal in a new card (using
$SHELL, inserted right after the triggering card). Useful for running side commands βgit status,ls,tailβ in the same working directory as your agent without leaving the dashboard. Terminal cards expand and close like any other card; closing one ends the shell and drops its history. - Session restore β the card layout (agent, working directory, last task) is persisted server-side in SQLite, so reloading the page or restarting the server brings your sessions back. Closing a card permanently removes it (and the tasks it launched) from the saved layout.
- Two execution modes β piped stdin for one-shot tools, PTY (via
node-pty) for interactive REPL-style agents - Real terminal in the browser β each card embeds an
xterm.js terminal. ANSI/colors/cursor moves render
natively, keystrokes go straight to the agent's stdin, and a
ResizeObserver+ the fit addon drive a resize handshake to the PTY so TUIs reflow correctly when you expand a card or resize the window. - Live streaming of stdout/stderr to the browser via Server-Sent Events, with automatic reconnect after laptop sleep / network drops so the stream resumes without a manual refresh.
- Persistent history in SQLite, plus per-task plain-text logs under
~/.concilium/logs/. Closing a card kills any running task and deletes that session's tasks + logs. - Light / dark / auto theme β defaults to your OS preference
(
prefers-color-scheme); the Auto button in the header cycles to Light or Dark and persists inlocalStorage. - Apache-style lifecycle β
conciliumctl start | stop | restart | status, with optional install as a launchd or systemd--userservice - PATH-based agent discovery β scans
$PATHfor known CLIs and lets you add them with one click - Vanilla web UI β no framework, no build step, just HTML/CSS/JS
- Loopback only (
127.0.0.1) β single-user, no auth
- Node.js 18+ (tested on 24)
- macOS or Linux
- A C toolchain only if
node-pty's prebuilt binaries aren't available for your platform; on macOS arm64/x64 and Linux x64/arm64 the prebuilds are used
External CLIs the server invokes (must be on $PATH):
gitβ required. Used to readorigin/upstreamremotes when detecting the GitHub repo for a card's working directory.zenityβ Linux only, optional. Powers the OS folder picker (π) on GNU/Linux desktops. Without it, type or paste paths into the cwd field. On macOS the picker uses built-inosascript; on Windows it uses built-inpowershell.
git clone git@github.com:jonathanbossenger/concilium.git
cd concilium
npm installThe postinstall step restores the executable bit on
node-pty's spawn-helper (npm strips it during install β without this,
PTY spawns fail with posix_spawnp failed.).
To get conciliumctl on your $PATH:
npm link./bin/conciliumctl start # daemonizes node, writes PID file
./bin/conciliumctl status
./bin/conciliumctl restart
./bin/conciliumctl stop
./bin/conciliumctl logs # tail -f the server log./bin/conciliumctl install # writes launchd plist or systemd --user unit
./bin/conciliumctl status # mode: service
./bin/conciliumctl uninstallThe install step bakes the absolute path to node, the project root, and
your current $PATH into the service definition, so the dashboard can find
agents installed via Homebrew, nvm, etc.
Open http://127.0.0.1:7878 after starting. The page boots with one empty session card; click + New session to add more, or the Γ on a card to close it (kills any running task in that card and deletes its history).
Header controls:
- + New session β adds another card.
- β§ β opens a New Project dialog. Concilium validates the project name against GitHub using your saved token, then creates a new repository (public by default, with an optional private toggle) with an initialized README, clones it into your selected target location, and opens a new session card with that directory pre-filled.
- π₯ / β / βΎ β cycles theme (auto/light/dark); defaults to your OS preference.
- Gear (β) β opens a settings dialog where you can:
- Add, edit, or delete agents
- Scan
$PATHfor known CLI agents and add the ones found - Set or clear an optional
githubTokenused for authenticated GitHub API calls
Concilium can make authenticated GitHub API calls if you provide a personal
access token. A token is required for the New Project flow (β§ in the
header) β repository creation goes through the authenticated
POST /user/repos endpoint and cannot fall back to unauthenticated. For
read-only features (e.g. the active-agent indicator on PR rows) the token is
optional; without one, requests fall back to unauthenticated and are subject
to a much lower rate limit.
Use a classic personal access token rather than a fine-grained one.
Fine-grained tokens are scoped to a single resource owner, so a token tied to
your own account returns 403 forbidden against repositories owned by other
users or organisations β even ones you contribute to. Classic tokens cover
every repository you can already read.
Create a classic token at https://github.com/settings/tokens/new:
- Note β anything memorable (e.g.
Concilium). - Expiration β GitHub recommends setting an expiration date.
- Select scopes β tick
repo(Full control of private repositories). That single scope covers everything Concilium does today: reading issues and PRs on any public or private repository, and creating new repositories (public or private) via the New Project flow. If you never create private repos and don't need to read private issues/PRs,public_repoalone is sufficient. Optionally adddelete_repoif you want Concilium to clean up the GitHub repo automatically when a post-creategit clonefails (rare β usually only flaky networks); without it, the orphaned repo stays on GitHub and the UI surfaces its URL so you can delete it manually. - Click Generate token, copy the value, then paste it into the gear (β) β GitHub token field in the Concilium UI. Submit an empty value to clear it.
State lives entirely under ~/.concilium/:
~/.concilium/
βββ config.yaml # port + optional githubToken + agent list
βββ tasks.db # SQLite history + saved card layout
βββ logs/<id>.log # per-task plain-text output log
βββ server.log # the server's own stdout/stderr
βββ run.pid # standalone-mode PID file
A minimal config.yaml:
port: 7878
githubToken: ""
agents:
- id: claude
name: Claude Code
command: claude
interactive: false
- id: aider
name: Aider
command: aider
interactive: true
args: ["--no-pretty"]interactive: false β stdin is piped in, then closed (one-shot).
interactive: true β spawned under a PTY; stays alive for follow-up input.
githubToken is optional and used for authenticated GitHub API requests.
Edits via the UI take effect immediately. Editing the YAML by hand requires
a restart (conciliumctl restart).
config.yaml may contain a secret token β keep it readable only by your user.
All endpoints are JSON; loopback only.
| Method | Path | Description |
|---|---|---|
GET |
/api/health |
server pid, uptime |
GET |
/api/agents |
list configured agents |
POST |
/api/agents |
create agent {id, name, command, args?, interactive} |
PATCH |
/api/agents/:id |
update fields |
DELETE |
/api/agents/:id |
remove |
GET |
/api/agents/discover |
scan $PATH for known CLIs |
GET |
/api/tasks |
task history (newest first) |
POST |
/api/tasks |
start task {agent_id, prompt?, cwd?} β {task_id} |
POST |
/api/tasks/terminal |
start a $SHELL PTY task {cwd?} β {task_id} (powers pop-out terminal cards) |
GET |
/api/tasks/:id |
task + all events |
DELETE |
/api/tasks/:id |
remove task (kills first if live), drops events + log file |
POST |
/api/tasks/:id/kill |
SIGTERM the running task |
POST |
/api/tasks/:id/input |
send stdin to interactive task {data} |
POST |
/api/tasks/:id/resize |
resize the PTY {cols, rows} (PTY mode only) |
GET |
/api/stream/:id |
SSE: replays past events then streams live |
POST |
/api/system/pick-directory |
open the OS folder picker, returns {path} |
POST |
/api/system/github-url |
{path} β {url} if the directory's origin/upstream remote points at GitHub |
POST |
/api/system/github-items |
{url} β {issues, pulls} for open GitHub issues/pull requests |
POST |
/api/system/github-pulls/action |
trigger a pull request action with {url, pullNumber, action, sha?, mergeMethod?} (currently action: "merge") |
GET |
/api/system/github-token |
returns whether githubToken is configured |
POST |
/api/system/github-token |
save/clear configured githubToken (submit empty to clear) |
POST |
/api/system/new-project/check |
check whether {name} can be used to create a repo with the saved GitHub token |
POST |
/api/system/new-project |
create repo + clone from {name, targetPath, private?} (defaults to public) β {ok, cwd, repoUrl, private} |
GET |
/api/system/layout |
the saved card layout (array of {agentId, cwd, lastTaskId}) |
POST |
/api/system/layout |
replace the saved card layout |
concilium/
βββ bin/conciliumctl # lifecycle CLI
βββ install/ # launchd & systemd templates
βββ public/ # vanilla HTML/CSS/JS UI
βββ scripts/fix-pty-perms.js # postinstall fixup
βββ server/
βββ index.js # Express entry
βββ config.js # YAML load/save (atomic)
βββ discover.js # PATH scan
βββ runner.js # spawn vs. PTY
βββ manager.js # live task registry, broadcast
βββ store.js # SQLite (tasks + events)
βββ util/path.js # tilde expansion (~/foo β /home/me/foo)
βββ routes/
βββ agents.js
βββ tasks.js # incl. /terminal for pop-out shell cards
βββ stream.js
βββ system.js # native OS folder picker
Runtime dependencies: express, better-sqlite3, js-yaml, node-pty,
@xterm/xterm, @xterm/addon-fit (the latter two are served straight from
node_modules via static mounts at /vendor/xterm and
/vendor/xterm-addon-fit β no bundler).
GPL-2.0-or-later. Free as in freedom, not just free beer. See LICENSE.


