
Parallel Task Tmux
- 224 repo stars
- Updated April 18, 2026
- am-will/swarms
Parallel Task tmux is a Claude Code skill that runs plan tasks as codex exec workers in live tmux panes, tiling as they launch and reaping panes as they finish.
About
Parallel Task tmux is a Claude Code skill that runs dependency-ordered plan execution like parallel-task but launches each worker via codex exec inside a tmux pane. Output streams live in each pane and to a per-task log file. A developer uses it when they want visible, real-time worker progress; completed panes are reaped automatically so the tiled grid grows and shrinks as tasks run and finish.
- Routes each unblocked task through `codex exec` in a live tmux pane for real-time visibility
- Tiled worker grid expands as tasks launch and shrinks as panes are reaped on completion
- Ships helper scripts tmux_spawn_worker.sh and tmux_reap_completed.sh
Parallel Task Tmux by the numbers
- Data as of Aug 2, 2026 (Skillselion catalog sync)
parallel-task-tmux capabilities & compatibility
- Capabilities
- parallel task · parallel task spark · super swarm
- Works with
- github
- Use cases
- orchestration · planning · testing
What parallel-task-tmux says it does
route each worker through `codex exec` inside tmux panes so progress is visible in real time.
Launching tasks adds panes and expands the tile grid.
Reaping completed tasks kills panes and shrinks the grid.
npx skills add https://github.com/am-will/swarms --skill parallel-task-tmuxAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| repo stars | ★ 224 |
|---|---|
| Last updated | April 18, 2026 |
| Repository | am-will/swarms ↗ |
What it does
Execute a plan with dependency-ordered codex workers shown live in tmux panes that tile and reap as tasks progress.
Who is it for?
Developers who want live, per-worker visibility while a plan executes in parallel.
Skip if: Environments without tmux or the codex CLI, which the preflight requires.
When should I use this skill?
You run /parallel-task-tmux and want each worker's codex exec output visible in its own pane.
What you get
Each task runs as a live tmux pane, tiling and reaping automatically, with logs captured per task.
- per-task tmux pane
- per-task log file under logs/
- status.tsv and task_map.tsv run state
By the numbers
- 6-step execution model (parse, build prompts, launch panes, monitor/reap, validate, repeat)
- 2 bundled helper scripts
Files
Parallel Task Executor (tmux Live Workers)
Run dependency-ordered plan execution like parallel-task, but route each worker through codex exec inside tmux panes so progress is visible in real time.
Use this skill when you want:
- Live visibility into each running worker
- A tiled worker view that expands as tasks launch
- Automatic pane cleanup that shrinks the layout as tasks finish
Execution Model
1. Parse the plan and compute unblocked tasks by depends_on. 2. Build one worker prompt file per task. 3. Launch one tmux pane per task via scripts/tmux_spawn_worker.sh. 4. Monitor status/logs and reap completed panes via scripts/tmux_reap_completed.sh. 5. Validate completed tasks before advancing to the next dependency wave. 6. Repeat until all requested tasks are complete.
Preflight
Run these checks before launching workers:
command -v tmux >/dev/null
command -v codex >/dev/nullResolve the skill directory once so helper script paths are stable:
SKILL_ROOT="$(fd -td -p 'parallel-task-tmux' "$PWD" "$HOME/.codex/skills" "$HOME/.agents/skills" 2>/dev/null | head -n 1)"Fail fast if SKILL_ROOT is empty.
Initialize one run directory per execution:
PLAN_FILE="./plan.md"
PLAN_BASE="$(basename "$PLAN_FILE" .md)"
RUN_ID="$(date +%Y%m%d-%H%M%S)"
SESSION_NAME="swarms-${PLAN_BASE}-${RUN_ID}"
RUN_ROOT=".swarms/tmux/${SESSION_NAME}"
mkdir -p "$RUN_ROOT/prompts" "$RUN_ROOT/logs"
: > "$RUN_ROOT/status.tsv"
: > "$RUN_ROOT/task_map.tsv"
: > "$RUN_ROOT/reaped.tsv"Plan Parsing and Scheduling
Mirror parallel-task behavior:
- Parse task sections (for example
### T1:). - Extract task id, title,
depends_on, location, description, acceptance criteria, validation. - Filter to requested subset and required dependencies if the user passes a subset.
- Launch only tasks whose dependencies are complete.
Worker Prompt Contract
Create one prompt file per task at:
$RUN_ROOT/prompts/<TASK_ID>.md
Use the same task context and completion requirements as parallel-task:
- Read the working plan and relevant files before coding.
- Default to TDD RED phase first using a
tdd_test_writersubagent, or explicitly recordreason_not_testablewith an alternative verification contract. - Treat RED-phase tests (or approved non-testable verification plan) as the implementation contract.
- Implement acceptance criteria.
- Keep edits atomic.
- Run the exact new/updated test commands until GREEN, or run the documented alternative verification and capture evidence.
- Commit only task-scoped files.
- Update the plan status/log/files after the commit.
- Return modified files, criteria coverage, and RED -> GREEN or non-testable verification evidence.
Launching tmux Workers
When running inside tmux, prefer in-place splits so the user can keep chatting in the current Codex pane while workers appear beside it.
In-place mode (recommended inside tmux):
"$SKILL_ROOT/scripts/tmux_spawn_worker.sh" \
--split-current \
--workspace "$PWD" \
--task-id "$TASK_ID" \
--prompt-file "$RUN_ROOT/prompts/${TASK_ID}.md" \
--log-file "$RUN_ROOT/logs/${TASK_ID}.log" \
--status-file "$RUN_ROOT/status.tsv" \
--map-file "$RUN_ROOT/task_map.tsv"Detached session mode (for non-tmux shells):
"$SKILL_ROOT/scripts/tmux_spawn_worker.sh" \
--session "$SESSION_NAME" \
--workspace "$PWD" \
--task-id "$TASK_ID" \
--prompt-file "$RUN_ROOT/prompts/${TASK_ID}.md" \
--log-file "$RUN_ROOT/logs/${TASK_ID}.log" \
--status-file "$RUN_ROOT/status.tsv" \
--map-file "$RUN_ROOT/task_map.tsv"Behavior:
- In split-current mode, launches workers as new panes in the current tmux window.
- In detached mode, creates tmux session/window if missing.
- Re-tiles panes after each launch so the grid expands live.
- Streams
codex execoutput live in each pane while also writing logs tologs/<TASK_ID>.log. - Tracks pane ids in
task_map.tsvfor deterministic cleanup.
In detached mode, if not already attached, print:
tmux attach -t "$SESSION_NAME"Monitoring and Pane Reaping
During each wave, monitor active panes:
tmux list-panes -t "${SESSION_NAME}:workers" -F '#{pane_id} #{pane_current_command} #{pane_dead}'Collect completed workers and close their panes:
"$SKILL_ROOT/scripts/tmux_reap_completed.sh" \
--session "$SESSION_NAME" \
--status-file "$RUN_ROOT/status.tsv" \
--map-file "$RUN_ROOT/task_map.tsv" \
--seen-file "$RUN_ROOT/reaped.tsv"This is what gives the expand/shrink behavior:
- Launching tasks adds panes and expands the tile grid.
- Reaping completed tasks kills panes and shrinks the grid.
Inspect logs before accepting a task:
tail -n 80 "$RUN_ROOT/logs/${TASK_ID}.log"Validation and Wave Control
For each completed task: 1. Verify files changed as expected. 2. Verify plan status/log/files fields were updated. 3. Verify RED -> GREEN test evidence or explicit reason_not_testable plus concrete alternative verification output. 4. Mark task complete in orchestrator state only after verification passes. 5. Retry failed tasks with corrected prompts when needed.
Launch the next wave only when all tasks in the current wave are verified complete.
Finalization
After all tasks are complete: 1. Run final validation commands from the plan. 2. Confirm no pending tasks remain. 3. Provide an execution summary with completed, failed, retried tasks, modified files, and verification evidence.
Leave the tmux session alive by default for auditability. Only kill it if the user asks:
tmux kill-session -t "$SESSION_NAME"Error Handling
- Missing task ids in subset: list valid task ids from the parsed plan.
tmuxunavailable: stop and instruct user to install tmux.- Worker exits non-zero: inspect log, repair prompt/context, relaunch task.
- No status updates: verify pane is still running; if dead without status line, relaunch.
- Parse failure: report parser assumptions and request corrected plan format.
Example Usage
/parallel-task-tmux plan.md
/parallel-task-tmux ./plans/auth-plan.md T1 T2 T4
/parallel-task-tmux user-profile-plan.md --tasks T3 T7interface:
display_name: "Parallel Task Tmux"
short_description: "Run parallel plan tasks in live tmux panes"
default_prompt: "Run the plan with /parallel-task-tmux so each worker is visible in tmux while tasks execute."
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
tmux_reap_completed.sh \
--session <session-name> \
--status-file <file> \
--map-file <file> \
--seen-file <file>
EOF
}
session=""
status_file=""
map_file=""
seen_file=""
while [[ $# -gt 0 ]]; do
case "$1" in
--session)
session="${2:-}"
shift 2
;;
--status-file)
status_file="${2:-}"
shift 2
;;
--map-file)
map_file="${2:-}"
shift 2
;;
--seen-file)
seen_file="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ -z "$session" || -z "$status_file" || -z "$map_file" || -z "$seen_file" ]]; then
usage >&2
exit 1
fi
if [[ ! -f "$status_file" || ! -f "$map_file" ]]; then
exit 0
fi
mkdir -p "$(dirname "$seen_file")"
touch "$seen_file"
while IFS='|' read -r task_id exit_code started_at ended_at log_file; do
[[ -n "$task_id" ]] || continue
record="${task_id}|${exit_code}|${started_at}|${ended_at}|${log_file}"
if grep -Fxq "$record" "$seen_file"; then
continue
fi
pane_id="$(awk -F'|' -v task="$task_id" '$1==task {pane=$2} END {print pane}' "$map_file")"
action="not-found"
if [[ -n "$pane_id" ]] && tmux list-panes -a -F '#{pane_id}' 2>/dev/null | grep -Fxq "$pane_id"; then
pane_window_id="$(tmux display-message -p -t "$pane_id" '#{window_id}' 2>/dev/null || true)"
tmux kill-pane -t "$pane_id"
if [[ -n "$pane_window_id" ]]; then
tmux select-layout -t "$pane_window_id" tiled >/dev/null 2>&1 || true
fi
action="killed"
fi
printf '%s\n' "$record" >> "$seen_file"
printf '%s|%s|%s|%s\n' "$task_id" "$exit_code" "$pane_id" "$action"
done < "$status_file"
#!/usr/bin/env bash
set -u -o pipefail
usage() {
cat <<'EOF'
Usage:
tmux_run_codex_task.sh \
--workspace <path> \
--task-id <id> \
--prompt-file <file> \
--log-file <file> \
--status-file <file>
EOF
}
workspace=""
task_id=""
prompt_file=""
log_file=""
status_file=""
while [[ $# -gt 0 ]]; do
case "$1" in
--workspace)
workspace="${2:-}"
shift 2
;;
--task-id)
task_id="${2:-}"
shift 2
;;
--prompt-file)
prompt_file="${2:-}"
shift 2
;;
--log-file)
log_file="${2:-}"
shift 2
;;
--status-file)
status_file="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ -z "$workspace" || -z "$task_id" || -z "$prompt_file" || -z "$log_file" || -z "$status_file" ]]; then
usage >&2
exit 1
fi
if [[ ! -f "$prompt_file" ]]; then
echo "Prompt file not found: $prompt_file" >&2
exit 1
fi
mkdir -p "$(dirname "$log_file")" "$(dirname "$status_file")"
start_ts="$(date -Is)"
rc=0
(
cd "$workspace" || exit 1
codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --cd "$workspace" - < "$prompt_file" 2>&1 | tee "$log_file"
) || rc=$?
end_ts="$(date -Is)"
printf '%s|%s|%s|%s|%s\n' "$task_id" "$rc" "$start_ts" "$end_ts" "$log_file" >> "$status_file"
exit "$rc"
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
tmux_spawn_worker.sh \
--workspace <path> \
--task-id <id> \
--prompt-file <file> \
--log-file <file> \
--status-file <file> \
--map-file <file> \
[--session <session-name>] \
[--window workers] \
[--split-current] \
[--runner-script <path>]
EOF
}
session=""
window="workers"
split_current=0
workspace=""
task_id=""
prompt_file=""
log_file=""
status_file=""
map_file=""
runner_script=""
while [[ $# -gt 0 ]]; do
case "$1" in
--session)
session="${2:-}"
shift 2
;;
--window)
window="${2:-}"
shift 2
;;
--split-current)
split_current=1
shift
;;
--workspace)
workspace="${2:-}"
shift 2
;;
--task-id)
task_id="${2:-}"
shift 2
;;
--prompt-file)
prompt_file="${2:-}"
shift 2
;;
--log-file)
log_file="${2:-}"
shift 2
;;
--status-file)
status_file="${2:-}"
shift 2
;;
--map-file)
map_file="${2:-}"
shift 2
;;
--runner-script)
runner_script="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ -z "$workspace" || -z "$task_id" || -z "$prompt_file" || -z "$log_file" || -z "$status_file" || -z "$map_file" ]]; then
usage >&2
exit 1
fi
if [[ -z "$runner_script" ]]; then
runner_script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/tmux_run_codex_task.sh"
fi
if [[ ! -x "$runner_script" ]]; then
echo "Runner script not executable: $runner_script" >&2
exit 1
fi
if [[ ! -f "$prompt_file" ]]; then
echo "Prompt file not found: $prompt_file" >&2
exit 1
fi
command -v tmux >/dev/null || { echo "tmux is required but not installed." >&2; exit 1; }
command -v codex >/dev/null || { echo "codex is required but not installed." >&2; exit 1; }
mkdir -p "$(dirname "$log_file")" "$(dirname "$status_file")" "$(dirname "$map_file")"
runner_cmd=(
"$runner_script"
--workspace "$workspace"
--task-id "$task_id"
--prompt-file "$prompt_file"
--log-file "$log_file"
--status-file "$status_file"
)
printf -v shell_cmd '%q ' "${runner_cmd[@]}"
if [[ "$split_current" -eq 1 ]]; then
if [[ -z "${TMUX:-}" ]]; then
echo "--split-current requires running inside tmux." >&2
exit 1
fi
current_window_id="$(tmux display-message -p '#{window_id}')"
pane_id="$(tmux split-window -d -P -F '#{pane_id}' -t "$current_window_id" -c "$workspace" "$shell_cmd")"
tmux select-layout -t "$current_window_id" tiled >/dev/null 2>&1 || true
target_ref="$current_window_id"
else
if [[ -z "$session" ]]; then
echo "--session is required unless --split-current is used." >&2
exit 1
fi
if ! tmux has-session -t "$session" 2>/dev/null; then
tmux new-session -d -s "$session" -n orchestrator -c "$workspace"
fi
window_exists=0
if tmux list-windows -t "$session" -F '#{window_name}' | grep -Fxq "$window"; then
window_exists=1
fi
target_window="${session}:${window}"
if [[ "$window_exists" -eq 1 ]]; then
pane_id="$(tmux split-window -d -P -F '#{pane_id}' -t "$target_window" -c "$workspace" "$shell_cmd")"
else
pane_id="$(tmux new-window -d -P -F '#{pane_id}' -t "$session" -n "$window" -c "$workspace" "$shell_cmd")"
fi
tmux select-layout -t "$target_window" tiled >/dev/null 2>&1 || true
target_ref="$target_window"
fi
printf '%s|%s|%s|%s|%s\n' "$task_id" "$pane_id" "$target_ref" "$log_file" "$prompt_file" >> "$map_file"
printf '%s\n' "$pane_id"
Related skills
FAQ
What does it require to run?
The preflight checks that both tmux and codex are installed before launching workers.
How does the pane layout change?
Launching tasks adds panes and expands the tile grid; reaping completed tasks kills panes and shrinks it.