Merge pull request 'fix: fix: formula agents run in isolated git worktrees — no session collisions (#460)' (#461) from fix/issue-460 into main
This commit is contained in:
commit
db325c4415
4 changed files with 52 additions and 3 deletions
16
BOOTSTRAP.md
16
BOOTSTRAP.md
|
|
@ -302,3 +302,19 @@ Meanwhile:
|
|||
| Approved PRs never merge (HTTP 405) | `review_bot` not in merge/approvals whitelist | Add as write collaborator; set both `approvals_whitelist_username` and `merge_whitelist_usernames` in branch protection |
|
||||
| Dev-agent churns through issues without waiting for open PRs to land | No single-threaded enforcement | `WAITING_PRS` check in dev-poll holds new work — verify TOML `name` is consistent across invocations |
|
||||
| Label ping-pong (issue reopened then immediately re-closed) | `already_done` handler doesn't close issue | Review dev-agent log; `already_done` status should auto-close the issue |
|
||||
|
||||
## Action Runner — disinto (harb-staging)
|
||||
|
||||
Added 2026-03-19. Polls disinto repo for `action`-labeled issues.
|
||||
|
||||
```
|
||||
*/5 * * * * cd /home/debian/dark-factory && bash action/action-poll.sh projects/disinto.toml >> /tmp/action-disinto-cron.log 2>&1
|
||||
```
|
||||
|
||||
Runs locally on harb-staging — same box where Caddy/site live. For formulas that need local resources (publish-site, etc).
|
||||
|
||||
### Fix applied: action-agent.sh needs +x
|
||||
The script wasn't executable after git clone. Run:
|
||||
```bash
|
||||
chmod +x action/action-agent.sh action/action-poll.sh
|
||||
```
|
||||
|
|
|
|||
0
action/action-agent.sh
Normal file → Executable file
0
action/action-agent.sh
Normal file → Executable file
0
action/action-poll.sh
Normal file → Executable file
0
action/action-poll.sh
Normal file → Executable file
|
|
@ -84,19 +84,48 @@ $(cat "$ctx_path")
|
|||
# ── Session management ───────────────────────────────────────────────────
|
||||
|
||||
# start_formula_session SESSION WORKDIR PHASE_FILE
|
||||
# Kills stale session, resets phase file, creates new tmux + claude session.
|
||||
# Kills stale session, resets phase file, creates a per-agent git worktree
|
||||
# for session isolation, and creates a new tmux + claude session in it.
|
||||
# Sets _FORMULA_SESSION_WORKDIR to the worktree path (or original workdir
|
||||
# on fallback). Callers must clean up via remove_formula_worktree after
|
||||
# the session ends.
|
||||
# Returns 0 on success, 1 on failure.
|
||||
start_formula_session() {
|
||||
local session="$1" workdir="$2" phase_file="$3"
|
||||
agent_kill_session "$session"
|
||||
rm -f "$phase_file"
|
||||
|
||||
# Create per-agent git worktree for session isolation.
|
||||
# Each agent gets its own CWD so Claude Code treats them as separate
|
||||
# projects — no resume collisions between sequential formula runs.
|
||||
_FORMULA_SESSION_WORKDIR="/tmp/disinto-${session}"
|
||||
# Clean up any stale worktree from a previous run
|
||||
git -C "$workdir" worktree remove "$_FORMULA_SESSION_WORKDIR" --force 2>/dev/null || true
|
||||
if git -C "$workdir" worktree add "$_FORMULA_SESSION_WORKDIR" HEAD --detach 2>/dev/null; then
|
||||
log "Created worktree: ${_FORMULA_SESSION_WORKDIR}"
|
||||
else
|
||||
log "WARNING: worktree creation failed — falling back to ${workdir}"
|
||||
_FORMULA_SESSION_WORKDIR="$workdir"
|
||||
fi
|
||||
|
||||
log "Creating tmux session: ${session}"
|
||||
if ! create_agent_session "$session" "$workdir" "$phase_file"; then
|
||||
if ! create_agent_session "$session" "$_FORMULA_SESSION_WORKDIR" "$phase_file"; then
|
||||
log "ERROR: failed to create tmux session ${session}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# remove_formula_worktree
|
||||
# Removes the worktree created by start_formula_session if it differs from
|
||||
# PROJECT_REPO_ROOT. Safe to call multiple times. No-op if no worktree was created.
|
||||
remove_formula_worktree() {
|
||||
if [ -n "${_FORMULA_SESSION_WORKDIR:-}" ] \
|
||||
&& [ "$_FORMULA_SESSION_WORKDIR" != "${PROJECT_REPO_ROOT:-}" ]; then
|
||||
git -C "$PROJECT_REPO_ROOT" worktree remove "$_FORMULA_SESSION_WORKDIR" --force 2>/dev/null || true
|
||||
log "Removed worktree: ${_FORMULA_SESSION_WORKDIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
# formula_phase_callback PHASE
|
||||
# Standard crash-recovery phase callback for formula sessions.
|
||||
# Requires globals: SESSION_NAME, PHASE_FILE, PROJECT_REPO_ROOT, PROMPT.
|
||||
|
|
@ -113,7 +142,7 @@ formula_phase_callback() {
|
|||
fi
|
||||
_FORMULA_CRASH_COUNT=$(( ${_FORMULA_CRASH_COUNT:-0} + 1 ))
|
||||
log "WARNING: tmux session died unexpectedly — attempting recovery"
|
||||
if create_agent_session "${_MONITOR_SESSION:-$SESSION_NAME}" "$PROJECT_REPO_ROOT" "$PHASE_FILE" 2>/dev/null; then
|
||||
if create_agent_session "${_MONITOR_SESSION:-$SESSION_NAME}" "${_FORMULA_SESSION_WORKDIR:-$PROJECT_REPO_ROOT}" "$PHASE_FILE" 2>/dev/null; then
|
||||
agent_inject_into_session "${_MONITOR_SESSION:-$SESSION_NAME}" "$PROMPT"
|
||||
log "Recovery session started"
|
||||
else
|
||||
|
|
@ -234,5 +263,9 @@ run_formula_and_monitor() {
|
|||
fi
|
||||
|
||||
matrix_send "$agent_name" "${agent_name^} session finished (${FINAL_PHASE:-no phase})" 2>/dev/null || true
|
||||
|
||||
# Clean up per-agent worktree — "the runtime creates and destroys"
|
||||
remove_formula_worktree
|
||||
|
||||
log "--- ${agent_name^} run done ---"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue