Home.composeSoul
Java · package io.github.muthuishere:toolnexus · SPEC §7E · agents/Agents.java
public record ComposedSoul(String soul, List<String> found)
public static ComposedSoul composeSoul(Path dir)Reads the bootstrap files it finds in dir — AGENTS.md, SOUL.md, IDENTITY.md, USER.md,
TOOLS.md, HEARTBEAT.md, MEMORY.md, in that order — and concatenates each present one as a
## <filename> section into a single soul string. Absent files are skipped silently; each file is
capped at 2 MB (bytes, not characters) with a truncation notice appended if it overflows. Returns
both the composed string and the list of files that actually contributed.
When to use it
Section titled “When to use it”You are assembling a persona’s system prompt and want the standard bootstrap-folder convention —
identity, voice, tool guidance and memory living as plain Markdown files an agent’s soul is built
from — instead of hand-writing one prompt string. composeSoul is what
Agents.agentFromDir calls internally; call it directly when you
want the composed text for something other than building an Agent — logging it, feeding it into
a different framework, or inspecting found to see which files a directory actually supplies.
Why this and not the alternative
Section titled “Why this and not the alternative”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 io.github.muthuishere.toolnexus.agents.Agents;import java.nio.file.Files;import java.nio.file.Path;
public class Example { public static void main(String[] args) throws Exception { Path dir = Files.createTempDirectory("persona-home"); Files.writeString(dir.resolve("SOUL.md"), "You are Kavi, a terse release-notes writer.");
Agents.ComposedSoul composed = Agents.composeSoul(dir);
if (!composed.found().equals(java.util.List.of("SOUL.md"))) { throw new AssertionError(composed.found()); } if (!composed.soul().startsWith("## SOUL.md\n\nYou are Kavi")) { throw new AssertionError(composed.soul()); }
System.out.println("ok: " + composed.found()); }}2. The realistic case — several files, in bootstrap order, absent ones skipped
Section titled “2. The realistic case — several files, in bootstrap order, absent ones skipped”import io.github.muthuishere.toolnexus.agents.Agents;import java.nio.file.Files;import java.nio.file.Path;import java.util.List;
public class Example { public static void main(String[] args) throws Exception { Path dir = Files.createTempDirectory("persona-home"); // Written out of order on disk — composeSoul still emits them in BOOTSTRAP_ORDER. Files.writeString(dir.resolve("MEMORY.md"), "- shipped v0.11.0 on 2026-07-15"); Files.writeString(dir.resolve("AGENTS.md"), "Answer in one paragraph."); Files.writeString(dir.resolve("USER.md"), "The user is Muthu, prefers terse replies."); // TOOLS.md and HEARTBEAT.md are absent — skipped, not blank sections.
Agents.ComposedSoul composed = Agents.composeSoul(dir);
if (!composed.found().equals(List.of("AGENTS.md", "USER.md", "MEMORY.md"))) { throw new AssertionError("wrong order: " + composed.found()); } int agentsAt = composed.soul().indexOf("## AGENTS.md"); int userAt = composed.soul().indexOf("## USER.md"); int memoryAt = composed.soul().indexOf("## MEMORY.md"); if (!(agentsAt < userAt && userAt < memoryAt)) { throw new AssertionError("sections out of bootstrap order: " + composed.soul()); } if (composed.soul().contains("## TOOLS.md") || composed.soul().contains("## HEARTBEAT.md")) { throw new AssertionError("absent files must not appear as empty sections"); }
System.out.println("ok: " + composed.found()); }}3. The full surface — an empty directory, and the 2 MB truncation cap
Section titled “3. The full surface — an empty directory, and the 2 MB truncation cap”import io.github.muthuishere.toolnexus.agents.Agents;import java.nio.file.Files;import java.nio.file.Path;
public class Example { public static void main(String[] args) throws Exception { // An empty home directory: no bootstrap files present at all. Path empty = Files.createTempDirectory("persona-empty"); Agents.ComposedSoul none = Agents.composeSoul(empty); if (!none.found().isEmpty() || !none.soul().isEmpty()) { throw new AssertionError("expected an empty composition: " + none); }
// A file larger than the 2 MB byte cap is truncated with a notice; the file on disk // is left untouched. Path big = Files.createTempDirectory("persona-big"); String oversized = "x".repeat(2 * 1024 * 1024 + 100); Files.writeString(big.resolve("SOUL.md"), oversized);
Agents.ComposedSoul truncated = Agents.composeSoul(big); if (!truncated.soul().contains("[truncated: exceeds 2 MB bootstrap cap]")) { throw new AssertionError("expected a truncation notice"); } if (Files.readString(big.resolve("SOUL.md")).length() != oversized.length()) { throw new AssertionError("composeSoul must never mutate the file on disk"); }
System.out.println("ok: empty=" + none.found() + " truncated=" + truncated.found()); }}Fields
Section titled “Fields”| Member | Type | What it is |
|---|---|---|
composeSoul(dir) |
ComposedSoul |
Reads present bootstrap files from dir, in BOOTSTRAP_ORDER. |
ComposedSoul.soul |
String |
The concatenated ## <file> sections, \n\n-joined. |
ComposedSoul.found |
List<String> |
Which bootstrap files actually contributed, in order. |
Agents.BOOTSTRAP_ORDER |
List<String> |
AGENTS.md, SOUL.md, IDENTITY.md, USER.md, TOOLS.md, HEARTBEAT.md, MEMORY.md. |
See also
Section titled “See also”Agents.agentFromDir— Point at an agent home directory and get a configured agent back.Agents.memoryTool— The opt-in built-in that lets a persona write durable notes to its own home.agents.Agent— WhatagentFromDirhands you: name, spec, and the six-verb runtime underneath.