Welcome back!
In Chapter 2: Dynamic Prompt Construction, we taught the AI how to explain its capabilities. It can now tell the user: "I can save this forever" or "I can only save this for now."
But words are cheap. Now we have to make sure the code actually behaves that way.
In this chapter, we will explore the logic that decides whether a task is written to a permanent file on your hard drive or just kept loosely in the computer's memory (RAM).
To understand Durability, imagine you are in a meeting room.
You write a reminder on the whiteboard: "Order pizza in 20 minutes."
You write a reminder in a physical notebook: "Staff meeting every Monday at 9 AM."
The Use Case:
How does the AI choose? It uses a specific input field called durable.
When we defined our tool in Cron Tool Suite, we included this boolean (true/false) flag in the input rules.
// CronCreateTool.ts
durable: semanticBoolean(z.boolean().optional()).describe(
'true = persist to .claude/scheduled_tasks.json... false = in-memory only'
),
When the AI calls the tool, it explicitly chooses a path:
durable: false -> Memory (Default)durable: true -> Disk (.json file)
Let's look at what happens inside the CronCreateTool when it runs.
In our system, "Teammates" are temporary sub-agents helping you with a specific task. Because they are temporary, they are not allowed to leave permanent marks on your hard drive.
Before we schedule anything, we check who is asking:
// CronCreateTool.ts
async validateInput(input): Promise<ValidationResult> {
// ... other checks ...
// Check if the user is a "Teammate" trying to be durable
if (input.durable && getTeammateContext()) {
return {
result: false,
message: 'durable crons are not supported for teammates',
}
}
return { result: true }
}
Explanation: If a sub-agent tries to set durable: true, we stop them immediately. They can only use the Whiteboard.
Even if the AI wants to be durable, and the user isn't a teammate, we still check one last thing: Is the durability feature actually enabled?
We might have disabled file writing for security reasons or because we are in a restricted environment.
// CronCreateTool.ts - inside call()
async call({ cron, prompt, recurring, durable = false }) {
// Logic: User wants durable AND the system allows durable
const effectiveDurable = durable && isDurableCronEnabled()
// Pass this final decision to the storage system
const id = await addCronTask(
cron,
prompt,
recurring,
effectiveDurable, // <--- The final decision
getTeammateContext()?.agentId,
)
// ...
}
This effectiveDurable variable is the source of truth.
durable is true but the system switch isDurableCronEnabled() is false, the task effectively becomes Session-Only.Here is the decision tree the code follows every time a task is created.
While the low-level file writing code is handled in a utility helper (addCronTask), it's important to know where this data goes.
If effectiveDurable is true, the task is appended to a JSON file located at:
/.claude/scheduled_tasks.json
This file is loaded every time the application starts. This is how the agent "remembers" tasks from last week.
If effectiveDurable is false, the task is pushed into a JavaScript Array variable. When you close the application, that variable is destroyed (garbage collected), and the task vanishes.
Finally, after we save the task, we need to tell the AI (and the user) what actually happened. Remember, we might have "downgraded" their request from Durable to Session-only if the feature was disabled.
We use the effectiveDurable result to generate the success message.
// CronCreateTool.ts
mapToolResultToToolResultBlockParam(output) {
const where = output.durable
? 'Persisted to .claude/scheduled_tasks.json'
: 'Session-only (not written to disk)'
return {
type: 'tool_result',
content: `Scheduled job ${output.id}. ${where}.`
}
}
Why is this important? If the AI thinks it saved a permanent reminder, but the system forced it to be temporary, this message lets the AI correct itself: "I scheduled that, but please note it is currently session-only because persistence is disabled."
In this chapter, we learned:
isDurableCronEnabled) to make the final decision.We have covered the Tools (Chapter 1), the Prompts (Chapter 2), and the Persistence Logic (Chapter 3).
The final piece of the puzzle is the User Interface. How does the user actually see that a tool is running? It's not just text in a consoleβwe can render beautiful UI components.
Next Chapter: Tool UI Rendering
Generated by Code IQ