agent-control-plane 0.1.16 → 0.2.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.
Files changed (47) hide show
  1. package/README.md +93 -14
  2. package/bin/pr-risk.sh +28 -6
  3. package/hooks/heartbeat-hooks.sh +62 -22
  4. package/npm/bin/agent-control-plane.js +322 -9
  5. package/package.json +1 -1
  6. package/references/architecture.md +8 -0
  7. package/references/control-plane-map.md +6 -2
  8. package/references/release-checklist.md +0 -2
  9. package/tools/bin/agent-github-update-labels +6 -1
  10. package/tools/bin/agent-project-catch-up-issue-pr-links +118 -0
  11. package/tools/bin/agent-project-catch-up-merged-prs +77 -21
  12. package/tools/bin/agent-project-catch-up-scheduled-issue-retries +123 -0
  13. package/tools/bin/agent-project-cleanup-session +84 -0
  14. package/tools/bin/agent-project-heartbeat-loop +10 -3
  15. package/tools/bin/agent-project-reconcile-issue-session +24 -12
  16. package/tools/bin/agent-project-run-claude-session +2 -2
  17. package/tools/bin/agent-project-run-kilo-session +346 -14
  18. package/tools/bin/agent-project-run-ollama-session +658 -0
  19. package/tools/bin/agent-project-run-openclaw-session +27 -25
  20. package/tools/bin/agent-project-run-opencode-session +354 -14
  21. package/tools/bin/agent-project-run-pi-session +479 -0
  22. package/tools/bin/agent-project-worker-status +1 -1
  23. package/tools/bin/flow-config-lib.sh +116 -3
  24. package/tools/bin/flow-resident-worker-lib.sh +1 -1
  25. package/tools/bin/flow-shell-lib.sh +5 -2
  26. package/tools/bin/heartbeat-recovery-preflight.sh +1 -0
  27. package/tools/bin/heartbeat-safe-auto.sh +105 -17
  28. package/tools/bin/install-project-launchd.sh +19 -2
  29. package/tools/bin/prepare-worktree.sh +4 -4
  30. package/tools/bin/profile-activate.sh +2 -2
  31. package/tools/bin/profile-adopt.sh +2 -2
  32. package/tools/bin/project-init.sh +1 -1
  33. package/tools/bin/project-runtimectl.sh +90 -7
  34. package/tools/bin/provider-cooldown-state.sh +14 -14
  35. package/tools/bin/render-flow-config.sh +30 -33
  36. package/tools/bin/run-codex-task.sh +53 -4
  37. package/tools/bin/scaffold-profile.sh +18 -3
  38. package/tools/bin/start-issue-worker.sh +1 -1
  39. package/tools/bin/start-pr-fix-worker.sh +30 -0
  40. package/tools/bin/start-pr-review-worker.sh +31 -0
  41. package/tools/bin/start-resident-issue-loop.sh +4 -4
  42. package/tools/bin/sync-agent-repo.sh +2 -2
  43. package/tools/bin/sync-dependency-baseline.sh +3 -3
  44. package/tools/bin/sync-shared-agent-home.sh +4 -1
  45. package/tools/templates/pr-fix-template.md +3 -7
  46. package/tools/templates/pr-merge-repair-template.md +3 -7
  47. package/tools/templates/pr-review-template.md +2 -1
@@ -17,9 +17,6 @@ CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
17
17
  for _clean in ACP_CODING_WORKER ACP_OPENCLAW_MODEL ACP_CLAUDE_MODEL \
18
18
  ACP_CLAUDE_TIMEOUT_SECONDS ACP_CLAUDE_MAX_ATTEMPTS ACP_CLAUDE_RETRY_BACKOFF_SECONDS \
19
19
  ACP_OPENCLAW_THINKING ACP_OPENCLAW_TIMEOUT_SECONDS \
20
- F_LOSNING_CODING_WORKER F_LOSNING_OPENCLAW_MODEL F_LOSNING_CLAUDE_MODEL \
21
- F_LOSNING_CLAUDE_TIMEOUT_SECONDS F_LOSNING_CLAUDE_MAX_ATTEMPTS F_LOSNING_CLAUDE_RETRY_BACKOFF_SECONDS \
22
- F_LOSNING_OPENCLAW_THINKING F_LOSNING_OPENCLAW_TIMEOUT_SECONDS \
23
20
  CODING_WORKER; do
24
21
  unset "${_clean}" 2>/dev/null || true
25
22
  done
@@ -69,33 +66,33 @@ if [[ -f "${PROFILE_NOTES}" ]]; then
69
66
  else
70
67
  printf 'PROFILE_NOTES_EXISTS=no\n'
71
68
  fi
