Skip to main content

Deep agents

A deep agent works on a long task on its own: it writes a plan, reads and writes files, hands parts of the work to sub-agents, and keeps going for many turns. Ailu gives it these abilities with the same governance as any agent: file access follows a policy, and sensitive writes wait for a human.

import { createGraph, InMemoryToolRegistry, model, writeTodosTool, type TodoItem } from "@ailu-ai/graph-sdk";

// The built-in planning tool: the agent keeps its plan as a todo list.
const tools = new InMemoryToolRegistry();
tools.register(writeTodosTool.definition, writeTodosTool.handler);

const app = createGraph({ name: "report-writer" })
.channel("brief", { type: "string", default: "" })
.channel("plan", { type: "json", default: [] as TodoItem[] })
.agentNode("writer", {
model: model.anthropic("claude-sonnet-4-6"),
prompt: { system: "Plan with writeTodos, then write the report to drafts/report.md." },
tools,
todosChannel: "plan", // the plan is saved here after every turn
enableFs: true, // read_file, write_file, ls, glob, grep, edit_file, ... scoped to this run
maxIterations: 20
})
// What the agent may do with files. Paths no rule matches are read-only.
.fsPolicy([
{ glob: "drafts/**", verb: "write" },
{ glob: "published/**", verb: "gate" }, // writing here needs a human approval
{ glob: "secrets/**", verb: "deny" }
])
.compile();

const out = await app.run({ brief: "Summarize Q3 incidents for the board." });
console.log(out.channels.plan); // [{ text, status }, ...]

Plan with todos​

writeTodosTool is a built-in tool: the agent calls it with its whole plan each time it changes ({ text, status } items, status pending, in_progress or completed). With todosChannel, the latest plan is saved in that channel after every turn, so you can show progress, and a resumed run keeps it.

Work with files​

enableFs: true gives the agent file tools: read_file, write_file, edit_file, delete_file, move_file, ls, glob and grep. The files live in a virtual filesystem that belongs to the run: the agent can't reach your disk.

.fsPolicy([...]) sets what the agent may do, path by path. The most specific rule wins, and paths no rule matches are read-only.

VerbEffect
readRead only.
writeRead and write.
gateWrites stop the run for a human approval, pinned to that exact path and content.
denyNo access at all.

To keep the files outside the process, point the engine at a storage service with AILU_FS_BACKEND_URL (and AILU_FS_BACKEND_TOKEN). If that service is unreachable, file operations fail rather than silently falling back.

Delegate​

Give a deep agent sub-agents with taskNode (one isolated helper that reports back) or mapAgents (one helper per item).

Presets​

profile sets sensible defaults in one word. Explicit options always win.

ProfileModel tierBehaviour
"fast"fastShort answers, tight context budget. For high-volume, low-stakes steps.
"frontier-careful"frontierRoomy context, self-review, stops for approval. For high-stakes reasoning.
"governed-deep"balancedShort answers, 12k context budget, self-review, stops for approval, files enabled. The one-line deep agent.

Memory across runs​

memory: { namespace: "customer-42" } lets an agent recall notes from earlier runs in the same namespace, and save new ones.

note

In the open-source SDK, memory lives in the process (it is lost on restart) and recall uses a simple built-in embedder, not a semantic model. Use it for development and demos.

Skills​

Skills are reusable playbooks (instructions, sometimes tools) an agent loads when relevant. You pass the skill records per run, on the catalog runner:

await runCatalogGraph(app.definition, { skills: [/* SkillRecord, ... */] });

and set skills: { namespace, required: ["refund-policy@1"] } on the agent. Skills are not loaded by app.run() yet.

Next​