@lmctl-ai/lmctl 0.2.19 → 0.2.21
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.
- package/dist/cli/index.js +466 -457
- package/dist/cli/ratelimit.d.ts +0 -1
- package/dist/cli/script.js +239 -227
- package/dist/cli/seed-flight.d.ts +2 -0
- package/dist/cli/teamfile-compat.d.ts +25 -0
- package/dist/providers/adapters/agy-adapter.d.ts +2 -1
- package/dist/providers/base-adapter.d.ts +3 -0
- package/dist/providers/config/model-selection-lint.d.ts +0 -1
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/ratelimit/agy.d.ts +21 -0
- package/dist/providers/ratelimit/claude.d.ts +5 -0
- package/dist/providers/ratelimit/codex.d.ts +6 -0
- package/dist/providers/ratelimit/kimi.d.ts +5 -0
- package/dist/providers/ratelimit/schema.d.ts +14 -0
- package/dist/providers/ratelimit-readings.d.ts +1 -16
- package/examples/book-team.lmctl +16 -12
- package/examples/research-team.lmctl +16 -12
- package/examples/review-team.lmctl +17 -12
- package/package.json +2 -3
- package/durable-memory/model_selection.md +0 -381
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
# Model Selection
|
|
2
|
-
|
|
3
|
-
`model=` on a `_MEMBER_` line is a provider-specific model request.
|
|
4
|
-
|
|
5
|
-
For `.lmctl` teamfile compatibility mode:
|
|
6
|
-
|
|
7
|
-
- `lmctl lint <teamfile>` resolves `model=` for `claude`, `gemini`, `qwen`,
|
|
8
|
-
and `hermes` against the lmprice model catalog (see
|
|
9
|
-
`## lmprice Model Catalog` below) and warns when the model is not found.
|
|
10
|
-
This REPLACED the static tested-model lists that used to live in this
|
|
11
|
-
document (2026-09-24) — hand-copied lists contradicted the catalog.
|
|
12
|
-
|
|
13
|
-
**Best-effort contract (operator, 2026-09-25, hardened 2026-09-29): lint is
|
|
14
|
-
advisory and is NOT claimed to be 100% up to date.** Checks can lag provider
|
|
15
|
-
reality in BOTH directions — a model lint warns about may have just been
|
|
16
|
-
added upstream, and a model lint accepts may have just been retired. Every
|
|
17
|
-
model check is a warning, never an error, full stop: lint has exactly two
|
|
18
|
-
outcomes (ok / warning) and always exits 0 on warnings-only. There used to be
|
|
19
|
-
a `--strict` flag that could promote warnings to a failing exit code; the
|
|
20
|
-
operator removed it entirely (2026-09-29: "no need to give users the choice
|
|
21
|
-
with no obvious value") — lmctl decides the scoping, not the caller. Exit 1
|
|
22
|
-
is reserved for genuine validation errors (a malformed teamfile, an
|
|
23
|
-
unparseable member line), never for a warning. The runtime stance for
|
|
24
|
-
anything unrecognized or out of date is always: "not recognized — could
|
|
25
|
-
still be valid; no cost information," never a failure. Cost is equally
|
|
26
|
-
best-effort (n/a with a reason, never a guessed price).
|
|
27
|
-
- `codex` and `agy` model validation queries each provider's own live
|
|
28
|
-
catalog command (`codex debug models`, `agy models`) instead of a
|
|
29
|
-
hand-copied list — see their `## Codex` / `## Antigravity` sections
|
|
30
|
-
below.
|
|
31
|
-
- `opencode` model validation reads configured models from
|
|
32
|
-
`~/.config/opencode/opencode.json` and WARNS (never injects) when a
|
|
33
|
-
`model=` isn't declared there and isn't a config-free github-copilot
|
|
34
|
-
GPT/Gemini/o-series id. When `model=` is present, `lmctl lint` also
|
|
35
|
-
opens a short-lived ACP session and asks opencode itself to validate
|
|
36
|
-
`model=` and `effort=`. It never sends a prompt. See the `## OpenCode`
|
|
37
|
-
section below.
|
|
38
|
-
- `kimi` model validation reads configured aliases from
|
|
39
|
-
`$KIMI_CODE_HOME/config.toml` (default `~/.kimi-code/config.toml`) and
|
|
40
|
-
WARNS (never injects) when `model=` isn't one of the declared
|
|
41
|
-
`[models.<alias>]` table names, or when the config file itself is
|
|
42
|
-
missing/unreadable. Same rationale as opencode: kimi model aliases are
|
|
43
|
-
user-defined, not a fixed vendor catalog, so a hardcoded list in this
|
|
44
|
-
doc would be wrong for every user whose aliases differ. See the
|
|
45
|
-
`## Kimi` section below.
|
|
46
|
-
- `hermes` model ids are the ENCODED `<provider>:<model>` form Hermes's
|
|
47
|
-
ACP server advertises (`acp_adapter/model_catalog.py`). lmctl sends the
|
|
48
|
-
value through ACP `session/set_model` and does NOT maintain a Hermes
|
|
49
|
-
model list to validate against: Hermes resolves models at runtime from
|
|
50
|
-
its own provider config + auth, so any hardcoded list here would be
|
|
51
|
-
wrong for most users. Lint warns only when `model=` has no `provider:`
|
|
52
|
-
prefix. Hermes only treats a leading `<x>:` as a provider delimiter when
|
|
53
|
-
`x` is a known provider name (`hermes_cli/models.py:parse_model_input`);
|
|
54
|
-
a bare id stays the model name and Hermes then has to infer the provider
|
|
55
|
-
by detection, which fails for models it cannot place. After the shape
|
|
56
|
-
check, lint ALSO resolves the id against the lmprice catalog (the hermes
|
|
57
|
-
adapter splits the `provider:` prefix) and warns on a catalog miss —
|
|
58
|
-
warning-only, since Hermes may still resolve it from user config. See the
|
|
59
|
-
`## Hermes` section below.
|
|
60
|
-
- `copilot` accepts `model=` syntactically, but model selection is not
|
|
61
|
-
supported and lint warns that the value is ignored.
|
|
62
|
-
- `lmctl seed <teamfile>` passes `model=` through to the provider seed
|
|
63
|
-
call. It does not contact provider model catalogs.
|
|
64
|
-
|
|
65
|
-
The `claude`/`gemini`/`qwen` tables in the sections below are HISTORICAL
|
|
66
|
-
evidence records of the retired tested-model lists (pre-2026-09-24); lint no
|
|
67
|
-
longer consults them — it resolves against the lmprice catalog.
|
|
68
|
-
|
|
69
|
-
## lmprice Model Catalog
|
|
70
|
-
|
|
71
|
-
Since 2026-09-24 (0.2.1), model validation and costing share one catalog
|
|
72
|
-
layer fed by the public lmprice dataset
|
|
73
|
-
(`https://lmctl.com/dataset/model_list.json` + `aliases.json`):
|
|
74
|
-
|
|
75
|
-
- **Loading**: ETag-conditional refresh into `~/.lmctl/cache/lmprice/` with a
|
|
76
|
-
6h TTL (`LMCTL_PRICE_TTL=0` forces; `LMCTL_PRICE_DATA=<dir>` pins a
|
|
77
|
-
snapshot and disables network); bundled snapshot from build time is the
|
|
78
|
-
offline fallback; the loader never throws.
|
|
79
|
-
- **Resolution order** (provider-aware): provider-qualified alias hit
|
|
80
|
-
(evidence `established`/`asserted` → standards chain → pinned row;
|
|
81
|
-
`unresolved` is terminal, never guessed) → provider adapter family match →
|
|
82
|
-
miss. States: priced / estimated / known-unpriced / unresolved / unknown /
|
|
83
|
-
no-catalog.
|
|
84
|
-
- **Invariant (operator, 2026-09-25): if we can lint, then we can cost.**
|
|
85
|
-
lmprice build validation rejects half-bindings (asserted alias ending in a
|
|
86
|
-
null record pin); lmctl surfaces any legacy known-unpriced as the lint
|
|
87
|
-
warning "recognized but no price information."
|
|
88
|
-
- **Freshness**: the catalog is only as current as the last lmprice publish
|
|
89
|
-
plus the client TTL — see the best-effort contract at the top of this
|
|
90
|
-
document. `cost --debug` shows the dataset's `generated_at`.
|
|
91
|
-
|
|
92
|
-
## Claude
|
|
93
|
-
|
|
94
|
-
| Configured `model=` | Evidence |
|
|
95
|
-
| --- | --- |
|
|
96
|
-
| `claude-opus-4-6` | Ported from lmctl0 tested-model catalog. |
|
|
97
|
-
| `claude-opus-4-7` | Ported from lmctl0 tested-model catalog. |
|
|
98
|
-
| `claude-opus-4-8` | Added from operator-confirmed availability on 2026-06-13; `lmctl lint` compatibility smoke accepts it. |
|
|
99
|
-
| `claude-opus-5` | Operator-confirmed valid 2026-07-25; next-gen Opus release following the `-5` naming (cf. `claude-sonnet-5`/`claude-fable-5`, dropping the `-4-` infix). Added to the lint tested-model catalog. |
|
|
100
|
-
| `claude-sonnet-4-6` | Ported from lmctl0 tested-model catalog. |
|
|
101
|
-
| `claude-sonnet-5` | Operator-confirmed 2026-07-05 (via GitHub Copilot: `opencode --model github-copilot/claude-sonnet-5 run …` → "build · claude-sonnet-5"). Also a valid native Claude Code model id (`claude --model claude-sonnet-5`). |
|
|
102
|
-
| `claude-haiku-4-5` | Ported from lmctl0 tested-model catalog. |
|
|
103
|
-
| `claude-fable-5` | Session observed locally via `lmctl0 ls` on 2026-06-11; `lmctl lint` compatibility smoke accepts it. Anthropic announced on 2026-06-12 that access to Fable 5 was suspended for customers; keep the id valid for existing teamfiles, but do not use it for new work while unavailable. |
|
|
104
|
-
| `claude-fable-5-1` | Fable 5.1, math.lmctl's designated review model as of 2026-09-02; requested addition to the lint tested-model catalog to silence the "not in the tested model list" warning on seed. |
|
|
105
|
-
|
|
106
|
-
## Codex
|
|
107
|
-
|
|
108
|
-
**2026-09-15: this section is no longer read by `lmctl lint`.** It used to
|
|
109
|
-
be a hand-copied list that went stale in BOTH directions within the same
|
|
110
|
-
week: it kept `gpt-5.4-mini` listed as valid after OpenAI withdrew it from
|
|
111
|
-
the subscription (194 codex members with no `model=` pinned were silently
|
|
112
|
-
falling through to it as the ambient default), and separately omitted
|
|
113
|
-
`gpt-5.6-terra`/`gpt-5.6-luna` after an operator quota downshift moved 260
|
|
114
|
-
members onto them — both real, working models (`lmctl prompt` confirmed
|
|
115
|
-
live), producing 45 fleet-wide false-positive warnings. `codex debug
|
|
116
|
-
models` ("Render the raw model catalog as JSON") shipped since the first
|
|
117
|
-
incident and gives codex the same live-catalog treatment `agy` already
|
|
118
|
-
has — lint now queries it directly (`model-selection-lint.ts`'s
|
|
119
|
-
`loadCodexModels`), filtering to entries with `"visibility": "list"` (the
|
|
120
|
-
catalog's own "offered to users" flag — `gpt-reserve`/`codex-auto-review`
|
|
121
|
-
come back `"hide"` and are excluded the same way a UI picker would skip
|
|
122
|
-
them). Left as historical reference only, not maintained going forward.
|
|
123
|
-
|
|
124
|
-
| Configured `model=` | Evidence |
|
|
125
|
-
| --- | --- |
|
|
126
|
-
| `gpt-5.5` | Observed from `codex debug models` on 2026-09-15. |
|
|
127
|
-
| `gpt-5.6-sol` | Observed from `codex debug models` on 2026-09-15. |
|
|
128
|
-
| `gpt-5.6-terra` | Observed from `codex debug models` on 2026-09-15. |
|
|
129
|
-
| `gpt-5.6-luna` | Observed from `codex debug models` on 2026-09-15. |
|
|
130
|
-
| `gpt-6-astra` | Observed from `codex debug models` on 2026-09-15. |
|
|
131
|
-
|
|
132
|
-
**Banned as a build model (operator, 2026-09-06):** `gpt-5.3-codex-spark`
|
|
133
|
-
— plenty of regular-GPT quota headroom now, so there's no cost reason left
|
|
134
|
-
to reach for the cheap/fast classification model on build work. `lmctl
|
|
135
|
-
lint` still warns on explicit `model=gpt-5.3-codex-spark` for this reason
|
|
136
|
-
regardless of live-catalog membership (it has since also dropped out of
|
|
137
|
-
the live catalog entirely).
|
|
138
|
-
|
|
139
|
-
**Retired:** `gpt-5.4-mini` -- removed from the OpenAI subscription
|
|
140
|
-
2026-09-15 while 194 codex members across ~90 teamfiles had no `model=`
|
|
141
|
-
pinned and were falling through to it as the ambient default. Unlike
|
|
142
|
-
`claude-fable-5` above (suspended, may return, kept valid), this id was
|
|
143
|
-
withdrawn outright and is not expected back.
|
|
144
|
-
|
|
145
|
-
## Gemini
|
|
146
|
-
|
|
147
|
-
**2026-09-24: lint no longer reads a tested-model table here** — gemini
|
|
148
|
-
models resolve against the lmprice catalog (chat rows only; embedding /
|
|
149
|
-
image / tts / realtime rows are excluded by the adapter). Note the
|
|
150
|
-
`gemini` provider requires an API/enterprise Google account; personal
|
|
151
|
-
subscriptions should use `agy`.
|
|
152
|
-
|
|
153
|
-
## Qwen
|
|
154
|
-
|
|
155
|
-
**2026-09-24: lint no longer reads a tested-model table here** — qwen
|
|
156
|
-
models resolve against the lmprice catalog (bare, `dashscope/*`, and
|
|
157
|
-
`qwen/` rows). `qwen/qwen3.5-plus` is an established identity whose
|
|
158
|
-
current catalog price is null (known-unpriced — not a warning);
|
|
159
|
-
`qwen/qwen3.6-plus` is deliberately unresolved in the alias table.
|
|
160
|
-
|
|
161
|
-
## Antigravity
|
|
162
|
-
|
|
163
|
-
Antigravity (`agy`) is a distinct provider from Gemini even though it stores
|
|
164
|
-
state under `~/.gemini/antigravity-cli`. `lmctl` supports it through native
|
|
165
|
-
terminal resume plus one-shot `agy -p` turns.
|
|
166
|
-
|
|
167
|
-
**2026-09-05: this section is no longer read by `lmctl lint`.** It used to
|
|
168
|
-
be a hand-copied snapshot of `agy models`' output (literally captioned
|
|
169
|
-
"Observed from `agy models` on <date>" below) — which went stale on every
|
|
170
|
-
new model release (fable-5.1 once, then Gemini 3.6/3.7/3.8 all landing the
|
|
171
|
-
same day). `agy` is the one provider with its own live model-catalog
|
|
172
|
-
command (`agy models`, tab-separated `<id>\t<Display Name>` lines), so lint
|
|
173
|
-
now queries it directly (`model-selection-lint.ts`'s `loadAgyModels`)
|
|
174
|
-
instead of maintaining a copy of it here. Left as historical reference only,
|
|
175
|
-
not maintained going forward.
|
|
176
|
-
|
|
177
|
-
| Configured `model=` | Evidence |
|
|
178
|
-
| --- | --- |
|
|
179
|
-
| `Gemini 3.5 Flash (Medium)` | Observed from `agy models` on 2026-07-20. |
|
|
180
|
-
| `Gemini 3.5 Flash (High)` | Observed from `agy models` on 2026-07-20. |
|
|
181
|
-
| `Gemini 3.5 Flash (Low)` | Observed from `agy models` on 2026-07-20. |
|
|
182
|
-
| `Gemini 3.1 Pro (Low)` | Observed from `agy models` on 2026-07-20. |
|
|
183
|
-
| `Gemini 3.1 Pro (High)` | Observed from `agy models` on 2026-07-20. |
|
|
184
|
-
| `Claude Sonnet 4.6 (Thinking)` | Observed from `agy models` on 2026-07-20. |
|
|
185
|
-
| `Claude Opus 4.6 (Thinking)` | Observed from `agy models` on 2026-07-20. |
|
|
186
|
-
| `GPT-OSS 120B (Medium)` | Observed from `agy models` on 2026-07-20. |
|
|
187
|
-
|
|
188
|
-
**Pricing (2026-09-29, operator decision, math.lmctl findings 002/003):** separate from the lint
|
|
189
|
-
question above ("is this a real agy model," answered live) is "does this resolve in the lmprice
|
|
190
|
-
catalog for cost purposes" — the fleet's largest unpriced population (86 members, 4 base models,
|
|
191
|
-
11 effort-tier declared strings). Root cause: agy exposes Google's Gemini models under its own
|
|
192
|
-
display-label strings with a reasoning-effort tier baked into the name (`"Gemini 3.8 Flash (High)"`),
|
|
193
|
-
and no upstream catalog source (LiteLLM or OpenRouter) will ever carry that exact string —
|
|
194
|
-
normalizing punctuation can't fix a naming SYSTEM difference, only an explicit, evidenced row can
|
|
195
|
-
(see `backlog/`'s finding-002/003 threads for the full reasoning).
|
|
196
|
-
|
|
197
|
-
**Two layers, discovered while fixing this, not designed up front:** lmprice's own `aliases.json`
|
|
198
|
-
already independently covers 4 of the 11 strings (established evidence, sourced from
|
|
199
|
-
antigravity.google/docs/models, added 2026-09-24 — predates this fix): `gemini 3.8 flash (high)`,
|
|
200
|
-
`gemini 3.8 flash (medium)`, `gemini 3.1 pro (high)`. Those resolve via lmctl's existing alias-table
|
|
201
|
-
step and never touch new code. `src/providers/model-catalog.ts`'s `agyAdapter`/
|
|
202
|
-
`AGY_DISPLAY_TO_IDENTITY` (added here) covers the remaining 7 lmprice hasn't published yet — all of
|
|
203
|
-
3.7-flash and 3.6-flash had zero coverage from either mechanism before this. Confirmed live via
|
|
204
|
-
`resolveOfferForCost`'s `provenance` field: `"alias-pin"` for the 4 lmprice already has,
|
|
205
|
-
`"route-preference"` (this new table) for the other 7 — no conflict, no double-resolution. Raw
|
|
206
|
-
`agy models` output this table was built from (verified live, 2026-09-29, agy binary on this
|
|
207
|
-
machine):
|
|
208
|
-
|
|
209
|
-
```
|
|
210
|
-
gemini-3.8-flash-high Gemini 3.8 Flash (High)
|
|
211
|
-
gemini-3.8-flash-medium Gemini 3.8 Flash (Medium)
|
|
212
|
-
gemini-3.8-flash-low Gemini 3.8 Flash (Low)
|
|
213
|
-
gemini-3.7-flash-high Gemini 3.7 Flash (High)
|
|
214
|
-
gemini-3.7-flash-medium Gemini 3.7 Flash (Medium)
|
|
215
|
-
gemini-3.7-flash-low Gemini 3.7 Flash (Low)
|
|
216
|
-
gemini-3.6-flash-high Gemini 3.6 Flash (High)
|
|
217
|
-
gemini-3.6-flash-medium Gemini 3.6 Flash (Medium)
|
|
218
|
-
gemini-3.6-flash-low Gemini 3.6 Flash (Low)
|
|
219
|
-
gemini-3.1-pro-high Gemini 3.1 Pro (High)
|
|
220
|
-
gemini-3.1-pro-low Gemini 3.1 Pro (Low)
|
|
221
|
-
claude-sonnet-4-6 Claude Sonnet 4.6 (Thinking)
|
|
222
|
-
claude-opus-4-6-thinking Claude Opus 4.6 (Thinking)
|
|
223
|
-
gpt-oss-120b-medium GPT-OSS 120B (Medium)
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Every effort-tier variant of one base model maps to that base model's own catalog identity —
|
|
227
|
-
reasoning effort/thinking budget changes how many tokens a turn generates, not the per-token rate,
|
|
228
|
-
true of every major vendor's reasoning-effort parameter (OpenAI, Claude, Gemini alike).
|
|
229
|
-
|
|
230
|
-
**agy fronts Claude too, not just Gemini (math.lmctl, 2026-09-29):** 3 members declare `Claude Opus
|
|
231
|
-
4.6 (Thinking)` on `provider=agy`. `coversRecord`/`AGY_FIRST_PARTY_PROVIDERS` were Gemini-only when
|
|
232
|
-
this was first written -- a real gap for Claude-on-agy, caught before it silently priced at zero.
|
|
233
|
-
Verified per-string, live:
|
|
234
|
-
|
|
235
|
-
- `claude opus 4.6 (thinking)` already had an established display-label alias in lmprice's table
|
|
236
|
-
(like the 4 Gemini ones above, added 2026-09-24) -- resolves via `alias-pin`, never touches
|
|
237
|
-
`AGY_MODEL_TO_IDENTITY` at all. No code change needed for this one specifically.
|
|
238
|
-
- `claude sonnet 4.6 (thinking)` had NO such alias and was a genuine `unknown` -- fixed by adding
|
|
239
|
-
`"claude sonnet 4.6": "claude-sonnet-4-6"` to `AGY_MODEL_TO_IDENTITY`, broadening `coversRecord` to
|
|
240
|
-
`/gemini|claude/`, and adding `"anthropic"` to `AGY_FIRST_PARTY_PROVIDERS` so the bare
|
|
241
|
-
`litellm:claude-sonnet-4-6` (provider `anthropic`) row wins the tie-break over routed variants
|
|
242
|
-
(`azure_ai/`, `deepinfra/`, `vertex_ai/`, `snowflake/`, `perplexity/`, `openrouter/`).
|
|
243
|
-
- `gpt-oss 120b (medium)` remains **deliberately unmapped**: unlike Claude/Gemini, OpenAI does not
|
|
244
|
-
host this open-weight model itself, so there is no single first-party row to prefer among a dozen
|
|
245
|
-
equally-plausible third-party inference providers (groq, fireworks_ai, cerebras, deepinfra, ...).
|
|
246
|
-
Picking one without evidence of which route agy actually uses would be exactly the kind of guess
|
|
247
|
-
this whole explicit-mapping design exists to avoid -- stays `unknown` until there's real evidence
|
|
248
|
-
(e.g. an antigravity.google/docs/models entry, same provenance as the existing aliases).
|
|
249
|
-
|
|
250
|
-
## OpenCode
|
|
251
|
-
|
|
252
|
-
opencode model ids use `<provider>/<model>` shape. **lmctl does NOT manage opencode
|
|
253
|
-
model config.** When lmctl spawns an opencode member it writes only
|
|
254
|
-
`permission: "allow"` (the YOLO contract — opencode ACP has no
|
|
255
|
-
`--dangerously-skip-permissions` flag) plus its own `mcp.lmctl` bridge entry into
|
|
256
|
-
the member's `.opencode/opencode.json`. It never injects a provider/model catalog.
|
|
257
|
-
Models resolve from **opencode's own default models.dev catalog + your
|
|
258
|
-
`~/.config/opencode/opencode.json`** — you own the model config.
|
|
259
|
-
|
|
260
|
-
What needs declaring:
|
|
261
|
-
- **github-copilot GPT / Gemini / o-series** → served **config-free** from opencode's
|
|
262
|
-
default catalog. Just `opencode auth login github-copilot`, then
|
|
263
|
-
`model=github-copilot/gpt-5.5`, etc.
|
|
264
|
-
- **github-copilot Claude** (`claude-opus-4.8`, `claude-sonnet-5`, …) → **must be
|
|
265
|
-
declared** in your `opencode.json`. Copilot proxies Claude through its own API and
|
|
266
|
-
opencode's default catalog does not route them (→ "404 page not found"); declaring
|
|
267
|
-
them under a `github-copilot` provider (`@ai-sdk/openai-compatible`,
|
|
268
|
-
`baseURL https://api.githubcopilot.com`) fixes it.
|
|
269
|
-
- **Custom providers** (`deepseek/*`, `z-ai-coding/*`, `openrouter/*`,
|
|
270
|
-
`ollama-local/*`, …) → **must be declared** (not in models.dev).
|
|
271
|
-
|
|
272
|
-
Copy the published sample and adjust for your account:
|
|
273
|
-
|
|
274
|
-
```sh
|
|
275
|
-
mkdir -p ~/.config/opencode
|
|
276
|
-
cp examples/opencode.json ~/.config/opencode/opencode.json # or: curl -sL https://lmctl.com/examples/opencode.json -o ~/.config/opencode/opencode.json
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
**Lint = detect + warn (never inject).** `lmctl lint`/`seed` warns when a
|
|
280
|
-
`provider=opencode model=` is **not declared** in your `opencode.json` and isn't a
|
|
281
|
-
config-free github-copilot GPT/Gemini/o id — pointing you at the sample. It also
|
|
282
|
-
warns when `model=` is absent (opencode would silently pick its own default). It
|
|
283
|
-
does not edit your config.
|
|
284
|
-
|
|
285
|
-
`effort=`/variants: an opencode member's `effort=` maps to opencode's `--variant`
|
|
286
|
-
(reasoning effort). Declare the variants on the model in your `opencode.json` (see
|
|
287
|
-
the sample's Claude/GPT entries with `variants: { high, xhigh, max }`); on the ACP
|
|
288
|
-
prompt path lmctl sends `session/set_config_option` with `configId: "model"` and
|
|
289
|
-
`configId: "effort"` before `session/prompt`.
|
|
290
|
-
|
|
291
|
-
For each opencode member with `model=`, `lmctl lint` runs the same ACP
|
|
292
|
-
initialization and config-option calls, then exits before `session/prompt`. A
|
|
293
|
-
provider rejection text is preserved inside an `ACP RPC error:` diagnostic so
|
|
294
|
-
lint reflects opencode's live catalog and validation rules. If the local binary
|
|
295
|
-
cannot start, complete its handshake, or respond before the probe timeout, lint
|
|
296
|
-
skips this live check without treating the environment problem as a teamfile
|
|
297
|
-
error.
|
|
298
|
-
|
|
299
|
-
Example:
|
|
300
|
-
|
|
301
|
-
```md
|
|
302
|
-
_MEMBER_ alias=Reviewer provider=opencode model=github-copilot/gpt-5.4 effort=xhigh sessionid=<seeded-id>
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
## Kimi
|
|
306
|
-
|
|
307
|
-
Kimi (Moonshot AI's Kimi Code CLI) speaks ACP, same transport family as opencode/
|
|
308
|
-
gemini/copilot. `model=` values are **user-defined aliases** declared in
|
|
309
|
-
`$KIMI_CODE_HOME/config.toml` under `[models.<alias>]` table headers (e.g.
|
|
310
|
-
`[models."kimi-code/k3"]`), not a fixed vendor catalog — same shape as opencode,
|
|
311
|
-
not claude/codex. `lmctl` does not manage this file; it only reads it to validate
|
|
312
|
-
`model=` at lint/seed time and warns (never injects) when the config is missing
|
|
313
|
-
or the alias isn't declared.
|
|
314
|
-
|
|
315
|
-
Kimi's ACP mode defaults to permission-**prompting** (unlike every argv-YOLO or
|
|
316
|
-
config-file-YOLO provider). lmctl forces it into full-auto via an ACP protocol
|
|
317
|
-
call (`session/set_config_option`, `configId: "mode"`, `value: "auto"`) sent
|
|
318
|
-
after `session/new`/`session/load` and before the first `session/prompt` —
|
|
319
|
-
fail-closed: if that call is rejected, lmctl throws rather than proceeding, on
|
|
320
|
-
the one-shot transport (`src/providers/transports/acp.ts`). See
|
|
321
|
-
`src/providers/yolo-contract.ts`'s `PROTOCOL_LEVEL_YOLO` set for the contract.
|
|
322
|
-
|
|
323
|
-
Kimi 0.28.x exposes `thinking` through ACP only as an `on`/`off` toggle.
|
|
324
|
-
Turning it on selects the current model alias's `default_effort` from
|
|
325
|
-
`config.toml`; it does not accept a session-level effort value. Choose or
|
|
326
|
-
define a different model alias when a different default effort is required.
|
|
327
|
-
Accordingly, lmctl warns that `_MEMBER_ effort=` is ignored for Kimi.
|
|
328
|
-
|
|
329
|
-
Example:
|
|
330
|
-
|
|
331
|
-
```md
|
|
332
|
-
_MEMBER_ alias=Reviewer provider=kimi model="kimi-code/k3" sessionid=<seeded-id>
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
`effort=` support by provider:
|
|
336
|
-
|
|
337
|
-
| Provider | Status |
|
|
338
|
-
| --- | --- |
|
|
339
|
-
| `opencode` | Supported (via the model's declared `variants` in opencode.json). |
|
|
340
|
-
| `kimi` | Not supported on the Kimi 0.28.x baseline; effort is fixed by the selected model alias's `default_effort`. |
|
|
341
|
-
| `claude` | Claude Code has native `--effort`, but lmctl has not wired `_MEMBER_ effort=` to Claude yet. |
|
|
342
|
-
| `codex` | Native effort surfaces exist; lmctl has not wired `_MEMBER_ effort=` to Codex yet. |
|
|
343
|
-
| `agy` | No verified effort flag; only `--model` supported. |
|
|
344
|
-
| `hermes` | Not supported. Hermes exposes reasoning effort through its own config (`--reasoning`) but not through its ACP surface, so lmctl ignores `effort=` for a Hermes member and warns. |
|
|
345
|
-
|
|
346
|
-
## Hermes
|
|
347
|
-
|
|
348
|
-
Hermes is driven over ACP (`hermes acp`), and its ACP model ids are the
|
|
349
|
-
encoded `provider:model` strings it advertises in `session/new`
|
|
350
|
-
(`acp_adapter/model_catalog.py`, `encode_model_choice`). lmctl applies
|
|
351
|
-
`model=` with ACP `session/set_model` when it differs from the loaded model.
|
|
352
|
-
|
|
353
|
-
```md
|
|
354
|
-
_MEMBER_ alias=Reviewer provider=hermes model="deepseek:deepseek-v4.1-flash" sessionid=<uuid>
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
There is deliberately **no** tested-model table here. Hermes resolves its
|
|
358
|
-
model inventory at runtime from the user's own provider configuration and
|
|
359
|
-
credentials, so a list in this repository would be wrong for most users —
|
|
360
|
-
the same reasoning as `kimi` and `opencode`. Lint checks the SHAPE only:
|
|
361
|
-
the value should carry a `provider:` prefix, because without one Hermes
|
|
362
|
-
has to infer the provider by model-name detection and fails for models it
|
|
363
|
-
cannot place.
|
|
364
|
-
|
|
365
|
-
V1 supports ACP seeding and structured prompt/dispatch against one effective
|
|
366
|
-
`HERMES_HOME`. Existing session IDs default to strict resume. Yolo mode enables
|
|
367
|
-
both the shell approval bypass and the per-process ACP edit mode; plan mode is
|
|
368
|
-
rejected. Native deletion, interactive resume, fork, and persistent daemon
|
|
369
|
-
sessions are not supported by this integration. The reader is read-only and
|
|
370
|
-
shows active transcript rows; token totals do not establish last-turn usage.
|
|
371
|
-
|
|
372
|
-
Release prerequisites: Hermes must return JSON-RPC errors for missing load/resume
|
|
373
|
-
IDs. Task 140 also uncovered an ACP compression-head restore defect: restart-safe
|
|
374
|
-
resume after compression requires a separate Hermes fix before this provider lands.
|
|
375
|
-
|
|
376
|
-
The source fixes are reviewed and committed locally in the Hermes checkout as
|
|
377
|
-
`989fd87461e23493fe62250b1671f9fc368e9117`. This is not an upstream release or an
|
|
378
|
-
installed-runtime update: the current GitHub identity has read-only access to
|
|
379
|
-
NousResearch/hermes-agent, and validation used the fixed checkout explicitly.
|
|
380
|
-
Provider publication remains gated on an approved, available patched Hermes
|
|
381
|
-
runtime and final owner landing approval (task 141 notes 548-549).
|