72
- printf 'EFFECTIVE_REPO_ROOT=%s\n' "$(config_or_env 'ACP_REPO_ROOT F_LOSNING_REPO_ROOT' repo.root)"
73
- printf 'EFFECTIVE_AGENT_REPO_ROOT=%s\n' "$(config_or_env 'ACP_AGENT_REPO_ROOT F_LOSNING_AGENT_REPO_ROOT' runtime.agent_repo_root)"
74
- printf 'EFFECTIVE_WORKTREE_ROOT=%s\n' "$(config_or_env 'ACP_WORKTREE_ROOT F_LOSNING_WORKTREE_ROOT' runtime.worktree_root)"
75
- printf 'EFFECTIVE_RUNS_ROOT=%s\n' "$(config_or_env 'ACP_RUNS_ROOT F_LOSNING_RUNS_ROOT' runtime.runs_root)"
76
- printf 'EFFECTIVE_STATE_ROOT=%s\n' "$(config_or_env 'ACP_STATE_ROOT F_LOSNING_STATE_ROOT' runtime.state_root)"
77
- printf 'EFFECTIVE_RETAINED_REPO_ROOT=%s\n' "$(config_or_env 'ACP_RETAINED_REPO_ROOT F_LOSNING_RETAINED_REPO_ROOT' runtime.retained_repo_root)"
78
- printf 'EFFECTIVE_VSCODE_WORKSPACE_FILE=%s\n' "$(config_or_env 'ACP_VSCODE_WORKSPACE_FILE F_LOSNING_VSCODE_WORKSPACE_FILE' runtime.vscode_workspace_file)"
79
- printf 'EFFECTIVE_CODING_WORKER=%s\n' "$(config_or_env 'ACP_CODING_WORKER F_LOSNING_CODING_WORKER' execution.coding_worker)"
80
- printf 'EFFECTIVE_PROVIDER_QUOTA_COOLDOWNS=%s\n' "$(config_or_env 'ACP_PROVIDER_QUOTA_COOLDOWNS F_LOSNING_PROVIDER_QUOTA_COOLDOWNS' execution.provider_quota.cooldowns)"
81
- printf 'EFFECTIVE_PROVIDER_POOL_ORDER=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_ORDER F_LOSNING_PROVIDER_POOL_ORDER' execution.provider_pool_order)"
82
- printf 'EFFECTIVE_PROVIDER_POOL_NAME=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_POOL_NAME F_LOSNING_ACTIVE_PROVIDER_POOL_NAME')"
83
- printf 'EFFECTIVE_PROVIDER_POOL_BACKEND=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_BACKEND F_LOSNING_ACTIVE_PROVIDER_BACKEND')"
84
- printf 'EFFECTIVE_PROVIDER_POOL_MODEL=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_MODEL F_LOSNING_ACTIVE_PROVIDER_MODEL')"
85
- printf 'EFFECTIVE_PROVIDER_POOL_KEY=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_KEY F_LOSNING_ACTIVE_PROVIDER_KEY')"
86
- printf 'EFFECTIVE_PROVIDER_POOLS_EXHAUSTED=%s\n' "$(config_or_env 'ACP_PROVIDER_POOLS_EXHAUSTED F_LOSNING_PROVIDER_POOLS_EXHAUSTED')"
87
- printf 'EFFECTIVE_PROVIDER_POOL_SELECTION_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_SELECTION_REASON F_LOSNING_PROVIDER_POOL_SELECTION_REASON')"
88
- printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH F_LOSNING_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH')"
89
- printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_AT=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_AT F_LOSNING_PROVIDER_POOL_NEXT_ATTEMPT_AT')"
90
- printf 'EFFECTIVE_PROVIDER_POOL_LAST_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_LAST_REASON F_LOSNING_PROVIDER_POOL_LAST_REASON')"
91
- printf 'EFFECTIVE_CODEX_PROFILE_SAFE=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_SAFE F_LOSNING_CODEX_PROFILE_SAFE' execution.safe_profile)"
92
- printf 'EFFECTIVE_CODEX_PROFILE_BYPASS=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_BYPASS F_LOSNING_CODEX_PROFILE_BYPASS' execution.bypass_profile)"
93
- printf 'EFFECTIVE_CLAUDE_MODEL=%s\n' "$(config_or_env 'ACP_CLAUDE_MODEL F_LOSNING_CLAUDE_MODEL' execution.claude.model)"
94
- printf 'EFFECTIVE_CLAUDE_PERMISSION_MODE=%s\n' "$(config_or_env 'ACP_CLAUDE_PERMISSION_MODE F_LOSNING_CLAUDE_PERMISSION_MODE' execution.claude.permission_mode)"
95
- printf 'EFFECTIVE_CLAUDE_EFFORT=%s\n' "$(config_or_env 'ACP_CLAUDE_EFFORT F_LOSNING_CLAUDE_EFFORT' execution.claude.effort)"
96
- printf 'EFFECTIVE_CLAUDE_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_TIMEOUT_SECONDS F_LOSNING_CLAUDE_TIMEOUT_SECONDS' execution.claude.timeout_seconds)"
97
- printf 'EFFECTIVE_CLAUDE_MAX_ATTEMPTS=%s\n' "$(config_or_env 'ACP_CLAUDE_MAX_ATTEMPTS F_LOSNING_CLAUDE_MAX_ATTEMPTS' execution.claude.max_attempts)"
98
- printf 'EFFECTIVE_CLAUDE_RETRY_BACKOFF_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_RETRY_BACKOFF_SECONDS F_LOSNING_CLAUDE_RETRY_BACKOFF_SECONDS' execution.claude.retry_backoff_seconds)"
99
- printf 'EFFECTIVE_OPENCLAW_MODEL=%s\n' "$(config_or_env 'ACP_OPENCLAW_MODEL F_LOSNING_OPENCLAW_MODEL' execution.openclaw.model)"
100
- printf 'EFFECTIVE_OPENCLAW_THINKING=%s\n' "$(config_or_env 'ACP_OPENCLAW_THINKING F_LOSNING_OPENCLAW_THINKING' execution.openclaw.thinking)"
101
- printf 'EFFECTIVE_OPENCLAW_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_OPENCLAW_TIMEOUT_SECONDS F_LOSNING_OPENCLAW_TIMEOUT_SECONDS' execution.openclaw.timeout_seconds)"
69
+ printf 'EFFECTIVE_REPO_ROOT=%s\n' "$(config_or_env 'ACP_REPO_ROOT' repo.root)"
70
+ printf 'EFFECTIVE_AGENT_REPO_ROOT=%s\n' "$(config_or_env 'ACP_AGENT_REPO_ROOT' runtime.agent_repo_root)"
71
+ printf 'EFFECTIVE_WORKTREE_ROOT=%s\n' "$(config_or_env 'ACP_WORKTREE_ROOT' runtime.worktree_root)"
72
+ printf 'EFFECTIVE_RUNS_ROOT=%s\n' "$(config_or_env 'ACP_RUNS_ROOT' runtime.runs_root)"
73
+ printf 'EFFECTIVE_STATE_ROOT=%s\n' "$(config_or_env 'ACP_STATE_ROOT' runtime.state_root)"
74
+ printf 'EFFECTIVE_RETAINED_REPO_ROOT=%s\n' "$(config_or_env 'ACP_RETAINED_REPO_ROOT' runtime.retained_repo_root)"
75
+ printf 'EFFECTIVE_VSCODE_WORKSPACE_FILE=%s\n' "$(config_or_env 'ACP_VSCODE_WORKSPACE_FILE' runtime.vscode_workspace_file)"
76
+ printf 'EFFECTIVE_CODING_WORKER=%s\n' "$(config_or_env 'ACP_CODING_WORKER' execution.coding_worker)"
77
+ printf 'EFFECTIVE_PROVIDER_QUOTA_COOLDOWNS=%s\n' "$(config_or_env 'ACP_PROVIDER_QUOTA_COOLDOWNS' execution.provider_quota.cooldowns)"
78
+ printf 'EFFECTIVE_PROVIDER_POOL_ORDER=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_ORDER' execution.provider_pool_order)"
79
+ printf 'EFFECTIVE_PROVIDER_POOL_NAME=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_POOL_NAME')"
80
+ printf 'EFFECTIVE_PROVIDER_POOL_BACKEND=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_BACKEND')"
81
+ printf 'EFFECTIVE_PROVIDER_POOL_MODEL=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_MODEL')"
82
+ printf 'EFFECTIVE_PROVIDER_POOL_KEY=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_KEY')"
83
+ printf 'EFFECTIVE_PROVIDER_POOLS_EXHAUSTED=%s\n' "$(config_or_env 'ACP_PROVIDER_POOLS_EXHAUSTED')"
84
+ printf 'EFFECTIVE_PROVIDER_POOL_SELECTION_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_SELECTION_REASON')"
85
+ printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH')"
86
+ printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_AT=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_AT')"
87
+ printf 'EFFECTIVE_PROVIDER_POOL_LAST_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_LAST_REASON')"
88
+ printf 'EFFECTIVE_CODEX_PROFILE_SAFE=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_SAFE' execution.safe_profile)"
89
+ printf 'EFFECTIVE_CODEX_PROFILE_BYPASS=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_BYPASS' execution.bypass_profile)"
90
+ printf 'EFFECTIVE_CLAUDE_MODEL=%s\n' "$(config_or_env 'ACP_CLAUDE_MODEL' execution.claude.model)"
91
+ printf 'EFFECTIVE_CLAUDE_PERMISSION_MODE=%s\n' "$(config_or_env 'ACP_CLAUDE_PERMISSION_MODE' execution.claude.permission_mode)"
92
+ printf 'EFFECTIVE_CLAUDE_EFFORT=%s\n' "$(config_or_env 'ACP_CLAUDE_EFFORT' execution.claude.effort)"
93
+ printf 'EFFECTIVE_CLAUDE_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_TIMEOUT_SECONDS' execution.claude.timeout_seconds)"
94
+ printf 'EFFECTIVE_CLAUDE_MAX_ATTEMPTS=%s\n' "$(config_or_env 'ACP_CLAUDE_MAX_ATTEMPTS' execution.claude.max_attempts)"
95
+ printf 'EFFECTIVE_CLAUDE_RETRY_BACKOFF_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_RETRY_BACKOFF_SECONDS' execution.claude.retry_backoff_seconds)"
96
+ printf 'EFFECTIVE_OPENCLAW_MODEL=%s\n' "$(config_or_env 'ACP_OPENCLAW_MODEL' execution.openclaw.model)"
97
+ printf 'EFFECTIVE_OPENCLAW_THINKING=%s\n' "$(config_or_env 'ACP_OPENCLAW_THINKING' execution.openclaw.thinking)"
98
+ printf 'EFFECTIVE_OPENCLAW_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_OPENCLAW_TIMEOUT_SECONDS' execution.openclaw.timeout_seconds)"
@@ -35,7 +35,7 @@ RECONCILE_COMMAND=""
35
35
  ADAPTER_ID="$(flow_resolve_adapter_id "${CONFIG_YAML}")"
