v1.91.332.0 feat(capy): remember a user's model preference (agent_model); every Capy session reads factory.md (#3634)

* feat(capy): agent_model preference via gstack-models resolve --role agent; capy/skill/gstack/factory.md

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(agent-model): pre-landing review fixes

- a broken preferences.yaml no longer blocks --request or config.yaml
- CRLF, a byte-order mark and a trailing comment still read the value
- never echo raw control or bidi bytes from an unvalidated source
- cap the bytes actually read, not only the stat size
- family names and host are case-insensitive in gstack-config too
- list passes the platform through to the agent block
- a wrapper inside the checkout names no preferences file
- docs: --check never writes the skill folder

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(changelog): restore CHANGELOG.md history that 1bec403 truncated

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs: agent_model and factory.md in capy-install, model-policy, troubleshooting and capy/README

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(capy): the Captain archives its own child threads by its plan for each (GST-211, R39)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* v1.91.332.0 stamp

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-10-30 12:03:08 +00:00
1 parent ae3d58c932
commit 39378ca6d1
20 files changed
+637 -18

No files matched your search

+10 -3
View File
@@ -10,7 +10,9 @@ to `/crew`); the lane-side rules for a thread working under a Captain are in
[capy-install.md](capy-install.md#working-under-a-captain). Every file named below has a
copy-paste template under [`captain/templates/`](../captain/templates/). For the story of how
one owner's crews run this day to day, with measured numbers, read
[capy/README.md](../capy/README.md).
[capy/README.md](../capy/README.md). Every Capy session also reads
[`capy/skill/gstack/factory.md`](../capy/skill/gstack/factory.md), a one-page summary of
these practices with pointers to the rules.
## The model in one paragraph
@@ -32,7 +34,10 @@ by a daily pass; nothing is retried into green.
- **The controller** (the Captain) runs the crew: starts lanes on disjoint files, keeps the
rules file, the digest and the notes, validates READYs, builds and merges trains, calls
slots, relays asks to the owner in the three shapes, runs the flaky pass, and decides
everything that needs no access, credentials, spend over cap or a cited approval.
everything that needs no access, credentials, spend over cap or a cited approval. It
archives its own child threads, including ones its crew or its automations started
outside the crew, when its plan for each thread says that thread's work is done; it
knows each thread's next step, so nobody else archives them.
- **A lane** (a crew thread) owns named files, builds on its own branch and machine,
runs /ship, sends one READY block, stamps on call (merging the base into its pin only
as part of that stamp commit, or when the controller names a real-code conflict),
@@ -361,7 +366,9 @@ only the run the lane named.
Every report ends with one Lesson. The controller reads lessons before chat, and each
one becomes a rule in CREW.md, a line in AGENTS.md, or a tool fix filed as an issue;
nothing stays a lesson for long. Rules carry the thread that produced them, so a new lane
can read the incident behind the rule.
can read the incident behind the rule. When the owner states a rule meant for every
Captain, forward it in the same turn to the thread that keeps the account's shared rules,
so every crew gets it.
## Setting it up on Capy
+5
View File
@@ -423,6 +423,11 @@ GSTACK_LAUNCH_FILE: <verdict file without .json>.env
`GSTACK_LAUNCH_FILE` names the same assignments as a sourceable script (mode
0600, beside the verdict under the state root; the PATH prepend is idempotent).
When the session starts from the Drive skill (a bootstrapper outside the
checkout), the file also exports `GSTACK_PREFERENCES_FILE`, the path of
`preferences.yaml` beside that skill's SKILL.md, which the `GSTACK_LAUNCH` line
leaves out; `gstack-models resolve --role agent` reads it
([your model preference](model-policy.md#your-model-preference)).
The file is part of the ok verdict: a passing run that cannot write it exits 1
with `gstack: fail launch-file — could not write the launch file <path>; fix:
make <dir> writable, or set GSTACK_STATE_ROOT to a writable directory
+46
View File
@@ -84,6 +84,7 @@ coverage, not a completed review.
| `model_frontier_openai` | Catalog's OpenAI frontier model | Explicit OpenAI model identifier |
| `model_smart_claude` | Catalog's Anthropic smart model | Explicit Anthropic model identifier |
| `model_smart_openai` | Catalog's OpenAI smart model | Explicit OpenAI model identifier |
| `agent_model` | unset (`host`) | `host`, a family or `<provider>/<model>`; see [your model preference](#your-model-preference) |
For plan reviews, a model named for that invocation wins over
`GSTACK_CLAUDE_MODEL` or `GSTACK_CODEX_MODEL`. That environment override wins over
@@ -120,6 +121,48 @@ JSON output list these limits. Use an explicit compatible model for those cases,
or `host` mode for plan reviews. Implementation recommendations require an
explicit implementation model rather than delegating to a hidden native choice.
## Your model preference
gstack takes no position for or against any model. If you prefer one, gstack
remembers it and uses it whenever it picks a model for a working agent: a lane,
a subagent or a reviewer. When it is unset, every agent keeps its own model.
```bash
"$GSTACK_ROOT/bin/gstack-config" set agent_model opus
"$GSTACK_ROOT/bin/gstack-models" resolve --role agent
```
| Value | Meaning |
| --- | --- |
| `host` (the default) | keep the running agent's own model and leave the model field out |
| a family: `opus`, `fable`, `sonnet`, `haiku`, `astra`, `sol`, `luna`, `terra` | today's model in that family (`opus` is `anthropic/claude-opus-5-5`); it moves when gstack's family table moves |
| `<provider>/<model>` | that exact model, for example `anthropic/claude-opus-5-5` |
The first match wins: a request for one job (`resolve --role agent --request sol`,
never saved), then `agent_model` in this machine's config.yaml, then
`agent_model` in the file `GSTACK_PREFERENCES_FILE` names, then `host`. The
output names the winner and shows both stored values; `--json` prints the
provider, model, provider-qualified `id` and source.
Two cases ignore the preference on purpose: a cross-family outside voice (the
`plan-review` role picks the other provider) and a model under test in an eval
(`eval-arms` and `/eval-plan` arms).
A value gstack can't use stops only the agent role, naming the file and the fix.
`plan-review`, `implementation` and `eval-arms` keep resolving, and
`gstack-models list` shows the problem in its agent block.
**On Capy.** Each cloud machine starts fresh, so config.yaml does not carry
over. Keep the preference in `preferences.yaml` next to the gstack skill's
SKILL.md in your Drive: one `agent_model: <value>` line, with `#` comments
allowed (any other key is ignored with a warning). The session start puts the
file's path in the launch file as `GSTACK_PREFERENCES_FILE` and gstack reads it
where it is: nothing is copied, and `--check` never writes the skill folder. Agents write that
file only when you ask them to remember a preference. To change or clear it for
good, edit or delete that line; `gstack-config unset agent_model` clears this
machine only. Copying a newer `capy/skill/gstack/` over the skill folder leaves
`preferences.yaml` alone, because the shipped folder has no such file.
## Reasoning effort
Codex calls carry a `model_reasoning_effort`. It follows the same shape as the
@@ -213,6 +256,9 @@ an environment pin. See [selection recovery](troubleshooting.md#model-policy-sel
`gstack-models` with no arguments is `list`. Both `list` and `resolve` accept
`--json`. Plan-review resolution requires `--provider anthropic|openai`;
implementation resolution can omit the provider to return both recommendations.
Agent resolution (`--role agent`) takes no `--provider`; its JSON carries an
`agent` object instead of `selections`, and `list --json` adds the same
top-level `agent` key.
```bash
"$GSTACK_ROOT/bin/gstack-models" resolve --role plan-review --provider anthropic --json
+1 -1
View File
@@ -37,7 +37,7 @@ no paid call: the Codex rows report the cached model check and its age, and
## Model policy
The [model-policy guide](model-policy.md) explains the two tiers, all six
The [model-policy guide](model-policy.md) explains the two tiers, all seven
settings, precedence and the read-only inspection command. A resolved selection
is not proof that the requested provider or model can run.