Skip to main content
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) 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] | nullnullTool whitelist (mutually exclusive with disallowed_tools)
disallowed_toolslist[str] | nullnullTool blacklist (mutually exclusive with allowed_tools)
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.
Specifying both allowed_tools and disallowed_tools raises a ValueError. Use one or the other.

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
backgroundboolfalseRun 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] | nullnullTool whitelist
disallowed_toolslist[str] | nullnullTool blacklist
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"
background: true
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
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.

Shared markdown conventions

These rules apply to all three markdown file types (routines, reminders, webhooks):
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 writestempfile.mkstemp() + os.replace() (POSIX-atomic)
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
Parsingyaml.safe_load(); unknown 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_idstrAgent SDK session 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 SDK auto-compaction
swappedFork promoted to main session
clearedSession cleared via /clear
interactive_forkInteractive fork created
bg_forkBackground fork created
isolated_bgIsolated background fork created
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 Agent SDK 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 MCP tool
Main sessions pop (read + clear) pending updates on the next interaction. Interactive forks peek (read-only). Writes are protected by an asyncio.Lock().

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.

Next steps