36
36
  ISSUE_SESSION_PREFIX="$(flow_resolve_issue_session_prefix "${CONFIG_YAML}")"
37
37
  PR_SESSION_PREFIX="$(flow_resolve_pr_session_prefix "${CONFIG_YAML}")"
38
- CODING_WORKER="${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-codex}}"
38
+ CODING_WORKER="${ACP_CODING_WORKER:-codex}"
39
39
  CODEX_PROFILE_SAFE="${ACP_CODEX_PROFILE_SAFE:-${F_LOSNING_CODEX_PROFILE_SAFE:-${CODEX_PROFILE_SAFE:-f_losning_safe_auto}}}"
40
40
  CODEX_PROFILE_BYPASS="${ACP_CODEX_PROFILE_BYPASS:-${F_LOSNING_CODEX_PROFILE_BYPASS:-${CODEX_PROFILE_BYPASS:-f_losning_yolo}}}"
41
41
  if [[ "$MODE" == "bypass" ]]; then
@@ -64,23 +64,47 @@ RESIDENT_OPENCLAW_CONFIG_PATH="${ACP_RESIDENT_OPENCLAW_CONFIG_PATH:-${F_LOSNING_
64
64
  OPENCLAW_MODEL="${OPENCLAW_MODEL:-${ACP_OPENCLAW_MODEL:-${F_LOSNING_OPENCLAW_MODEL:-openrouter/qwen/qwen3.6-plus-preview:free}}}"
