A tier's model can be unusable for reasons that have nothing to do with the
task, typically an expired AWS SSO session behind an amazon-bedrock profile.
pi reports that as a normal run: rc 0, agent_end, willRetry=false. The failure
shows only as stopReason="error" + errorMessage on the assistant message
(measured 2026-10-12). pi-task turned it into "no fenced json envelope",
which points at the wrong layer.
- Always surface it, first in the problem list:
"child model error (<provider>/<id>): ...".
- New, optional: pi-task.fallbackProfiles.<effort> = {provider, id[, thinking]}
in ~/.pi/agent/settings.json. It is tried ONCE, and only when the primary
ended in an auth-class error, made zero tool calls, left the boundary
diff empty, and at least 30 s of wall_s remain. A write task that failed
after acting is never re-run on a half-edited tree.
- A fallback without `thinking` inherits the primary's rather than "off".
A fallback identical to the primary is ignored, with a warning.
- The key lives in pi-task's own namespace because the fork tool does not
fall back. pi-fork's parser silently drops unknown profile keys.
- Reporting: "[FALLBACK]" on the verdict line plus a warning line.
result.json gains fallback{} and attempts[]; metrics.model/provider name
the model that produced the verdict. Audit keeps raw.primary.ndjson,
argv.fallback.json and boundary-after.primary.json. The second attempt
gets only the remaining wall budget, so the task tool's (wall_s+90) s kill
still holds.
- Unchanged: exit 0 = PASS / 1 = FAIL, and the closing "audit:" line.
selftest: 14 -> 29 checks, two-sided for every gate (fixtures mirror the
measured event shape; the SSO string is verbatim from a real expired
session). Each gate was mutation-checked: removing it turns its line BAD.
End-to-end, emb-7kj4vr4g, with fake AWS keys in the environment:
- the old pi-task gives FAIL "no fenced json envelope";
- the new one, per tier, gives PASS [FALLBACK] with the correct answer and
real tool calls;
- with real credentials: PASS on the primary, fallback configured but unused;
- with no fallback configured: FAIL, model error listed first.
A fork child inherits the parent's whole session branch by design, and has
twice written to the shared palace under the parent's identity. extensions: []
runs children with --no-extensions; the mempalace bridge is an extension, so
the write path is gone by construction rather than by instruction. Costs forks
their palace search and recall; set to null to restore normal loading.
pi 0.82.0 added Claude Opus 5 (Anthropic + Bedrock, adaptive thinking incl.
xhigh, 1M ctx / 128K out). Point the template at it:
- defaultModel: eu.anthropic.claude-opus-4-8 -> eu.anthropic.claude-opus-5
- enabledModels: add opus-5 at the head, drop opus-4-7 (superseded; 4-8 kept
as the previous-gen fallback so the picker stays at four entries)
- pi-fork deep tier: opus-4-8 -> opus-5 (fast=haiku-4-5, balanced=sonnet-5
unchanged)
README's settings-template snippet updated in the same commit to stay in sync.
Fresh machines / fresh pi-devbox volumes get this verbatim via the entrypoint
bootstrap. Existing volumes are unaffected: entrypoint-user.sh deep-merges
template-FIRST, live-SECOND with arrays as leaves, so live values win and no
model a user removed is re-added.
pi-fork balanced tier + enabledModels and the README examples now point at
eu.anthropic.claude-sonnet-5 (matches the live settings.json change made
before the container recreate).
settings.example.json is consumed by two very different deployments:
the native workstation (where pi-env.zsh sources ~/.config/pi/.env — the
path is real and correct) AND the pi-devbox image, which bakes this file
as the settings.json seed at /opt/pi-toolkit/. In the container there is
no ~/.config/pi/.env: env comes from the compose env_file. The old
comment pointed only at the workstation path, which is stale/misleading
inside the container.
Reword to 'Must match your AWS_REGION' — accurate in both contexts,
without asserting a path that exists in only one. Comment-only change;
no keys touched. The other ~/.config/pi/.env references (install.sh,
README, AGENTS, pi-env.zsh) are workstation-correct and left as-is.
Pi-generic config artifacts (no mempalace dependency):
- pi-env.zsh: shell loader sourcing ~/.config/pi/.env for AWS_PROFILE /
AWS_REGION. POSIX-compatible (works in bash and zsh).
- keybindings.json: mosh/tmux newline bindings (shift+enter, ctrl+j, alt+j).
- settings.example.json: ~/.pi/agent/settings.json template so pi starts
without --provider/--model. Region-specific (Bedrock inference-profile
prefix).
install.sh mirrors mempalace-toolkit + opencode-toolkit patterns:
- require_pi_installed: hard exit 4 if ~/.pi/agent/ missing (cannot do
anything useful; user must install pi first).
- symlink keybindings.json (safe: pi doesn't rewrite it).
- cp pi-env.zsh into ~/.oh-my-zsh/custom/ (portability over symlink,
that dir is part of dotfiles backups). Print source snippet for bash
/ plain-zsh users.
- settings.example.json NOT installed \u2014 pi rewrites settings.json at
runtime. check_pi_settings probe prints the cp command instead.
- check_aws_env: gated on settings.json selecting amazon-bedrock; silent
for non-Bedrock providers or missing settings.
- All probes warn + return 0, never halt.
- Non-destructive: backup on symlink collision, cmp-based drift detection
on the cp path, uninstall only removes copies whose content still
matches repo.
Split rationale: opencode-devbox's mempalace opt-out (~300 MB saved)
wants pi available without mempalace. That dependency asymmetry is
cleanest when pi's own config lives in its own repo, same shape as
opencode-toolkit split out earlier today.
The pi\u2194mempalace MCP bridge (mempalace.ts) stays in mempalace-toolkit
where it belongs \u2014 it imports pi's ExtensionAPI but only exists to
bridge to the palace.
Verified on tor-ms22: fresh install \u2192 drift detect \u2192 adopt canonical \u2192
uninstall \u2192 reinstall \u2192 zsh -ic loads AWS vars. Bash fallback path also
tested via HOME=/tmp/fake SHELL=/bin/bash.