← Blog

17 October 2026

Triglav is public: a local orchestrator for Claude Code and Codex agents

ai-agentsclaude-codecodexmcptypescriptopen-source

Triglav is now public at github.com/adam-drag/triglav. It’s a local orchestrator that runs AI coding agents on real tickets the way a small software consultancy works. I keep control of what matters: the goal, the decisions the agents can’t settle, and what gets merged. The agents handle the rest.

A Staff agent plans and delegates, Seniors implement, reviewers check the work, and researchers advise on a shared message board. In Triglav I’m called the Client. In the ten days since I started it, it has run 41 jobs on my own repositories, and 34 of them are done.

Part 1 explained the idea and the roles, and part 2 followed one real job from start to finish. This post is about what’s in the first public release, and how to run it.

The Triglav home page: one client decision waiting, two jobs with sub-jobs, five agents online, and plan usage.

All screenshots in this post come from Triglav’s test stack with a fictional web shop. The agents and the reviewer output are scripted.

Before anything else: Triglav does not include a model and does not call an AI API. It starts and coordinates the Claude Code and Codex CLIs that are already signed in on your machine. Every agent turn, review and researcher run is a request on your own plan, and some of them start without a click. Staff wakes up on events and starts Seniors, and a review round can run several reviewers at once. Watch the Usage page for the first few jobs.

Start a job from a ticket or from a prompt

The New job form takes a ticket link from Linear, Jira or GitHub Issues, or a plain prompt. You give it the repository path and the base branch, and the host runner starts a Staff session for you. If the start fails, the form says why in one sentence, for example when Claude Code hasn’t trusted the folder yet. The failed start then stays as a red bar on every page until you retry or dismiss it.

A prompt job starts in a refining stage. Staff writes the goal, the scope, the non-goals and the acceptance criteria, and asks its open questions on the job’s thread, each with a recommended answer. You answer, edit the proposal, or both, and Staff revises it. While Staff is writing, the fields are locked so it can’t overwrite what you type. Planning starts only when you click Approve. Staff can’t approve its own proposal.

The same form has a table of roles: runtime, model and effort for Staff, Seniors, reviewers and researchers. The model lists come from the CLIs themselves, so there’s nothing to type.

Every push goes through a local review panel

This is the biggest change since part 1. Before a Senior pushes, it asks for a local code review of base_sha..head_sha in its worktree. A panel of read-only reviewers reads the diff and the repository, and the server merges their findings into one verdict.

The panel is a Client setting on the Models page: one strong seat and up to four cheap seats, each with its own runtime, model and effort. The release default is a strong seat on Codex (gpt-6.1-sol, high effort) and one cheap seat on Claude Code (Sonnet 5.5, low effort). A cheap Codex seat was in the default at first. I removed it after a replay on five earlier PRs, where it matched none of Copilot’s 14 first-round findings and one of its five other findings was valid. You can also run up to four instances of the strong reviewer, and each one reads the files of the diff in a different order.

The gate is on the server. submit_review_package is refused unless a finished review of exactly that head commit has the verdict ok. One piece of work gets at most three local rounds, and each round after the first reviews only the fix. The reviewed ranges of a job form one chain from the merge base with the base branch, so a commit can’t slip in between two reviews. The runner checks this in the Senior’s worktree before any reviewer starts.

The reviewers only read. Claude runs with --tools Read,Grep,Glob and Codex with -s read-only, both with every MCP server switched off, so a reviewer has no Triglav token and can’t post anything. The runner computes the diff itself and sends the output back to the server. A reviewer that fails or returns something unreadable makes the round fail, and a failed round never counts as a pass.

The reviewer prompt follows the workflow GitHub describes for Copilot’s code review. A reviewer starts from the diff, searches the repository for callers and sibling code paths, and checks the ticket, the acceptance criteria, the PR description and the repository’s own rules (AGENTS.md, CLAUDE.md, .github/copilot-instructions.md) against the change.

Two local review rounds on a job page. Round 1 has one P1 finding that both seats reported, with the Senior’s triage. Round 2 reviews only the fix and passes.

When a commit passes the local review, the Senior posts one comment on the PR with every local round of the job: seats, tokens, cost, and the findings with the Senior’s answer to each. The server writes that text from its database and quotes everything an agent wrote as code, so a mention or a link inside it does nothing on GitHub.

So far the panel has finished 96 review rounds. 54 passed and 42 asked for changes. Another 14 failed to run. These numbers show how much the gate was used. They don’t measure how accurate the reviewers are, and 42 rounds with changes is not 42 distinct bugs.

Measuring the panel against Copilot

The repository has an evaluation harness in scripts/review-eval/. It replays the panel on three of Triglav’s own PRs, at the commit where Copilot did its first review, and scores the result against Copilot’s findings. Copilot is a useful benchmark here, but a match with Copilot doesn’t prove a finding is correct. The harness is manual, it costs real tokens, and one run per seat is a small sample.

Copilot and CI after the local gate

After the local gate, the Senior opens the PR and runs a Copilot review loop with gh. It gets at most three rounds per PR, and it stops after Copilot recommends approval or after a round with no serious new finding. How strict this is depends on the review mode, which is your setting. Auto uses Copilot where the repository has it. Copilot required refuses a delivery without a clean Copilot review. CI only skips Copilot.

A job is done only when Staff has checked CI itself on the same commit the Senior reported. Merging stays with you. Triglav never merges, deploys, force pushes or changes repository settings.

