Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Subagents and context isolation

After this lesson: I can give a side task its own window and take back only a short answer.

60 min lesson6 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

Give a side task its own window

A subagent is a second model call that takes one side task, works in a fresh window and hands back a short answer. The parent never sees the work, only the result.

That is the point. A search that reads forty files would fill the parent's window. Done in a subagent, it costs the parent a few lines.

By the end of this lesson

Note

I can give a side task its own window and take back only a short answer.

Key words

WordWhat it means
Subagenta model call that does one side task alone
Isolationthe side task has its own window
Briefthe short message that starts a subagent
Contractthe fields and size a result must have
Resultwhat the subagent gives back
Parentthe agent that asked for the side task

The cells students fill in are left blank in this preview.

A subagent is not a handoff

A handoff passes the whole job to another agent, and that agent carries on. A subagent is different. The parent stays in charge and asks one question.

The subagent starts empty. It does not see the parent's history. It sees the brief and nothing else.

Write a brief, then a contract

A good brief states the goal, the facts that matter, the files to look at and the size of the answer. Everything the subagent needs is in it, because it has no other source.

A contract says what comes back: named fields and a word limit. The harness cuts the result to the contract before the parent reads it. A long answer is not a better one.

The shape of a brief and a result

PartHoldsWhy
GoalOne questionThe subagent knows when it is done
FactsWhat is already knownIt does not repeat work
FilesWhere to lookIt does not wander
SizeA word limitThe result stays short
ContractFields and a limitThe parent reads a fixed shape

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people pass the parent's whole history to the subagent, to be safe. Then nothing is isolated and the cost doubles. Write a brief with only what the side task needs.

Write the model helper, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// The token counts of a reply, or null when the reply carries none.' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the model helper, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const data = await res.json();' '    const text = data.choices[0].message.content;' '    return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the subagent run, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '// Words stand in for tokens, as in lesson 1.' 'function words(text) { return text.split(\" \").length; }' 'const parent = \"User wants the failing test fixed. We read app.py, ran the tests twice, checked the readme and talked about style for a while. The user asked to keep changes small.\";' 'const work = [' '  \"ls: app.py readme tests notes.txt old.py\",' '  \"grep total: app.py line 4 def total items return sum items\",' '  \"grep total: tests line 9 assert total of 3 items equals 12\",' '  \"read tests: 40 lines of test code for the basket\",' '  \"read app.py: 22 lines that price a basket and add tax\",' '];' > sub4.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the subagent run, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function makeBrief(goal, facts, files, max) {' '  const lines = [\"Goal: \" + goal];' '  for (const f of facts) lines.push(\"Fact: \" + f);' '  for (const f of files) lines.push(\"File: \" + f);' '  lines.push(\"Answer in at most \" + max + \" words.\");' '  return lines.join(\" | \");' '}' 'function cut(text, max) { return text.split(\" \").slice(0, max).join(\" \"); }' 'function sum(list) { return list.reduce(function (a, b) { return a + b; }, 0); }' >> sub4.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the subagent run, part 3

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const brief = makeBrief(\"Find where the basket total is worked out\", [\"The test for 3 items is wrong\"], [\"app.py\", \"tests\"], 20);' '  const sample = \"The total is worked out in app.py at line 4. It sums the items and adds no tax. See tests line 9.\";' '  const own = brief + \" | \" + work.join(\" ; \");' '  const reply = await ask([{ role: \"user\", content: own }], sample, 60);' '  const result = cut(reply.text, 20);' '  console.log(\"parent window: \" + words(parent) + \" words\");' '  console.log(\"side task window: \" + (words(own)) + \" words, of which \" + sum(work.map(words)) + \" are tool results\");' '  console.log(\"result kept: \" + result);' '  console.log(\"the parent pays \" + (words(brief) + words(result)) + \" words\");' '}' 'main();' >> sub4.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run the subagent

Command
docker exec -w /home/node/project agent node sub4.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

The tool results are recorded

The five tool results are invented and recorded, standing for what a real subagent would read. The one live call gets the brief and those results, and the Run cuts the reply to twenty words.

With no model it prints a Recorded sample and uses a recorded answer.

One possible output

LineWhat it shows
parent window: 30 wordsWhat the parent already holds
side task window: 86 words, of which 50 are tool resultsWhere the work happened
result kept: The total is worked out in ...Twenty words at most
the parent pays 51 wordsThe brief and the result, not the 50

The cells students fill in are left blank in this preview.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.