devlyn-cli 2.10.1 → 3.0.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/AGENTS.md +4 -9
- package/CLAUDE.md +11 -15
- package/README.md +31 -7
- package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.json +25 -0
- package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.md +10 -0
- package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.json +18 -0
- package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.md +9 -0
- package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.json +18 -0
- package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.md +9 -0
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/l2_risk_probes/result.json +28 -0
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F23-cli-fulfillment-wave/l2_risk_probes/result.json +28 -0
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F25-cli-cart-promotion-rules/l2_risk_probes/result.json +30 -0
- package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/l2_risk_probes/result.json +32 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.json +44 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.md +16 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.json +18 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.md +9 -0
- package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.md +15 -0
- package/bin/devlyn.js +6 -1
- package/config/skills/_shared/.ruff.toml +2 -0
- package/config/skills/_shared/adapters/claude.md +9 -1
- package/config/skills/_shared/adapters/codex.md +5 -0
- package/config/skills/_shared/adapters/grok.md +4 -2
- package/config/skills/_shared/archive_run.py +738 -56
- package/config/skills/_shared/codex-config.md +19 -4
- package/config/skills/_shared/codex-monitored.sh +81 -12
- package/config/skills/_shared/collect-codex-findings.py +311 -128
- package/config/skills/_shared/engine-preflight.md +8 -7
- package/config/skills/_shared/expected.schema.json +61 -0
- package/config/skills/_shared/finish-gate.py +12 -11
- package/config/skills/_shared/grok-anchor-guard.py +18 -1
- package/config/skills/_shared/invocation-receipt.py +1041 -0
- package/config/skills/_shared/judge-output-parser.py +200 -0
- package/config/skills/_shared/judge-role-evidence.py +273 -0
- package/config/skills/_shared/process-evidence.py +909 -0
- package/config/skills/_shared/resolve-bootstrap.py +776 -84
- package/config/skills/_shared/resolve-stop-hook.py +33 -1
- package/config/skills/_shared/role-config.py +552 -0
- package/config/skills/_shared/run-bounded.py +1 -1
- package/config/skills/_shared/spec-verify-check.py +749 -181
- package/config/skills/_shared/state-phase-write.py +1838 -58
- package/config/skills/_shared/terminal-claim-check.py +15 -0
- package/config/skills/_shared/verify-merge-findings.py +958 -51
- package/config/skills/devlyn:engines/SKILL.md +8 -16
- package/config/skills/devlyn:ideate/references/spec-template.md +1 -0
- package/config/skills/devlyn:queue/SKILL.md +7 -4
- package/config/skills/devlyn:resolve/SKILL.md +91 -33
- package/config/skills/devlyn:resolve/references/outer-loop.md +15 -0
- package/config/skills/devlyn:resolve/references/phases/build-gate.md +31 -2
- package/config/skills/devlyn:resolve/references/phases/implement.md +3 -2
- package/config/skills/devlyn:resolve/references/phases/verify.md +120 -84
- package/config/skills/devlyn:resolve/references/state-schema.md +22 -8
- package/package.json +5 -1
- package/scripts/lint-skills.sh +314 -285
|
@@ -38,6 +38,20 @@ CODEX_MONITORED_ISOLATED=1 bash "$CODEX_MONITORED_PATH" \
|
|
|
38
38
|
bash "$CODEX_MONITORED_PATH" \
|
|
39
39
|
-C <project-root> \
|
|
40
40
|
-s workspace-write \
|
|
41
|
+
-c sandbox_workspace_write.network_access=false \
|
|
42
|
+
-c model_reasoning_effort=xhigh \
|
|
43
|
+
"<inlined-prompt>"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**CI-equivalent BUILD_GATE** keeps the same write sandbox and enables general
|
|
47
|
+
outbound network access inside that sandbox, including the loopback servers and
|
|
48
|
+
network-backed test gates that CI may exercise:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
bash "$CODEX_MONITORED_PATH" \
|
|
52
|
+
-C <project-root> \
|
|
53
|
+
-s workspace-write \
|
|
54
|
+
-c sandbox_workspace_write.network_access=true \
|
|
41
55
|
-c model_reasoning_effort=xhigh \
|
|
42
56
|
"<inlined-prompt>"
|
|
43
57
|
```
|
|
@@ -45,10 +59,11 @@ bash "$CODEX_MONITORED_PATH" \
|
|
|
45
59
|
Notes:
|
|
46
60
|
- `-C` — project root so Codex's working directory matches.
|
|
47
61
|
- `-s read-only` / `-s workspace-write` — sandbox policy. Use workspace-write for implementation/probe phases that write tracked files or `.devlyn` artifacts.
|
|
62
|
+
- `-c sandbox_workspace_write.network_access=<true|false>` — required and receipt-bound for mutation phases: `true` only for BUILD_GATE and, per call, PROBE-DERIVE when the probe's visible Verification command requires a localhost service; `false` for PLAN, IMPLEMENT, CLEANUP, and PROBE-DERIVE by default. This allows CI-equivalent loopback/network tests without widening to `danger-full-access` and prevents user configuration from silently changing other phases.
|
|
48
63
|
- `-c model_reasoning_effort=xhigh` — config override for reasoning depth. Required for deep critique; skills may choose `high` or `medium` when thoroughness doesn't warrant xhigh.
|
|
49
|
-
- **
|
|
64
|
+
- **For every receipt-bound Codex call, add `--json -m <model_requested>` to the recipes above**, matching the model recorded at spawn; keep the skill’s existing model-selection rules. Other routes keep their omission rules unless an explicit role profile supplies a model: normal workers may inherit user config, while unconfigured isolated VERIFY uses its CLI default. Explicit profiles use role-config.py options and the separate judge-role-evidence.py contract; they do not relax mutation receipts. Omission proves neither model identity nor role fitness. Re-certify seats after model/version changes before re-pinning them.
|
|
50
65
|
- `CODEX_MONITORED_ISOLATED=1` — required for bounded read-only critique/probe/judge calls. The wrapper adds `--ignore-user-config --ignore-rules --ephemeral --disable codex_hooks --disable hooks` so user config, AGENTS.md, hooks, and project rules cannot add hidden context, tool calls, or transcript side effects. Do not set it for workspace-write implementation phases.
|
|
51
|
-
- Wrapper calls are **foreground-blocking**. Never launch them via a backgrounded shell (`run_in_background`, `&`, `nohup`) and never end the orchestrator message while one runs: a headless print-mode session kills backgrounded children at wind-down (observed 2026-07-07: an FS1 A-arm IMPLEMENT codex call was killed at turn end → 0-byte delivery). The heartbeat stream is the observability channel; block on the call.
|
|
66
|
+
- Wrapper calls are **foreground-blocking**. Never launch them via a backgrounded shell (`run_in_background`, `&`, `nohup`) and never end the orchestrator message while one runs: a headless print-mode session kills backgrounded children at wind-down (observed 2026-07-07: an FS1 A-arm IMPLEMENT codex call was killed at turn end → 0-byte delivery). The heartbeat stream is the observability channel; block on the call. Interactive Claude Code caps a foreground Bash call at `BASH_MAX_TIMEOUT_MS` (the installer sets at least 3600000 ms, IMPLEMENT's effective outer ceiling), so every foreground Codex wrapper call must pass the Bash `timeout` explicitly at that ceiling or the phase's own budget (for example, 600s judges) — never rely on the 120 s default.
|
|
52
67
|
- Raw `codex exec ...` invocations are **forbidden** in skill prompts. The benchmark variant arm runs a PATH shim (`scripts/codex-shim/codex`) that transparently re-routes any raw `codex exec` to the wrapper as a safety net, but skills should always emit the wrapper form directly so the orchestrator's first-attempt has the right shape. Two prior iterations (iter-0006 universal foreground ban, iter-0008 prompt-level kill-shape contract) failed because the orchestrator picked starvation-prone shapes (`codex exec ... 2>&1 | tail -200`) from its own pattern prior — the wrapper plus the shim is the runtime binding layer those iters lacked. See `autoresearch/iterations/0009-wrapper-and-hook.md`.
|
|
53
68
|
|
|
54
69
|
## Availability check
|
|
@@ -63,10 +78,10 @@ If the check fails while Codex is explicitly selected or conditionally required
|
|
|
63
78
|
|
|
64
79
|
## Why CLI over other paths
|
|
65
80
|
|
|
66
|
-
The local Codex CLI
|
|
81
|
+
The local Codex CLI, fronted by `codex-monitored.sh`, is the integration boundary. CLI flags compose with the existing phase routes and keep invocation evidence inspectable. The shared preflight checks availability; a present binary does not establish model identity or role fitness.
|
|
67
82
|
|
|
68
83
|
## Invocation from inside a skill prompt
|
|
69
84
|
|
|
70
85
|
Skills write the invocation as a Bash command the runtime executes. Example shape from `/devlyn:resolve` PHASE 2 IMPLEMENT when routed to Codex:
|
|
71
86
|
|
|
72
|
-
> Run `bash "$CODEX_MONITORED_PATH" -C <state.base_ref.repo_root> -s workspace-write -c model_reasoning_effort=xhigh "<IMPLEMENT prompt>"`.
|
|
87
|
+
> Run `bash "$CODEX_MONITORED_PATH" --json -C <state.base_ref.repo_root> -s workspace-write -m <model_requested> -c sandbox_workspace_write.network_access=false -c model_reasoning_effort=xhigh "<IMPLEMENT prompt>"`. Capture stdout as the IMPLEMENT reply; non-zero exit → treat as subagent failure. The wrapper emits `[codex-monitored]` heartbeat and lifecycle lines on **stderr** — stdout stays clean for Codex output, so the orchestrator can parse the reply without filtering. Heartbeat-on-stderr keeps the orchestrator's combined-output stream non-silent (defeats the iter-0008 byte-watchdog kill) without polluting the codex-reply view of stdout. Do not pipe the wrapper; direct capture or file redirection preserves streaming and avoids the pipe-refusal exit.
|
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
# CODEX_MONITORED_ALLOW_PIPED — set non-empty to skip the pipe-stdout
|
|
55
55
|
# refusal. Reserved for tests; don't use
|
|
56
56
|
# in skill prompts.
|
|
57
|
+
# DEVLYN_INVOCATION_* — run/phase/round/workdir/prompt/session/
|
|
58
|
+
# receipt identity. When any is set, all
|
|
59
|
+
# are required and the wrapper seals a
|
|
60
|
+
# canonical invocation receipt.
|
|
57
61
|
|
|
58
62
|
set -uo pipefail
|
|
59
63
|
|
|
@@ -76,6 +80,19 @@ START=$(date +%s)
|
|
|
76
80
|
TIMEOUT_FLAG=""
|
|
77
81
|
CODEX_ARGS=("$@")
|
|
78
82
|
|
|
83
|
+
for codex_arg in "${CODEX_ARGS[@]}"; do
|
|
84
|
+
case "$codex_arg" in
|
|
85
|
+
--dangerously-bypass-approvals-and-sandbox|--yolo)
|
|
86
|
+
printf '[codex-monitored] error: forbidden Codex bypass flag: %s\n' "$codex_arg" >&2
|
|
87
|
+
exit 64
|
|
88
|
+
;;
|
|
89
|
+
danger-full-access|-s=danger-full-access|--sandbox=danger-full-access)
|
|
90
|
+
printf '[codex-monitored] error: forbidden Codex sandbox: danger-full-access\n' >&2
|
|
91
|
+
exit 64
|
|
92
|
+
;;
|
|
93
|
+
esac
|
|
94
|
+
done
|
|
95
|
+
|
|
79
96
|
require_nonnegative_int() {
|
|
80
97
|
local name="$1"
|
|
81
98
|
local value="$2"
|
|
@@ -102,6 +119,34 @@ require_positive_int() {
|
|
|
102
119
|
require_positive_int CODEX_MONITORED_HEARTBEAT "$HEARTBEAT_SEC"
|
|
103
120
|
require_nonnegative_int CODEX_MONITORED_TIMEOUT_SEC "$TIMEOUT_SEC"
|
|
104
121
|
|
|
122
|
+
RECEIPT_ENABLED=""
|
|
123
|
+
for receipt_value in \
|
|
124
|
+
"${DEVLYN_INVOCATION_RUN_ID:-}" \
|
|
125
|
+
"${DEVLYN_INVOCATION_PHASE:-}" \
|
|
126
|
+
"${DEVLYN_INVOCATION_ROUND:-}" \
|
|
127
|
+
"${DEVLYN_INVOCATION_WORKDIR:-}" \
|
|
128
|
+
"${DEVLYN_INVOCATION_PROMPT_FILE:-}" \
|
|
129
|
+
"${DEVLYN_INVOCATION_SESSION_FILE:-}" \
|
|
130
|
+
"${DEVLYN_INVOCATION_RECEIPT:-}"; do
|
|
131
|
+
if [ -n "$receipt_value" ]; then
|
|
132
|
+
RECEIPT_ENABLED=1
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
if [ -n "$RECEIPT_ENABLED" ]; then
|
|
136
|
+
for receipt_name in \
|
|
137
|
+
DEVLYN_INVOCATION_RUN_ID DEVLYN_INVOCATION_PHASE DEVLYN_INVOCATION_ROUND \
|
|
138
|
+
DEVLYN_INVOCATION_WORKDIR DEVLYN_INVOCATION_PROMPT_FILE \
|
|
139
|
+
DEVLYN_INVOCATION_SESSION_FILE DEVLYN_INVOCATION_RECEIPT; do
|
|
140
|
+
eval "receipt_value=\${$receipt_name:-}"
|
|
141
|
+
if [ -z "$receipt_value" ]; then
|
|
142
|
+
printf '[codex-monitored] error: %s is required for invocation receipt\n' \
|
|
143
|
+
"$receipt_name" >&2
|
|
144
|
+
exit 64
|
|
145
|
+
fi
|
|
146
|
+
done
|
|
147
|
+
require_nonnegative_int DEVLYN_INVOCATION_ROUND "$DEVLYN_INVOCATION_ROUND"
|
|
148
|
+
fi
|
|
149
|
+
|
|
105
150
|
if [ -n "${CODEX_MONITORED_ISOLATED:-}" ]; then
|
|
106
151
|
CODEX_ARGS=(
|
|
107
152
|
--ignore-user-config
|
|
@@ -187,16 +232,25 @@ terminate_process_group() {
|
|
|
187
232
|
kill -KILL -- "-$pgid" 2>/dev/null || true
|
|
188
233
|
}
|
|
189
234
|
|
|
235
|
+
terminate_monitor_group() {
|
|
236
|
+
local pid="$1"
|
|
237
|
+
kill -TERM -- "-$pid" 2>/dev/null || kill -TERM "$pid" 2>/dev/null || true
|
|
238
|
+
kill -KILL -- "-$pid" 2>/dev/null || kill -KILL "$pid" 2>/dev/null || true
|
|
239
|
+
wait "$pid" 2>/dev/null || true
|
|
240
|
+
}
|
|
241
|
+
|
|
190
242
|
forward_signal() {
|
|
191
243
|
local sig="$1"
|
|
192
244
|
if [ -n "${CODEX_PID:-}" ] && kill -0 "$CODEX_PID" 2>/dev/null; then
|
|
193
245
|
kill -"$sig" -- "-$CODEX_PID" 2>/dev/null || kill -"$sig" "$CODEX_PID" 2>/dev/null || true
|
|
194
246
|
fi
|
|
195
|
-
if [ -n "${HB_PID:-}" ]
|
|
196
|
-
|
|
247
|
+
if [ -n "${HB_PID:-}" ]; then
|
|
248
|
+
terminate_monitor_group "$HB_PID"
|
|
249
|
+
HB_PID=""
|
|
197
250
|
fi
|
|
198
|
-
if [ -n "${WATCHDOG_PID:-}" ]
|
|
199
|
-
|
|
251
|
+
if [ -n "${WATCHDOG_PID:-}" ]; then
|
|
252
|
+
terminate_monitor_group "$WATCHDOG_PID"
|
|
253
|
+
WATCHDOG_PID=""
|
|
200
254
|
fi
|
|
201
255
|
}
|
|
202
256
|
|
|
@@ -215,11 +269,23 @@ if [ -n "${CODEX_MONITORED_ISOLATED:-}" ]; then
|
|
|
215
269
|
printf '[codex-monitored] isolated=1\n' >&2
|
|
216
270
|
fi
|
|
217
271
|
|
|
272
|
+
if [ -n "$RECEIPT_ENABLED" ]; then
|
|
273
|
+
RECEIPT_HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/invocation-receipt.py"
|
|
274
|
+
python3 "$RECEIPT_HELPER" start \
|
|
275
|
+
--workdir "$DEVLYN_INVOCATION_WORKDIR" \
|
|
276
|
+
--receipt "$DEVLYN_INVOCATION_RECEIPT" \
|
|
277
|
+
--run-id "$DEVLYN_INVOCATION_RUN_ID" \
|
|
278
|
+
--phase "$DEVLYN_INVOCATION_PHASE" \
|
|
279
|
+
--round "$DEVLYN_INVOCATION_ROUND" \
|
|
280
|
+
--prompt-file "$DEVLYN_INVOCATION_PROMPT_FILE" \
|
|
281
|
+
--session-file "$DEVLYN_INVOCATION_SESSION_FILE" \
|
|
282
|
+
-- "${CODEX_ARGS[@]}" || exit 64
|
|
283
|
+
fi
|
|
284
|
+
|
|
218
285
|
# Launch codex with stdin closed; output streams directly to OUR stdout/stderr.
|
|
219
286
|
set -m
|
|
220
287
|
"$CODEX_BIN" exec "${CODEX_ARGS[@]}" < /dev/null &
|
|
221
288
|
CODEX_PID=$!
|
|
222
|
-
set +m
|
|
223
289
|
printf '[codex-monitored] codex pid=%d\n' "$CODEX_PID" >&2
|
|
224
290
|
|
|
225
291
|
heartbeat_loop "$CODEX_PID" &
|
|
@@ -231,21 +297,24 @@ if [ "$TIMEOUT_SEC" -gt 0 ]; then
|
|
|
231
297
|
timeout_loop "$CODEX_PID" "$TIMEOUT_SEC" "$TIMEOUT_FLAG" &
|
|
232
298
|
WATCHDOG_PID=$!
|
|
233
299
|
fi
|
|
300
|
+
set +m
|
|
234
301
|
|
|
235
302
|
wait "$CODEX_PID"
|
|
236
303
|
EXIT=$?
|
|
237
304
|
terminate_process_group "$CODEX_PID" "post-exit-descendants"
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
wait "$HB_PID" 2>/dev/null || true
|
|
241
|
-
if [ -n "${WATCHDOG_PID:-}" ]; then
|
|
242
|
-
kill -TERM "$WATCHDOG_PID" 2>/dev/null || true
|
|
243
|
-
wait "$WATCHDOG_PID" 2>/dev/null || true
|
|
244
|
-
fi
|
|
305
|
+
CODEX_PID=""
|
|
306
|
+
forward_signal TERM
|
|
245
307
|
if [ -n "$TIMEOUT_FLAG" ] && [ -f "$TIMEOUT_FLAG" ]; then
|
|
246
308
|
EXIT=124
|
|
247
309
|
fi
|
|
248
310
|
|
|
311
|
+
if [ -n "$RECEIPT_ENABLED" ]; then
|
|
312
|
+
python3 "$RECEIPT_HELPER" finish \
|
|
313
|
+
--workdir "$DEVLYN_INVOCATION_WORKDIR" \
|
|
314
|
+
--receipt "$DEVLYN_INVOCATION_RECEIPT" \
|
|
315
|
+
--exit-code "$EXIT" || exit 64
|
|
316
|
+
fi
|
|
317
|
+
|
|
249
318
|
printf '[codex-monitored] codex exited: code=%d elapsed=%ds\n' \
|
|
250
319
|
"$EXIT" $(( $(date +%s) - START )) >&2
|
|
251
320
|
exit "$EXIT"
|