v3.1: per-account dir + workspace pin (no more keychain materialize)#13
Merged
Conversation
…gin) Code-review follow-up on T1: use the `workspace:` init parameter rather than mutating after construction, and assert the raw JSON contains `"workspace":"work"` so a future typo in `CodingKeys` would surface instead of being masked by the `?? "origin"` decode fallback. Plus a new test that explicit "origin" round-trips distinctly from the absent-field default fallback. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…links Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace precondition(account.tool == .claude) with guarded throw of Error.wrongTool — matches KeychainCredentialAdapter convention, surfaces a recoverable error instead of crashing. - Distinguish "wrong symlink" (replace) from "real directory at symlink path" (throw Error.existingDirectoryAtSymlinkPath) — the latter could contain user / claude data; silently deleting it would be a data-loss footgun on a repoint. - Add 3 tests covering the repoint path, the real-dir-collision guard, and the wrong-tool guard. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
….json Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…stderr Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…yout Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…counts Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…s via use), migrate surfaces errors - use): short-circuit -h/--help/--version before _account-dir command substitution; otherwise ArgumentParser's stdout help text gets exported as a garbage CLAUDE_CONFIG_DIR - phantom loop: change `command orrery-bin use` to `orrery use` so the shell function's use) case updates CLAUDE_CONFIG_DIR for v3.1 accounts; v3.0.4 sandboxes still work (use) falls through internally) - MigrateToV31Command: let acctStore.list errors propagate rather than silently treating store failure as "no accounts to migrate" Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…arded) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ored Account.email/plan No tests deleted — no tests exercised the live-read path directly. All 320 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…cBack (v3.1) - prepareMaterialize: early-return when tool == .claude; shell function wrapper + per-account dir layout owns claude setup, not the binary. - prepareSyncBack: early-return when tool == .claude; CaptureClaudeExitCommand via claude-identity.json owns exit capture, not RunCommand. - Add test: claudePrepareMaterializeIsNoOp (RunCommandTests) - Add test: claudePrepareSyncBackIsNoOp (AccountInfoTests) - No claude-specific tests deleted: existing tests already used .codex only. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ell wrapper in v3.1 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…e use Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… claude errors surface Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove L10n.Sandbox.* keys entirely from l10n-signatures.json - Add L10n.Workspace.set-env/unset-env keys (11 strings total in Workspace namespace) - Update en.json, zh-Hant.json, ja.json: replace sandbox.* strings with workspace.* equivalents using workspace vocabulary throughout - Update workspace.abstract in all locales to remove sandbox references - Update SandboxCommand.swift: all L10n.Sandbox.* → L10n.Workspace.* - Update keys.md: remove ## sandbox section, expand ## workspace section Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…stSandboxHeader vocabulary
- AccountAddFinalizeCommand calls ClaudeAccountMigration.migrateAccount
for new claude accounts so they get the v3.1 per-account-dir layout
immediately — closes the "new account after first auto-migrate" gap
where the .v3.1-account-layout-migrated flag would silently skip the
newly-added account
- account.listSandboxHeader value changes from "sandbox: {name}" to
"workspace: {name}" in en/zh-Hant/ja — last user-visible string still
using sandbox vocabulary after Plan 4 T10's rename pass
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Plan 1 foundation md + html were written to the worktree dir earlier (visible in main repo as untracked since they sit at the worktree root path which both git working trees see). These 3 are the remaining ones written for Plans 2/3/4 and used as the source-of-truth task lists during execution. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ace flag alias 1. Extract SandboxCommand.subcommandTypes as a public static let so both SandboxCommand and WorkspaceCommand reference it explicitly. Avoids WorkspaceCommand silently breaking if SandboxCommand.configuration's shape ever changes. 2. Add --workspace/-w as flag aliases for --sandbox/-s in set-env and unset-env subcommands. Property renamed sandbox -> workspace for internal consistency with the v3.1 vocabulary. Both old and new flag spellings continue to work (no breaking change).
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
v3.1 is a structural rework of how orrery manages Claude credentials. The v3.0.x design — swap keychain items inside a shared
CLAUDE_CONFIG_DIR— caused identity/plan drift (thegradyzhuo+team/jiabao+maxmixed-display bug),/loginpoisoning of pool slots, and mid-session/statusflapping when another shell ranorrery use. v3.1 fixes the root cause: each Claude account gets its own CLAUDE_CONFIG_DIR, with workspace content (projects/,memory/,agents/,commands/,todos/) shared across pinned accounts via symlinks.New conceptual model:
~/.orrery/accounts/claude/<id>/~/.orrery/envs/<name>/claude-workspace/orrery use Xnow justexport CLAUDE_CONFIG_DIR=<X's dir>in the shell — no keychain copy, no.claude.jsonmutation, no disturbance to running claude sessions. The new `claude()` shell wrapper handles per-launch identity/shared merge and per-exit split.Delivered across 4 plans (43 commits)
Net: +~2300 / -~900 lines, 315 tests passing (244 baseline + ~70 new).
Out of scope (deferred)
/.claude/projects/` session content is NOT migrated into the new workspace dir — needs separate UX design around the existing `/.claude` symlinkDesign docs
Test Plan
🤖 Generated with Claude Code