Skip to main content
YAML frontmatter specs for routines, reminders, webhooks, and skills, plus JSON/JSONL schemas for all state files. All persistent data in ollim-bot lives under ~/.ollim-bot/ as flat files. There are two families of formats: markdown files with YAML frontmatter (routines, reminders, webhooks, skills) and JSON/JSONL files (sessions, pending updates, inquiries, ping budget). The data directory is a git repository — most writes are auto-committed.

Markdown files (YAML frontmatter)

Routines, reminders, and webhooks share a common file structure: YAML frontmatter delimited by ---, followed by a markdown body. Fields that match their default value are omitted from the YAML when serialized.

Routines

Stored in ~/.ollim-bot/routines/*.md. Filenames are auto-generated slugs based on the message body.
FieldTypeDefaultDescription
idstrauto-generated8-character hex UUID (uuid4().hex[:8])
cronstrCron expression (5-field standard format)
descriptionstr""Human-readable description
backgroundboolfalseRun as background fork
modelstr | nullnullModel override ("opus", "sonnet", "haiku")
thinkingbooltrueEnable extended thinking
isolatedboolfalseRun in isolated session (no conversation history)
update-main-sessionstr"on_ping"When to report: always, on_ping, freely, blocked
allow-pingbooltrueAllow ping_user and discord_embed tools
allowed-toolslist[str] | nullnullAdditional tools merged with default background tools
skillslist[str] | nullnullSkill names to load at fire time (e.g., [ux-principles, async-principles])
subagentstr | nullnullSubagent to delegate the core task to at fire time
The markdown body after the closing --- becomes the routine’s task message.
routines/nightly-sleep-review.md
---
id: "eb56e06b"
cron: "0 22 * * *"
description: "10 PM daily -- read sleep data"
background: true
---
Review tonight's sleep data and prepare a brief summary.
Check the sleep tracker for any anomalies.
Every background fork always receives the default tools — help, tasks CLI, and read-only file tools (Read, Glob, Grep scoped to ./**.md). Discord tools are controlled separately by allow-ping and update-main-session. When allowed-tools is set, your tools are merged in on top of these defaults. See Tool restrictions for details.

Reminders

Stored in ~/.ollim-bot/reminders/*.md. Same slug-based filenames as routines.
FieldTypeDefaultDescription
idstrauto-generated8-character hex UUID
run-atstrISO 8601 datetime with timezone (e.g., 2026-02-24T15:30:00-08:00)
descriptionstr""Human-readable description
backgroundbooltrueRun as background fork
chain-depthint0Current position in a follow-up chain (0 = root)
max-chainint0Maximum chain depth (0 = no chaining)
chain-parentstr | nullnullID of chain root (auto-set to own id when max-chain > 0)
modelstr | nullnullModel override
thinkingbooltrueEnable extended thinking
isolatedboolfalseRun in isolated session
update-main-sessionstr"on_ping"When to report: always, on_ping, freely, blocked
allow-pingbooltrueAllow ping_user and discord_embed tools
allowed-toolslist[str] | nullnullAdditional tools merged with default background tools
skillslist[str] | nullnullSkill names to load at fire time (e.g., [ux-principles, async-principles])
subagentstr | nullnullSubagent to delegate the core task to at fire time
reminders/pick-up-groceries.md
---
id: "a1b2c3d4"
run-at: "2026-02-24T18:30:00-08:00"
---
Pick up groceries on the way home.
Chained reminder example:
reminders/follow-up-on-project.md
---
id: "f5e6d7c8"
run-at: "2026-02-24T20:00:00-08:00"
max-chain: 2
chain-parent: "f5e6d7c8"
description: "Project follow-up"
---
Follow up on project timeline. Check if deadlines have been updated.

Webhooks

Stored in ~/.ollim-bot/webhooks/*.md. Same slug-based filenames.
FieldTypeDefaultDescription
idstrWebhook identifier (used in endpoint URL: POST /hook/{id})
fieldsdictJSON Schema (Draft 7) defining the expected payload
isolatedboolfalseRun in isolated session
modelstr | nullnullModel override
thinkingbooltrueEnable extended thinking
allow-pingbooltrueAllow notification tools
update-main-sessionstr"on_ping"When to report: always, on_ping, freely, blocked
allowed-toolslist[str] | nullnullAdditional tools merged with default background tools
skillslist[str] | nullnullSkill names to load at fire time
subagentstr | nullnullSubagent to delegate the core task to at fire time
The markdown body is a template — {field_name} placeholders are replaced with payload values at dispatch time.
webhooks/ci-for-repo-status.md
---
id: "ci"
isolated: true
model: "haiku"
fields:
  type: object
  required:
    - repo
    - status
  properties:
    repo:
      type: string
      maxLength: 200
    status:
      type: string
      enum: [success, failure]
  additionalProperties: false
---
CI for {repo}: {status}. Review the build logs and take any necessary action.
String properties in the fields schema that lack an explicit maxLength automatically get a default limit of 500 characters. The total payload size is capped at 10 KB, with a maximum of 20 properties.

Skills

Stored in ~/.ollim-bot/skills/<name>/SKILL.md. Each skill is a directory containing a single SKILL.md file.
FieldTypeDefaultDescription
namestrSkill name (lowercase with hyphens, matches directory name)
descriptionstrWhat the skill does and when to use it
allowed-toolslist[str] | nullnullTool dependencies merged into the host job’s allowed tools
The markdown body contains the skill’s instructions. It can include dynamic context markers using the !`command` syntax — shell commands expanded to their output at load time.
skills/ux-principles/SKILL.md
---
name: "ux-principles"
description: "User-facing design principles for notifications, proactive outreach, and bot responses"
---
When designing user-facing features, follow these principles:

1. Surface errors clearly — the user should never wonder what happened.
2. Prefer report_updates over pinging when the information isn't time-sensitive.
Dynamic context markers (!`command`) have a 10-second per-command timeout and a 30-second total cap. Each command’s output is truncated to 2000 characters. See Dynamic context injection for the full expansion rules.

Tool policy (tool-policy.yaml)

Stored at ~/.ollim-bot/tool-policy.yaml. An optional YAML file that lets you extend or override the default tool sets without editing source code.
KeyTypeDescription
main_session.additional_allowedlist[str]Extra tool patterns merged into the main session’s allowed_tools
bg_forks.additional_allowedlist[str]Extra tool patterns merged into the default background fork tools
bg_forks.overridelist[str]Completely replaces the default background fork tools (takes precedence over additional_allowed)
The file is loaded with mtime-based caching — changes take effect without a restart.
tool-policy.yaml
main_session:
  additional_allowed:
    - "Bash(git status)"
bg_forks:
  additional_allowed:
    - "Bash(ollim-bot cal *)"
If bg_forks.override is set, it completely replaces the default background tools — use with care. The additional_allowed key is safer for most use cases.

Shared markdown conventions

These rules apply to routines, reminders, and webhooks. Skills use a directory-based structure (skills/<name>/SKILL.md) instead of slug-generated filenames, but share the same atomic write and git conventions.
BehaviorDetails
Slug generationLowercase, replace non-alphanumeric characters with -, max 50 characters, strip trailing -
Collision handlingSame id overwrites the file; different id appends -2, -3, etc.
Atomic writesWrites are atomic — partial writes never corrupt files
Default omissionOnly non-default fields appear in YAML frontmatter
String serializationDouble-quoted: key: "value"
Boolean serializationLowercase: key: true
List serializationYAML block format with quoted string items
ParsingUnknown YAML keys are silently skipped (forward-compatible)
Git integrationEach write auto-commits with a message like "add routine eb56e06b"

JSON and JSONL files

Session history (session_history.jsonl)

Append-only JSONL log of session lifecycle events.
FieldTypeDescription
session_idstrSession identifier
eventstrEvent type (see below)
timestampstrISO datetime in the configured timezone
parent_session_idstr | nullParent session for forks and compactions
Event types:
EventDescription
createdNew session created
compactedSession ID changed due to context compaction
swappedFork promoted to main session
clearedSession cleared via /clear
interactive_forkInteractive fork created
bg_forkBackground fork created
isolated_bgIsolated background fork created
restartingBot is restarting (recorded before exit)
session_history.jsonl
{"session_id": "sess_abc", "event": "created",
  "timestamp": "2026-02-24T14:30:45-08:00", "parent_session_id": null}
{"session_id": "sess_def", "event": "bg_fork",
  "timestamp": "2026-02-24T15:00:00-08:00", "parent_session_id": "sess_abc"}

Current session (sessions.json)

Plain text file containing the current session ID. Despite the .json extension, it is not JSON — it contains only the raw session ID string.

Fork messages (fork_messages.json)

JSON array tracking Discord messages associated with active forks.
FieldTypeDescription
message_idintDiscord message ID
fork_session_idstrSession ID of the fork
parent_session_idstr | nullParent session ID
tsfloatUnix timestamp (for TTL enforcement)
Records expire after 7 days (604,800 seconds). Expired entries are filtered out on read.

Pending updates (pending_updates.json)

JSON array of updates written by background forks for the main session.
FieldTypeDescription
tsstrISO datetime string
messagestrSummary text from the report_updates tool
Main sessions pop (read + clear) pending updates on the next interaction. Interactive forks peek (read-only). Writes are protected by a lock to prevent concurrent corruption.

Inquiries (inquiries.json)

JSON object mapping 8-character hex UUIDs to button inquiry entries. Persists inquiry prompts so agent-created buttons survive bot restarts.
FieldTypeDescription
promptstrThe prompt text sent to the agent when the button is clicked
tsfloatUnix timestamp (for TTL enforcement)
Records expire after 7 days. Expired entries are filtered out on read.
inquiries.json
{
  "a3f8b2c1": {"prompt": "The user clicked 'Mark as done'. Complete the task.", "ts": 1740441045.12},
  "d4e9f0a2": {"prompt": "The user wants more details about this item.", "ts": 1740441060.45}
}

Ping budget (ping_budget.json)

JSON object tracking the refill-on-read ping budget for background forks.
FieldTypeDefaultDescription
capacityint5Maximum available pings
availablefloat5.0Current available pings (fractional during refill)
refill_rate_minutesint90Minutes per ping refill
last_refillstrISO datetime of last refill calculation
critical_usedint0Critical pings used today (bypasses budget)
critical_reset_datestrISO date for critical counter reset
daily_usedint0Total pings used today
daily_used_resetstrISO date for daily counter reset
Ping budget is not git-committed — it is ephemeral state that resets to defaults if the file is deleted.

Runtime configuration (config.json)

JSON object storing persistent settings you configure via the /config slash command.
KeyTypeDefaultDescription
model_mainstr | nullnullDefault model for the main session
model_forkstr | nullnullDefault model for interactive forks
thinking_mainstr"off"Extended thinking mode for the main session ("off", "adaptive", or a budget integer as string)
thinking_forkstr"adaptive"Extended thinking mode for interactive forks ("off", "adaptive", or a budget integer as string)
bg_fork_timeoutint1800Max background fork runtime (seconds)
fork_idle_timeoutint10Interactive fork idle timeout (minutes)
permission_modestr"dontAsk"Default permission mode
auto_updateboolfalseAuto-pull, upgrade tool install, and restart on new commits
auto_update_intervalint60Update check interval (minutes)
auto_update_hourint6Hour of day (0-23) to apply updates
config.json
{
  "model_main": "sonnet",
  "thinking_fork": "32000",
  "fork_idle_timeout": 15
}
Only non-default values are stored. Missing keys use their defaults.
The JSON keys use underscores (model_main), while the /config slash command displays them with dots (model.main). The command translates between the two formats automatically.

Next steps

Data directory

Full layout of the ~/.ollim-bot/ directory structure.

Configuration reference

Environment variables and configuration options.

Routines

How to create and manage recurring routines.

Webhooks

External triggers and webhook spec files.