Use this skill when the user wants to persist the current conversation into the active agent's daily memory file.
The command name is /savenow.
Scope: OpenClaw + Telegram only. Relies on sessions_list / sessions_history, the runtime MessageThreadId, and Telegram inline keyboards. Vanilla Claude Code, CLI, and web surfaces are not supported by design.
Supported forms:
/savenow — preview only. Extract candidates, compare semantically against today's memory, show markdown diff + Apply/Cancel inline buttons. Writes nothing./savenow apply — write the most recent pending preview (within the 30-minute TTL and from the same session/topic)./savenow cancel — discard the pending preview without writing./savenow auto — extract + compare + write directly. Skip preview and buttons./savenow auto <sessionKey> — auto on an explicit session./savenow list — show same-topic candidate sessions without writing./savenow <sessionKey> — preview against an explicit session.Write only durable, high-value notes to memory/YYYY-MM-DD.md in the current agent workspace.
Do not patch built-in commands. Do not change Telegram settings. Do not write MEMORY.md.
Keep:
Skip:
Inspect the raw command argument first and pick a branch:
ArgBranchWrites?(empty)previewnolistlist (unchanged)noapplyapplyyes, from pendingcancelcancelno, deletes pendingautoauto on resolved sessionyesauto <key>auto on explicit keyyesother tokenexplicit-session previewno
/savenow (and explicit-session preview)#Resolve the target session.
If runtime exposes CommandTargetSessionKey, use it.
If the raw arg is a non-empty value other than list/ apply/ cancel/ auto, treat it as the explicit sessionKey.
Else read the current MessageThreadId from runtime, call sessions_list, filter strictly:
:slash:cron, hook, node kindsIf exactly one clear candidate remains, use it. If multiple, pick the newest non-slash real chat session from the same thread.
If thread is missing, no same-topic candidate exists, or it stays ambiguous, fail closed and ask the user to rerun /savenow <sessionKey>. Do not write.
Read the transcript. Call sessions_history against the resolved target session with includeTools: false, limit: 120..180.
Read today's memory file (new step). Use the Read tool on memory/YYYY-MM-DD.md so the agent can perform semantic comparison. If the file does not exist yet, proceed as if empty.
Extract 0..5 candidate memory entries. Each entry must be specific, reusable, short, self-contained. For each candidate, perform semantic comparison against existing sections in the memory file and assign an action:
"add" — net-new durable note"merge" — substantial overlap with an existing section; adds new bullets to it (set merge_target_title to the exact existing title)"skip" — semantically already covered, or not durable enoughJSON shape (write to temp/savenow-entries.json):
json
[
{
"candidate_index": 0,
"title": "Gateway token mismatch fix",
"bullets": [
"Resolved `unauthorized: gateway token mismatch` by updating `gateway.cmd` and the related env variables.",
"Next time a similar error appears, check token and env alignment first."
],
"action": "add",
"reason": ""
},
{
"candidate_index": 1,
"title": "Telegram inline button rules",
"bullets": ["Inline keyboards use a single-row, 3-button layout."],
"action": "merge",
"merge_target_title": "Telegram UI conventions",
"reason": "New rule belongs to the same existing topic."
}
]
Backward-compat: { "title": "...", "bullets": [...] } without action is treated as "add".
Run the preview script from the workspace root: text
node "{baseDir}/scripts/preview-diff.mjs" \
--entries-file "temp/savenow-entries.json" \
--memory-path "memory/YYYY-MM-DD.md" \
--pending-file "temp/savenow-pending.json" \
--session-key "<resolved sessionKey>" \
--message-thread-id "<MessageThreadId>" \
--ttl-minutes 30
Pipe the script's stdout to the chat as the user-facing reply.
Render a Telegram inline keyboard below the markdown reply, two buttons in a single row:
✅ Apply → callback /savenow apply❌ Cancel → callback /savenow cancelIf the script reports 0 candidates, do not render the keyboard (nothing to apply).
/savenow apply#Read temp/savenow-pending.json. Reject with a one-liner if:
"No pending preview, run /savenow first."expiresAt < now → "Preview expired (X min ago), rerun /savenow."sessionKey or messageThreadId mismatches the current runtime → "Pending preview is from a different topic. Rerun /savenow here."Run the merge script using entriesFile from the pending JSON:
text
node "{baseDir}/scripts/merge-daily-memory.mjs" --entries-file "<pending.entriesFile>"
On success delete temp/savenow-pending.json (and the entries file if you wish to clean up).
Reply briefly (no buttons): text
Saved to memory/2026-05-15.md: Gateway token mismatch fix (+2 bullets to "Telegram UI conventions").
Mini summary: saved gateway auth fix and a Telegram button rule.
Mention added titles, merged titles (with bullet counts), and any fallbackAdded / fallbackSkipped events from the script's JSON output.
/savenow cancel#temp/savenow-pending.json exists, delete it. Also delete temp/savenow-entries.json if it exists.Pending preview cancelled. Nothing written.No pending preview to cancel. (not an error.)/savenow auto [sessionKey]#Run steps 1–4 from the preview branch (resolve session, pull transcript, read today's memory, extract candidates with actions).
Skip the preview script and pending file.
Run the merge script directly: text
node "{baseDir}/scripts/merge-daily-memory.mjs" --entries-file "temp/savenow-entries.json"
Reply with the same "Saved to memory/… + mini summary" format. No buttons.
/savenow list#Call sessions_list and return same-topic candidate sessions only. Do not write.
text
# YYYY-MM-DD
## HH:MM - Short title
- bullet
- bullet
For merges, the script appends new bullets in-place to the matched section and adds a trailing - (merged HH:MM) marker bullet. A second merge into the same section replaces the previous marker rather than stacking.
/savenow never writes — it previews and shows Apply/Cancel buttons.apply or auto.