Workflows
Bosun's daemon runs in the background, executing workflows on a schedule. It summarizes sessions, fills handoffs, generates chronicles, and backs up your workspace — without you thinking about it.
How the daemon works
The daemon starts automatically with just start. It runs a heartbeat every 30 seconds, checking which workflows need to run based on their schedule and input validators.
heartbeat (30s)
│
├── Check schedules (hourly, daily:HH)
│ │
│ └── Has enough time elapsed?
│
├── Run input validators
│ │
│ └── Is there work to do?
│
└── Queue matching workflows
│
└── Execute sequentially, retry on failure
Input validators
Each workflow has a validate-input.ts that checks whether there's work to do. If not, the workflow is skipped — no agent spawned, no resources wasted.
For example, catchup-sessions checks whether any session JSONL files exist that don't have a corresponding summary. If all sessions are summarized, it skips.
Schedules
| Schedule | Meaning |
|---|---|
hourly |
Run once per hour (checks elapsed time) |
daily:02 |
Run once per day at 02:00 |
startup = true |
Also run when the daemon starts |
Built-in workflows
catchup-sessions
Schedule: Hourly + startup
Finds completed Pi session files (.jsonl) that don't have summaries yet. Spawns a lite agent to read the session and write a structured summary:
workspace/users/{user}/sessions/2026-02/2026-02-24-refactor-auth-module.md
Summaries include:
- Title and date
- What was accomplished
- Key decisions
- Files modified
- Reference to the original session file
fill-handoff
Schedule: Hourly + startup
Scans for handoff documents with status: pending. Spawns a lite agent to fill them with session analysis — what was done, what's next, key context for resuming.
chronicle-analyzer
Schedule: Hourly
Groups session summaries into development "journeys" — multi-session arcs that tell the story of a feature or investigation. Writes analysis JSON files that the scribe consumes.
chronicle-scribe
Schedule: Hourly
Reads chronicle analyses and generates readable builder's log narratives in markdown. These are the public-facing output:
workspace/users/{user}/public/chronicles/2026-02/24-daemon-infrastructure-cleanup.md
backup-workspace
Schedule: Daily at 02:00
Creates a compressed backup of the workspace directory.
Daemon commands
Check daemon status from any agent:
// Current status
daemon({ action: "status" })
// Recent logs
daemon({ action: "logs", lines: 20 })
// Manually trigger a workflow
daemon({ action: "trigger", handler: "catchup-sessions" })
// Reload after config changes
daemon({ action: "reload" })
Writing custom workflows
A workflow is a directory with:
packages/your-package/workflows/your-workflow/
├── config.toml # Schedule and settings
├── agent.md # Agent prompt (if agent-based)
├── validate-input.ts # Input validator (optional)
└── validate-output.ts # Output validator (optional)
config.toml
[workflow]
name = "your-workflow"
description = "What this workflow does"
schedule = "hourly" # or "daily:HH"
startup = false # run on daemon start?
[workflow.agent]
model = "lite" # model tier for the agent
validate-input.ts
Returns exit code 0 if there's work to do, non-zero to skip:
import { existsSync } from "node:fs";
const pendingDir = `${process.env.BOSUN_WORKSPACE}/pending`;
if (!existsSync(pendingDir)) {
console.error("No pending work");
process.exit(1);
}
// Check for actual work...
console.log("Found pending items");
process.exit(0);
agent.md
The agent prompt — what the spawned agent should do. Can reference environment variables set by the daemon:
You are a workflow agent. Your task:
1. Scan {{ BOSUN_WORKSPACE }} for pending items
2. Process each one
3. Write output to the expected location
Workflows are discovered automatically from packages listed in package.json's "pi" config.