| name | doey-add-window |
| description | Add a new team window (Subtaskmaster + Workers), optionally as a reserved freelancer pool. |
- Session config: !
cat $(tmux show-environment DOEY_RUNTIME 2>/dev/null | cut -d= -f2-)/session.env 2>/dev/null || true
- Windows: !
tmux list-windows -t "$(grep SESSION_NAME $(tmux show-environment DOEY_RUNTIME 2>/dev/null | cut -d= -f2-)/session.env 2>/dev/null | cut -d= -f2)" -F '#{window_index} #{window_name}' 2>/dev/null|| true
/doey-add-window [grid] [--freelancer] [--workers N] [--name NAME] [--task-id ID] [--reserved] (default 4x2). No confirmation. Stays on the session's branch (usually main); use /doey-worktree separately to isolate a window after the fact.
0. Try CLI first (preferred — handles --workers, --name, --task-id)
bash: if command -v doey >/dev/null 2>&1; then doey add-window "$@" 2>&1 && echo "Team spawned via CLI" && exit 0; echo "CLI failed, falling back to inline steps"; fi
1. Parse + validate (fallback if CLI unavailable)
bash: RD=$(tmux show-environment DOEY_RUNTIME 2>/dev/null | cut -d= -f2-) && _sv() { grep "^$1=" "${RD}/session.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"'; } && SESSION_NAME=$(_sv SESSION_NAME) && PROJECT_DIR=$(_sv PROJECT_DIR) && PROJECT_NAME=$(_sv PROJECT_NAME) && GRID="${USER_GRID:-4x2}" && COLS=$(echo "$GRID" | cut -dx -f1) && ROWS=$(echo "$GRID" | cut -dx -f2) && TOTAL=$((COLS * ROWS)) && FREELANCER_MODE="false" && for _a in "$@"; do [ "$_a" = "--freelancer" ] && FREELANCER_MODE="true"; done && if [ "$FREELANCER_MODE" = "true" ]; then WORKER_COUNT=$TOTAL; else [ "$TOTAL" -lt 2 ] && { echo "ERROR: Need ≥2 panes"; exit 1; } || true; WORKER_COUNT=$((TOTAL - 1)); fi
2. Create window + grid
bash: tmux new-window -t "$SESSION_NAME" -c "$PROJECT_DIR" && sleep 0.5 && NEW_WIN=$(tmux display-message -t "$SESSION_NAME" -p '#{window_index}') && for _s in $(seq 1 $((TOTAL - 1))); do tmux split-window -t "${SESSION_NAME}:${NEW_WIN}" -c "$PROJECT_DIR"; done && tmux select-layout -t "${SESSION_NAME}:${NEW_WIN}" tiled && sleep 0.5 && WORKER_PANES_LIST="" && if [ "$FREELANCER_MODE" = "true" ]; then for i in $(seq 0 $((WORKER_COUNT - 1))); do tmux select-pane -t "${SESSION_NAME}:${NEW_WIN}.${i}" -T "T${NEW_WIN} F${i}"; [ -n "$WORKER_PANES_LIST" ] && WORKER_PANES_LIST="${WORKER_PANES_LIST},${i}" || WORKER_PANES_LIST="${i}"; done; else tmux select-pane -t "${SESSION_NAME}:${NEW_WIN}.0" -T "T${NEW_WIN} Subtaskmaster"; for i in $(seq 1 $WORKER_COUNT); do tmux select-pane -t "${SESSION_NAME}:${NEW_WIN}.${i}" -T "T${NEW_WIN} W${i}"; [ -n "$WORKER_PANES_LIST" ] && WORKER_PANES_LIST="${WORKER_PANES_LIST},${i}" || WORKER_PANES_LIST="${i}"; done; fi
"create pane failed" = terminal too small.
3. Write team env + update session
bash: MGR_PANE="0" && TT="" && [ "$FREELANCER_MODE" = "true" ] && { MGR_PANE=""; TT="freelancer"; } && cat > "${RD}/team_${NEW_WIN}.env.tmp" << TEAM_EOF
SESSION_NAME=${SESSION_NAME}
PROJECT_DIR=${PROJECT_DIR}
PROJECT_NAME=${PROJECT_NAME}
WINDOW_INDEX=${NEW_WIN}
GRID=${GRID}
TOTAL_PANES=${TOTAL}
MANAGER_PANE=${MGR_PANE}
WORKER_PANES=${WORKER_PANES_LIST}
WORKER_COUNT=${WORKER_COUNT}
TEAM_TYPE=${TT}
TEAM_NAME=${FREELANCER_MODE:+Freelancers}
RESERVED=
TASK_ID=
TEAM_EOF
mv "${RD}/team_${NEW_WIN}.env.tmp" "${RD}/team_${NEW_WIN}.env" && CUR=$(grep '^TEAM_WINDOWS=' "${RD}/session.env" 2>/dev/null | cut -d= -f2 | tr -d '"') && { [ -n "$CUR" ] && NW="${CUR},${NEW_WIN}" || NW="${NEW_WIN}"; } && TMPENV=$(mktemp "${RD}/session.env.tmp_XXXXXX") && if grep -q '^TEAM_WINDOWS=' "${RD}/session.env"; then sed "s/^TEAM_WINDOWS=.*/TEAM_WINDOWS=${NW}/" "${RD}/session.env" > "$TMPENV"; else cat "${RD}/session.env" > "$TMPENV"; echo "TEAM_WINDOWS=${NW}" >> "$TMPENV"; fi && mv "$TMPENV" "${RD}/session.env"
4. Launch Claude
bash: source "$HOME/.local/bin/doey-send.sh" 2>/dev/null || true; if [ "$FREELANCER_MODE" = "true" ]; then for i in $(echo "$WORKER_PANES_LIST" | tr ',' ' '); do WP=$(grep -rl "pane ${NEW_WIN}.${i} " "${RD}"/worker-system-prompt-.md 2>/dev/null | head -1); CMD="claude --dangerously-skip-permissions --model opus --name "T${NEW_WIN} F${i}""; [ -n "$WP" ] && CMD="${CMD} --append-system-prompt-file "${WP}""; doey_send_launch "${SESSION_NAME}:${NEW_WIN}.${i}" "$CMD"; sleep 0.5; done; else doey_send_launch "${SESSION_NAME}:${NEW_WIN}.0" "claude --dangerously-skip-permissions --name "T${NEW_WIN} Subtaskmaster" --agent "t${NEW_WIN}-manager"" && sleep 1; for i in $(echo "$WORKER_PANES_LIST" | tr ',' ' '); do WP=$(grep -rl "pane ${NEW_WIN}.${i} " "${RD}"/worker-system-prompt-.md 2>/dev/null | head -1); CMD="claude --dangerously-skip-permissions --model opus --name "T${NEW_WIN} W${i}""; [ -n "$WP" ] && CMD="${CMD} --append-system-prompt-file "${WP}""; doey_send_launch "${SESSION_NAME}:${NEW_WIN}.${i}" "$CMD"; sleep 0.5; done; fi
5. Layout
bash: bash -c "eval "$(sed -n '/^_env_val()/,/^}/p' '${PROJECT_DIR}/shell/doey.sh')" && eval "$(sed -n '/^_layout_checksum()/,/^}/p' '${PROJECT_DIR}/shell/doey.sh')" && eval "$(sed -n '/^rebalance_grid_layout()/,/^}/p' '${PROJECT_DIR}/shell/doey.sh')" && rebalance_grid_layout '${SESSION_NAME}' '${NEW_WIN}' '${RD}'"
6. Verify boot
bash: sleep 8 && NOT_READY=0 && DOWN="" && for i in 0 $(echo "$WORKER_PANES_LIST" | tr ',' ' '); do CHILD=$(pgrep -P "$(tmux display-message -t "${SESSION_NAME}:${NEW_WIN}.${i}" -p '#{pane_pid}')" 2>/dev/null); OUTPUT=$(tmux capture-pane -t "${SESSION_NAME}:${NEW_WIN}.${i}" -p 2>/dev/null); if [ -z "$CHILD" ] || ! echo "$OUTPUT" | grep -q "bypass permissions"; then NOT_READY=$((NOT_READY + 1)); DOWN="$DOWN ${NEW_WIN}.$i"; fi; done; [ "$NOT_READY" -eq 0 ] && echo "All booted" || echo "WARNING: ${NOT_READY} not ready:${DOWN}"
Pane 0 = Subtaskmaster (freelancer: all workers). Write team env before launch. Default flow stays on the session's branch (usually main); use /doey-worktree after the fact for explicit isolation.