Running seven coding-agent CLIs from one approval queue

Nagano includes no model. A local daemon starts each agent’s own CLI as a supervised process and records every approval it asks for. How that works, and which agents ask.

A Nagano conversation: the prompt, two bash tool calls with their commands, the agent’s summary and the follow-up composer.A Nagano conversation: the prompt, two bash tool calls with their commands, the agent’s summary and the follow-up composer.

Nagano is a macOS app for coding-agent CLIs. The window is a client of a local daemon on 127.0.0.1:7788, a Node process bundled inside the app. The daemon contains no harness implementation of its own. Each harness is a plugin: a separate process that speaks versioned JSON-RPC over NDJSON on stdio, selected through the nagano.plugins.json lock file and probed at startup. One session gets one process.

Seven harnesses, three protocols

Nagano talks to each CLI over that CLI's own interface. Claude Code streams JSON. Codex speaks its app-server JSON-RPC protocol. Kimi Code is run with --output-format stream-json. GLM is z.ai's Coding Plan, which runs the Claude Code binary against api.z.ai. Grok Build (grok agent stdio) and OpenCode Go (opencode acp) both speak ACP. Antigravity is Google's agy --print.

You install each CLI yourself; Nagano bundles none of them. Each one signs in on its own, and Nagano forwards no key unless you configure one. Health is a probe, not a version check: an ACP initialize handshake for Grok Build and OpenCode Go, the --help flags the plugin passes for Claude Code and Antigravity, a protocol compatibility probe for Kimi Code, the app-server's own init for Codex. Each verdict is cached by the binary's SHA-256, successes only, so a CLI that updates itself is re-verified automatically.

What an interaction is

When a harness asks for approval, asks a question or proposes a plan, the daemon records an interaction. GET /v1/interactions?state=pending is the inbox; POST /v1/interactions/{id}/resolve answers one, with a revision check so a stale answer is rejected. In the app that inbox is "Needs you" on the Dashboard, plus a notification, and each approval opens in the conversation that raised it.

The README lists the rules the daemon holds itself to. Every approval must offer deny or cancel, and any default in the interface must deny or cancel. Approval choices carry explicit scopes, and the execution envelope forbids persistent grants, so "always allow" cannot be expressed. The journal stores the option you chose and the plugin's acknowledgement separately, and presents neither as proof that the side effect happened. A plugin must supersede its unresolved interactions before it can end the turn. An interrupt that arrives first cancels pending approvals. After a daemon restart, a pending interaction becomes uncertain rather than being resolved for you.

A project in Nagano: a new task with model, harness and provider set to Auto, the project’s task defaults, and finished Claude Code conversations.
A project against a throwaway daemon and the public google/uuid repository: the New task card, the project's defaults (permissions set to Ask), and two finished Claude Code conversations.

Which agents ask

Each plugin declares what it can do in nagano-plugin.json. Five declare interaction.request.approval: Claude Code, Codex, GLM, Grok Build and OpenCode Go. Codex goes further and tells command approvals apart from file-change approvals. Claude Code and GLM also expose session.setPermissionMode, which is how a project's permission mode (ask, full or plan) reaches the CLI.

Kimi Code and Antigravity declare no interaction capability. They run non-interactively, so there is nothing to approve mid-turn: you get the result when the turn ends. That is a property of those CLIs today, not a setting in Nagano.

The rest of the window

The conversation view streams the transcript with tool calls, file events and a checkpoint timeline. Its side panel has Context (a token breakdown), Git (the diffstat), Preview and Ongoing. There is no code editor.

A project is a folder. One live session holds one directory at a time, enforced by a workspace lease in SQLite; a second job on a directory that another session owns gets 409 conflict before it is persisted. Git worktrees are how you run parallel lanes on one repository, and the New task sheet offers Same checkout, New worktree, and New worktree carrying your changes.

Orchestrate takes a brief and splits it into lanes across harnesses, in waves, with a plan card and lanes you can stop. The same thing exists on the command line: nagano orchestrate --plugin claude,kimi --start --wait.

Limits worth knowing

  • macOS 15 or later, Apple silicon only.
  • The journal at ~/.nagano/nagano.sqlite stores prompts, tool output and anything a harness prints, unredacted. The README calls the current security level a trusted local MVP.
  • The daemon listens on your LAN for pairing with other Macs and the iPhone app, gated by a QR code. Nagano runs locally, with optional pairing over your network; it is not "nothing leaves your Mac". Prompts and repository content go to each provider through that provider's own CLI.
  • Titles, attention judgements and previews are produced by hidden jobs on your own harness, and they spend your quota.
  • No analytics or crash reporting was found in the source.

More from the team

A Cosmo channel with a thread open beside it: a teammate asks @cosmo for the launch checklist and the agent answers in the same thread with what is still open.A Cosmo channel with a thread open beside it: a teammate asks @cosmo for the launch checklist and the agent answers in the same thread with what is still open.

Building Cosmo

Why agents are members in Cosmo

An agent in Cosmo is a user record with a model, a system prompt and a set of tools. What that one decision changes in the product, and what it rules out.