65
65
  OPENCLAW_THINKING="${OPENCLAW_THINKING:-${ACP_OPENCLAW_THINKING:-${F_LOSNING_OPENCLAW_THINKING:-low}}}"
66
66
  OPENCLAW_TIMEOUT_SECONDS="${OPENCLAW_TIMEOUT_SECONDS:-${ACP_OPENCLAW_TIMEOUT_SECONDS:-${F_LOSNING_OPENCLAW_TIMEOUT_SECONDS:-900}}}"
67
+ OLLAMA_MODEL="${ACP_OLLAMA_MODEL:-${F_LOSNING_OLLAMA_MODEL:-qwen2.5-coder:7b}}"
68
+ OLLAMA_BASE_URL="${ACP_OLLAMA_BASE_URL:-${F_LOSNING_OLLAMA_BASE_URL:-http://localhost:11434}}"
69
+ OLLAMA_TIMEOUT_SECONDS="${ACP_OLLAMA_TIMEOUT_SECONDS:-${F_LOSNING_OLLAMA_TIMEOUT_SECONDS:-900}}"
70
+ PI_MODEL="${ACP_PI_MODEL:-${F_LOSNING_PI_MODEL:-openrouter/qwen/qwen3.6-plus:free}}"
71
+ PI_THINKING="${ACP_PI_THINKING:-${F_LOSNING_PI_THINKING:-low}}"
72
+ PI_TIMEOUT_SECONDS="${ACP_PI_TIMEOUT_SECONDS:-${F_LOSNING_PI_TIMEOUT_SECONDS:-900}}"
73
+ PI_STALL_SECONDS="${ACP_PI_STALL_SECONDS:-${F_LOSNING_PI_STALL_SECONDS:-300}}"
74
+ OPENCODE_MODEL="${ACP_OPENCODE_MODEL:-${F_LOSNING_OPENCODE_MODEL:-anthropic/claude-sonnet-4-20250514}}"
75
+ OPENCODE_TIMEOUT_SECONDS="${ACP_OPENCODE_TIMEOUT_SECONDS:-${F_LOSNING_OPENCODE_TIMEOUT_SECONDS:-900}}"
76
+ KILO_MODEL="${ACP_KILO_MODEL:-${F_LOSNING_KILO_MODEL:-anthropic/claude-sonnet-4-20250514}}"
77
+ KILO_TIMEOUT_SECONDS="${ACP_KILO_TIMEOUT_SECONDS:-${F_LOSNING_KILO_TIMEOUT_SECONDS:-900}}"
67
78
  printf -v SESSION_Q '%q' "$SESSION"
68
79
  printf -v CONFIG_YAML_Q '%q' "$CONFIG_YAML"
69
80
  printf -v ADAPTER_ID_Q '%q' "$ADAPTER_ID"
70
- RECONCILE_ENV_PREFIX="ACP_PROJECT_ID=${ADAPTER_ID_Q} AGENT_PROJECT_ID=${ADAPTER_ID_Q} AGENT_CONTROL_PLANE_CONFIG=${CONFIG_YAML_Q} ACP_CONFIG=${CONFIG_YAML_Q}"
81
+ printf -v CANONICAL_REPO_ROOT_Q '%q' "$CANONICAL_REPO_ROOT"
82
+ RECONCILE_ENV_PREFIX="ACP_PROJECT_ID=${ADAPTER_ID_Q} AGENT_PROJECT_ID=${ADAPTER_ID_Q} AGENT_CONTROL_PLANE_CONFIG=${CONFIG_YAML_Q} ACP_CONFIG=${CONFIG_YAML_Q} ACP_ROOT=${CANONICAL_REPO_ROOT_Q} AGENT_CONTROL_PLANE_ROOT=${CANONICAL_REPO_ROOT_Q}"
83
+
84
+ # The materialized skills surface is cleaned up after each heartbeat cycle.
85
+ # Reconcile runs post-tmux via nohup, after the skills dir is gone.
86
+ # Use the permanent runtime-home/tools/bin path derived from AGENT_PLATFORM_HOME.
87
+ _runtime_tools_bin="${AGENT_PLATFORM_HOME:-${HOME}/.agent-runtime}/runtime-home/tools/bin"
88
+ if [[ -f "${_runtime_tools_bin}/reconcile-pr-worker.sh" ]]; then
89
+ RECONCILE_ISSUE_BIN="${_runtime_tools_bin}/reconcile-issue-worker.sh"
90
+ RECONCILE_PR_BIN="${_runtime_tools_bin}/reconcile-pr-worker.sh"
91
+ else
92
+ RECONCILE_ISSUE_BIN="${WORKSPACE_DIR}/bin/reconcile-issue-worker.sh"
93
+ RECONCILE_PR_BIN="${WORKSPACE_DIR}/bin/reconcile-pr-worker.sh"
94
+ fi
71
95
 
72
96
  case "$SESSION" in
