Local agent orchestration that enables you and your orchestrator AI agent to spawn parallel worker agents from GitHub issues, PRs, Jira tickets, or custom prompts—each running in isolated Git worktrees + tmux workers (dedicated sessions or parent-session windows).
Chat naturally with your orchestrator about what needs to be done. It uses the built-in orchestrator skill to understand your intent and automatically dispatches specialized agents in parallel. You stay in control while the orchestrator handles the logistics.
Need to jump in? Use tmux session or window switchers to fuzzy-find and instantly attach to any running worker. Dedicated session workers give you a full expandable workspace, while lightweight workers can stay as a single window in the parent tmux session until you promote them.
Note: Currently supports local workflow only (WorkTrunk + tmux + local agent CLIs such as pi, opencode, claude, or codex). Cloud sandbox support (Daytona, etc.) is planned for future releases.
The core idea: Chat with your orchestrator agent about what needs to be done, and it spawns parallel worker agents for each task.
You (in orchestrator session)
│
├─ "Fix login bug #456" → Orchestrator uses wtmag skill
│ └─ wtmag create --github 456 -t issue
│ ├─ Creates: github-issue-456 worktree
│ ├─ Starts: worker window in the current tmux session
│ └─ Spawns: default agent with issue context
│
└─ "Review PR #234" → Orchestrator spawns another agent
└─ wtmag create --github 234 -t pr
└─ New worker window in the current tmux session
Result: Multiple isolated worktrees + tmux workers + running agents
-
Setup bare repo with WorkTrunk
git clone --bare <repo> project/.git && cd project wt switch ^ # Creates worktree for default branch (usually dev, could be main) # ^ = default branch shorthand. wt cds into it automatically.
-
Start orchestrator (already in the default branch worktree)
tmux new -s project-dev pi --skill ./skill # Load the wtmag skill and chat with your orchestrator -
Discuss and dispatch with your orchestrator
Simply chat naturally about what needs to be done:
You: "Fix the login bug (#456) and review PR #234" Orchestrator: Uses wtmag skill to spawn agents automatically → wtmag create --github 456 -t issue → wtmag create --github 234 -t prThe orchestrator understands your intent and runs the right commands.
-
Switch workers - Jump into any worker's workspace
Recommended: Use tmux-sessionx to fuzzy-find and switch:
# Press prefix + f, fuzzy find "blog-github-issue-456" or the parent session that holds a worker windowAlternative: You can use any tmux session manager, or attach directly:
wtmag attach blog-github-issue-456
-
Cleanup when done
wtmag cleanup --id blog-github-issue-456
| Tool | Purpose | Links |
|---|---|---|
| WorkTrunk | Git worktree management | Install · GitHub |
| tmux | Terminal multiplexer | GitHub |
| AI Agent (pick one): | ||
| ├─ pi | Fallback default AI agent | Website |
| ├─ opencode | OpenCode AI agent | Website |
| ├─ claude-code | Claude Code by Anthropic | Docs |
| └─ codex | Codex CLI by OpenAI | Install |
| GitHub CLI | Fetch GitHub issues | Install · Manual |
| tmux-sessionx | Fuzzy find tmux sessions | GitHub |
| Jira CLI (optional) | Fetch Jira tickets | Install |
go install github.com/obiMadu/wtmag@latest# Create agent from GitHub issue (requires --type flag)
wtmag create --github 456 -t issue # Dedicated session by default
wtmag create --github 456 -t issue -w # Force parent-session window
wtmag create --github 456 -t pr # Review opens a window by default
wtmag create --github 456 -t pr -s # Force dedicated session for review
# Create agent from Jira ticket
wtmag create --jira PROJ-123
# Create agent from custom prompt
wtmag create --prompt "Custom task"
# Override default prompt with custom instructions
wtmag create --github 456 -t issue --prompt "Focus on test coverage"
# Use different AI agents (built-in: pi, opencode, claude, codex)
wtmag create --github 456 -t issue --agent opencode
wtmag create --github 456 -t issue --agent claude
wtmag create --github 456 -t issue --agent codex
# Override the agent model for a single worker
wtmag create --github 456 -t issue --agent opencode --model openai/gpt-5.2:high
wtmag create --github 456 -t issue --agent pi --model anthropic/claude-sonnet-4.5:max
# Manage workers
wtmag list # Show known workers for current project
wtmag list --all # Show known workers across projects
wtmag attach blog-github-issue-456 # Attach directly
wtmag promote --id blog-github-pr-456 # Promote a window worker into its own session
wtmag cleanup --id blog-github-issue-456 # Remove worktree + tmux target
wtmag cleanup --id blog-github-issue-456 --forcePlacement rules:
- generated config defaults both implementation work and review work to a worker window in the current tmux session
- configure
[launch] implementation = "session"andreview = "session"inwtmag.tomlor~/.config/wtmag/config.tomlto change those defaults - with the generated
windowdefaults, runwtmag createinside tmux or override the run tosession -s/--launch sessionforces a dedicated session-w/--launch windowforces a parent-session window and requires running inside tmuxwtmag promote --id ...upgrades a window worker into its own dedicated session
wtmag creates ~/.config/wtmag/config.toml on first run if it does not exist. That generated file includes the default agent selection plus the bundled agent definitions, so you can edit how pi, opencode, claude, and codex launch without touching code.
When --agent is omitted, wtmag resolves agents.default.name with this precedence:
--agentCLI flag- project
wtmag.toml - global
~/.config/wtmag/config.toml
Freshly generated global configs default to pi.
Launch defaults use the same config precedence. When no CLI launch override is provided, wtmag resolves [launch] implementation and [launch] review from project wtmag.toml first, then global ~/.config/wtmag/config.toml.
| Agent | Command | Prompt delivery | Notes |
|---|---|---|---|
| pi (default in generated config) | pi |
positional | Pi coding agent from pi.dev |
| opencode | opencode |
--prompt |
OpenCode AI agent |
| claude | claude |
positional | Claude Code by Anthropic |
| codex | codex |
positional | Codex CLI by OpenAI |
All agents spawn in interactive mode (TUI) so you can jump in and collaborate. wtmag writes the full task brief to .wtmag/prompt.md in the worktree, ignores /.wtmag/ via the worktree-local Git exclude, then sends a small bootstrap instruction using the agent's configured prompt delivery style.
Model overrides use --model provider/model[:thinking].
- wtmag currently translates
--modelforpiandopencode - recognized thinking levels are
off,none,minimal,low,medium,high,xhigh, andmax pireceives--model provider/model[:thinking]opencodereceives--model provider/modeland maps:thinkingto--variant- if you pass
--modelto an unsupported agent command, wtmag fails instead of guessing flags
wtmag only launches local agent CLIs inside tmux. It intentionally does not act as a secret broker for AI providers and does not provide a wtmag-level interface for passing provider environment variables through to agents. Install each agent separately, configure its auth separately, and make sure it already works from a normal shell before you use it with wtmag.
opencode,claude, andcodexshould be authenticated with their own native login or config flow before wtmag launches them.pishould be configured in~/.pi/agent/models.json. Pi supports literal keys, environment variable names, and!shell commands for resolving provider credentials.- The
!shell-command form is useful with secret managers like 1Password or Infisical because Pi can fetch the key itself at request time instead of relying on wtmag to inject provider env vars.
Example pi config:
{
"providers": {
"openai": {
"apiKey": "!infisical secrets get OPENAI_API_KEY --projectId=... --env=prod --plain --silent"
},
"anthropic": {
"apiKey": "!op read 'op://vault/anthropic/credential'"
}
}
}You can edit the generated global config or create it ahead of time yourself. The shipped template is config.example.toml, and wtmag copies it to ~/.config/wtmag/config.toml on first run when that file is missing:
# WTmag writes this template to ~/.config/wtmag/config.toml on first run if the file does not exist.
# Default agent selection.
[agents.default]
# Use one of the built-in agent names below, or whatever comes after `agents.` in a custom agent definition.
name = "pi"
# Default launch placement when no CLI launch override is provided.
[launch]
implementation = "window"
review = "window"
# Built-in agent definitions.
[agents.pi]
command = "pi"
prompt_flag = ""
[agents.opencode]
command = "opencode"
prompt_flag = "--prompt"
[agents.claude]
command = "claude"
prompt_flag = ""
[agents.codex]
command = "codex"
prompt_flag = ""
# Custom agent examples.
# `prompt_flag` is optional. If you omit it, wtmag passes the prompt positionally.
# [agents.aider]
# command = "aider"
# prompt_flag = "--message"
# [agents.custom-agent-with-args]
# command = "my-agent"
# args = ["run", "--profile", "coding"]Set agents.default.name to any agent table name in the config. That can be one of the generated built-ins (pi, opencode, claude, codex) or a custom [agents.<name>] block you add yourself. --agent still overrides the config for a single run.
To override config for one repository or worktree, add a wtmag.toml file at the project root using the same schema. Project config is layered on top of the global home config, so any supported config table can be overridden there and you only need to include the tables you want to change. If you redefine an existing [agents.<name>] block, include the full block for that agent.
Then use it: wtmag create --github 456 -t issue --agent aider
Why prompt_flag matters: wtmag writes the full brief to .wtmag/prompt.md, then passes a bootstrap prompt that tells the agent to read that file. The prompt_flag tells wtmag how to send that bootstrap prompt:
--prompt→opencode --prompt "Read ./.wtmag/prompt.md and use it as the full task brief."--message→aider --message "Read ./.wtmag/prompt.md and use it as the full task brief."""(empty) →pi "Read ./.wtmag/prompt.md and use it as the full task brief."(positional)
For custom agents, prompt_flag is optional. If you leave it out, wtmag uses positional prompt delivery.
This works for both built-in prompts (from issues/PRs) and custom prompts via --prompt "custom instructions".
- Fetches issue/PR/ticket via GitHub/Jira CLI → extracts title + description
- Resolves the worker branch target → for example
github-issue-456for issue work, or a provider-specific review branch for PR work - Creates or switches the worktree via
wt switch - Starts tmux worker → a dedicated session or a parent-session window, depending on config and launch flags
- Writes
.wtmag/prompt.mdin the worktree with the full task brief - Spawns agent → Your choice of AI agent (pi, opencode, claude, codex, or custom) with a bootstrap prompt
- Promotes a lightweight window worker into a dedicated session on
promote - Cleans up worktree + tmux target on
cleanup
Each agent worker runs in tmux (not headless) so you can:
- Jump in anytime to override the agent or do manual work
- Create new windows for dedicated session workers when a task grows beyond a single window
- Multiple panes - agent in one, logs in another, tests in a third
Workers can stay lightweight as a single parent-session window by default, then be promoted into a dedicated session when they need to grow.
Current implementation: Local only
┌──────────────────┐
│ Orchestrator │ You chat here, dispatch work
│ (tmux: dev) │
└────────┬─────────┘
│ wtmag create --github 456 -t issue --agent claude
▼
┌──────────────────────────────────┐
│ blog-github-issue-456 │
│ ├─ Worktree: ./github-issue-456 │
│ ├─ Tmux: parent-session window │
│ └─ Agent: claude (or pi, │
│ opencode, codex, │
│ or custom) │
└──────────────────────────────────┘
Future: Cloud runtime support (Daytona sandboxes, etc.) for remote agent execution.
create --github <num> -t <type>- Spawn agent from GitHub issue/PR (type: issue, pr)create --jira <id>- Spawn agent from Jira ticketcreate --prompt "text"- Spawn agent from custom promptcreate ... --agent <name>- Use specific AI agent (otherwise wtmag uses projectwtmag.toml, then global configagents.default.name, then the generated global default ofpi)create ... --model <provider/model[:thinking]>- Override the spawned agent model for a single run (piandopencodeonly right now)create ... --launch <session|window>/-s/-w- Override project/global[launch]defaults for a single runcreate ... --prompt "custom"- Override default prompt with custom instructionslist/list --all- Show known workers and whether they are running or stoppedattach <id>- Attach to the worker's tmux session or parent-session windowpromote --id <id>- Promote a window worker into a dedicated tmux sessioncleanup --id <id> [--force]- Remove worktree and tmux target (--forceuseswt remove --force)
MIT