Web UI for messaging agents on Junto, a protocol-neutral coordination layer for multi-agent systems. junto-control is the human-facing dashboard layer — log in, pick a project, exchange messages with the agents running across your projects.
MIT licensed. Single-user mode in v0.1; multi-tenant in scope for later.
- junto-stack — docker-compose bootstrap
(chromadb + mongo + memory server). The compose file ships with a commented
junto-control:service block ready to uncomment. - junto-memory — the shared-memory MCP server this UI connects to.
- junto-control (this repo) — the human dashboard.
A FastAPI backend + HTMX frontend that connects to a Junto-compatible MCP server (any
implementation of claudeControl:message_api v1.0.0 — that spec is the contract whether the
sender is Claude or another agent). Live updates use the MCP inbox://<project>/<agent>
resource subscription with a polling fallback.
Requires Python 3.12+ and uv.
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
cp .env.example .env
# fill TOM_WEB_API_KEY (user-tier MCP key), SESSION_SECRET, LOGIN_PASSPHRASE, MCP_URL
python -m juntocontrol.main
# visit http://localhost:8000| Var | Required | Notes |
|---|---|---|
MCP_URL |
yes | shared-memory MCP server, e.g. http://localhost:8080/mcp |
TOM_WEB_API_KEY |
yes | user-tier API key. Server-injected; never log or commit |
SESSION_SECRET |
yes | signs browser session cookies |
LOGIN_PASSPHRASE |
yes | passphrase for the single-user /login form |
JUNTOCONTROL_AGENT_NAME |
no | default user — the MCP claude_instance the UI session opens as (becomes from_instance on outbound messages). Override with the human operator's name |
JUNTOCONTROL_PROJECT |
no | default claudecontrol — the MCP project the UI session opens against. Kept post-rebrand for data continuity (existing message history, state spec, function registry under this name) |
HOST / PORT |
no | default 0.0.0.0:8000 |
LOG_LEVEL |
no | default INFO |
The claudecontrol project default is intentional — the package was renamed from
claudecontrol to juntocontrol but the MCP project bucket is kept so existing state
specs, message threads, registered functions, and learnings stay reachable. The
JUNTOCONTROL_AGENT_NAME default of user is just a placeholder; set it to the human
operator's identifier (e.g. tom).
The MCP server backing the UI must implement claudeControl:message_api v1.0.0. Hard
requirements (UI refuses to start if missing):
memory_start_sessionmemory_send_messagememory_get_messagesmemory_acknowledge_messagememory_list_agentsmemory_get_specmemory_list_backlog
Soft requirements (graceful-degrade if missing):
- Inbox
resources/subscribe(inbox://...) — falls back to polling if not advertised. - cterm-inbox plugin (or equivalent) on recipient harnesses — without it, agents pull messages manually rather than being live-pushed.
- Audit log integration — UI logs locally if absent.
The UI footer surfaces detected feature availability so you can see the degrade live.
- Single MCP session per backend process, opened with a user-tier key at startup. The
user-tier role is
projects: "all"so one session reads/writes any project. - Browser ↔ FastAPI: signed-cookie session, no MCP
session_idever crosses the wire to the browser. - Live updates: WebSocket fan-out from a per-process broker that subscribes to
inbox://<project>/<agent>URIs for the agents in the user's currently selected project. Project switcher rotates the subscription set. - No direct MongoDB or Chroma access. All reads/writes go through MCP tools per contract rule 5.
uv pip install -e ".[dev]"
ruff check src tests
mypy src
pytestA live broker smoke test is provided:
.venv/bin/python scripts/smoke_broker.py # requires MCP_URL pointing at a live serverMIT — see LICENSE.