73
97
  "${ISSUE_SESSION_PREFIX}"*)
74
98
  TASK_KIND="issue"
75
99
  TASK_ID="${ISSUE_ID:-${SESSION#${ISSUE_SESSION_PREFIX}}}"
76
100
  if [[ "${RESIDENT_WORKER_ENABLED}" != "yes" ]]; then
77
- RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${WORKSPACE_DIR}/bin/reconcile-issue-worker.sh ${SESSION_Q}"
101
+ RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${RECONCILE_ISSUE_BIN} ${SESSION_Q}"
78
102
  fi
79
103
  ;;
80
104
  "${PR_SESSION_PREFIX}"*)
81
105
  TASK_KIND="pr"
82
106
  TASK_ID="${PR_NUMBER:-${SESSION#${PR_SESSION_PREFIX}}}"
83
- RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${WORKSPACE_DIR}/bin/reconcile-pr-worker.sh ${SESSION_Q}"
107
+ RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${RECONCILE_PR_BIN} ${SESSION_Q}"
84
108
  ;;
85
109
  esac
86
110
 
@@ -219,11 +243,36 @@ case "$CODING_WORKER" in
219
243
  bash "${FLOW_TOOLS_DIR}/agent-project-run-openclaw-session" "${ARGS[@]}"
220
244
  ;;
221
245
  opencode)
246
+ ARGS+=(
247
+ --opencode-model "${OPENCODE_MODEL}"
248
+ --opencode-timeout-seconds "${OPENCODE_TIMEOUT_SECONDS}"
249
+ )
222
250
  bash "${FLOW_TOOLS_DIR}/agent-project-run-opencode-session" "${ARGS[@]}"
223
251
  ;;
224
252
  kilo)
253
+ ARGS+=(
254
+ --kilo-model "${KILO_MODEL}"
255
+ --kilo-timeout-seconds "${KILO_TIMEOUT_SECONDS}"
256
+ )
225
257
  bash "${FLOW_TOOLS_DIR}/agent-project-run-kilo-session" "${ARGS[@]}"
226
258
  ;;
259
+ ollama)
260
+ ARGS+=(
261
+ --ollama-model "${OLLAMA_MODEL}"
262
+ --ollama-base-url "${OLLAMA_BASE_URL}"
263
+ --ollama-timeout-seconds "${OLLAMA_TIMEOUT_SECONDS}"
264
+ )
265
+ bash "${FLOW_TOOLS_DIR}/agent-project-run-ollama-session" "${ARGS[@]}"
266
+ ;;
267
+ pi)
268
+ ARGS+=(
269
+ --pi-model "${PI_MODEL}"
270
+ --pi-thinking "${PI_THINKING}"
271
+ --pi-timeout-seconds "${PI_TIMEOUT_SECONDS}"
272
+ --pi-stall-seconds "${PI_STALL_SECONDS}"
273
+ )
274
+ bash "${FLOW_TOOLS_DIR}/agent-project-run-pi-session" "${ARGS[@]}"
275
+ ;;
227
276
  *)
228
277
  echo "unsupported coding worker: ${CODING_WORKER}" >&2
229
278
  exit 1
@@ -22,7 +22,7 @@ Options:
22
22
  --worktree-root <path> Worktree parent root
23
23
  --retained-repo-root <path> Optional retained/manual checkout root
24
24
  --vscode-workspace-file <path> Optional VS Code workspace file
25
- --coding-worker <codex|openclaw|claude>
25
+ --coding-worker <codex|openclaw|claude|ollama|pi|opencode|kilo>
26
26
  Default coding backend (default: openclaw)
27
27
  --claude-model <model> Claude model alias or full name
28
28
  --claude-permission-mode <mode> Claude permission mode (default: acceptEdits)
@@ -97,9 +97,9 @@ if [[ ! "$profile_id" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
97
97
  fi
98
98
 
99
99
  case "$coding_worker" in
100
- codex|openclaw|claude) ;;
100
+ codex|openclaw|claude|ollama|pi|opencode|kilo) ;;
101
101
  *)
102
- echo "--coding-worker must be codex, openclaw, or claude" >&2
102
+ echo "--coding-worker must be codex, openclaw, claude, ollama, pi, opencode, or kilo" >&2
103
103
  exit 1
104
104
  ;;
105
105
  esac
@@ -271,6 +271,21 @@ execution:
271
271
  model: "${openclaw_model}"
272
272
  thinking: "${openclaw_thinking}"
273
273
  timeout_seconds: ${openclaw_timeout_seconds}
274
+ ollama:
275
+ model: "qwen2.5-coder:7b"
276
+ base_url: "http://localhost:11434"
277
+ timeout_seconds: 900
278
+ pi:
279
+ model: "openrouter/qwen/qwen3.6-plus:free"
280
+ thinking: "low"
281
+ timeout_seconds: 900
282
+ stall_seconds: 300
283
+ opencode:
284
+ model: "anthropic/claude-sonnet-4-20250514"
285
+ timeout_seconds: 900
286
+ kilo:
287
+ model: "anthropic/claude-sonnet-4-20250514"
288
+ timeout_seconds: 900
274
289
  review_requires_independent_final_review: true
275
290
  verification:
276
291
  web_playwright_command: "pnpm exec playwright test"
@@ -30,7 +30,7 @@ LOCAL_INSTALL_POLICY_BIN="${WORKSPACE_DIR}/bin/issue-requires-local-workspace-in
30
30
  SESSION="${ISSUE_SESSION_PREFIX}${ISSUE_ID}"
