Files
nanobot-runtime/skills/compact-memory/SKILL.md
2026-08-27 14:18:51 +02:00

142 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: compact-memory
description: >
Audit and compact memory/MEMORY.md by removing superseded, duplicated, overly detailed,
or ephemeral entries, and merging related items within a subsection.
Runs interactively when the user asks; nightly mode is driven by a script.
---
# compact-memory
Compact `memory/MEMORY.md` when it grows too large or stale. The skill reads `memory/MEMORY.md` plus `USER.md`, `SOUL.md`, and `keep.md` (all three in the workspace root) to detect duplicates and outdated context, but only ever changes `memory/MEMORY.md`.
## When to use
- User says "compact memory", "clean up MEMORY.md", "memory audit", or similar.
- `MEMORY.md` exceeds ~250 lines.
- There are obvious duplicates between `MEMORY.md` and other memory files.
- Old project notes, ephemeral debugging details, or superseded facts accumulate.
The line threshold is only a proactive trigger. When the user invokes the skill explicitly, run the full audit regardless of line count.
## Modes
### Interactive mode (default)
You perform every step yourself with your file tools. There is nothing to `exec` or spawn.
1. Read `memory/MEMORY.md`, and — for duplicate detection — also `USER.md`, `SOUL.md`, and `keep.md` (all three in the workspace root).
2. Count total lines (`wc -l memory/MEMORY.md`). If the skill was **not** invoked explicitly by the user, the file is ≤ 250 lines, and there is no obvious staleness, report "nothing to clean up" and stop. When invoked explicitly, always continue to the audit.
3. **Audit the WHOLE file in a single pass.** Walk every `##` section and every `###` subsection in order, top to bottom, and evaluate every bullet. Do not stop after the first few findings — the proposal in step 5 must cover the entire file at once. Re-running the skill should find nothing left, not "the next batch".
4. Identify candidates:
- **superseded** — replaced by newer facts, completed work, or no longer relevant.
- **detail** — concrete commands, flags, paths, measurements, or **code references** (e.g. `telegram.py:384`, script paths, DB paths) that belong in a skill, in code, or in a `results/` file.
- **duplicate** — same fact already present in `USER.md`, `SOUL.md`, or `keep.md`.
- **ephemeral** — one-off debugging, temporary state, resolved incidents, or transient build/run progress (counts, task-failure notes, in-flight status).
- **stale section** — an entire `##`/`###` section whose contents are all superseded or ephemeral (e.g. a finished project, a one-off task log, transient system state). Propose removing the whole block at once, not bullet by bullet.
5. Identify merge candidates within the same `###` subsection — related bullets that can be combined into one concise bullet.
6. Present a single numbered proposal in chat that covers the entire file:
- list each delete with reason and original text (use `[stale section]` and cite the heading for whole-section removals);
- list each merge with merged text.
- Kept items are not listed.
7. Wait for user approval. Accept commands like:
- `apply` / `ok` / `yes` — apply all proposed changes.
- `keep 3, 7, 12` — keep listed items, apply the rest.
- `delete 2, 5` — delete only listed items.
- `cancel` — abort.
8. Apply approved changes to `memory/MEMORY.md`.
9. Append deleted items to `log/memory-clean.log` with timestamp `YYYY-MM-DD HH:MM`, one line per item, via `exec` shell append so existing lines cannot be lost:
`printf '%s\n' '<YYYY-MM-DD HH:MM> DELETED [<category>] "<text>" — <reason>' >> log/memory-clean.log`
10. Report summary.
### Nightly mode (script-driven)
Triggered only by `scripts/compact_memory_auto.py` from the crontab. Never start this mode from a chat message — the change-set you produce here is applied by the script, and outside that script nothing would apply it. A user asking for an unattended-style cleanup in chat gets interactive mode.
**You change nothing in this mode.** Do not edit `memory/MEMORY.md`, do not write a backup, do not touch `log/memory-clean.log`. The script applies the change-set, writes the backup and the log, and composes the message the user receives. Your prose is never delivered.
1. Run the same audit as interactive mode steps 15.
2. Answer with **exactly one ```json code block and nothing else** — no narration, no summary, no text before or after it.
3. Nothing qualifies → a block with an empty `changes` list.
4. If the script replies that the validator rejected your change-set, fix exactly what it lists and answer again with one corrected block and nothing else.
When in doubt, keep the item — no user is there to prune, and there is no way to mention what you kept.
## Output format
### Interactive proposal
```
Found X candidates to change in MEMORY.md:
Delete:
1. [superseded] <text>
2. [detail] <text>
3. [stale section] ## <heading> (N bullets) — <reason>
...
Merge:
5 + 6: <merged text>
...
Commands: apply | keep <numbers> | delete <numbers> | cancel
```
### Nightly change-set
```json
{
"changes": [
{
"op": "delete",
"category": "ephemeral",
"original": ["- Debug run 2026-07-25: output-format test in progress"],
"reason": "one-off debug marker, task finished"
},
{
"op": "merge",
"original": [
"- Runs as a systemd user service `nanobot.service`",
"- Model switching via `my` tool requires `tools.my.allow_set = true`"
],
"new_text": ["- Runs as a systemd user service `nanobot.service`; model switching via `my` needs `tools.my.allow_set = true`"],
"reason": "same subsection, one topic"
}
]
}
```
Nothing to change:
```json
{
"changes": []
}
```
Field rules — the validator rejects the whole change-set if any of these is violated:
- `op``"delete"` or `"merge"`. No other fields than the ones shown above are allowed.
- `category``delete` only, one of `superseded`, `detail`, `duplicate`, `ephemeral`, `stale-section`.
- `original` — list of whole lines copied **character-for-character** from `MEMORY.md`, in file order, max 20 lines. The block must appear in the file exactly once, so include enough surrounding lines to make it unique.
- `new_text``merge` only, list of lines replacing `original`. Max 3 lines, max 300 characters, and always fewer lines than `original`.
- `reason` — max 120 characters, **in English**, one clause saying why. It is shown to the user verbatim.
- Blocks of different items must not overlap, and the change-set must not remove more than half of the file.
## Rules
- Only ever change `memory/MEMORY.md` — and in nightly mode not even that; the script does it.
- Do not touch `SOUL.md`, `USER.md`, or `keep.md`.
- In interactive mode do not create backups of `MEMORY.md`; rely on `log/memory-clean.log` for traceability.
- `log/memory-clean.log` is append-only: write new lines with `>>` via `exec`, never with `write_file`/`edit_file`. Never delete, reformat, or "clean up" existing lines — not even ones that do not match the current format.
- Write to `log/memory-clean.log` only when something was deleted or merged — never a "no changes" entry.
- Merge only within the same `###` subsection (never across `##` sections or across different `###` subsections).
- Preserve active project context, user preferences, and durable infrastructure facts.
- Be exhaustive: propose every qualifying candidate in one pass, not a handful. In interactive mode the user prunes via `keep`/`delete`, so propose generously and flag borderline items rather than silently keeping them.
## Example
User: `compact memory`
Agent: reads files, counts lines, proposes changes, waits for `apply`.