playmaker-cli 0.5.1__tar.gz → 0.6.0__tar.gz

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 (34) hide show
  1. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/CHANGELOG.md +42 -0
  2. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/PKG-INFO +55 -12
  3. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/README.md +52 -9
  4. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/pyproject.toml +4 -2
  5. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/skills/playmaker-coach/SKILL.md +12 -7
  6. playmaker_cli-0.6.0/src/playmaker/agents/opencode.py +461 -0
  7. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/cli.py +36 -6
  8. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/quotas.py +160 -0
  9. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/registry.py +2 -0
  10. playmaker_cli-0.6.0/tests/test_opencode.py +430 -0
  11. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_permissions.py +18 -0
  12. playmaker_cli-0.6.0/tests/test_quotas_zai.py +165 -0
  13. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_registry.py +2 -2
  14. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/.gitignore +0 -0
  15. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/LICENSE +0 -0
  16. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/__init__.py +0 -0
  17. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/__main__.py +0 -0
  18. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/agents/__init__.py +0 -0
  19. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/agents/agy.py +0 -0
  20. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/agents/base.py +0 -0
  21. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/agents/claude.py +0 -0
  22. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/agents/codex.py +0 -0
  23. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/agents/gemini.py +0 -0
  24. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/config.py +0 -0
  25. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/notify.py +0 -0
  26. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/state.py +0 -0
  27. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/src/playmaker/watcher.py +0 -0
  28. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/__init__.py +0 -0
  29. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_agy.py +0 -0
  30. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_claude.py +0 -0
  31. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_codex.py +0 -0
  32. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_quotas_antigravity.py +0 -0
  33. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_skill.py +0 -0
  34. {playmaker_cli-0.5.1 → playmaker_cli-0.6.0}/tests/test_state.py +0 -0