31
31
  RUN_DIR="${RUNS_ROOT}/${SESSION}"
32
32
  UPDATE_LABELS_BIN="${WORKSPACE_DIR}/bin/agent-github-update-labels"
33
- CODING_WORKER="${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-codex}}"
33
+ CODING_WORKER="${ACP_CODING_WORKER:-codex}"
34
34
  launch_success="no"
35
35
  label_rollback_armed="no"
36
36
  RECURRING_CHECKLIST_SYNC_BIN="${FLOW_TOOLS_DIR}/sync-recurring-issue-checklist.sh"
@@ -133,6 +133,34 @@ PR_LINKED_ISSUE_ID="$(jq -r '.linkedIssueId // ""' <<<"$RISK_JSON")"
133
133
  PR_FILES_TEXT="$(jq -r '.files[] | "- " + .' <<<"$RISK_JSON")"
134
134
  PR_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
135
135
  PR_DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$PR_REPO_ROOT}}"
136
+ render_pr_context_reads_text() {
137
+ local repo_root="${1:?repo root required}"
138
+ local -a candidate_paths=(
139
+ "${repo_root}/AGENTS.md"
140
+ "${repo_root}/openspec/AGENT_RULES.md"
141
+ "${repo_root}/openspec/AGENTS.md"
142
+ "${repo_root}/openspec/project.md"
143
+ "${repo_root}/openspec/CONVENTIONS.md"
144
+ "${repo_root}/docs/TESTING_AND_SEED_POLICY.md"
145
+ )
146
+ local -a existing_paths=()
147
+ local candidate_path=""
148
+
149
+ for candidate_path in "${candidate_paths[@]}"; do
150
+ if [[ -f "${candidate_path}" ]]; then
151
+ existing_paths+=("${candidate_path}")
152
+ fi
153
+ done
154
+
155
+ if [[ "${#existing_paths[@]}" -eq 0 ]]; then
156
+ printf '%s\n' '- No repo-specific context files were found under the expected AGENTS/OpenSpec/testing-doc locations; rely on the current diff and nearby source.'
157
+ return 0
158
+ fi
159
+
160
+ printf '%s\n' "${existing_paths[@]}" | sed 's/^/- `/' | sed 's/$/`/'
161
+ }
162
+
163
+ PR_CONTEXT_READS_TEXT="$(render_pr_context_reads_text "${PR_REPO_ROOT}")"
136
164
  PR_CHECK_FAILURES_TEXT="$(jq -r '(.checkFailures + .pendingChecks)[]? | "- " + .' <<<"$RISK_JSON")"
137
165
  if [[ -z "$PR_CHECK_FAILURES_TEXT" ]]; then
138
166
  PR_CHECK_FAILURES_TEXT="- none reported"
@@ -293,6 +321,7 @@ PR_MERGE_STATE_STATUS="$PR_MERGE_STATE_STATUS" \
293
321
  PR_MERGEABLE_STATUS="$PR_MERGEABLE_STATUS" \
294
322
  PR_CHECKS_TEXT="$PR_CHECKS_TEXT" \
295
323
  PR_FILES_TEXT="$PR_FILES_TEXT" \
324
+ PR_CONTEXT_READS_TEXT="$PR_CONTEXT_READS_TEXT" \
296
325
  PR_CHECK_FAILURES_TEXT="$PR_CHECK_FAILURES_TEXT" \
297
326
  PR_MISSING_REASONS_TEXT="$PR_MISSING_REASONS_TEXT" \
298
327
  PR_REVIEW_FINDINGS_TEXT="$PR_REVIEW_FINDINGS_TEXT" \
@@ -403,6 +432,7 @@ const replacements = {
403
432
  '{PR_MERGEABLE_STATUS}': process.env.PR_MERGEABLE_STATUS || '',
404
433
  '{PR_CHECKS_TEXT}': process.env.PR_CHECKS_TEXT || '',
405
434
  '{PR_FILES_TEXT}': process.env.PR_FILES_TEXT || '',
435
+ '{PR_CONTEXT_READS_TEXT}': process.env.PR_CONTEXT_READS_TEXT || '',
406
436
  '{PR_CHECK_FAILURES_TEXT}': process.env.PR_CHECK_FAILURES_TEXT || '',
407
437
  '{PR_MISSING_REASONS_TEXT}': process.env.PR_MISSING_REASONS_TEXT || '',
408
438
  '{PR_REVIEW_FINDINGS_TEXT}': process.env.PR_REVIEW_FINDINGS_TEXT || '',
@@ -123,6 +123,35 @@ PR_FILES_TEXT="$(jq -r '.files[] | "- " + .' <<<"$RISK_JSON")"
123
123
  PR_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
124
124
  PR_DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$PR_REPO_ROOT}}"
125
125
 
126
+ render_pr_context_reads_text() {
127
+ local repo_root="${1:?repo root required}"
128
+ local -a candidate_paths=(
129
+ "${repo_root}/AGENTS.md"
130
+ "${repo_root}/openspec/AGENT_RULES.md"
131
+ "${repo_root}/openspec/AGENTS.md"
132
+ "${repo_root}/openspec/project.md"
133
+ "${repo_root}/openspec/CONVENTIONS.md"
134
+ "${repo_root}/docs/TESTING_AND_SEED_POLICY.md"
135
+ )
136
+ local -a existing_paths=()
137
+ local candidate_path=""
138
+
139
+ for candidate_path in "${candidate_paths[@]}"; do
140
+ if [[ -f "${candidate_path}" ]]; then
141
+ existing_paths+=("${candidate_path}")
142
+ fi
143
+ done
144
+
145
+ if [[ "${#existing_paths[@]}" -eq 0 ]]; then
146
+ printf '%s\n' '- No repo-specific context files were found under the expected AGENTS/OpenSpec/testing-doc locations; rely on the current diff and nearby source.'
147
+ return 0
148
+ fi
149
+
150
+ printf '%s\n' "${existing_paths[@]}" | sed 's/^/- `/' | sed 's/$/`/'
151
+ }
152
+
153
+ PR_CONTEXT_READS_TEXT="$(render_pr_context_reads_text "${PR_REPO_ROOT}")"
154
+
126
155
  case "$PR_AGENT_LANE" in
