- Go 53.7%
- Shell 46%
- Makefile 0.3%
agnt
agnt is a host-side server and CLI tool for managing named AI agent sessions in tmux panes.
The server runs on the host (inside the tmux session it manages), accepts REST commands from
anywhere that can reach it — including Claude/opencode instances running in Docker or Podman
containers — and executes the actual tmux operations on the host.
The CLI is a thin REST client that locates the running server via a session file and issues commands to it.
Inspired by Lada Kesseler's talk.
Typical workflow
First-time setup
# 1. Create your tmux session and split it into your desired layout
tmux new-session -s agents
# ... split panes with Ctrl+B % and Ctrl+B "
# 2. Create a workspace in your project directory
cd ~/project
agnt new-workspace
# 3. Edit .agnt.yaml to define your agent types
# (add a types: section with run: commands)
# 4. In each pane, register the agent
# (run this from inside each pane)
# Use --autostart to have the server launch agents automatically
agnt register Alice claude --autostart
agnt register Bob docker-claude --variant go --autostart
# 5. Start the server — agents marked --autostart launch automatically
agnt server start
# 6. Or start agents manually (if not using autostart)
# agnt start Alice
# agnt start Bob
# 7. Verify everything looks right
agnt validate
After reopening tmux
If your pane indices have changed (e.g. new tmux session), run:
agnt validate # see what's missing
agnt remap # reassign agents to current panes (coming soon)
If you use tmux-resurrect, your pane layout — including pane indices — is reliably restored after a system restart. No remap needed.
Working with multiple workspaces
Use --workspace-config to work with a specific config file without changing your current
directory:
agnt --workspace-config ~/teamA/.agnt.yaml validate
agnt --workspace-config ~/teamB/.agnt.yaml server status
Architecture
┌─────────────────────────────────────────────────────┐
│ Host (tmux session) │
│ │
│ ┌──────────────┐ REST ┌───────────────────┐ │
│ │ agnt server │◄──────────│ agnt CLI │ │
│ │ start │ │ (thin client) │ │
│ │ (port 7717) │ └───────────────────┘ │
│ │ │ │
│ │ │──tmux send-keys──► pane A (claude)│
│ │ │──tmux send-keys──► pane B (claude)│
│ └──────────────┘ │
└─────────────────────────────────────────────────────┘
Components:
agnt server start— foreground REST server, runs in the tmux session it will manage. Logs spawns and errors to stdout. Must be started before usingagnt start.agnt <command>— thin CLI client. Discovers the server port from a session file next to.agnt.yamland issues REST requests.
Installation
git clone <repo>
cd agnt
make install
Or build locally:
make build
# produces ./agnt
Requirements: Go 1.21+, tmux
Concepts
Workspace
A workspace is a .agnt.yaml file that describes your agent types and registered agents. agnt
searches for it by walking up from the current directory toward $HOME — so you can run agnt
commands from anywhere inside your project tree.
types:claude:run:"claude --agent {{name}}"docker-claude:run:"docker run --rm -e AGENT={{name}} -e VARIANT={{variant}} my-claude-image"agents:Alice:type:claudepane:"0.0"autostart:trueBob:type:docker-claudevariant:gopane:"0.1"Each agent has:
- name — stable identifier used in all commands
- type — must match a key in the
types:section - variant (optional) — passed to the type's run command via
{{variant}} - pane — tmux window.pane index (e.g.
0.1) - autostart (optional) — if
true, the agent is started automatically whenagnt server startruns
Agent types
Types are defined in the types: section of .agnt.yaml. Each type has a run: field with
the command to send to the pane when agnt start is called. You can add types by editing the
file directly, or with agnt type add (see Commands).
types:simple:run:"claude"named:run:"claude --agent {{name}}"Placeholders
The run: command can include placeholders that are substituted with agent-specific values at
start time:
| Placeholder | Value |
|---|---|
{{name}} |
The agent's name as registered in .agnt.yaml |
{{variant}} |
The agent's variant, or empty string if none is set |
Substitution is plain string replacement. Using any unknown placeholder is an error at start
time. A run: string with no placeholders is used as-is.
Agent names and variants must not contain spaces (enforced by agnt register).
Pane layout
The recommended workflow is to create a fixed tmux split layout first, then register your agents
into it. The pane indices (shown in tmux when you press Ctrl+B q) stay stable as long as your
layout doesn't change.
Agent groups
Groups are alternative agent configurations for the same pane layout. Multiple agents can share the same pane index — but only one runs there at a time:
agents:Alice:{type: claude, pane:"0.0"}# Group 1Bob:{type: claude, pane:"0.1"}# Group 1Charlie:{type: claude, pane:"0.0"}# Group 2Dave:{type: claude, pane:"0.1"}# Group 2You run either Group 1 (Alice+Bob) or Group 2 (Charlie+Dave) in the same two panes. Stop one group before starting the other. The tool doesn't need to know about groups — you decide which agents to start and stop.
Commands
agnt server start [--port <port>]
Starts the REST server in the foreground. Must be run inside a tmux session. Logs to stdout.
agnt server start
# agnt server listening on localhost:7717
- Default port is
7717. Override with--port. - Writes a
.agnt-server.yamlsession file next to.agnt.yamlon start; removes it on exit. - Errors if a server is already running for this workspace.
- Automatically starts all agents marked with
autostart: trueonce the server is ready (see Autostart below).
Run this in a dedicated tmux pane before using agnt start.
Autostart
Agents can be marked for autostart so they launch automatically when the server starts:
agnt register Alice claude --autostart
agnt register Bob docker-claude --variant go --autostart
This sets autostart: true in .agnt.yaml. When agnt server start runs:
- Every agent with
autostart: trueis started in YAML definition order. - Agents already running (a non-shell process detected in their pane) are skipped.
- The server logs each action:
autostarting Alice in pane 0.0: ...orautostarting Bob: already running, skipping.
Agents without autostart: true are not touched.
agnt server status
Checks whether the server is running and prints basic info.
agnt server status
# Server: running
# PID: 12345
# Address: localhost:7717
# Uptime: 3m42s
Queries the server's health endpoint directly — works from inside a container if the server is
reachable (e.g. with --network host and the workspace directory mounted).
agnt start <name>
Starts the named agent by sending its configured command as keystrokes to its registered tmux pane.
agnt start Alice
# Starting Alice in pane 0.0: claude --agent Alice
Requires a running server (agnt server start). Errors if no server is found, the agent name is
unknown, its pane doesn't exist, or its type is not defined.
agnt attach <name> --podman <container-name>
Registers a running podman container as the active container for a named agent. Called from inside a container's start script before launching the main process.
agnt attach Agatha --podman Agatha-9s2sbd7w
# Attached Agatha (podman: Agatha-9s2sbd7w)
The server records the container name in memory (cleared on server restart). Once attached,
agnt server status shows the agent and its container:
Server: running
PID: 12345
Address: localhost:7717
Uptime: 3m42s
Agents: Agatha (podman: Agatha-9s2sbd7w)
Writing a start script
The typical pattern is to generate a unique container name, attach to the server, then start the container with that name:
#!/usr/bin/env bash
set -euo pipefail
SUFFIX=$(tr -dc 'a-z0-9' < /dev/urandom | head -c 8)
CONTAINER_NAME="${AGENT_NAME}-${SUFFIX}"
agnt attach "$AGENT_NAME" --podman "$CONTAINER_NAME"
exec podman run -it --rm \
--name "$CONTAINER_NAME" \
--network host \
--volume /path/to/project:/workspace \
-e AGENT_NAME="$AGENT_NAME" \
my-claude-image
The random suffix ensures the container name is unique if an agent is restarted without the
server noticing (e.g. after a crash). agnt attach replaces any previous entry for the same
agent name.
The script runs on the host (inside the tmux pane), so agnt attach finds the server via
the normal session file lookup.
To automatically clear the attachment record when the container exits, drop exec and call
agnt detach afterwards:
#!/usr/bin/env bash
set -euo pipefail
SUFFIX=$(tr -dc 'a-z0-9' < /dev/urandom | head -c 8)
CONTAINER_NAME="${AGENT_NAME}-${SUFFIX}"
agnt attach "$AGENT_NAME" --podman "$CONTAINER_NAME"
podman run -it --rm \
--name "$CONTAINER_NAME" \
--network host \
--volume /path/to/project:/workspace \
-e AGENT_NAME="$AGENT_NAME" \
my-claude-image
agnt detach "$AGENT_NAME"
If the container exits unexpectedly and the detach call is skipped, use agnt detach manually
to clear the stale record.
The agnt binary inside the container
If the agent inside the container needs to communicate with other agents (via agnt send,
agnt list, etc.), the agnt binary must be available inside the container. Two common approaches:
Copy during image build:
COPY --from=build /usr/local/bin/agnt /usr/local/bin/agntMount at container startup:
exec podman run -it --rm \
--name "$CONTAINER_NAME" \
--network host \
--volume /path/to/project:/workspace \
--volume /usr/local/bin/agnt:/usr/local/bin/agnt:ro \
-e AGENT_NAME="$AGENT_NAME" \
my-claude-image
The container also needs access to the workspace directory (for the .agnt.yaml and
.agnt-server.yaml session file) and must be able to reach the server — typically via
--network host.
agnt detach <name>
Clears the attachment record for a named agent. Use this when the agent process has already
exited but agnt stop was not called — for example, after a container crash or manual kill.
agnt detach Agatha
# Detached Agatha
- If the agent has no attachment record, prints a warning and exits zero.
- If the agent name is not in
.agnt.yaml, prints an error to stderr and exits non-zero. - Requires a running server.
After detach, agnt list shows the agent as stopped.
agnt new-workspace
Creates a new .agnt.yaml in the current directory.
agnt new-workspace
# Created workspace at /home/user/project/.agnt.yaml
Errors if a .agnt.yaml already exists in the current directory. Use --workspace-config to
create a file at an arbitrary path.
agnt type add <name>
Interactively adds a new agent type to .agnt.yaml. Prompts for the run command, then presents
a numbered menu to append placeholders one at a time.
$ agnt type add researcher
Run command: claude --agent
1) name
2) variant
3) done
Choice: 1
1) variant
2) done
Choice: 3
Type "researcher" saved: claude --agent {{name}}
- An empty run command re-prompts.
- An out-of-range or non-numeric menu choice re-prompts.
- Each placeholder can only be added once — once selected it is removed from the menu.
- If no
.agnt.yamlexists in any parent directory, one is created in the current directory.
Update mode
If a type with the same name already exists, the wizard runs as normal. Afterwards:
- Identical result: prints
Type "researcher" already exists with identical config. No update made.and exits. - Different result: shows a diff and prompts to accept or reject (reject is default):
Type "researcher" already exists. Proposed changes:
Field Existing New
──────────────────────────────────────────────────────
run claude --agent {{name}} → claude {{name}} ✏️
Accept changes? [y/N]:
agnt register <name> <type> [--variant <variant>] [--autostart]
Registers the current tmux pane as a named agent. Must be run from inside a tmux pane.
agnt register Alice claude
agnt register Bob docker-claude --variant go
agnt register Carol claude --autostart
- Searches parent directories for an existing
.agnt.yaml; creates one in the current directory if none is found. - Errors if the name or variant contains spaces.
--autostartmarks the agent to be started automatically whenagnt server startruns (see Autostart below).
Re-registering an existing agent
If an agent with the same name already exists, agnt register enters update mode instead of
erroring.
No changes: if the proposed type, variant, and autostart flag are identical to the existing entry, it prints a message and exits:
Agent "Alice" already exists with identical config. No update made.
Changes detected: a side-by-side diff is shown with changed fields highlighted in colour and marked with ✏️. Unchanged fields are shown without highlighting. Reject is the default:
Agent "Alice" already exists. Proposed changes:
Field Existing New
──────────────────────────────
type simple → claude ✏️
Accept changes? [y/N]:
Pressing Enter or n prints No changes made. and exits zero. Typing y updates the config
and prints Updated agent "Alice".
The pane field is never changed by agnt register — use agnt remap (coming soon) to
reassign panes. If the current pane differs from the registered one, a warning is shown after
the outcome message.
agnt validate
Checks the workspace config and reports the status of each agent's pane.
agnt validate
Workspace: /home/user/project/.agnt.yaml
Syntax: OK
Agents (2):
Alice pane 0.0 OK [claude]
Bob pane 0.1 OK [bash]
Summary: 2/2 checks passed
Checks that:
- The workspace file exists and is valid YAML
- Each agent's type is defined in
types: - Each agent's pane exists in the current tmux session
Exits non-zero if any check fails.
agnt agent-info
Prints an onboarding briefing for the running agent: its name, how to send messages to other agents, and how to recognise incoming messages.
agnt agent-info
# You are operating as agent: researcher
#
# To communicate with other agents, use the agnt command-line tool.
# ...
Reads the agent's name from the AGENT_NAME environment variable. Exits non-zero if
AGENT_NAME is not set. Requires no server and no workspace config.
--test flag
Use --test to preview the briefing outside of a live agent session (no AGENT_NAME required):
# Provide a name directly:
agnt agent-info --test alice
# Omit the name — reads the first agent from .agnt.yaml:
agnt agent-info --test
If no name argument is given, the workspace config is loaded and the first agent defined in
agents: (in YAML order) is used. Exits non-zero if no workspace config or no agents are
defined.
Agent-specific briefing file
If .agnt/<name>.md exists in the current directory, its contents are appended to the
briefing output, separated by one blank line. This is a convenient place to give an agent
its role description, available tools, or project context without touching the type definition.
.agnt/
researcher.md ← appended when agent name is "researcher"
helper.md ← appended when agent name is "helper"
A missing file is silently ignored. Works in both normal and --test mode.
Using as a Claude Code hook
You can configure Claude Code to run agnt agent-info automatically at the start of every
session using a UserPromptSubmit hook in .claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "agnt agent-info"
}
]
}
]
}
}
This injects the briefing into the agent's context on the first prompt, so the agent knows its identity and how to reach other agents without needing to be told manually.
Alternatively, call it directly from the type's run: command in .agnt.yaml if you want
it printed to the pane before the agent starts:
types:claude-agent:run:"agnt agent-info && claude"agnt info
Prints version and build information.
agnt info
# Version: 1.0.0
# Commit: abc1234
# Built: 2025年01月01日T00:00:00Z
# Go version: go1.24.1
# Binary: /usr/local/bin/agnt
Global flag: --workspace-config <file>
Override the workspace config file lookup for any command:
agnt --workspace-config ~/other-project/.agnt.yaml validate
agnt --workspace-config /tmp/test.yaml new-workspace
Errors if the specified file does not exist (except with new-workspace, which creates it).
Troubleshooting
When do pane indices change?
Pane indices are stable in most situations, but a few operations will shift them and leave your config pointing at the wrong panes:
| Operation | Effect on indices | What to do |
|---|---|---|
| Detach and reattach | Stable | Nothing |
| Add a new window | Stable | Nothing |
| tmux-resurrect save/restore | Stable | Nothing |
| Split a registered pane | All panes after the split point are re-indexed | Run agnt remap |
| Reorder windows | Window numbers of affected agents change | Run agnt remap |
| Kill server and recreate manually | Indices likely differ | Run agnt remap |
| Close a registered pane | Pane is gone | Remove or remap the agent |
agnt validate reports OK as long as the index number exists somewhere in the current
session — it does not verify that the right process is running there.
pane-base-index
If your .tmux.conf sets pane-base-index to a non-zero value (e.g. 1), agnt captures and
uses whatever index tmux assigns — so a single-pane window at base-index 1 registers as 0.1.
This works transparently; just be aware that your indices won't start at 0.
License
Copyright 2025 David Tanzer (business@davidtanzer.net)
Licensed under the Apache License, Version 2.0. See LICENSE for details.