Building My Second Brain on OpenClaw (Part 10)

Welcome back to another Articles by Victoria, the place where I randomly write things I'm curious about.
Part 10 is about something I did not expect to become a problem. My cron jobs, which had been running reliably for months, started timing out. Not all at once. Not dramatically. Just gradually, like a car that takes longer to start each morning until one day it does not start at all.
The daily Todoist sync, which used to finish in under a minute, started hitting 3-minute timeouts. Then 5-minute timeouts. Then it failed entirely. The fix turned out to be one configuration change, but understanding why that change mattered required digging into how OpenClaw actually manages sessions under the hood.
Here's the parts in case you need to catch up:
- Part 1: Getting Started with OpenClaw
- Part 2: Connecting Telegram and Google Workspace
- Part 3: Daily Automations and Task Management
- Part 4: Advanced Workflows - RAG, LinkedIn, and Content Generation
- Part 5: Security and Monitoring
- Part 6: System Design and Best Practices
- Part 7: Building the Memory Wiki
- Part 8: Personal Automation Systems - Learning, Reflection, and Creative Production
- Part 9: Buffer Integration and Content Repurposing
This post is about what I learned: how sessions grow, why that growth breaks cron jobs, and what a more robust design would look like.
The Symptom: A Job That Used to Work
The daily-todoist-sync job has been running at 3 PM SGT every day since I built it. Its job is simple: fetch my active tasks from Todoist, check which ones have due dates, and create 15-minute reminder cron jobs for any timed events.
Here is what the run history looked like over two weeks:
| Date | Duration | Result |
|---|---|---|
| May 14 | 300s | Timeout ❌ |
| May 13 | 180s | Timeout ❌ |
| May 12 | 73s | Success ✅ |
| May 11 | 47s | Success ✅ |
| May 10 | 146s | Success ✅ |
| May 9 | 155s | Success ✅ |
| May 7 | 120s | Timeout ❌ |
| Apr 30 | 120s | Timeout ❌ |
The pattern is clear. When the job succeeds, it takes 47 to 155 seconds. When it times out, it hits the limit even at 300 seconds. The job is not doing more work on the slow days. The Todoist task list is roughly the same size. Something else is getting slower.
The Root Cause: Session Bloat
The job was originally configured with sessionTarget: "session:agent:main:telegram:group:-1003828113148:topic:314". This means it runs in the main session, the same session that handles my Telegram messages, rather than in an isolated session.
This seemed fine at first. The job needs to create reminder cron jobs, and those reminders deliver to Topic 314. Running in the main session means the job inherits the delivery context automatically.
The problem is that the main session never gets smaller. Every message I send, every tool call the agent makes, every response it generates, all of that gets appended to the session transcript. Over days and weeks, the session accumulates thousands of turns.
When the cron job fires, OpenClaw loads the entire session history into context before executing the job. The agent has to process all of that accumulated conversation, even though none of it is relevant to fetching Todoist tasks. The context window gets consumed by old chat history, leaving less room for the actual work. The model slows down because it is parsing irrelevant conversation. Eventually, the job exceeds the timeout before it can finish.
This is not a bug in the cron scheduler. It is a consequence of how session persistence works when you bind a recurring job to a long-lived session.
How OpenClaw Stores Sessions
To understand why this happens, I had to look at how OpenClaw actually manages session state.
Where State Lives
All session data is owned by the Gateway process. According to the OpenClaw documentation on session management, sessions are stored in two places:
~/.openclaw/agents/<agentId>/sessions/sessions.json— the session registry with lifecycle metadata~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl— the full transcript of every turn in that session
The sessions.json file tracks when the session started, when the last interaction happened, and when it was last updated. The .jsonl transcript file is the one that grows over time. Every message, every tool call, every system event gets appended as a new line.
Session Lifecycle
Sessions do not last forever, but they last longer than you might expect. By default, OpenClaw resets sessions daily at 4:00 AM local time. There is also an optional idle reset that creates a new session after a period of inactivity. But here is the key detail from the docs: heartbeat, cron, exec, and other system-event turns may write session metadata, but those writes do not extend daily or idle reset freshness.
This means a cron job running in the main session does not keep the session alive in a meaningful way, but it also does not prevent the session from growing. The session accumulates history until the daily reset rolls it over.
Session Maintenance and Pruning
OpenClaw has a maintenance system that can prune old sessions. The default mode is warn, which reports what would be cleaned but does not actually clean it. You can set it to enforce for automatic cleanup with pruneAfter and maxEntries limits.
But maintenance preserves durable external conversation pointers, including group sessions and thread-scoped chat sessions. A cron job bound to a group chat session is effectively attached to a durable session that maintenance will not clean up aggressively.
The Four Session Targets for Cron
OpenClaw cron jobs support four execution styles, and the choice of session target determines whether you hit this bloat problem:
| Style | Value | Runs In | Best For |
|---|---|---|---|
| Main session | main |
Next heartbeat turn | Reminders, system events |
| Isolated | isolated |
Dedicated cron:<jobId> session |
Reports, background chores |
| Current session | current |
Bound at creation time | Context-aware recurring work |
| Custom session | session:custom-id |
Persistent named session | Workflows that build on history |
The docs explicitly recommend isolated for reports and background chores. I had configured my job as a custom session bound to the main Telegram group, which behaves like the current style: it inherits all the context from the bound session.
Why This Design Exists
The custom session and current session targets exist for good reasons. If you want a daily standup summary that builds on yesterday's summary, you need a persistent session that remembers what was discussed. If you want a weekly report that references last week's findings, you need history.
The tradeoff is that persistent sessions accumulate state, and that state has costs:
- Context window consumption — every turn in the transcript eats into the model's available context window
- Processing overhead — the model spends tokens parsing irrelevant history before getting to the actual task
- Timeout risk — slower processing means jobs are more likely to hit timeout limits
- Cost inflation — more context means more tokens per request, which means higher API costs
For jobs that do not need historical context, like fetching today's tasks or checking calendar events, isolated sessions are the correct choice. The job gets a clean slate every time.
The Fix: One Configuration Change
The fix for my daily-todoist-sync job was to change sessionTarget from the bound main session to isolated. This gives the job a fresh cron:<jobId> session on every run, with no inherited history.
The timeout remains at 300 seconds, which is more than enough for the actual work. Fetching tasks from Todoist takes a few seconds. Creating reminder cron jobs takes a few more. The job now consistently completes in under 30 seconds.
The job still delivers to Topic 314 because the delivery target is explicitly configured in the job definition. The session target controls where the job runs, not where its output goes. Those are separate concerns, and I had conflated them.
Other Failure Modes I Found
While investigating this, I came across several GitHub issues and Reddit threads describing related cron problems. These are worth knowing about because they show how session management affects reliability in different ways.
The 600-Second Hard Timeout
GitHub issue #27427 describes isolated cron jobs that always log status: "error" at exactly 600 seconds, even when the job actually completed successfully. The orchestrator session continues running, receives all sub-agent results, and delivers the output correctly. But the cron runtime marks it as timed out because a 600-second threshold appears to be hardcoded regardless of timeoutSeconds configuration.
This is a different bug, but it compounds the session bloat problem. If your job is already slow because of bloated context, and then it gets killed at 600 seconds even if it would have finished, you have two problems stacked on top of each other.
Provider Timeouts in Isolated Sessions
GitHub issue #49597 describes OpenRouter provider timeouts that only happen in cron isolated sessions. The same model works fine in direct chat and manual subagent spawns, but consistently times out at ~125 seconds when run from cron with sessionTarget: "isolated".
The workaround is to use a local model for cron jobs, but the underlying issue suggests that isolated sessions may have different network or authentication behavior than main sessions.
Silent Failures on Telegram
A Reddit thread from February 2026 describes cron jobs that execute successfully in logs but never send Telegram messages. The fix involves ensuring the session is isolated and explicitly defining the delivery target in the payload.
All of these issues share a common theme: cron job reliability depends heavily on session configuration, and the interaction between session targets, timeouts, and provider behavior is not always intuitive.
Designing a More Robust System
Based on what I learned, here is how I would design a more robust cron session system if I were building it from scratch.
Principle 1: Default to Isolated
The default session target for new cron jobs should be isolated, not main or current. Most cron jobs do not need historical context. They need to run a task and deliver output. Defaulting to isolated would prevent the most common cause of session bloat failures.
If a user explicitly wants a persistent session for a workflow that builds on history, they should opt into it with session:custom-id. That opt-in should come with a warning about the accumulation tradeoff.
Principle 2: Context Budgets, Not Just Timeouts
Timeouts are necessary but insufficient. A job should also have a context budget: a maximum number of tokens or transcript turns that the session can consume before the job starts. If the session exceeds that budget, the job should either fail fast with a clear error or automatically switch to a clean session.
This would have caught my Todoist sync problem before it started timing out. The job would have failed with "session context exceeds budget" instead of mysteriously slowing down over weeks.
Principle 3: Session Health Metrics
The cron runtime should track and expose session health metrics:
- Session transcript size before job start
- Context window utilization percentage
- Average processing time per turn
- Historical trend of job duration
With these metrics, I could have seen that my job was getting slower because the session was growing, not because the Todoist API was slower.
Principle 4: Automatic Session Rotation for Custom Sessions
For jobs that genuinely need persistent sessions, the system should support automatic rotation. Instead of one session that grows forever, the job could maintain a sliding window of recent history. Old turns get summarized or pruned, and the session stays bounded.
OpenClaw already has session compaction and pruning features, but they are manual or time-based. A context-aware compaction that triggers when a session-bound cron job is about to run would be more useful.
Principle 5: Clearer Error Messages
When a cron job times out, the error message should include session context. Instead of just "timeout at 300s", it should say "timeout at 300s after processing 4,200 transcript turns (12,800 tokens of context)". This would immediately point users toward the session bloat diagnosis.
Principle 6: Pre-Flight Checks
Before executing a cron job, the scheduler should run a pre-flight check:
- Is the session target valid?
- If bound to an existing session, how large is its transcript?
- Does the estimated context fit within the job's timeout budget?
- If not, warn or automatically switch to isolated.
This would be a small amount of overhead that prevents a large class of failures.
What I Changed in My Setup
Beyond fixing the daily-todoist-sync job, I audited all my other cron jobs:
- Daily Event Scan (
daily-calendar-sync): Already usingisolated✅ - ragTech Collab Evaluator (
ragtech-collab-eval): Already usingisolated✅ - Daily 9 AM Japanese Lesson: Already using
isolated✅ - Daily 9 PM Workout Prompt: Already using
isolated✅ - Daily 10 PM Mood Summary: Already using
isolated✅ - Weekly Review (Sunday 8 PM): Already using
isolated✅
The Todoist sync was the only job bound to the main session. I had set it up that way because I thought it needed the delivery context, but I now understand that delivery targets are independent of session targets.
I also added a note to my cron job creation checklist: always start with sessionTarget: "isolated", and only use a custom session if the job explicitly needs to reference previous runs.
Sources and References
- OpenClaw Documentation: Session Management — https://docs.openclaw.ai/concepts/session
- OpenClaw Documentation: Scheduled Tasks (Cron Jobs) — https://docs.openclaw.ai/automation/cron-jobs
- GitHub Issue #27427: Isolated cron job timeout at 600s — https://github.com/openclaw/openclaw/issues/27427
- GitHub Issue #49597: OpenRouter provider timeout in cron isolated sessions — https://github.com/openclaw/openclaw/issues/49597
- Reddit r/AI_Agents: Cron jobs silent failures fix — https://www.reddit.com/r/AI_Agents/comments/1qv8hl0/
Conclusion: Prevention is better than cure

Psyduck representing the universal feeling after a successful debugging session
The lesson here is that state accumulates whether you think about it or not. A session that works fine today will be slower next week and broken next month if it keeps growing. The fix is usually simple once you understand the mechanism, but the mechanism is not obvious from the outside.
OpenClaw's session system is powerful. Custom sessions enable workflows that build on history, which is genuinely useful for things like weekly reviews or adaptive learning systems. But that power comes with a cost: sessions grow, context windows shrink, and jobs that used to work quietly start failing.
The robust design is to default to isolation, measure what matters, and let users opt into persistence with full knowledge of the tradeoff.
Thanks for reading! I am curious to know your own personal thoughts and experiences on this topic! Feel free to connect, send me an email (my inbox is always open) or let me know in the comments! Cheers!






