Repository navigation
feat(personal-assets): canonical home is private machine-<host> dir - #548
Merged
Merged
Conversation
Each Stand has its own identity + avatar. These files are gitignored and
machine-local; the canonical home moves to
`$SUTANDO_PRIVATE_DIR/machine-<hostname>/<file>` so they live with the rest
of the per-machine memory under the private sync repo. Public-workspace
fallback is preserved so existing installs keep working until they
migrate naturally.
Pieces:
- `src/util_paths.py` — Python helper `personal_path(filename, workspace)`.
Lookup order: private machine dir → public assets/ (avatar only) →
public root. Falls back to preferred private path on miss so the
caller's `.exists()` check fails gracefully.
- `src/voice-agent.ts` + `skills/phone-conversation/scripts/conversation-server.ts`
— TypeScript twin `personalPath(filename)` with the same lookup order.
- Wired callers: `src/agent-api.py` (/avatar, /stand-identity), `src/dashboard.py`
(/avatar, /stand-identity), `src/event_log.py` (_machine_id),
`src/voice-agent.ts` (system-prompt + greeting),
`skills/phone-conversation/scripts/conversation-server.ts` (call instructions).
- `src/migrate.sh` — bundle/restore now uses the correct
`$REPO/assets/stand-avatar.png` source path (was `$REPO/stand-avatar.png`,
silently failing). Restore lands the file under `assets/` so the public
fallback path keeps working alongside the private canonical home.
Companion fix already shipped in private memory-sync repo
(scripts/sync-memory.sh, commit 50e095c): `MACHINE_FILES` entry for
the avatar is now `assets/stand-avatar.png` instead of `stand-avatar.png`,
so the per-machine backup actually copies it. After this PR + that fix,
the Mac's avatar lives in `machine-<host>/` and `personal_path()`
resolves there directly.
Verified end-to-end: `SUTANDO_PRIVATE_DIR=... python3 -c "from util_paths
import personal_path; print(personal_path('stand-avatar.png'))"` returns
the private path post-sync.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 of 6 tasks
sonichi
added a commit
that referenced
this pull request
Apr 30, 2026
) Migration #4 + #5 in the private-repo plan. Notes/ are SHARED across the fleet (top-level private dir); pending-questions.md, PERSONAL_CLAUDE.md, tab-aliases.json are PER-MACHINE (machine-<host>/, like #548). Two resolver families: - `personal_path()` (existing, #548) — per-machine: $SUTANDO_PRIVATE_DIR/machine-<host>/<file> - `shared_personal_path()` (new) — fleet-shared: $SUTANDO_PRIVATE_DIR/<file> New `src/util_paths.ts` is the TS twin of util_paths.py with both helpers exported. voice-agent.ts replaces its inline `personalPath` with imports from the new module. Wired callers: NOTES (shared_personal_path): - src/inline-tools.ts NOTES_DIR → save_note / read_note / list_notes / delete_note - src/voice-agent.ts: meeting-note save (line 285) - src/dashboard.py: /notes/{slug} route + /notes index (lines 48, 437) - src/daily-insight.py: NOTES_DIR - src/friction-detector.py: notes_dir - src/discord-bridge.py: SEND_ALLOWED_ROOTS adds private notes path - src/health-check.py: notes-dir check now points at canonical home PER-MACHINE (personal_path): - src/dashboard.py: get_pending_count - src/agent-api.py: pq_file (2 sites) - src/friction-detector.py: pending-questions.md - src/check-pending-questions.py: PQ_FILE - src/session-handoff.sh: pending-questions.md (via inline python3) PERSONAL_CLAUDE.md and tab-aliases.json: no runtime callers — only referenced in migrate.sh bundle/restore (#548 already covers per-machine shape, so they ride along without extra wiring). Test plan: - [x] `npx tsc --noEmit` clean - [x] All Python files compile (`ast.parse`) - [x] Resolver verified end-to-end with SUTANDO_PRIVATE_DIR set: shared_personal_path('notes') → /Users/wangchi/.sutando-memory-sync/notes personal_path('pending-questions.md') → .../machine-Chis-MacBook-Air/pending-questions.md - [ ] Drop a voice-tool note via save_note, verify it lands in private dir - [ ] Open the note in dashboard, verify /notes/{slug} reads from private dir - [ ] Restart check-pending-questions cron, verify it reads private PQ file After merge: kickstart voice-agent (touches voice-agent.ts + inline-tools.ts), restart web-client/dashboard/agent-api/discord-bridge (Python files), restart conversation-server. Same pattern as #548. 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
…onichi#548) Each Stand has its own identity + avatar. These files are gitignored and machine-local; the canonical home moves to `$SUTANDO_PRIVATE_DIR/machine-<hostname>/<file>` so they live with the rest of the per-machine memory under the private sync repo. Public-workspace fallback is preserved so existing installs keep working until they migrate naturally. Pieces: - `src/util_paths.py` — Python helper `personal_path(filename, workspace)`. Lookup order: private machine dir → public assets/ (avatar only) → public root. Falls back to preferred private path on miss so the caller's `.exists()` check fails gracefully. - `src/voice-agent.ts` + `skills/phone-conversation/scripts/conversation-server.ts` — TypeScript twin `personalPath(filename)` with the same lookup order. - Wired callers: `src/agent-api.py` (/avatar, /stand-identity), `src/dashboard.py` (/avatar, /stand-identity), `src/event_log.py` (_machine_id), `src/voice-agent.ts` (system-prompt + greeting), `skills/phone-conversation/scripts/conversation-server.ts` (call instructions). - `src/migrate.sh` — bundle/restore now uses the correct `$REPO/assets/stand-avatar.png` source path (was `$REPO/stand-avatar.png`, silently failing). Restore lands the file under `assets/` so the public fallback path keeps working alongside the private canonical home. Companion fix already shipped in private memory-sync repo (scripts/sync-memory.sh, commit 50e095c): `MACHINE_FILES` entry for the avatar is now `assets/stand-avatar.png` instead of `stand-avatar.png`, so the per-machine backup actually copies it. After this PR + that fix, the Mac's avatar lives in `machine-<host>/` and `personal_path()` resolves there directly. Verified end-to-end: `SUTANDO_PRIVATE_DIR=... python3 -c "from util_paths import personal_path; print(personal_path('stand-avatar.png'))"` returns the private path post-sync. 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
…onichi#555) Migration sonichi#4 + sonichi#5 in the private-repo plan. Notes/ are SHARED across the fleet (top-level private dir); pending-questions.md, PERSONAL_CLAUDE.md, tab-aliases.json are PER-MACHINE (machine-<host>/, like sonichi#548). Two resolver families: - `personal_path()` (existing, sonichi#548) — per-machine: $SUTANDO_PRIVATE_DIR/machine-<host>/<file> - `shared_personal_path()` (new) — fleet-shared: $SUTANDO_PRIVATE_DIR/<file> New `src/util_paths.ts` is the TS twin of util_paths.py with both helpers exported. voice-agent.ts replaces its inline `personalPath` with imports from the new module. Wired callers: NOTES (shared_personal_path): - src/inline-tools.ts NOTES_DIR → save_note / read_note / list_notes / delete_note - src/voice-agent.ts: meeting-note save (line 285) - src/dashboard.py: /notes/{slug} route + /notes index (lines 48, 437) - src/daily-insight.py: NOTES_DIR - src/friction-detector.py: notes_dir - src/discord-bridge.py: SEND_ALLOWED_ROOTS adds private notes path - src/health-check.py: notes-dir check now points at canonical home PER-MACHINE (personal_path): - src/dashboard.py: get_pending_count - src/agent-api.py: pq_file (2 sites) - src/friction-detector.py: pending-questions.md - src/check-pending-questions.py: PQ_FILE - src/session-handoff.sh: pending-questions.md (via inline python3) PERSONAL_CLAUDE.md and tab-aliases.json: no runtime callers — only referenced in migrate.sh bundle/restore (sonichi#548 already covers per-machine shape, so they ride along without extra wiring). Test plan: - [x] `npx tsc --noEmit` clean - [x] All Python files compile (`ast.parse`) - [x] Resolver verified end-to-end with SUTANDO_PRIVATE_DIR set: shared_personal_path('notes') → /Users/wangchi/.sutando-memory-sync/notes personal_path('pending-questions.md') → .../machine-Chis-MacBook-Air/pending-questions.md - [ ] Drop a voice-tool note via save_note, verify it lands in private dir - [ ] Open the note in dashboard, verify /notes/{slug} reads from private dir - [ ] Restart check-pending-questions cron, verify it reads private PQ file After merge: kickstart voice-agent (touches voice-agent.ts + inline-tools.ts), restart web-client/dashboard/agent-api/discord-bridge (Python files), restart conversation-server. Same pattern as sonichi#548. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Each Stand has its own identity + avatar. These files are gitignored and machine-local. This PR makes the canonical home the per-machine private dir (
$SUTANDO_PRIVATE_DIR/machine-<hostname>/), with public-workspace fallback preserved so existing installs keep working until they migrate naturally.Pieces
src/util_paths.py— Pythonpersonal_path(filename, workspace). Lookup: private machine dir → publicassets/(avatar only) → public root. Returns the preferred private-dir path on miss so callers'.exists()checks fail gracefully.src/voice-agent.ts+skills/phone-conversation/scripts/conversation-server.ts— TypeScript twinpersonalPath(filename), same lookup order.src/agent-api.py(/avatar,/stand-identity),src/dashboard.py(same two endpoints),src/event_log.py(_machine_id), voice-agent.ts (system prompt + greeting), conversation-server.ts (call instructions).src/migrate.sh— bundle/restore now uses the correct$REPO/assets/stand-avatar.pngsource path (was$REPO/stand-avatar.png, silently failing for everyone). Restore lands the file underassets/.Companion fix already in private memory-sync
Commit
50e095cin~/.sutando-memory-sync/scripts/sync-memory.sh:MACHINE_FILESentry for the avatar is nowassets/stand-avatar.pnginstead ofstand-avatar.png(same root cause as the migrate.sh bug — backup was silently skipping the avatar). After this PR + that fix, the avatar lives inmachine-<host>/for real.Test plan
SUTANDO_PRIVATE_DIR=~/.sutando-memory-sync python3 -c "from util_paths import personal_path; print(personal_path('stand-avatar.png'))"returns the private path post-sync.npx tsc --noEmitclean.python3 -m py_compileon all touched Python files clean.SUTANDO_PRIVATE_DIRis unset (fallback path verified by reading the helper).Deferred (follow-ups, not in this PR)
WORKSPACE_ROOTdefault flip — already env-overridable, currently working via the shim copies from yesterday's talk-prep.personal-talk-highlight,personal-voice-context, etc. live private-only). Framework skills (x-twitter,phone-conversation) stay public.🤖 Generated with Claude Code