@@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.6.0] - 2026-07-27
9
+
10
+ ### Added
11
+
12
+ - **`opencode` agent handler — one lane, ~75 providers.** The ask was z.ai GLM
13
+ support, but playmaker never talks to a model API: it drives agent CLIs. So
14
+ rather than teach the claude handler an `ANTHROPIC_BASE_URL` override — which
15
+ would have *replaced* the Anthropic lane rather than added one — the handler
16
+ wraps [opencode](https://opencode.ai), whose `--model provider/model` already
17
+ reaches GLM (`zai-coding-plan/glm-5.2`), local LMStudio/MLX models, and
18
+ everything else on models.dev. Oneshot via `opencode run --format json`,
19
+ resume via `-s <id>`; every JSONL event carries `sessionID`, so a detached
20
+ dispatch records the id from the first line rather than at completion.
21
+
22
+ Four behaviours worth knowing. opencode resolves its working directory from
23
+ `process.env.PWD`, which `subprocess.Popen(cwd=…)` does not update — left
24
+ alone it ignores `--cwd` and writes into whatever directory the coach was
25
+ sitting in, so the handler passes `--dir` and corrects `PWD`.
26
+ opencode ≥1.18 keeps transcripts in SQLite
27
+ (`opencode.db`), not one file per session, so playmaker writes a pointer at
28
+ `~/.playmaker/opencode/<id>.session` and reads the `session`/`message`/`part`
29
+ tables live — which keeps `thread --follow` current rather than frozen.
30
+ Cost comes from opencode's own per-session accounting rather than the stream,
31
+ because `run --format json` can exit before its final `step_finish`
32
+ ([opencode#26855](https://github.com/anomalyco/opencode/issues/26855)).
33
+ And `[agents.opencode] model` matters more than the usual `--model` default:
34
+ left unset, opencode falls back to whatever its own `opencode.json` says,
35
+ which is typically the model you last picked interactively rather than the
36
+ one you meant to dispatch to.
37
+
38
+ Permissions follow agy, for the same reason: `--auto` is opencode's only
39
+ lever, so a detached run either auto-approves or comes back having done
40
+ nothing. `yolo` defaults to `true`; narrow it with the `permission` block in
41
+ your own opencode.json, which `--auto` still honours for denies.
42
+ - **`zai` quota probe** — GLM Coding Plan windows (5-hour, weekly, and the
43
+ monthly MCP tool pool) from `api.z.ai/api/monitor/usage/quota/limit`, keyed
44
+ off the credential opencode already wrote to its `auth.json`, so playmaker
45
+ still stores no secret of its own. Reported as its own provider rather than
46
+ under `opencode`, because the quota belongs to the plan — an opencode lane
47
+ pointed at a local model spends nothing here. Degrades to *unsupported*, not
48
+ an error row, when no Z.ai credential exists.
49
+
8
50
  ## [0.5.1] - 2026-07-27
9
51
 
10
52
  ### Fixed
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: playmaker-cli
3
- Version: 0.5.1
4
- Summary: Playing-coach CLI for orchestrating Claude Code, Codex and Antigravity sub-agents in parallel.
3
+ Version: 0.6.0
4
+ Summary: Playing-coach CLI for orchestrating Claude Code, Codex, Antigravity and opencode sub-agents in parallel.
5
5
  Project-URL: Homepage, https://github.com/vladsafedev/playmaker
6
6
  Project-URL: Repository, https://github.com/vladsafedev/playmaker
7
7
  Project-URL: Issues, https://github.com/vladsafedev/playmaker/issues
8
8
  Author-email: Vladislav Shulyugin <vladislav.shulyugin@gmail.com>
9
9
  License-Expression: MIT
10
10
  License-File: LICENSE
11
- Keywords: agents,ai,antigravity,claude,claude-code,cli,codex,gemini,orchestration,subagents
11
+ Keywords: agents,ai,antigravity,claude,claude-code,cli,codex,gemini,glm,opencode,orchestration,subagents
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Environment :: Console
14
14
  Classifier: Intended Audience :: Developers
@@ -28,11 +28,11 @@ Description-Content-Type: text/markdown
28
28
  # playmaker
29
29
 
30
30
  [![CI](https://github.com/vladsafedev/playmaker/actions/workflows/ci.yml/badge.svg)](https://github.com/vladsafedev/playmaker/actions/workflows/ci.yml)
31
- [![PyPI](https://img.shields.io/pypi/v/playmaker-cli.svg)](https://pypi.org/project/playmaker-cli/)
32
- [![Python](https://img.shields.io/pypi/pyversions/playmaker-cli.svg)](https://pypi.org/project/playmaker-cli/)
31
+ [![PyPI](https://img.shields.io/pypi/v/playmaker-cli.svg?cacheSeconds=3600)](https://pypi.org/project/playmaker-cli/)
32
+ [![Python](https://img.shields.io/pypi/pyversions/playmaker-cli.svg?cacheSeconds=3600)](https://pypi.org/project/playmaker-cli/)
33
33
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
34
34
 
35
- **Run Claude Code, Codex and Antigravity as parallel sub-agents from one terminal — and spend three separate quotas instead of one.**
35
+ **Run Claude Code, Codex, Antigravity and opencode as parallel sub-agents from one terminal — and spend separate quotas instead of one.**
36
36
 
37
37
  You stay in your Claude Code session doing the part only you can do. `playmaker`
38
38
  fans the rest out to other agent CLIs as detached processes, tracks them,
@@ -74,10 +74,12 @@ in one serial session:
74
74
  1. **Wall-clock speed.** A task that decomposes into 3–5 independent
75
75
  work-streams (schema, backend, frontend, tests, docs) finishes 2–4× faster
76
76
  when each stream runs as its own parallel agent.
77
- 2. **Provider arbitrage.** Codex and Antigravity quotas are entirely separate
78
- pools from your Anthropic plan. Every slice you hand them is capacity your
79
- main session never spends — and Antigravity's roster includes Claude
80
- Sonnet/Opus, so even Claude-quality work can run on Google's pool.
77
+ 2. **Provider arbitrage.** Codex, Antigravity and opencode quotas are entirely
78
+ separate pools from your Anthropic plan. Every slice you hand them is
79
+ capacity your main session never spends — and Antigravity's roster includes
80
+ Claude Sonnet/Opus, so even Claude-quality work can run on Google's pool.
81
+ `opencode` widens this the most: one CLI fronting ~75 providers, from a z.ai
82
+ GLM coding plan to models running locally on your own machine.
81
83
  3. **Bucket arbitrage inside one plan.** Headless `claude -p` draws on the same
82
84
  subscription as your interactive session, but per-model weekly buckets are
83
85
  separate — dispatching `--model sonnet` spends Sonnet's usually-idle bucket
@@ -134,6 +136,16 @@ The other agents differ, because their CLIs do:
134
136
  either auto-approves or comes back having done nothing. It therefore
135
137
  defaults to `yolo = true`; layer `sandbox = true` on top for agy's own
136
138
  terminal restrictions.
139
+ - **opencode** is the same story: its only lever is `--auto`, so it also
140
+ defaults to `yolo = true`. The granular control lives in opencode's own
141
+ config rather than in playmaker — and `--auto` still honours it, because it
142
+ auto-approves only what you have not explicitly denied:
143
+
144
+ ```jsonc
145
+ // ~/.config/opencode/opencode.json
146
+ { "permission": { "edit": "allow", "bash": "allow", "webfetch": "deny" } }
147
+ ```
148
+
137
149
  - **gemini** (legacy) runs with `--yolo`.
138
150
 
139
151
  ## Install
@@ -170,6 +182,7 @@ playmaker agents # which agent CLIs are reachable
170
182
  | **Claude Code** | `npm i -g @anthropic-ai/claude-code` | `--model sonnet` / `opus` / `haiku` |
171
183
  | **Codex CLI** | `npm i -g @openai/codex` | the model roster depends on your plan; omit `--model` to use the account default |
172
184
  | **Antigravity (`agy`)** | bundled with [Antigravity](https://antigravity.google) | `--model claude-opus-4-6-thinking` — the roster moves, so read it from `agy models` |
185
+ | **opencode** | `brew install sst/tap/opencode` (or see [opencode.ai](https://opencode.ai)) | `--model provider/model`, e.g. `zai-coding-plan/glm-5.2`; roster from `opencode models`, providers from `opencode auth login` |
173
186
  | **Gemini CLI** (legacy) | `npm i -g @google/gemini-cli` | still supported, superseded by `agy` |
174
187
 
175
188
  At least one is required; `playmaker agents` tells you which it can see.
@@ -233,9 +246,11 @@ flowchart LR
233
246
  P --> A1["claude -p<br/>--model sonnet"]
234
247
  P --> A2["codex exec"]
235
248
  P --> A3["agy -p"]
249
+ P --> A4["opencode run<br/>-m zai-coding-plan/glm-5.2"]
236
250
  A1 --> S[("state.db<br/>outputs/ + logs/")]
237
251
  A2 --> S
238
252
  A3 --> S
253
+ A4 --> S
239
254
  S -->|"list / thread / summary"| C
240
255
  S -.->|"batch drained"| N["one ping"]
241
256
  ```
@@ -250,6 +265,7 @@ bookkeeping in between.
250
265
  ├── agents/ optional agent profile markdown (claude.md, codex.md, agy.md…)
251
266
  ├── outputs/ final output per session — .md, or .json if the agent returned JSON
252
267
  ├── logs/ subprocess stdout for detached runs
268
+ ├── opencode/ pointer per opencode session (its transcript lives in SQLite)
253
269
  └── quotas.json latest capacity snapshot
254
270
  ```
255
271
 
@@ -261,6 +277,7 @@ and locates the session file the tool writes locally. Empirically:
261
277
  | Claude | `~/.claude/projects/<cwd-with-slashes-as-dashes>/<id>.jsonl` |
262
278
  | Codex | `~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<ts>-<thread_id>.jsonl` |
263
279
  | Antigravity | `~/.gemini/antigravity-cli/brain/<conversation-id>/.system_generated/logs/transcript_full.jsonl` |
280
+ | opencode | SQLite — `~/.local/share/opencode/opencode.db` (`session` / `message` / `part`); playmaker keeps a pointer at `~/.playmaker/opencode/<id>.session` |
264
281
  | Gemini | `~/.gemini/tmp/<cwd-basename>/chats/session-<ts>-<short_id>.{json,jsonl}` |
265
282
 
266
283
  `thread` and `summary` normalize all of them into the same turn list, so every
@@ -276,6 +293,21 @@ dispatch; and a wrong `--model` is a silent failure on both **codex** (reports
276
293
  `turn.failed` while exiting 0) and **agy** (runs its default model instead) —
277
294
  playmaker turns both into real errors.
278
295
 
296
+ **opencode** deserves its own note, because one CLI is many providers. Models
297
+ are `provider/model` strings from `opencode models`, and if you don't pass
298
+ `--model` opencode falls back to the default in *its* config — often whatever
299
+ you last picked interactively. Set the lane's default once:
300
+
301
+ ```toml
302
+ [agents.opencode]
303
+ model = "zai-coding-plan/glm-5.2"
304
+ ```
305
+
306
+ It also has agy's working-directory problem in a different costume: opencode
307
+ reads `process.env.PWD`, which a subprocess `cwd` does not update, so left
308
+ alone it would ignore `--cwd` and write into the directory *you* were standing
309
+ in. playmaker passes `--dir` and fixes up `PWD`, so `--cwd` means what it says.
310
+
279
311
  ## Notifications
280
312
 
281
313
  Every detached dispatch pings when it finishes. With
@@ -321,11 +353,16 @@ Antigravity (agy)
321
353
  Gemini weekly ███████████████████░ 95% left
322
354
  Claude/GPT 5h ██████████████████░░ 90% left resets in 2h 05m
323
355
  Claude/GPT weekly ██████████████░░░░░░ 70% left resets in 5d 1h
356
+
357
+ Z.ai (GLM, via opencode) Max
358
+ Session ████████████████████ 100% left
359
+ Weekly ███████████████████░ 95% left resets in 1d 11h
360
+ MCP tools ███████████████████░ 99% left resets in 25d 11h
324
361
  ```
325
362
 
326
363
  The `Weekly` and `Sonnet` rows above are the point: they are **separate
327
- buckets**. So is every agy row. Routing a subtask is choosing which of them to
328
- spend.
364
+ buckets**. So is every agy row, and so is the whole Z.ai block. Routing a
365
+ subtask is choosing which of them to spend.
329
366
 
330
367
  - **Claude** — OAuth usage API; token from the Claude Code Keychain entry.
331
368
  - **Codex** — ChatGPT `wham/usage` API; token from `~/.codex/auth.json`.
@@ -336,6 +373,12 @@ spend.
336
373
  `retrieveUserQuota` on the Antigravity backend, which surfaces only coarse
337
374
  Gemini buckets and is flagged *daemon offline*. Approach ported from
338
375
  [steipete/CodexBar](https://github.com/steipete/CodexBar).
376
+ - **Z.ai** — GLM Coding Plan usage API; key from opencode's
377
+ `~/.local/share/opencode/auth.json` (or `$ZAI_API_KEY`). Reported as its own
378
+ provider because the quota belongs to the plan, not to opencode — an opencode
379
+ lane pointed at a local model spends nothing here. Shows *unsupported* rather
380
+ than an error when no Z.ai credential exists. `MCP tools` is the monthly
381
+ web-search/reader pool, not inference.
339
382
 
340
383
  Reading these at *model* granularity is the point: they are the load-balancing
341
384
  input the coach skill uses to route each subtask.
@@ -1,11 +1,11 @@
1
1
  # playmaker
2
2
 
3
3
  [![CI](https://github.com/vladsafedev/playmaker/actions/workflows/ci.yml/badge.svg)](https://github.com/vladsafedev/playmaker/actions/workflows/ci.yml)
4
- [![PyPI](https://img.shields.io/pypi/v/playmaker-cli.svg)](https://pypi.org/project/playmaker-cli/)
5
- [![Python](https://img.shields.io/pypi/pyversions/playmaker-cli.svg)](https://pypi.org/project/playmaker-cli/)
4
+ [![PyPI](https://img.shields.io/pypi/v/playmaker-cli.svg?cacheSeconds=3600)](https://pypi.org/project/playmaker-cli/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/playmaker-cli.svg?cacheSeconds=3600)](https://pypi.org/project/playmaker-cli/)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
 
8
- **Run Claude Code, Codex and Antigravity as parallel sub-agents from one terminal — and spend three separate quotas instead of one.**
8
+ **Run Claude Code, Codex, Antigravity and opencode as parallel sub-agents from one terminal — and spend separate quotas instead of one.**
9
9
 
10
10
  You stay in your Claude Code session doing the part only you can do. `playmaker`
11
11
  fans the rest out to other agent CLIs as detached processes, tracks them,
@@ -47,10 +47,12 @@ in one serial session:
47
47
  1. **Wall-clock speed.** A task that decomposes into 3–5 independent
48
48
  work-streams (schema, backend, frontend, tests, docs) finishes 2–4× faster
49
49
  when each stream runs as its own parallel agent.
50
- 2. **Provider arbitrage.** Codex and Antigravity quotas are entirely separate
51
- pools from your Anthropic plan. Every slice you hand them is capacity your
52
- main session never spends — and Antigravity's roster includes Claude
53
- Sonnet/Opus, so even Claude-quality work can run on Google's pool.
50
+ 2. **Provider arbitrage.** Codex, Antigravity and opencode quotas are entirely
51
+ separate pools from your Anthropic plan. Every slice you hand them is
52
+ capacity your main session never spends — and Antigravity's roster includes
53
+ Claude Sonnet/Opus, so even Claude-quality work can run on Google's pool.
54
+ `opencode` widens this the most: one CLI fronting ~75 providers, from a z.ai
55
+ GLM coding plan to models running locally on your own machine.
54
56
  3. **Bucket arbitrage inside one plan.** Headless `claude -p` draws on the same
55
57
  subscription as your interactive session, but per-model weekly buckets are
56
58
  separate — dispatching `--model sonnet` spends Sonnet's usually-idle bucket
@@ -107,6 +109,16 @@ The other agents differ, because their CLIs do:
107
109
  either auto-approves or comes back having done nothing. It therefore
108
110
  defaults to `yolo = true`; layer `sandbox = true` on top for agy's own
109
111
  terminal restrictions.
112
+ - **opencode** is the same story: its only lever is `--auto`, so it also
113
+ defaults to `yolo = true`. The granular control lives in opencode's own
114
+ config rather than in playmaker — and `--auto` still honours it, because it
115
+ auto-approves only what you have not explicitly denied:
116
+
117
+ ```jsonc
118
+ // ~/.config/opencode/opencode.json
119
+ { "permission": { "edit": "allow", "bash": "allow", "webfetch": "deny" } }
120
+ ```
121
+
110
122
  - **gemini** (legacy) runs with `--yolo`.
111
123
 
112
124
  ## Install
@@ -143,6 +155,7 @@ playmaker agents # which agent CLIs are reachable
143
155
  | **Claude Code** | `npm i -g @anthropic-ai/claude-code` | `--model sonnet` / `opus` / `haiku` |
144
156
  | **Codex CLI** | `npm i -g @openai/codex` | the model roster depends on your plan; omit `--model` to use the account default |
145
157
  | **Antigravity (`agy`)** | bundled with [Antigravity](https://antigravity.google) | `--model claude-opus-4-6-thinking` — the roster moves, so read it from `agy models` |
158
+ | **opencode** | `brew install sst/tap/opencode` (or see [opencode.ai](https://opencode.ai)) | `--model provider/model`, e.g. `zai-coding-plan/glm-5.2`; roster from `opencode models`, providers from `opencode auth login` |
146
159
  | **Gemini CLI** (legacy) | `npm i -g @google/gemini-cli` | still supported, superseded by `agy` |
147
160
 
148
161
  At least one is required; `playmaker agents` tells you which it can see.
@@ -206,9 +219,11 @@ flowchart LR
206
219
  P --> A1["claude -p<br/>--model sonnet"]
207
220
  P --> A2["codex exec"]
208
221
  P --> A3["agy -p"]
222
+ P --> A4["opencode run<br/>-m zai-coding-plan/glm-5.2"]
209
223
  A1 --> S[("state.db<br/>outputs/ + logs/")]
210
224
  A2 --> S
211
225
  A3 --> S
226
+ A4 --> S
212
227
  S -->|"list / thread / summary"| C
213
228
  S -.->|"batch drained"| N["one ping"]
214
229
  ```
@@ -223,6 +238,7 @@ bookkeeping in between.
223
238
  ├── agents/ optional agent profile markdown (claude.md, codex.md, agy.md…)
224
239
  ├── outputs/ final output per session — .md, or .json if the agent returned JSON
225
240
  ├── logs/ subprocess stdout for detached runs
241
+ ├── opencode/ pointer per opencode session (its transcript lives in SQLite)
226
242
  └── quotas.json latest capacity snapshot
227
243
  ```
228
244
 
@@ -234,6 +250,7 @@ and locates the session file the tool writes locally. Empirically:
234
250
  | Claude | `~/.claude/projects/<cwd-with-slashes-as-dashes>/<id>.jsonl` |
235
251
  | Codex | `~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<ts>-<thread_id>.jsonl` |
236
252
  | Antigravity | `~/.gemini/antigravity-cli/brain/<conversation-id>/.system_generated/logs/transcript_full.jsonl` |
253
+ | opencode | SQLite — `~/.local/share/opencode/opencode.db` (`session` / `message` / `part`); playmaker keeps a pointer at `~/.playmaker/opencode/<id>.session` |
237
254
  | Gemini | `~/.gemini/tmp/<cwd-basename>/chats/session-<ts>-<short_id>.{json,jsonl}` |
238
255
 
239
256
  `thread` and `summary` normalize all of them into the same turn list, so every
@@ -249,6 +266,21 @@ dispatch; and a wrong `--model` is a silent failure on both **codex** (reports
249
266
  `turn.failed` while exiting 0) and **agy** (runs its default model instead) —
250
267
  playmaker turns both into real errors.
251
268
 
269
+ **opencode** deserves its own note, because one CLI is many providers. Models
270
+ are `provider/model` strings from `opencode models`, and if you don't pass
271
+ `--model` opencode falls back to the default in *its* config — often whatever
272
+ you last picked interactively. Set the lane's default once:
273
+
274
+ ```toml
275
+ [agents.opencode]
276
+ model = "zai-coding-plan/glm-5.2"
277
+ ```
278
+
279
+ It also has agy's working-directory problem in a different costume: opencode
280
+ reads `process.env.PWD`, which a subprocess `cwd` does not update, so left
281
+ alone it would ignore `--cwd` and write into the directory *you* were standing
282
+ in. playmaker passes `--dir` and fixes up `PWD`, so `--cwd` means what it says.
283
+
252
284
  ## Notifications
253
285
 
254
286
  Every detached dispatch pings when it finishes. With
@@ -294,11 +326,16 @@ Antigravity (agy)
294
326
  Gemini weekly ███████████████████░ 95% left
295
327
  Claude/GPT 5h ██████████████████░░ 90% left resets in 2h 05m
296
328
  Claude/GPT weekly ██████████████░░░░░░ 70% left resets in 5d 1h
329
+
330
+ Z.ai (GLM, via opencode) Max
331
+ Session ████████████████████ 100% left
332
+ Weekly ███████████████████░ 95% left resets in 1d 11h
333
+ MCP tools ███████████████████░ 99% left resets in 25d 11h
297
334
  ```
298
335
 
299
336
  The `Weekly` and `Sonnet` rows above are the point: they are **separate
300
- buckets**. So is every agy row. Routing a subtask is choosing which of them to
301
- spend.
337
+ buckets**. So is every agy row, and so is the whole Z.ai block. Routing a
338
+ subtask is choosing which of them to spend.
302
339
 
303
340
  - **Claude** — OAuth usage API; token from the Claude Code Keychain entry.
304
341
  - **Codex** — ChatGPT `wham/usage` API; token from `~/.codex/auth.json`.
@@ -309,6 +346,12 @@ spend.
309
346
  `retrieveUserQuota` on the Antigravity backend, which surfaces only coarse
310
347
  Gemini buckets and is flagged *daemon offline*. Approach ported from
311
348
  [steipete/CodexBar](https://github.com/steipete/CodexBar).
349
+ - **Z.ai** — GLM Coding Plan usage API; key from opencode's
350
+ `~/.local/share/opencode/auth.json` (or `$ZAI_API_KEY`). Reported as its own
351
+ provider because the quota belongs to the plan, not to opencode — an opencode
352
+ lane pointed at a local model spends nothing here. Shows *unsupported* rather
353
+ than an error when no Z.ai credential exists. `MCP tools` is the monthly
354
+ web-search/reader pool, not inference.
312
355
 
313
356
  Reading these at *model* granularity is the point: they are the load-balancing
314
357
  input the coach skill uses to route each subtask.
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "playmaker-cli"
3
- version = "0.5.1"
4
- description = "Playing-coach CLI for orchestrating Claude Code, Codex and Antigravity sub-agents in parallel."
3
+ version = "0.6.0"
4
+ description = "Playing-coach CLI for orchestrating Claude Code, Codex, Antigravity and opencode sub-agents in parallel."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  license = "MIT"
@@ -19,6 +19,8 @@ keywords = [
19
19
  "codex",
20
20
  "antigravity",
21
21
  "gemini",
22
+ "opencode",
23
+ "glm",
22
24
  "subagents",
23
25
  ]
24
26
  classifiers = [
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: playmaker-coach
3
- description: Playing-coach orchestration of Claude/Codex/Antigravity (agy) sub-agents via the `playmaker` CLI and in-session Task sub-agents. Triggered when the user gives a complex multi-component task where decomposition gives >2x parallel speedup (e.g. "build admin dashboard with schema, backend, FE, tests, docs"). NOT triggered for single-file refactor, single bug fix, single component, or simple Q&A — those stay in this thread without delegation.
3
+ description: Playing-coach orchestration of Claude/Codex/Antigravity (agy)/opencode sub-agents via the `playmaker` CLI and in-session Task sub-agents. Triggered when the user gives a complex multi-component task where decomposition gives >2x parallel speedup (e.g. "build admin dashboard with schema, backend, FE, tests, docs"). NOT triggered for single-file refactor, single bug fix, single component, or simple Q&A — those stay in this thread without delegation.
4
4
  ---
5
5
 
6
6
  # playmaker-coach — playing-coach orchestration
7
7
 
8
- Use the `playmaker` CLI as a facade to dispatch sub-tasks to Codex / Antigravity (`agy`) / a sibling Claude, monitor them, read their threads, review their diffs, and feed back. The coach (this thread) does its own portion of the work in parallel.
8
+ Use the `playmaker` CLI as a facade to dispatch sub-tasks to Codex / Antigravity (`agy`) / opencode / a sibling Claude, monitor them, read their threads, review their diffs, and feed back. The coach (this thread) does its own portion of the work in parallel.
9
9
 
10
10
  > **`agy` (Antigravity CLI)** does not only serve Google models: alongside the Gemini Flash and Pro tiers, `agy models` carries **Claude Sonnet and Opus** and a **GPT-OSS** mid-tier. Opus via agy runs on *Google's* quota pool — top-tier Claude work that does not touch the Anthropic subscription's scarce Opus weekly bucket: `--model claude-opus-4-6-thinking`.
11
11
  >
@@ -23,7 +23,7 @@ All Claude work — coach, internal sub-agents, external `claude -p` — draws f
23
23
 
24
24
  3. **External dispatch — `playmaker dispatch <agent>`.** Separate OS processes, tracked in playmaker (`list`/`watch`/`thread`/`continue`):
25
25
  - **`claude -p` (sibling Claude):** same subscription. Its key lever is the model bucket — **Sonnet is a separate weekly bucket from Opus**, usually idle while Opus depletes, so default **`--model sonnet`** to spare the scarce Opus bucket (**`--model haiku`** for trivial mechanical work). It **can write files** — playmaker runs it in `acceptEdits`, so it edits and runs commands freely inside `--cwd` and is refused outside it (see §10). Use it over an internal sub-agent when you want a **tracked, detached work-stream** you can monitor/continue independently of the coach's turn.
26
- - **`codex` / `agy`:** each on its own subscription/quota — the right home for **write-heavy** parallel implementation that can leave the Anthropic subscription. `agy` is special: besides Gemini tiers it carries **Claude Sonnet/Opus 4.6 (Thinking)** on Google's pool, so even "must be Claude-quality" work can leave the Anthropic quota.
26
+ - **`codex` / `agy` / `opencode`:** each on its own subscription/quota — the right home for **write-heavy** parallel implementation that can leave the Anthropic subscription. `agy` is special: besides Gemini tiers it carries **Claude Sonnet/Opus 4.6 (Thinking)** on Google's pool, so even "must be Claude-quality" work can leave the Anthropic quota. `opencode` is the widest lane: one CLI over ~75 providers, addressed as `provider/model` — a GLM coding plan (`zai-coding-plan/glm-5.2`), or a model running locally on this machine, which spends **no** subscription quota at all.
27
27
 
28
28
  **Routing cheat-sheet for Claude-side work:**
29
29
 
@@ -32,8 +32,10 @@ All Claude work — coach, internal sub-agents, external `claude -p` — draws f
32
32
  | writes files and the coach integrates the result directly | **internal sub-agent** (Task tool) | in-session, write-capable, returns into context |
33
33
  | is an independent stream you'll monitor / continue separately | **external `dispatch claude --model sonnet`** | tracked & detached; Sonnet's own weekly bucket spares Opus |
34
34
  | is heavy reasoning only the coach can do | **coach** | top-tier Opus, serial |
35
- | is write-heavy and can leave Claude | **codex / agy** | their own quotas |
35
+ | is write-heavy and can leave Claude | **codex / agy / opencode** | their own quotas |
36
36
  | needs top-tier Claude but the Anthropic Opus weekly is precious | **`dispatch agy --model claude-opus-4-6-thinking`** | Opus quality on Google's pool |
37
+ | is bulk work and every subscription is running low | **`dispatch opencode --model zai-coding-plan/glm-5.2`** | a separate GLM plan, untouched by the others |
38
+ | is mechanical and privacy-sensitive, or all quotas are spent | **`dispatch opencode --model <local provider>/<model>`** | runs on this machine; costs no quota, just wall-clock |
37
39
 
38
40
  **Sonnet is your cheap parallel Claude worker** — a separate weekly bucket that usually sits idle while Opus depletes. Reach for it (via `dispatch claude --model sonnet`, or by pointing an internal sub-agent at Sonnet) instead of burning Opus on mid-tier work.
39
41
 
@@ -61,6 +63,7 @@ playmaker quotas --refresh # current capacity, broken out per model
61
63
  - Claude: two non-coach ways to run it — an **internal sub-agent** (Task tool; in-session, write-capable, result returns to the coach) and an **external `claude -p` dispatch** (tracked, detached stream). Both draw on the subscription; the difference is where results land, not cost. See "Execution lanes". Default external Claude to `--model sonnet` — its weekly bucket is separate from Opus and usually idle, so it spares the scarce coach (Opus) bucket.
62
64
  - Antigravity (`agy`): one Google pool split across model families — Gemini Flash tiers for cheap bulk work, Gemini 3.1 Pro for hard Gemini work, **Claude Sonnet/Opus 4.6 (Thinking)** as Anthropic-quality capacity that spends *Google's* quota, GPT-OSS 120B as a spare mid-tier. `playmaker quotas` shows the **full categorized breakdown** — `Gemini 5h` / `Gemini weekly` and `Claude/GPT 5h` / `Claude/GPT weekly`. Two things share a bucket: all Gemini models draw the Gemini bucket, and Claude *and* GPT-OSS share the Claude/GPT bucket. So dispatching Opus 4.6 via agy spends the same `Claude/GPT` bucket as Sonnet or GPT-OSS — watch the `Claude/GPT 5h` window when fanning out several agy-Claude jobs. (This needs agy's local daemon up — normally true when any agy process is running; if `playmaker quotas` tags agy "daemon offline" it fell back to a coarse Gemini-only view.)
63
65
  - Codex: top-tier vs lighter modes (where applicable).
66
+ - Z.ai (GLM): shown as its own provider because the plan is what has the quota, not the CLI — `Session` (5h) and `Weekly` windows plus a monthly `MCP tools` pool that only web-search/reader calls touch. It appears whenever `opencode auth login` has a Z.AI credential, and reads *unsupported* when it doesn't. An `opencode` dispatch pointed at a **local** model spends none of it, so local lanes never show up in this table at all.
64
67
 
65
68
  If `quotas.json` is more than 1h old (or shows errors), say so before relying on the numbers.
66
69
 
@@ -159,6 +162,8 @@ Two exceptions to "always pass `--model`":
159
162
  - **codex** — its model roster depends on the account plan, and an unavailable name fails the whole dispatch (`codex turn failed: … not supported when using Codex with a ChatGPT account`). Omitting `--model` uses whatever that account actually has, which is usually what you want.
160
163
  - **agy** — its own default is a top-tier model, so omitting `--model` on a dispatch meant to be cheap silently spends the expensive bucket. Always pass it here.
161
164
 
165
+ **opencode is `provider/model`, and the default is a trap.** Names look like `zai-coding-plan/glm-5.2` or `lmstudio/qwen/qwen3-coder-30b` — **run `opencode models` and copy a line** rather than writing one from memory; playmaker validates against that roster and fails the dispatch on a name it doesn't contain. Omitting `--model` does *not* fall back to something sensible: it uses whatever is set in the user's own `~/.config/opencode/opencode.json`, which is typically the last model they picked interactively — often a small local one. So for opencode, always pass `--model` unless `[agents.opencode] model` is already set in `~/.playmaker/config.toml`.
166
+
162
167
  **agy prompt discipline:** the agy agent's shell lives in a private scratch directory, not the workspace. playmaker automatically prepends a workspace preamble to every agy dispatch, but reinforce it: word file instructions with paths relative to the workspace root or absolute paths, never "in the current directory".
163
168
 
164
169
  **Bad-model handling (playmaker ≥0.4 does this for you):** a wrong `--model` is the classic silent failure. Codex returns a `turn.failed` while exiting 0 with empty output; agy silently runs its *default* model instead of erroring. playmaker catches both — a codex model/auth failure raises `codex turn failed: …`, and an unknown agy model raises with the valid roster before dispatch. So a dispatch that comes back **failed** with a model message means: fix the `--model` string (for agy, copy it exactly from `agy models`) and re-dispatch. Don't retry the same string.
@@ -230,7 +235,7 @@ If `playmaker dispatch` returns an error (binary missing, auth bad, agent unavai
230
235
  Both Claude lanes are on the subscription, so pick by **where the work lives**, not cost:
231
236
  - **Coach folds the result in directly → internal sub-agent (Task tool).** In-session, write-capable, returns into context. Default choice for "more Claude."
232
237
  - **Independent stream you'll monitor / continue separately → `playmaker dispatch claude --model sonnet`.** Tracked, detached; Sonnet's separate weekly bucket spares Opus.
233
- - **Work that can leave the Claude family → Codex / agy** (their own quotas).
238
+ - **Work that can leave the Claude family → Codex / agy / opencode** (their own quotas, or none at all for a local model).
234
239
 
235
240
  If a dispatch comes back with zero file changes, check `playmaker summary <id>`. Two common causes for Claude: the subtask tried to write outside `--cwd` and was refused (re-dispatch with the right `--cwd`), or the run needed a permission the configured mode doesn't grant — a "I need your permission" answer, not a crash. For **agy** specifically, a "done" with no file changes usually means the files landed in agy's private scratch dir (`~/.gemini/antigravity-cli/scratch/`) — the prompt referred to "the current directory" instead of workspace paths; re-dispatch with explicit paths.
236
241
 
@@ -244,7 +249,7 @@ If a dispatch comes back with zero file changes, check `playmaker summary <id>`.
244
249
  ## Quota awareness
245
250
 
246
251
  - **Read Claude quota at model granularity:** Sonnet weekly and Opus weekly are **independent buckets**. Coach and internal sub-agents on Opus spend the scarce one; Sonnet usually sits idle. Push mid-tier work to Sonnet (an internal sub-agent set to Sonnet, or `dispatch claude --model sonnet`) to spare Opus.
247
- - Read quotas at *model* granularity, not *agent* granularity. For agy, the probe reports four windows — `Gemini 5h/weekly` and `Claude/GPT 5h/weekly`; for Codex, top-tier vs lighter modes.
252
+ - Read quotas at *model* granularity, not *agent* granularity. For agy, the probe reports four windows — `Gemini 5h/weekly` and `Claude/GPT 5h/weekly`; for Codex, top-tier vs lighter modes; for opencode, the quota is reported under the **provider** it is pointed at (`Z.ai`), and a local model reports nothing because it spends nothing.
248
253
  - Skip a *model* if its `*_left` is below ~10%; reroute the subtask to the same agent with a different model, or to a different agent entirely.
249
254
  - If a top-tier `weekly_*_left` is degrading toward the deadline, push as much work as possible to mid- and cheap-tier models on the same provider (which are often nowhere near depleted), instead of switching providers blindly.
250
255
  - agy's **5-hour** window is the one that bites during a fan-out: it "smooths aggregate demand", so a burst of agy dispatches drains `Gemini 5h` or `Claude/GPT 5h` well before the weekly. If a 5h window is low, spread the burst or move some slices to Codex/coach.
@@ -269,7 +274,7 @@ playmaker watch # Rich live TUI of sessions
269
274
 
270
275
  Every command takes `--json` for machine-readable output.
271
276
 
272
- `--model NAME` is forwarded to the agent's native CLI: `claude --model sonnet`, `agy --model claude-opus-4-6-thinking`, `codex -m <whatever that account has>`. Without it the agent CLI uses its own default. Model is stored on the session row, so detached re-runs and `continue` inherit it; `continue --model X` overrides for that one turn.
277
+ `--model NAME` is forwarded to the agent's native CLI: `claude --model sonnet`, `agy --model claude-opus-4-6-thinking`, `codex -m <whatever that account has>`, `opencode -m zai-coding-plan/glm-5.2`. Without it the agent CLI uses its own default. Model is stored on the session row, so detached re-runs and `continue` inherit it; `continue --model X` overrides for that one turn.
273
278
 
274
279
  **The agy roster is not documented here on purpose** — it changes with Antigravity releases, and so does the spelling convention. Run `agy models` and copy a line. At the time of writing it returns bare slugs in the shape `gemini-3.6-flash-{low,medium,high}`, `gemini-3.1-pro-{low,high}`, `claude-sonnet-4-6`, `claude-opus-4-6-thinking`, `gpt-oss-120b-medium` — but treat that as an example of the *shape*, not a list to copy from.
275
280