Because the server can’t run gh itself, it relies on the Seniors to report their Copilot rounds. A Senior still has gh, so these limits are a soft rule. The README says this too.

The Inbox: what needs you

The Inbox collects everything that waits for you. Client decisions are blockers an agent can’t resolve. Each one has the problem, the question, a recommendation, any commands to run in their own copy boxes, and the researchers’ advice. When the recommendation is something the agent can do itself, Accept recommendation answers it with one click. When the decision no longer applies, you can dismiss it without making up an answer.

A client decision in the Inbox: the problem, the question, a command with a Copy button, Staff’s recommendation, and the answer buttons.

The Inbox also lists jobs waiting for your refinement, finished jobs whose PRs may be waiting for a merge, and messages an agent tagged to you. Stopped Staff sessions show up there with a Resume button, for example after a reboot or a usage limit. If a resumed session doesn’t come back in two minutes, the card says so and offers Restart session.

The Operator: a chat that asks before it acts

The Operator page is a chat with Claude Code on your machine. It’s for questions like “why is this job stuck” and “what needs me”. It reads Triglav’s live state, the runner logs and the repository before it answers.

It can’t change anything by itself. The claude process runs with --tools Read,Grep,Glob and no Bash, because a read-only-looking command like git log can still write a file with --output. Its host commands are fixed MCP tools: claude agents, claude logs, docker compose ps and logs, git status and git log. Each one takes only a short id, a service name from a list or a number.

When the Operator wants to act, it puts a card in the chat: pause or cancel a job, poke an agent, resume a Staff, answer a decision, change a model. The card text comes from the database, not from the model’s words. Nothing happens until I click Confirm, and an unanswered card expires after 30 minutes.

An Operator card that asks to pause a job, with Confirm and Deny buttons.

Claude Code, Codex, or both

The host runner checks every five minutes which of claude and codex are installed, and every hour which models each one lists. Every role can run on either CLI. If you only have one, Triglav uses it everywhere and keeps your saved settings for when the other one comes back.

With only Codex, Staff runs as a detached codex exec that can write in the repository and sees your GITHUB_TOKEN. When it needs the network, GitHub or a signed commit, Codex’s automatic reviewer decides, and no human is asked. Use a Codex Staff only on repositories you trust it with. The README lists exactly what it gets.

Researchers are short runs with no session between them. Triglav routes questions, proposals and decisions into a researcher’s inbox and starts a run when there’s something to read. The run answers, marks what it read and exits. Runs are held back when the Codex usage window is nearly used up.

Usage and token cost

The Usage page reads the agents’ own transcripts and shows tokens per day, per model and per agent, and how much of the five-hour and weekly plan windows is used. Codex writes this into every transcript. Claude Code doesn’t, so the repository has a status line script that forwards Claude’s rate limits to Triglav.

Part 1 covered why the cost is mostly turns and cached context, not output. That work is all in the release: Staff wakes only for events it needs, waits up to 50 minutes on its one-hour prompt cache, and compacts at about 280k tokens.

Security

There are three credentials with three audiences. Agents hold an enrollment key that opens the MCP endpoint only. The host runner holds its own key for the runner API. The Client logs in with a password whose scrypt hash sits in .env, and every other API route needs that session by default. The server listens on 127.0.0.1 only.

The server runs in Docker and can’t start processes on the host. The host runner does that, and it never runs a command string from the server. It builds each command itself from a fixed template after it checks every field. The processes it starts get an environment without Triglav’s own secrets.

The limit is that agents run as your OS user. They can read .env, your home directory and your browser cookies. So the credentials make an attack harder, but they don’t stop an agent that deliberately goes after a secret. A real boundary would need a separate OS user or a sandbox, and I haven’t built that. Use a throwaway clone and protect your branches on GitHub while you learn how it behaves.

Running it

You need Linux or macOS with Docker, Node 24 and pnpm, and Claude Code or Codex signed in. gh is needed if Seniors should open PRs. I’ve only run it on Linux.

git clone https://github.com/adam-drag/triglav.git
cd triglav
pnpm install --frozen-lockfile
node scripts/setup.ts            # creates .env with random keys and asks for a dashboard password
docker compose up -d --build     # server, MySQL and dashboard on :7400
node scripts/runner.ts           # the host runner, in its own terminal

Then connect your agents to the MCP endpoint (the README has the one-line claude mcp add-json and the Codex config) and click New job.

Ten days of use

I started Triglav on 7 October. Since then it has run 41 top-level jobs from my work tickets and from Triglav itself, and 34 of them are done. These are my own repositories and my own use, so treat the numbers as early use. 165 agents registered: 42 Staff, 107 Seniors, 10 researchers and 6 reviewers.

It’s early software built and used by one person. CI runs the type check and the unit and coordination tests against a throwaway MySQL on every PR. A Playwright suite drives the dashboard while scripted agents use the real MCP tools, and I run that one locally.

License

Triglav is source-available under the Business Source License 1.1. It is not open source. You can use it for your own work and for your organization’s internal work. You can’t offer it, or a product or service whose value comes mainly from it, to third parties as a hosted service, a managed service or a redistributed product. Each version becomes GPL-2.0-or-later four years after its first public release, and on 12 October 2030 at the latest.

Try it

I’ve only used Triglav on my own repositories, so I don’t know yet how it works with other repositories, other workflows and other people. If you try it, I’d like to hear what works and what breaks. Issues are open on GitHub, and security problems go through the private report described in SECURITY.md.