#!/bin/sh # Pi adapter: implements the Mosaic adapter contract for the pinned # @earendil-works/pi-coding-agent CLI. # # Contract: see /opt/mosaic/adapters/README.md. # Headless (default): stdout = response only; stderr = diagnostics; exit 0. # Interactive (MOSAIC_INTERACTIVE=1): full pi TUI on the attached terminal. set -eu [ -n "${MOSAIC_SYSTEM_PROMPT_FILE:-}" ] || { echo "pi adapter: MOSAIC_SYSTEM_PROMPT_FILE is required" >&2; exit 2; } [ -r "$MOSAIC_SYSTEM_PROMPT_FILE" ] || { echo "pi adapter: system prompt not readable: $MOSAIC_SYSTEM_PROMPT_FILE" >&2; exit 2; } # MOSAIC_AGENT_NAME is optional in headless mode (identity section is then # omitted); interactive launches always set it via scripts/agent.sh. : "${PI_PROVIDER:?pi adapter: PI_PROVIDER is required}" : "${PI_MODEL:?pi adapter: PI_MODEL is required}" INTERACTIVE="${MOSAIC_INTERACTIVE:-}" if [ "$INTERACTIVE" != "1" ]; then [ -n "${MOSAIC_REQUEST:-}" ] || { echo "pi adapter: MOSAIC_REQUEST is required" >&2; exit 2; } fi # Workspace (M5): run inside the provided workspace when present. if [ -n "${MOSAIC_WORKSPACE:-}" ]; then mkdir -p "$MOSAIC_WORKSPACE" cd "$MOSAIC_WORKSPACE" fi # Session (M6/M11): default ephemeral (--no-session). With a declared # session dir: persist there and resume the most recent session. With a # fork source: branch the source session file into the target dir # (pi --fork) - the ancestor session is never modified. SESSION_FLAGS="--no-session" if [ -n "${MOSAIC_SESSION_FORK:-}" ]; then [ -n "${MOSAIC_SESSION_DIR:-}" ] || { echo "pi adapter: session fork requires MOSAIC_SESSION_DIR" >&2; exit 2; } mkdir -p "$MOSAIC_SESSION_DIR" SESSION_FLAGS="--fork $MOSAIC_SESSION_FORK --session-dir $MOSAIC_SESSION_DIR" elif [ -n "${MOSAIC_SESSION_DIR:-}" ]; then mkdir -p "$MOSAIC_SESSION_DIR" SESSION_FLAGS="--session-dir $MOSAIC_SESSION_DIR" if [ -n "$(ls -A "$MOSAIC_SESSION_DIR" 2>/dev/null)" ]; then SESSION_FLAGS="$SESSION_FLAGS -c" fi fi # Capabilities (M5): explicit allowlist or no tools. TOOLS_FLAG="--no-tools" [ -n "${MOSAIC_TOOLS:-}" ] && TOOLS_FLAG="--tools $MOSAIC_TOOLS" # Mode (M13): interactive TUI or one-shot print. PRINT_MODE="-p" REQUEST_ARG="" if [ "$INTERACTIVE" = "1" ]; then PRINT_MODE="" else REQUEST_ARG="$MOSAIC_REQUEST" fi # All flags documented in the pi package README (CLI Reference): # -p/--print one-shot mode: print the response and exit (omitted in # interactive TUI mode) # --system-prompt replace the default prompt with the generated one # --no-* no ambient context/skills/extensions/templates/themes # SESSION_FLAGS ephemeral | persistent | forked (per env) # TOOLS_FLAG per capabilities # --offline no startup network operations (update checks/telemetry) PROMPT_CONTENT="$(cat "$MOSAIC_SYSTEM_PROMPT_FILE")" set -- \ --offline \ --no-extensions \ --no-skills \ --no-prompt-templates \ --no-themes \ --no-context-files \ $TOOLS_FLAG \ $SESSION_FLAGS \ --provider "$PI_PROVIDER" \ --model "$PI_MODEL" \ --system-prompt "$PROMPT_CONTENT" # One-shot mode appends -p and the request (both safely quoted); # interactive mode appends nothing - clean TUI. [ "$INTERACTIVE" = "1" ] || set -- "$@" -p "$MOSAIC_REQUEST" exec pi "$@"