Published on

9agent: run Claude Code, Pi or Hermes on any model with one command

9agent: run Claude Code, Pi or Hermes on any model with one command
Authors
On this page

This is one piece of my AI coding agent setup. It covers the launcher I use to start every agent.

The problem

Claude Code is my favourite agent harness. The hooks, the skills, the subagents, the way it edits files. But out of the box it talks to one provider, and I have a gateway, 9Router, sitting in front of six Antigravity accounts, two Codex Pro subscriptions, a Claude Max subscription, OpenCode Go and LongCat.

Claude Code can be pointed somewhere else with environment variables. The trouble is remembering them. Five variables, model IDs that change every few weeks, and a different mechanism again for Pi and Hermes. Anything hardcoded goes stale fast.

So I wrote 9agent.

9agent flow: pick agent, pick model from the gateway, pick mode, then exec the agent. A table shows how each agent reaches 9Router and what --yolo becomes

What it does

Run it with no arguments and it asks three questions:

  1. Which agent? Claude Code, Pi or Hermes.
  2. Which model? A searchable list, fetched live from the gateway's /v1/models. Mine has a few hundred entries, so search matters.
  3. Which mode? Safe, or skip permission prompts. On the host, or in Docker.

Then it starts the agent and steps aside.

npm i -g 9agent
9agent

Once I know what I want, I skip the questions:

9agent -a claude -m claude-fusion,ag/gemini-3.8-flash-high,glm-5.3-flash

Claude Code on three models at once

Claude Code has three model slots: Opus for heavy work, Sonnet for everyday work, Haiku for small background calls. Give 9agent a comma separated list and it fills them in order. The command above resolves to:

ANTHROPIC_BASE_URL=http://localhost:20128/v1
ANTHROPIC_DEFAULT_OPUS_MODEL=claude-fusion
ANTHROPIC_DEFAULT_SONNET_MODEL=ag/gemini-3.8-flash-high
ANTHROPIC_DEFAULT_HAIKU_MODEL=glm-5.3-flash
CLAUDE_CODE_SUBAGENT_MODEL=claude-fusion

You can check this without starting anything, using --print-only:

Terminal output of 9agent --print-only showing the resolved Claude Code environment variables, with the key redacted

Claude Code still believes it has an Opus, a Sonnet and a Haiku. Behind them:

  • Opus is a fusion combo. Several models answer, and the answers get merged.
  • Sonnet is Gemini Flash on the Antigravity pool. Fast, and plenty for most edits.
  • Haiku is GLM Flash. Cheap, for the small calls Claude Code makes in the background.

Same CLI, same hooks, same skills. Different brains.

Pi and Hermes

Pi and Hermes do not take a base URL from the environment. They read it from their own config files. 9agent reads those files to find the gateway, but it never writes them. If an agent needs a modified config, it gets a temporary copy, and the original file is never touched.

The permission flag also differs per agent. --yolo becomes --dangerously-skip-permissions for Claude Code, --yolo for Hermes, and nothing for Pi, which has no permission system. I do not have to remember which is which.

The sandbox

9agent -a claude -m ag/gemini-3.8-flash-high --yolo --sandbox

--sandbox runs the same agent in Docker. Only the current directory and the agent's home are mounted, and anything the host would execute, like hooks and plugins, is mounted read-only.

Sandbox mounts: current directory and agent home read-write, hooks and plugins read-only, the rest of the disk not mounted; network stays on

I use it when I let an agent run unattended with permissions skipped. It limits how much of the filesystem a confused agent can damage. It is not a security boundary against a hostile agent: the container still has network access, because it has to reach the gateway. The README is explicit about that, and I would rather say it plainly than oversell it.

Two design rules

9agent resolves a model, execs the agent, and passes its exit code back. That is the whole job. Two rules keep it that way:

  • Never rewrite a config file you own. Tools that silently edit your dotfiles are how you lose an afternoon.
  • Never supervise what it starts. No wrapping, no proxying, no restarts. Signals and exit codes are the agent's own, so it behaves exactly like running the agent directly.

Small things that turned out to matter

  • --print-only prints the resolved environment and command without launching anything. It is the fastest way to answer "what is this agent actually talking to?"
  • No gateway means a clear error and exit 1, never a hang. A launcher that hangs is worse than no launcher.
  • Keys are saved once at a masked prompt, per gateway URL, in a file only you can read. They never go into shell history.

Where it fits

On my setup, 9agent runs in the Ubuntu terminals on my Windows PC that I reach through Herdr. Every pane that starts an agent starts it with 9agent, and every request it makes goes through 9Router.

It is MIT licensed and on npm. If you already run a gateway that serves /v1/models, it should work with yours too.