From 6c1e2b065f87c7091f640ca45c7375185087b1d5 Mon Sep 17 00:00:00 2001 From: Justin Shook <20212198+shookya@users.noreply.github.com> Date: Sat, 24 Oct 2026 13:40:25 -0600 Subject: [PATCH] feat(models): register GPT-6 Astra as an optional Codex family Codex CLI 0.164.0 `codex debug models` lists gpt-6-astra with efforts low to ultra, so the family takes low to ultra and defaults to max, as Sol and Luna do. Its released pair is appended to the append-only list. Codex families generate no Claude agents; the renderer adds only the catalog row. Default roles and panels are unchanged. Co-Authored-By: Claude Opus 5.5 --- CHANGES.md | 4 ++++ docs/reference.md | 2 +- .../poteto-mode/references/model-catalog.md | 1 + .../poteto-mode/scripts/runner/registry.test.ts | 15 ++++++++++++--- .../poteto-mode/scripts/runner/registry/models.ts | 10 ++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 30240cba..1a1b9721 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,10 @@ Open Pstack lands on green: Mergify merges a ready PR to main once verify and exact-head live-gate pass and no review thread is unresolved, and a workflow resolves Unfret's own threads. A PR that touches `.github/` or the Mergify config also waits for Unfret, and workflow changes require operator queueing. This port applies the Cursor → Claude Code substitutions in skill bodies. Earlier drafts left them flagged; this revision resolves them. A later pass added a Codex build that shares the same skills; see [Codex port](#codex-port) below. +## Unreleased + +**GPT-6 Astra lanes.** The model catalog registers `codex:gpt-6-astra` as an optional family with efforts `low` to `ultra`, as `codex debug models` lists them in Codex CLI 0.164.0, and a default of `max`. Astra is the second family after Sol that offers `ultra`. Codex families have no generated Claude agents, so a Claude Code parent runs Astra through the external runner. Default roles and panels are unchanged. + ## 1.16.0 syncs to Cursor pstack 0.15.29 Open Pstack 1.16.0 tracks Cursor pstack 0.15.29 at `88d47514b82e7c44f00f2b2a72ff6dd12158038c`. Sixteen upstream commits since 0.15.25 touch pstack. Nine change skill content, and all nine are applied with the port adaptations below. `a968159` names two skills after their folders: the port's `poteto-mode` already complies, and `make-bot-ui` stays out. Three add upstream's own Claude Code install and a docs check, which stay out apart from their README text. Three bump only the Cursor manifests and guide, which stay out. The release also fixes #46 and #235, and ships Claude Haiku 5.5 lanes (#223), foreground waits on Claude Code (#232, #233) and the comment sweep (#218), all merged after 1.15.0. Default roles and panels are unchanged. diff --git a/docs/reference.md b/docs/reference.md index 3cd85268..dbf41d2c 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -86,7 +86,7 @@ The Codex build shares one `skills/` tree with the Claude Code build. Nothing is - **Tool and built-in mapping.** Claude tool names and built-in skills resolve through [`codex-tools.md`](../plugins/pstack/skills/poteto-mode/references/codex-tools.md). Model execution resolves separately through [`provider-dispatch.md`](../plugins/pstack/skills/poteto-mode/references/provider-dispatch.md), so Codex models stay native while other providers run through the external runner. - **Subagents.** The `Agent` tool maps to Codex `spawn_agent` / `wait_agent`, enabled by `multi_agent = true`. Parallel fan-out is multiple `spawn_agent` calls in one turn. If the native Codex lane is unavailable, record that lane as a dropout; the configured external lanes still run, and no provider is silently substituted. There is no `poteto-agent` subagent type on Codex; route ad-hoc subagents by dispatching a `spawn_agent` told to read `poteto-mode` first. - **Auto-fire.** The `hooks/` SessionStart injection is Claude Code-only; Codex has no plugin hook runtime. Enter `pstack:poteto-mode` by name, or add a standing instruction to `~/.codex/AGENTS.md` if you want the same always-on routing. -- **Models.** `/setup-pstack` writes provider-qualified descriptors and asks one requested effort per assigned family (`low`, `medium`, `high`, `xhigh`, `max`, and `ultra` where the model's CLI lists it, today only Sol). The first-run sheet is the model catalog's [role defaults](../plugins/pstack/skills/poteto-mode/references/model-catalog.md#role-defaults), with a panel of Opus, Sol, and Grok; Fable, Sonnet, Luna, Haiku 5.5 and an exact Opus pin stay selectable. Fable, Opus and Sonnet use Claude's rolling aliases; a registered exact pin keeps its own model. Runtime dispatch normalizes older versioned descriptors in memory, so an installed sheet stops pinning immediately. A setup rerun persists that migration while keeping each role's family and effort. In Codex, Codex families such as Sol use native `spawn_agent`; every other provider uses the deterministic external runner. In Claude Code, Claude families use native agents; every other provider uses the runner. A Codex writer that the runner launches stays in Codex's `workspace-write` sandbox unless the sheet opts in with the line `codex writer sandbox: full-access`, which setup asks about once. Full access lets the writer launch a browser and write dot-folders such as `.agents/`, and removes every sandbox limit. Children never detect the parent or reroute themselves. The `bug-fix`, `perf-issue`, and `hillclimb` roles stay on Sol instead of upstream's Grok default. +- **Models.** `/setup-pstack` writes provider-qualified descriptors and asks one requested effort per assigned family (`low`, `medium`, `high`, `xhigh`, `max`, and `ultra` where the model's CLI lists it, today Sol and Astra). The first-run sheet is the model catalog's [role defaults](../plugins/pstack/skills/poteto-mode/references/model-catalog.md#role-defaults), with a panel of Opus, Sol, and Grok; Fable, Sonnet, Luna, Astra, Haiku 5.5 and an exact Opus pin stay selectable. Fable, Opus and Sonnet use Claude's rolling aliases; a registered exact pin keeps its own model. Runtime dispatch normalizes older versioned descriptors in memory, so an installed sheet stops pinning immediately. A setup rerun persists that migration while keeping each role's family and effort. In Codex, Codex families such as Sol use native `spawn_agent`; every other provider uses the deterministic external runner. In Claude Code, Claude families use native agents; every other provider uses the runner. A Codex writer that the runner launches stays in Codex's `workspace-write` sandbox unless the sheet opts in with the line `codex writer sandbox: full-access`, which setup asks about once. Full access lets the writer launch a browser and write dot-folders such as `.agents/`, and removes every sandbox limit. Children never detect the parent or reroute themselves. The `bug-fix`, `perf-issue`, and `hillclimb` roles stay on Sol instead of upstream's Grok default. Verified in fresh installed Claude Code and Codex sessions: the user-facing skills are discovered and namespaced under `pstack`; both parents fan out the configured panel through the documented native/external route table, retain long-running handles without a default timeout, and cross-judge only after every candidate is terminal. The `principle-*` leaves remain available for `poteto-mode` to read by path. Claude honors their `user-invocable: false` metadata; Codex 0.149.0 does not ([#8](https://github.com/ericlitman/open-pstack/issues/8)). diff --git a/plugins/pstack/skills/poteto-mode/references/model-catalog.md b/plugins/pstack/skills/poteto-mode/references/model-catalog.md index 1be5b3a8..8745f7f0 100644 --- a/plugins/pstack/skills/poteto-mode/references/model-catalog.md +++ b/plugins/pstack/skills/poteto-mode/references/model-catalog.md @@ -13,6 +13,7 @@ Model and provider facts for [`provider-dispatch.md`](provider-dispatch.md), whi | grok | Grok 4.7 | grok | grok-4.7 | xhigh | low medium high xhigh max | - | default | grok-4.7-xhigh-fast | | opus | Opus | claude | opus | max | low medium high xhigh max | `pstack-opus-` | default | opus | | luna | GPT-6 Luna | codex | gpt-6-luna | max | low medium high xhigh max | - | optional | - | +| astra | GPT-6 Astra | codex | gpt-6-astra | max | low medium high xhigh max ultra | - | optional | - | | sonnet | Sonnet | claude | sonnet | max | low medium high xhigh max | `pstack-sonnet-` | optional | - | | opus-5-5 | Opus 5.5 | claude | claude-opus-5-5 | max | low medium high xhigh max | `pstack-opus-5-5-` | optional | claude-opus-5-5-xhigh | | haiku-5-5 | Haiku 5.5 | claude | claude-haiku-5-5 | max | low medium high xhigh max | `pstack-haiku-5-5-` | optional | - | diff --git a/plugins/pstack/skills/poteto-mode/scripts/runner/registry.test.ts b/plugins/pstack/skills/poteto-mode/scripts/runner/registry.test.ts index 943ea6a1..8c03ec52 100644 --- a/plugins/pstack/skills/poteto-mode/scripts/runner/registry.test.ts +++ b/plugins/pstack/skills/poteto-mode/scripts/runner/registry.test.ts @@ -85,13 +85,14 @@ describe("registry data", () => { } }); - it("keeps the default efforts, the Claude rolling aliases and Sol's ultra", () => { + it("keeps the default efforts, the Claude rolling aliases, and ultra on Sol and Astra", () => { expect(REGISTRY.families.map((entry) => [entry.name, entry.defaultEffort])).toEqual([ ["fable", "max"], ["sol", "max"], ["grok", "xhigh"], ["opus", "max"], ["luna", "max"], + ["astra", "max"], ["sonnet", "max"], ["opus-5-5", "max"], ["haiku-5-5", "max"], @@ -111,8 +112,8 @@ describe("registry data", () => { .map((entry) => [entry.name, entry.rolling!.revisionPrefix])) .toEqual([["fable", "claude-fable-"], ["opus", "claude-opus-"], ["sonnet", "claude-sonnet-"]]); expect(REGISTRY.families.filter((entry) => entry.provider === "codex").map((entry) => [entry.name, entry.model])) - .toEqual([["sol", "gpt-6.1-sol"], ["luna", "gpt-6-luna"]]); - expect(REGISTRY.families.filter((entry) => effortsOf(entry).includes("ultra")).map((entry) => entry.name)).toEqual(["sol"]); + .toEqual([["sol", "gpt-6.1-sol"], ["luna", "gpt-6-luna"], ["astra", "gpt-6-astra"]]); + expect(REGISTRY.families.filter((entry) => effortsOf(entry).includes("ultra")).map((entry) => entry.name)).toEqual(["sol", "astra"]); }); it("keeps family names and (provider, model) pairs unique, and efforts ordered", () => { @@ -463,6 +464,14 @@ describe("resolveLane", () => { .toThrow("effort ultra is not offered for claude:sonnet"); }); + it("resolves Astra at max by default and passes ultra to Codex", () => { + const astra = resolveLane(request({ parent: "claude", provider: "codex", model: "gpt-6-astra" })); + expect([astra.family?.name, astra.effort]).toEqual(["astra", "max"]); + const ultra = resolveLane(request({ parent: "claude", provider: "codex", model: "gpt-6-astra", effort: "ultra" })); + expect(ultra.adapter.launch.argv(ultra, { sharedGitDir: null, providerSidecar: null })) + .toEqual(expect.arrayContaining(["gpt-6-astra", 'model_reasoning_effort="ultra"'])); + }); + it("maps each Devin effort to its CLI model ID and keeps the descriptor's model for the receipt", () => { const devin = (model: string, effort: string, mode = "read-only") => resolveLane(request({ parent: "claude", provider: "devin", model, effort, mode })); diff --git a/plugins/pstack/skills/poteto-mode/scripts/runner/registry/models.ts b/plugins/pstack/skills/poteto-mode/scripts/runner/registry/models.ts index 7d87eb0c..7550be7c 100644 --- a/plugins/pstack/skills/poteto-mode/scripts/runner/registry/models.ts +++ b/plugins/pstack/skills/poteto-mode/scripts/runner/registry/models.ts @@ -53,6 +53,15 @@ export const FAMILIES = [ defaultEffort: "max", upstream: null, }), + family({ + name: "astra", + label: "GPT-6 Astra", + provider: "codex", + model: "gpt-6-astra", + efforts: UP_TO_ULTRA, // `codex debug models`, Codex CLI 0.164.0 + defaultEffort: "max", + upstream: null, + }), family({ name: "sonnet", label: "Sonnet", @@ -209,4 +218,5 @@ export const RELEASED_PAIRS = [ { pair: "cursor:composer-2.5", family: "composer-2.5" }, { pair: "cursor:gemini-3.7-flash", family: "gemini-3.7-flash" }, { pair: "claude:claude-haiku-5-5", family: "haiku-5-5" }, + { pair: "codex:gpt-6-astra", family: "astra" }, ] as const satisfies readonly ReleasedPair[];