Skip to main content

oc-subagent

Use OpenCode serve child sessions as persistent, inspectable subagents. Use when proving or operating OpenCode subagents, child-session reuse, parent/child session maps, concurrent subagent fan-out, DAG-like task probes, SSE/event capture, or persistence across multiple turns without the full scillm transport/orchestrator overhead.

소스 정보

저장소
grahama1970/agent-stack-public
최근 소스 활동
2026년 9월 24일 15:51
감지된 SKILL.md 언어
영어
스타
0
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
43 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
oc-subagent
description
Use OpenCode serve child sessions as persistent, inspectable subagents. Use when proving or operating OpenCode subagents, child-session reuse, parent/child session maps, concurrent subagent fan-out, DAG-like task probes, SSE/event capture, or persistence across multiple turns without the full scillm transport/orchestrator overhead.
triggers
["oc-subagent","OpenCode subagent persistence","persistent OpenCode child session","child-session reuse","concurrent OpenCode subagents","prove subagents persist between tasks","OpenCode parent child session map","simple subagent DAG probe"]
provides
["opencode-subagent-control","child-session-persistence-proof","concurrent-subagent-probe"]
composes
["agentic-evals"]
taxonomy
["validation","orchestration","persistence","concurrency"]
disciplines
["agentic-orchestration"]
# oc-subagent ## Overview Use this skill when a project agent needs a simple, direct OpenCode serve MVP for subagents: one parent session, stable logical subagent ids, child sessions for executors, blocking turn completion, and proof artifacts. Prefer this skill over hand-written OpenCode endpoint logic. This skill intentionally stays below the full `$scillm` transport/orchestrator layer. Use `$scillm` transport when the work needs durable DAG state, retries, validation gates, amendment, or UI steering. Use `$oc-subagent` when the immediate question is whether OpenCode child sessions can run concurrently and preserve state across turns. ## Core Invariants 1. Create exactly one parent OpenCode session for the test run unless explicitly recovering from failure. 2. Create one child session per logical subagent using `parentID`. 3. Track a stable logical id such as `subagent_1` separately from the physical `child_session_id`. 4. Reuse the same child session for repeated turns to the same logical subagent. 5. Serialize turns sent to the same `subagent_run_id`. 6. Dispatch independent `subagent_run_id`s concurrently only when they use different child sessions. 7. Never advance a dependent task based only on prompt dispatch or partial SSE output. 8. Advance only after the turn returns a terminal HTTP response or equivalent terminal run status and the result validates. 9. Persist session maps, request/response artifacts, raw SSE, normalized JSONL events, heartbeats, task status, child listings, message listings, and final proof JSON. 10. A persistence prompt must not leak the prior result or its ingredients (the turn-2 prompt uses no digits). 11. Prove session memory with a negative control: the same turn-2 prompt sent to a fresh child session that never ran turn 1 must not produce the persisted answer. 12. Derive proof booleans from recorded timestamps and prompt scans, never hard-code them. ## Session Model ```text project_agent_run_id └── parent_session_id ├── child_session_id for subagent_1 ├── child_session_id for subagent_2 └── child_session_id for subagent_3 ``` The project agent should reason in logical ids: ```text subagent_1 subagent_2 subagent_3 ``` The skill user maps those to physical OpenCode ids: ```json { "run_id": "oc-subagent-persistence-001", "parent_session_id": "ses_parent", "subagents": { "subagent_1": {"child_session_id": "ses_child_a"}, "subagent_2": {"child_session_id": "ses_child_b"}, "subagent_3": {"child_session_id": "ses_child_c"} } } ``` ## Minimal MVP Probe Use this task list to prove persistence and concurrency without `$scillm` transport overhead: ```text 1. Project agent computes 2 + 2 = 4. 2. subagent_1 turn 1: "Compute 3 * 6, then add the project-agent previous result, which is 4. Store the resulting number as last_result." Expected: 22 3. In parallel: subagent_2: "What is the capital of France?" Expected: Paris subagent_3: "In simple everyday examples, what color is most commonly associated with an apple?" Expected: red 4. Wait for both subagent_2 and subagent_3 to finish. 5. subagent_1 turn 2 (same child session, value not restated): "Add ten to your last_result from this same session." Expected: 32 6. Negative control (fresh child session, no turn 1): Send the turn-2 prompt to a brand-new child session that never ran turn 1. Expected: it must NOT produce 32 (it has no last_result to recall). ``` The turn-2 `subagent_1` prompt must not contain `22`, `18`, `4`, or `32`; it uses the word "ten" and contains no digits. If it does, the test proves prompt leakage, not session persistence. If the negative-control session produces `32` anyway, the `32` from the real run is not trustworthy evidence of session memory and the proof fails. ## Direct OpenCode Serve Calls Prefer a local OpenCode serve instance: ```bash export OPENCODE_BASE="${OPENCODE_BASE:-http://127.0.0.1:4096}" export OC_AGENT="${OC_AGENT:-build}" export OC_MODEL="${OC_MODEL:-}" export RUN_ID="${RUN_ID:-oc-subagent-persistence-$(date +%Y%m%dT%H%M%S)}" export ARTIFACT_DIR="${ARTIFACT_DIR:-./artifacts/$RUN_ID}" mkdir -p "$ARTIFACT_DIR" ``` Use OpenCode agent profiles such as `build`, `plan`, `general`, or configured local profiles. Do not put chat model ids such as `opencode-go/kimi-k2.6` in the OpenCode `agent` field. For this MVP proof, prefer a cheap model because the questions are simple and the proof target is child-session behavior. The live runner auto-selects a model unless `OC_MODEL` is set: 1. Local/free Ollama Qwen models, preferring `ollama/qwen3:14b` when present, then available local Qwen variants such as `ollama/qwen3:8b-nothink`, `ollama/qwen3:8b`, or `ollama/qwen2.5:14b`. 2. Cheap OpenCode Go fallback, currently `opencode-go/kimi-k2.6`. 3. Paid/high-confidence fallback, currently `openai/gpt-5.5`. `OC_MODEL` is sent as the message `model` object; it is not the `agent` profile. Set `OC_MODEL_CANDIDATES` to a comma-separated list to override the auto-selection order. Set `OC_OLLAMA_MODEL` to prefer a specific local Ollama tag. The selected model and rejected candidates are written to `model-selection.json`. Use different models for different work: | Work type | Default model policy | |-----------|----------------------| | Cheap MVP persistence/concurrency proof | Local Ollama Qwen first, then OpenCode Go | | Design critique, information architecture, broad synthesis | Moonshot AI Kimi K2.6 when configured, or OpenCode Go Kimi K2.6 | | Coding, debugging, patch planning, hard correctness gates | GPT-5.5 high reasoning via OAuth/profile only when the task needs it | Do not spend GPT-5.5 high reasoning on this MVP sanity unless cheaper candidates fail or the runner is diagnosing a real substrate bug. ## Live Sanity Run the real MVP task list against a local OpenCode serve sidecar: ```bash OPENCODE_BASE=http://127.0.0.1:4098 \ ARTIFACT_DIR=/tmp/oc-subagent/live-proof-$(date +%Y%m%dT%H%M%S) \ ./sanity-live.sh ``` Expected success output: ```json { "verdict": "PASS", "artifact_dir": "/tmp/oc-subagent/live-proof-..." } ``` If OpenCode is unreachable, the script writes `proof.json` with `verdict: BLOCKED`. If a task answer, session id, concurrency, or prompt-leak invariant fails, it writes `verdict: FAIL`. Minimal helpers: ```bash oc_json_id() { jq -r '.id // .ID // .sessionID // .session_id // empty' } oc_message_body() { local text="$1" jq -n --arg agent "$OC_AGENT" --arg text "$text" \ '{agent: $agent, parts: [{type: "text", text: $text}]}' } oc_create_parent() { local title="$1" curl -sS -X POST "$OPENCODE_BASE/session" \ -H 'Content-Type: application/json' \ -d "$(jq -n --arg title "$title" '{title: $title}')" } oc_create_child() { local parent_id="$1" local title="$2" curl -sS -X POST "$OPENCODE_BASE/session" \ -H 'Content-Type: application/json' \ -d "$(jq -n --arg parentID "$parent_id" --arg title "$title" '{parentID: $parentID, title: $title}')" } oc_send_turn_and_wait() { local child_session_id="$1" local text="$2" curl -sS -X POST "$OPENCODE_BASE/session/$child_session_id/message" \ -H 'Content-Type: application/json' \ -d "$(oc_message_body "$text")" } ``` ## Evidence Contract Write artifacts under one run directory: ```text artifacts/<run_id>/ project-agent-state.json parent-session.json session-map.json events.sse subagent_1-session.json subagent_1-turn-1-request.txt subagent_1-turn-1-response.json subagent_1-turn-2-request.txt subagent_1-turn-2-response.json subagent_2-session.json subagent_2-concurrent-request.txt subagent_2-concurrent-response.json subagent_3-session.json subagent_3-concurrent-request.txt subagent_3-concurrent-response.json subagent_1_negative-session.json subagent_1_negative-request.txt subagent_1_negative-response.json children-after.json messages-subagent_1-after.json model-selection.json events.jsonl heartbeats.jsonl timeline.jsonl task-status.json proof.json ``` Final proof shape: ```json { "verdict": "PASS", "run_id": "oc-subagent-persistence-001", "parent_session_id": "ses_parent", "model_selection": { "selected_model": "ollama/qwen3:8b-nothink", "artifact": "model-selection.json" }, "project_agent_persistence": { "step_1_result": 4, "state_survived_unrelated_tasks": true }, "sequential_subagent_persistence": { "subagent_run_id": "subagent_1", "child_session_id_turn_1": "ses_child_a", "child_session_id_turn_2": "ses_child_a", "same_child_session": true, "turn_1_answer": 22, "turn_2_answer": 32, "turn_2_prompt_did_not_leak_prior_value": true, "turn_2_waited_for_turn_1": true, "passed": true }, "concurrent_subagents": { "subagent_2_child_session_id": "ses_child_b", "subagent_3_child_session_id": "ses_child_c", "subagent_2_answer": "Paris", "subagent_3_answer": "red", "both_dispatched_before_first_result_consumed": true, "passed": true }, "negative_control": { "subagent_run_id": "subagent_1_negative", "child_session_id": "ses_child_neg", "prompt_is_turn_2_without_turn_1": true, "answer": null, "produced_32": false, "passed": true }, "failure_reasons": [], "artifacts": { "model_selection": "model-selection.json", "session_map": "session-map.json", "events": "events.sse", "events_jsonl": "events.jsonl", "heartbeats": "heartbeats.jsonl", "timeline": "timeline.jsonl", "task_status": "task-status.json", "children_after": "children-after.json", "messages_subagent_1_after": "messages-subagent_1-after.json", "negative_control_session": "subagent_1_negative-session.json", "negative_control_response": "subagent_1_negative-response.json" } } ``` ## Observability Contract The live runner follows the scillm transport convention: raw SSE is preserved for forensics, normalized JSONL is written for machines, and task state is snapshotted for operators. ```text events.sse raw OpenCode event stream events.jsonl normalized SSE rows keyed by session/subagent when known timeline.jsonl project-agent lifecycle rows such as run_started, task_started, task_completed heartbeats.jsonl periodic liveness rows for active DAG nodes/subagent calls task-status.json latest per-node state snapshot ``` Completion still gates on a terminal message response plus result validation. Heartbeats and streamed deltas prove liveness and diagnosability; they are not sufficient by themselves to advance a dependent DAG node. ## Failure Conditions Fail the proof if any of these occur: - `subagent_1` turn 2 uses a different child session without an explicit fork/recovery receipt. - Turn 2 dispatches before turn 1 returned and validated. - Two simultaneous turns are sent to the same child session. - Concurrent distractor results are consumed before both independent calls were dispatched. - The turn-2 `subagent_1` prompt includes `22`, `18`, `4`, or `32`. - The negative-control session (turn-2 prompt, no turn 1) produces `32`, which would mean `32` is not proof of session memory. - A measured invariant (`turn_2_prompt_did_not_leak_prior_value`, `turn_2_waited_for_turn_1`, `both_dispatched_before_first_result_consumed`) is false rather than asserted true. - The proof is based only on natural-language claims rather than saved artifacts. - A chat model id is used as the OpenCode `agent` field. - `events.jsonl`, `heartbeats.jsonl`, `timeline.jsonl`, or `task-status.json` is missing from a live run. ## Output Summary Return a concise final summary: ```text VERDICT: PASS | FAIL Project-agent state: PASS | FAIL Sequential subagent persistence: PASS | FAIL Concurrent subagents: PASS | FAIL Final values: project_agent_step_1 = 4 subagent_1_final = 32 subagent_2 = Paris subagent_3 = red Artifact directory: artifacts/<run_id> ```
GitHub에서 보기