Repository navigation
feat: rename SUTANDO_PRIVATE_DIR → SUTANDO_MEMORY_DIR (closes #870) - #876
Conversation
liususan091219
left a comment
There was a problem hiding this comment.
Solid rename + deprecation alias pattern. Three notes:
1. Every-read deprecation warning may flood stderr in hot paths. The comment explicitly defends this ("cron environments miss startup-only warnings, so logging at every resolution is intentional"). Fair for cron — cron runs the script once per fire, so every-read is once-per-fire. But for long-running daemons (voice-agent, discord-bridge, telegram-bridge, slack-bridge) that call personalPath() / sharedPersonalPath() repeatedly, this becomes log spam. Suggest a module-level "warned-once-per-process" sentinel: still fires once per cron invocation (which is what cron needs), but doesn't flood the daemon logs. Two extra lines.
2. loadSkillManifestTools() resolves memoryDirEnv() at module-init time (in inline-tools.ts:1037ish) — fine as long as no test mutates process.env.SUTANDO_MEMORY_DIR between agent restarts, which I don't think any does. Just calling out the import-time read so it's a deliberate choice, not an accidental capture.
3. conversation-server.ts keeps its inline personalPath() twin with manually-duplicated deprecation-warn code. PR body acknowledges this is intentional (skill import-surface isolation). When/if hostLabel() logic shifts in #877 follow-ups, both sites need updates — worth a // keep in sync with src/util_paths.ts:hostLabel() comment over the inline twin to make the duplication discoverable.
Docs are thorough (CLAUDE.md / workspace-contract.md / MANIFEST.md all updated, 4 spots touched). 10 Py + 5 TS tests is right-sized for a rename + alias. LGTM net.
vidhuUC
left a comment
There was a problem hiding this comment.
APPROVE. Clean env rename with proper one-release backward compat. All the callsites I spot-checked (CLAUDE.md, workspace-contract.md, MANIFEST.md, conversation-server.ts) consistently use the new name with legacy fallthrough commentary. The pattern SUTANDO_MEMORY_DIR || SUTANDO_PRIVATE_DIR is applied uniformly. CI green.
Per workspace-design RFC #858 (Decision 2), the env var for the Memory space is renamed from `SUTANDO_PRIVATE_DIR` to `SUTANDO_MEMORY_DIR` so the vocabulary matches the 3-space mental model (Code / State / Memory). One-release alias period: - The new name `SUTANDO_MEMORY_DIR` is the canonical lookup. - The old name `SUTANDO_PRIVATE_DIR` continues to work as a fallback. - A deprecation warning fires to stderr on every read of the legacy var (not just at startup — cron / launchd environments would otherwise miss startup-only warnings and silently sit on the legacy name). Resolution helper: - Python: `_memory_dir_env()` in src/util_paths.py. - TypeScript: `memoryDirEnv()` exported from src/util_paths.ts. - Both: prefer the new var, fall back to the legacy one with the warning. Call-site updates: - src/util_paths.py — `_private_machine_dir()` + `shared_personal_path()` route through the helper. - src/util_paths.ts — `personalPath()` + `sharedPersonalPath()` route through the helper. - src/inline-tools.ts — `loadSkillManifestTools()` + `loadCoreDocumentedSkills()` + open_file doc text. - src/voice-agent.ts — voice-context loader. - skills/phone-conversation/scripts/conversation-server.ts — inline `personalPath()` twin. - src/session-handoff.sh — passes both env vars through to the python child. - Docs: CLAUDE.md, docs/workspace-contract.md, skills/MANIFEST.md. Tests: 10 Python + 5 TS unit tests covering precedence, legacy fallback, deprecation warning, and the every-read guard. Zero existing-user breakage: anyone with only `SUTANDO_PRIVATE_DIR` set keeps working through the deprecation window, sees the warning, and can migrate by renaming the env var. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ced1ce6 to
be885fa
Compare
Plan-only document. Owner asked for a release-process + migration-framework
proposal in #dev. Sutando-Mini and I split it: Mini covers when-to-cut + tag
conventions; this doc covers what-goes-in + CHANGELOG culture + migration
framework + joint engine↔product coupling section.
270 lines covering:
1. CHANGELOG culture — 5 categories, author-curated + release-curator-pruned.
2. Migration framework — numbered migrations/NNNN-*.{sh,py},
state/schema-version.json, idempotent startup-runner, 1-release
backward-compat overlap (formalizes the ad-hoc #876 alias pattern),
per-migration tempdir tests, 3-phase rollout.
3. Engine↔product coupling — Option A loose coupling (recommended) vs
Option B lockstep. Engine = sonichi/sutando, Product = Sutando.app.
4. 4 open questions for owner.
Located under docs/ (parallel to docs/workspace-design.md's RFC pattern),
not notes/ (gitignored). Promotion to docs/release-process.md waits on
owner + Chi greenlight and Mini's companion proposal.
No code shipped. Plan only.
…906) * docs: release process proposal (qingyun-sutando half) Plan-only document. Owner asked for a release-process + migration-framework proposal in #dev. Sutando-Mini and I split it: Mini covers when-to-cut + tag conventions; this doc covers what-goes-in + CHANGELOG culture + migration framework + joint engine↔product coupling section. 270 lines covering: 1. CHANGELOG culture — 5 categories, author-curated + release-curator-pruned. 2. Migration framework — numbered migrations/NNNN-*.{sh,py}, state/schema-version.json, idempotent startup-runner, 1-release backward-compat overlap (formalizes the ad-hoc #876 alias pattern), per-migration tempdir tests, 3-phase rollout. 3. Engine↔product coupling — Option A loose coupling (recommended) vs Option B lockstep. Engine = sonichi/sutando, Product = Sutando.app. 4. 4 open questions for owner. Located under docs/ (parallel to docs/workspace-design.md's RFC pattern), not notes/ (gitignored). Promotion to docs/release-process.md waits on owner + Chi greenlight and Mini's companion proposal. No code shipped. Plan only. * docs(rfc #906): add Overview + Motivations sections per owner ask Owner asked in two consecutive Discord messages (task-1779223601794 + task-1779223627953): - "Update the RFC to include motivations" - "Give an overview picture of what we are trying to do, why it matters" Two new sections at the top of the proposal: 1. **Overview** — TL;DR framing. What (release process + migration framework), why it matters (rollback discipline, commercial pinning, silent-breakage prevention, bot coordination, continuous gate), what it does NOT try to do (time-based cadence, backward migrations, data re-encoding, engine-product lockstep), and the co-author split. 2. **Motivations** — 5 numbered motivations (M1-M5): - M1: named snapshots of known-good states - M2: state-format changes happen often, silently breaking users - M3: commercial deploys need a pin point - M4: two bots are coordinating, need a shared spec - M5: release process IS the migration-test framework Plus an explicit **Non-goals** subsection listing what we're deliberately NOT solving here (time cadence, backward migrations, etc.) — anchors scope for future contributors. No content change to Parts 1-2 or the joint section; just preamble that explains why before the design pages dive in. * docs(rfc): add Mini's half — when to cut + tag conventions Half of the consolidated release-process RFC (#906). Covers: - When to cut a release (feature-completion trigger, owner cuts the tag) - SemVer vs CalVer (SemVer; engine-vX.Y.Z prefix) - Tag on main vs release branch (tag on main; no release branch) - Git tag vs GitHub Release (both — tag is anchor, Release is narrative) - What to cut next (aligned with qingyun-sutando: cut v0.1.0 now, framework as v0.1.1) - Explicit coupling table mapping every joint surface to the corresponding section in qingyun-sutando's half Plan-only. No code shipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(rfc #906): remove commercial framing — OSS readers may not be from AG2 Owner asked (task-1779223950387): "Remove the part about 'Commercial pinning'. Remember OSS user may not care about commercial things as they are not necessarily from Ag2 the company." Changes: - Overview "Commercial pinning" bullet → "Pinning for anyone building on top" (forks, downstream consumers, sister-node fleets — generic framing that includes but doesn't assume AG2-commercial users). - M1 dropped "(commercial waitlist, OSS contributors, sister-node fleets)" parenthetical — just "users." - Removed entire M3 "Commercial deploys need a pin point" motivation (was specifically about sutando.ag2.ai install instructions). M4/M5 renumbered to M3/M4. - Joint section's bottom bullet reworded: "Customer who hits a bug correlates ..." → "Anyone running the bundle who hits a bug ... Downstream consumers can pin install instructions to an engine tag." Per memory feedback_internal_vs_public_docs.md — the sonichi/sutando repo is PUBLIC; specific paths and commercial framings belong in INTERNAL (#dev, workspace, owner DM), not in landed docs. * docs(rfc #906): owner-quote line removed; M3 restored as downstream-pin-point (AG2-internal facing too) Owner two follow-ups: 1. task-1779224091789: "Remove wordings like this — Owner (Chi) explicitly said 'Plan and make proposals first.'" — the preamble quote framing owner's instruction directly was leaking internal chatter into a public-repo doc. Replaced with neutral "This is half of a co-drafted proposal" framing. 2. task-1779224131237: "M3. Commercial deploys need a pin point — This is AG2 internal facing as well." — clarified that the doc serves both OSS contributors AND AG2-internal-facing audiences (sutando.ag2.ai, packaged bundles, commercial integrators). Restored as M3, generalized to "Pin points for downstream consumers and bundle deploys" — explicitly enumerates forks, sister-node fleets, Sutando.app, AG2-internal deploys, commercial integrators. M4/M5 renumber accordingly (Two bots coordinating + release-process-is- migration-test). Companion file `docs/release-process-proposal-mini.md` landed in 7d4f260 (Mini's half: when to cut + tag conventions). Both halves now live on this PR's branch. * docs(rfc #906): consolidated doc merging Mini's + qingyun-sutando's halves Claimed the consolidation step in #dev bot-coord. Merges both source files (both preserved on the branch as authorship record) into a single review surface for Chi + Qingyun. Structure: - Top-of-doc overview + motivations + non-goals (combined from both). - Part 1-4 from Mini (when to cut, SemVer + tag namespace, tag-on-main no release branch, git tag + GitHub Release + hard/soft gates). - Part 5-6 from qingyun-sutando (CHANGELOG culture, migration framework with numbered migrations/state/runner/tests/phasing). - Part 7 joint section (engine ↔ product coupling, Option A recommended). - Part 8 "what to cut next" — both halves landed on (c): cut engine-v0.1.0 now with manual migration notes, framework as v0.1.1. - Coupling table verifying no double-coverage between the two halves. - 5 consolidated open questions for owner (was 4 from each half; deduped + added Mini's signed-tags question). - Next move: owner + Chi review, pick answers, then promote to docs/release-process.md + open implementation issues. Source halves stay on the branch: - docs/release-process-proposal-mini.md - docs/release-process-proposal-qingyun-sutando.md If owner greenlights, this consolidated doc moves to docs/release-process.md and the two source files can be archived (or kept as authorship record). No code shipped. Plan only. * docs(rfc #906): integrate review-round resolutions Integrates the 3 reviews on #906: - Bassil (cold-review 2026-05-20 06:28) — 4-question picks aligned with Chi's later owner-pick; reinforces option (c) cut-now-with-manual-notes + framework as next-release primary payload. - Lucy (review 11:31) — 3 implementation questions on the migration framework: multi-core race on schema-version.json, merge-order collision on migration numbers, health-check gate on fresh clone. - Chi (sub-agent draft 19:28 + owner-pick 20:30) — final calls on 3 open questions: bare v0.MINOR.PATCH (drop engine- prefix), working-state when-to-cut (not commit-count), unsigned tags for v0.1.x (signed deferred). Concrete changes in the doc: - Sweep `engine-vX.Y.Z` → bare `vX.Y.Z` everywhere (frontmatter status, body prose, schema-version.json example, alias timeline, coupling section, open-question text). 13 occurrences. - Rewrite "Open questions for owner" as "RESOLVED 2026-05-20" section with each pick + reasoning (§§ 4a/4b for when-to-cut refinement + GPG deferral). - §2.7 — replace cut-gate language with Chi's working-state framing + clarify health-check scope (tagging install, not fresh clone — addresses Lucy Q3). - §2.8 (new) — Concurrency & ordering: resolve Lucy Q1 (migrations run as pre-pool step in startup.sh, single-writer- by-construction; runner also called from resolve_workspace as idempotent fallback for manual sessions) and Q2 (number reserved at merge time, pre-merge CI check fails on collision, mirrors Rails/Alembic). - Add "Future hardening" section gathering deferred items (signed tags, backward migrations, data re-encoding, PR-template migration checklist, docs/install.md fresh-install path, docs/release-process.md promotion). - Rewrite "Next move" to reflect Chi's "mergeable" verdict + the Phase 1 framework PR sequence + cut v0.1.0 + workspace contract A/B as forcing function for migration 0002. - Frontmatter: reviewers_integrated field naming the 3 reviews, status updated to "open questions resolved; pending merge", intro callout quoting Chi's mergeable line. Plan-only doc — no code shipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(rfc): sweep consolidated doc to reflect Chi's 2026-05-20 owner-picks The qingyun-sutando half integrated the review-round decisions, but the consolidated doc — the file that promotes to docs/release-process.md — was never swept and still contradicted them. Chi's stated merge bar was "once the RFC text reflects these, it's mergeable"; this makes it so. - engine-vX.Y.Z → bare vX.Y.Z everywhere (decision 1). - §2.2 rewritten: bare tag namespace, no engine- prefix; the namespace collision the prefix defended against doesn't exist (product ships from its own repo / tag line). - Part 1.1: add the working-state precondition (decision 4a) — CI green, no release-blocker, no half-finished migration; quality gate not count. - "Consolidated open questions" → "Consolidated decisions (resolved)" with all 5 answers recorded inline. - "Next move" + coupling table + frontmatter status updated to reflect that nothing is owner-gated anymore. Proposal files (mini / qingyun) left as the authorship record per the consolidated doc's own header; the mini half still reads `engine-` — flag if it should be swept too. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(rfc): sweep mini proposal half to bare vX.Y.Z (consistency with #906 decisions) Companion to e248cc6 (consolidated-doc sweep). The mini proposal half still recommended the `engine-` tag prefix — the option the 2026-05-20 review round overrode. The qingyun-sutando half was already swept to bare `vX.Y.Z`, so leaving the mini half unswept left the PR internally inconsistent. - engine-vX.Y.Z → bare vX.Y.Z throughout. - §2.2 rewritten: records that this half's engine-prefix recommendation was overridden, states the resolved bare-vX.Y.Z decision + rationale. - Coupling table + open-questions section marked resolved. Per Chi's "up to you" call on whether to sweep the mini half. All three release-process docs now consistent with the resolved decisions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Chi Wang <4250911+sonichi@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…#870) (sonichi#876) Per workspace-design RFC sonichi#858 (Decision 2), the env var for the Memory space is renamed from `SUTANDO_PRIVATE_DIR` to `SUTANDO_MEMORY_DIR` so the vocabulary matches the 3-space mental model (Code / State / Memory). One-release alias period: - The new name `SUTANDO_MEMORY_DIR` is the canonical lookup. - The old name `SUTANDO_PRIVATE_DIR` continues to work as a fallback. - A deprecation warning fires to stderr on every read of the legacy var (not just at startup — cron / launchd environments would otherwise miss startup-only warnings and silently sit on the legacy name). Resolution helper: - Python: `_memory_dir_env()` in src/util_paths.py. - TypeScript: `memoryDirEnv()` exported from src/util_paths.ts. - Both: prefer the new var, fall back to the legacy one with the warning. Call-site updates: - src/util_paths.py — `_private_machine_dir()` + `shared_personal_path()` route through the helper. - src/util_paths.ts — `personalPath()` + `sharedPersonalPath()` route through the helper. - src/inline-tools.ts — `loadSkillManifestTools()` + `loadCoreDocumentedSkills()` + open_file doc text. - src/voice-agent.ts — voice-context loader. - skills/phone-conversation/scripts/conversation-server.ts — inline `personalPath()` twin. - src/session-handoff.sh — passes both env vars through to the python child. - Docs: CLAUDE.md, docs/workspace-contract.md, skills/MANIFEST.md. Tests: 10 Python + 5 TS unit tests covering precedence, legacy fallback, deprecation warning, and the every-read guard. Zero existing-user breakage: anyone with only `SUTANDO_PRIVATE_DIR` set keeps working through the deprecation window, sees the warning, and can migrate by renaming the env var. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…onichi#906) * docs: release process proposal (qingyun-sutando half) Plan-only document. Owner asked for a release-process + migration-framework proposal in #dev. Sutando-Mini and I split it: Mini covers when-to-cut + tag conventions; this doc covers what-goes-in + CHANGELOG culture + migration framework + joint engine↔product coupling section. 270 lines covering: 1. CHANGELOG culture — 5 categories, author-curated + release-curator-pruned. 2. Migration framework — numbered migrations/NNNN-*.{sh,py}, state/schema-version.json, idempotent startup-runner, 1-release backward-compat overlap (formalizes the ad-hoc sonichi#876 alias pattern), per-migration tempdir tests, 3-phase rollout. 3. Engine↔product coupling — Option A loose coupling (recommended) vs Option B lockstep. Engine = sonichi/sutando, Product = Sutando.app. 4. 4 open questions for owner. Located under docs/ (parallel to docs/workspace-design.md's RFC pattern), not notes/ (gitignored). Promotion to docs/release-process.md waits on owner + Chi greenlight and Mini's companion proposal. No code shipped. Plan only. * docs(rfc sonichi#906): add Overview + Motivations sections per owner ask Owner asked in two consecutive Discord messages (task-1779223601794 + task-1779223627953): - "Update the RFC to include motivations" - "Give an overview picture of what we are trying to do, why it matters" Two new sections at the top of the proposal: 1. **Overview** — TL;DR framing. What (release process + migration framework), why it matters (rollback discipline, commercial pinning, silent-breakage prevention, bot coordination, continuous gate), what it does NOT try to do (time-based cadence, backward migrations, data re-encoding, engine-product lockstep), and the co-author split. 2. **Motivations** — 5 numbered motivations (M1-M5): - M1: named snapshots of known-good states - M2: state-format changes happen often, silently breaking users - M3: commercial deploys need a pin point - M4: two bots are coordinating, need a shared spec - M5: release process IS the migration-test framework Plus an explicit **Non-goals** subsection listing what we're deliberately NOT solving here (time cadence, backward migrations, etc.) — anchors scope for future contributors. No content change to Parts 1-2 or the joint section; just preamble that explains why before the design pages dive in. * docs(rfc): add Mini's half — when to cut + tag conventions Half of the consolidated release-process RFC (sonichi#906). Covers: - When to cut a release (feature-completion trigger, owner cuts the tag) - SemVer vs CalVer (SemVer; engine-vX.Y.Z prefix) - Tag on main vs release branch (tag on main; no release branch) - Git tag vs GitHub Release (both — tag is anchor, Release is narrative) - What to cut next (aligned with qingyun-sutando: cut v0.1.0 now, framework as v0.1.1) - Explicit coupling table mapping every joint surface to the corresponding section in qingyun-sutando's half Plan-only. No code shipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(rfc sonichi#906): remove commercial framing — OSS readers may not be from AG2 Owner asked (task-1779223950387): "Remove the part about 'Commercial pinning'. Remember OSS user may not care about commercial things as they are not necessarily from Ag2 the company." Changes: - Overview "Commercial pinning" bullet → "Pinning for anyone building on top" (forks, downstream consumers, sister-node fleets — generic framing that includes but doesn't assume AG2-commercial users). - M1 dropped "(commercial waitlist, OSS contributors, sister-node fleets)" parenthetical — just "users." - Removed entire M3 "Commercial deploys need a pin point" motivation (was specifically about sutando.ag2.ai install instructions). M4/M5 renumbered to M3/M4. - Joint section's bottom bullet reworded: "Customer who hits a bug correlates ..." → "Anyone running the bundle who hits a bug ... Downstream consumers can pin install instructions to an engine tag." Per memory feedback_internal_vs_public_docs.md — the sonichi/sutando repo is PUBLIC; specific paths and commercial framings belong in INTERNAL (#dev, workspace, owner DM), not in landed docs. * docs(rfc sonichi#906): owner-quote line removed; M3 restored as downstream-pin-point (AG2-internal facing too) Owner two follow-ups: 1. task-1779224091789: "Remove wordings like this — Owner (Chi) explicitly said 'Plan and make proposals first.'" — the preamble quote framing owner's instruction directly was leaking internal chatter into a public-repo doc. Replaced with neutral "This is half of a co-drafted proposal" framing. 2. task-1779224131237: "M3. Commercial deploys need a pin point — This is AG2 internal facing as well." — clarified that the doc serves both OSS contributors AND AG2-internal-facing audiences (sutando.ag2.ai, packaged bundles, commercial integrators). Restored as M3, generalized to "Pin points for downstream consumers and bundle deploys" — explicitly enumerates forks, sister-node fleets, Sutando.app, AG2-internal deploys, commercial integrators. M4/M5 renumber accordingly (Two bots coordinating + release-process-is- migration-test). Companion file `docs/release-process-proposal-mini.md` landed in 7d4f260 (Mini's half: when to cut + tag conventions). Both halves now live on this PR's branch. * docs(rfc sonichi#906): consolidated doc merging Mini's + qingyun-sutando's halves Claimed the consolidation step in #dev bot-coord. Merges both source files (both preserved on the branch as authorship record) into a single review surface for Chi + Qingyun. Structure: - Top-of-doc overview + motivations + non-goals (combined from both). - Part 1-4 from Mini (when to cut, SemVer + tag namespace, tag-on-main no release branch, git tag + GitHub Release + hard/soft gates). - Part 5-6 from qingyun-sutando (CHANGELOG culture, migration framework with numbered migrations/state/runner/tests/phasing). - Part 7 joint section (engine ↔ product coupling, Option A recommended). - Part 8 "what to cut next" — both halves landed on (c): cut engine-v0.1.0 now with manual migration notes, framework as v0.1.1. - Coupling table verifying no double-coverage between the two halves. - 5 consolidated open questions for owner (was 4 from each half; deduped + added Mini's signed-tags question). - Next move: owner + Chi review, pick answers, then promote to docs/release-process.md + open implementation issues. Source halves stay on the branch: - docs/release-process-proposal-mini.md - docs/release-process-proposal-qingyun-sutando.md If owner greenlights, this consolidated doc moves to docs/release-process.md and the two source files can be archived (or kept as authorship record). No code shipped. Plan only. * docs(rfc sonichi#906): integrate review-round resolutions Integrates the 3 reviews on sonichi#906: - Bassil (cold-review 2026-05-20 06:28) — 4-question picks aligned with Chi's later owner-pick; reinforces option (c) cut-now-with-manual-notes + framework as next-release primary payload. - Lucy (review 11:31) — 3 implementation questions on the migration framework: multi-core race on schema-version.json, merge-order collision on migration numbers, health-check gate on fresh clone. - Chi (sub-agent draft 19:28 + owner-pick 20:30) — final calls on 3 open questions: bare v0.MINOR.PATCH (drop engine- prefix), working-state when-to-cut (not commit-count), unsigned tags for v0.1.x (signed deferred). Concrete changes in the doc: - Sweep `engine-vX.Y.Z` → bare `vX.Y.Z` everywhere (frontmatter status, body prose, schema-version.json example, alias timeline, coupling section, open-question text). 13 occurrences. - Rewrite "Open questions for owner" as "RESOLVED 2026-05-20" section with each pick + reasoning (§§ 4a/4b for when-to-cut refinement + GPG deferral). - §2.7 — replace cut-gate language with Chi's working-state framing + clarify health-check scope (tagging install, not fresh clone — addresses Lucy Q3). - §2.8 (new) — Concurrency & ordering: resolve Lucy Q1 (migrations run as pre-pool step in startup.sh, single-writer- by-construction; runner also called from resolve_workspace as idempotent fallback for manual sessions) and Q2 (number reserved at merge time, pre-merge CI check fails on collision, mirrors Rails/Alembic). - Add "Future hardening" section gathering deferred items (signed tags, backward migrations, data re-encoding, PR-template migration checklist, docs/install.md fresh-install path, docs/release-process.md promotion). - Rewrite "Next move" to reflect Chi's "mergeable" verdict + the Phase 1 framework PR sequence + cut v0.1.0 + workspace contract A/B as forcing function for migration 0002. - Frontmatter: reviewers_integrated field naming the 3 reviews, status updated to "open questions resolved; pending merge", intro callout quoting Chi's mergeable line. Plan-only doc — no code shipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(rfc): sweep consolidated doc to reflect Chi's 2026-05-20 owner-picks The qingyun-sutando half integrated the review-round decisions, but the consolidated doc — the file that promotes to docs/release-process.md — was never swept and still contradicted them. Chi's stated merge bar was "once the RFC text reflects these, it's mergeable"; this makes it so. - engine-vX.Y.Z → bare vX.Y.Z everywhere (decision 1). - §2.2 rewritten: bare tag namespace, no engine- prefix; the namespace collision the prefix defended against doesn't exist (product ships from its own repo / tag line). - Part 1.1: add the working-state precondition (decision 4a) — CI green, no release-blocker, no half-finished migration; quality gate not count. - "Consolidated open questions" → "Consolidated decisions (resolved)" with all 5 answers recorded inline. - "Next move" + coupling table + frontmatter status updated to reflect that nothing is owner-gated anymore. Proposal files (mini / qingyun) left as the authorship record per the consolidated doc's own header; the mini half still reads `engine-` — flag if it should be swept too. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(rfc): sweep mini proposal half to bare vX.Y.Z (consistency with sonichi#906 decisions) Companion to e248cc6 (consolidated-doc sweep). The mini proposal half still recommended the `engine-` tag prefix — the option the 2026-05-20 review round overrode. The qingyun-sutando half was already swept to bare `vX.Y.Z`, so leaving the mini half unswept left the PR internally inconsistent. - engine-vX.Y.Z → bare vX.Y.Z throughout. - §2.2 rewritten: records that this half's engine-prefix recommendation was overridden, states the resolved bare-vX.Y.Z decision + rationale. - Coupling table + open-questions section marked resolved. Per Chi's "up to you" call on whether to sweep the mini half. All three release-process docs now consistent with the resolved decisions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Chi Wang <4250911+sonichi@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… resolveAxReadPath (Path B sweep) Owner DM 2026-06-06 14:46Z (task-1780757193114): `src/Sutando/main.swift:1492` had a hardcoded `~/.sutando/memory-sync/skills/personal-deictic/ax-read` candidate path in `resolveAxReadPath()`. That was the pre-v0.3.0 default-private location — `sync-memory.sh`'s rsync target. Post-v0.3.0 (#1440 + the sync-workspace.sh flow), the legacy `.sutando/memory-sync/` clone is deprecated (removed in v0.4.0). Dropped the hardcoded candidate; kept the `$SUTANDO_MEMORY_DIR` + `$SUTANDO_PRIVATE_DIR` env lookups (canonical + legacy alias #876) + the public-repo `<repo>/skills/context-drop/ax-read` fallback. Net behavior on a host whose `$SUTANDO_MEMORY_DIR` is set: identical. On a host where neither env var is set: now falls straight to the public-repo binary instead of probing a deprecated path that's guaranteed not to exist post-migration. Updated the resolution-order doc comment to match + added a v0.3.0 deprecation note. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mespace across resolvers, helpers, docs (8 commits) (#1490) * fix(stage-readiness): modernize sync-age check to workspace-sync (drops SUTANDO_PRIVATE_DIR + legacy memory-sync fallbacks) Owner flagged the stale `MEMORY_DIR` chain in `scripts/stage-readiness.sh` 2026-06-06 13:25Z (task-1780752348761): ```bash MEMORY_DIR="${SUTANDO_MEMORY_DIR:-${SUTANDO_PRIVATE_DIR:-}}" if [ -z "$MEMORY_DIR" ]; then if [ -d "$HOME/.sutando/memory-sync" ]; then MEMORY_DIR="$HOME/.sutando/memory-sync" else MEMORY_DIR="$HOME/.sutando-memory-sync" fi fi ``` Three legacy artifacts: (a) `SUTANDO_PRIVATE_DIR` deprecated alias (#870; one-release honor window), (b) `~/.sutando/memory-sync/` pre-v0.3.0 clone path (sync-memory.sh is removed in v0.4.0), (c) `~/.sutando-memory-sync/` pre-#870 alias. Modernized: the workspace itself is the sync target as of v0.3.0 (`scripts/sync-workspace.sh`, PR #1445+) — check `<workspace>/.git/FETCH_HEAD` mtime for freshness. Legacy `~/.sutando/memory-sync/` retained as a fallback during the v0.3.x deprecation window so hosts still on `sync-memory.sh` don't lose the readiness signal; the warning hint includes a migrate-to-workspace-sync nudge in the legacy path. Drops `SUTANDO_PRIVATE_DIR` reference (#870's one-release window has elapsed as of v0.3.0) and `~/.sutando-memory-sync/` (pre-#870). Workspace resolution goes through the canonical M0 helper (no dead else-branch fallback — script is already repo-coupled). Smoke: stage-readiness.sh runs clean and reports `workspace-sync last sync 33h ago — run 'bash scripts/sync-workspace.sh'` on this MBP. Net -4 lines after dropping the legacy fork. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(agent-registry): modernize _workspace_resolve.py to delegate to M0 helper Owner DM 2026-06-06 13:27Z (task-1780752451373 + task-1780752464055): the docstring still claimed `~/.sutando/workspace` was "the canonical default" and `$SUTANDO_WORKSPACE` was honored. Both wrong post-#1440 / v0.8 — canonical default is `<repo>/workspace/` and the env var is no longer honored for resolution. The module previously re-implemented its own 3-step resolver (env-var, .env-file walk-up, hardcoded `~/.sutando/workspace` default) — all three steps are obsolete post-v0.8. Replaced with a thin delegate that walks up to find `scripts/sutando-config.sh` and shells out to the canonical M0 helper, so this script can never drift from the resolver contract again. The walk-up logic (5-level realpath() bounded walk) is retained because the symlinks-into-the-repo concern still applies (when invoked via `~/.claude/skills/agent-registry/...`). Symptom of the prior bug was silent-data-loss-equivalent: registry writes to wrong dir while readers look at the right one. Smoke: resolves correctly to `/Users/qingyunwu/Documents/github/sutando/workspace` on this MBP. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(submit-use-case): drop hardcoded `/Users/wangchi/.sutando/workspace/` Chi-fleet probe (post-#1440) Owner DM 2026-06-06 13:28Z (task-1780752526451 + task-1780752549313: "Why this is still not fixed?"): three sites in the submit-use-case skill still referenced `/Users/wangchi/.sutando/workspace/` as Chi's fleet-detection signal. Pre-#1440 that path existed on Chi's hosts; post-#1440 the workspace is in-repo (`<repo>/workspace/`), so the path-existence probe always returns false and the fleet-detection silently broke. 3 sites updated: - `skills/submit-use-case/scripts/submit_use_case.py` — `is_chi_fleet()` drops the `Path("/Users/wangchi/.sutando/workspace").exists()` check; retains the `SUTANDO_FLEET_OWNER=chi` env signal (Chi sets this once per host in `.env`, no longer needs the path probe). - `skills/submit-use-case/SKILL.md` L59 — prose updated to match. - `skills/submit-use-case/README.md` L64 — same. If Chi-fleet auto-detection regresses (the env var isn't set on a host that used to be detected via the path), the user can re-enable by setting `SUTANDO_FLEET_OWNER=chi` in their `.env` — same setup documented in the README. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(workspace-resolver): drop legacy .sutando/workspace fallback (Mini opinion-requested Path B) Per Mini's #design opinion 2026-06-06 14:42Z + owner's "go ahead with B" 14:44Z: post-v0.8 (#1440) the legacy `.sutando/workspace/` namespace should be fully retired from production resolution, not just from the documented contract. Three sites updated in this commit (the Tier 1+2 contract-bearing changes — Tier 3+ doc-comment sweep to follow): - `src/sutando_config.py:344-352` — no-config-no-repo-root last-ditch fallback now `~/sutando-workspace/` instead of `~/.sutando/workspace/`. Preserves the safety net for ad-hoc invocations outside a checkout while fully dropping the deprecated `.sutando/` namespace. - `src/Sutando/SutandoConfig.swift:228-236` — same change, Swift side. Mirrors Python intentionally per the cross-language contract. - `src/session-handoff.sh:38-49` — drop the `$SUTANDO_WORKSPACE`-aware defensive fallback entirely. Post-v0.8 the env var is no longer honored for workspace resolution; if the M0 helper isn't reachable via either of the two probed paths, fail loud rather than risk writing `session-state.md` to the wrong workspace via the deprecated env value. CI lint `--diff` clean. Smoke: `bash scripts/sutando-config.sh workspace` still resolves correctly to `<repo>/workspace/` on this MBP. Stand: Mini's scope-expansion caveat noted — there's a follow-up sweep of resolver-module docstrings (workspace_default.{py,ts}) + ~9 stale code-comment sites + config.json.example templates to land in subsequent commits before this PR is ready for review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(sutando-app): drop hardcoded ~/.sutando/memory-sync/ candidate in resolveAxReadPath (Path B sweep) Owner DM 2026-06-06 14:46Z (task-1780757193114): `src/Sutando/main.swift:1492` had a hardcoded `~/.sutando/memory-sync/skills/personal-deictic/ax-read` candidate path in `resolveAxReadPath()`. That was the pre-v0.3.0 default-private location — `sync-memory.sh`'s rsync target. Post-v0.3.0 (#1440 + the sync-workspace.sh flow), the legacy `.sutando/memory-sync/` clone is deprecated (removed in v0.4.0). Dropped the hardcoded candidate; kept the `$SUTANDO_MEMORY_DIR` + `$SUTANDO_PRIVATE_DIR` env lookups (canonical + legacy alias #876) + the public-repo `<repo>/skills/context-drop/ax-read` fallback. Net behavior on a host whose `$SUTANDO_MEMORY_DIR` is set: identical. On a host where neither env var is set: now falls straight to the public-repo binary instead of probing a deprecated path that's guaranteed not to exist post-migration. Updated the resolution-order doc comment to match + added a v0.3.0 deprecation note. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(workspace_default): refresh module docstrings to post-v0.8 contract (Path B sweep Tier 3) `src/workspace_default.{py,ts}` are the historic resolver wrappers; their module docstrings still described the pre-v0.8 contract ($SUTANDO_WORKSPACE honored, ~/.sutando/workspace/ as fallback). Per Mini's opinion-requested B reading + owner directive 2026-06-06: rewrite to match the actual post-#1440 contract. - `src/workspace_default.py:1-32` — module docstring now describes the M0 helper chain (`sutando.config.local.json` → `<repo>/workspace/`), notes the env-var is no longer honored, points readers at `src.sutando_config.resolve_workspace` as the canonical entry point, and explains that `default_workspace_dir` is a test-only export. - `src/workspace_default.py:23` — `_DEFAULT_SUBPATH` updated from `(".sutando", "workspace")` to `("sutando-workspace",)`. Matches the new `~/sutando-workspace/` last-ditch fallback in `sutando_config.py`. - `src/workspace_default.py:46` — `default_workspace_dir()` docstring rewritten to clarify it returns the post-v0.8 fallback, NOT the production default. - `src/workspace_default.ts:1-22` — module docstring refreshed with the same content, TS-flavored. - `src/workspace_default.ts:24-45` — `resolveWorkspace()` docstring rewritten: drops the "$SUTANDO_WORKSPACE env var (legacy escape hatch; warn once)" claim, notes the env-var is no longer honored, describes the warn-and-ignore + auto-migrate behavior. Behavior change: callers using `default_workspace_dir()` for the no-config-no-repo-root fallback now get `~/sutando-workspace/` instead of `~/.sutando/workspace/`. Tests use this via `patch.object(...)` so they're unaffected by the underlying path change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(config-templates): drop $SUTANDO_WORKSPACE + ~/.sutando/workspace/ from skill examples (Path B Tier 5) Owner DM 2026-06-06 14:50Z (task-1780757426171): the `_comment` field in `skills/phone-conversation/config.json.example` (and the sibling `skills/discord-voice/config.json.example`) still described the pre-v0.8 contract: "lives at \$SUTANDO_WORKSPACE/config/foo.json (default ~/.sutando/workspace/config/foo.json)". Both wrong post-#1440. Rewrote to point at the canonical resolver: "<workspace>/config/foo.json (the workspace resolves via `bash scripts/sutando-config.sh workspace`, default <repo>/workspace/)". Drops both the deprecated env-var mention and the deprecated `.sutando/` namespace fallback in one stroke. These are user-facing template files copied into the workspace on first run — getting the prose right matters because the `_comment` field is what a user reads when they open the live config to edit it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(code-comments): refresh 8 stale ~/.sutando/workspace comments to post-v0.8 contract (Path B Tier 4) Path B sweep round-up for the 8 code-comment sites where the prose still described the pre-v0.8 contract: - `skills/call-diagnostics/scripts/diagnose.py:38` — "(~/.sutando/workspace)" → "post-v0.8 default `<repo>/workspace/`" - `src/archive-stale-results.py:37-38` — "$SUTANDO_WORKSPACE (default ~/.sutando/workspace/)" → "the resolved workspace (post-v0.8 default `<repo>/workspace/`)" - `src/inline-tools.ts:659-661` — "$SUTANDO_WORKSPACE/state/ (default ~/.sutando/workspace/state/)" → "<workspace>/state/ (default <repo>/workspace/ post-v0.8)" - `src/web-client.ts:3108-3113` — same shape as inline-tools - `src/util_paths.py:65-66` — docstring updated: "canonical default (~/.sutando/workspace/)" → "post-v0.8 canonical default (<repo>/workspace/)"; notes $SUTANDO_WORKSPACE no longer honored - `src/util_paths.ts:13-18` — same shape - `src/health-check.py:847-850` — "~/.sutando/workspace/notes" → "<workspace>/notes"; v0.8 default note - `src/voice-agent.ts:19, 99-100` — header env-doc + inline comment both refreshed Pure prose; no behavior change. CI lint --diff clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(workspace-default): update default-path assertion to match post-v0.8 sutando-workspace (Path B sweep) CI test failure on `f7f5ce7`: `test_default_is_dot_sutando_workspace_under_home` expected `default_workspace_dir()` to return `~/.sutando/workspace/`. Per the B sweep's `_DEFAULT_SUBPATH` change (`(".sutando", "workspace")` → `("sutando-workspace",)`), the function now returns `~/sutando-workspace/`. Renamed the test method to match the new behavior; updated all three assertion lines + the equality-on-full-path; added a docstring tying the test to the post-v0.8 contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(watch-tasks-stream): drop legacy env-var + hardcoded ~/.sutando/workspace fallbacks (Path B sweep) Owner DM 2026-06-06 14:57Z (task-1780757867862): `src/watch-tasks-stream.sh` had a 4-tier fallback chain for both TASKS_DIR and STATE_DIR — positional arg → M0 helper → `$SUTANDO_WORKSPACE` env → hardcoded `$HOME/.sutando/workspace/`. Post-v0.8 (#1440 + Mini opinion-requested 2026-06-06) the env-var path is no longer honored and the `.sutando/workspace/` namespace is retired. Replaced both blocks with a single-path resolver: M0 helper required, fail-loud if not reachable. Matches the contract change applied to `session-handoff.sh` earlier in this PR. Also removed `src/watch-tasks-stream.sh` from the lint `ALLOWED` regex in `scripts/lint-workspace-resolution.sh` — the file no longer needs a defense-in-depth exemption now that the legacy paths are gone. Behavior change: a host where the sutando checkout is broken/incomplete will now error visibly with "cannot resolve workspace" instead of silently watching `~/.sutando/workspace/tasks/` (which would be empty post-migration and produce no events — owner DMs would land silently in the bridges' workspace dir). This matches the divergence-prevention rationale in the surrounding comment, but enforces it strictly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(discord-voice): refresh _resolve_workspace docstring post-v0.8 (Path B sweep tail) `skills/discord-voice/scripts/join_trigger.py:46` had a docstring still describing the pre-v0.8 resolver chain ("$SUTANDO_WORKSPACE env, else ~/.sutando/workspace/"). Refreshed to point at the canonical helper + note the env-var is no longer honored post-v0.8. Behavior unchanged — this is the docstring only; the actual code already prefers the helper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(memory-sync-refs): refresh 4 stale "memory-sync" references to workspace-sync (Path B sweep cont'd) Owner DM 2026-06-06 15:08Z (task-1780758535617): grep for "memory-sync" turned up 19 files. 4 had stale references that should now point at the v0.3.0 canonical workspace-sync flow + deprecation note: - `README.md:218` — multi-machine sync row pointed at deleted `docs/memory-sync.md` and recommended `sync-memory.sh` as primary path. Updated to: vault config + `sync-workspace.sh --init`, with link to `docs/workspace-sync.md`; called out the v0.4.0 sync-memory.sh removal. - `skills/relay/SKILL.md:33` — "Sync via the existing memory-sync engine" → "Sync via the workspace-sync engine (`scripts/sync-workspace.sh`)"; added deprecation note. - `skills/catchup-after-startup/SKILL.md:57` — "across multiple cores via memory-sync" → "via workspace-sync". - `docs/state-sync-allowlist.md:171` — link to deleted `docs/memory-sync.md` → `docs/workspace-sync.md` (with note that it's canonical as of v0.3.0). Remaining 15 of 19 are either (a) intentional historical / deprecation prose (CHANGELOG.md, scripts/sync-memory.sh, scripts/sync-workspace.sh --migrate-from-legacy block, docs/workspace-sync.md deprecation section, tests/sync-{memory,workspace}-migration.test.sh), (b) already addressed in this PR (stage-readiness.sh, main.swift), or (c) describing a real concept that's separate from the legacy clone (skills/MANIFEST.md, context-drop/Package.swift, health-check.py legacy-path lookup, inline-tools.ts skills location, workspace_default.py symlink comment, sutando-migrate.sh conflict-resolution comment, schedule-crons example narrative). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
SUTANDO_PRIVATE_DIRtoSUTANDO_MEMORY_DIRso vocabulary matches the 3-space mental model (Code / State / Memory) ratified in docs: add workspace-design.md — 3-space model RFC (Code/State/Memory) #858 Decision 2.SUTANDO_PRIVATE_DIRcontinues to work as a fallback, with a deprecation warning emitted to stderr on every read (cron / launchd miss startup-only warnings — every-read is intentional).What changed
New helper (single source of truth for the lookup):
_memory_dir_env()insrc/util_paths.pymemoryDirEnv()exported fromsrc/util_paths.tsBoth return
SUTANDO_MEMORY_DIRwhen set, elseSUTANDO_PRIVATE_DIRwith aDEPRECATIONwarning, elseNone/undefined.Call-site updates:
src/util_paths.{py,ts}—personal_path()/personalPath()+shared_personal_path()/sharedPersonalPath()route through the helper.src/inline-tools.ts—loadSkillManifestTools(),loadCoreDocumentedSkills(), and theopen_filetool description.src/voice-agent.ts— voice-context dynamic loader.skills/phone-conversation/scripts/conversation-server.ts— inlinepersonalPath()twin (kept inline to avoid pulling main repo's util_paths.ts through the skill's import surface).src/session-handoff.sh— passes both env vars through to the python child.CLAUDE.md,docs/workspace-contract.md,skills/MANIFEST.md.Risk to existing users
None. Anyone with only
SUTANDO_PRIVATE_DIRset:DEPRECATIONwarning on stderr per read..env.The legacy alias will be removed in the next release.
Test plan
python3 tests/util-paths-memory-dir.test.py— 10/10 passnpx tsx --test tests/util-paths-memory-dir.test.ts— 5/5 passpython3 tests/workspace-default.test.py— still 27/27 passnpx tsc --noEmitcleanCloses #870
🤖 Generated with Claude Code