Skip to content

Commitments

A commitment is something the agent owes: a reply it promised, a report it files every Friday, a follow-up it said it would make. Meaning Memory stores commitments as their own memory type, so they behave differently from facts:

  • They are written to the store straight away, not queued for consolidation.
  • They appear in the agent’s due list until the agent closes them. They never drop out because they are old or rarely used.
  • Every change (closed, reopened, satisfied, waived) is recorded with who made it and why.

The examples on this page are MCP tool calls, as an agent makes them. They assume the setup from the Quickstart.

Set memory_type to commitment, give it a status, and give it a due date:

mm_remember({
"source": "agent",
"text": "Send Dana at Acme the updated pricing sheet.",
"memory_type": "commitment",
"commitment_status": "pending",
"due_at": "2026-11-07"
})
**Remembered** — `c9f737d32b583106`

Keep the returned id; the closing tools take it as memory_id. A pending or acknowledged commitment must have a due_at; without one the write is refused. To record a promise that has no date yet, use pending_unscheduled.

Status Meaning
pending Open, with a due date. The default.
acknowledged Open, and the agent has confirmed it to the other party.
pending_unscheduled Open, but no due date yet.
completed Done. Closed.
failed The deadline passed without the work being done. Closed.
cancelled No longer owed: the work was deliberately dropped. Closed.
mm_due_commitments({})
## Commitments (due / overdue)
📅 Scheduled
- Post the weekly support summary in #support. — due 2026-10-23 · 63b62433c5c5a4f8
- Send Dana at Acme the updated pricing sheet. — due 2026-11-07 · c9f737d32b583106

Overdue commitments come first, then those due soon, then scheduled ones, then unscheduled ones. Each line ends with the commitment’s id. To have the same section in the agent’s compiled memory file, set MM_COMMITMENT_COMPILE=true on the consolidation command; it is off by default. Either way, mm_due_commitments is the live view, so call it at the start of each cycle to catch anything that came due since.

mm_close_commitment({
"memory_id": "c9f737d32b583106",
"status": "completed",
"reason": "Sheet sent Nov 3."
})
**Closed** commitment `c9f737d32b583106`: pending → **completed**.
- **Actor:** support-bot
- **Reason:** Sheet sent Nov 3.
It drops off the Commitments section at the next consolidation.

status is completed (the default), failed or cancelled. Closing twice to the same status changes nothing; moving between closed statuses is refused.

To undo a close, reopen it:

mm_reopen_commitment({
"memory_id": "c9f737d32b583106",
"reason": "Dana asked for a revision."
})
**Reopened** commitment `c9f737d32b583106`: completed → **pending_unscheduled**.
…
Due date cleared (one-shot). There is no reschedule verb; re-create the commitment if it needs a date.

A reopened one-off commitment has no due date. If it needs one, store a new commitment with the new date.

A duty that repeats takes a recurrence rule in iCalendar RRULE form, and a catch-up policy. Give due_at as a full timestamp with its time zone offset, because each occurrence is identified by that exact time:

mm_remember({
"source": "agent",
"text": "Post the weekly support summary in #support.",
"memory_type": "commitment",
"commitment_status": "pending",
"due_at": "2026-10-09T17:00:00-07:00",
"recurrence": "FREQ=WEEKLY;BYDAY=FR",
"catchup_policy": "latest"
})

catchup_policy decides what happens when occurrences were missed. In this release the only value is latest: the schedule moves on to the next occurrence after now.

When the agent does this week’s duty, it marks the occurrence satisfied. expected_due_at is the occurrence it means:

mm_satisfy_commitment({
"memory_id": "63b62433c5c5a4f8",
"expected_due_at": "2026-10-09T17:00:00-07:00",
"reason": "Posted."
})
**Satisfied** occurrence `2026-10-09T17:00:00-07:00` of `63b62433c5c5a4f8`; next due **2026-10-16T17:00:00-07:00**.

To skip an occurrence on purpose, waive it. A waived occurrence is recorded as skipped, never counted as done:

mm_waive_commitment({
"memory_id": "63b62433c5c5a4f8",
"expected_due_at": "2026-10-16T17:00:00-07:00",
"reason": "Office closed."
})
**Waived** occurrence `2026-10-16T17:00:00-07:00` of `63b62433c5c5a4f8`; next due **2026-10-23T17:00:00-07:00**.

Each response gives the next occurrence’s exact time; keep it for the next call. expected_due_at must include a time zone offset, and the same moment in another zone is accepted. Two safety checks make these calls safe to retry:

  • Satisfying the same occurrence twice changes nothing: **No change** — occurrence … was already satisfied (idempotent replay).
  • Naming an occurrence that is not the current one is refused, and the error gives the current one: occurrence_conflict: … expected due_at 2026-10-23T09:00:00-07:00 but the live cursor is 2026-10-23T17:00:00-07:00.

mm_close_commitment refuses a recurring commitment by default, because closing it would silently stop the schedule:

**Error:** Validation failed: recurring_commitment: … recurs (FREQ=WEEKLY;BYDAY=FR); a terminal close to 'completed' would strand the cadence. Use mm_satisfy_commitment (did it this cycle) or mm_waive_commitment (skipping this cycle) to advance the cursor. To genuinely retire the duty, pass force_terminate=True.

When the duty really is over, say so explicitly:

mm_close_commitment({
"memory_id": "63b62433c5c5a4f8",
"status": "cancelled",
"force_terminate": true,
"reason": "Weekly summary replaced by the dashboard."
})

Agents use commitments well when the system prompt says when to. A line like this is enough to start:

When you promise to do something, store it with mm_remember as a commitment with a due_at. At the start of each task, call mm_due_commitments. When you finish a promised task, close it with mm_close_commitment, or for a recurring duty, mm_satisfy_commitment.