Skip to content

feat(cross-node-sync): package MEMORY.md regenerator + auto-call after sync (closes #712) - #758

Merged
liususan091219 merged 1 commit into
mainfrom
feat/package-memory-regen
May 16, 2026
Merged

liususan091219 merged 1 commit into
mainfrom
feat/package-memory-regen

Conversation

@liususan091219

Copy link
Copy Markdown
Collaborator

Summary

The skill's setup-rsync-sync.sh has excluded MEMORY.md from the rsync pass since 2026-04-17 (both Studio and MBP hit the truncate-on-mtime-wins regression: 74 files on disk, only 19 linked in MEMORY.md after sync). The comment near the rsync call promised "regenerate locally from file frontmatter after each sync", and the cron-prompt in crons.example.json told operators to "Then regenerate MEMORY.md from frontmatter" — but the regen script lived only in operators' local checkouts (private), never committed.

This PR:

  • Adds skills/cross-node-sync/scripts/regenerate-memory-index.py — walks \$SUTANDO_MEMORY_DIR (or auto-derives from ~/.claude/projects/<slug>/), parses each *.md's YAML frontmatter, emits - [name](file) — description lines sorted alphabetically, truncates each line to ~200 chars per CLAUDE.md. Skips MEMORY.md / INDEX.md / self_identity.md from the index.
  • Hooks the regen into setup-rsync-sync.sh at the tail, after all rsync legs finish but before the "Sync complete" banner. Skipped on --dry-run. If python3 isn't on PATH, prints a friendly note and continues. If the memory dir doesn't exist (first-run / fresh install), the regen exits 0 with a skip message rather than failing the whole sync.

After this lands, operators no longer need to wire a separate cron entry for regen — setup-rsync-sync.sh handles the full sync+regen cycle in one call.

Closes #712.

Test plan

  • regenerate-memory-index.py --dry-run exits 0 with a skip message when the memory dir doesn't exist
  • Default default_memory_dir() correctly derives slug from script's repo root (portable across operators)
  • CLI flags --memory-dir PATH and --dry-run work
  • setup-rsync-sync.sh regen hook only runs in non-dry-run mode
  • setup-rsync-sync.sh regen hook tolerates missing python3 / missing memory dir gracefully
  • @chetanunadkat to verify after his next sync — should see MEMORY.md auto-regen without the separate cron entry

🤖 Generated with Claude Code

…r sync (closes #712)

The skill's setup-rsync-sync.sh has excluded MEMORY.md from the rsync pass
since 2026-04-17 (both Studio and MBP hit the truncate-on-mtime-wins
regression: 74 files on disk, only 19 linked in MEMORY.md after sync). The
comment near the rsync call promised "regenerate locally from file frontmatter
after each sync", and the cron-prompt in crons.example.json told operators to
"Then regenerate MEMORY.md from frontmatter" — but the regen script lived only
in operators' local checkouts (private), never committed.

This PR:

- Adds `skills/cross-node-sync/scripts/regenerate-memory-index.py` — walks
  `$SUTANDO_MEMORY_DIR` (or auto-derives from `~/.claude/projects/<slug>/`),
  parses each `*.md`'s YAML frontmatter, emits `- [name](file) — description`
  lines sorted alphabetically, truncates each line to ~200 chars per CLAUDE.md.
  Skips MEMORY.md / INDEX.md / self_identity.md from the index.

- Hooks the regen into `setup-rsync-sync.sh` at the tail, after all rsync legs
  finish but before the "Sync complete" banner. Skipped on `--dry-run`. If
  python3 isn't on PATH, prints a friendly note and continues. If the memory
  dir doesn't exist (first-run / fresh install), the regen exits 0 with a
  skip message rather than failing the whole sync.

After this lands, operators no longer need to wire a separate cron entry for
regen — `setup-rsync-sync.sh` handles the full sync+regen cycle in one call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@liususan091219
liususan091219 merged commit 685f6da into main May 16, 2026
1 check passed
@liususan091219
liususan091219 deleted the feat/package-memory-regen branch May 16, 2026 09:37
sonichi added a commit that referenced this pull request May 20, 2026
#936)

* fix(schedule-crons): remove cross-node-sync from default cron template

Cross-node-sync requires `SUTANDO_SYNC_PEER` + SSH setup between two physical
nodes, plus assumes per-file-frontmatter is the source of truth for memory
entries. Default new-user installs:
- have no peer (single-host)
- start with inline entries in MEMORY.md (auto-memory init: `# userEmail`,
  `# currentDate`)

#806 added a defensive guard so regen refuses to clobber when 0 frontmatter
entries + non-empty target — but the guard fires only on the *zero-entries*
boundary. Once a user creates one frontmatter file, regen silently drops
remaining inline entries from MEMORY.md.

Per #758 PR test plan, the `dir-exists-but-zero-frontmatter-siblings` case
was never validated end-to-end (the unchecked @chetanunadkat verify item).

Net: make the cron explicit opt-in via the SKILL.md. Single-host users don't
need rsync-over-ssh; multi-host users add it deliberately when they set up
peer auth.

Refs #787 (the clobber bug), #806 (defensive guard, already merged), #758
(the auto-call wiring that introduced this for new users).

* docs(cross-node-sync): rewrite cron-wiring section for opt-in reality

Per Lucy's review on #936: SKILL.md previously said the cron-example wires
cross-node-sync automatically via 'cp crons.example.json crons.json'. After
the #936 removal that's false, so the doc actively misled.

Rewrite the 'Cron wiring' section as a single 'explicit opt-in' block that:
- Explains why it's opt-in (SUTANDO_SYNC_PEER + SSH + per-file-frontmatter
  requirements don't apply to single-host)
- Includes the exact JSON entry operators copy into their crons.json
- Updates the jq verify command (.[] not .jobs[] — crons.json is a top-level
  array, not an object)
liususan091219 added a commit to liususan091219/sutando-fork that referenced this pull request May 28, 2026
…r sync (closes sonichi#712) (sonichi#758)

The skill's setup-rsync-sync.sh has excluded MEMORY.md from the rsync pass
since 2026-04-17 (both Studio and MBP hit the truncate-on-mtime-wins
regression: 74 files on disk, only 19 linked in MEMORY.md after sync). The
comment near the rsync call promised "regenerate locally from file frontmatter
after each sync", and the cron-prompt in crons.example.json told operators to
"Then regenerate MEMORY.md from frontmatter" — but the regen script lived only
in operators' local checkouts (private), never committed.

This PR:

- Adds `skills/cross-node-sync/scripts/regenerate-memory-index.py` — walks
  `$SUTANDO_MEMORY_DIR` (or auto-derives from `~/.claude/projects/<slug>/`),
  parses each `*.md`'s YAML frontmatter, emits `- [name](file) — description`
  lines sorted alphabetically, truncates each line to ~200 chars per CLAUDE.md.
  Skips MEMORY.md / INDEX.md / self_identity.md from the index.

- Hooks the regen into `setup-rsync-sync.sh` at the tail, after all rsync legs
  finish but before the "Sync complete" banner. Skipped on `--dry-run`. If
  python3 isn't on PATH, prints a friendly note and continues. If the memory
  dir doesn't exist (first-run / fresh install), the regen exits 0 with a
  skip message rather than failing the whole sync.

After this lands, operators no longer need to wire a separate cron entry for
regen — `setup-rsync-sync.sh` handles the full sync+regen cycle in one call.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
liususan091219 pushed a commit to liususan091219/sutando-fork that referenced this pull request May 28, 2026
sonichi#936)

* fix(schedule-crons): remove cross-node-sync from default cron template

Cross-node-sync requires `SUTANDO_SYNC_PEER` + SSH setup between two physical
nodes, plus assumes per-file-frontmatter is the source of truth for memory
entries. Default new-user installs:
- have no peer (single-host)
- start with inline entries in MEMORY.md (auto-memory init: `# userEmail`,
  `# currentDate`)

sonichi#806 added a defensive guard so regen refuses to clobber when 0 frontmatter
entries + non-empty target — but the guard fires only on the *zero-entries*
boundary. Once a user creates one frontmatter file, regen silently drops
remaining inline entries from MEMORY.md.

Per sonichi#758 PR test plan, the `dir-exists-but-zero-frontmatter-siblings` case
was never validated end-to-end (the unchecked @chetanunadkat verify item).

Net: make the cron explicit opt-in via the SKILL.md. Single-host users don't
need rsync-over-ssh; multi-host users add it deliberately when they set up
peer auth.

Refs sonichi#787 (the clobber bug), sonichi#806 (defensive guard, already merged), sonichi#758
(the auto-call wiring that introduced this for new users).

* docs(cross-node-sync): rewrite cron-wiring section for opt-in reality

Per Lucy's review on sonichi#936: SKILL.md previously said the cron-example wires
cross-node-sync automatically via 'cp crons.example.json crons.json'. After
the sonichi#936 removal that's false, so the doc actively misled.

Rewrite the 'Cron wiring' section as a single 'explicit opt-in' block that:
- Explains why it's opt-in (SUTANDO_SYNC_PEER + SSH + per-file-frontmatter
  requirements don't apply to single-host)
- Includes the exact JSON entry operators copy into their crons.json
- Updates the jq verify command (.[] not .jobs[] — crons.json is a top-level
  array, not an object)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Package MEMORY.md regenerator referenced in cross-node-sync's prompt and TODO comment

1 participant