compose_soul
Python · package toolnexus · SPEC §7E · python/src/toolnexus/agents/surface.py
def compose_soul(dir: str) -> tuple[str, list[str]]Reads a persona’s home directory for the fixed BOOTSTRAP_ORDER of bootstrap files
(AGENTS.md, SOUL.md, IDENTITY.md, USER.md, TOOLS.md, HEARTBEAT.md, MEMORY.md),
folds each present file into a ## <filename> section, and returns (soul, found) — the
composed system prompt and the ordered list of files that were actually there. Absent files
are silently skipped; nothing is required.
When to use it
Section titled “When to use it”- You are building a persona’s system prompt from files on disk and want the same
discovery-order, section-naming and truncation rules
agent_from_diruses internally, without going through the fullAgentwrapper. - You want to inspect which bootstrap files a directory actually supplies (
found) — for a diagnostics tool, a “is this persona configured” check, or a docs generator. - You’re composing your own agent surface on top of the §7D runtime and want the §7E
file-to-soul convention without adopting the rest of
Agent/AgentRuntime.
Why this and not the alternative
Section titled “Why this and not the alternative”Composition happens once, at the point you call it — the returned soul is a frozen
snapshot, never re-read mid-session. That is deliberate (SPEC §7E): a long-lived agent’s
system prompt must stay stable within a run so caching (and the model’s sense of its own
identity) doesn’t shift turn to turn. To pick up edits — including ones the memory tool
just wrote to MEMORY.md — call compose_soul again at the start of the next session.
Examples
Section titled “Examples”1. The smallest useful call — one file, one section
Section titled “1. The smallest useful call — one file, one section”import osimport tempfile
from toolnexus.agents import compose_soul
with tempfile.TemporaryDirectory() as home: with open(os.path.join(home, "SOUL.md"), "w", encoding="utf-8") as f: f.write("You are Aster, a calm and precise research assistant.")
soul, found = compose_soul(home)
assert found == ["SOUL.md"] assert soul == "## SOUL.md\n\nYou are Aster, a calm and precise research assistant."
print("ok:", found, "|", len(soul), "chars")2. The realistic case — discovery order wins, absent files are skipped
Section titled “2. The realistic case — discovery order wins, absent files are skipped”Files are folded in BOOTSTRAP_ORDER, not creation order or directory-listing order — write
MEMORY.md before AGENTS.md on disk and the composed soul still puts AGENTS.md first.
IDENTITY.md, USER.md, TOOLS.md, HEARTBEAT.md are simply absent here and contribute
nothing.
import osimport tempfile
from toolnexus.agents import compose_soul
with tempfile.TemporaryDirectory() as home: # Write MEMORY.md first on disk — BOOTSTRAP_ORDER still wins over write order. with open(os.path.join(home, "MEMORY.md"), "w", encoding="utf-8") as f: f.write("- prefers metric units\n- last project: rag_go") with open(os.path.join(home, "AGENTS.md"), "w", encoding="utf-8") as f: f.write("Always cite your sources.") with open(os.path.join(home, "SOUL.md"), "w", encoding="utf-8") as f: f.write("You are Aster.")
soul, found = compose_soul(home)
assert found == ["AGENTS.md", "SOUL.md", "MEMORY.md"] # bootstrap order, not write order assert soul.index("## AGENTS.md") < soul.index("## SOUL.md") < soul.index("## MEMORY.md") assert "prefers metric units" in soul # IDENTITY.md / USER.md / TOOLS.md / HEARTBEAT.md were never written — no sections, no error. assert "## IDENTITY.md" not in soul
print("ok:", found)3. The full surface — the 2 MB byte cap truncates, never errors
Section titled “3. The full surface — the 2 MB byte cap truncates, never errors”Each bootstrap file is read with a hard 2 MB cap measured in bytes. Over the cap, the file is truncated at that byte boundary and a notice is appended — the on-disk file itself is left untouched.
import osimport tempfile
from toolnexus.agents import compose_soul
CAP = 2 * 1024 * 1024 # MAX_BOOTSTRAP_FILE_BYTES
with tempfile.TemporaryDirectory() as home: oversized_path = os.path.join(home, "AGENTS.md") with open(oversized_path, "wb") as f: f.write(b"x" * (CAP + 1024)) # 1 KB over the cap
with open(os.path.join(home, "SOUL.md"), "w", encoding="utf-8") as f: f.write("You are Aster.")
soul, found = compose_soul(home)
assert found == ["AGENTS.md", "SOUL.md"] assert "[truncated: exceeds 2 MB bootstrap cap]" in soul # The on-disk file is untouched — still oversized. assert os.path.getsize(oversized_path) == CAP + 1024
print("ok: truncated at", CAP, "bytes; found", found)compose_soul(dir) fields
Section titled “compose_soul(dir) fields”| Value | Type | What it is |
|---|---|---|
soul |
str |
The composed system prompt: ## <file> sections, in BOOTSTRAP_ORDER, joined with blank lines. |
found |
list[str] |
The bootstrap filenames actually present, in the same order they appear in soul. |
See also
Section titled “See also”agent_from_dir— Point at an agent home directory and get a configured agent back.memory_tool— The opt-in built-in that lets a persona write durable notes to its own home.