savenow
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.
Goal
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.
What counts as durable
Keep:
- resolved root causes and fixes
- stable workflow rules and conventions
- preferences and routing rules
- important system mappings, ids, and file locations
- decisions that will matter again later
Skip:
- chit-chat and acknowledgements
- temporary plans or one-off status updates
- repetitive back-and-forth with no lasting value
- content already saved today in the same or very similar form
Routing
Inspect the raw command argument first and pick a branch:
| Arg |
Branch |
Writes? |
| (empty) |
preview |
no |
list |
list (unchanged) |
no |
apply |
apply |
yes, from pending |
cancel |
cancel |
no, deletes pending |
auto |
auto on resolved session |
yes |
auto <key> |
auto on explicit key |
yes |
| other token |
explicit-session preview |
no |
Preview branch — /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:
- same topic/thread only
- exclude keys containing
:slash:
- exclude
cron, hook, node kinds
- exclude command-only or internal helper sessions
- If 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 enough
JSON shape (write to temp/savenow-entries.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:
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 cancel
If the script reports 0 candidates, do not render the keyboard (nothing to apply).
Apply branch — /savenow apply
Read temp/savenow-pending.json. Reject with a one-liner if:
- file is missing →
"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:
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):
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.
Cancel branch — /savenow cancel
- If
temp/savenow-pending.json exists, delete it. Also delete temp/savenow-entries.json if it exists.
- Reply:
Pending preview cancelled. Nothing written.
- If there was no pending file, reply:
No pending preview to cancel. (not an error.)
Auto branch — /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:
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.
List branch — /savenow list
Call sessions_list and return same-topic candidate sessions only. Do not write.
Memory file format
# 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.
Important constraints
- Default
/savenow never writes — it previews and shows Apply/Cancel buttons.
- Only auto-resolve within the current topic/thread. If unresolvable, fail closed.
- Do not fall back to a global "most recent session" guess.
- Let the merge script handle same-day dedup, in-place merges, and file creation.
- Do not manually append markdown yourself unless the script is unavailable.
- Always include the mini summary line after a successful
apply or auto.
- Inline buttons only on the preview branch and only when the script reports ≥1 candidate.
1---2name: savenow3description: Save durable notes from the current OpenClaw + Telegram conversation into today's memory/YYYY-MM-DD.md, with a semantic-dedupe preview/apply flow and inline Apply/Cancel buttons. Use for /savenow on Telegram-backed sessions.4---56# savenow78Use this skill when the user wants to persist the current conversation into the active agent's daily memory file.910The command name is `/savenow`.1112**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.1314Supported forms:1516- `/savenow` — preview only. Extract candidates, compare semantically against today's memory, show markdown diff + Apply/Cancel inline buttons. **Writes nothing.**17- `/savenow apply` — write the most recent pending preview (within the 30-minute TTL and from the same session/topic).18- `/savenow cancel` — discard the pending preview without writing.19- `/savenow auto` — extract + compare + write directly. Skip preview and buttons.20- `/savenow auto <sessionKey>` — auto on an explicit session.21- `/savenow list` — show same-topic candidate sessions without writing.22- `/savenow <sessionKey>` — preview against an explicit session.2324## Goal2526Write only durable, high-value notes to `memory/YYYY-MM-DD.md` in the current agent workspace.2728Do not patch built-in commands. Do not change Telegram settings. Do not write `MEMORY.md`.2930## What counts as durable3132Keep:3334- resolved root causes and fixes35- stable workflow rules and conventions36- preferences and routing rules37- important system mappings, ids, and file locations38- decisions that will matter again later3940Skip:4142- chit-chat and acknowledgements43- temporary plans or one-off status updates44- repetitive back-and-forth with no lasting value45- content already saved today in the same or very similar form4647## Routing4849Inspect the raw command argument first and pick a branch:5051| Arg | Branch | Writes? |52|-------------------|------------------------|--------------------|53| (empty) | preview | no |54| `list` | list (unchanged) | no |55| `apply` | apply | yes, from pending |56| `cancel` | cancel | no, deletes pending|57| `auto` | auto on resolved session | yes |58| `auto <key>` | auto on explicit key | yes |59| other token | explicit-session preview | no |6061## Preview branch — `/savenow` (and explicit-session preview)62631. **Resolve the target session.**64 - If runtime exposes `CommandTargetSessionKey`, use it.65 - If the raw arg is a non-empty value other than `list`/`apply`/`cancel`/`auto`, treat it as the explicit `sessionKey`.66 - Else read the current `MessageThreadId` from runtime, call `sessions_list`, filter strictly:67 - same topic/thread only68 - exclude keys containing `:slash:`69 - exclude `cron`, `hook`, `node` kinds70 - exclude command-only or internal helper sessions71 - If exactly one clear candidate remains, use it. If multiple, pick the newest non-slash real chat session from the same thread.72 - 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.73742. **Read the transcript.** Call `sessions_history` against the resolved target session with `includeTools: false`, `limit: 120..180`.75763. **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.77784. **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`:7980 - `"add"` — net-new durable note81 - `"merge"` — substantial overlap with an existing section; adds new bullets to it (set `merge_target_title` to the exact existing title)82 - `"skip"` — semantically already covered, or not durable enough8384 JSON shape (write to `temp/savenow-entries.json`):8586 ```json87 [88 {89 "candidate_index": 0,90 "title": "Gateway token mismatch fix",91 "bullets": [92 "Resolved `unauthorized: gateway token mismatch` by updating `gateway.cmd` and the related env variables.",93 "Next time a similar error appears, check token and env alignment first."94 ],95 "action": "add",96 "reason": ""97 },98 {99 "candidate_index": 1,100 "title": "Telegram inline button rules",101 "bullets": ["Inline keyboards use a single-row, 3-button layout."],102 "action": "merge",103 "merge_target_title": "Telegram UI conventions",104 "reason": "New rule belongs to the same existing topic."105 }106 ]107 ```108109 Backward-compat: `{ "title": "...", "bullets": [...] }` without `action` is treated as `"add"`.1101115. **Run the preview script** from the workspace root:112113 ```text114 node "{baseDir}/scripts/preview-diff.mjs" \115 --entries-file "temp/savenow-entries.json" \116 --memory-path "memory/YYYY-MM-DD.md" \117 --pending-file "temp/savenow-pending.json" \118 --session-key "<resolved sessionKey>" \119 --message-thread-id "<MessageThreadId>" \120 --ttl-minutes 30121 ```1221236. **Pipe the script's stdout to the chat as the user-facing reply.**1241257. **Render a Telegram inline keyboard** below the markdown reply, two buttons in a single row:126127 - `✅ Apply` → callback `/savenow apply`128 - `❌ Cancel` → callback `/savenow cancel`129130 If the script reports 0 candidates, do not render the keyboard (nothing to apply).131132## Apply branch — `/savenow apply`1331341. Read `temp/savenow-pending.json`. Reject with a one-liner if:135 - file is missing → `"No pending preview, run /savenow first."`136 - `expiresAt < now` → `"Preview expired (X min ago), rerun /savenow."`137 - `sessionKey` or `messageThreadId` mismatches the current runtime → `"Pending preview is from a different topic. Rerun /savenow here."`1381392. Run the merge script using `entriesFile` from the pending JSON:140141 ```text142 node "{baseDir}/scripts/merge-daily-memory.mjs" --entries-file "<pending.entriesFile>"143 ```1441453. On success delete `temp/savenow-pending.json` (and the entries file if you wish to clean up).1461474. Reply briefly (no buttons):148149 ```text150 Saved to memory/2026-05-15.md: Gateway token mismatch fix (+2 bullets to "Telegram UI conventions").151 Mini summary: saved gateway auth fix and a Telegram button rule.152 ```153154 Mention added titles, merged titles (with bullet counts), and any `fallbackAdded` / `fallbackSkipped` events from the script's JSON output.155156## Cancel branch — `/savenow cancel`1571581. If `temp/savenow-pending.json` exists, delete it. Also delete `temp/savenow-entries.json` if it exists.1592. Reply: `Pending preview cancelled. Nothing written.`1603. If there was no pending file, reply: `No pending preview to cancel.` (not an error.)161162## Auto branch — `/savenow auto [sessionKey]`1631641. Run steps 1–4 from the preview branch (resolve session, pull transcript, read today's memory, extract candidates with actions).1652. Skip the preview script and pending file.1663. Run the merge script directly:167168 ```text169 node "{baseDir}/scripts/merge-daily-memory.mjs" --entries-file "temp/savenow-entries.json"170 ```1711724. Reply with the same "Saved to memory/… + mini summary" format. No buttons.173174## List branch — `/savenow list`175176Call `sessions_list` and return same-topic candidate sessions only. Do not write.177178## Memory file format179180```text181# YYYY-MM-DD182183## HH:MM - Short title184- bullet185- bullet186```187188For 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.189190## Important constraints191192- Default `/savenow` never writes — it previews and shows Apply/Cancel buttons.193- Only auto-resolve within the current topic/thread. If unresolvable, fail closed.194- Do not fall back to a global "most recent session" guess.195- Let the merge script handle same-day dedup, in-place merges, and file creation.196- Do not manually append markdown yourself unless the script is unavailable.197- Always include the mini summary line after a successful `apply` or `auto`.198- Inline buttons only on the preview branch and only when the script reports ≥1 candidate.