learn-claude-code s06-s10: Context and Capability Review Notes
Created: 2026-06-26
Scope: s06_subagent through s10_system_prompt
Goal: review how the Agent harness evolves in context isolation, knowledge loading, context compaction, long-term memory, and system prompt assembly.
0. Memorize These Five Sentences First
s06: a sub-agent completes a subtask on its own freshmessages[], and the main Agent only receives the summary.s07: Skill Loading first gives the model a skill catalog, then loads the fullSKILL.mdwithload_skillwhen needed.s08: Context Compact cleans upmessagesbefore every LLM call to keep the context window from blowing up.s09: Memory writes long-term useful information into.memory/, preserved across compaction and across sessions.s10: the System Prompt is no longer hardcoded; it is assembled at runtime from the currentcontext.
1. The Overall Storyline of s06-s10
s01-s05 addresses whether the Agent can act at all:
tool_use -> Python handler -> tool_result -> loop
s06-s10 addresses how the Agent can act over the long run, professionally and stably:
s06: the complex process is too noisy -> isolate it with a sub-agent
s07: there is too much domain knowledge -> load skills on demand
s08: the historical context is too long -> shrink it with compaction
s09: compaction loses important information -> preserve it with memory
s10: the system prompt is too messy -> assemble it from sections at runtime
You can see these five sections as different facets of the same problem:
Context is a finite resource.
subagent: keep the subtask process from polluting the main context
skill: keep irrelevant knowledge from entering the context ahead of time
compact: keep the message history from growing without bound
memory: keep important information from disappearing because of compaction
system prompt: keep system instructions from becoming one unmaintainable blob of text
2. s06: Subagent, Context Isolation
File: s06_subagent/code.py
2.1 The Problem s06 Solves
A complex task generates a lot of intermediate process. For example:
read 20 files
run 10 commands
analyze the call chain
in the end only one sentence of conclusion is needed
If all of that intermediate process stays in the main Agent’s messages, the main context becomes very noisy.
So s06 adds a task tool that lets the main Agent dispatch a sub-agent to handle a side task.
2.2 task Is an Ordinary tool
Code location: s06_subagent/code.py:252
TOOLS.append({
"name": "task",
"description": "Launch a subagent to handle a complex subtask. Returns only the final conclusion.",
"input_schema": {"type": "object", "properties": {"description": {"type": "string"}}, "required": ["description"]},
})
TOOL_HANDLERS["task"] = spawn_subagent
This is exactly the same as the earlier tool mechanism:
The model sees the task schema
-> the model returns tool_use: task
-> Python looks up TOOL_HANDLERS["task"]
-> executes spawn_subagent(description)
So there is no magic in task. It is just a tool whose handler happens to be special.
2.3 The Sub-agent Has Its Own system prompt
Code location: s06_subagent/code.py:58
SUB_SYSTEM = (
f"You are a coding agent at {WORKDIR}. "
"Complete the task you were given, then return a concise summary. "
"Do not delegate further."
)
This shows the sub-agent’s goal is narrower:
Complete the task you were given
Return a concise summary
Do not delegate further
2.4 The Sub-agent Has Its Own Tool Set
Code location: s06_subagent/code.py:182
SUB_TOOLS = [
bash,
read_file,
write_file,
edit_file,
glob,
]
Note: SUB_TOOLS does not include task.
The purpose:
prevent main Agent -> sub-agent -> sub-sub-agent -> infinite recursion
2.5 spawn_subagent Is the Core
Code location: s06_subagent/code.py:207
def spawn_subagent(description: str) -> str:
print("[Subagent spawned]")
messages = [{"role": "user", "content": description}]
The most critical line is this one:
messages = [{"role": "user", "content": description}]
What it creates is the sub-agent’s own local messages, not the main Agent’s history.
So:
Main Agent messages: the user's original task + the main flow history
Sub-agent messages: the subtask description + the sub-agent's internal process
That is context isolation.
2.6 The Sub-agent Runs Its Own loop
Code location: s06_subagent/code.py:212
for _ in range(30):
response = client.messages.create(
model=MODEL,
system=SUB_SYSTEM,
messages=messages,
tools=SUB_TOOLS,
max_tokens=8000,
)
The sub-agent essentially has a miniature agent loop as well:
call the LLM
-> if tool_use
-> execute SUB_HANDLERS
-> put the tool_result back into the sub messages
-> continue
for _ in range(30) is a safety cap that prevents the sub-agent from looping forever.
2.7 Return Only the Summary, Not the Process
Code location: s06_subagent/code.py:249
return result
In the end the main Agent gets only a string:
the sub-agent's final summary
It will not receive the detailed process of the sub-agent’s 10 file reads and 5 bash calls.
But note:
The sub-agent's messages do not enter the main Agent.
The sub-agent's real side effects are kept.
For example, if the sub-agent wrote a file, that file really does exist.
2.8 The s06 Review Mnemonic
task is the entry point
spawn_subagent is the execution
fresh messages are the isolation
SUB_TOOLS without task prevents recursion
return summary reduces context
3. s07: Skill Loading, Knowledge Loaded On Demand
File: s07_skill_loading/code.py
3.1 The Problem s07 Solves
An Agent needs domain knowledge, for example:
code review conventions
PDF processing workflow
how to write an MCP server
agent architecture guide
Stuffing all of it into SYSTEM up front wastes tokens and makes the context noisy.
The s07 design has two layers:
Layer one: the skill catalog stays resident in the system prompt
Layer two: the full SKILL.md is loaded on demand via load_skill
3.2 The skills/ Directory
Code location: s07_skill_loading/code.py:47
SKILLS_DIR = WORKDIR / "skills"
The skill file structure in the project:
skills/
agent-builder/SKILL.md
code-review/SKILL.md
mcp-builder/SKILL.md
pdf/SKILL.md
Each SKILL.md has frontmatter at the top:
---
name: code-review
description: Perform thorough code reviews...
---
3.3 _parse_frontmatter Parses the Short Information
Code location: s07_skill_loading/code.py:53
def _parse_frontmatter(text: str) -> tuple[dict, str]:
if not text.startswith("---"):
return {}, text
parts = text.split("---", 2)
meta = yaml.safe_load(parts[1]) or {}
return meta, parts[2].strip()
It extracts from the top of SKILL.md:
name
description
At this step nothing has been given to the LLM yet; it is just parsing inside Python.
3.4 _scan_skills Builds the Registry
Code location: s07_skill_loading/code.py:69
def _scan_skills():
...
raw = manifest.read_text()
meta, body = _parse_frontmatter(raw)
name = meta.get("name", d.name)
desc = meta.get("description", ...)
SKILL_REGISTRY[name] = {"name": name, "description": desc, "content": raw}
SKILL_REGISTRY is a skill database in Python memory.
It looks roughly like this:
{
"code-review": {
"name": "code-review",
"description": "Perform thorough code reviews...",
"content": "the full SKILL.md content"
}
}
Note: the LLM cannot read Python variables directly. They must be turned into text and sent to it via system / messages / tool_result.
3.5 list_skills Generates a Lightweight Catalog
Code location: s07_skill_loading/code.py:86
def list_skills() -> str:
if not SKILL_REGISTRY:
return "(no skills found)"
return "\n".join(f"- **{s['name']}**: {s['description']}" for s in SKILL_REGISTRY.values())
This step turns the Python dictionary into a plain text menu:
- **agent-builder**: Design and build AI agents...
- **code-review**: Perform thorough code reviews...
- **mcp-builder**: Build MCP servers...
- **pdf**: Process PDF files...
Humans can read this text, and so can the LLM.
3.6 build_system Sends the Catalog to the LLM
Code location: s07_skill_loading/code.py:93
def build_system() -> str:
catalog = list_skills()
return (
f"You are a coding agent at {WORKDIR}. "
f"Skills available:\n{catalog}\n"
"Use load_skill to get full details when needed."
)
It is finally sent to the LLM through:
client.messages.create(..., system=SYSTEM, ...)
The full chain:
SKILL.md file
-> _parse_frontmatter()
-> _scan_skills()
-> SKILL_REGISTRY
-> list_skills()
-> build_system()
-> client.messages.create(system=SYSTEM)
-> LLM
3.7 load_skill Loads the Full Content
Code location: s07_skill_loading/code.py:269
def load_skill(name: str) -> str:
skill = SKILL_REGISTRY.get(name)
if not skill:
return f"Skill not found: {name}"
return skill["content"]
After seeing the catalog, if the model decides it needs a certain skill, it can call:
load_skill({"name": "code-review"})
Python returns the full SKILL.md, which enters messages as a tool_result.
3.8 The s07 Review Mnemonic
skill files live in skills/
frontmatter yields name/description
SKILL_REGISTRY lives in Python memory
list_skills turns it into a text menu
build_system sends the catalog
load_skill sends the full text
4. s08: Context Compact, Context Compaction
File: s08_context_compact/code.py
4.1 The Problem s08 Solves
messages keeps growing:
user prompt
assistant tool_use
user tool_result
assistant tool_use
user tool_result
...
Reading files, running commands, and loading skills all add context.
Without compaction, the API will eventually report:
prompt_too_long
too many tokens
The s08 principle:
Run the cheap compaction first, the expensive compaction last.
4.2 Three Constants
Code location: s08_context_compact/code.py:265
CONTEXT_LIMIT = 50000
KEEP_RECENT = 3
PERSIST_THRESHOLD = 30000
Meanings:
CONTEXT_LIMIT: exceeding this estimated size triggers LLM summarization
KEEP_RECENT: the most recent 3 tool_results are kept in full
PERSIST_THRESHOLD: a single large output longer than this is written to disk
The teaching version estimates size with len(str(messages)), which is not a real token count.
4.3 snip_compact: Trimming the Middle Messages
Code location: s08_context_compact/code.py:295
def snip_compact(messages, max_messages=50):
if len(messages) <= max_messages:
return messages
keep_head, keep_tail = 3, max_messages - 3
...
return messages[:head_end] + [{"role": "user", "content": f"[snipped {snipped} messages]"}] + messages[tail_start:]
What it does:
keep the first few messages
keep the most recent few dozen
replace the old messages in the middle with a placeholder
Why can’t you cut arbitrarily?
Because assistant(tool_use) and user(tool_result) form a pair, and you cannot leave half a pair behind.
4.4 micro_compact: Placeholders for Old Tool Results
Code location: s08_context_compact/code.py:322
def micro_compact(messages):
tool_results = collect_tool_results(messages)
if len(tool_results) <= KEEP_RECENT:
return messages
for _, _, block in tool_results[:-KEEP_RECENT]:
if len(block.get("content", "")) > 120:
block["content"] = "[Earlier tool result compacted. Re-run if needed.]"
return messages
What it does:
the most recent 3 tool_results are kept in full
older long tool_results are replaced with a one-line placeholder
This is lossy compaction. The old content is gone, but the model can re-read the file or re-run the command.
4.5 tool_result_budget: Persisting Large Output to Disk
Code location: s08_context_compact/code.py:332
def persist_large_output(tool_use_id, output):
if len(output) <= PERSIST_THRESHOLD:
return output
TOOL_RESULTS_DIR.mkdir(parents=True, exist_ok=True)
path = TOOL_RESULTS_DIR / f"{tool_use_id}.txt"
if not path.exists():
path.write_text(output)
return f"<persisted-output>\nFull output: {path}\nPreview:\n{output[:2000]}\n</persisted-output>"
What it does:
the complete large output is written to disk
messages keeps only the path + a preview
This is more robust than throwing it away, because the full content is still at:
.task_outputs/tool-results/<tool_use_id>.txt
4.6 compact_history: LLM Summarization
Code location: s08_context_compact/code.py:375
def compact_history(messages):
transcript_path = write_transcript(messages)
print(f"[transcript saved: {transcript_path}]")
summary = summarize_history(messages)
return [{"role": "user", "content": f"[Compacted]\n\n{summary}"}]
What it does:
write the full history to a transcript
have the LLM summarize the current goal, key findings, changed files, remaining work, and user constraints
replace the old messages with a single summary
This is the most expensive layer, because it requires an extra LLM call.
4.7 reactive_compact: Emergency Compaction
Code location: s08_context_compact/code.py:383
def reactive_compact(messages):
...
return [{"role": "user", "content": f"[Reactive compact]\n\n{summary}"}, *messages[tail_start:]]
If the API still reports prompt_too_long when the request is made, it compacts as an emergency measure and retries once.
4.8 Wiring Compaction into agent_loop
Code location: s08_context_compact/code.py:454
def agent_loop(messages: list):
while True:
messages[:] = tool_result_budget(messages)
messages[:] = snip_compact(messages)
messages[:] = micro_compact(messages)
if estimate_size(messages) > CONTEXT_LIMIT:
messages[:] = compact_history(messages)
response = client.messages.create(...)
Note the actual execution order:
tool_result_budget -> snip_compact -> micro_compact -> compact_history
Although the explanation calls them L1/L2/L3/L4, at execution time the large output is persisted first, so that the full content is not lost when placeholders are later inserted.
4.9 The compact Tool
Code location: s08_context_compact/code.py:416
{"name": "compact", "description": "Summarize earlier conversation to free context space."}
The model can call compact on its own initiative to trigger compact_history().
4.10 The s08 Review Mnemonic
messages get longer the further you run
persist large output to disk first
trim the old messages in the middle
put placeholders in for old tool_results
if it is still too big, summarize with the LLM
if the API errors, reactive compact
5. s09: Memory, Long-Term Memory
File: s09_memory/code.py
5.1 The Problem s09 Solves
s08’s compaction lets the session continue, but compaction is lossy.
Important information may be summarized too coarsely, or simply lost in a new session.
For example, the user says:
From now on, please explain code in Chinese and give more examples.
This should not stay only in the current messages; it should be preserved long term.
The s09 approach:
write important information to the .memory/ file system
use MEMORY.md as the index
load relevant memories at the start of every turn
extract new memories at the end of every turn
merge and tidy up once there are too many memories
5.2 The Memory Directory
Code location: s09_memory/code.py:42
MEMORY_DIR = WORKDIR / ".memory"
MEMORY_INDEX = MEMORY_DIR / "MEMORY.md"
The directory structure:
.memory/
MEMORY.md
user-prefers-chinese.md
project-facts.md
feedback-style.md
5.3 Four Kinds of Memory
Code location: s09_memory/code.py:56
MEMORY_TYPES = ["user", "feedback", "project", "reference"]
Meanings:
user: who the user is, user preferences
feedback: the user's feedback on how the Agent does things
project: project facts
reference: external leads or reference locations
5.4 write_memory_file: Writing a Single Memory
Code location: s09_memory/code.py:72
def write_memory_file(name: str, mem_type: str, description: str, body: str):
slug = name.lower().replace(" ", "-").replace("/", "-")
filename = f"{slug}.md"
filepath = MEMORY_DIR / filename
filepath.write_text(
f"---\nname: {name}\ndescription: {description}\ntype: {mem_type}\n---\n\n{body}\n"
)
_rebuild_index()
return filepath
The format of a single memory file:
---
name: user-prefers-chinese
description: User prefers Chinese explanations
type: user
---
User prefers Chinese explanations with concrete examples.
5.5 _rebuild_index: Rebuilding MEMORY.md
Code location: s09_memory/code.py:84
def _rebuild_index():
lines = []
for f in sorted(MEMORY_DIR.glob("*.md")):
if f.name == "MEMORY.md":
continue
...
lines.append(f"- [{name}]({f.name}) — {desc}")
MEMORY_INDEX.write_text(...)
MEMORY.md is a memory catalog, not the full text:
- [user-prefers-chinese](user-prefers-chinese.md) — User prefers Chinese explanations
5.6 build_system: Putting the Index into SYSTEM
Code location: s09_memory/code.py:337
def build_system() -> str:
index = read_memory_index()
memories_section = f"\n\nMemories available:\n{index}" if index else ""
return (
f"You are a coding agent at {WORKDIR}."
f"{memories_section}\n"
"Relevant memories are injected below. Respect user preferences from memory.\n"
"When the user says 'remember' or expresses a clear preference, extract it as a memory."
)
This is very similar to s07:
s07: the skill catalog goes into SYSTEM
s09: the memory index goes into SYSTEM
The index stays resident; the full text is loaded on demand.
5.7 select_relevant_memories: Choosing Relevant Memories
Code location: s09_memory/code.py:132
def select_relevant_memories(messages: list, max_items: int = 5) -> list[str]:
It will:
read the name/description of every memory file
collect the recent user messages
have the LLM pick the relevant items from the memory catalog
fall back to keyword matching on failure
pick at most 5 items
5.8 load_memories: Reading the Full Text of Relevant Memories
Code location: s09_memory/code.py:207
def load_memories(messages: list) -> str:
selected_files = select_relevant_memories(messages)
...
parts = ["<relevant_memories>"]
for filename in selected_files:
content = read_memory_file(filename)
if content:
parts.append(content)
parts.append("</relevant_memories>")
It returns:
<relevant_memories>
...full text of the relevant memories...
</relevant_memories>
5.9 Injecting Memory into the Current Request
Code location: s09_memory/code.py:583
memories_content = load_memories(messages)
memory_turn = len(messages) - 1 if messages and isinstance(messages[-1].get("content"), str) else None
system = build_system()
Code location: s09_memory/code.py:606
request_messages = messages
if memories_content and memory_turn is not None and memory_turn < len(messages):
request_messages = messages.copy()
request_messages[memory_turn] = {
**messages[memory_turn],
"content": memories_content + "\n\n" + messages[memory_turn]["content"],
}
Note that it does not modify the original messages directly; it constructs request_messages and sends that to the LLM.
What the LLM actually sees:
<relevant_memories>
...
</relevant_memories>
the user's current question
5.10 extract_memories: Extracting New Memories at the End of Each Turn
Code location: s09_memory/code.py:222
def extract_memories(messages: list):
It extracts from the recent conversation:
user preferences
user constraints
project facts
user feedback
and asks the LLM to return JSON:
[
{
"name": "user-prefers-chinese",
"type": "user",
"description": "User prefers Chinese explanations",
"body": "User prefers Chinese explanations with examples."
}
]
It then calls write_memory_file() to write to disk.
5.11 pre_compress: A Snapshot Before Compaction
Code location: s09_memory/code.py:592
pre_compress = [...]
Why save a pre-compaction version?
Because s08 may have compacted the details away.
When extracting memories, you need to see a more complete original conversation.
Note:
pre_compress temporarily occupies Python RAM
it is not long-term storage
it is not the main LLM context
it is released once the function returns
5.12 consolidate_memories: Tidying Up Memories
Code location: s09_memory/code.py:287
def consolidate_memories():
files = list_memory_files()
if len(files) < CONSOLIDATE_THRESHOLD:
return
Once there are 10 memory files, it has the LLM:
merge duplicates
delete stale entries
resolve contradictions
keep important preferences
5.13 The s09 Review Mnemonic
messages are short-term memory
.memory is long-term memory
MEMORY.md is the index
relevant memories are injected on demand
new memories are extracted at the end of each turn
when there are too many, consolidate
6. s10: System Prompt, Assembled at Runtime
File: s10_system_prompt/code.py
6.1 The Problem s10 Solves
The earlier chapters keep adding content to the system prompt:
identity
tools
working directory
skill catalog
memory index
permission notes
context rules
If you keep using a single hardcoded SYSTEM string, it becomes harder and harder to maintain.
The s10 approach:
split the system prompt into sections
concatenate them on demand based on the current real context
if the context has not changed, use the cache
6.2 PROMPT_SECTIONS: Defining the Available Fragments
Code location: s10_system_prompt/code.py:42
PROMPT_SECTIONS = {
"identity": "You are a coding agent. Act, don't explain.",
"tools": "Available tools: bash, read_file, write_file.",
"workspace": f"Working directory: {WORKDIR}",
"memory": "Relevant memories are injected below when available.",
}
This splits one whole block of system prompt into multiple topics.
6.3 assemble_system_prompt: Concatenating by context
Code location: s10_system_prompt/code.py:50
def assemble_system_prompt(context: dict) -> str:
sections = []
sections.append(PROMPT_SECTIONS["identity"])
sections.append(PROMPT_SECTIONS["tools"])
sections.append(PROMPT_SECTIONS["workspace"])
memories = context.get("memories", "")
if memories:
sections.append(f"Relevant memories:\n{memories}")
return "\n\n".join(sections)
Always loaded:
identity
tools
workspace
Conditionally loaded:
memory
If .memory/MEMORY.md does not exist or is empty, the memory section does not make it into the final prompt.
6.4 update_context: Reading the Real State
Code location: s10_system_prompt/code.py:156
def update_context(context: dict, messages: list) -> dict:
memories = ""
if MEMORY_INDEX.exists():
content = MEMORY_INDEX.read_text().strip()
if content:
memories = content
return {
"enabled_tools": list(TOOL_HANDLERS.keys()),
"workspace": str(WORKDIR),
"memories": memories,
}
The context here comes from real state:
which tools are actually registered
what the current working directory is
whether MEMORY.md really exists and has content
It is not guessed from whether keywords appear in the user’s message.
6.5 get_system_prompt: Caching
Code location: s10_system_prompt/code.py:71
def get_system_prompt(context: dict) -> str:
key = json.dumps(context, sort_keys=True, ensure_ascii=False, default=str)
if key == _last_context_key and _last_prompt:
return _last_prompt
_last_context_key = key
_last_prompt = assemble_system_prompt(context)
return _last_prompt
What it does:
context unchanged -> return the previous prompt directly
context changed -> reassemble the prompt
Why use json.dumps?
dict/list cannot be hashed directly
Python hashes are not stable
json.dumps(sort_keys=True) produces a stable string key
Note: this is a local string cache, not an API prompt cache.
6.6 agent_loop Uses a Dynamic system
Code location: s10_system_prompt/code.py:172
def agent_loop(messages: list, context: dict):
system = get_system_prompt(context)
while True:
response = client.messages.create(
model=MODEL,
system=system,
messages=messages,
tools=TOOLS,
max_tokens=8000
)
It used to be:
system=SYSTEM
Now it is:
system=get_system_prompt(context)
Recomputed after tool execution:
Code location: s10_system_prompt/code.py:195
context = update_context(context, messages)
system = get_system_prompt(context)
6.7 The s10 Review Mnemonic
PROMPT_SECTIONS defines the materials
update_context reads the real state
assemble_system_prompt puts them together on demand
get_system_prompt does the caching
client.messages.create sends it to the LLM
7. A Side-by-Side Comparison of s06-s10
| Section | Problem Solved | Core Data Structure | Key Functions | End Effect |
|---|---|---|---|---|
| s06 | The subtask process pollutes the main context | The sub-agent’s local messages[] |
spawn_subagent() |
The main Agent receives only a summary |
| s07 | Too much domain knowledge to stuff into the prompt | SKILL_REGISTRY |
list_skills(), load_skill() |
The skill catalog stays resident, the full text is on demand |
| s08 | messages keeps getting longer |
messages + transcript + tool output files |
snip_compact(), micro_compact(), compact_history() |
Long sessions do not blow the context |
| s09 | compact loses important information | .memory/*.md, MEMORY.md |
extract_memories(), load_memories() |
Preferences and facts are remembered long term |
| s10 | The system prompt gets messier | PROMPT_SECTIONS, context |
assemble_system_prompt(), get_system_prompt() |
The prompt is assembled dynamically |
8. Three Pairs of Easily Confused Concepts
8.1 skill vs memory
skill:
- domain knowledge written in advance by a human
- lives in skills/
- examples: code-review, pdf, mcp-builder
- loaded on demand with load_skill
memory:
- long-term information the Agent accumulates from conversation
- lives in .memory/
- examples: user preferences, project facts, feedback
- extract_memories at the end of each turn
8.2 compact vs memory
compact:
- solves the current messages being too long
- the goal is to reduce context volume
- details may be dropped
memory:
- solves preserving important information long term
- the goal is to remember across compaction and across sessions
- should not be dropped casually
In one sentence:
compact is responsible for forgetting the unimportant.
memory is responsible for remembering the important.
8.3 SYSTEM vs messages vs tool_result
SYSTEM:
- high-priority long-term instructions for the model
- s07 puts the skill catalog here
- s09 puts the memory index here
- s10 assembles it dynamically
messages:
- the current conversation history
- it grows, and it gets compacted
tool_result:
- the result of executing a tool
- returned to the model as the content of a user message
9. Imagining the Five Sections Executing Together
Suppose the user says:
Please review this project, and remember to explain in Chinese from now on.
What might happen:
1. s10 update_context()
assembles the system prompt from tools, workspace, and memory
2. s07 puts the skill catalog into the system prompt
the model sees the code-review skill
3. the model calls load_skill("code-review")
the full review guide enters the tool_result
4. when the task is large, the model calls task
s06 spawn_subagent does the subtask on independent messages
5. there are many file reads and tool outputs
s08 compacts messages before the next LLM call
6. the user says "use Chinese from now on"
s09 runs extract_memories at the end of the turn
and writes .memory/user-prefers-chinese.md
7. at the start of the next conversation
s10/s09 bring the MEMORY.md index and the relevant memories back into the context
That is the complete capability of s06-s10 combined.
10. The Spoken Summary
If someone asks you: what are s06-s10 about?
You can answer like this:
These five sections add context and knowledge management capabilities to the Agent. s06 uses a sub-agent to isolate a complex subtask and returns only the final summary to the main Agent. s07 uses two-level skill loading so the model first sees the skill catalog and only loads the full skill document when needed. s08 compacts messages before every LLM call to keep the context from getting too long. s09 writes user preferences and project facts into
.memory/, forming long-term memory that survives compaction and spans sessions. s10 splits the system prompt into sections and assembles them at runtime according to the current context, avoiding one hardcoded, unmaintainable chunk of prompt.
A shorter version:
The theme of s06-s10 is: protect the context, load knowledge on demand, preserve important information long term, and assemble the system prompt dynamically.
11. Self-Test Questions
Question 1
After the main Agent calls task, the sub-agent internally reads 10 files and runs bash 5 times. Will the main Agent’s messages keep the details of those 15 steps?
Answer: no. The main Agent only receives the final summary returned by spawn_subagent(). But the sub-agent’s real side effects, such as writing files, are kept.
Question 2
Can the model see SKILL_REGISTRY directly?
Answer: no. It is a dictionary in Python memory. It must be converted to plain text by list_skills() and then sent to the model via system=SYSTEM.
Question 3
Why doesn’t s07 stuff all the SKILL.md files into SYSTEM?
Answer: because most tasks do not need all the skills, and the full text would waste tokens and create noise. s07 puts only the catalog in and loads the full text on demand with load_skill.
Question 4
Why does s08 write large tool_results to disk?
Answer: large outputs would blow up the context. Writing to disk preserves the complete content while messages keeps only the path and a preview.
Question 5
Do compact_history() and extract_memories() have the same goal?
Answer: no. compact_history() exists to shorten the current context; extract_memories() exists to preserve important preferences, constraints, and project facts long term.
Question 6
Why does s09 use pre_compress for memory extraction?
Answer: because the compacted messages may already have lost the details. pre_compress is a pre-compaction snapshot that lets memory extraction see more complete information.
Question 7
When .memory/MEMORY.md does not exist, will s10 add the memory section to the system prompt?
Answer: no. update_context() yields memories = "", so the if memories check in assemble_system_prompt() fails.
Question 8
Is s10’s cache the same thing as an API prompt cache?
Answer: no. The teaching version’s get_system_prompt() only avoids repeatedly concatenating strings locally; an API prompt cache is a server-side mechanism for caching prompt tokens.
12. Code Location Index
s06
s06_subagent/code.py:58-SUB_SYSTEMs06_subagent/code.py:182-SUB_TOOLSs06_subagent/code.py:196-SUB_HANDLERSs06_subagent/code.py:201-extract_text()s06_subagent/code.py:207-spawn_subagent()s06_subagent/code.py:210- the sub-agent’s freshmessagess06_subagent/code.py:212- the sub-agent’s 30-round caps06_subagent/code.py:249- returning only the summarys06_subagent/code.py:252-tasktool schemas06_subagent/code.py:257-taskhandler mapping
s07
s07_skill_loading/code.py:47-SKILLS_DIRs07_skill_loading/code.py:53-_parse_frontmatter()s07_skill_loading/code.py:67-SKILL_REGISTRYs07_skill_loading/code.py:69-_scan_skills()s07_skill_loading/code.py:86-list_skills()s07_skill_loading/code.py:93-build_system()s07_skill_loading/code.py:102-SYSTEM = build_system()s07_skill_loading/code.py:269-load_skill()s07_skill_loading/code.py:297-load_skillschemas07_skill_loading/code.py:304-load_skillhandler mapping
s08
s08_context_compact/code.py:265- context constantss08_context_compact/code.py:295-snip_compact()s08_context_compact/code.py:313-collect_tool_results()s08_context_compact/code.py:322-micro_compact()s08_context_compact/code.py:332-persist_large_output()s08_context_compact/code.py:339-tool_result_budget()s08_context_compact/code.py:357-write_transcript()s08_context_compact/code.py:364-summarize_history()s08_context_compact/code.py:375-compact_history()s08_context_compact/code.py:383-reactive_compact()s08_context_compact/code.py:416-compacttool schemas08_context_compact/code.py:454- the compaction insertion point inagent_loop()s08_context_compact/code.py:488- the model calling compact on its own
s09
s09_memory/code.py:42- the.memory/paths09_memory/code.py:56- memory typess09_memory/code.py:72-write_memory_file()s09_memory/code.py:84-_rebuild_index()s09_memory/code.py:98-read_memory_index()s09_memory/code.py:114-list_memory_files()s09_memory/code.py:132-select_relevant_memories()s09_memory/code.py:207-load_memories()s09_memory/code.py:222-extract_memories()s09_memory/code.py:287-consolidate_memories()s09_memory/code.py:337- memory-awarebuild_system()s09_memory/code.py:583- memory loading inagent_loop()s09_memory/code.py:592-pre_compresss09_memory/code.py:606- memory injection into requests09_memory/code.py:627- extract memory after final response
s10
s10_system_prompt/code.py:42-PROMPT_SECTIONSs10_system_prompt/code.py:50-assemble_system_prompt()s10_system_prompt/code.py:67- prompt cache variabless10_system_prompt/code.py:71-get_system_prompt()s10_system_prompt/code.py:156-update_context()s10_system_prompt/code.py:172- dynamic prompt inagent_loop()s10_system_prompt/code.py:195- recomputing context/prompt after a tool rounds10_system_prompt/code.py:204- initialcontext = update_context({}, [])
13. Recommended Review Order
First review pass:
1. Read section 1, the overall storyline
2. Read section 7, the side-by-side comparison
3. Read s06 and s07
4. Read s08 and s09
5. Read s10
6. Do the self-test questions in section 11
Second review pass:
1. Look only at the code index in section 12
2. Jump to the corresponding source lines
3. Say out loud what problem each function solves in the whole Agent harness
Third review pass:
Draw this line yourself:
complex task -> task -> subagent -> summary
domain knowledge -> skill catalog -> load_skill
context too long -> compact pipeline
important information -> extract_memories -> .memory
system prompt -> context -> prompt sections -> SYSTEM
If you can draw it, you have mastered the skeleton of s06-s10.