Commitments
A commitment is a durable record of a future obligation: a promise you
made ("I'll review the PR Thursday"), a user request to follow up
("let me know how the deploy goes"), or an open loop worth revisiting
("circle back on the auth migration once #108 lands"). The store is
append-only JSONL at <home>/.mimir/commitments.jsonl; the agent
sees active records in the per-turn ## Upcoming commitments prompt
block.
What you see turn-to-turn
The ## Upcoming commitments block lists active records scoped to
the current channel (plus unbound commitments — those visible
everywhere). Each line:
- [c-abc123def0] in 3d Review PR #142 by Thursday — for @alice
- [c-2f4a8e1234] (next sprint) Audit logging coverage in dispatcher (unbound)
- [c-77ee0011aa] [care] today Check in with bob after the outage — snoozed×2
Components:
[c-...]— the commitment id you pass to the lifecycle tools.- Due phrase —
in Nd/today/overdue Ndwhen there's an explicit time anchor, or(natural-language hint)when the extractor saw a phrase like "Thursday" / "once #108 merges" but no concrete date.(no anchor)means no time info at all. - Text — the natural-language description (capped at ~120 chars at write time).
— for @name— the recipient, if any. The commitment is for that person; mention them when you act on it.(unbound)— the commitment isn't tied to a single channel. Surfaces everywhere; act on it wherever it makes sense.[care]/[personal]— sensitivity prefix. CARE = wellbeing follow-ups (someone's hard week, health item). PERSONAL = mundane individual asks. Tone the response accordingly.— snoozed×N— you've already punted this N times. ≥3 fires an algedonic pileup alarm. If you see ≥2, ask yourself whether to actually do it, dismiss it, or rescope.
The block is capped at 8 entries; if a …and N more footer appears,
use commitment_list to see the rest.
When to act
Resolve a commitment when:
- You followed through →
commitment_complete. The promised thing happened. If you just delivered the answer in this turn, passmessage_idso the completion links to the reply that fulfilled it. - It's no longer relevant →
commitment_dismisswith a shortreason. Cancelled, resolved by someone else, context expired. Distinct from complete: dismissed means "didn't need doing," completed means "I did it." - You can't do it yet but it still matters →
commitment_snooze. Passfor_days(relative —7for a week, fractional OK) oruntil_unix(absolute). Include areasonso future-you can read the audit trail.
If a commitment shows up but you don't recognize it, that's a signal
to check the Recent session summaries block or commitment_list
for context before acting. Don't blindly dismiss — the extractor may
have caught something real you've forgotten.
When NOT to act
- Mid-conversation context — if the operator is still actively asking about something, don't immediately mark the original commitment complete just because you mentioned it. Wait until the thread settles. The block surfaces the same record each turn; one more turn of patience won't lose anything.
- Repeated snoozing without progress — if you see your own
snoozed×2count climbing on the same record, you're avoiding it. Either commit to a date and do it, or dismiss it with a reason ("blocked indefinitely on X" or "the operator deprioritized this in turn Y"). Pileup alarms (≥3 snoozes) are a signal that you are the problem, not the commitment. - Synthetic ticks — heartbeat / poller-tick turns don't see the
commitments block on purpose. The block is suppressed on
scheduler:*andpoller:*channels because acting on a stranger's commitment from a heartbeat context produces weird routing. Don't go fishing for commitments to resolve in a heartbeat.
Tool reference
commitment_complete
{"id": "c-abc123def0", "message_id": "<optional>"}
Terminal — completed commitments can't be re-opened. Pass message_id
when the just-sent reply fulfilled the promise so the link is
auditable.
commitment_snooze
{"id": "c-abc123def0", "for_days": 7, "reason": "blocked on review"}
OR
{"id": "c-abc123def0", "until_unix": 1714521600, "reason": "after launch"}
Exactly one of for_days / until_unix. The snooze count
auto-increments — chronic punting is visible.
commitment_dismiss
{"id": "c-abc123def0", "reason": "operator cancelled in turn ..."}
Terminal. Reason is optional but please include one so the audit log explains why a record left the surface.
commitment_list
{"channel_id": "<optional>", "status": "<optional>"}
Returns JSON. Defaults to active records (pending + delivered + snoozed) across all channels when both args are omitted. Use when:
- The prompt block's
…and N morefooter is hiding records. - You want to see snoozed/delivered records the operator is asking about.
- You want a channel-scoped view (pass
channel_id).
Algedonic signals
The Phase 2b poller emits three event kinds you may see in the
Recent feedback signals block:
commitment_due(positive) — a time-anchored commitment is inside its window. Act now if you haven't already.commitment_expired(negative) —due_window_endpassed without resolution. The record is terminal-expired. This is a miss; understand why before extracting similar ones again.commitment_snooze_pileup(negative) — a record crossed the snooze threshold (default 3). Either act or dismiss; further snoozing without action is the problem the signal is flagging.
The block dedupes these to first-occurrence-only within the 24h algedonic window, so you'll see each kind once per record per day.
Operator parallels
The operator has the same surface via mimir commitments {list,add,complete,snooze,dismiss,trim}. If you complete a record
the operator is also tracking, no coordination needed — the JSONL is
the single source of truth; the operator's CLI replays the same
events. Manual operator entries (no extraction prompt version)
appear in the prompt block the same as extracted ones.