Skip to content
Back to skills

Setup Pstack

ASecurity

Configure pstack's provider-qualified models, reasoning budget, subscription access, approved API spend, and saved backend fallbacks. Verifies only the assigned native and external model lanes before writing the override sheet. Use for /setup-pstack, "configure pstack models", "pstack budget", subscription routing, changing pstack's model choices, or the optional Codex startup-routing hook.

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
ai-agentsrustgoshellrefactoringgitapibackend

Works with

  • claude code
  • cursor
  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add arjitj2/open-pstack --skill setup-pstack --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Setup Pstack?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Setup Pstack
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/arjitj2-setup-pstack/badge)](https://www.skillsdirectory.com/skills/arjitj2-setup-pstack)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: setup-pstack
description: Configure pstack's provider-qualified models, reasoning budget, subscription access, approved API spend, and saved backend fallbacks. Verifies only the assigned native and external model lanes before writing the override sheet. Use for /setup-pstack, "configure pstack models", "pstack budget", subscription routing, changing pstack's model choices, or the optional Codex startup-routing hook.
---

# Setup pstack

For a routing-only request, establish the parent in step 1, then go directly to [Codex startup routing](#codex-startup-routing-optional).

Configure one portable model sheet for the current parent harness. Read [`provider-dispatch.md`](../poteto-mode/references/provider-dispatch.md) before probing or writing anything. Its model matrix, descriptor grammar, sheet grammar, and route table are the contract. Choose one requested effort per assigned provider/model pair and, when the operator wants it, an explicit ordered `primary -> fallback` attempt chain per seat plus, when the operator accepts it, one `# fallback` policy line declaring which terminal outcomes may advance the chain (`usage-exhausted` is the only authorized outcome when the line is absent). An optional `# continuation: {"on":["permission","handoff"],"max":2}` line is a separate same-route execution policy; preserve a loaded line or its absence unless the operator explicitly chooses a change. Do not add a second configuration file or an unapproved substitution; a saved chain is the only authorized provider fallback. The installed helper `skills/poteto-mode/scripts/model-policy/pstack-model-policy` validates the rendered sheet (`validate --sheet <file> --parent <claude|codex>`) before it is written.

Claude Code writes `~/.claude/pstack-models.md` and loads it from `~/.claude/CLAUDE.md` with:

```text
@~/.claude/pstack-models.md
```

Codex writes `~/.codex/pstack-models.md`. Codex has no `@` include, so mirror the sheet's exact bytes inside one bounded block in `~/.codex/AGENTS.md` and retain the sheet as the editable source of truth:

```text
<!-- pstack:models:begin -->
<exact contents of ~/.codex/pstack-models.md>
<!-- pstack:models:end -->
```

## Steps

### 1. Establish the parent

Use the harness and tool surface running this skill: Claude Code or Codex. Environment markers may corroborate that top-level answer, but do not launch a child and ask it to detect where it came from. Record the parent because the same descriptor takes a different route in each harness.

### 2. Load current state

Read the current parent-specific sheet when it exists. Before validating the loaded descriptors, normalize only the rolling-alias predecessors that earlier pstack releases generated. A provider-qualified Claude model is migratable when its model component starts with `claude-fable-`, `claude-opus-`, or `claude-sonnet-` and the remaining revision contains only digits and hyphens. Replace that component in memory with `fable`, `opus`, or `sonnet`, preserving the provider, effort, role, and lane order. Record each original and normalized descriptor for the confirmation in step 8. This migration is valid loaded state and does not require a separate operator choice.

Read the sheet's `# budget` line as the recorded budget choice; a missing or unreadable line means no recorded budget. Read each `# access: <JSON>` line as a per-provider access fact (funding, capacity, `apiSpend`, provenance, and optional display-only plan/note/observedAt). Preserve those facts verbatim unless the operator updates them. Funding, capacity, plan, notes, and observation times are advisory evidence, never credentials or durable entitlement. `apiSpend` is different: it is the binding saved authorization passed to every policy-enabled external attempt until the operator changes it. One `# access` record per provider is the maximum. Provider observations alone do not authorize dispatch: selected funding and API-spend choices require operator confirmation and `provenance: "user"`. Retain provider-reported plan details as optional evidence, then mark the access record user-confirmed when the operator accepts those binding choices. Treat the normalized values as current role-to-family assignments. Overlay those rows on the complete first-run role map in step 8. Materialize any missing documented role row from that map on the next successful write. A duplicate or unknown role row is inconsistent state; report it and resolve it before probing. A bare host-native slug from an older sheet is also invalid because it does not say which provider owns it. A versioned Claude ID outside the three migration families is not an alias or an inconsistency: it stays an exact model ID subject to the same provider rules as any other descriptor. If the sheet is missing, use the complete first-run role map and the model matrix's Default effort cells for rows marked First-run active. Fable, Sonnet, Astra, Luna, and Terra are opt-in: offer them as named role replacements without adding them to the three-family first-run panel. First-run active only seeds defaults; derive assigned families from the final role map on every run.

### Optional Cursor roles

Cursor lanes are opt-in and separate from the three baseline families below. Preserve existing `cursor:<slug>@default` assignments and collect any named Cursor role additions before probing; do not add Cursor to the default panel. Discover exact slugs with `cursor-agent models`; require `default` effort and reject Cursor's `auto` model selector. In step 6, each distinct selected Cursor slug gets one external read-only runner probe from the current parent, alongside the other assigned pairs. `cursor-agent status --format json` must confirm stored OAuth authentication. When `CURSOR_API_KEY` is supplied, the runner instead checks CLI availability and defers authentication to execution; only a successful model result establishes availability. The CLI must be available as `cursor-agent`; never substitute an unrelated `agent` binary.

A selected Cursor lane that fails its probe requires explicit repair or reassignment through step 4 before saving, without changing the active sheet. An unassigned Cursor provider requires neither installation nor probing. Model parsing and final role validation must accept these discovered, probed optional descriptors alongside the model matrix families and aliases. Store them directly in the same role map with `@default`; do not ask a separate reasoning-effort question or create another source of truth.

### Optional Antigravity roles

Antigravity lanes are opt-in and separate from the default panel. Preserve loaded `antigravity:<exact-agy-slug>@default` assignments and accept named additions only after `agy models` lists the exact slug. Do not use `auto`, infer a slug for a hosted Claude model, or pass a separate effort flag: reasoning is part of the listed slug. Record an explicit user-confirmed `# access` fact with `apiSpend: "deny"` or `"approved"` before probing; the runner rejects an omitted choice even for an older sheet. Probe each selected slug from the current parent through the external read-only runner. A model listing alone does not prove authentication or execution. An unassigned Antigravity provider needs no installation or probe.

### Optional OpenCode roles

OpenCode lanes are also opt-in and do not change default panels. Require OpenCode 1.18.29 or newer; older versions predate the GPT-6 OAuth model-filtering fix. The current local validation CLI is 1.18.32. Preserve explicit `opencode:<provider>/<model>@default` assignments. Discover exact IDs with `opencode models`; model IDs can contain additional slash segments. Reject `auto`, missing segments, and non-default effort. Do not pass `--variant`, since unavailable variants can silently use the default. Only built-in providers and native OpenCode authentication are supported initially. Never inspect or copy credential files. OpenCode requires the operator's explicit `apiSpend: approved` access fact; subscription-only routing cannot be proven and both `deny` and omitted legacy policy block before CLI startup. Do not infer approval from an installed CLI, a subscription, or successful authentication. In step 6, probe each distinct assigned OpenCode model through the external runner after approval. The effective-config preflight proves configuration only; a real successful final response proves executable access. Read-only probes have no shell. Writers require the assigned Git worktree root and can edit files but cannot build or run tests. Follow the configuration and startup limits in provider-dispatch.md.

### Optional Devin roles

Preserve loaded Devin assignments and accept explicitly requested named roles using the Optional Devin models rules in provider-dispatch. SWE-2 offers medium/high/max; SWE-1.6 uses the fixed `default` token without an effort question. For other models, use the exact CLI UID at `default` effort and follow the discovery guidance in provider-dispatch. Effort is part of the UID, so never ask a separate effort question or invent a variant suffix. An unavailable or unreadable listing does not reject an explicitly selected ID; the selected-pair probe still must pass. Neither family changes the first-run panel or requires installation or probing when unassigned. For an assigned Devin pair, run `devin auth status`, inspect `devin models list --format json`, and probe the exact model and effort through the external runner. An account gate is a failed selected route, never permission to substitute a model.

### 2b. Discover observable access

Before recommending anything, separate what is observable from what only the operator knows. Discover only supported, read-only facts for the providers the operator is interested in: CLI presence, authentication status, authoritative provider-reported plan metadata, and advertised model lists where the CLI exposes them (for example `codex login status`, `grok models`, `cursor-agent status --format json`, `devin auth status`, `devin models list --format json`, `agy models`). A provider-reported plan or tier is useful evidence about that plan at the observation time and may populate the optional display field; it does not by itself establish included entitlement. An installed binary, successful login, plan report, or model listing does not prove remaining usage, executable capacity, or freedom from provider-managed overage. Never read credential files or print secret values. When the parent exposes an official account/usage tool (such as a usage-limits surface on this host), its snapshot may inform a warning; label it with its source and observation time and do not persist transient usage as entitlement.

Ask only for routing facts discovery cannot prove: which providers have subscription/included access, expected capacity (`standard`, `high`, or `unknown`), and whether metered API spend is `deny` or `approved` for that provider. Reuse facts the operator already gave and access facts already persisted in the sheet; an existing explicit `apiSpend` choice remains binding until the operator changes it, so do not ask again. Plan labels, notes, and observation times are optional; never block setup or ask solely to fill them. Capacity may remain `unknown`. Funding may remain unknown while comparing options, but every provider selected by the final role map must have operator-confirmed funding and an authorized combination before probing or saving: `included` with either saved `apiSpend` choice, or `metered` with `apiSpend: "approved"`. Unknown funding and metered funding with saved denial are blocked routes. Clarify or reassign them; never skip them to a later attempt. Provider-managed overage or on-demand credits can apply under OAuth without an API key, so never promise that denying API credentials guarantees zero charges; name the provider account's own billing controls as the place to set hard limits, and do not change billing settings, redeem credits, or enable paid billing.

### 3. Ask the reasoning budget

Ask for a budget before changing assignments. Prefer AskQuestion over free text. Offer these four options with these exact labels, and name the current budget when the loaded sheet records one.

- `unlimited — keep max`
- `large — xhigh reasoning`
- `medium — high reasoning`
- `small — medium reasoning`

Apply the choice to the normalized working table loaded in step 2, including every existing provider, model, effort, alias, and panel order. Use first-run defaults only for a missing sheet or missing role. Do not infer which loaded values were customized by comparing them with today's defaults. `unlimited` leaves every effort in this table unchanged. For `large`, `medium`, and `small`, use a ceiling of `xhigh`, `high`, or `medium` on the ladder `max` > `xhigh` > `high` > `medium` > `low`. Preserve any valid effort already at or below the ceiling. For an effort above the ceiling, propose the family's highest selectable effort at or below the target; if none qualifies, mark the role as needing a choice. Validate loaded descriptors before applying a ceiling, so an unsupported stored effort is not silently repaired. Aliases and fixed-`default` families such as SWE-1.6, Cursor, and Antigravity lanes do not change. `small` proposes `claude:opus@medium` for `claude:opus@max` but preserves `claude:opus@low`. `large` proposes `devin:swe-2@high` for `devin:swe-2@max`. Every budget preserves `devin:swe-1.6@default`, exact Antigravity slugs at `@default`, `inherit-parent`, and `auto`.

Show every proposed effort change before the final confirmation. This is a requested configuration change, not permission to substitute a model or effort after a failed probe. Honor explicit per-family overrides without raising other families' efforts.

### 4. Select role assignments

Show the normalized complete role map, the model matrix, and this parent's routes. Ask whether to keep the assignments or change named roles. Preserve current assignments by default; on a first run, explain that the example uses all three families but none is mandatory. The operator can replace named lanes with any supported provider's `provider:model@effort` descriptor — a recommended matrix family, another exact model ID the provider's CLI advertises, or an exact Devin, Cursor, Antigravity, or OpenCode slug — plus `inherit-parent`, or `auto`, or remove named entries from a panel. A request to omit a provider must resolve every occurrence, including single-model roles and panel entries. Do not silently remap missing providers, reset customized lanes, or drop an entire role. Keep at least two entries in `architect runners`, at least one entry in every other panel, and exactly one descriptor for each single-model role. Repeated descriptors are allowed: `architect runners: inherit-parent, inherit-parent` launches two independent candidates without requiring another provider. If a requested removal leaves fewer than two architect entries, ask for an explicit replacement or another entry before probing or writing; never add a provider silently.

Why and Reflect require the parent's live MCP surface. Keep their investigator, reviewer, and synthesizer roles on `inherit-parent` or `auto`. Preserve all documented role rows, and preserve the order of untouched lanes. Say when replacements or removals reduce provider diversity. If the operator already named role changes, apply those without asking them to repeat the choice.

When recommending a mix, reason from confirmed facts: task fit, included or reported capacity before metered spend, the requested reasoning budget, required MCP access, and panel provider diversity. Suggest concrete ordered fallbacks where they add real coverage — a second provider's included capacity behind a constrained primary — and explain what each fallback changes in quality or provider mix. Every fallback must name an exact `provider:model@effort` descriptor, `inherit-parent`, or `auto`; never a different model on the same provider's current CLI account, and at most three attempts per seat. Choose recovery behavior separately in step 4a. An existing sheet's policy line, including its absence (quota-only), is preserved verbatim unless the operator explicitly accepts a change. Preserve existing customized assignments, efforts, lane order, and chains unless the operator accepts a change. Why and Reflect stay on `inherit-parent` or `auto`; an MCP-less external lane is not an equivalent substitute there.

Derive the assigned family set from the resulting role descriptors, excluding `inherit-parent` and `auto`. An unassigned family is optional: do not ask for its effort, check its CLI or credentials, or probe it. A missing Grok CLI cannot block a configuration with no Grok roles. Availability checks must not choose assignments for the operator.

### 4a. Choose automatic recovery

On first setup and reruns, show the current fallback mode, including usage exhaustion only when no `# fallback` line exists. Ask which mode to use, with these choices and effects. Reuse an explicit choice already made in this conversation instead of asking again; an unanswered question preserves the current policy. Recommend automatic recovery for a new sheet, but do not enable it without acceptance.

- **Automatic recovery (recommended).** Use the next saved fallback when usage is exhausted, a route is unavailable, the backend terminates unsuccessfully, or an explicitly configured deadline expires. Save `# fallback: {"on":["usage-exhausted","route-unavailable","terminal-failure","deadline-exceeded"]}`.
- **Usage exhaustion only.** Use the next saved fallback only on proven exhaustion. Save `# fallback: {"on":["usage-exhausted"]}` when changing modes; preserve an existing quota-only declaration or its absence when keeping that mode.
- **No automatic fallback.** Do not advance to another descriptor after a failed attempt. Save `# fallback: {"on":[]}`; removing the line would restore quota-only behavior. Preserve saved chains so they remain available if the operator later enables fallback.

For an existing custom subset, show its actual triggers and allow keeping it verbatim rather than forcing it into one of these presets. Explain that each mode uses only the exact saved chains; a seat without a backup gains no additional provider. Changing recovery never changes models, efforts, access or spending permission, and never adds a timeout. A completed response reporting failing project tests is task output, not a backend failure. Cancellation, billing blocks, safety denials, and unsupported capabilities stop under every fallback mode. A verified permission blockage cannot switch providers. Refer to [saved fallback and backend recovery](../poteto-mode/references/provider-dispatch.md#saved-fallback-and-backend-recovery) for receipt classification and writer inspection requirements.

Ask a separate continuation question on first setup and reruns, showing the current `# continuation` policy or its absence. Offer **Resume the same model after a corrected permission blockage or completed parent handoff** with `# continuation: {"on":["permission","handoff"],"max":2}`, or **Stop without automatic continuation**, represented by no continuation line. The limit is two total executions per descriptor, including the original, not two retries. Keep the current choice unless the operator explicitly changes it; reuse a choice already made and preserve custom causes or limits verbatim when keeping them. Explain that continuation requires parent inspection of partial work and side effects, a concrete corrected blockage or completed operation, stopped prior writers, and a fresh execution. It never bypasses a denial or switches models. Do not infer continuation consent from accepting automatic fallback. Show both selected policies again at confirmation.

### 5. Validate and choose assigned efforts

Every non-alias value must match `<provider>:<model>@<effort>` on a supported provider. Apply the optional Cursor, Antigravity, and OpenCode rules above to their descriptors. The model matrix supplies recommended defaults and effort guidance, never an allowlist: the model is the exact ID the provider's CLI accepts, not a matrix row. Where the CLI advertises a model list — `grok models`, `devin models list --format json` (`variants[].model_uid` only), `cursor-agent models`, `agy models`, `opencode models` — choose the ID from it, remembering that a listing is evidence, not entitlement. Use current host capabilities for Claude and Codex where exposed, and let the step 6 probe prove an explicitly selected alias or exact model ID. Effort stays per provider: `low` through `max` for Claude, Codex, and Grok; fixed `default` for Cursor, Antigravity, OpenCode, and Devin UIDs, whose effort is part of the ID; the legacy `devin:swe-2@medium|high|max` and `devin:swe-1.6@default` mappings unchanged. Matrix rows keep their Selectable efforts guidance for the listed families. An invalid descriptor, out-of-domain effort, duplicate role, or unknown role is inconsistent state; never mutate an unknown model into a matrix family name or substitute a different model for the selected one. Show the conflicting rows verbatim and resolve them through an explicit provider-qualified descriptor or alias replacement before probing or writing.

Within one seat, `attempt -> attempt` is an ordered chain: at most three attempts, no repeated descriptor, and no two attempts on the same provider's current CLI account (an alias or a descriptor on the parent's provider both use the parent provider). Why and Reflect rows may contain aliases only. A seat's commas still mean independent lanes; chains never merge seats.

Use the resulting efforts from step 3 as the requested efforts. `unlimited` has no replacement target and never resets an existing effort to `max`. Collect a different effort only when the operator requests an override, a newly assigned model needs a choice, or the resulting map has a conflict. Name the model, its valid efforts for that provider, and its current value; propose the matrix Default effort for a matrix family and `high` for another Claude, Codex, or Grok model. Empty input keeps that value. If the resulting roles use mixed efforts for one provider/model, show all conflicting rows and ask for one effort from its valid set. Do not invent precedence. Honor efforts the operator already explicitly selected.

An effort-only rerun preserves each role's family and lane order. Rewrite every occurrence of an assigned family to its selected effort; leave aliases unchanged. If every role uses an alias, there are no family effort questions or model-pair probes.

### 6. Probe the assigned routes

Probe each distinct assigned `provider:model@effort` pair once, even when two assigned families share a provider, and probe every attempt in every saved chain — a persisted fallback must be proven like a primary. Do not enumerate or offer older models as substitutes. The table below defines routes for providers that are assigned; it is not a required-provider checklist. Probe the operator's exact selected model ID — never a matrix-family substitute — and treat every listing as advisory: only the probe proves the route runs.

Every route probed as a candidate for the new rendered sheet is policy-controlled, including an unchanged assignment loaded from a legacy sheet. Pass that provider's saved `apiSpend` policy to every external probe. Reuse an existing `approved` or `deny` decision without asking again. Only when no saved decision exists and a probe could spend money — a route whose only usable credential is an ambient API key or a provider-declared metered account — ask once for explicit permission. Record a new approval in that provider's `# access` fact and pass `--api-spend approved`; when approval is absent or declined, record and pass `--api-spend deny` so a known ambient API credential cannot silently take over the lane. A metered-denied route remains blocked and must be reassigned unless the operator chooses to change that decision. Grok currently cannot prove subscription-only routing: per-model BYOK can override login. With `apiSpend: deny`, reassign that route when its probe is blocked; never suggest approving API spend merely to bypass this check. Claude invocations under `deny` exclude user/project/local settings and reject known API environment routes. Do not run `claude auth status`, including during discovery: its startup refresh can invalidate login before the replacement token is saved. Authentication is deferred to the actual one-turn probe; Claude billing type remains unverified. See [the recorded exception](https://github.com/arjitj2/open-pstack/issues/38) and [upstream refresh bug](https://github.com/anthropics/claude-code/issues/95822). Ordinary runtime execution from an untouched legacy sheet preserves its existing behavior only until setup writes a policy-enabled sheet.

If any role uses `inherit-parent` or `auto`, also run one tiny read-only native inherited-agent probe with a unique marker before writing. It must use the parent's native delegation surface with the model omitted, even when there are no explicit model pairs. Reuse that successful alias-route result for aliases within this setup run only while the parent and native route remain unchanged. A disabled or unavailable native delegation tool fails this probe; the parent answering the marker itself does not count.

A failed probe writes nothing. Report the failing pair or inherited native route, cause, and affected roles. Let the operator repair availability and retry, explicitly remap or remove affected lanes via step 4, or cancel. Recompute assigned families and efforts after any role change, and probe any new or changed pairs before proceeding. Successful results may be reused only within this setup run for the same parent, pair, and unchanged route. Do not treat a failed selected lane as successful or silently replace it. Until every final selected pair and any required alias-route probe passes, keep the active sheet and parent integration bytes unchanged; a failed first run creates neither artifact.

| Assigned provider | Claude parent route | Codex parent route | Availability proof |
|---|---|---|---|
| Claude model | shipped `pstack-<stem>-<effort>` agent when one's frontmatter selects the model and effort, else Claude CLI | Claude CLI | native one-turn probe or one-turn runner probe without a separate auth-status command |
| Codex model | `codex exec` | native `spawn_agent` with the assigned model and effort | `codex login status` plus one-turn probe or native one-turn probe |
| Grok model | Grok CLI | Grok CLI | `grok models` must list the requested model; one-turn probe |
| Optional Antigravity slug | `agy` CLI | `agy` CLI | `agy models` must list the exact slug; one-turn read-only probe |

Use a tiny read-only probe that returns a unique marker. A login-status command alone proves credentials, not that the requested model and effort flags run. Record native and external results separately. Never call the external launcher for a descriptor the parent's native route covers. On a Claude parent, a Claude model is native exactly when a shipped `pstack-<stem>-<effort>` agent's frontmatter selects that model and effort — this includes Fable's, Opus's, and Sonnet's five effort-specific agents; probe every other Claude model through the external runner with its ID unchanged. On a Codex parent, each assigned Codex model uses native `spawn_agent` with its exact model and selected `reasoning_effort`; if the host's advertised capabilities exclude the selected model, report that limitation honestly instead of substituting another model. Every other pair uses the external runner with the selected effort; Cursor, Antigravity, OpenCode, and Devin UIDs use `default` and pass no reasoning-effort flag to their CLIs.

Launch Claude-native probes and smoke candidates in the background with retained handles. Before native probes, observe the available native agent slots, accounting for existing live handles. Launch no more native probes than the available capacity. Drain each completed handle and release its slot using a harness lifecycle tool when exposed, or observe automatic release on completion before launching the next wave. If capacity cannot be observed, run native probes conservatively one at a time; when no slot is available, drain existing owned work or report unavailable delegation without rerouting. Launch external probes in the background concurrently with distinct paths and retained handles; native capacity does not serialize external processes. Finish and verify every probe before confirmation. Never use a timeout or fallback to clear a slot.

Receipts and native transcripts prove the requested effort and the route. They do not prove a provider's hidden applied reasoning depth. There is no implicit timeout, weaker-model fallback, or second mutable configuration source. A same-parent external Claude route is selected before the attempt, never used as a retry after native failure.

### 7. Render the selected role map

Build the new sheet in memory from the complete role map selected in step 4 and the requested efforts from step 5. Record the chosen budget as a `# budget: <label> (<target effort>)` line, matching the example below. Write one `# access: <JSON>` line for every provider used by a descriptor or native alias, preserving funding, capacity, `apiSpend`, provenance, and any optional display-only plan/note/observedAt value already known; aliases use the parent provider's record. Write at most one `# fallback: <JSON>` line carrying the accepted policy (a verbatim copy of the loaded line when unchanged, absent when retaining an existing implicit quota-only policy); never write two declarations. Render the accepted step 4a continuation choice, preserving a loaded line or its absence when unchanged; remove the line only when stopping continuation was explicitly selected. Do not insert one merely because a probe succeeded. Capacity may remain `unknown`; reject unknown funding or metered funding with denied API spend for any selected provider. Render each seat's attempts joined by ` -> ` and seats joined by `, `, exactly as the model sheet grammar defines. Do not write it yet. Run `pstack-model-policy validate --sheet <candidate-file> --parent <claude|codex>` and require it to resolve every configured role row. Also validate complete role coverage, at least two architect runner entries, nonempty other panels, Why/Reflect aliases, chain limits, and successful step 6 results for every non-alias descriptor in every chain and the inherited native route whenever aliases are present. Refuse an unqualified slug, an unavailable selected route, a descriptor that violates its provider's grammar or effort rule, an unprobed model ID, a provider/model mismatch, or a missing binding `apiSpend` choice.

There is no requirement to assign every matrix family. Efforts persist only in assigned role descriptors; do not add placeholder roles or another configuration source to store unassigned efforts. If the operator changes a role at confirmation, return to step 4 and revalidate its resulting pairs before writing.

### 8. Confirm and commit

Show any rolling-alias migrations as original and normalized descriptors. Then show the complete diff: the route table for this parent, every rendered role with its seats and ordered chains, every `# access` fact with its provenance and funding labels, and the selected fallback and continuation modes with their effective triggers and total execution limit. Show an implicit quota-only mode and absent continuation explicitly in the summary even when neither adds a line. Explain quality or provider-diversity changes the new map makes. Ask for confirmation before writing.

Why and Reflect require the parent's live MCP surface. Keep their investigator, reviewer, and synthesizer roles on `inherit-parent` or `auto`; the bounded external runner deliberately omits ambient MCPs. `inherit-parent` and `auto` are valid descriptors, but their native route must pass step 6. Say when they reduce a panel's provider diversity. For panel roles, one lane runs per entry. The list length is the fan-out count; do not deduplicate repeated entries. Architect still requires at least two structurally distinct design candidates before synthesis; repeating a model does not waive that requirement. `arena cross-judge pool` is a list from which Arena chooses a provider different from the parent and base candidate when possible. `swarm workers` is the default for every worker unless a race explicitly assigns another descriptor.

Every non-alias value must match `<provider>:<model>@<effort>` and must have passed step 6. Any aliases require a successful inherited native-route probe.

After the operator confirms, write the in-memory render from step 7. Never paste the example below as the result. It is only the complete first-run role map used to seed step 2; selected efforts and explicit role changes always replace its example values before writing.

```markdown
# pstack model configuration

Provider-qualified per-role choices. Read the installed pstack provider-dispatch reference before dispatching a configured role. Every documented role remains present. `inherit-parent` and `auto` use the parent model natively and still count as one panel lane. The `# budget` line records the reasoning budget chosen in step 3.

# budget: unlimited (max)

feature, refactoring: grok:grok-4.7@xhigh
bug-fix: codex:gpt-5.6-sol@max
perf-issue: codex:gpt-5.6-sol@max
hillclimb: codex:gpt-5.6-sol@max
judgment and prose: claude:opus@max
hardest tasks: claude:opus@max
how explorer: grok:grok-4.7@xhigh
how explainer: claude:opus@max
why investigators, synthesizer: inherit-parent
reflect tooling, judgment, divergent, synthesizer: inherit-parent
arena runners: codex:gpt-5.6-sol@max, grok:grok-4.7@xhigh, claude:opus@max
arena cross-judge pool: codex:gpt-5.6-sol@max, grok:grok-4.7@xhigh, claude:opus@max
swarm workers: grok:grok-4.7@xhigh
architect runners: codex:gpt-5.6-sol@max, grok:grok-4.7@xhigh, claude:opus@max
interrogate reviewers: codex:gpt-5.6-sol@max, grok:grok-4.7@xhigh, claude:opus@max
```

### 9. Wire it in

Render the parent integration in memory before either write. On Claude, the integration is the single `@~/.claude/pstack-models.md` include in `~/.claude/CLAUDE.md`. On Codex, it is the exact sheet bytes between one `<!-- pstack:models:begin -->` and `<!-- pstack:models:end -->` pair in `~/.codex/AGENTS.md`. Replace that whole bounded block on a rerun. Insert one block at the end on first run. If either marker is missing, duplicated, or reversed, stop and report inconsistent state instead of guessing a boundary.

Snapshot every target's current bytes. Write the sheet and parent integration only after all required assigned-pair and inherited native-route probes pass and the operator confirms. Read both targets back and compare them with the in-memory render. If either write or readback fails, restore every snapshot and report the failure. An unchanged rerun must produce byte-identical sheet and integration content after normalization.

Do not copy the model sheet between harnesses without rerunning the parent-specific probes; route availability can differ even on the same host.

### 10. Behavioral smoke

Before declaring setup complete, run one small read-only panel from this parent using each distinct assigned descriptor, with distinct output/receipt paths and an independent cross-judge from the configured cross-judge pool. If any roles use aliases, also exercise a native inherited lane; for an alias-only sheet, that native lane is the whole panel. Use a different-provider judge when the configured pool permits it, otherwise use a separate native or configured judge and report the reduced diversity. Never add an unassigned provider merely to make the smoke multi-provider. A smoke failure leaves setup incomplete; report the failing lane and return to step 4 or let the operator repair and retry. Observe available native slots again for the smoke. Launch native candidates in capacity-bounded waves, drain completed handles and release their slots before subsequent waves, and use one native lane at a time if capacity cannot be observed. Launch every external process in the background concurrently with retained handles. Wait for all candidates to finish and verify their results before launching the independent judge; the judge uses the same native capacity and handle-release rules. Never time out a candidate or substitute another route to make room. Verify the native transcript entries and every external receipt. A structural config check or unit test is not a substitute.

Report the sheet path, parent route table, requested-effort probe results, smoke results, and external elapsed/token/cost receipts. Re-running this skill re-probes and updates the same sheet. Do not claim the provider exposed hidden applied-effort observability.

## Codex startup routing (optional)

On a Codex parent only, offer one independent choice after the model flow settles: whether Pstack's bundled `SessionStart` hook should route non-trivial engineering tasks into `pstack:poteto-mode` at session startup, resume, clear, and compaction. Codex owns this preference: the plugin hook is listed in `/hooks` but skipped until the operator reviews and trusts its exact definition, and `/hooks` also owns the per-hook enabled switch. A hook reported as enabled but untrusted is inactive until trusted. Never describe it as already routing or as Pstack-disabled by a saved setting. Leaving the hook untrusted keeps routing off; an already trusted hook can be disabled in `/hooks`, and a changed hook definition needs renewed trust before it runs again.

Setup guides this native choice and never fabricates it: do not write a preference file, copy the routing text into `AGENTS.md`, claim a saved or trusted state, or infer consent from model setup. To enable, the operator opens `/hooks` in Codex CLI, reviews the pstack `SessionStart` entry, and trusts it; to opt out later, they disable the same entry. If the host exposes a read-only hook listing, report its observed trust and enabled state verbatim; otherwise ask the operator to check `/hooks`. An unrelated model-setup rerun preserves the existing hook choice — setup never changes hook trust or enabled state.

A request to enable, disable, or check Codex startup routing without changing models skips steps 2 through 10: no provider discovery, no probes, no sheet render, no writes. Confirm `~/.codex/pstack-models.md` and the `<!-- pstack:models:begin -->`/`<!-- pstack:models:end -->` block in `~/.codex/AGENTS.md` remain byte-identical. On a Claude parent this section does not run; Claude Code already loads the shared instruction through its own plugin hook.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…