Skip to content

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 dirAGENTS.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.

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.

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());
}
}
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.
  • 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 — What agentFromDir hands you: name, spec, and the six-verb runtime underneath.