Initial commit: pi harness bring-up split out of mempalace-toolkit

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.
This commit is contained in:
2026-05-05 17:22:06 +02:00
commit ff774cf88f
7 changed files with 762 additions and 0 deletions
+197
View File
@@ -0,0 +1,197 @@
# AGENTS.md
## What this is
Harness-side bring-up for the [pi coding-agent](https://github.com/mariozechner/pi-coding-agent).
Installs three pi-generic config artifacts into the right places and
runs a couple of non-halting probes. Does not depend on MemPalace.
Sibling to [`opencode-toolkit`](https://gitea.jordbo.se/joakimp/opencode-toolkit) —
same shape: one `install.sh` at the root, cp-or-symlink the config files,
probe the environment, compose independently of the palace memory layer.
Read [`README.md`](README.md) first for the user-facing walk-through.
This file is for agents modifying the repo.
## Structure
```
install.sh # Idempotent installer (symlink + cp + probes)
pi-env.zsh # Shell loader sourcing ~/.config/pi/.env (POSIX-compatible)
keybindings.json # ~/.pi/agent/keybindings.json — mosh/tmux newline fix
settings.example.json # Template for ~/.pi/agent/settings.json (copy + edit)
README.md # User-facing quickstart + new-machine deploy recipe.
AGENTS.md # This file.
LICENSE # MIT.
```
## Conventions
- **One install step per artifact**, with a matching uninstall step.
- **Symlink what's safe to symlink, cp what's part of a dotfiles backup,
template what the harness rewrites.**
- `keybindings.json` → symlink. pi doesn't rewrite it; the symlink
lets edits flow through git without a re-install step.
- `pi-env.zsh``cp` into `~/.oh-my-zsh/custom/`. That dir is
typically part of a dotfiles backup (e.g. `myconfigs`'s
`rsync_copy.sh`); a symlink into this repo's absolute path breaks
when the backup is restored on another host.
- `settings.example.json`**not installed**. pi rewrites
`~/.pi/agent/settings.json` at runtime (`lastChangelogVersion` bumps
on upgrade), so any symlink back to the repo would dirty the
working tree. Installer prints the `cp` command and walks away.
- **Probes warn, never halt.** `warn` + `return 0`. The installer's only
hard-fail path is "pi isn't installed at all" — that's an early
`exit 4` from `require_pi_installed` because there's nothing useful
to do without `~/.pi/agent/`.
- **Non-destructive.** Existing real files at symlink destinations get
backed up with a timestamp (`.bak.YYYYMMDD-HHMMSS`) before linking.
The shell loader's cp path refuses to clobber local edits: detects
drift via `cmp -s`, prints a `diff` hint, leaves the file alone.
- **Do not auto-edit rc files.** If oh-my-zsh isn't present, print the
`source` snippet the user manually adds to `~/.zshrc` or `~/.bashrc`.
Invasive shell-rc edits belong in a dotfiles installer, not here.
- **No hard dependency on mempalace.** If the surface ever grows
mempalace-aware (unlikely — those pieces live in `mempalace-toolkit`
on purpose), it must degrade gracefully when mempalace is absent.
- **POSIX-compatible shell glue.** `set -a` / `source` / `set +a` work
in bash and zsh both. Don't add zsh-only constructs to files that
may end up sourced from `~/.bashrc`.
## What `install.sh` does
Hard-required:
- `require_pi_installed` — aborts with exit 4 if `~/.pi/agent/` is missing.
Creates `~/.pi/agent/extensions/` proactively so a later
`mempalace-toolkit` install has somewhere to symlink into.
Always (once pi is present):
- Symlinks `keybindings.json` into `~/.pi/agent/`. Backs up any
pre-existing real file.
oh-my-zsh path (gated on `~/.oh-my-zsh/custom/` existing):
- Copies `pi-env.zsh` into that directory. Drift-safe — prints a `diff`
hint if installed content differs from repo, doesn't clobber.
No oh-my-zsh path:
- Prints a shell-specific source snippet for `~/.zshrc` or `~/.bashrc`
(selected from `$SHELL`). User pastes manually.
Probes (non-halting):
- `~/.pi/agent/settings.json` exists. Without it pi refuses to start
without `--provider`/`--model`. Prints the `cp settings.example.json`
command.
- `AWS_PROFILE` + `AWS_REGION` are set, **only if** `settings.json`
selects `amazon-bedrock`. Silent for non-Bedrock providers. Silent if
settings.json is missing (check_pi_settings already handled that case).
## Adding a new artifact
Follow the same shape `keybindings.json` / `pi-env.zsh` / `settings.example.json` use:
1. **One file at repo root.** Flat layout; no `extensions/` subdir yet.
Revisit if five+ artifacts ever accumulate.
2. **Choose symlink / cp / template** per the conventions above. Document
the choice in a comment next to the variable declarations at the top
of `install.sh`.
3. **One install step + one uninstall step** in `install.sh`, guarded by
`link_if_into_repo` (for symlinks) or `cmp -s` (for copies). Never
remove user edits silently.
4. **One probe per external dependency** the artifact implies. `warn` +
`return 0`.
5. **Update this file's Structure block** and `README.md`.
## Adding mempalace-aware functionality
Don't. Those pieces belong in `mempalace-toolkit/extensions/pi/`:
- The mempalace MCP bridge TypeScript extension (`mempalace.ts`) —
imports pi's `ExtensionAPI`, registers MCP tools, injects wake-up
context.
- The `install_pi_extension` function that symlinks it in.
- Any probes that check for mempalace being reachable *through* pi.
That boundary is load-bearing for `opencode-devbox`'s slim container
path: a container built with `INSTALL_MEMPALACE=false` should install
pi-toolkit cleanly and get a functional pi without dragging in
chromadb + embedding models (~300 MB).
## Testing
No framework. Manual:
```bash
./install.sh --help # flags
./install.sh --yes # fresh install
./install.sh --yes # re-run (idempotent)
./install.sh --uninstall --yes # remove
./install.sh --yes # reinstall
```
oh-my-zsh fallback simulation:
```bash
SHELL=/bin/bash HOME=/tmp/fake ./install.sh --yes # should print ~/.bashrc snippet
```
Environment verification (after install + `exec zsh` or new shell):
```bash
zsh -ic 'echo $AWS_PROFILE $AWS_REGION' # should print values from ~/.config/pi/.env
```
Drift simulation:
```bash
echo "# local edit" >> ~/.oh-my-zsh/custom/pi-env.zsh
./install.sh --yes # should warn "differs from repo" and leave alone
```
## Gotchas
- **pi must be installed upstream first.** `~/.pi/agent/` is created by
pi on first run, not by this installer. Missing → exit 4 with
pointer to https://github.com/mariozechner/pi-coding-agent.
- **`settings.example.json` is region-specific.** The shipped default
uses `eu.` Bedrock inference-profile prefixes. Users on us-east need
to swap to `us.` before first run, or pi will reject the model ID.
- **Bedrock is not the only provider.** If the user is on bare
Anthropic or OpenAI, `AWS_PROFILE` / `AWS_REGION` are irrelevant. The
probe gates on `grep -q '"amazon-bedrock"' settings.json` to stay
quiet in those cases.
- **Mosh strips modifiers upstream of tmux.** The keybindings file's
`ctrl+j` / `alt+j` fallbacks are specifically because mosh's vt220-ish
emulation does not forward `Shift+Enter` as CSI-u — tmux's
`extended-keys csi-u` setting doesn't help over mosh (only helps on
direct ssh / local / WireGuard). Documented in README.
- **The shell loader runs on every shell start.** Keep it fast. If it
grows beyond a few lines, gate on `[[ $- == *i* ]]` so
non-interactive shells skip the work.
- **`~/.config/pi/.env` should be chmod 600.** It's plaintext on disk;
git-crypt encryption only applies in the dotfiles repo. The installer
does not enforce this because it doesn't ship the file.
## Related repos
- [`mempalace-toolkit`](https://gitea.jordbo.se/joakimp/mempalace-toolkit)
— adds a pi↔mempalace MCP bridge on top of this toolkit. Installs the
`mempalace.ts` extension into `~/.pi/agent/extensions/`. Optional.
- [`opencode-toolkit`](https://gitea.jordbo.se/joakimp/opencode-toolkit)
— sibling pattern for the opencode coding-agent. Same install.sh
shape.
- [`opencode-devbox`](https://gitea.jordbo.se/joakimp/opencode-devbox)
— Docker containers; composes any subset of these toolkits via
independent install.sh invocations.
- [`myconfigs`](https://gitea.jordbo.se/joakimp/myconfigs) — dotfiles
repo where `~/.config/pi/.env` is tracked (git-crypt encrypted).
## History
Split out of `mempalace-toolkit/extensions/pi/` on 2026-05-05. Previously
the pi-generic config artifacts (env loader, keybindings, settings
template) lived alongside the `mempalace.ts` MCP bridge inside
mempalace-toolkit because that's where the pattern first crystallized.
The split was motivated by `opencode-devbox`'s mempalace opt-out and
future pi-option: a container built with mempalace off should still be
able to install a functional pi, and that dependency asymmetry is
cleanest when pi's own config lives in its own repo. Mirrors the
2026-05-05 split of `opencode-toolkit` out of the same parent.
+18
View File
@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2026 joakimp
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+228
View File
@@ -0,0 +1,228 @@
# pi-toolkit
Harness-side bring-up for the [pi coding-agent](https://github.com/mariozechner/pi-coding-agent).
**What's here:**
- `pi-env.zsh` — loads `~/.config/pi/.env` into every shell so pi's Bedrock provider has `AWS_PROFILE` / `AWS_REGION` available.
- `keybindings.json` — mosh/tmux-friendly newline bindings (`shift+enter`, `ctrl+j`, `alt+j`).
- `settings.example.json` — template for `~/.pi/agent/settings.json` so `pi` starts without having to pass `--provider`/`--model` on every invocation.
- `install.sh` — idempotent installer wiring all three into place.
**No dependency on MemPalace.** For the palace memory layer see [`mempalace-toolkit`](https://gitea.jordbo.se/joakimp/mempalace-toolkit) — it installs a pi↔mempalace MCP bridge on top of this toolkit. The two repos compose but don't require each other, same pattern as [`opencode-toolkit`](https://gitea.jordbo.se/joakimp/opencode-toolkit) ↔ mempalace.
---
## Why this exists
Pi, out of the box on a fresh machine, has three friction points that this toolkit fixes:
1. **No model selection without `--model`.** Every invocation needs `pi --provider ... --model ...` until `~/.pi/agent/settings.json` exists with defaults. The shipped `settings.example.json` is a working eu-west-1 Bedrock template — copy, edit for your region, done.
2. **`Shift+Enter` (newline in the TUI) doesn't work over mosh/tmux.** mosh's vt220-ish emulation strips modifier keys upstream of tmux, so pi never sees the Shift bit. The shipped `keybindings.json` adds `ctrl+j` and `alt+j` fallbacks that pass through as plain control/meta bytes.
3. **Bedrock provider needs `AWS_PROFILE` and `AWS_REGION` in the shell environment at spawn time.** The shipped `pi-env.zsh` sources `~/.config/pi/.env` into every shell (`set -a; source; set +a`), so you can edit credentials in one plaintext-on-disk, encrypted-in-git-repo file.
None of this talks to MemPalace; it's all pi's own configuration surface.
---
## Install
```bash
git clone ssh://git@gitea.jordbo.se:2222/joakimp/pi-toolkit.git ~/pi-toolkit
cd ~/pi-toolkit
./install.sh
```
Requires pi to be installed first (`~/.pi/agent/` must exist). Install via:
```bash
brew install pi-coding-agent # macOS
# or see https://github.com/mariozechner/pi-coding-agent for Linux
pi --help # first run creates ~/.pi/agent/
```
What `install.sh` does:
| Step | Action |
|---|---|
| Symlink `keybindings.json` | `~/.pi/agent/keybindings.json` → repo. Safe to symlink: pi doesn't rewrite it. |
| Install `pi-env.zsh` | `cp` into `~/.oh-my-zsh/custom/` if oh-my-zsh detected; otherwise print shell-specific `source` snippet for `~/.zshrc` or `~/.bashrc`. Does not auto-edit rc files. |
| `settings.example.json` | **Not installed.** Installer warns if `~/.pi/agent/settings.json` is missing and prints the `cp` command. NOT symlinked because pi rewrites `settings.json` at runtime (`lastChangelogVersion` bumps) and a symlink would dirty the repo. |
| AWS env probe | If `settings.json` selects `amazon-bedrock`, warn if `AWS_PROFILE` / `AWS_REGION` not set. Silent otherwise. |
Everything is non-destructive: existing real files get backed up with a timestamp before symlinking; shell loader copy refuses to clobber local edits (prints `diff` hint and moves on). Re-runs are idempotent.
## Uninstall
```bash
./install.sh --uninstall
```
Removes the keybindings symlink and the shell-loader copy (only if content still matches the repo). Your `settings.json` is never touched.
---
## Deploying pi on a new machine
Full recipe from a clean macOS or Linux box to a working pi install. Follow in order.
### 0. Prerequisites
- Shell: zsh + oh-my-zsh recommended (the `pi-env.zsh` loader installs into `~/.oh-my-zsh/custom/`). Bash or plain zsh works too — installer prints a manual source snippet.
- `git`, pi (installed upstream), optional: `tmux` ≥ 3.2 for CSI-u extended keys on non-mosh paths.
- AWS credentials reachable via `AWS_PROFILE` (either `aws configure sso` cache or static keys in `~/.aws/credentials`) — only if using `amazon-bedrock` as pi's provider.
### 1. Dotfiles (if you keep one)
Your dotfiles repo should ship `~/.config/pi/.env` (git-crypt encrypted, containing `AWS_PROFILE` and `AWS_REGION`). Provision it first so the loader has something to source:
```bash
git clone <your-dotfiles> ~/src/dotfiles
cd ~/src/dotfiles
git-crypt unlock <key>
# Run your dotfiles provisioner (example: myconfigs)
./provision.sh --profile <profile>
```
If you don't use a dotfiles repo, create the file manually after step 3 (installer will point you at the right path).
### 2. Install pi
```bash
brew install pi-coding-agent # macOS
# or see https://github.com/mariozechner/pi-coding-agent for Linux
pi --help # creates ~/.pi/agent/
```
### 3. Install this toolkit
```bash
git clone ssh://git@gitea.jordbo.se:2222/joakimp/pi-toolkit.git ~/pi-toolkit
cd ~/pi-toolkit && ./install.sh
```
This symlinks `keybindings.json`, copies `pi-env.zsh`, and prints the `settings.json` bootstrap command.
### 4. Bootstrap pi settings
```bash
cp ~/pi-toolkit/settings.example.json ~/.pi/agent/settings.json
$EDITOR ~/.pi/agent/settings.json
```
Adjust the inference-profile prefix to match your AWS region:
| Region | Prefix | Example model ID |
|---|---|---|
| eu-west-1 | `eu.` | `eu.anthropic.claude-sonnet-4-6` |
| us-east-1 | `us.` | `us.anthropic.claude-sonnet-4-6` |
| non-Bedrock | (none) | `anthropic:claude-sonnet-4-6` |
Run `pi --list-models` to confirm what your credentials can actually invoke.
### 5. Verify AWS env vars in your shell
If step 1 provisioned `~/.config/pi/.env` and step 3 installed `pi-env.zsh`:
```bash
exec zsh
echo "$AWS_PROFILE $AWS_REGION" # should print your values
```
If empty, check that `~/.config/pi/.env` decrypted (plain text, not binary) — `git-crypt unlock` in step 1 is the usual culprit.
### 6. First run
```bash
pi # should start with the default model, no --model needed
```
### 7. (Optional) Add MemPalace memory
If you want pi to have persistent memory across sessions, install [`mempalace-toolkit`](https://gitea.jordbo.se/joakimp/mempalace-toolkit):
```bash
uv tool install mempalace
git clone ssh://git@gitea.jordbo.se:2222/joakimp/mempalace-toolkit.git ~/mempalace-toolkit
cd ~/mempalace-toolkit && ./install.sh
```
It detects pi and symlinks a `mempalace.ts` extension into `~/.pi/agent/extensions/` that wires pi's MCP client to the palace.
### Verification checklist
```bash
# keybindings symlinked into this repo
ls -la ~/.pi/agent/keybindings.json
# shell loader installed
ls -la ~/.oh-my-zsh/custom/pi-env.zsh
# env vars loaded in a fresh shell
zsh -ic 'echo $AWS_PROFILE $AWS_REGION'
# pi starts with its defaults
pi --version
# Re-run is idempotent
./install.sh --yes # all rows should say "already linked/installed"
```
---
## Settings template reference
`settings.example.json`:
```json
{
"defaultProvider": "amazon-bedrock",
"defaultModel": "eu.anthropic.claude-sonnet-4-6",
"enabledModels": [
"eu.anthropic.claude-sonnet-4-6",
"eu.anthropic.claude-opus-4-7",
"eu.anthropic.claude-haiku-4-5-20251001-v1:0"
]
}
```
- `defaultProvider` — most common values: `amazon-bedrock`, `anthropic`, `openai`.
- `defaultModel` — Bedrock IDs have region-specific prefixes (`eu.`, `us.`). Bare Anthropic uses `anthropic:claude-...`. Run `pi --list-models` to see what you can actually call.
- `enabledModels` — optional; restricts the model picker inside pi to this subset.
pi rewrites `settings.json` at runtime (`lastChangelogVersion` bumps on upgrade), so don't symlink this file.
## Keybindings reference
`keybindings.json`:
```json
{
"tui.input.newLine": ["shift+enter", "ctrl+j", "alt+j"]
}
```
Over direct `kitty` / `iTerm2` / `WezTerm` with tmux configured for CSI-u extended keys, `Shift+Enter` works natively. The `ctrl+j` / `alt+j` fallbacks kick in when modifier forwarding is stripped (most commonly: mosh). Pi reads this file once at startup — restart pi after editing.
## Environment file reference
`~/.config/pi/.env` format (plaintext on disk, chmod 600, encrypt in your dotfiles repo):
```bash
AWS_PROFILE=YourBedrockProfile
AWS_REGION=eu-west-1
```
Loaded by `pi-env.zsh` via `set -a; source; set +a` — plain `KEY=VALUE`, no `export` needed. Add any other pi-scoped env vars here as the surface grows.
---
## Related repos
- [`mempalace-toolkit`](https://gitea.jordbo.se/joakimp/mempalace-toolkit) — MemPalace memory layer. Installs a pi↔mempalace MCP bridge on top of this toolkit. Optional.
- [`opencode-toolkit`](https://gitea.jordbo.se/joakimp/opencode-toolkit) — sibling repo for the opencode coding-agent. Same shape (shell loader + install.sh). Independent of this repo.
- [`opencode-devbox`](https://gitea.jordbo.se/joakimp/opencode-devbox) — Docker containers with coding agents preinstalled. Can compose pi-toolkit and mempalace-toolkit as independent layers.
- [`myconfigs`](https://gitea.jordbo.se/joakimp/myconfigs) — dotfiles repo where `~/.config/pi/.env` is tracked (git-crypt encrypted).
## License
MIT — see [`LICENSE`](LICENSE).
Executable
+276
View File
@@ -0,0 +1,276 @@
#!/usr/bin/env bash
# install.sh — install pi-toolkit
#
# Harness-side bring-up for the pi coding-agent (https://github.com/mariozechner/pi-coding-agent):
# - pi-env.zsh : shell loader sourcing ~/.config/pi/.env so AWS_PROFILE
# and AWS_REGION are in every shell that launches pi.
# - keybindings.json : mosh/tmux-friendly newline bindings
# (shift+enter, ctrl+j, alt+j).
# - settings.example.json : template for ~/.pi/agent/settings.json so pi
# starts without --provider/--model. Copy + edit.
#
# No dependency on MemPalace. For the palace bridge see
# https://gitea.jordbo.se/joakimp/mempalace-toolkit (optional).
#
# Idempotent. Safe to re-run. Non-destructive on drift: if installed content
# differs from repo, leaves user edits alone and points at diff.
set -euo pipefail
# ── locate self ──────────────────────────────────────
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# ── targets ──────────────────────────────────────────
PI_EXT_DEST_DIR="${HOME}/.pi/agent/extensions" # existence = pi is installed
PI_AGENT_DIR="${HOME}/.pi/agent"
# keybindings — symlinked (pi doesn't rewrite it at runtime)
PI_KEYS_SRC="${SCRIPT_DIR}/keybindings.json"
PI_KEYS_DEST="${HOME}/.pi/agent/keybindings.json"
# settings template — NOT installed, only referenced (pi rewrites settings.json)
PI_SETTINGS_EXAMPLE="${SCRIPT_DIR}/settings.example.json"
PI_SETTINGS_DEST="${HOME}/.pi/agent/settings.json"
# shell env loader — cp'd into oh-my-zsh custom dir (portability over symlink)
PI_ENV_SRC="${SCRIPT_DIR}/pi-env.zsh"
PI_ENV_OMZ_DEST="${HOME}/.oh-my-zsh/custom/pi-env.zsh"
# ── args ─────────────────────────────────────────────
ACTION="install"
ASSUME_YES="no"
while [[ $# -gt 0 ]]; do
case "$1" in
--uninstall) ACTION="uninstall"; shift ;;
-y|--yes) ASSUME_YES="yes"; shift ;;
-h|--help)
cat <<EOF
install.sh — install pi-toolkit
Usage:
./install.sh # install (interactive confirm)
./install.sh --yes # install without prompt
./install.sh --uninstall # remove symlinks and copied loaders
What install does:
- Requires pi installed (~/.pi/agent/ must exist). Aborts cleanly otherwise.
- Symlinks keybindings.json into ~/.pi/agent/keybindings.json.
- If oh-my-zsh is present (~/.oh-my-zsh/custom/), copies pi-env.zsh there
so every new zsh shell sources ~/.config/pi/.env. Uses cp (not symlink)
for dotfile-backup portability. Prints source snippet otherwise.
- Probes (non-halting warnings): settings.json present, and AWS_PROFILE /
AWS_REGION set if settings.json selects amazon-bedrock.
What uninstall does:
- Removes keybindings.json symlink if it points into this repo.
- Removes pi-env.zsh copy ONLY if its content still matches the repo.
- Never touches settings.json (it's your file, not managed here).
No dependency on MemPalace. For memory integration see:
https://gitea.jordbo.se/joakimp/mempalace-toolkit
EOF
exit 0 ;;
*) echo "Unknown flag: $1" >&2; exit 2 ;;
esac
done
# ── helpers ──────────────────────────────────────────
ok() { printf ' \e[32m✓\e[0m %s\n' "$*"; }
note() { printf '==> %s\n' "$*"; }
warn() { printf ' \e[33m!\e[0m %s\n' "$*" >&2; }
err() { printf ' \e[31m✗\e[0m %s\n' "$*" >&2; }
confirm() {
[[ "$ASSUME_YES" == "yes" ]] && return 0
read -r -p "Proceed? [y/N] " ans
[[ "$ans" =~ ^[Yy]$ ]]
}
link_if_into_repo() {
# Return 0 if $1 is a symlink pointing into $SCRIPT_DIR
local target
[[ -L "$1" ]] || return 1
target=$(readlink -f "$1")
[[ "$target" == "$SCRIPT_DIR"/* ]]
}
require_pi_installed() {
if [[ ! -d "$PI_AGENT_DIR" ]]; then
err "pi not detected at $PI_AGENT_DIR"
printf ' Install pi first: https://github.com/mariozechner/pi-coding-agent\n'
printf ' Re-run this installer after `pi` has been started at least once\n'
printf ' (first run creates ~/.pi/agent/).\n'
exit 4
fi
# Ensure the extensions dir exists so pi loads any extensions we may add
# later (e.g. mempalace-toolkit's mempalace.ts). pi creates this on first
# extension install but we may race ahead of that.
mkdir -p "$PI_EXT_DEST_DIR"
ok "pi detected at $PI_AGENT_DIR"
}
# ── install ──────────────────────────────────────────
install_keybindings() {
# Generic mosh/tmux newline fix. Symlinked so edits flow through git.
note "Linking keybindings.json → $PI_KEYS_DEST"
if [[ -e "$PI_KEYS_DEST" || -L "$PI_KEYS_DEST" ]]; then
if link_if_into_repo "$PI_KEYS_DEST"; then
ok "pi keybindings already linked"
return 0
fi
# Back up any existing real file / foreign symlink.
local backup="${PI_KEYS_DEST}.bak.$(date +%Y%m%d-%H%M%S)"
mv "$PI_KEYS_DEST" "$backup"
warn "Existing $PI_KEYS_DEST backed up to $backup"
fi
ln -s "$PI_KEYS_SRC" "$PI_KEYS_DEST"
ok "Linked keybindings.json → $PI_KEYS_SRC"
}
install_env_loader() {
# Copy pi-env.zsh into ~/.oh-my-zsh/custom/ (auto-loaded by omz).
# cp not symlink because that dir is typically part of a dotfiles backup
# and a symlink into this repo breaks on restore to another host.
# No oh-my-zsh → print a source snippet for manual rc-file addition.
if [[ -d "$HOME/.oh-my-zsh/custom" ]]; then
note "Installing pi-env.zsh into ~/.oh-my-zsh/custom/"
if [[ -f "$PI_ENV_OMZ_DEST" ]]; then
if cmp -s "$PI_ENV_SRC" "$PI_ENV_OMZ_DEST"; then
ok "pi-env.zsh already installed (content matches repo)"
return 0
fi
warn "$PI_ENV_OMZ_DEST exists and differs from repo copy"
printf ' Leaving your edits alone. Compare with:\n'
printf ' diff %q %q\n' "$PI_ENV_OMZ_DEST" "$PI_ENV_SRC"
printf ' To adopt the repo version: rm that file and re-run install.sh\n'
return 0
fi
cp "$PI_ENV_SRC" "$PI_ENV_OMZ_DEST"
ok "Copied pi-env.zsh → $PI_ENV_OMZ_DEST"
printf ' Open a new shell (or `exec zsh`) to load AWS_PROFILE / AWS_REGION.\n'
return 0
fi
# No oh-my-zsh — print shell-specific snippet.
note "oh-my-zsh not detected — manual shell setup needed"
local shell_name
shell_name="$(basename "${SHELL:-bash}")"
local rc_file
case "$shell_name" in
zsh) rc_file="~/.zshrc" ;;
bash) rc_file="~/.bashrc" ;;
*) rc_file="~/.${shell_name}rc # adjust for your shell" ;;
esac
printf ' Add this line to %s so every shell sources ~/.config/pi/.env:\n' "$rc_file"
printf ' source %q\n' "$PI_ENV_SRC"
printf ' (the loader itself is POSIX-compatible — works in bash and zsh.)\n'
}
# ── Probes ───────────────────────────────────────────
# Never halt. warn + return 0 — mirrors opencode-toolkit and mempalace-toolkit.
check_pi_settings() {
# If settings.json missing, pi refuses to start without --provider/--model
# on every run. Template exists in this repo; point at the cp command.
if [[ -f "$PI_SETTINGS_DEST" ]]; then
ok "pi settings.json present at $PI_SETTINGS_DEST"
return 0
fi
warn "pi settings.json NOT found at $PI_SETTINGS_DEST"
printf ' Without it, pi must be invoked with --provider/--model every run.\n'
printf ' Bootstrap from the shipped template:\n'
printf ' cp %q %q\n' "$PI_SETTINGS_EXAMPLE" "$PI_SETTINGS_DEST"
printf ' $EDITOR %q # adjust region prefix + model IDs\n' "$PI_SETTINGS_DEST"
printf ' See README.md for the eu./us./anthropic: prefix rules.\n'
}
check_aws_env() {
# Only warn if settings.json selects amazon-bedrock. If pi uses a
# non-Bedrock provider (bare anthropic, openai, ...) AWS creds are
# irrelevant and this probe would be noise. If settings.json doesn't
# exist yet, check_pi_settings already told the user to bootstrap it
# — we can't know which provider they'll pick, so stay quiet here.
[[ -f "$PI_SETTINGS_DEST" ]] || return 0
grep -q '"amazon-bedrock"' "$PI_SETTINGS_DEST" 2>/dev/null || return 0
if [[ -n "${AWS_PROFILE:-}" && -n "${AWS_REGION:-}" ]]; then
ok "AWS env present (AWS_PROFILE=$AWS_PROFILE, AWS_REGION=$AWS_REGION)"
return 0
fi
warn "AWS_PROFILE and/or AWS_REGION not set in this shell"
printf ' pi with defaultProvider=amazon-bedrock needs both to invoke Bedrock.\n'
printf ' Recommended layout (matches tor-ms22 dotfiles pattern):\n'
printf ' ~/.config/pi/.env # AWS_PROFILE=..., AWS_REGION=...\n'
printf ' The pi-env.zsh loader (installed above) sources it automatically.\n'
printf ' Open a fresh shell to pick up the vars after creating the file.\n'
}
do_install() {
echo
echo "pi-toolkit installer"
echo "Repository: $SCRIPT_DIR"
echo
require_pi_installed
echo
echo "==> Installation plan:"
echo " Symlink keybindings.json → $PI_KEYS_DEST"
if [[ -d "$HOME/.oh-my-zsh/custom" ]]; then
echo " Copy pi-env.zsh → $PI_ENV_OMZ_DEST"
else
echo " Print manual source-snippet instructions for pi-env.zsh"
fi
echo
confirm || { echo "Aborted."; exit 0; }
echo
install_keybindings
echo
install_env_loader
echo
check_pi_settings
echo
check_aws_env
echo
ok "Done."
}
# ── uninstall ────────────────────────────────────────
do_uninstall() {
echo
echo "pi-toolkit uninstaller"
echo "Repository: $SCRIPT_DIR"
echo
confirm || { echo "Aborted."; exit 0; }
echo
note "Removing pi keybindings symlink"
if link_if_into_repo "$PI_KEYS_DEST"; then
rm "$PI_KEYS_DEST"
ok "Removed pi keybindings symlink"
else
ok "No pi keybindings symlink to remove"
fi
echo
note "Removing pi-env.zsh loader (oh-my-zsh path)"
# Only remove if content still matches the repo copy — user may have
# local edits we shouldn't silently discard.
if [[ -f "$PI_ENV_OMZ_DEST" ]] && cmp -s "$PI_ENV_SRC" "$PI_ENV_OMZ_DEST"; then
rm "$PI_ENV_OMZ_DEST"
ok "Removed $PI_ENV_OMZ_DEST"
elif [[ -f "$PI_ENV_OMZ_DEST" ]]; then
warn "$PI_ENV_OMZ_DEST differs from repo copy — left alone"
else
ok "No pi-env.zsh loader to remove"
fi
echo
ok "Done."
}
case "$ACTION" in
install) do_install ;;
uninstall) do_uninstall ;;
esac
+3
View File
@@ -0,0 +1,3 @@
{
"tui.input.newLine": ["shift+enter", "ctrl+j", "alt+j"]
}
+28
View File
@@ -0,0 +1,28 @@
# Load pi coding-agent environment variables from ~/.config/pi/.env
#
# Canonical source: pi-toolkit/pi-env.zsh
# Installed by pi-toolkit/install.sh via `cp` (not symlink) to keep
# ~/.oh-my-zsh/custom/ portable across machines with different $HOME paths.
# See pi-toolkit/README.md for the full story.
#
# Sources ~/.config/pi/.env (AWS_PROFILE, AWS_REGION, and any future
# pi-scoped secrets) so pi's Bedrock provider works when spawned from any
# shell. The .env file itself is shipped (git-crypt encrypted) from the
# myconfigs dotfiles repo.
#
# `set -a` auto-exports every assignment in the sourced file, so plain
# KEY=VALUE lines become exported env vars without needing `export` in .env.
# Also works in bash (set -a and source are POSIX) — non-oh-my-zsh users
# can source this file directly from ~/.bashrc or ~/.zshrc instead.
#
# Historical note: these vars used to live in ~/.config/opencode/.env
# under a "# Environment variables for pi" block. Split out 2026-05-05
# so each tool owns its own env file.
_pi_env="${HOME}/.config/pi/.env"
if [[ -r "${_pi_env}" ]]; then
set -a
source "${_pi_env}"
set +a
fi
unset _pi_env
+12
View File
@@ -0,0 +1,12 @@
{
"_comment": "Template for ~/.pi/agent/settings.json. Copy to that path and adjust for your region/account — this file is NOT symlinked by install.sh because pi rewrites settings.json at runtime (lastChangelogVersion bumps), which would dirty the repo. This template exists so a fresh machine can start pi without --model by copying + editing.",
"_comment_models": "The 'eu.' prefix on Bedrock model IDs is an inference-profile prefix tied to the AWS region. Must match AWS_REGION in ~/.config/pi/.env. For us-east use 'us.anthropic.*'; for bare Anthropic provider (non-Bedrock) use the raw 'anthropic:claude-*' IDs. Run `pi --list-models` to see what your credentials can actually invoke.",
"defaultProvider": "amazon-bedrock",
"defaultModel": "eu.anthropic.claude-sonnet-4-6",
"enabledModels": [
"eu.anthropic.claude-sonnet-4-6",
"eu.anthropic.claude-opus-4-7",
"eu.anthropic.claude-haiku-4-5-20251001-v1:0"
]
}