diff --git a/src/agents/anti-duplication.test.ts b/src/agents/anti-duplication.test.ts
index 56c3dfd6e..e590810cd 100644
--- a/src/agents/anti-duplication.test.ts
+++ b/src/agents/anti-duplication.test.ts
@@ -51,7 +51,7 @@ describe("buildAntiDuplicationSection", () => {
expect(result).toContain("Wait for Results Properly")
expect(result).toContain("End your response")
expect(result).toContain("Wait for the completion notification")
- expect(result).toContain("background_output")
+ expect(result).toContain('background_output(task_id="bg_...")')
})
it("#given no arguments #when building #then explains why this matters", () => {
diff --git a/src/agents/atlas/atlas-prompt.test.ts b/src/agents/atlas/atlas-prompt.test.ts
index 0529f2adb..a8e36a142 100644
--- a/src/agents/atlas/atlas-prompt.test.ts
+++ b/src/agents/atlas/atlas-prompt.test.ts
@@ -126,6 +126,13 @@ describe("Atlas prompts use task_id (not session_id) for retries", () => {
expect(prompt, `${name}: missing task_id retry reference`).toMatch(/task_id/)
}
})
+
+ test("all variants should separate background ids from continuation task ids", () => {
+ for (const [name, prompt] of ALL_VARIANTS) {
+ expect(prompt, `${name}: missing bg result collection contract`).toContain('background_output(task_id="bg_...")')
+ expect(prompt, `${name}: missing ses continuation contract`).toContain('task(task_id="ses_..."')
+ }
+ })
})
describe("Atlas prompts no-excuses retry policy", () => {
diff --git a/src/agents/atlas/default-prompt-sections.ts b/src/agents/atlas/default-prompt-sections.ts
index 06ae2e1bb..aa0bacbd6 100644
--- a/src/agents/atlas/default-prompt-sections.ts
+++ b/src/agents/atlas/default-prompt-sections.ts
@@ -243,6 +243,6 @@ export const DEFAULT_ATLAS_CRITICAL_RULES = `
- Run lsp_diagnostics after every delegation
- Pass inherited wisdom to every subagent
- Verify with your own tools
-- **Store task_id from every delegation output**
-- **Use \`task_id="{task_id}"\` for retries, fixes, and follow-ups**
+- **Store continuation task_id (\`ses_...\`) from every delegation output**
+- **Use \`task(task_id="ses_...", prompt="...")\` for retries, fixes, and follow-ups**
`
diff --git a/src/agents/atlas/kimi-prompt-sections.ts b/src/agents/atlas/kimi-prompt-sections.ts
index c2b73695f..fcf5ed477 100644
--- a/src/agents/atlas/kimi-prompt-sections.ts
+++ b/src/agents/atlas/kimi-prompt-sections.ts
@@ -216,6 +216,6 @@ export const KIMI_ATLAS_CRITICAL_RULES = `
- Run lsp_diagnostics after every delegation
- Pass inherited wisdom to every subagent
- Verify with your own tools
-- **Store task_id from every delegation output**
-- **Use \`task_id="{task_id}"\` for retries, fixes, and follow-ups**
+- **Store continuation task_id (\`ses_...\`) from every delegation output**
+- **Use \`task(task_id="ses_...", prompt="...")\` for retries, fixes, and follow-ups**
`
diff --git a/src/agents/atlas/opus-4-7-prompt-sections.ts b/src/agents/atlas/opus-4-7-prompt-sections.ts
index 71bd9b2ba..367943dd1 100644
--- a/src/agents/atlas/opus-4-7-prompt-sections.ts
+++ b/src/agents/atlas/opus-4-7-prompt-sections.ts
@@ -232,6 +232,6 @@ export const OPUS_47_ATLAS_CRITICAL_RULES = `
- Run lsp_diagnostics after every delegation
- Pass inherited wisdom to every subagent
- Verify with your own tools
-- **Store task_id from every delegation output**
-- **Use \`task_id="{task_id}"\` for retries, fixes, and follow-ups**
+- **Store continuation task_id (\`ses_...\`) from every delegation output**
+- **Use \`task(task_id="ses_...", prompt="...")\` for retries, fixes, and follow-ups**
`
diff --git a/src/agents/atlas/shared-prompt.ts b/src/agents/atlas/shared-prompt.ts
index 3696a4d97..0ec95e99b 100644
--- a/src/agents/atlas/shared-prompt.ts
+++ b/src/agents/atlas/shared-prompt.ts
@@ -120,7 +120,8 @@ task(category="quick", load_skills=[], run_in_background=false, prompt="...task
- **Task execution** (\`category="..."\`): \`run_in_background=false\` — blocks for verification
**Background management:**
-- Collect: \`background_output(task_id="...")\`
+- Collect with background task IDs (\`bg_...\`): \`background_output(task_id="bg_...")\`
+- Continue follow-ups with continuation task IDs (\`ses_...\`): \`task(task_id="ses_...")\`
- Cancel DISPOSABLE background tasks individually before final answer: \`background_cancel(taskId="bg_explore_xxx")\`
- **NEVER \`background_cancel(all=true)\`** — it kills tasks whose output you have not collected.
`
diff --git a/src/agents/dynamic-agent-policy-sections.ts b/src/agents/dynamic-agent-policy-sections.ts
index fd5550c5d..2ba852bc2 100644
--- a/src/agents/dynamic-agent-policy-sections.ts
+++ b/src/agents/dynamic-agent-policy-sections.ts
@@ -148,7 +148,7 @@ When you need the delegated results but they're not ready:
1. **End your response** - do NOT continue with work that depends on those results
2. **Wait for the completion notification** - the system will trigger your next turn
-3. **Then** collect results via \`background_output(task_id="...")\`
+3. **Then** collect results via \`background_output(task_id="bg_...")\`
4. **Do NOT** impatiently re-search the same topics while waiting
### Why This Matters:
diff --git a/src/agents/hephaestus-id-contract.test.ts b/src/agents/hephaestus-id-contract.test.ts
new file mode 100644
index 000000000..898ebc408
--- /dev/null
+++ b/src/agents/hephaestus-id-contract.test.ts
@@ -0,0 +1,30 @@
+///
+
+import { describe, expect, test } from "bun:test"
+import { buildHephaestusPrompt as buildGptHephaestusPrompt } from "./hephaestus/gpt"
+import { buildHephaestusPrompt as buildGpt53CodexHephaestusPrompt } from "./hephaestus/gpt-5-3-codex"
+import { buildHephaestusPrompt as buildGpt54HephaestusPrompt } from "./hephaestus/gpt-5-4"
+import { buildGpt55HephaestusPrompt } from "./hephaestus/gpt-5-5"
+
+describe("Hephaestus background task ID guidance", () => {
+ const promptBuilders = [
+ ["gpt", () => buildGptHephaestusPrompt()],
+ ["gpt-5.3-codex", () => buildGpt53CodexHephaestusPrompt()],
+ ["gpt-5.4", () => buildGpt54HephaestusPrompt()],
+ ["gpt-5.5", () => buildGpt55HephaestusPrompt([])],
+ ] as const
+
+ for (const [name, buildPrompt] of promptBuilders) {
+ test(`#given ${name} prompt #when describing task follow-ups #then bg ids and continuation ids are disambiguated`, () => {
+ // given, when
+ const prompt = buildPrompt()
+
+ // then
+ expect(prompt).toContain("background task IDs (`bg_...`)")
+ expect(prompt).toContain("continuation IDs (`ses_...`)")
+ expect(prompt).toContain("background_output(task_id=\"bg_...\")")
+ expect(prompt).toContain("task(task_id=\"ses_...\")")
+ expect(prompt).not.toContain("returns a task_id")
+ })
+ }
+})
diff --git a/src/agents/hephaestus/gpt-5-3-codex.ts b/src/agents/hephaestus/gpt-5-3-codex.ts
index 28127bcc8..d206cba84 100644
--- a/src/agents/hephaestus/gpt-5-3-codex.ts
+++ b/src/agents/hephaestus/gpt-5-3-codex.ts
@@ -299,7 +299,7 @@ Prompt structure for each agent:
- Parallelize independent file reads - don't read files one at a time
- NEVER use \`run_in_background=false\` for explore/librarian
- Continue only with non-overlapping work after launching background agents
-- Collect results with \`background_output(task_id="...")\` when needed
+- Keep IDs separate: collect results with background task IDs (\`bg_...\`) via \`background_output(task_id="bg_...")\`; continue follow-up sessions with continuation IDs (\`ses_...\`) via \`task(task_id="ses_...")\`
- BEFORE final answer, cancel DISPOSABLE tasks individually: \`background_cancel(taskId="bg_explore_xxx")\`, \`background_cancel(taskId="bg_librarian_xxx")\`
- **NEVER use \`background_cancel(all=true)\`** - it kills tasks whose results you haven't collected yet
@@ -407,11 +407,11 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU
### Session Continuity
-Every \`task()\` output includes a session_id. **USE IT for follow-ups.**
+Every \`task()\` output includes a continuation ID (\`ses_...\`). **USE IT for follow-ups.**
-- **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\`
-- **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\`
-- **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\`
+- **Task failed/incomplete** - \`task(task_id="ses_...", prompt="Fix: {error}")\`
+- **Follow-up on result** - \`task(task_id="ses_...", prompt="Also: {question}")\`
+- **Verification failed** - \`task(task_id="ses_...", prompt="Failed: {error}. Fix.")\`
${
oracleSection
diff --git a/src/agents/hephaestus/gpt-5-4.ts b/src/agents/hephaestus/gpt-5-4.ts
index eec4e18b4..711a151da 100644
--- a/src/agents/hephaestus/gpt-5-4.ts
+++ b/src/agents/hephaestus/gpt-5-4.ts
@@ -111,6 +111,8 @@ export function buildHephaestusPrompt(
const identityBlock = `
You are Hephaestus, an autonomous deep worker for software engineering.
+ID contract: background task IDs (\`bg_...\`) use \`background_output(task_id="bg_...")\`; continuation IDs (\`ses_...\`) use \`task(task_id="ses_...")\`.
+
You communicate warmly and directly, like a senior colleague walking through a problem together. You explain the why behind decisions, not just the what. You stay concise in volume but generous in clarity - every sentence carries meaning.
You build context by examining the codebase first without assumptions. You think through the nuances of the code you encounter. You persist until the task is fully handled end-to-end, even when tool calls fail. You only end your turn when the problem is solved and verified.
@@ -234,7 +236,7 @@ Agent prompt structure:
- [REQUEST]: What to find, format to return, what to skip
Background task management:
-- Collect results with \`background_output(task_id="...")\` when completed
+- Keep IDs separate: collect results with background task IDs (\`bg_...\`) via \`background_output(task_id="bg_...")\`; continue follow-up sessions with continuation IDs (\`ses_...\`) via \`task(task_id="ses_...")\`
- Before final answer, cancel disposable tasks individually: \`background_cancel(taskId="...")\`
- Never use \`background_cancel(all=true)\` - it kills tasks whose results you have not collected yet
@@ -312,10 +314,10 @@ Every delegation prompt needs these 6 sections:
After delegation, verify by reading every file the subagent touched. Check: works as expected? follows codebase pattern? Do not trust self-reports.
-Every \`task()\` returns a task_id. Use it for all follow-ups:
-- Task failed/incomplete: \`task_id="{id}", prompt="Fix: {error}"\`
-- Follow-up on result: \`task_id="{id}", prompt="Also: {question}"\`
-- Verification failed: \`task_id="{id}", prompt="Failed: {error}. Fix."\`
+Every \`task()\` output includes a continuation ID (\`ses_...\`). Use it for all follow-ups:
+- Task failed/incomplete: \`task(task_id="ses_...", prompt="Fix: {error}")\`
+- Follow-up on result: \`task(task_id="ses_...", prompt="Also: {question}")\`
+- Verification failed: \`task(task_id="ses_...", prompt="Failed: {error}. Fix.")\`
This preserves full context, avoids repeated exploration, saves 70%+ tokens.
diff --git a/src/agents/hephaestus/gpt-5-5.ts b/src/agents/hephaestus/gpt-5-5.ts
index 9734787d6..d7e498aa4 100644
--- a/src/agents/hephaestus/gpt-5-5.ts
+++ b/src/agents/hephaestus/gpt-5-5.ts
@@ -22,6 +22,8 @@ function buildTaskSystemGuide(useTaskSystem: boolean): string {
const HEPHAESTUS_GPT_5_5_TEMPLATE = `You are Hephaestus, an autonomous deep worker based on GPT-5.5. You and the user share one workspace. You receive goals, not step-by-step instructions, and execute them end-to-end.
+ID contract: background task IDs (\`bg_...\`) use \`background_output(task_id="bg_...")\`; continuation IDs (\`ses_...\`) use \`task(task_id="ses_...")\`.
+
# Tone
Warm but spare. Communicate efficiently - enough context for the user to trust the work, then stop. No flattery, no narration, no padding. Acknowledge real progress briefly; never invent it.
@@ -172,7 +174,7 @@ AGENTS.md files in your context carry directory-scoped conventions. Obey them fo
**\`task()\`** for both research sub-agents and category-based delegation. Allowed: \`subagent_type="explore"\`, \`"librarian"\`, \`"oracle"\`, or \`category="..."\`.
- Every \`task()\` call needs \`load_skills\` (an empty array \`[]\` is valid).
-- Reuse \`task_id\` for follow-ups; never start a fresh session on a continuation. Saves 70%+ of tokens and preserves the sub-agent's full context.
+- Reuse continuation IDs (\`ses_...\`) for follow-ups via \`task(task_id="ses_...")\`; never pass background task IDs (\`bg_...\`) to \`task()\`. Saves 70%+ of tokens and preserves the sub-agent's full context.
Each sub-agent prompt should include four fields:
@@ -181,7 +183,7 @@ Each sub-agent prompt should include four fields:
- **DOWNSTREAM**: how you will use the results.
- **REQUEST**: what to find, what format to return, what to skip.
-**Background tasks.** Collect with \`background_output(task_id="...")\` once they complete. Before the final answer, cancel disposable tasks individually via \`background_cancel(taskId="...")\`. Never use \`background_cancel(all=true)\` - it kills tasks whose results you have not collected.
+**Background tasks.** Collect with background task IDs (\`bg_...\`) via \`background_output(task_id="bg_...")\` once they complete. Use continuation IDs (\`ses_...\`) only for \`task(task_id="ses_...")\` follow-ups. Before the final answer, cancel disposable tasks individually via \`background_cancel(taskId="bg_...")\`. Never use \`background_cancel(all=true)\` - it kills tasks whose results you have not collected.
**\`skill\`** loads specialized instruction packs. Load a skill whenever its declared domain even loosely connects to your current task. Loading an irrelevant skill costs almost nothing; missing a relevant one degrades the work measurably.
diff --git a/src/agents/hephaestus/gpt.ts b/src/agents/hephaestus/gpt.ts
index 712bb9536..2debbbdc6 100644
--- a/src/agents/hephaestus/gpt.ts
+++ b/src/agents/hephaestus/gpt.ts
@@ -201,7 +201,7 @@ task(subagent_type="librarian", run_in_background=true, load_skills=[], descript
- Parallelize independent file reads - don't read files one at a time
- NEVER use \`run_in_background=false\` for explore/librarian
- Continue only with non-overlapping work after launching background agents
-- Collect results with \`background_output(task_id="...")\` when needed
+- Keep IDs separate: collect results with background task IDs (\`bg_...\`) via \`background_output(task_id="bg_...")\`; continue follow-up sessions with continuation IDs (\`ses_...\`) via \`task(task_id="ses_...")\`
- BEFORE final answer, cancel DISPOSABLE tasks individually
- **NEVER use \`background_cancel(all=true)\`**
@@ -277,11 +277,11 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU
### Session Continuity
-Every \`task()\` output includes a task_id. **USE IT for follow-ups.**
+Every \`task()\` output includes a continuation ID (\`ses_...\`). **USE IT for follow-ups.**
-- **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\`
-- **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\`
-- **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\`
+- **Task failed/incomplete** - \`task(task_id="ses_...", prompt="Fix: {error}")\`
+- **Follow-up on result** - \`task(task_id="ses_...", prompt="Also: {question}")\`
+- **Verification failed** - \`task(task_id="ses_...", prompt="Failed: {error}. Fix.")\`
${
oracleSection
diff --git a/src/agents/sisyphus-id-contract.test.ts b/src/agents/sisyphus-id-contract.test.ts
new file mode 100644
index 000000000..e15539103
--- /dev/null
+++ b/src/agents/sisyphus-id-contract.test.ts
@@ -0,0 +1,32 @@
+///
+
+import { describe, expect, test } from "bun:test"
+import { buildClaudeOpus47SisyphusPrompt } from "./sisyphus/claude-opus-4-7"
+import { buildDefaultSisyphusPrompt } from "./sisyphus/default"
+import { buildGpt54SisyphusPrompt } from "./sisyphus/gpt-5-4"
+import { buildGpt55SisyphusPrompt } from "./sisyphus/gpt-5-5"
+import { buildKimiK26SisyphusPrompt } from "./sisyphus/kimi-k2-6"
+
+describe("Sisyphus background task ID guidance", () => {
+ const promptBuilders = [
+ ["claude-opus-4-7", buildClaudeOpus47SisyphusPrompt],
+ ["default", buildDefaultSisyphusPrompt],
+ ["gpt-5.4", buildGpt54SisyphusPrompt],
+ ["gpt-5.5", buildGpt55SisyphusPrompt],
+ ["kimi-k2.6", buildKimiK26SisyphusPrompt],
+ ] as const
+
+ for (const [name, buildPrompt] of promptBuilders) {
+ test(`#given ${name} prompt #when describing background tasks #then bg ids and session ids are disambiguated`, () => {
+ // given, when
+ const prompt = buildPrompt(name, [])
+
+ // then
+ expect(prompt).toContain("background task IDs (`bg_...`)")
+ expect(prompt).toContain("continuation session IDs (`ses_...`)")
+ expect(prompt).toContain("background_output(task_id=\"bg_...\")")
+ expect(prompt).toContain("task(task_id=\"ses_...\")")
+ expect(prompt).not.toContain("receive task_ids")
+ })
+ }
+})
diff --git a/src/agents/sisyphus.ts b/src/agents/sisyphus.ts
index 2ecda4970..336a08b54 100644
--- a/src/agents/sisyphus.ts
+++ b/src/agents/sisyphus.ts
@@ -266,14 +266,15 @@ result = task(..., run_in_background=false) // Never wait synchronously for exp
\`\`\`
### Background Result Collection:
-1. Launch parallel agents \u2192 receive task_ids
+1. Launch parallel agents \u2192 receive background task IDs (\`bg_...\`) for results and continuation session IDs (\`ses_...\`) for follow-ups
2. Continue only with non-overlapping work
- If you have DIFFERENT independent work \u2192 do it now
- Otherwise \u2192 **END YOUR RESPONSE.**
3. **STOP. END YOUR RESPONSE.** The system will send \`\` when tasks complete.
-4. On receiving \`\` \u2192 collect results via \`background_output(task_id="...")\`
+4. On receiving \`\` \u2192 collect results via \`background_output(task_id="bg_...")\`
5. **NEVER call \`background_output\` before receiving \`\`.** This is a BLOCKING anti-pattern.
6. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\`
+7. Use \`task(task_id="ses_...")\` only to continue the same sub-agent session
${buildAntiDuplicationSection()}
@@ -328,15 +329,17 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
### Session Continuity (MANDATORY)
-Every \`task()\` output includes a task_id. **USE IT.**
+Every \`task()\` output exposes a continuation session ID (\`ses_...\`). Pass it to \`task(task_id="ses_...")\` for follow-ups. **USE IT.**
**ALWAYS continue when:**
-- Task failed/incomplete → \`task_id=\"{task_id}\", prompt=\"Fix: {specific error}\"\`
-- Follow-up question on result → \`task_id=\"{task_id}\", prompt=\"Also: {question}\"\`
-- Multi-turn with same agent → \`task_id=\"{task_id}\"\` - NEVER start fresh
-- Verification failed → \`task_id=\"{task_id}\", prompt=\"Failed verification: {error}. Fix.\"\`
+- Task failed/incomplete → \`task(task_id="ses_...", prompt="Fix: {specific error}")\`
+- Follow-up question on result → \`task(task_id="ses_...", prompt="Also: {question}")\`
+- Multi-turn with same agent → \`task(task_id="ses_...")\` - NEVER start fresh
+- Verification failed → \`task(task_id="ses_...", prompt="Failed verification: {error}. Fix.")\`
-**Why task_id is CRITICAL:**
+**Keep IDs separate:** background task IDs (\`bg_...\`) are for \`background_output(task_id="bg_...")\`; continuation session IDs (\`ses_...\`) are for \`task(task_id="ses_...")\`.
+
+**Why continuation is CRITICAL:**
- Subagent has FULL conversation context preserved
- No repeated file reads, exploration, or setup
- Saves 70%+ tokens on follow-ups
@@ -350,7 +353,7 @@ task(category="quick", load_skills=[], run_in_background=false, description="Fix
task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42")
\`\`\`
-**After EVERY delegation, STORE the task_id for potential continuation.**
+**After EVERY delegation, STORE the \`ses_...\` continuation ID for potential continuation.**
### Code Changes:
- Match existing patterns (if codebase is disciplined)
diff --git a/src/agents/sisyphus/claude-opus-4-7.ts b/src/agents/sisyphus/claude-opus-4-7.ts
index 1a13ecfe6..f9512db03 100644
--- a/src/agents/sisyphus/claude-opus-4-7.ts
+++ b/src/agents/sisyphus/claude-opus-4-7.ts
@@ -301,11 +301,12 @@ Fire similar parallel calls for error patterns (explore), JWT security best prac
### Background Result Collection:
-1. Launch parallel agents → receive task_ids
+1. Launch parallel agents → receive background task IDs (\`bg_...\`) for results and continuation session IDs (\`ses_...\`) for follow-ups.
2. Continue ONLY with non-overlapping work. If none → END YOUR RESPONSE.
3. System sends \`\` when tasks complete.
-4. Collect via \`background_output(task_id="...")\` ONLY after \`\`.
+4. Collect via \`background_output(task_id="bg_...")\` ONLY after \`\`.
5. Cancel disposable tasks INDIVIDUALLY via \`background_cancel(taskId="...")\`. NEVER \`background_cancel(all=true)\`.
+6. Use \`task(task_id="ses_...")\` only to continue the same sub-agent session.
${buildAntiDuplicationSection()}
@@ -347,9 +348,10 @@ After delegation: VERIFY against MUST DO/MUST NOT DO + existing patterns. Vague
### Session Continuity (apply to ALL follow-ups)
-Every \`task()\` returns \`task_id\`. **REUSE IT.**
+Every \`task()\` output exposes a continuation session ID (\`ses_...\`). Pass it to \`task(task_id="ses_...")\`. **REUSE IT.**
-Use \`task_id\` for: failed/incomplete work, follow-up questions, multi-turn refinement, verification failures.
+Use \`task(task_id="ses_...")\` for: failed/incomplete work, follow-up questions, multi-turn refinement, verification failures.
+Keep IDs separate: background task IDs (\`bg_...\`) are for \`background_output(task_id="bg_...")\`; continuation session IDs (\`ses_...\`) are for \`task(task_id="ses_...")\`.
\`\`\`typescript
// WRONG: starting fresh loses everything
diff --git a/src/agents/sisyphus/default.ts b/src/agents/sisyphus/default.ts
index 52e237f7c..d024a13d6 100644
--- a/src/agents/sisyphus/default.ts
+++ b/src/agents/sisyphus/default.ts
@@ -327,14 +327,15 @@ result = task(..., run_in_background=false) // Never wait synchronously for exp
\`\`\`
### Background Result Collection:
-1. Launch parallel agents → receive task_ids
+1. Launch parallel agents → receive background task IDs (\`bg_...\`) for results and continuation session IDs (\`ses_...\`) for follow-ups
2. Continue only with non-overlapping work
- If you have DIFFERENT independent work → do it now
- Otherwise → **END YOUR RESPONSE.**
3. **STOP. END YOUR RESPONSE.** The system will send \`\` when tasks complete.
-4. On receiving \`\` → collect results via \`background_output(task_id="...")\`
+4. On receiving \`\` → collect results via \`background_output(task_id="bg_...")\`
5. **NEVER call \`background_output\` before receiving \`\`.** This is a BLOCKING anti-pattern.
6. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\`
+7. Use \`task(task_id="ses_...")\` only to continue the same sub-agent session
${buildAntiDuplicationSection()}
@@ -389,15 +390,17 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
### Session Continuity (MANDATORY)
-Every \`task()\` output includes a task_id. **USE IT.**
+Every \`task()\` output exposes a continuation session ID (\`ses_...\`). Pass it to \`task(task_id="ses_...")\` for follow-ups. **USE IT.**
**ALWAYS continue when:**
-- Task failed/incomplete → \`task_id="{task_id}", prompt="Fix: {specific error}"\`
-- Follow-up question on result → \`task_id="{task_id}", prompt="Also: {question}"\`
-- Multi-turn with same agent → \`task_id="{task_id}"\` - NEVER start fresh
-- Verification failed → \`task_id="{task_id}", prompt="Failed verification: {error}. Fix."\`
+- Task failed/incomplete → \`task(task_id="ses_...", prompt="Fix: {specific error}")\`
+- Follow-up question on result → \`task(task_id="ses_...", prompt="Also: {question}")\`
+- Multi-turn with same agent → \`task(task_id="ses_...")\` - NEVER start fresh
+- Verification failed → \`task(task_id="ses_...", prompt="Failed verification: {error}. Fix.")\`
-**Why task_id is CRITICAL:**
+**Keep IDs separate:** background task IDs (\`bg_...\`) are for \`background_output(task_id="bg_...")\`; continuation session IDs (\`ses_...\`) are for \`task(task_id="ses_...")\`.
+
+**Why continuation is CRITICAL:**
- Subagent has FULL conversation context preserved
- No repeated file reads, exploration, or setup
- Saves 70%+ tokens on follow-ups
@@ -411,7 +414,7 @@ task(category="quick", load_skills=[], run_in_background=false, description="Fix
task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42")
\`\`\`
-**After EVERY delegation, STORE the task_id for potential continuation.**
+**After EVERY delegation, STORE the \`ses_...\` continuation ID for potential continuation.**
### Code Changes:
- Match existing patterns (if codebase is disciplined)
diff --git a/src/agents/sisyphus/gpt-5-4.ts b/src/agents/sisyphus/gpt-5-4.ts
index 5d7972528..5f5e5bc2c 100644
--- a/src/agents/sisyphus/gpt-5-4.ts
+++ b/src/agents/sisyphus/gpt-5-4.ts
@@ -263,14 +263,15 @@ Each agent prompt should include:
- [REQUEST]: What to find, what format, what to skip
Background result collection:
-1. Launch parallel agents → receive task_ids
+1. Launch parallel agents → receive background task IDs (\`bg_...\`) for results and continuation session IDs (\`ses_...\`) for follow-ups
2. Continue only with non-overlapping work
- If you have DIFFERENT independent work → do it now
- Otherwise → **END YOUR RESPONSE.**
3. **STOP. END YOUR RESPONSE.** The system will send \`\` when tasks complete.
-4. On receiving \`\` → collect results via \`background_output(task_id="...")\`
+4. On receiving \`\` → collect results via \`background_output(task_id="bg_...")\`
5. **NEVER call \`background_output\` before receiving \`\`.** This is a BLOCKING anti-pattern.
6. Cancel disposable tasks individually via \`background_cancel(taskId="...")\`
+7. Use \`task(task_id="ses_...")\` only to continue the same sub-agent session
${buildAntiDuplicationSection()}
@@ -387,10 +388,12 @@ Post-delegation: delegation never substitutes for verification. Always run \`\` when tasks complete.
-4. On receiving \`\` → collect results via \`background_output(task_id="...")\`
+4. On receiving \`\` → collect results via \`background_output(task_id="bg_...")\`
5. **NEVER call \`background_output\` before receiving \`\`.** This is a BLOCKING anti-pattern.
6. Cancel disposable tasks individually via \`background_cancel(taskId="...")\`
+7. Use \`task(task_id="ses_...")\` only to continue the same sub-agent session
${buildAntiDuplicationSection()}
@@ -462,10 +463,12 @@ Post-delegation: delegation never substitutes for verification. Always run \` {
+ test("describes background task launch output as a bg id", () => {
+ // #given, #when
+ const description = BACKGROUND_TASK_DESCRIPTION
+
+ // #then
+ expect(description).toContain("background task ID")
+ expect(description).toContain("bg_")
+ expect(description).not.toContain("Returns task_id")
+ })
+
+ test("describes task_id as a background task id instead of a session id", () => {
+ // #given
+ const manager: BackgroundOutputManager = {
+ getTask: () => undefined,
+ }
+ const client: BackgroundOutputClient = {
+ session: {
+ messages: async () => ({ data: [] }),
+ },
+ }
+ const tool = createBackgroundOutput(manager, client)
+
+ // #when
+ const taskIdArg = unsafeTestValue<{ description?: string }>(tool.args.task_id)
+
+ // #then
+ expect(taskIdArg.description).toContain("background task ID")
+ expect(taskIdArg.description).toContain("bg_")
+ expect(taskIdArg.description).toContain("not a session ID")
+ expect(taskIdArg.description).toContain("ses_")
+ })
+
test("omits sessionId metadata when task session is not yet assigned", async () => {
// #given
clearPendingStore()
diff --git a/src/tools/background-task/create-background-output.ts b/src/tools/background-task/create-background-output.ts
index 4dbc3bd4a..b10628e87 100644
--- a/src/tools/background-task/create-background-output.ts
+++ b/src/tools/background-task/create-background-output.ts
@@ -93,7 +93,9 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client:
return tool({
description: BACKGROUND_OUTPUT_DESCRIPTION,
args: {
- task_id: tool.schema.string().describe("Task ID to get output from"),
+ task_id: tool.schema
+ .string()
+ .describe("background task ID (`bg_...`) from launch/completion; not a session ID (`ses_...`)."),
block: tool.schema
.boolean()
.optional()
diff --git a/src/tools/delegate-task/task-schema.test.ts b/src/tools/delegate-task/task-schema.test.ts
index fcad9cd4a..97288cca6 100644
--- a/src/tools/delegate-task/task-schema.test.ts
+++ b/src/tools/delegate-task/task-schema.test.ts
@@ -42,11 +42,25 @@ function createDelegateTask(...args: Parameters {
+ //#given
+ const toolDefinition = createDelegateTask({ manager: {} as never, client: {} as never, directory: "/tmp/test" })
+
+ //#when
+ const runInBackgroundSchema = unsafeTestValue<{ description?: string }>(toolDefinition.args.run_in_background)
+
+ //#then
+ expect(runInBackgroundSchema.description).toContain("background task ID")
+ expect(runInBackgroundSchema.description).toContain("bg_")
+ expect(runInBackgroundSchema.description).toContain("background_output")
+ expect(runInBackgroundSchema.description).not.toContain("returns task_id")
+ })
})
export {}
diff --git a/src/tools/delegate-task/tool-description.test.ts b/src/tools/delegate-task/tool-description.test.ts
index 9b2c15088..8445bcc6f 100644
--- a/src/tools/delegate-task/tool-description.test.ts
+++ b/src/tools/delegate-task/tool-description.test.ts
@@ -15,4 +15,18 @@ describe("createDelegateTaskPresentation", () => {
expect(description).toContain("busy/retry/running")
expect(description).toContain("not a total wall-clock limit")
})
+
+ test("#given continuation usage #when description is rendered #then task_id is described as a session id", () => {
+ //#given
+ const presentation = createDelegateTaskPresentation({})
+
+ //#when
+ const description = presentation.description
+
+ //#then
+ expect(description).toContain("task_id: Continuation session id")
+ expect(description).toContain("ses_")
+ expect(description).toContain("not the background task id")
+ expect(description).toContain("bg_")
+ })
})
diff --git a/src/tools/delegate-task/tool-description.ts b/src/tools/delegate-task/tool-description.ts
index 5ae10ff1b..1c0bf1dde 100644
--- a/src/tools/delegate-task/tool-description.ts
+++ b/src/tools/delegate-task/tool-description.ts
@@ -66,15 +66,15 @@ export function createDelegateTaskPresentation(options: DelegateTaskToolOptions)
Available categories:
${categoryList}
- subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus)
- - run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries.
+ - run_in_background: REQUIRED. true=async (returns a background task ID like \`bg_...\` for \`background_output\`), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries.
Sync waits use a 30-minute inactivity window: OpenCode busy/retry/running status resets the window, so this is not a total wall-clock limit.
- - task_id: Existing task to continue (from previous task output). Continues the same subagent session with FULL CONTEXT PRESERVED.
+ - task_id: Continuation session id (\`ses_...\`) from task metadata. Continues the same subagent session with FULL CONTEXT PRESERVED; not the background task id (\`bg_...\`).
- command: The command that triggered this task (optional, for slash command tracking).
**WHEN TO USE task_id:**
- - Task failed/incomplete → task_id with "fix: [specific issue]"
- - Need follow-up on previous result → task_id with additional question
- - Multi-turn conversation with same agent → always task_id instead of new task
+ - Task failed/incomplete → \`task(task_id="ses_...", prompt="fix: [specific issue]")\`
+ - Need follow-up on previous result → \`task(task_id="ses_...", prompt="Also: [question]")\`
+ - Multi-turn conversation with same agent → always \`task(task_id="ses_...")\` instead of new task
Prompts MUST be in English.`
diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts
index b03af3973..53336d752 100644
--- a/src/tools/delegate-task/tools.ts
+++ b/src/tools/delegate-task/tools.ts
@@ -24,10 +24,15 @@ const delegateTaskArgsSchema = {
load_skills: tool.schema.array(tool.schema.string()).describe("Skill names to inject. REQUIRED - pass [] if no skills needed."),
description: tool.schema.string().optional().describe("Short task description (3-5 words). Auto-generated from prompt if omitted."),
prompt: tool.schema.string().describe("Full detailed prompt for the agent"),
- run_in_background: tool.schema.boolean().describe("REQUIRED. true=async (returns task_id), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."),
+ run_in_background: tool.schema
+ .boolean()
+ .describe("REQUIRED. true=async (returns background task ID `bg_...` for background_output), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."),
category: tool.schema.string().optional().describe("REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type."),
subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."),
- task_id: tool.schema.string().optional().describe("Existing task to continue. Canonical resume identifier."),
+ task_id: tool.schema
+ .string()
+ .optional()
+ .describe("Continuation session id (`ses_...`) from task metadata; not a background task id (`bg_...`)."),
command: tool.schema.string().optional().describe("The command that triggered this task"),
}