sideby 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -2
  3. package/README.zh-CN.md +112 -0
  4. package/dist/build.json +1 -0
  5. package/dist/src/cli/args.d.ts +13 -0
  6. package/dist/src/cli/args.js +38 -0
  7. package/dist/src/cli/commands.d.ts +50 -0
  8. package/dist/src/cli/commands.js +566 -0
  9. package/dist/src/cli/format.d.ts +16 -0
  10. package/dist/src/cli/format.js +80 -0
  11. package/dist/src/cli/json-schemas.d.ts +2 -0
  12. package/dist/src/cli/json-schemas.js +259 -0
  13. package/dist/src/cli/main.d.ts +2 -0
  14. package/dist/src/cli/main.js +276 -0
  15. package/dist/src/cli/schemas.d.ts +1 -0
  16. package/dist/src/cli/schemas.js +16 -0
  17. package/dist/src/core/account-name.d.ts +2 -0
  18. package/dist/src/core/account-name.js +2 -0
  19. package/dist/src/core/accounts.d.ts +20 -0
  20. package/dist/src/core/accounts.js +131 -0
  21. package/dist/src/core/config.d.ts +61 -0
  22. package/dist/src/core/config.js +184 -0
  23. package/dist/src/core/create.d.ts +30 -0
  24. package/dist/src/core/create.js +126 -0
  25. package/dist/src/core/doctor.d.ts +41 -0
  26. package/dist/src/core/doctor.js +171 -0
  27. package/dist/src/core/errors.d.ts +12 -0
  28. package/dist/src/core/errors.js +14 -0
  29. package/dist/src/core/file-memo.d.ts +24 -0
  30. package/dist/src/core/file-memo.js +41 -0
  31. package/dist/src/core/fs-safe.d.ts +38 -0
  32. package/dist/src/core/fs-safe.js +205 -0
  33. package/dist/src/core/handoff.d.ts +41 -0
  34. package/dist/src/core/handoff.js +54 -0
  35. package/dist/src/core/identity.d.ts +23 -0
  36. package/dist/src/core/identity.js +79 -0
  37. package/dist/src/core/last-doctor.d.ts +36 -0
  38. package/dist/src/core/last-doctor.js +69 -0
  39. package/dist/src/core/launch.d.ts +37 -0
  40. package/dist/src/core/launch.js +108 -0
  41. package/dist/src/core/login-path.d.ts +23 -0
  42. package/dist/src/core/login-path.js +96 -0
  43. package/dist/src/core/paths.d.ts +13 -0
  44. package/dist/src/core/paths.js +32 -0
  45. package/dist/src/core/quota-levels.d.ts +19 -0
  46. package/dist/src/core/quota-levels.js +34 -0
  47. package/dist/src/core/resume.d.ts +9 -0
  48. package/dist/src/core/resume.js +15 -0
  49. package/dist/src/core/secret-file.d.ts +30 -0
  50. package/dist/src/core/secret-file.js +116 -0
  51. package/dist/src/core/share-meaning.d.ts +6 -0
  52. package/dist/src/core/share-meaning.js +32 -0
  53. package/dist/src/core/share-mode-names.d.ts +1 -0
  54. package/dist/src/core/share-mode-names.js +10 -0
  55. package/dist/src/core/share-modes.d.ts +24 -0
  56. package/dist/src/core/share-modes.js +405 -0
  57. package/dist/src/core/shell-init.d.ts +31 -0
  58. package/dist/src/core/shell-init.js +84 -0
  59. package/dist/src/core/skill-check.d.ts +11 -0
  60. package/dist/src/core/skill-check.js +57 -0
  61. package/dist/src/core/usage-days.d.ts +15 -0
  62. package/dist/src/core/usage-days.js +33 -0
  63. package/dist/src/core/version.d.ts +9 -0
  64. package/dist/src/core/version.js +46 -0
  65. package/dist/src/desktop/app.d.ts +60 -0
  66. package/dist/src/desktop/app.js +316 -0
  67. package/dist/src/desktop/icon.d.ts +16 -0
  68. package/dist/src/desktop/icon.js +174 -0
  69. package/dist/src/families/claude/index.d.ts +10 -0
  70. package/dist/src/families/claude/index.js +127 -0
  71. package/dist/src/families/claude/layout.d.ts +6 -0
  72. package/dist/src/families/claude/layout.js +5 -0
  73. package/dist/src/families/claude/quota-cache.d.ts +31 -0
  74. package/dist/src/families/claude/quota-cache.js +111 -0
  75. package/dist/src/families/claude/quota.d.ts +3 -0
  76. package/dist/src/families/claude/quota.js +53 -0
  77. package/dist/src/families/claude/usage.d.ts +22 -0
  78. package/dist/src/families/claude/usage.js +146 -0
  79. package/dist/src/families/codex/index.d.ts +5 -0
  80. package/dist/src/families/codex/index.js +70 -0
  81. package/dist/src/families/codex/rollout.d.ts +67 -0
  82. package/dist/src/families/codex/rollout.js +298 -0
  83. package/dist/src/families/grok/index.d.ts +8 -0
  84. package/dist/src/families/grok/index.js +82 -0
  85. package/dist/src/families/index.d.ts +3 -0
  86. package/dist/src/families/index.js +40 -0
  87. package/dist/src/families/logos.d.ts +21 -0
  88. package/dist/src/families/logos.js +26 -0
  89. package/dist/src/families/pi/index.d.ts +3 -0
  90. package/dist/src/families/pi/index.js +54 -0
  91. package/dist/src/families/shared/sessions.d.ts +9 -0
  92. package/dist/src/families/shared/sessions.js +70 -0
  93. package/dist/src/families/shared/toml.d.ts +5 -0
  94. package/dist/src/families/shared/toml.js +16 -0
  95. package/dist/src/index.d.ts +5 -0
  96. package/dist/src/index.js +4 -0
  97. package/dist/src/panel/background.d.ts +62 -0
  98. package/dist/src/panel/background.js +274 -0
  99. package/dist/src/panel/handler.d.ts +91 -0
  100. package/dist/src/panel/handler.js +396 -0
  101. package/dist/src/panel/i18n.d.ts +287 -0
  102. package/dist/src/panel/i18n.js +570 -0
  103. package/dist/src/panel/page-logic.d.ts +154 -0
  104. package/dist/src/panel/page-logic.js +326 -0
  105. package/dist/src/panel/page-script.d.ts +2 -0
  106. package/dist/src/panel/page-script.js +1633 -0
  107. package/dist/src/panel/page-styles.d.ts +7 -0
  108. package/dist/src/panel/page-styles.js +514 -0
  109. package/dist/src/panel/page.d.ts +20 -0
  110. package/dist/src/panel/page.js +96 -0
  111. package/dist/src/panel/server.d.ts +32 -0
  112. package/dist/src/panel/server.js +133 -0
  113. package/dist/src/panel/theme.d.ts +116 -0
  114. package/dist/src/panel/theme.js +132 -0
  115. package/dist/src/plugins/account-script.d.ts +4 -0
  116. package/dist/src/plugins/account-script.js +66 -0
  117. package/dist/src/plugins/bus.d.ts +33 -0
  118. package/dist/src/plugins/bus.js +84 -0
  119. package/dist/src/plugins/loader.d.ts +58 -0
  120. package/dist/src/plugins/loader.js +250 -0
  121. package/dist/src/quota/claude-statusline.d.ts +28 -0
  122. package/dist/src/quota/claude-statusline.js +301 -0
  123. package/dist/src/quota/statusline-tap.d.ts +11 -0
  124. package/dist/src/quota/statusline-tap.js +104 -0
  125. package/dist/src/runtime.d.ts +195 -0
  126. package/dist/src/runtime.js +424 -0
  127. package/dist/src/types.d.ts +285 -0
  128. package/dist/src/types.js +3 -0
  129. package/dist/testing/demo.d.ts +8 -0
  130. package/dist/testing/demo.js +50 -0
  131. package/dist/testing/index.d.ts +36 -0
  132. package/dist/testing/index.js +118 -0
  133. package/package.json +66 -4
  134. package/schemas/alias.json +102 -0
  135. package/schemas/app-install.json +74 -0
  136. package/schemas/app-uninstall.json +54 -0
  137. package/schemas/config.json +170 -0
  138. package/schemas/doctor.json +229 -0
  139. package/schemas/error.json +25 -0
  140. package/schemas/families.json +205 -0
  141. package/schemas/list.json +177 -0
  142. package/schemas/new.json +199 -0
  143. package/schemas/next.json +127 -0
  144. package/schemas/plugins.json +74 -0
  145. package/schemas/quota-setup.json +60 -0
  146. package/schemas/quota-teardown.json +30 -0
  147. package/schemas/quota.json +203 -0
  148. package/skills/sideby/SKILL.md +61 -0
  149. package/skills/sideby/references/accounts.md +31 -0
  150. package/skills/sideby/references/diagnose.md +47 -0
  151. package/skills/sideby/references/handoff.md +41 -0
  152. package/skills/sideby/references/quota.md +14 -0
  153. package/skills/sideby/references/setup.md +31 -0
  154. package/skills/sideby/references/sharing.md +17 -0
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/plugins.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "plugins",
8
+ "errors"
9
+ ],
10
+ "properties": {
11
+ "schemaVersion": {
12
+ "type": "number",
13
+ "const": 1
14
+ },
15
+ "plugins": {
16
+ "type": "array",
17
+ "items": {
18
+ "type": "object",
19
+ "required": [
20
+ "name",
21
+ "version",
22
+ "source",
23
+ "families",
24
+ "configKeys"
25
+ ],
26
+ "properties": {
27
+ "name": {
28
+ "type": "string"
29
+ },
30
+ "version": {
31
+ "type": "string"
32
+ },
33
+ "source": {
34
+ "type": "string"
35
+ },
36
+ "description": {
37
+ "type": "string"
38
+ },
39
+ "families": {
40
+ "type": "array",
41
+ "items": {
42
+ "type": "string"
43
+ }
44
+ },
45
+ "configKeys": {
46
+ "type": "array",
47
+ "items": {
48
+ "type": "string"
49
+ }
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "errors": {
55
+ "type": "array",
56
+ "items": {
57
+ "type": "object",
58
+ "required": [
59
+ "where",
60
+ "message"
61
+ ],
62
+ "properties": {
63
+ "where": {
64
+ "type": "string"
65
+ },
66
+ "message": {
67
+ "type": "string"
68
+ }
69
+ }
70
+ }
71
+ }
72
+ },
73
+ "title": "sideby plugins --json"
74
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/quota-setup.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "family",
8
+ "applied",
9
+ "plan"
10
+ ],
11
+ "properties": {
12
+ "schemaVersion": {
13
+ "type": "number",
14
+ "const": 1
15
+ },
16
+ "family": {
17
+ "type": "string"
18
+ },
19
+ "applied": {
20
+ "type": "boolean"
21
+ },
22
+ "plan": {
23
+ "type": "object",
24
+ "required": [
25
+ "status",
26
+ "file",
27
+ "diff",
28
+ "message"
29
+ ],
30
+ "properties": {
31
+ "status": {
32
+ "anyOf": [
33
+ {
34
+ "type": "string",
35
+ "const": "enabled"
36
+ },
37
+ {
38
+ "type": "string",
39
+ "const": "ready"
40
+ },
41
+ {
42
+ "type": "string",
43
+ "const": "blocked"
44
+ }
45
+ ]
46
+ },
47
+ "file": {
48
+ "type": "string"
49
+ },
50
+ "diff": {
51
+ "type": "string"
52
+ },
53
+ "message": {
54
+ "type": "string"
55
+ }
56
+ }
57
+ }
58
+ },
59
+ "title": "sideby quota setup --json"
60
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/quota-teardown.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "family",
8
+ "ok",
9
+ "message"
10
+ ],
11
+ "properties": {
12
+ "schemaVersion": {
13
+ "type": "number",
14
+ "const": 1
15
+ },
16
+ "family": {
17
+ "type": "string"
18
+ },
19
+ "ok": {
20
+ "type": "boolean"
21
+ },
22
+ "message": {
23
+ "type": "string"
24
+ },
25
+ "diff": {
26
+ "type": "string"
27
+ }
28
+ },
29
+ "title": "sideby quota teardown --json"
30
+ }
@@ -0,0 +1,203 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/quota.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "accounts"
8
+ ],
9
+ "properties": {
10
+ "schemaVersion": {
11
+ "type": "number",
12
+ "const": 1
13
+ },
14
+ "accounts": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "required": [
19
+ "ref",
20
+ "kind",
21
+ "quota",
22
+ "usage"
23
+ ],
24
+ "properties": {
25
+ "ref": {
26
+ "type": "string"
27
+ },
28
+ "kind": {
29
+ "anyOf": [
30
+ {
31
+ "type": "string",
32
+ "const": "subscription"
33
+ },
34
+ {
35
+ "type": "string",
36
+ "const": "api"
37
+ }
38
+ ]
39
+ },
40
+ "quota": {
41
+ "anyOf": [
42
+ {
43
+ "type": "object",
44
+ "required": [
45
+ "status",
46
+ "windows",
47
+ "observedAt",
48
+ "source"
49
+ ],
50
+ "properties": {
51
+ "status": {
52
+ "type": "string",
53
+ "const": "ok"
54
+ },
55
+ "windows": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "object",
59
+ "required": [
60
+ "label",
61
+ "windowMinutes",
62
+ "usedPercent",
63
+ "resetsAt"
64
+ ],
65
+ "properties": {
66
+ "label": {
67
+ "type": "string"
68
+ },
69
+ "windowMinutes": {
70
+ "type": "number"
71
+ },
72
+ "usedPercent": {
73
+ "type": "number"
74
+ },
75
+ "resetsAt": {
76
+ "type": "string"
77
+ }
78
+ }
79
+ }
80
+ },
81
+ "observedAt": {
82
+ "type": "string"
83
+ },
84
+ "source": {
85
+ "type": "string"
86
+ },
87
+ "plan": {
88
+ "type": "string"
89
+ }
90
+ }
91
+ },
92
+ {
93
+ "type": "object",
94
+ "required": [
95
+ "status",
96
+ "reason"
97
+ ],
98
+ "properties": {
99
+ "status": {
100
+ "type": "string",
101
+ "const": "unavailable"
102
+ },
103
+ "reason": {
104
+ "type": "string"
105
+ },
106
+ "detail": {
107
+ "type": "string"
108
+ }
109
+ }
110
+ }
111
+ ]
112
+ },
113
+ "usage": {
114
+ "anyOf": [
115
+ {
116
+ "type": "object",
117
+ "required": [
118
+ "status",
119
+ "days",
120
+ "sessions",
121
+ "inputTokens",
122
+ "outputTokens",
123
+ "cacheReadTokens",
124
+ "cacheWriteTokens",
125
+ "totalTokens"
126
+ ],
127
+ "properties": {
128
+ "status": {
129
+ "type": "string",
130
+ "const": "ok"
131
+ },
132
+ "days": {
133
+ "type": "number"
134
+ },
135
+ "sessions": {
136
+ "type": "number"
137
+ },
138
+ "inputTokens": {
139
+ "type": "number"
140
+ },
141
+ "outputTokens": {
142
+ "type": "number"
143
+ },
144
+ "cacheReadTokens": {
145
+ "type": "number"
146
+ },
147
+ "cacheWriteTokens": {
148
+ "type": "number"
149
+ },
150
+ "totalTokens": {
151
+ "type": "number"
152
+ },
153
+ "daily": {
154
+ "type": "array",
155
+ "items": {
156
+ "type": "object",
157
+ "required": [
158
+ "date",
159
+ "totalTokens"
160
+ ],
161
+ "properties": {
162
+ "date": {
163
+ "type": "string"
164
+ },
165
+ "totalTokens": {
166
+ "type": "number"
167
+ }
168
+ }
169
+ },
170
+ "description": "Tokens per local day (YYYY-MM-DD), oldest first, days without records as 0."
171
+ },
172
+ "lastActivityAt": {
173
+ "type": "string"
174
+ }
175
+ }
176
+ },
177
+ {
178
+ "type": "object",
179
+ "required": [
180
+ "status",
181
+ "reason"
182
+ ],
183
+ "properties": {
184
+ "status": {
185
+ "type": "string",
186
+ "const": "unavailable"
187
+ },
188
+ "reason": {
189
+ "type": "string"
190
+ },
191
+ "detail": {
192
+ "type": "string"
193
+ }
194
+ }
195
+ }
196
+ ]
197
+ }
198
+ }
199
+ }
200
+ }
201
+ },
202
+ "title": "sideby quota --json"
203
+ }
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: sideby
3
+ description: Use when the user runs, or wants to run, several AI coding accounts (Claude Code, Codex, Grok Build, pi) side by side. Covers installing sideby and setting up a new account ("install sideby", "set up another Claude account", "add cc008", "配置一个 cc00x", "再加一个 Codex 账号"), explaining what accounts share and what stays separate ("what do my accounts share?", "这些账号共享了什么"), seeing accounts, quota and usage, moving on when one hits its 5-hour or weekly limit, adding a short command (alias), and repairing drifted account directories (skills, hooks, rules or settings not shared, wrong symlinks, credential file permissions). Drives the `sideby` CLI with `--json`; the agent does every step except browser sign-in, filling in secrets and starting interactive sessions, which it hands to the user as one command.
4
+ metadata:
5
+ version: "0.2.1"
6
+ requires:
7
+ bins: [sideby, node]
8
+ cliHelp: sideby --help
9
+ ---
10
+
11
+ # sideby
12
+
13
+ `sideby` runs each AI coding account from its own directory (`~/.claude-work`, `~/.codex-api`, ...) and keeps skills, hooks and rules shared with the Main Account (`~/.claude`, `~/.codex`, `~/.grok`, `~/.pi/agent`). Requires Node 22.18+. If `sideby` is not installed, follow `references/setup.md`; `sideby <command> --help` shows examples for `new`, `alias`, `login`, `doctor` and `families`.
14
+
15
+ Do every step you can yourself. Only browser sign-in, secrets and interactive sessions belong to the user: hand each to them as exactly one line to run (in Claude Code they can type `! <command>`), then continue once they say it is done.
16
+
17
+ ## Hard rules
18
+
19
+ - **Never read credential files**: `proxy.env`, `auth.json`, `.claude.json`, or anything under an account directory that may hold a token. Do not `cat`, `grep`, `head`, open or summarize them. `sideby list --json` gives the signed-in email as `identity.email`; that is all you need.
20
+ - **Never sign in for the user.** Give them `sideby login <ref>` as one line to run in their own terminal (Claude Code: `! sideby login <ref>`). OAuth needs their browser and their decision.
21
+ - **Never put a secret on the command line or in chat.** For API accounts, the user edits `proxy.env` themselves.
22
+ - **Never start a Host session from your shell.** `sideby run`, `sideby next` (without `--dry-run`) and `sideby login` open an interactive session; give the user the command instead.
23
+ - **Never switch, rotate or proxy accounts.** sideby does not do it, and you must not work around that by editing config, copying session files or moving credentials. Choosing the next account is the user's call; `sideby next` only recommends.
24
+ - **Say what you change.** Read-only commands first. What the user asked for (the account they asked to create, its short command, the shell line that makes it work) you do, saying what you do. Changes they did not ask for (`doctor --fix` on other accounts, `quota setup`, `app install`) wait until they have seen the change and agreed.
25
+ - Do not edit Host config files (`settings.json`, `config.toml`, symlinks in account directories) by hand when a `sideby` command does the job.
26
+
27
+ ## Output and exit codes
28
+
29
+ - Every `--json` output has `schemaVersion: 1`. On an error it is `{ "schemaVersion": 1, "error": "<what to do next>", "code": "<reason>" }`; `code` is `usage` for a malformed command line.
30
+ - Exit codes: `0` done, `1` failed or found a `fail` problem, `2` malformed command line, `10` **needs the user's confirmation**. `run`, `next` and `login` return the Host's own exit code once it starts.
31
+ - On `10`: show the user the change the command printed, ask, and only after a clear yes run the same command again with `--yes` added. Never add `--yes` on your own.
32
+
33
+ ## What do you want to do
34
+
35
+ Account refs are `<family>:<name>`; a bare `<name>` works only when it is unique. Families: `claude`, `codex`, `grok`, `pi`.
36
+
37
+ | The user wants to | Run | Then read |
38
+ |---|---|---|
39
+ | Install sideby, or set up a new account ("add cc008") | `sideby --version`, `sideby list --json`, `sideby new <family> --next --json` | `references/setup.md` |
40
+ | Know what accounts share and what stays separate | `sideby families <family> --json` | `references/sharing.md` |
41
+ | See accounts, health, quota and usage | `sideby list --json`, `sideby doctor --json`, `sideby quota --json` | `references/diagnose.md` |
42
+ | Repair drift or permissions | `sideby doctor [ref] --json`, then `--fix` after they agree | `references/diagnose.md` |
43
+ | Keep working because an account hit its limit | `sideby next <family> --json` | `references/handoff.md` |
44
+ | Create an account with a given name, an API account, or a short command | `sideby new`, `sideby alias add` | `references/accounts.md` |
45
+ | See Claude quota (it shows `not-enabled`) | `sideby quota setup claude` (exits 10) | `references/quota.md` |
46
+ | See everything at once | `sideby ui` (local panel on `127.0.0.1:17420`; `--no-open` prints the address) | — |
47
+ | Start an account | give them `sideby run <ref> [-- host args]` | — |
48
+
49
+ Read only the reference the task needs.
50
+
51
+ ## Launching and the panel
52
+
53
+ `eval "$(sideby shell-init zsh)"` defines one function per account (`sideby-claude-work`) plus the config `aliases`. Users who source a file instead set config `shellInitFile` (for example `{ "zsh": "~/.config/sideby/shell-init.zsh" }`); `new` and `alias add|rm` keep it current, and `sideby shell-init zsh --write` rewrites it. New functions work in a new shell.
54
+
55
+ When a terminal manager such as Orca reopens a pane with a bare `claude --resume <id>` (or `codex resume <id>`, `grok --resume <id>`) and the Host says `No conversation found`, the session lives in another account. Suggest config `"resumeRouting": true` followed by `sideby shell-init --write` (or a new shell with `eval`): `shell-init` then defines Host-named functions that call `sideby resume <family>`, which starts the account holding that session. For a one-off, find it with `ls -d ~/.claude*/projects/*/<id>.jsonl` and run `sideby run <ref> -- --resume <id>`.
56
+
57
+ For someone who would rather double-click than use a terminal, `sideby app install` adds a desktop app (macOS `~/Applications/sideby.app`, Linux app menu) that runs `sideby ui --background`; `sideby ui --stop` stops it and `sideby app uninstall` removes the app. Ask before `app install`: it writes outside sideby's own directories.
58
+
59
+ ## Keeping this skill current
60
+
61
+ If `sideby doctor --json` reports `skill.outdated`, this skill was written for another sideby version. Tell the user to update it with `npx skills add Adonis0123/sideby -g`.
@@ -0,0 +1,31 @@
1
+ # Create accounts and short commands
2
+
3
+ ## Create an account
4
+
5
+ Check the name first: `^[a-z0-9][a-z0-9-]{0,31}$`, and not already taken (`sideby list --json`).
6
+
7
+ ```sh
8
+ sideby new claude work # subscription account: ~/.claude-work
9
+ sideby new claude deepseek --api # API account: ~/.claude-deepseek with a proxy.env template (mode 600)
10
+ sideby new claude 008 --alias cc008 # also adds the short command cc008 to config aliases
11
+ ```
12
+
13
+ Only pass `--alias` when the user wants a short command. To continue their numbering (`cc001`…`cc007` for `claude:001`…`claude:007`), use `sideby new claude --next --json` instead of a name: it picks `008` and `cc008` the same way the panel does (see `setup.md`). An invalid, reserved or taken alias is refused before anything is created (error `code: "alias-invalid"`). If `alias.added` is false in `--json`, the account exists but the alias is missing: tell the user the message, do not edit the config by hand.
14
+
15
+ Then:
16
+
17
+ - **Subscription account**: tell the user to run `sideby login claude:work` in their own terminal (for pi, `sideby login pi:<name>` starts pi; then they type `/login`). Do not run it for them.
18
+ - **API account**: tell the user to open the `proxy.env` path printed by `new` in their editor and fill in the values. Do not read or write it yourself. It then shows `login: "not-needed"`.
19
+ - **pi**: a `proxy.env` in a pi account only loads provider keys; the account stays a subscription account and still needs `/login`.
20
+ - Afterwards: `sideby doctor <ref> --json` to confirm the new account is healthy, then the user starts it with `sideby run <ref>`.
21
+
22
+ ## Short commands (aliases)
23
+
24
+ For an account that already exists: `sideby alias add <short> <ref> --json`.
25
+
26
+ To start one account with fixed Host arguments, such as another model, put them after `--`: `sideby alias add pi-kimi pi:main --json -- --model kimi-coding/k3`. It is the same account (same login, same sessions), not a new one; do not create an account per model. Only `sideby run <short>` adds the arguments.
27
+
28
+ - `status: "exists"` means it was already there.
29
+ - A refusal names the next step (`sideby alias rm <short>` first).
30
+ - Entry points that need environment variables are not aliases: leave them in the user's shell rc.
31
+ - Do not edit `aliases` in the config by hand.
@@ -0,0 +1,47 @@
1
+ # Diagnose and repair
2
+
3
+ ## Diagnose
4
+
5
+ Start read-only:
6
+
7
+ ```sh
8
+ sideby list --json # accounts: ref, family, kind (subscription|api), dir, login, identity.email, model, hostInstalled, problems
9
+ sideby doctor --json # findings: level ok|warn|fail, account, item, code, message, hint, fixable
10
+ sideby quota --json # per account: quota windows (5h, 7d, usedPercent, resetsAt, observedAt) and 7-day tokens
11
+ sideby plugins --json # loaded plugins (setting names only, never values) and load errors
12
+ ```
13
+
14
+ Narrow with an account or family: `sideby doctor claude:work --json`, `sideby doctor codex --json`, `sideby quota work --json`. On an ambiguity error, use the full ref from the candidates listed.
15
+
16
+ Shared Items the Main Account does not have are skipped: no Finding, not counted in `shared`. A directory such as `~/.claude-code-router` that holds neither `proxy.env` nor any Shared Item is not listed as an account.
17
+
18
+ | Signal | Meaning | What to do |
19
+ |---|---|---|
20
+ | `fail` / `warn` with `fixable: true` | Safe repair exists | Offer `doctor --fix` (see Repair) |
21
+ | `fixable: false` with a `hint` | sideby will not touch it on purpose (real file where a link belongs, API account item) | Show the hint; the user decides |
22
+ | `warn` `link.other-target` | The link resolves, but not to the Main Account's item; often deliberate | Mention it; change nothing unless the user asks |
23
+ | `fail` `link.dangling` | The link points at nothing | Show the hint (`ls -l <path>`); the user decides how to repair it |
24
+ | `fail` `symlink-forbidden` without `fixable` | The Host needs a real file here, but the link points somewhere other than the Main Account | Show the hint; sideby will not replace a link it did not create |
25
+ | credential item, mode not 600 | `proxy.env`, `auth.json`, `.claude.json` readable by others | `--fix` resets the mode to 600 |
26
+ | `warn` `skill.outdated` (in `general`) | The installed sideby skill is for another sideby version | Tell the user to run `npx skills add Adonis0123/sideby -g` |
27
+ | name looks like a backup (`bak`, `backup`, `old`, `tmp`) | A stray directory was picked up as an account | Suggest adding its ref to `ignore` in `${XDG_CONFIG_HOME:-~/.config}/sideby/config.json` |
28
+ | `login: "not-needed"` (`key` in `sideby list`) | API account; it authenticates with `proxy.env` | Nothing to do |
29
+ | `problems` on an account in `list --json` | A plugin failed while reading it (for example a settings file that is not valid JSON) | Show the message; the account itself still works |
30
+ | quota `unavailable` / `not-enabled` | Claude quota source is off | Offer `sideby quota setup claude` |
31
+ | quota `unavailable` / `no-session` | No session since the source was enabled | Ask the user to start one session with that account |
32
+ | quota `unavailable` / `no-source` | Grok, pi: the Host has no public source | Nothing to fix |
33
+ | quota `unavailable` / `api-account` | API accounts have no quota | Nothing to fix |
34
+ | quota `unavailable` / `unrecognized` | Host changed its file format | Report it; suggest filing an issue with the Host version |
35
+ | host not installed | Accounts exist but the CLI is missing | Point to the Host's install docs; do not install it unasked |
36
+
37
+ Quota is only as fresh as each account's last session; `observedAt` says when it was recorded. A window whose `resetsAt` has passed has reset.
38
+
39
+ ## Repair
40
+
41
+ 1. Run `sideby doctor [ref] --json` and show the user every finding you plan to fix, grouped by account.
42
+ 2. After the user agrees, run `sideby doctor [ref] --fix`, then `sideby doctor [ref] --json` again and report what is still open.
43
+ 3. `--force` is only for `json-key` items (for example `.claude.json#mcpServers`) when a fix would remove entries the account already has. Never add `--force` without telling the user exactly which entries would disappear.
44
+
45
+ `--fix` never replaces a real file with a link, never re-points an existing symlink (wrong or dangling links are only reported), never writes through a link into the Main Account, and never changes credential contents. Findings it skips need a human decision; explain the hint, do not work around it with `rm` or `ln`.
46
+
47
+ `doctor` exits 1 only when a `fail` finding is left; warnings alone exit 0.
@@ -0,0 +1,41 @@
1
+ # Handoff: keep working on another account
2
+
3
+ Use this when the user says an account hit its 5-hour or weekly limit ("usage limit reached", "rate limited", "resets at …") and wants to keep working, or asks which account has room. sideby recommends the account of the same family with the lowest Quota Pressure (the fullest window that has not reset yet). It never switches by itself; the user starts the next account.
4
+
5
+ ## Steps
6
+
7
+ 1. Run `sideby next <family> --json` (`claude` or `codex`). It only recommends; it starts nothing.
8
+ 2. Tell the user the pick and why, from `pick` and `accounts`:
9
+
10
+ | `state` | Meaning | Can be picked |
11
+ |---|---|---|
12
+ | `ready` | Subscription account with room; `pressure` is its fullest live window in percent | Yes, lowest `pressure` first |
13
+ | `unknown` | No quota data yet (no session since quota was turned on, or Claude quota is off) | Yes, after `ready` |
14
+ | `api` | API account, pay per use | Only with `--include-api` |
15
+ | `full` | A live window is at 85% or more; `resetsAt` is when it is usable again | No |
16
+ | `logged-out` | Needs `sideby login <ref>` | No |
17
+
18
+ Each entry's `observedAt` says when its quota was recorded. If `hasQuota` is `false`, no account has quota data: the pick is only a guess, so say so and suggest turning quota on (see the routing table in SKILL.md) or letting the user choose.
19
+ 3. Give the user the command to run in their own terminal: `sideby next <family>` (starts the pick) or `sideby run <pick>`. Host arguments go after `--`. Do not run it yourself.
20
+ 4. Offer a handoff note: the new session starts empty, because each account keeps its own sessions. Write a short note the user can paste into it: the goal, what is done, what is in progress, the files involved, and the next step.
21
+
22
+ ## When nothing can be picked
23
+
24
+ `pick` is `null` and the exit code is 1:
25
+
26
+ - Every account `full`: tell the user `earliestReset.ref` comes back at `earliestReset.at`.
27
+ - Accounts `logged-out`: the user can sign in with `sideby login <ref>`.
28
+ - Only `api` left: ask whether they want to pay per use before suggesting `sideby next <family> --include-api`.
29
+
30
+ ## Other answers
31
+
32
+ - Error `code: "no-quota-source"` (Grok, pi): the Host publishes no quota. The message lists the family's accounts; let the user choose one for `sideby run <ref>`.
33
+ - Error `code: "no-accounts"`: the family has no account yet; see creating accounts.
34
+ - Many `unknown` Claude accounts: Claude quota may be off. `sideby quota --json` shows `not-enabled`; the one-time setup turns it on.
35
+ - Host arguments the user wants (another model, say) go after `--`: `sideby next claude -- --model opus`.
36
+ - Quota is only as fresh as each account's last session. Do not promise an account has room; say what the data shows and when it was recorded.
37
+
38
+ ## Never
39
+
40
+ - Switch accounts by editing config or environment, copy session files between account directories, or read any credential.
41
+ - Start a session for the user.
@@ -0,0 +1,14 @@
1
+ # Claude quota
2
+
3
+ Claude quota needs a one-time change to `~/.claude/settings.json`: the status line command becomes `sideby statusline-tap --orig-b64 <base64 of the original command>`. Claude Code then hands each refresh's official `rate_limits` (5-hour and 7-day used percent and reset time) to sideby, which caches them per account. Nothing is sent anywhere.
4
+
5
+ 1. sideby must be installed globally (`npm i -g sideby`), because Claude Code runs the wrapper on every status line refresh. Setup is refused when `sideby` is missing from PATH or comes from the npx cache; tell the user to install it rather than working around it.
6
+ 2. Run `sideby quota setup claude`. It prints the diff, changes nothing and exits **10**: show the diff to the user.
7
+ 3. Only after the user approves, run `sideby quota setup claude --yes`.
8
+ 4. To undo: `sideby quota teardown claude`. It restores the file byte for byte only if nothing changed since setup. If it refuses, show its diff and tell the user to set `statusLine.command` back to the original command (the base64 after `--orig-b64`), or delete `statusLine` if there was none.
9
+
10
+ Accounts with their own (not linked) `settings.json` show quota `not-enabled` until that file's status line is wrapped the same way; tell the user instead of editing it.
11
+
12
+ After setup, each account shows quota once it has had one session with a reply. Codex quota needs no setup: sideby reads it from Codex's own session files.
13
+
14
+ Usage (7-day tokens) is read by sideby itself from Claude Code and Codex local records; no ccusage is needed. Grok and pi have no quota or usage source.
@@ -0,0 +1,31 @@
1
+ # Install sideby and set up an account
2
+
3
+ For "install sideby", "set up another Claude account", "add cc008", "配置一个 cc00x". Do each step yourself unless it says **user**; give the user that step as exactly one line (in Claude Code: `! <command>`) and continue when they say it is done.
4
+
5
+ 1. **Node and sideby.** `node --version` must be 22.18 or newer; otherwise tell the user to upgrade Node and stop. `sideby --version`; when it is missing, run `npm i -g sideby` (Claude quota and shell functions need the global install, not `npx`).
6
+ 2. **This skill.** If it was not installed with `npx skills add Adonis0123/sideby -g`, install it that way so it stays current; `sideby doctor` warns when it is for another version.
7
+ 3. **Hosts and accounts.** `sideby list --json`. `families[].installed: false` means that Host CLI is not on PATH: give the user its `installUrl` and stop; never install a Host unasked. No `<family>:main` in `accounts` means the Host has never run: ask the user to start it once (for example `claude`), because `new` builds on the Main Account.
8
+ 4. **What it will share.** `sideby families <family> --json`, then tell the user in a sentence or two (see `sharing.md`): skills, hooks, rules and settings come from the Main Account; sign-in, sessions and history are the new account's own.
9
+ 5. **Create.**
10
+ - The user gave no name, or said "cc00x" / "the next one": `sideby new <family> --next --json`. It picks the next number (`008` after `001`…`007`) and, when existing short commands show a pattern (`cc007` for `claude:007`), adds the next one (`cc008`). Read `suggestion`: `aliasProblem` means that short command was taken and left out; tell the user.
11
+ - The user gave a name: `sideby new <family> <name> --json`; a short command they named: add `--alias <short>`.
12
+ - An API account (DeepSeek, a gateway, …): add `--api`.
13
+ - A short command the user did not ask for and no pattern suggests: none. Do not invent a prefix.
14
+ 6. **user: sign in or fill in the key.**
15
+ - Subscription account: `sideby login <ref>`. It opens the Host's sign-in in their browser. For pi it starts pi; they type `/login`.
16
+ - API account: they open the `proxy.env` path that `new` printed and fill in the values. Never read or write it, and never ask for the key in chat.
17
+ 7. **Short command in new terminals.** If `~/.config/sideby/config.json` has no `shellInitFile`, and `~/.zshrc` (bash: `~/.bashrc`) has no line containing `sideby shell-init`, say so and append `eval "$(sideby shell-init zsh)"` (or `bash`). It takes effect in new terminals. Skip this when the user wanted no short command.
18
+ 8. **Verify.** `sideby doctor <ref> --json` should report no `fail`; fix only the new account with `sideby doctor <ref> --fix`. After the user signed in, `sideby list --json` shows `login: "logged-in"` for it.
19
+ 9. **Optional, Claude Code:** for quota in `sideby quota` and the panel, follow `quota.md` (it needs the user's yes).
20
+
21
+ Finish with how to start it: the short command in a new terminal (`cc008`), or `sideby run <ref>`; and `sideby ui` to see every account's quota.
22
+
23
+ ## When a step fails
24
+
25
+ | Result | Do |
26
+ |---|---|
27
+ | `new` exit 1, `code: "alias-invalid"` | Nothing was created. Pick another short command with the user, or leave `--alias` out. |
28
+ | `new` says the directory exists | The account is already there: `sideby list --json`, then continue from step 6. |
29
+ | `new` says the Main Account is missing | Step 3: the user starts the Host once. |
30
+ | `npm i -g` fails with `EACCES` | npm's global directory is not writable; tell the user to use a Node version manager (nvm, fnm) rather than `sudo`. |
31
+ | `doctor` reports `link.real-file` | The account already had its own file there; show the hint, do not move it without the user. |
@@ -0,0 +1,17 @@
1
+ # What accounts share
2
+
3
+ Answer from `sideby families [family] --json`, not from memory: it covers plugin families and the user's own `extraSharedItems`. Each `shared[]` entry has `path`, `mode` and `meaning`, a sentence you can quote.
4
+
5
+ - **Shared** (one copy, from the Main Account): `link` items. A change in the Main Account reaches every account at once.
6
+ - **Kept equal**: `copy` and `link-or-copy` items, a subscription account's `local-if-api` item, and the one key of a `json-key` item (Claude's MCP servers in `.claude.json`). `sideby doctor --fix` brings them back in line after the Main Account changes.
7
+ - **The account's own**: `local` items (copied once, then theirs), an API account's `local-if-api` item (it starts as a copy, so its endpoint and model never change the Main Account's), and `info` items such as `auth.json` (sign-in; never shared, never read).
8
+ - **Not in the list at all**: sessions, history and everything else in the account directory belong to that account. That is why two accounts can run at the same time.
9
+
10
+ An item the Main Account does not have is skipped: nothing to share, no Finding.
11
+
12
+ To share one more file or directory (a `scripts` folder, a status line script), add it to config `extraSharedItems`, for example `{ "extraSharedItems": { "claude": [{ "path": "scripts", "mode": "link" }] } }` in `~/.config/sideby/config.json`, then run `sideby doctor claude --fix` to link it into every account. Keep the user's other config keys; never add a path with `..` or an absolute path.
13
+
14
+ Two answers people often need:
15
+
16
+ - "Will my new account have my MCP servers?" Claude Code: yes, `new` copies the `mcpServers` entry and `doctor --fix` keeps it equal later; OAuth servers (GitHub, Figma) still need each account to authorize once. Codex: yes for subscription accounts, through the linked `config.toml`.
17
+ - "Will it see my old sessions?" No. Sessions stay in the account that made them; `sideby run <old-account> -- --resume` reopens them there.