127
156
  double-check-1)
128
157
  PR_REVIEW_STAGE_TEXT="Independent agent double-check 1 of 2. A clean pass should advance this PR to the second review pass, not merge it yet."
@@ -157,6 +186,7 @@ PR_CHECKS_BYPASSED="$PR_CHECKS_BYPASSED" \
157
186
  PR_MERGE_STATE_STATUS="$PR_MERGE_STATE_STATUS" \
158
187
  PR_CHECKS_TEXT="$PR_CHECKS_TEXT" \
159
188
  PR_FILES_TEXT="$PR_FILES_TEXT" \
189
+ PR_CONTEXT_READS_TEXT="$PR_CONTEXT_READS_TEXT" \
160
190
  PR_REPO_ROOT="$PR_REPO_ROOT" \
161
191
  PR_DEPENDENCY_SOURCE_ROOT="$PR_DEPENDENCY_SOURCE_ROOT" \
162
192
  REPO_SLUG="$REPO_SLUG" \
@@ -183,6 +213,7 @@ const replacements = {
183
213
  '{PR_MERGE_STATE_STATUS}': process.env.PR_MERGE_STATE_STATUS || '',
184
214
  '{PR_CHECKS_TEXT}': process.env.PR_CHECKS_TEXT || '',
185
215
  '{PR_FILES_TEXT}': process.env.PR_FILES_TEXT || '',
216
+ '{PR_CONTEXT_READS_TEXT}': process.env.PR_CONTEXT_READS_TEXT || '',
186
217
  '{REPO_ROOT}': process.env.PR_REPO_ROOT || '',
187
218
  '{DEPENDENCY_SOURCE_ROOT}': process.env.PR_DEPENDENCY_SOURCE_ROOT || '',
188
219
  };
@@ -29,7 +29,7 @@ PENDING_LAUNCH_DIR="${ACP_PENDING_LAUNCH_DIR:-${F_LOSNING_PENDING_LAUNCH_DIR:-${
29
29
  SCHEDULED_STATE_DIR="${STATE_ROOT}/scheduled-issues"
30
30
  CONTROLLER_FILE="$(flow_resident_issue_controller_file "${CONFIG_YAML}" "${ISSUE_ID}")"
31
31
  RESIDENT_META_FILE="$(flow_resident_issue_meta_file "${CONFIG_YAML}" "${ISSUE_ID}")"
32
- CODING_WORKER="${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-codex}}"
32
+ CODING_WORKER="${ACP_CODING_WORKER:-codex}"
33
33
  MAX_IMMEDIATE_CYCLES="$(flow_resident_issue_controller_max_immediate_cycles "${CONFIG_YAML}")"
34
34
  POLL_SECONDS="$(flow_resident_issue_controller_poll_seconds "${CONFIG_YAML}")"
35
35
  IDLE_TIMEOUT_SECONDS="$(flow_resident_issue_controller_idle_timeout_seconds "${CONFIG_YAML}")"
