dispatch-agents 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +117 -33
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -77,8 +77,9 @@ function loadConfig(cliOverrides) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// src/commands.ts
|
|
80
|
-
import { existsSync as existsSync2, writeFileSync as writeFileSync2, readdirSync } from "fs";
|
|
80
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, appendFileSync as appendFileSync2, readdirSync } from "fs";
|
|
81
81
|
import { join as join3 } from "path";
|
|
82
|
+
import { homedir as homedir2 } from "os";
|
|
82
83
|
import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
|
|
83
84
|
|
|
84
85
|
// src/shell.ts
|
|
@@ -471,8 +472,8 @@ Work on this ticket. Create commits as you go. When done, push the branch.`;
|
|
|
471
472
|
if (TICKET_RE.test(input)) {
|
|
472
473
|
log.warn(`Ticket prompt for ${input} overridden by --prompt-file`);
|
|
473
474
|
}
|
|
474
|
-
const { readFileSync:
|
|
475
|
-
prompt =
|
|
475
|
+
const { readFileSync: readFileSync4 } = await import("fs");
|
|
476
|
+
prompt = readFileSync4(promptFileArg, "utf-8");
|
|
476
477
|
}
|
|
477
478
|
if (windowExists(id)) {
|
|
478
479
|
log.error(`Agent '${id}' is already running. Use 'dispatch stop ${id}' first.`);
|
|
@@ -803,51 +804,131 @@ function cmdNotifyDone(args) {
|
|
|
803
804
|
notify("Dispatch", `Agent ${agentId} finished`);
|
|
804
805
|
log.ok(`Agent ${agentId} completed`);
|
|
805
806
|
}
|
|
807
|
+
var CLAUDE_MD_SNIPPET = `
|
|
808
|
+
## Dispatch (multi-agent orchestration)
|
|
809
|
+
|
|
810
|
+
Launch Claude Code agents in isolated git worktrees. Each agent gets its own branch, so it can make changes without affecting your working tree or other agents. Agents run inside tmux \u2014 interactive mode to watch/guide, headless for fire-and-forget.
|
|
811
|
+
|
|
812
|
+
**When to use:** Hand off well-defined tasks (Linear tickets, bug fixes, features) to a parallel agent while you keep working. Avoid dispatching two agents to the same files \u2014 they'll create merge conflicts.
|
|
813
|
+
|
|
814
|
+
\`\`\`bash
|
|
815
|
+
# Launch agents
|
|
816
|
+
dispatch run HEY-123 # From Linear ticket (auto-fetches title + description)
|
|
817
|
+
dispatch run "Fix the auth bug" --name HEY-879 # Free text with custom branch name (hey-879)
|
|
818
|
+
dispatch run HEY-123 --headless # Background \u2014 check with: dispatch logs HEY-123
|
|
819
|
+
dispatch run HEY-123 -m sonnet --max-turns 20 # Sonnet, 20 turn limit
|
|
820
|
+
dispatch run HEY-123 HEY-124 HEY-125 # Batch launch in parallel
|
|
821
|
+
|
|
822
|
+
# Monitor and interact
|
|
823
|
+
dispatch list # Status: green=running, yellow=idle, red=exited
|
|
824
|
+
dispatch attach HEY-123 # Jump to agent's terminal (auto-opens tab if no TTY)
|
|
825
|
+
dispatch logs HEY-123 # Tail headless agent output
|
|
826
|
+
|
|
827
|
+
# Lifecycle
|
|
828
|
+
dispatch stop HEY-123 # Interrupt agent (worktree preserved)
|
|
829
|
+
dispatch resume HEY-123 # Pick up where it left off (--continue)
|
|
830
|
+
dispatch cleanup HEY-123 --delete-branch # Remove worktree + branch
|
|
831
|
+
dispatch cleanup --all --delete-branch # Clean up everything
|
|
832
|
+
\`\`\`
|
|
833
|
+
|
|
834
|
+
**Key flags:** \`--name/-n\` sets branch name, \`--model/-m\` picks model, \`--headless/-H\` for background, \`--prompt-file/-f\` for long prompts, \`--base/-b\` to branch off something other than dev.
|
|
835
|
+
|
|
836
|
+
Config: \`~/.dispatch.yml\` (base_branch, model, max_turns, max_budget, worktree_dir, claude_timeout).
|
|
837
|
+
Requires: tmux, claude CLI, git.
|
|
838
|
+
`;
|
|
839
|
+
function cmdSetup() {
|
|
840
|
+
const claudeMdPath = join3(homedir2(), ".claude", "CLAUDE.md");
|
|
841
|
+
if (existsSync2(claudeMdPath)) {
|
|
842
|
+
const content = readFileSync3(claudeMdPath, "utf-8");
|
|
843
|
+
if (content.includes("dispatch run") || content.includes("Dispatch (multi-agent")) {
|
|
844
|
+
log.warn("Dispatch section already exists in ~/.claude/CLAUDE.md");
|
|
845
|
+
log.info("To update it, remove the existing Dispatch section and run setup again.");
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
appendFileSync2(claudeMdPath, "\n" + CLAUDE_MD_SNIPPET);
|
|
849
|
+
log.ok("Added dispatch section to ~/.claude/CLAUDE.md");
|
|
850
|
+
} else {
|
|
851
|
+
const claudeDir = join3(homedir2(), ".claude");
|
|
852
|
+
if (!existsSync2(claudeDir)) {
|
|
853
|
+
spawnSync2("mkdir", ["-p", claudeDir]);
|
|
854
|
+
}
|
|
855
|
+
writeFileSync2(claudeMdPath, CLAUDE_MD_SNIPPET.trimStart());
|
|
856
|
+
log.ok("Created ~/.claude/CLAUDE.md with dispatch section");
|
|
857
|
+
}
|
|
858
|
+
}
|
|
806
859
|
|
|
807
860
|
// src/cli.ts
|
|
808
|
-
var VERSION = "0.
|
|
861
|
+
var VERSION = "0.4.0";
|
|
809
862
|
function help() {
|
|
810
|
-
console.log(`dispatch \u2014
|
|
863
|
+
console.log(`dispatch \u2014 Launch Claude Code agents in isolated git worktrees
|
|
864
|
+
|
|
865
|
+
Each agent gets its own branch and worktree, so it can make changes without
|
|
866
|
+
affecting your working tree or other agents. Agents run inside tmux \u2014 use
|
|
867
|
+
interactive mode to watch and guide them, or headless for fire-and-forget.
|
|
811
868
|
|
|
812
|
-
|
|
813
|
-
dispatch run <ticket|prompt> [
|
|
814
|
-
dispatch list
|
|
815
|
-
dispatch logs <id>
|
|
816
|
-
dispatch stop <id>
|
|
817
|
-
dispatch resume <id> [--headless]
|
|
818
|
-
dispatch cleanup <id>
|
|
819
|
-
dispatch
|
|
869
|
+
Commands:
|
|
870
|
+
dispatch run <ticket|prompt> [options] Launch an agent
|
|
871
|
+
dispatch list Show all running agents with status
|
|
872
|
+
dispatch logs <id> Tail a headless agent's output
|
|
873
|
+
dispatch stop <id> Send Ctrl-C and kill the tmux window
|
|
874
|
+
dispatch resume <id> [--headless] Restart a stopped agent (keeps context)
|
|
875
|
+
dispatch cleanup <id> [--delete-branch] Remove worktree (and optionally branch)
|
|
876
|
+
dispatch cleanup --all [--delete-branch] Remove all worktrees
|
|
877
|
+
dispatch attach [id] Open tmux session (or jump to specific agent)
|
|
878
|
+
dispatch setup Add dispatch docs to ~/.claude/CLAUDE.md
|
|
820
879
|
|
|
821
880
|
Run Options:
|
|
822
|
-
--headless, -H
|
|
823
|
-
--model, -m <model>
|
|
824
|
-
--
|
|
825
|
-
--max-
|
|
826
|
-
--
|
|
827
|
-
--
|
|
828
|
-
--
|
|
829
|
-
--no-worktree
|
|
881
|
+
--headless, -H Fire-and-forget mode (no interactive terminal)
|
|
882
|
+
--model, -m <model> Claude model: sonnet, opus, haiku (default: from config)
|
|
883
|
+
--name, -n <name> Set agent name and branch (default: ticket ID or task-{random})
|
|
884
|
+
--max-turns <n> Limit agentic turns before stopping (headless only)
|
|
885
|
+
--max-budget <usd> Cap spending in USD (headless only)
|
|
886
|
+
--base, -b <branch> Branch to create worktree from (default: dev)
|
|
887
|
+
--prompt-file, -f <file> Load prompt from a file instead of CLI arg
|
|
888
|
+
--no-worktree Run in current directory (no isolation)
|
|
889
|
+
|
|
890
|
+
Lifecycle:
|
|
891
|
+
1. run \u2014 Creates worktree + branch, opens tmux window, starts Claude Code
|
|
892
|
+
2. work \u2014 Agent reads codebase, makes changes, commits, pushes, creates PRs
|
|
893
|
+
3. attach \u2014 View/interact with the agent (auto-opens terminal tab if no TTY)
|
|
894
|
+
4. stop \u2014 Interrupt the agent (worktree and branch preserved)
|
|
895
|
+
5. resume \u2014 Pick up where it left off (Claude --continue)
|
|
896
|
+
6. cleanup \u2014 Remove worktree when done (--delete-branch to also delete the branch)
|
|
897
|
+
|
|
898
|
+
Input Types:
|
|
899
|
+
Linear ticket dispatch run HEY-837 Fetches title + description from Linear
|
|
900
|
+
Free text dispatch run "Fix the auth bug" Uses your prompt directly
|
|
901
|
+
Prompt file dispatch run X -f prompt.txt Loads prompt from file (good for long prompts)
|
|
830
902
|
|
|
831
903
|
Examples:
|
|
832
|
-
dispatch run HEY-837
|
|
833
|
-
dispatch run HEY-837 --headless
|
|
834
|
-
dispatch run HEY-837 HEY-838 HEY-839
|
|
835
|
-
dispatch run "Fix the auth bug"
|
|
836
|
-
dispatch run HEY-837 -m sonnet
|
|
837
|
-
dispatch
|
|
904
|
+
dispatch run HEY-837 # Interactive, from Linear ticket
|
|
905
|
+
dispatch run HEY-837 --headless # Background \u2014 check with: dispatch logs HEY-837
|
|
906
|
+
dispatch run HEY-837 HEY-838 HEY-839 # Batch launch 3 agents in parallel
|
|
907
|
+
dispatch run "Fix the auth bug" --name HEY-879 # Free text with custom branch name
|
|
908
|
+
dispatch run HEY-837 -m sonnet --max-turns 20 # Sonnet model, 20 turn limit
|
|
909
|
+
dispatch attach HEY-837 # Jump to agent's terminal
|
|
910
|
+
dispatch list # See what's running
|
|
911
|
+
dispatch cleanup --all --delete-branch # Clean everything up
|
|
912
|
+
|
|
913
|
+
Tips:
|
|
914
|
+
- Each agent works on its own branch \u2014 avoid dispatching two agents to the same files
|
|
915
|
+
- Use --name to get meaningful branch names (e.g., --name HEY-879 creates branch hey-879)
|
|
916
|
+
- Interactive mode lets you guide the agent; headless is for well-defined tasks
|
|
917
|
+
- Works from inside Claude Code sessions (agents launch in separate terminals)
|
|
918
|
+
- Use dispatch list to check status: green = running, yellow = idle, red = exited
|
|
838
919
|
|
|
839
920
|
Environment:
|
|
840
|
-
LINEAR_API_KEY
|
|
921
|
+
LINEAR_API_KEY Linear API key for auto-fetching ticket details
|
|
841
922
|
DISPATCH_BASE_BRANCH Default base branch (default: dev)
|
|
842
923
|
DISPATCH_MODEL Default model
|
|
843
924
|
DISPATCH_CONFIG Config file path (default: ~/.dispatch.yml)
|
|
844
925
|
|
|
845
926
|
Config (~/.dispatch.yml):
|
|
846
|
-
base_branch: dev
|
|
847
|
-
model: opus
|
|
848
|
-
max_turns: 20
|
|
849
|
-
claude_timeout: 30
|
|
850
|
-
worktree_dir: .worktrees`);
|
|
927
|
+
base_branch: dev # Branch to create worktrees from
|
|
928
|
+
model: opus # Default Claude model
|
|
929
|
+
max_turns: 20 # Default max turns for headless
|
|
930
|
+
claude_timeout: 30 # Seconds to wait for Claude to start
|
|
931
|
+
worktree_dir: .worktrees # Where worktrees are created`);
|
|
851
932
|
}
|
|
852
933
|
async function main() {
|
|
853
934
|
const args = process.argv.slice(2);
|
|
@@ -877,6 +958,9 @@ async function main() {
|
|
|
877
958
|
case "attach":
|
|
878
959
|
cmdAttach(rest);
|
|
879
960
|
break;
|
|
961
|
+
case "setup":
|
|
962
|
+
cmdSetup();
|
|
963
|
+
break;
|
|
880
964
|
case "_notify-done":
|
|
881
965
|
cmdNotifyDone(rest);
|
|
882
966
|
break;
|