agentctl GitHub
agentctl · control for coding agents

Every agent on its own track.

One git worktree per task, with its own ports, env and URL, so ten agents can run the same app side by side. Start them in the terminal. Answer them from your phone.

$git clone https://github.com/hanse/agentctl && cd agentctl && make install
working needs you done one track = one worktree, branch, port slot and URL
4agent CLIs: claude, codex, pi, agy
3issue trackers: Linear, Sentry, GitHub
26commands, one for each job
0ports to pick by hand
Two screens

Start in the terminal. Answer from the couch.

agentctl opens each task in Herdr with its own tabs. The same agents show up on your phone a second after they start.

herdr — myapp
WORKSPACES
myappmain
fix-auth⏳ #408
sentry-4x✅ #411
gh-30
shellclaudediffdev~/dev/myapp
How it works

From an issue to a running agent

Give it an issue ID, a link or plain words. agentctl lays the track you would lay by hand.

  1. Branch from a fresh origin/main, named after the task.
  2. Worktree in .worktrees/eng-123, so folder trust carries over.
  3. Ports and env. Copies .env, picks a free port slot.
  4. Prepare. Runs your install commands before any shell opens.
  5. Herdr opens claude, shell and diff tabs.
zsh — ~/dev/myapp
agentctl list
Features

Everything a herd needs

Small, plain tools that each do one thing. Together they let you run many agents without losing track.

Database isolation

Its own database, copied in a blink

Agents run migrations and write test data. Give each worktree its own copy of your local Postgres, so one agent never breaks the data of another.

MYAPP_DEV your local base, the template MYAPP_WT1 MYAPP_WT2 MYAPP_WT3 eng-123 fix-auth gh-30
  • {n} is the worktree's port slot, so the names never clash: myapp_wt1, myapp_wt2, and so on.
  • prepare runs before any shell opens, so the copy is ready when the agent starts.
  • teardown runs on destroy and gc, so old copies do not pile up.
  • Instant with Postgres 18 and file_copy_method = clone on APFS, btrfs or XFS, also for a big database.
  • Postgres only copies a database nobody is connected to. Stop the dev server on main first, or keep a separate template database just for copying.
# ~/.config/agentctl/config.toml
[repos.myapp]
prepare = [
  "npm ci",
  "psql -d postgres -c 'CREATE DATABASE myapp_wt{n} TEMPLATE myapp_dev'",
]
teardown = [
  "dropdb --if-exists myapp_wt{n}",
]

[repos.myapp.env]   # written to each worktree's .env
DATABASE_URL = "postgresql://localhost/myapp_wt{n}"

[repos.myapp.ports]
PORT = 3000
VITE_PORT = 5173
zsh — ~/dev/myapp
$ agentctl ENG-123 Creating worktree .worktrees/eng-123 slot 1 $ npm ci $ psql -d postgres -c 'CREATE DATABASE myapp_wt1 TEMPLATE myapp_dev' CREATE DATABASE claude is starting on ENG-123 env DATABASE_URL=postgresql://localhost/myapp_wt1 $ agentctl destroy eng-123 $ dropdb --if-exists myapp_wt1 Removed .worktrees/eng-123 and branch hanse/eng-123
agentctl phone

The control room fits in your pocket

Start work from the couch, answer a permission prompt in the queue, and get a push when an agent is done. It is a small web app on your own tailnet.

See all
Type or dictate an issue. All agents and loops, by repo.
Reply
See the agent's screen. Tap 1 to say yes, or type an answer.
Push
Right away, also while you sit at the Mac. Pause them for an hour, or until 08:00.
New work
An issue ID, a Linear or Sentry link, or what to do. The Mac runs it like agentctl in a terminal.
Keys for prompts
Enter, Esc, 1–3, arrows, y/n. Enough for every question an agent asks.
Actions
Ask an agent to ship, rebase, share or merge. Or destroy it.
Loops
Last result, cost and next run. Run now, pause, or add one.
Share sheet, Siri
A Shortcut starts work right from the Linear or Sentry app.
Clean up
Runs gc for all repos. Shows what it removes, and asks first.
Only on your tailnet, only for you. The app runs behind tailscale serve, never on the public internet. Only your own Tailscale user gets in, and it can only do the things above. Never a shell.

agentctl phone puts the app on your tailnet and prints a QR code. Scan it, then Share → Add to Home Screen. No App Store, no account.

Loops and machines

Work that runs while you sleep

Put prompts on a timetable. Move agents to machines that never sleep. Keep using the same commands.

Loops

A prompt on a timetable

Each run is a new worktree. It knows what earlier runs found, opens a PR or a report, and destroys itself when there is nothing to do.

# ~/.config/agentctl/config.toml
[repos.myapp.loops.sentry]
every   = "2h"
prompt  = "Fix the most common Sentry issue."
backoff = true   # finds nothing? wait longer

[repos.myapp.loops.deps]
at          = ["07:00"]
prompt_file = "loops/deps.md"
max_waiting = 1   # never two deps PRs
$ agentctl loop list
LOOP    SCHEDULE  NEXT   TODAY  LAST RESULT
sentry  every 2h  14:00  $1.20  pr  TypeError in cart, #415
deps    07:00     07:00  $0.35  nothing  all up to date
Machines

More than one station

Add a Linux VM and work goes where there is room. Every machine keeps its own worktrees. Your Mac only talks to them over ssh.

$ agentctl machine add dev@vm-1 --group hetzner
$ agentctl --on hetzner ENG-123
→ vm-2 (3/8 agents, load 1.2)
$ agentctl list
MACHINE  NAME       STATUS   REVIEW      COST
local    fix-auth   blocked  needed      $3.10
vm-1     eng-123    working  2 findings  $0.42
vm-2     eng-131    working  -           $0.18
vm-2     sentry-4x  done     clean       $1.75
Timetable

The commands

Inside a worktree, leave out the name. Outside, you get a picker with a live preview of each agent.

agentctl ENG-123New worktree and agent for an issue
agentctl -a codex #30Another agent, a GitHub issue
agentctl listAll agents, all repos, with cost
agentctl nextGo to the next agent that needs you
agentctl go eng-123Focus it in Herdr
agentctl devStart the dev server, open its URL
agentctl review --fixSecond agent reviews, author fixes
agentctl feedbackAgent acts on PR comments
agentctl shipPush and open a PR the agent wrote
agentctl upload shot.pngScreenshot into the PR
agentctl shareOpen the app on your tailnet, with a QR
agentctl boardThe agent explains its change on Whiteboard
agentctl gcRemove worktrees whose PR merged
agentctl destroyStop, tear down, remove. Safely.
agentctl config initClaude studies your repo and writes the config
agentctl doctorCheck the setup, with a fix for each problem
Install

Lay the first track

A few commands, and the next task gets its own worktree.

$ git clone https://github.com/hanse/agentctl
$ cd agentctl && make install
$ agentctl watch --install   # notifications and local names, at login
$ agentctl doctor            # checks the rest

Needs macOS, Go, git, Herdr and an agent CLI. Optional: gh, fzf, hunk, Codex, Tailscale.