@@ -192,7 +192,7 @@ issue_id_is_scheduled() {
192
192
 
193
193
  controller_refresh_execution_context() {
194
194
  unset \
195
- ACP_CODING_WORKER F_LOSNING_CODING_WORKER \
195
+ ACP_CODING_WORKER \
196
196
  ACP_CODEX_PROFILE_SAFE F_LOSNING_CODEX_PROFILE_SAFE \
197
197
  ACP_CODEX_PROFILE_BYPASS F_LOSNING_CODEX_PROFILE_BYPASS \
198
198
  ACP_CLAUDE_MODEL F_LOSNING_CLAUDE_MODEL \
@@ -216,7 +216,7 @@ controller_refresh_execution_context() {
216
216
  ACP_PROVIDER_POOL_LAST_REASON F_LOSNING_PROVIDER_POOL_LAST_REASON
217
217
  flow_export_execution_env "${CONFIG_YAML}"
218
218
  flow_export_project_env_aliases
219
- CODING_WORKER="${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-codex}}"
219
+ CODING_WORKER="${ACP_CODING_WORKER:-codex}"
220
220
  controller_capture_active_provider_context
221
221
  }
222
222
 
@@ -544,7 +544,7 @@ controller_provider_state() {
544
544
 
545
545
  provider_state="$(
546
546
  env \
547
- -u ACP_CODING_WORKER -u F_LOSNING_CODING_WORKER \
547
+ -u ACP_CODING_WORKER \
548
548
  -u ACP_CODEX_PROFILE_SAFE -u F_LOSNING_CODEX_PROFILE_SAFE \
549
549
  -u ACP_CODEX_PROFILE_BYPASS -u F_LOSNING_CODEX_PROFILE_BYPASS \
550
550
  -u ACP_CLAUDE_MODEL -u F_LOSNING_CLAUDE_MODEL \
@@ -6,11 +6,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
6
  source "${SCRIPT_DIR}/flow-config-lib.sh"
7
7
 
8
8
  CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
9
- SOURCE_REPO_ROOT="${ACP_SOURCE_REPO_ROOT:-${F_LOSNING_SOURCE_REPO_ROOT:-$(flow_resolve_retained_repo_root "${CONFIG_YAML}")}}"
9
+ SOURCE_REPO_ROOT="${ACP_SOURCE_REPO_ROOT:-$(flow_resolve_retained_repo_root "${CONFIG_YAML}")}"
10
10
  CANONICAL_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
11
11
  AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
12
12
  DEFAULT_BRANCH="$(flow_resolve_default_branch "${CONFIG_YAML}")"
13
- REMOTE_NAME="${ACP_REMOTE_NAME:-${F_LOSNING_REMOTE_NAME:-origin}}"
13
+ REMOTE_NAME="${ACP_REMOTE_NAME:-origin}"
14
14
  FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
15
15
  FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
16
16
 
@@ -13,9 +13,9 @@ STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
13
13
  LOCK_DIR="${STATE_ROOT}/dependency-baseline.lock"
14
14
  PID_FILE="${LOCK_DIR}/pid"
15
15
  HASH_FILE="${STATE_ROOT}/dependency-baseline.sha256"
16
- PACKAGE_MANAGER_BIN="${ACP_PACKAGE_MANAGER_BIN:-${F_LOSNING_PACKAGE_MANAGER_BIN:-pnpm}}"
17
- WORKSPACE_BUILD_PACKAGES_RAW="${ACP_WORKSPACE_BUILD_PACKAGES:-${F_LOSNING_WORKSPACE_BUILD_PACKAGES:-}}"
18
- WORKSPACE_BUILD_ARTIFACTS_RAW="${ACP_WORKSPACE_BUILD_ARTIFACTS:-${F_LOSNING_WORKSPACE_BUILD_ARTIFACTS:-}}"
16
+ PACKAGE_MANAGER_BIN="${ACP_PACKAGE_MANAGER_BIN:-pnpm}"
17
+ WORKSPACE_BUILD_PACKAGES_RAW="${ACP_WORKSPACE_BUILD_PACKAGES:-}"
18
+ WORKSPACE_BUILD_ARTIFACTS_RAW="${ACP_WORKSPACE_BUILD_ARTIFACTS:-}"
19
19
  declare -a WORKSPACE_BUILD_PACKAGES=()
20
20
  declare -a WORKSPACE_BUILD_ARTIFACTS=()
21
21
 
@@ -207,7 +207,10 @@ sync_tree_rsync() {
207
207
  local target_dir="${2:?target dir required}"
208
208
  [[ -d "${source_dir}" ]] || return 0
209
209
  mkdir -p "${target_dir}"
210
- rsync -a --delete --exclude='.git/' "${source_dir}/" "${target_dir}/"
210
+ if rsync -a --delete --exclude='.git/' "${source_dir}/" "${target_dir}/"; then
211
+ return 0
212
+ fi
213
+ sync_tree_copy_mode "${source_dir}" "${target_dir}"
211
214
  }
212
215
 
213
216
  reset_runtime_skill_targets() {
@@ -2,13 +2,9 @@ You are the PR repair worker for `{REPO_SLUG}`.
2
2
 
3
3
  Before making any change:
4
4
 
5
- 1. Read `{REPO_ROOT}/AGENTS.md`.
6
- 2. If present, read `{REPO_ROOT}/openspec/AGENT_RULES.md`.
7
- 3. If present, read `{REPO_ROOT}/openspec/AGENTS.md`.
8
- 4. If present, read `{REPO_ROOT}/openspec/project.md`.
9
- 5. If present, read `{REPO_ROOT}/openspec/CONVENTIONS.md`.
10
- 6. If present, read `{REPO_ROOT}/docs/TESTING_AND_SEED_POLICY.md`.
11
- 7. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
5
+ 1. Read the following repo context before changing code:
6
+ {PR_CONTEXT_READS_TEXT}
7
+ 2. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
12
8
 
13
9
  PR metadata:
14
10
 
@@ -2,13 +2,9 @@ You are the PR merge-repair worker for `{REPO_SLUG}`.
2
2
 
3
3
  Before making any change:
4
4
 
5
- 1. Read `{REPO_ROOT}/AGENTS.md`.
6
- 2. If present, read `{REPO_ROOT}/openspec/AGENT_RULES.md`.
7
- 3. If present, read `{REPO_ROOT}/openspec/AGENTS.md`.
8
- 4. If present, read `{REPO_ROOT}/openspec/project.md`.
9
- 5. If present, read `{REPO_ROOT}/openspec/CONVENTIONS.md`.
10
- 6. If present, read `{REPO_ROOT}/docs/TESTING_AND_SEED_POLICY.md`.
11
- 7. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
5
+ 1. Read the following repo context before changing code:
6
+ {PR_CONTEXT_READS_TEXT}
7
+ 2. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
12
8
 
13
9
  PR metadata:
14
10
 
@@ -2,7 +2,8 @@ You are the PR review and final-merge worker for `{REPO_SLUG}`.
2
2
 
3
3
  Before making any decision:
4
4
 
5
- 1. Read `{REPO_ROOT}/AGENTS.md` and any repo-specific conventions or design docs relevant to the PR.
5
+ 1. Read the following repo context before deciding:
6
+ {PR_CONTEXT_READS_TEXT}
6
7
  2. Do not edit product code in this worktree. This is review and final-review only.
7
8
  3. Never run dependency bootstrap or workspace-mutating commands here.
8
9