Important
Early alpha. I’m building Monitter for myself, but I think it has the potential to be useful to others. Expect rough edges and frequent changes. Testers, feedback, and contributions are welcome.
Your agents, together.
A cross-platform workspace for running, watching, and coordinating AI agents. Keep multiple conversations in view, give every project its own workspace, and work with agents on your computer or a remote machine over SSH.
Monitter brings your existing CLI harnesses into one interface. It uses their native sessions and authentication, with native adapters and support for the Agent Client Protocol (ACP).
Known to run on macOS, Android, and iOS. Windows and Linux are untested—we welcome testers and contributions. The mobile apps are paired controllers: agents keep running on the connected desktop or its configured remote hosts.
Real Monitter workspace: two agent chats side by side, with project navigation and monitoring in the sidebar.
- Multiple panes. Keep agent conversations side by side, follow parallel work, and expand the pane that needs your attention.
- Project workspaces. Group chats by project, switch between saved workspaces, and configure working folders for local and SSH hosts. One project can involve several agents and machines.
- Persistent conversations. Keep native session IDs, transcripts, tabs, and execution settings together. Resume work without turning every follow-up into a new session.
- Cross-agent collaboration. Let supported agents discover peers, exchange messages, and delegate linked tasks. The receiving agent uses its own harness and host, and results return to the originating conversation.
- Native and ACP harnesses. Native adapters cover Codex, Claude Code, OpenCode, and Hermes. ACP connects compatible agents through a common protocol, locally or over SSH. Capabilities vary by harness; a successful connection is not a guarantee that every provider feature is supported.
Keep your hands on the keyboard. The searchable Controls palette puts layouts, pane balancing, new chats, terminals, agent creation, and settings within reach. Use ↑ / ↓ to navigate, Enter to select, and Esc to dismiss.
On macOS, ⌘P opens Controls and ⌘K jumps between chats, agents, projects, and channels. Keyboard shortcuts make it easy to move around the workspace without hunting through menus.
Resource monitoring shows the app and its owned harness processes together.
- CPU and RAM graphs. See Monitter and its owned harness processes in the sidebar, then open a resource breakdown with usage history and per-process details. Native resource monitoring is currently macOS-specific.
- Provider usage rings. Watch reported account allowances and reset windows for supported providers, including Codex, Claude, MiniMax, and OpenCode Go. Missing or stale readings are shown explicitly.
- Context and goals. See reported context usage and supported goal budgets alongside the conversation. The goal box stays above the composer while messages scroll.
- Readable activity. Inspect tool calls, available reasoning summaries, errors, approvals, and run details without losing the conversation. Scroll back to read while new output waits for you.
- Git and terminals. Inspect the current branch and changes, view tracked processes, and open a terminal in the chat's working folder.
Persistent agents should not mean an ever-growing collection of idle processes.
Monitter's runtime collector retires eligible local harnesses after more than five minutes of inactivity, freeing their processes and disposable helpers while preserving the conversation and native session. Your next message resumes that session.
Cleanup is conservative: active work, queued messages, pending approvals, and uncertain background jobs keep a runtime alive. It only targets processes Monitter owns. Automatic retirement currently covers eligible macOS Codex app-server, Claude stream-json, and resumable ACP sessions; SSH runtimes are retained.
Configure a host, working folder, and harness executable, then control the agent over SSH from the same workspace.
Monitter uses your system SSH configuration, keys, and host-key checks. The harness must already be installed and authenticated on the remote machine. Native and ACP connections use that machine's session and credentials; Monitter does not replace the harness with its own model API.
- Android and iOS controllers. Pair a phone with the desktop to read conversations, send messages, and stop work. Execution stays on the host.
- Browser sharing. Share selected chats or project scope through an approval-based invitation. Guests join by name, and shared chat supports uploads and read-only model, effort, permissions, and context information where available.
- Observer presence. A sparkling eye shows connected observers with access to a chat; its tooltip lists their names.
- Make it yours. Light and dark themes, configurable accents, interface scaling, tab styles, and flexible pane layouts.
| Platform | Status |
|---|---|
| macOS | Confirmed running; main desktop development and validation platform. |
| Android | Confirmed running as a paired mobile controller. |
| iOS | Confirmed running as a paired mobile controller. |
| Windows | Untested. Build and compatibility reports welcome. |
| Linux | Untested. Build and compatibility reports welcome. |
This is an actively developed project, not a claim of feature parity across platforms. Desktop packaging, native process monitoring, and harness integration need more cross-platform testing. Provider support also depends on the installed CLI or ACP bridge and its version.
The primary desktop GUI uses GPUI and Rust, with a shared Rust backend in
src-tauri/. Both live on main. Tauri/Svelte is retained for Android, iOS
and mobile web; it is not the primary desktop GUI.
npm ci
npm run build
npm run build:gpui
npm run dev:gpuiFor Omarchy / Arch Linux, follow the Linux build guide. For desktop architecture, verification and platform limitations, see desktop-gpui/README.md. Linux and Windows runtime compatibility remains unverified.
npm run check:gpui checks the native desktop. npm run check checks the
Svelte/TypeScript clients. npm run dev serves the web UI; agent execution
requires the Rust backend and an installed, authenticated harness.
Monitter includes a deliberately narrow native MVP for evaluating whether a
Jev-guided route can use less expensive models without reducing coding-task
success. It is a library module (src-tauri/src/model_router.rs), a local CLI,
and an opt-in desktop feature attached to each saved harness. It cannot deploy,
auto-merge, spend money, alter credentials, or grant permissions.
In Settings → Agents → Jev routing, choose one mode per harness:
- Off is the default and makes no Jev call.
- Recommend only classifies a fresh task and records a compact local route trace, but keeps the operator's model selection.
- Safe auto-route may apply the operator's explicit tier-to-model mapping and a recommended reasoning level only when confidence is at least 0.50.
The composer marks enabled routing with a small Jev chip. An explicit composer
model selection always wins. A route requiring human review is stopped before
the harness is created; routing does not change the permission picker or
approve an effect. The desktop command is owner-local and stores only a prompt
fingerprint plus decision/evidence under Monitter app data router-traces/.
Build and run the credential-free mock path from the repository root:
cargo run --manifest-path src-tauri/Cargo.toml --bin harness -- \
run "Find the failing test and fix the smallest underlying bug"
cargo run --manifest-path src-tauri/Cargo.toml --bin harness -- evalAfter cargo build --manifest-path src-tauri/Cargo.toml --bin harness, the
same command is available as src-tauri/target/debug/harness run "…". The
bundled mock provider is intentional: it exercises classification, isolated
worktree creation, evidence capture, reassessment, trace persistence, and the
evaluation report without a model account, shell execution, or live changes.
prompt → Jev classifier → typed routing decision → isolated Git worktree
→ provider adapter → evidence → reassessment → finish/escalate/review
MockJevClassifier is a deterministic local stand-in. Its output has the
typed fields task_kind, model_tier, reasoning_level, execution_mode,
permission_tier, confidence, rationale, and escalation_conditions.
It follows the initial policy: low-cost answer/inspection first, balanced
routes for contained edits and ordinary bugs, strong for refactors, and
frontier inspection plus review for architecture or sensitive work.
An adapter implements AgentProvider and receives this exact request:
AgentRunRequest {
prompt, workspace, model, reasoning_level, permission_tier, max_steps
}Adapters return normalized evidence: executed-command descriptions, test results, uncertainty, code/plan identification, steps used, and optional token and cost fields. This keeps provider/model selection independent from authority. A production adapter should bridge to Monitter's existing native provider/runtime and approval controls; it must never accept a router decision as a permission grant.
The MVP bundles two adapters: mock (safe, deterministic, no model call) and
codex (the installed, authenticated local Codex CLI). For Codex, model tier
maps to MONITTER_ROUTER_FAST_MODEL, MONITTER_ROUTER_BALANCED_MODEL,
MONITTER_ROUTER_STRONG_MODEL, and MONITTER_ROUTER_FRONTIER_MODEL; an
explicit --model wins. If a tier variable is absent, Codex uses its configured
default model and the trace says codex-config-default. The Codex adapter uses
only its read-only or workspace-write sandbox in the router-created Git
worktree, and does not pass --approve-for-me or either bypass flag.
The run command can use TypeSafe Jev for classification while retaining the
side-effect-free mock coding-agent provider. This makes a real HTTPS request to
Jev but does not call a coding model, execute shell commands, or make file
changes. It reads the Keychain-backed Monitter TYPESAFE_API_KEY secret first
(JEV_API_KEY remains a legacy alias), then uses the same preference in the
process environment.
The value is never added to an argv, trace, error, or renderer state.
cargo run --manifest-path src-tauri/Cargo.toml --bin harness -- \
run "Find the failing test and fix the smallest underlying bug" --classifier jevOne POST https://api.typesafe.ai/v1/systemone call asks five parallel Choice
questions: task kind, model tier, reasoning level, execution mode, and minimum
permission tier. The router takes the lowest returned confidence as the
decision confidence and records TypeSafe-reported model, usage, cost when
available, and latency in the trace. A local sensitive-keyword preflight blocks
production, credentials, billing, deployment, deletion, permission, and
migration prompts before any request leaves Monitter.
To run the full local POC, combine the live Jev classifier with Codex:
MONITTER_ROUTER_BALANCED_MODEL="your-codex-model" \
cargo run --manifest-path src-tauri/Cargo.toml --bin harness -- \
run "Find the failing test and fix the smallest underlying bug" \
--classifier jev --provider codex --max-steps 6- Edit-capable runs require a Git workspace and receive a fresh detached worktree under the system temporary directory. The original workspace is not given to the adapter.
- Sensitive signals (production, deploy, credentials, billing, migrations,
deletion, access control, and similar) become
human_review_requiredand stop before the provider is called. - Explicit
--model,--tier, and--reasoning-levelpreferences are kept, but cannot remove a review gate or change the permission tier. - Reassessment recommends escalation when confidence is below 0.50, code or a plan is missing, file/step budgets are crossed, tests fail, uncertainty is reported, or more than one top-level subsystem changes. The MVP never automatically retries on a stronger model.
Each run writes a compact JSON trace under .monitter/router-traces/ (local
state, ignored by Git). The trace uses a SHA-256 prompt fingerprint rather than
storing the raw prompt, and records both decisions, selected provider/model,
permissions, evidence, files touched, test outcome, escalation, cost/tokens if
provided, outcome, and an optional --user-correction note. The live POC
records provider-reported tokens but does not invent a dollar cost when a
provider omits one.
harness eval compares the small representative fixture set against a fixed
strong route and the mock Jev route, reporting success, escalation, mock cost,
mock latency, and incorrect downgrades. These mock figures validate the
evaluation plumbing only; they are not claims about live model quality, price,
or latency. A later live evaluation should run the same tasks with explicitly
approved providers and preserve the resulting traces for review.
Monitter can turn Gmail results from a connected coding agent into native,
clickable mail cards without putting Gmail OAuth inside Monitter. The harness
keeps its own Gmail plugin access. When asked to list or triage mail, it reads
messages through that connector and calls Monitter's built-in
present_mail_batch MCP tool once with up to 20 normalized headers and bounded
snippets. Repeated snapshot calls upsert one persistent task/account inbox by
Gmail message ID; absent messages move to local history rather than producing
another mail block. Each non-empty group is classified in one Jev HTTP request,
rather than paying connection and TLS setup cost once per message.
Provider message/thread IDs remain in Monitter for exact click-to-fetch routing
but are omitted from the Jev request.
Monitter renders provisional low-confidence cards immediately, then enriches
the batch with Jev in the background so Jev network latency does not block the
mail list. Five typed decisions are collected for each message: importance,
intent, whether a reply appears necessary, likely next-action owner, and
suggested action. Cards show the source account, score, confidence, and
pending/Jev/fallback provenance. Set
MONITTER_MAIL_TRIAGE_CLASSIFIER=mock when developing without a live key;
otherwise the Keychain-backed TYPESAFE_API_KEY is used and any failure is shown as
a low-confidence local fallback. The allowlisted key is cached in process after
its first Keychain read and refreshed when the Settings vault changes; it is
never exposed to the UI or persisted outside Keychain.
Clicking a card is an explicit detail request. Monitter sends a visible,
read-only follow-up to the same agent, which reads that exact Gmail message and
returns plain text through present_mail_detail. Full bodies are held in a
bounded process-local cache for 30 minutes: they are not written to SQLite,
Snapshot, visitor sharing, or Monitter's event trace. Mail tool payloads are
redacted before normalized provider activity is persisted.
This milestone is reading and classification only. It does not expose Gmail credentials or provide compose, send, reply, forward, archive, label, delete, attachment-download, background polling, or autonomous mailbox actions. Email content is always untrusted data and Jev never grants additional authority. For the strictest boundary, configure the harness's Gmail connector itself with read-only account scopes: Monitter cannot revoke independent mailbox powers already granted to a provider plugin, but its mail workflow never invokes or exposes mutation tools.
See the protocol and safety contract for the MCP schemas,
limits, cache rules, and owner/visitor boundaries. Run the focused UI fixture
with npm run test:mail-triage:ui.
Platform build instructions:
- macOS desktop:
npm run build:gpui -- --release(see the desktop guide). - Android: Android build and pairing guide.
- iOS: iOS build and device guide.
The macOS build is locally ad-hoc signed; this is not a notarized public installer.
For legacy Tauri/mobile web frontend development, run npm run dev:app-ui, then choose Monitter → Load Hot-Reload UI. Follow the LAN access pairing prompt if requested. Backend changes still require a rebuild. Run only one hot-reload server on port 18420 at a time.
Especially on Windows and Linux: try building the desktop app, connect a harness, and tell us what works and what breaks. Mobile device reports and native/ACP compatibility reports are welcome too.
When opening an issue, include your OS and version, Monitter commit, harness/version, whether the connection is local or SSH, and steps to reproduce. Remove credentials and private conversation content from logs and screenshots.
- Architecture and command boundary
- Read-only Gmail and Jev triage
- ACP adapter and compatibility
- Idle runtime retirement
- Mobile controller
- Validation evidence and known limits
- Shared browser interface
- Design reference
Monitter is independently implemented. Orbit informed early CLI execution and resume patterns. Bundled font licenses are in static/licenses/.
The built-in collaboration MCP runs in Rust over loopback HTTP. Local harnesses connect directly; SSH harnesses use an owned reverse tunnel. Codex, Claude, OpenCode and compatible ACP sessions receive scoped collaboration tools. The Python MCP relay has been removed; other Python integrations remain. See the Rust HTTP MCP notes.


