From 29ecb6a13c74fdd1331cbd87e7d5645751a55735 Mon Sep 17 00:00:00 2001 From: revfactory Date: Mon, 14 Sep 2026 16:10:24 +0900 Subject: [PATCH] fix: check native subagent spawn before fan-out --- CHANGELOG.md | 1 + docs/compatibility.md | 20 ++++++++- docs/multi-agent.md | 8 ++-- docs/quickstart.md | 28 ++++++++++--- docs/verification.md | 42 +++++++++++++++++++ scripts/live_smoke.py | 4 +- skills/harness/SKILL.md | 10 ++--- .../references/orchestrator-template.md | 13 +++--- skills/harness/references/runtime-guide.md | 24 ++++++++++- 9 files changed, 127 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6b7bc..5baa790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased — Codex run coordination improvements +- Added a first-standby native spawn preflight, missing-thread diagnostics that stop per-role retries, and sequential fallback guidance that preserves persistence preferences and keeps native-only failures explicit ([#1](https://github.com/revfactory/codex-harness/issues/1)). - Added v2 run state, refreshed task context with input fingerprints and decisions, native agent ID/lifecycle records, and selective resume invalidation. - Added completion checks for required result evidence, artifacts, and freshness, separate from native runtime observations. - Added explicit concurrent communication logs under `_workspace/communications/`, with correlated questions, answers, delivery outcomes, acknowledgments, and optional Markdown export. diff --git a/docs/compatibility.md b/docs/compatibility.md index 350e31b..646375f 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -56,7 +56,23 @@ The Codex plugin manifest packages the skill. Installing it makes that workflow Sandbox declarations express the intended agent policy. Parent session runtime overrides and platform restrictions can affect the effective sandbox. Ownership instructions do not create per-file access controls. Check the active client's effective policy when verifying write boundaries. [OpenAI subagent reference](https://learn.chatgpt.com/docs/agent-configuration/subagents). -If custom roles are absent, verify the working project root, trust/configuration loading, and TOML validity, then start a new thread. If native subagent tools are unavailable, the parent can still follow the workflow sequentially; it should report that execution mode explicitly. +If custom roles are absent, verify the working project root, trust/configuration loading, and TOML validity, then start a new thread. An available built-in role can cover a suitable task with explicit instructions; report that substitution. Role discovery and exposed subagent tools do not establish that native spawning works in the current session. + +## Native spawn preflight and ephemeral sessions + +Before wider fan-out, use the first planned agent as a compatibility check: + +1. Inspect the active native tool schema, available roles, and actual capacity. If no native tool is exposed, proceed with the sequential fallback below. +2. Spawn one agent with a standby-only instruction: wait for the refreshed task packet and do not read or write product files. Inspect the actual tool result before spawning more agents. +3. Only when a real child ID is returned, register it with `run.py start` if using a run plan, then dispatch the refreshed packet through the actual follow-up tool. Reuse this child for its planned task and count it against capacity; no separate throwaway probe is needed. + +If the result contains `collab spawn failed: no thread with id`, stop further spawn attempts in that session. Preserve the full error and client/version as evidence. Retrying each role or switching to a built-in role does not address this missing-thread failure. Without a returned child ID, do not call `run.py start` or invent an agent ID. Capacity errors are a separate case: inspect actual session states and use supported lifecycle controls before a justified retry. + +`codex exec --ephemeral` avoids persisting session rollout files to disk. This is the documented flag meaning and was confirmed by installed **Codex CLI 0.154.0** help on **2026-09-14**; it is not a guarantee of native subagent compatibility. The [CLI reference](https://learn.chatgpt.com/docs/developer-commands?surface=cli) and [subagent reference](https://learn.chatgpt.com/docs/agent-configuration/subagents) do not establish that combination's compatibility. Known ephemeral mode is a reason to check the first spawn carefully; the Python helpers do not detect the parent CLI mode. + +The [verification record](verification.md) contains the historical **0.153.4** ephemeral failure and ordinary-session success, plus a bounded **0.154.0** ephemeral probe that reported success without independent spawn metadata. These observations neither establish universal incompatibility nor identify a fixed version. + +If native spawning is unavailable or fails, the parent can complete suitable substantive work sequentially in the existing session and report that mode. Preserve the user's persistence preference; do not silently restart without `--ephemeral`. An ordinary invocation is an option when persistent sessions are acceptable; see the [quickstart](quickstart.md#2-open-the-project-in-a-new-session). Keep native tasks that never started pending and record parent work separately, without synthetic IDs or native results. Native-only smoke checks remain `failed` for an observed failure or `not_run` for unexecuted checks; sequential work does not make that smoke pass. ## Local helpers and native runtime actions @@ -70,4 +86,4 @@ Read-only agents remain read-only and ask the parent to record important message Keep the output of `python3 scripts/validate.py --project .` and the automated test suite separate from a live smoke result. For runtime reports, include client/version, project root, effective subagent settings, discovered roles, observed concurrent sessions, and the parent integration result. Follow the [quickstart live smoke procedure](quickstart.md#live-multi-agent-smoke-test). -The [verification record](verification.md) documents a successful two-custom-agent read workflow on Codex CLI 0.153.4 and a failed ephemeral-session probe. There is no maintained cross-version matrix or performance benchmark. Static validation alone still does not imply a live runtime pass. +The [verification record](verification.md) distinguishes historical live results from the more limited current probe. There is no maintained cross-version matrix or performance benchmark. Static validation alone still does not imply a live runtime pass. diff --git a/docs/multi-agent.md b/docs/multi-agent.md index 08dea4e..44c15bb 100644 --- a/docs/multi-agent.md +++ b/docs/multi-agent.md @@ -64,13 +64,13 @@ Read scope can overlap. Write ownership must be disjoint while tasks execute con 1. Audit the existing harness and clarify only information needed to proceed. 2. Establish a compact dependency graph and interface contracts. -3. Spawn independent tasks up to the available subagent capacity while continuing useful parent work. +3. Check native compatibility with the first planned standby agent and inspect its actual spawn result before wider fan-out. With a returned child ID, register and reuse that agent, then spawn further independent tasks within actual capacity while continuing useful parent work. 4. Reuse an agent for related follow-ups with refreshed inputs, decisions, and skill paths. Register the actual native agent ID and its observed lifecycle separately from task status. Close unnecessary sessions with the actual runtime tool and record the observed outcome. 5. Inspect each result, reconcile interfaces, and integrate before dispatching dependent tasks. 6. Review and test the integrated change. Route confirmed defects back to the owning worker, then recheck the affected behavior. 7. Report completed work, actual evidence, and remaining limitations. -The project requests `max_concurrent_threads_per_session = 3` under `[agents]`; these are subagent threads coordinated by the parent session. The effective runtime can impose a lower limit. If a spawn fails due to capacity, inspect actual session states, collect pending results, and use the runtime's supported lifecycle tools before retrying. Waiting or marking a local task complete does not itself release native capacity. If tools are unavailable, use sequential parent execution and report that limitation. Do not abandon required work or manufacture tool names. +The project requests `max_concurrent_threads_per_session = 3` under `[agents]`; these are subagent threads coordinated by the parent session. The effective runtime can impose a lower limit. If a spawn fails due to capacity, inspect actual session states, collect pending results, and use the runtime's supported lifecycle tools before retrying. Waiting or marking a local task complete does not itself release native capacity. Exposed tools and discovered roles do not guarantee successful spawning. For `collab spawn failed: no thread with id`, stop further spawn attempts in that session, including retries with different roles. Follow the [compatibility preflight](compatibility.md#native-spawn-preflight-and-ephemeral-sessions). Do not abandon required substantive work or manufacture tool names. Five role definitions do not mean five simultaneous agents. Spawn only concrete tasks that gain something from independent execution. Workers do not spawn their own agents. Hierarchical decomposition stays in the parent's dependency graph, with leaf tasks scheduled within the same bounded pool. @@ -80,7 +80,7 @@ Use the [runtime guide](../skills/harness/references/runtime-guide.md) to initia Independent tasks receive small, self-contained packets. Related follow-ups reread the changed packet, files, and decisions. An independent reviewer can use fresh context when supported; do not assume a full conversation fork or a particular fork flag exists. -The parent creates new native agents with a standby-only instruction, registers their actual IDs through `start` in `agents.json`, then dispatches the refreshed packet through the actual follow-up tool. A failed local registration prevents task dispatch. `run.py result` records task evidence but does not mark the native agent idle. Confirm actual idleness or a stop acknowledgment before reassigning write ownership; `stop_requested` alone is insufficient. Use the native follow-up tool to resume work and the native lifecycle tool to stop or close a session. The local CLI records observations; it does not perform those native actions. +The parent creates new native agents with a standby-only instruction to wait for the refreshed packet without reading or writing product files, registers their actual IDs through `start` in `agents.json`, then dispatches the packet through the actual follow-up tool. Without a returned native child ID, do not call `run.py start`; a synthetic ID or the parent's ID cannot stand in for a child. A failed local registration prevents task dispatch. `run.py result` records task evidence but does not mark the native agent idle. Confirm actual idleness or a stop acknowledgment before reassigning write ownership; `stop_requested` alone is insufficient. Use the native follow-up tool to resume work and the native lifecycle tool to stop or close a session. The local CLI records observations; it does not perform those native actions. `run.py resume` creates a new run, preserves prior records, and invalidates changed inputs/results plus affected descendants. `validate.py --project . --run ID --complete` checks required result evidence, artifacts, and freshness before the parent reports completion. Neither operation proves native execution. @@ -96,6 +96,8 @@ Events append under `_workspace/communications/.jsonl` through the helpe A blocked child returns the exact dependency or failure and any useful partial findings. The parent resolves the dependency, narrows the task, or finishes it locally. Retry only when the input or environment has changed enough to justify another attempt. A child saying “complete” does not satisfy acceptance criteria without evidence. +If native tools are unavailable or the first spawn fails, the parent can complete suitable substantive work sequentially in the current session and report the limitation. Keep native tasks that never started pending and record parent work separately; do not use invented IDs or submit parent work as native child results to make completion validation pass. Required native-only checks remain `failed` or `not_run` according to the evidence, so this fallback cannot pass a native smoke test. Preserve an explicit ephemeral-session preference; ordinary persistent execution is an option only when that persistence is acceptable. The [compatibility guide](compatibility.md#native-spawn-preflight-and-ephemeral-sessions) separates historical ephemeral failures from current evidence. + When concurrent edits collide, stop assigning overlapping writes, inspect the combined diff, and preserve both contributors' intent. The parent owns reconciliation. Do not reset shared files to a prior version or overwrite the workspace to recover one task's result. ## Boundaries and verification diff --git a/docs/quickstart.md b/docs/quickstart.md index 029d69c..c4df840 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -27,6 +27,14 @@ Open the project you want to configure, rather than the downloaded marketplace d codex -C /absolute/path/to/project ``` +For a non-interactive ordinary session: + +```bash +codex exec -C /absolute/path/to/project '$harness Build a harness for this project. Use subagents for independent tasks after checking the first native spawn.' +``` + +These examples keep your configured model and permissions. Single quotes preserve the literal `$harness` prompt in the shell. If you chose `--ephemeral` to avoid persistent session files, keep that choice and follow the [native spawn preflight](compatibility.md#native-spawn-preflight-and-ephemeral-sessions); do not silently switch to an ordinary session. + Start a new session after installation, then send: ```text @@ -75,6 +83,7 @@ If you already have this checkout, run only the last two commands from its root. - **Marketplace or plugin not found:** run `codex plugin marketplace list` and `codex plugin list --marketplace codex-harness --available --json`. Confirm the source includes `.agents/plugins/marketplace.json`; use the local-checkout route for unpublished changes. - **`harness` is missing:** confirm the plugin is installed and enabled, then start a new session in the target project. In the desktop app, use `@` to select the plugin or bundled skill. [Official plugin usage](https://learn.chatgpt.com/docs/plugins). - **`.agents/skills/harness/scripts/...` is missing:** those project-local paths come from the optional project installer. Ask the plugin to use its installed helper paths, or install the project scaffold below. +- **`collab spawn failed: no thread with id`:** stop native fan-out and per-role retries in that session. Record the error and CLI version; no returned child ID means no `run.py start`. Follow the [preflight and fallback guidance](compatibility.md#native-spawn-preflight-and-ephemeral-sessions), preserving any explicit `--ephemeral` preference. ## Use this checkout @@ -133,7 +142,9 @@ python3 .agents/skills/harness/scripts/run.py --project . ready --run project-v1 python3 .agents/skills/harness/scripts/run.py --project . status --run project-v1 ``` -The parent first creates a native agent with a standby-only instruction, uses its real ID for `start`, then sends the refreshed packet through the actual follow-up tool. It registers actual results with `result`, and separately records confirmed session idleness or termination with `agent`. Important questions, answers, findings, and handoffs are explicitly recorded under `_workspace/communications/`; native delivery remains a separate tool call. Read-only roles ask the parent to log and route messages. +The parent first creates one native agent with a standby-only instruction and inspects the returned result before wider fan-out. Only a successful spawn with a real child ID permits `start`, followed by delivery of the refreshed packet through the actual follow-up tool. Reuse that agent for its planned task within actual capacity. A missing-thread error stops retries; leave unstarted native tasks pending and record sequential parent work separately. See the [preflight](compatibility.md#native-spawn-preflight-and-ephemeral-sessions). + +The parent registers actual results with `result`, and separately records confirmed session idleness or termination with `agent`. Important questions, answers, findings, and handoffs are explicitly recorded under `_workspace/communications/`; native delivery remains a separate tool call. Read-only roles ask the parent to log and route messages. ```bash python3 .agents/skills/harness/scripts/communication.py --project . --run project-v1 view \ @@ -145,21 +156,28 @@ A later input change can start a new run through `run.py resume --run project-v1 ## Live multi-agent smoke test -Static validation cannot establish runtime discovery or parallel execution. In a new trusted local Codex session, ask: +Static validation and exposed tools cannot establish native spawning or parallel execution. In a new trusted local Codex session, ask: ```text -Use harness_explorer and harness_architect as two separate subagents in parallel. +First spawn one harness_explorer with a standby-only instruction: wait for the +task packet and do not read or write product files. Inspect its actual result +before starting another agent. If no child ID is returned, report the error and +stop this native smoke. For "collab spawn failed: no thread with id", do not retry +other roles in this session. +On success, reuse that child for the Explorer task below, then start a separate +harness_architect for the Architect task within actual capacity. Dispatch both +independent tasks before waiting for their results. Explorer: inspect the harness entry points and cite the relevant files. Architect: inspect the task ownership protocol and return a small improvement plan in your response only. Both tasks are read-only and independent. Have the parent combine the two results. Do not modify files. ``` -Check that two native subagent sessions start, each completes its assigned task, and the parent combines their results. Record the Codex client/version, effective configuration, discovered role names, observed overlap, returned evidence, and any errors. An instruction to run in parallel is not proof that the runtime did so. +Check that the first spawn returns a real child ID, two native subagent sessions start, each completes its assigned task, and the parent combines their results. Record the Codex client/version, session mode if known, effective configuration, discovered role names, observed overlap, returned evidence, and any errors. An instruction to run in parallel is not proof that the runtime did so. For write-path verification, use a disposable project and explicitly assign separate temporary files to two workers. Verify both expected contents, unchanged sentinel files outside ownership, parent integration, and reviewer/QA results. Task packets and a completion checklist are in [multi-agent.md](multi-agent.md). -If roles are missing, confirm the project root and trust settings, validate the files, then start a new thread. If subagent tools are unavailable or capacity is exhausted, have the parent complete the work sequentially and report the reduced execution mode. +If roles are missing, confirm the project root and trust settings, validate the files, then start a new thread. Distinguish missing roles, unavailable tools, capacity limits, and the missing-thread error using the [compatibility guide](compatibility.md#native-spawn-preflight-and-ephemeral-sessions). The parent can perform suitable substantive work sequentially in the existing session, preserving the user's persistence preference. Native-only checks stay `failed` or `not_run` as observed; sequential fallback is not a successful native smoke. ## Repository checks diff --git a/docs/verification.md b/docs/verification.md index 4ac7a13..2477efd 100644 --- a/docs/verification.md +++ b/docs/verification.md @@ -1,5 +1,47 @@ # Verification record +## Issue #1 compatibility recheck — 2026-09-14 + +On macOS, installed **codex-cli 0.154.0** help still describes `--ephemeral` +as disabling session-file persistence. A bounded read-only probe ran with +`codex exec --ephemeral --json --sandbox read-only -C ` and inherited +model/reasoning settings. It requested one standby `harness_explorer`, with +no product reads, writes, or recursive delegation and no retry on spawn failure. + +The CLI exited **0** and reported child ID `/root/compatibility_probe` and its +`READY` response. The captured JSONL contains a completed wait event and that +final report, but no spawn metadata independently confirming the dispatch. +This is a **reported success**, not proof of a fixed CLI version, native +parallelism, or a complete Harness workflow. The earlier 0.153.4 failure below +remains a separate observation. Use the actual first-spawn check described in +[compatibility](compatibility.md) for each session. + +The same installed CLI also completed the updated ordinary-session regression: + +```bash +python3 scripts/live_smoke.py run \ + --target _workspace/live-tests/issue-1-20260914 \ + --baseline-file /tmp/codex-harness-issue-1-20260914-baseline.json --timeout 900 +``` + +The runner exited **0** using its caller-held protected-file baseline. It +verified rejection of the deliberately blocked first run, preservation of +that run and alpha's output, reuse of alpha, rerun of beta and QA, and both +final tests passing. Native tool metadata separately confirmed that alpha's +child ID returned before beta was spawned, with exactly two `harness_worker` +children and one `harness_qa`; the first child was reused without an extra +probe. The local verifier still labels transport records as reported; this +recheck does not independently audit all message contents or prove behavior +under the original missing-thread failure. Local evidence is retained under +the ignored fixture's `_workspace/` and `.harness/runs/issue-1-inputs/`. + +For this change, independent offline QA passed **94 tests**, root and example +structural validation, `git diff --check`, and the changed documentation's +local links, anchors, and shell examples. These checks remain separate from +native execution evidence. + +## 2026-09-07 baseline + Checked **2026-09-07 (Asia/Seoul)** against upstream revision `cceac68ea1d0ad198ef4b7b906cd238375836387`, using Python **3.13.7** and **codex-cli 0.153.4** on macOS. diff --git a/scripts/live_smoke.py b/scripts/live_smoke.py index dcc948c..b31cb86 100644 --- a/scripts/live_smoke.py +++ b/scripts/live_smoke.py @@ -140,13 +140,13 @@ def prepare(project: Path) -> Path: Use python3 .agents/skills/harness/scripts/run.py --project . for lifecycle commands. Use communication.py --project . --run first|resumed for separate message logs. Never edit generated plan/agents/result records by hand. Parent may write candidate result JSON files under _workspace then submit with run.py result. Result schema is run_id,task_id,status,summary,artifacts,checks[{name,status,evidence,required,command?}],issues. Record only observed checks. Agent state updates require actual native idle/stop/close evidence. -1. Initialize run first from plan.template.json. Spawn TWO harness_worker children into standby, collect real IDs, assign alpha and beta via run.py start, then give both their input.md and each other's IDs before waiting. You are not alone; each owns only its matching .py file. Tell them to read refreshed packets and preserve others' work. Have alpha ask beta a relevant contract question via actual native send (e.g. whether both functions use value() and whether beta has an input blocker); beta must answer with the observed mismatch and notify the parent. Record correlated question/answer and actual delivery observations with communication.py. The parent may relay/log if necessary but must actually deliver the exchange. Record sender/recipient as real native IDs and attach message IDs to native text. No fake heartbeat or invented delivery. +1. Initialize run first from plan.template.json. Probe native availability by spawning only the first harness_worker into standby, with no product reads or writes. Inspect the actual spawn result and real child ID before any further spawn or run.py start. If spawning fails with `collab spawn failed: no thread with id` or returns no usable child ID, stop further spawning, preserve the exact error and any known CLI version/session mode in _workspace/native-failure.md, and report native smoke failure. Do not retry this missing-parent-thread error per role, invent IDs, substitute sequential parent work, or silently change session persistence. On success, reuse this SAME child as alpha and register it via run.py start; do not create an extra probe worker. Within actual native capacity, spawn the second harness_worker into standby, collect its real ID, register beta via run.py start, then give both their input.md and each other's IDs before waiting. You are not alone; each owns only its matching .py file. Tell them to read refreshed packets and preserve others' work. Have alpha ask beta a relevant contract question via actual native send (e.g. whether both functions use value() and whether beta has an input blocker); beta must answer with the observed mismatch and notify the parent. Record correlated question/answer and actual delivery observations with communication.py. The parent may relay/log if necessary but must actually deliver the exchange. Record sender/recipient as real native IDs and attach message IDs to native text. No fake heartbeat or invented delivery. 2. Alpha implements value() -> ALPHA and runs its test. Beta sees UNRESOLVED in its spec versus BETA in the test, runs its test to capture the actual failure, and returns blocked without guessing or modifying specs/tests. Record both results and observed idle states. QA remains pending. Do not silently fix the first-run blocker. 3. Run `python3 _workspace/smoke_control.py checkpoint --target .`. This external control checks that completion fails, records the original run hashes and alpha hash, and changes only beta's spec to BETA as an explicitly authorized scenario transition. Then run `run.py --project . resume --run first --new-run resumed`. It must reuse alpha and invalidate beta and verify. 4. Reuse the actual idle beta worker if available (or spawn another actual harness_worker within native limits), register beta in resumed, deliver the NEW input packet, and implement/test beta. Do not rerun alpha. Record beta's completed result and observed idle state. Start harness_qa only after dependencies have accepted results. Give it the verify packet; it runs both tests without product edits. Record the actual QA result and observed idle state. 5. Run `python3 .agents/skills/harness/scripts/validate.py --project . --run resumed --complete`. Export both communication logs to Markdown under _workspace/communications. Write _workspace/native-report.json with actual parent_thread_id if exposed, worker_agent_ids (all workers from first and resumed), qa_agent_id, role_fallbacks (empty if none), and a short description of the native question/answer. Do not claim closure when only idle is observed. Return the actual outcome and evidence paths. -This is a bounded fixture: two 2-line modules and two small unit tests. Continue through the deliberate blocker using the checkpoint transition; no user confirmation is needed. If native delegation is unavailable or a required check fails, report the failure honestly and leave evidence intact. +This is a bounded fixture: two 2-line modules and two small unit tests. Continue through the deliberate blocker using the checkpoint transition; no user confirmation is needed. This smoke specifically requires native delegation: if it is unavailable or a required check fails, report the failure honestly and leave evidence intact. Do not pass this smoke through sequential parent implementation; unstarted native tasks remain pending and later unperformed checks remain not_run. """ path = project / "_workspace/prompt.md" path.write_text(prompt, encoding="utf-8") diff --git a/skills/harness/SKILL.md b/skills/harness/SKILL.md index 1407e9a..949e365 100644 --- a/skills/harness/SKILL.md +++ b/skills/harness/SKILL.md @@ -10,8 +10,8 @@ description: "Codex용 하네스를 구축·마이그레이션·확장·점검 ## 기본 원칙 - 프로젝트 에이전트는 `.codex/agents/.toml`, 스킬은 `.agents/skills//SKILL.md`에 둔다. 개인 설치는 요청받은 경우에만 `~/.agents/skills/`를 사용한다. -- 현재 노출된 서브에이전트 도구와 스키마를 먼저 확인한다. 제품마다 호출 이름·매개변수·종료 방식이 다르므로 문서의 개념을 실제 도구에 맞춘다. 도구가 없으면 같은 작업 계약으로 메인 세션에서 순차 수행하고 한계를 기록한다. -- 독립적으로 완료 가능한 작업을 병렬화한다. 유용한 자식 작업 2~3개로 시작하고 실제 동시 실행 한도에 맞춘다. 에이전트 수 자체를 목표로 삼지 않는다. +- 현재 노출된 서브에이전트 도구와 스키마를 먼저 확인하고 [실행 가이드의 네이티브 실행 사전 점검](references/runtime-guide.md#네이티브-실행-사전-점검)을 따른다. 도구 노출이나 정적 검증만으로 실행 가능하다고 판단하지 않는다. 첫 대기 자식의 실제 ID가 반환된 뒤 팬아웃하며, 성공한 자식을 첫 작업에 재사용한다. +- 독립적으로 완료 가능한 작업을 병렬화한다. 첫 생성 확인 후 유용한 자식 작업 2~3개로 넓히고 실제 동시 실행 한도에 맞춘다. 도구가 없거나 부모 스레드 오류로 ID 없이 실패하면 추가 생성을 멈추고 메인 세션에서 같은 실질 작업을 순차 수행한다. 네이티브 실행의 미완료 상태와 한계는 별도로 기록한다. - 메인이 의존성, 파일 소유권, 공용 설정, 에이전트 수명, 통합, 완료 판정을 소유한다. 워커에게 배타적인 수정 범위를 주고 다른 작업자의 변경을 되돌리지 않도록 명시한다. - 동료에게 영향을 주는 발견·질문·차단 사유·인계를 적극적으로 전달하고 신속히 답한다. 중요한 메시지는 `_workspace/communications/`에 기록한다. 네이티브 전송과 로컬 기록은 별도 동작이며 메인이 계약·소유권 변경을 확정한다. - 모델·추론 수준은 부모 설정을 상속한다. 명시적인 요구가 없는 한 특정 모델을 고정하지 않는다. 전역 설정을 변경하지 않는다. @@ -77,10 +77,10 @@ python3 .agents/skills/harness/scripts/create_agent.py \ [오케스트레이터 템플릿](references/orchestrator-template.md)을 바탕으로 도메인 오케스트레이터를 구성한다. 실제 초기화·결과 등록·재사용·통신 기록에는 [실행 가이드](references/runtime-guide.md)의 CLI와 네이티브 도구 경계를 따른다. 1. 메인이 `run.py init`으로 `.harness/runs//plan.json`과 작업별 `input.md`를 만든다. v2 계획은 프로젝트 루트, 입력·계약 지문, 결정·스킬 경로를 기록한다. 수정 대상은 `ownership`, 변하지 않는 계약·참조는 `inputs`에 두며 선행 산출물은 `dependencies`로 전달한다. -2. 의존성이 충족된 작업만 실행한다. 메인은 자식이 실행하는 동안 공용 계약·통합 준비 등 독립 작업을 수행한다. +2. 의존성이 충족된 작업만 실행한다. 첫 대기 자식의 실제 생성 결과로 네이티브 실행을 점검하고 성공한 자식을 등록한 뒤 병렬 작업을 늘리고 최신 패킷을 배정한다. 부모 스레드를 찾지 못하면 역할별 재시도나 가짜 ID 등록 없이 순차 대체 절차를 따른다. 메인은 자식이 실행하는 동안 공용 계약·통합 준비 등 독립 작업을 수행한다. 3. `run.py result`로 실제 결과를 등록하고 작업 상태와 네이티브 세션 상태를 구분한다. 메인은 실제 유휴·중단 응답을 확인한 뒤 레지스트리를 갱신하며, 이전 작성자의 중단·유휴 확인 전에는 쓰기 소유권을 재배정하지 않는다. 로컬 상태 변경은 에이전트를 멈추거나 슬롯을 반환하지 않는다. 4. 중요한 발견, 구체적인 질문·답변, 계약 제안, 입력 준비, 차단 사유, 의미 있는 이정표와 인계를 적극적으로 전달한다. 쓰기 가능한 역할은 `communication.py log`로 발신 내용을 먼저 기록한 뒤 실제 도구로 보내고 전송 결과를 별도 연결한다. 읽기 전용 역할은 메인에게 기록·전달을 요청한다. 동료 토론 후 계약·소유권 확정은 메인이 한다. -5. 실패 원인을 확인하고 기본 1회 추가 시도 또는 제한된 재할당을 수행한다. 필수 작업 실패는 하네스 완료를 막는다. 선택적 작업 생략은 영향과 사유를 기록한다. +5. 실패 원인을 확인하고 일시적인 작업 오류는 기본 1회 추가 시도 또는 제한된 재할당을 수행한다. 네이티브 실행 사전 점검의 부모 스레드 오류에는 이 역할별 재시도를 적용하지 않는다. 필수 작업 실패는 하네스 완료를 막는다. 선택적 작업 생략은 영향과 사유를 기록한다. 6. 모듈 경계가 준비되는 즉시 QA를 수행하고 통합 후 최종 검증한다. 같은 캐시를 쓰는 테스트·빌드는 충돌을 피하도록 순차 실행한다. 7. `AGENTS.md`에는 도메인 관리 마커 안에 목표와 오케스트레이터 포인터만 추가한다. 설치기가 관리하는 `codex-harness:start/end` 부트스트랩 블록과 도메인 블록을 구분하여 재설치해도 도메인 연결이 유지되게 한다. 기존 내용은 보존하고 긴 실행 규칙·역할 목록은 복제하지 않는다. @@ -99,7 +99,7 @@ python3 .agents/skills/harness/scripts/create_agent.py \ 1. 대상 프로젝트 루트에서 `python3 .agents/skills/harness/scripts/validate.py --project .`를 실행한다. 이 명령은 구조를 검사하며 실제 에이전트 실행 성공을 증명하지 않는다. 2. 에이전트 TOML, 스킬 frontmatter, 참조 경로, 포인터, 소유권 중복, 의존성 순환을 확인한다. 실행 완료 전에는 `validate.py --project . --run --complete`로 필수 결과·산출물·검사 근거·최신성을 확인한다. 3. [QA 가이드](references/qa-agent-guide.md)에 따라 생산자와 소비자 양쪽을 비교한다. 테스트·리뷰 결과는 통과/실패/미실행으로 구분한다. -4. [스킬 테스트 가이드](references/skill-testing-guide.md)에 따라 현실적인 정상·오류·부분 재실행 사례를 검증한다. 런타임 도구가 있으면 서로 다른 파일을 맡은 워커와 독립 검증의 작은 실제 실행을 수행한다. +4. [스킬 테스트 가이드](references/skill-testing-guide.md)에 따라 현실적인 정상·오류·부분 재실행 사례를 검증한다. 네이티브 실행 사전 점검이 성공하면 서로 다른 파일을 맡은 워커와 독립 검증의 작은 실제 실행을 수행한다. 네이티브 실행을 검증하는 스모크 테스트는 순차 대체 작업으로 통과 처리하지 않는다. 5. 문제를 수정한 후 영향받는 검사를 다시 실행한다. QA 수정은 기본 최대 2회 반복하며, 한도 이후에도 필수 실패는 실패로 남긴다. 실행하지 않은 테스트를 통과로 보고하지 않는다. ## Phase 7: 진화·운영·유지보수 diff --git a/skills/harness/references/orchestrator-template.md b/skills/harness/references/orchestrator-template.md index 47109fb..57d161c 100644 --- a/skills/harness/references/orchestrator-template.md +++ b/skills/harness/references/orchestrator-template.md @@ -22,14 +22,15 @@ description: "{도메인}의 {산출물}을 생성·검증한다. {시작 표현 ## 실행 1. 기존 지시·산출물·실행 기록을 확인하고 최초/새 입력/부분 재실행을 구분한다. 2. run.py init으로 입력 지문·결정·스킬 경로가 있는 v2 실행을 만든다. 부분 재실행은 resume으로 이전 실행을 연결한다. -3. 실제 도구 스키마와 역할 목록, 사용 가능한 동시 실행 수를 확인한다. -4. 선행 작업이 완료된 독립 작업 2~3개를 배정하고 메인은 별도 통합 작업을 수행한다. +3. 실제 도구 스키마와 역할 목록, 사용 가능한 동시 실행 수를 확인한다. 실행 가이드의 네이티브 실행 사전 점검에 따라 첫 대기 자식 하나의 실제 생성 응답·ID를 확인한다. 부모 스레드 오류로 ID 없이 실패하면 추가 생성을 멈추고 순차 대체 절차를 따른다. +4. 성공한 첫 자식을 준비된 작업에 맞는 역할로 등록·재사용한 뒤, 선행 작업이 완료된 독립 작업 2~3개로 넓힌다. 실제 슬롯 한도를 지키며 메인은 별도 통합 작업을 수행한다. 5. 중요한 발견·질문·답변·차단 사유·인계를 기록 후 실제 메시지로 전달한다. 결과를 수집하여 의존성을 풀고 완성된 모듈의 경계면을 즉시 검증한다. 6. 문제를 소유자에게 재배정하고 정해진 횟수 안에서 수정·재검증한다. 7. 메인이 결과 등록, 실제 세션 상태 확인, validate.py --run ID --complete, 최종 통합 검사와 결과 보고를 수행한다. ## 오류와 후속 작업 필수 실패는 완료를 막는다. 선택적 생략은 사유와 영향을 기록한다. +네이티브 도구가 없거나 첫 생성이 부모 스레드 오류로 실패하면 같은 실질 작업을 메인 세션에서 순차 수행한다. 시작되지 않은 네이티브 작업은 pending으로 남기고 메인의 변경·검사는 별도 기록한다. 가짜 ID로 start하거나 네이티브 스모크 테스트를 순차 대체로 통과 처리하지 않는다. 사용자의 기록 선호를 바꾸어 영속 세션을 조용히 시작하지 않는다. 변경된 입력·공용 계약의 영향을 받는 하위 작업을 함께 재실행한다. ## 테스트 시나리오 @@ -158,7 +159,7 @@ description: "{도메인}의 {산출물}을 생성·검증한다. {시작 표현 ## 스케줄링과 통신 1. `pending`이고 모든 선행 작업이 `completed`인 작업을 고른다. 선택적 선행 작업 생략이 허용되는 경우에는 계약을 갱신한 뒤 실행한다. -2. 실행 중인 작업과 소유 경로가 겹치지 않는지 확인한다. 새 자식은 본 작업 없이 대기 지시로 생성하고 실제 ID를 run.py start로 등록해 최신 패킷을 준비한 뒤 실제 후속 도구로 배정한다. 등록에 실패하면 작업을 전달하지 않는다. 동시 실행 슬롯과 메인의 독립 작업이 모두 있을 때 병렬화한다. +2. 실행 중인 작업과 소유 경로가 겹치지 않는지 확인한다. 첫 대기 자식 하나의 실제 ID가 반환되는지 확인한 뒤 그 자식을 첫 작업에 재사용한다. 새 자식은 본 작업 없이 대기 지시로 생성하고 실제 ID를 run.py start로 등록해 최신 패킷을 준비한 뒤 실제 후속 도구로 배정한다. 생성·등록에 실패하면 작업을 전달하지 않는다. 첫 생성이 성공하고 동시 실행 슬롯과 메인의 독립 작업이 모두 있을 때 추가 자식을 생성해 병렬화한다. 3. 실제 동료 ID·책임 목록을 전달한다. 자식은 영향을 주는 발견을 먼저 알리고 필요한 사실을 질문하며, 답변·차단·인계를 근거와 함께 전달한다. 메인도 계약 결정을 관련 소비자에게 전파한다. 4. 중요한 발신은 communication.py로 기록한 뒤 실제 도구로 전송한다. 전송 결과와 수신 답변을 이벤트 ID로 연결한다. 읽기 전용 역할의 기록과 미지원 동료 통신은 메인이 대신한다. 기록이 전송을 대신하지 않는다. 5. 완료 결과를 등록한 뒤에도 네이티브 세션 상태를 별도 확인한다. 중단 요청만으로 다른 작성자에게 소유권을 넘기지 않는다. 실제 유휴·중단 확인을 레지스트리에 기록한다. @@ -170,14 +171,16 @@ description: "{도메인}의 {산출물}을 생성·검증한다. {시작 표현 | 상황 | 대응 | | --- | --- | -| 일시적인 도구 실패 | 원인 확인 후 기본 1회 추가 시도, 같은 실패를 무한 반복하지 않음 | +| 일시적인 도구 실패 | 원인 확인 후 기본 1회 추가 시도. 아래 부모 스레드 오류에는 역할별 재시도를 적용하지 않음 | +| `collab spawn failed: no thread with id`로 자식 ID 없이 실패 | 추가 생성 중단, 원문 오류·알려진 모드와 버전 기록. 가짜 ID 등록 없이 기존 메인 세션의 순차 대체 절차 적용 | | 작업 범위·입력 불충분 | 가능한 독립 작업은 계속하고 필요한 사실을 메인에게 보고 | | 소유권 충돌 | 관련 쓰기를 멈추고 메인이 기존 변경을 보존하며 재배분 | | 상충되는 분석 | 출처·재현 근거를 비교하고 메인이 결론 또는 남은 불확실성 기록 | | QA 실패 | 담당 소유자가 수정, 기본 최대 2회 수정·재검증 | | 필수 작업이 여전히 실패 | 작업을 실패/차단 상태로 유지하고 전체 완료를 주장하지 않음 | | 선택 작업 생략 | 메인이 생략 사유와 최종 결과에 미치는 영향 기록 | -| 실제 서브에이전트 도구 없음 | 메인이 동일 계약으로 순차 실행, 병렬 실행은 미검증으로 보고 | +| 실제 서브에이전트 도구 없음 | 메인이 같은 실질 작업을 순차 수행하고 별도 근거 기록. 네이티브 pending 작업은 완료로 제출하지 않으며 병렬 실행은 미검증으로 보고 | +| 네이티브 전용 스모크의 생성 실패 | 생성 검사는 실패, 후속 미실행 검사는 미실행으로 보고. 순차 대체로 통과 처리하지 않음 | ## 부분 재실행과 drift diff --git a/skills/harness/references/runtime-guide.md b/skills/harness/references/runtime-guide.md index 17b1c46..a9b5f26 100644 --- a/skills/harness/references/runtime-guide.md +++ b/skills/harness/references/runtime-guide.md @@ -2,6 +2,28 @@ 하네스의 실행 장부, 에이전트 재사용, 부분 재실행, 통신 기록을 구성할 때 읽는다. 아래 Python 도구는 로컬 상태와 근거를 관리한다. Codex 에이전트를 생성·중단하거나 메시지를 전달하지 않는다. 네이티브 동작에는 현재 런타임이 실제 제공하는 도구를 별도로 사용한다. +## 네이티브 실행 사전 점검 + +도구 목록에 spawn이 노출되어도 실제 자식 생성 전에 실패할 수 있다. 정적 검증 성공도 부모 스레드 조회나 네이티브 실행 가능 여부를 증명하지 않는다. 팬아웃 전에 다음 순서로 현재 세션의 실행 결과를 확인한다. + +1. 실제 도구 스키마, 사용 가능한 역할과 동시 실행 한도를 확인한다. 알려진 실행 명령·세션 모드와 CLI 버전이 있으면 함께 기록하되, Python 상태 관리 도구가 현재 세션 모드를 자동 감지한다고 가정하지 않는다. +2. 네이티브 도구가 있으면 첫 자식 하나만 본 작업 없는 대기 지시로 생성한다. 제품 파일을 읽거나 쓰지 않고 갱신된 패킷을 기다리게 한다. 실제 생성 응답과 반환 ID를 확인하기 전에는 다음 자식을 만들거나 `run.py start`를 호출하지 않는다. +3. 성공하면 그 자식을 첫 준비된 작업의 에이전트로 재사용한다. 해당 작업에 맞는 탐색·구현·리뷰 등의 역할을 사용한다. 아래 수명 절차에 따라 실제 ID를 등록하고 최신 패킷을 준비한다. 필요한 독립 작업을 추가하면서 패킷과 실제 동료 ID를 전달한다. 사전 점검용 자식을 따로 더 만들지 않으며 실제 동시 실행 한도를 지킨다. +4. `collab spawn failed: no thread with id`처럼 부모 스레드를 찾지 못해 ID가 반환되지 않으면 추가 생성을 멈춘다. 동일한 부모 컨텍스트에서 역할마다 다시 호출하지 않는다. 원문 오류, 실행 모드·버전 중 확인한 정보, 자식 ID가 없다는 사실을 기록한다. ID가 없는 호출을 `run.py start`로 등록하거나 성공한 자식·전송을 꾸며내지 않는다. +5. 도구가 없거나 위 오류로 사용할 수 없으면 기존 메인 세션에서 같은 실질 작업과 검증을 순차 수행한다. 메인의 실제 변경·검사 근거는 별도 요약에 기록한다. 시작되지 않은 네이티브 작업은 `pending`으로 남기며, 이를 메인의 가짜 에이전트 ID로 시작하거나 네이티브 완료로 제출하지 않는다. 이 경우 네이티브 실행의 `--complete`가 통과한다고 보고하지 않는다. + +과거 CLI 0.153.4에서는 일반 `codex exec`의 생성 성공과 `--ephemeral`의 위 부모 스레드 오류가 관찰되었다. 알려진 ephemeral 모드는 확인할 위험 신호이며 모든 버전·런타임의 실패를 뜻하지 않는다. 현재 세션의 실제 첫 생성 결과로 판단한다. 사용자가 선택한 기록·개인정보 선호를 유지하고, 오류를 우회하려고 `--ephemeral`을 조용히 제거하거나 영속 세션을 새로 시작하지 않는다. 모드 변경이 기존 사용자 승인 범위에 포함되면 진행할 수 있다. 포함되지 않으면 기록 방식의 차이와 변경 이유를 설명해 승인을 받고, 그동안 가능한 순차 작업은 기존 세션에서 진행한다. + +일반 CLI 세션을 사용하기로 했다면 다음과 같이 대상 프로젝트에서 시작한 뒤 `$harness`와 작업 요청을 입력할 수 있다. 모델·권한 등 기존 설정을 상속한다. + +```bash +codex -C /path/to/project +``` + +이 명령은 과거 성공이 관찰된 일반 세션의 진입 대안이며 현재 버전의 성공 보장은 아니다. 새 세션에서도 위 첫 자식 생성 점검을 수행한다. + +실제 네이티브 역할·병렬 실행을 요구하는 스모크 테스트에서는 순차 대체를 통과 근거로 사용할 수 없다. 생성 오류가 발생한 네이티브 검사는 실패로, 그 뒤 실행하지 못한 검사는 미실행으로 기록하고 근거를 보존한다. 메인의 실질 작업 완료와 네이티브 실행 검증 결과를 구분해 보고한다. + ## 컨텍스트와 실행 초기화 독립 작업에는 목표, 프로젝트 루트, 입력, 결정, 필요한 스킬, 쓰기 소유권, 의존성, 완료 기준이 포함된 작은 패킷을 전달한다. 전체 대화 복제나 특정 fork 옵션을 기본값으로 가정하지 않는다. 같은 주제의 후속 작업은 에이전트를 재사용하되 갱신된 `input.md`와 변경된 계약·스킬을 다시 읽게 한다. 독립 리뷰에는 런타임이 지원하면 새 컨텍스트를 사용하고, 구현자의 결론 대신 요구사항·diff·검증 기준을 제공한다. @@ -42,7 +64,7 @@ python3 .agents/skills/harness/scripts/run.py --project . ready --run profile-v1 ## 작업과 에이전트 세션의 수명 -작업 완료와 네이티브 에이전트의 유휴·중단·종료는 서로 다른 사실이다. 새 네이티브 에이전트는 먼저 작업 지시를 기다리는 상태로 생성한다. 이 최초 지시에는 아직 제품 파일을 읽거나 쓰지 말고 최신 패킷을 기다리라고 명시한다. 실제 반환된 ID를 레지스트리에 연결한 뒤 본 작업을 전달한다. 다음 명령의 `ACTUAL_AGENT_ID`는 실제 도구가 반환한 값으로 바꾼다. +작업 완료와 네이티브 에이전트의 유휴·중단·종료는 서로 다른 사실이다. 위 사전 점검을 통과한 첫 자식을 재사용하고, 추가 네이티브 에이전트도 먼저 작업 지시를 기다리는 상태로 생성한다. 이 최초 지시에는 아직 제품 파일을 읽거나 쓰지 말고 최신 패킷을 기다리라고 명시한다. 실제 반환된 ID를 레지스트리에 연결한 뒤 본 작업을 전달한다. 다음 명령의 `ACTUAL_AGENT_ID`는 실제 도구가 반환한 값으로 바꾼다. ```bash python3 .agents/skills/harness/scripts/run.py --project . start \