#!/usr/bin/env bash # setup-pi.sh — Install pi and configure models/settings like the reference machine. # # Usage: # curl -fsSL | bash # or # bash setup-pi.sh # bash setup-pi.sh --force # overwrite existing config files # PI_INSTALL_METHOD=npm bash setup-pi.sh # # After install, edit API keys in: # ~/.pi/agent/models.json set -euo pipefail PI_HOME="${PI_HOME:-$HOME/.pi}" AGENT_DIR="$PI_HOME/agent" FORCE=0 INSTALL_METHOD="${PI_INSTALL_METHOD:-auto}" # auto | bun | npm PI_PACKAGE="@earendil-works/pi-coding-agent" # ── args ────────────────────────────────────────────────────────────────────── for arg in "$@"; do case "$arg" in --force|-f) FORCE=1 ;; --bun) INSTALL_METHOD=bun ;; --npm) INSTALL_METHOD=npm ;; --help|-h) sed -n '2,14p' "$0" exit 0 ;; *) echo "Unknown option: $arg" >&2 exit 1 ;; esac done # ── helpers ──────────────────────────────────────────────────────────────────── info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } ok() { printf '\033[1;32m✓\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m!\033[0m %s\n' "$*"; } die() { printf '\033[1;31m✗\033[0m %s\n' "$*" >&2; exit 1; } write_file() { # write_file local path="$1" if [[ -f "$path" && $FORCE -eq 0 ]]; then warn "skip existing: $path (use --force to overwrite)" return 0 fi mkdir -p "$(dirname "$path")" cat > "$path" ok "wrote $path" } have() { command -v "$1" >/dev/null 2>&1; } # ── 1. prerequisites ────────────────────────────────────────────────────────── info "Checking prerequisites" if ! have curl && ! have wget; then die "Need curl or wget" fi # Node is required for pi runtime even when installed via bun if ! have node; then die "Node.js is required. Install Node 20+ then re-run." fi NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]')" if (( NODE_MAJOR < 20 )); then warn "Node $NODE_MAJOR detected; pi recommends Node 20+" fi ok "node $(node -v)" # ── 2. install pi ───────────────────────────────────────────────────────────── info "Installing $PI_PACKAGE" resolve_method() { case "$INSTALL_METHOD" in bun|npm) echo "$INSTALL_METHOD" ;; auto) if have bun; then echo bun elif have npm; then echo npm else die "Need bun or npm to install pi" fi ;; *) die "Invalid PI_INSTALL_METHOD=$INSTALL_METHOD (use auto|bun|npm)" ;; esac } METHOD="$(resolve_method)" case "$METHOD" in bun) ok "using bun $(bun -v 2>/dev/null || true)" bun install -g "$PI_PACKAGE" # Ensure bun bin is on PATH for this session export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}" export PATH="$BUN_INSTALL/bin:$PATH" ;; npm) ok "using npm $(npm -v 2>/dev/null || true)" npm install -g --ignore-scripts "$PI_PACKAGE" ;; esac if ! have pi; then die "pi binary not found on PATH after install. Add bun/npm global bin to PATH and re-run." fi ok "pi $(pi --version 2>/dev/null || echo installed) via $METHOD" # ── 3. directory layout ─────────────────────────────────────────────────────── info "Creating $AGENT_DIR" mkdir -p "$AGENT_DIR"/{sessions,extensions,skills,bin,npm,ayu/checkpoints} ok "dirs ready" # ── 4. settings.json ────────────────────────────────────────────────────────── info "Writing settings.json" write_file "$AGENT_DIR/settings.json" <<'EOF' { "defaultProvider": "llm-gw", "defaultModel": "code", "packages": [], "images": { "blockImages": true }, "terminal": { "showTerminalProgress": true }, "steeringMode": "one-at-a-time", "theme": "dark", "hideThinkingBlock": true, "collapseChangelog": true, "defaultProjectTrust": "always", "warnings": { "anthropicExtraUsage": true }, "defaultThinkingLevel": "high", "enableInstallTelemetry": false, "compaction": { "enabled": true, "reserveTokens": 25600, "keepRecentTokens": 20000 }, "retry": { "enabled": true, "maxRetries": 3, "baseDelayMs": 2000, "provider": { "timeoutMs": 300000, "maxRetries": 2, "maxRetryDelayMs": 60000 } }, "lsp": { "hookMode": "disabled" }, "httpIdleTimeoutMs": 120000, "treeFilterMode": "default" } EOF # ── 5. models.json (template keys) ──────────────────────────────────────────── info "Writing models.json (API key placeholders)" write_file "$AGENT_DIR/models.json" <<'EOF' { "providers": { "llm-gw": { "baseUrl": "https://llm-gw.luulam.dev/v1", "apiKey": "YOUR_LLM_GW_API_KEY", "api": "openai-completions", "models": [ { "id": "code", "name": "code", "reasoning": false, "input": ["text"], "contextWindow": 256000, "maxTokens": 128000, "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 } } ] }, "mbbank": { "baseUrl": "https://api-sandbox.mbbank.com.vn/llm-gateway-dev/v1", "apiKey": "YOUR_MBBANK_API_KEY", "api": "openai-completions", "models": [ { "id": "glm-text", "name": "glm-text", "reasoning": false, "input": ["text"], "contextWindow": 256000, "maxTokens": 128000, "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 } } ] } } } EOF # ── 6. APPEND_SYSTEM.md ─────────────────────────────────────────────────────── info "Writing APPEND_SYSTEM.md" write_file "$AGENT_DIR/APPEND_SYSTEM.md" <<'EOF' # Default Coding Guidelines Apply these guidelines by default for all coding, reviewing, debugging, and refactoring tasks. ## Karpathy Guidelines Behavioral guidelines to reduce common LLM coding mistakes. These guidelines bias toward caution over speed. For trivial tasks, use judgment. ### 1. Think Before Coding Don't assume. Don't hide confusion. Surface tradeoffs. Before implementing: - State your assumptions explicitly. If uncertain, ask. - If multiple interpretations exist, present them; don't pick silently. - If a simpler approach exists, say so. Push back when warranted. - If something is unclear, stop. Name what's confusing. Ask. ### 2. Simplicity First Minimum code that solves the problem. Nothing speculative. - No features beyond what was asked. - No abstractions for single-use code. - No "flexibility" or "configurability" that wasn't requested. - No error handling for impossible scenarios. - If you write 200 lines and it could be 50, rewrite it. Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. ### 3. Surgical Changes Touch only what you must. Clean up only your own mess. When editing existing code: - Don't "improve" adjacent code, comments, or formatting. - Don't refactor things that aren't broken. - Match existing style, even if you'd do it differently. - If you notice unrelated dead code, mention it; don't delete it. When your changes create orphans: - Remove imports, variables, or functions that your changes made unused. - Don't remove pre-existing dead code unless asked. The test: every changed line should trace directly to the user's request. ### 4. Goal-Driven Execution Define success criteria. Loop until verified. Transform tasks into verifiable goals: - "Add validation" → "Write tests for invalid inputs, then make them pass." - "Fix the bug" → "Write a test that reproduces it, then make it pass." - "Refactor X" → "Ensure tests pass before and after." For multi-step tasks, state a brief plan: ```text 1. [Step] → verify: [check] 2. [Step] → verify: [check] 3. [Step] → verify: [check] ``` Strong success criteria let you loop independently. Weak criteria like "make it work" require clarification. EOF # ── 7. minimal auth + trust stubs ───────────────────────────────────────────── # auth.json empty object is fine; keys live in models.json for custom providers if [[ ! -f "$AGENT_DIR/auth.json" || $FORCE -eq 1 ]]; then echo '{}' > "$AGENT_DIR/auth.json" ok "wrote $AGENT_DIR/auth.json" else warn "skip existing: $AGENT_DIR/auth.json" fi if [[ ! -f "$AGENT_DIR/trust.json" || $FORCE -eq 1 ]]; then # Trust the pi home dir by default; add project paths later via pi UI cat > "$AGENT_DIR/trust.json" </dev/null; then ok "PATH already configured in $rc" return 0 fi # Append without command-substitution (avoids ')' inside case breaking $()) { echo "" echo "# >>> pi / bun >>>" echo 'export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}"' echo 'if [[ ":$PATH:" != *":$BUN_INSTALL/bin:"* ]]; then' echo ' export PATH="$BUN_INSTALL/bin:$PATH"' echo 'fi' echo "# <<< pi / bun <<<" } >> "$rc" ok "appended bun PATH to $rc" } ensure_path_hint # ── done ────────────────────────────────────────────────────────────────────── cat </dev/null || echo unknown) Config : $AGENT_DIR Next steps: 1. Edit API keys: $EDITOR "$AGENT_DIR/models.json" Replace: YOUR_LLM_GW_API_KEY YOUR_MBBANK_API_KEY 2. Verify models: pi --list-models 3. Start: pi # or pin model: pi --provider llm-gw --model code Re-run with --force to overwrite settings/models/APPEND_SYSTEM. Optional later: pi install npm:context-mode pi install npm:pi-mcp-adapter # ...other packages from the full machine profile ──────────────────────────────────────────────────────── EOF