feat: model taxonomy gains gpt-5.6-sol + per-host generation defaults

Adds 'gpt-5.6-sol' to the model taxonomy with exact-match-only resolution
(Terra/Luna/suffixed IDs deliberately fall back to generic gpt) and replaces
the hardcoded 'claude' generation default with a validated
HostConfig.defaultModel: codex renders the gpt profile when --model is
absent, every other host keeps claude. Codex ship golden regenerated
accordingly; ADDING_A_HOST documents the new field.
This commit is contained in:
Garry Tan
2026-08-18 13:10:27 -07:00
parent c86e6472eb
commit 819414eda7
8 changed files with 87 additions and 21 deletions
+33 -11
View File
@@ -113,7 +113,7 @@ if [ -d ".agents/skills/gstack" ] && [ ! -L ".agents/skills/gstack" ]; then
fi
fi
echo "VENDORED_GSTACK: $_VENDORED"
echo "MODEL_OVERLAY: claude"
echo "MODEL_OVERLAY: gpt"
_CHECKPOINT_MODE=$($GSTACK_BIN/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit")
_CHECKPOINT_PUSH=$($GSTACK_BIN/gstack-config get checkpoint_push 2>/dev/null || echo "false")
echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE"
@@ -579,23 +579,45 @@ At skill END before telemetry:
```
## Model-Specific Behavioral Patch (claude)
## Model-Specific Behavioral Patch (gpt)
The following nudges are tuned for the claude model family. They are
The following nudges are tuned for the gpt model family. They are
**subordinate** to skill workflow, STOP points, AskUserQuestion gates, plan-mode
safety, and /ship review gates. If a nudge below conflicts with skill instructions,
the skill wins. Treat these as preferences, not rules.
**Todo-list discipline.** When working through a multi-step plan, mark each task
complete individually as you finish it. Do not batch-complete at the end. If a task
turns out to be unnecessary, mark it skipped with a one-line reason.
**Completion bias.** Do not end your turn with a partial solution when the full
solution is reachable. If you encounter an error, debug it. If a test fails, fix it.
If something is ambiguous, make your best judgment and proceed — don't stop and ask
unless you're genuinely blocked.
**Think before heavy actions.** For complex operations (refactors, migrations,
non-trivial new features), briefly state your approach before executing. This lets
the user course-correct cheaply instead of mid-flight.
**Prefer doing over listing.** When you'd be tempted to write "you could also try X,
Y, or Z," try the best option yourself. Pick, execute, report results.
**Dedicated tools over Bash.** Prefer Read, Edit, Write, Glob, Grep over shell
equivalents (cat, sed, find, grep). The dedicated tools are cheaper and clearer.
**No preamble.** Skip "Great question!", "Let me help with that", and restating the
user's request. Start with the work.
**AskUserQuestion is NOT preamble.** The "No preamble" and "Prefer doing over listing"
rules above do NOT apply to AskUserQuestion content. When you invoke AskUserQuestion,
the user is about to make a decision — they need context, not terseness. Always emit
the full format from the preamble's AskUserQuestion Format section:
1. **Re-ground** (project + branch + task — 1-2 sentences).
2. **Simplify (ELI10)** — explain what's happening in plain English a 16-year-old could
follow. Concrete stakes, not abstract tradeoffs. Non-negotiable; this is NOT preamble.
3. **Recommend**`RECOMMENDATION: Choose [X] because [one-line reason]` on its own
line. Never omit this line. Never collapse it into the options list.
4. **Options** — lettered `A) B) C)` with Completeness scores (coverage-differentiated)
or the "options differ in kind" note (kind-differentiated).
If you find yourself about to present an AskUserQuestion without the Simplify/ELI10
paragraph, without a RECOMMENDATION line, or by just listing options and asking "which
one?" — stop, back up, and emit the full format. The user will ask you to do it anyway,
so do it the first time.
**Reminder: subordination applies.** When a skill workflow says STOP, stop. When the
skill asks via AskUserQuestion, that is the wait-for-user gate, not an ambiguity.
Completion bias does not override safety gates.
## Voice
+14
View File
@@ -112,6 +112,7 @@ describe('validateHostConfig', () => {
name: 'test-host',
displayName: 'Test Host',
cliCommand: 'testcli',
defaultModel: 'claude',
globalRoot: '.test/skills/gstack',
localSkillRoot: '.test/skills/gstack',
hostSubdir: '.test',
@@ -165,6 +166,12 @@ describe('validateHostConfig', () => {
expect(validateHostConfig(c)).toEqual([]);
});
test('invalid defaultModel is caught', () => {
const c = makeValid();
(c as any).defaultModel = 'llama-local';
expect(validateHostConfig(c).some(e => e.includes('defaultModel'))).toBe(true);
});
test('invalid globalRoot is caught', () => {
const c = makeValid();
c.globalRoot = 'path with spaces';
@@ -470,6 +477,13 @@ describe('golden-file regression', () => {
// ─── Individual host config correctness ─────────────────────
describe('host config correctness', () => {
test('Codex defaults to generic GPT while all existing hosts retain Claude', () => {
expect(codex.defaultModel).toBe('gpt');
for (const host of ALL_HOST_CONFIGS.filter(h => h.name !== 'codex')) {
expect(host.defaultModel).toBe('claude');
}
});
test('claude is the only host with real-dir-symlink strategy', () => {
for (const config of ALL_HOST_CONFIGS) {
if (config.name === 'claude') {