openpiper
v0.9.5
Published
Runner-grade AI CLI and interactive terminal UI for reproducible LLM workflows.
Downloads
358
Maintainers
Readme
OpenPiper
A merged runner-grade CLI (piper) and interactive TUI (openpiper) for working with LLMs from the terminal. Runner-first, TUI second - both ship from the same npm package and share a common provider adapter layer.
v0.2.x - TUI working with Anthropic, OpenAI, Gemini, Ollama Local, and Ollama Cloud. Runner (piper run) supports strict JSON execution, replay inputs, auditable artifacts, workspace-root controls, built-in file tools, and provider selection for Ollama, Anthropic, OpenAI, and Gemini.
What This Is
Release notes are tracked in docs/release-notes.md.
Two binaries, one package, one core:
piper- non-interactive runner with a strict JSON stdout contract, stable exit codes, deterministic request fingerprinting, auditable workdir artifacts, replayable message files, provider selection, and workspace-root controls. Built for scripts, CI, and orchestration.openpiper- interactive Ink-based TUI with streaming responses, multi-provider support, session persistence, drag-drop file attach, mouse wheel scroll, clickable markdown links, and view focus toggles for clean copy/paste.
See docs/piper-runner-plan.md for the canonical plan, contract, architecture, and migration phases. That document is the single source of truth for both binaries.
Current State
- TUI (
openpiper): working with Anthropic, OpenAI, Gemini, Ollama Local, and Ollama Cloud. Interactive chat, streaming, session resume, drag-drop attach, mouse wheel scroll, OSC 8 hyperlinks, view focus toggles. - Runner (
piper): active runner path for non-interactive execution with strict JSON stdout, provider selection, message-file replay, deterministic request fingerprints, artifacts, dry runs, streaming event output, workspace roots, and built-in file tools.
TUI Feature Scope
The interactive openpiper TUI is the primary daily-use experience. It supports:
- Multi-provider chat: Anthropic, OpenAI, Gemini, Ollama Local, and Ollama Cloud through one shared TUI flow.
- Model and provider switching:
/modelopens a picker or switches directly withprovider/model; selections are persisted back to config. - Provider setup in the terminal:
/connectconfigures provider credentials or Ollama endpoints;/disconnectremoves saved provider credentials. - Streaming conversations: assistant output streams into a scrollable conversation pane with multi-turn history.
- Session persistence: sessions are saved locally, resumable with
openpiper --resume <sessionId>, and summarized on exit. - Session-to-runner export:
/export [dir]writes a runner-ready package with messages, generation config, tool config, transcript, manifest, andrun.sh. - Prompt recipes:
/recipelists reusable JSON recipes from~/.openpiper/recipes;/recipe <name> key=valuerenders and runs one in the TUI. - File context loading:
/file <path>injects a file into the conversation, and pasted or drag-dropped file paths are detected. - Built-in file tools: model-callable file read, file search, and directory listing tools for inspecting the workspace.
- Tool approval gate: tool calls show a modal with arguments, access scope, and decisions for allow once, allow for session, always allow, deny, or abort turn.
- Path-scoped permissions: approvals are scoped by read/write access and path, with persisted always-allow entries stored in
~/.openpiper/config.json. - Workspace roots:
--add-dir,--include-dir, and config roots allow explicit read/write or read-only access outside the current directory. - Workspace sidepanel: current folder, added workspace roots, status, command/message counts, context window, token usage, estimated cost, tool permissions, tool activity, and recent activity.
- Memory model foundation: committed conversation history is durable; user/assistant drafts are streamed separately and only committed on successful completion.
- Usage accounting: per-turn and session token counts, cache reads, model rollups, and cost display where pricing is available.
- Responsive terminal layout: conversation plus workspace sidebar on wide terminals, compact sidepanel on narrower terminals, and focused views for chat or workspace.
- Reader mode: Ctrl+R hides nonessential chrome for cleaner reading and copying.
- Scroll controls: arrow keys, PageUp/PageDown, Ctrl+U/Ctrl+D half-page scrolling, and mouse wheel support.
- Command completion: slash commands autocomplete with Tab.
- Themes:
/themeswitches betweenopenpiper,forest, andamber. - Clickable output: rendered markdown includes clickable OSC 8 hyperlinks where the terminal supports them.
- Debug visibility:
--debugshows provider events and writes structured logs to~/.openpiper/logs/. - Durable memory extraction:
node scripts/extract-session-messages.js <session-id>writes a versioned durable message artifact (schema-aware role/body stream) in~/.openpiper/memory/<session-id>.durable-messages-v1.json. - Terminal cleanup and cancellation: Ctrl+C aborts active work and restores terminal mouse/paste modes on exit.
Workflow Direction
OpenPiper is being shaped around a specific loop:
explore interactively -> lock the winning prompt/config/context -> export a deterministic runner invocation -> reuse in automationThe product direction is to make messy LLM exploration reproducible, comparable, validatable, exportable, and auditable. The TUI is the exploration surface; piper run is the automation surface. The shared core is intended to let successful interactive work become a repeatable runner workflow instead of staying trapped in chat history.
The first foundational workflow primitives are session-to-runner export and prompt recipes.
Session export writes:
messages.jsonfor runner replaygeneration-config.jsonas the replay config surfacetool-config.jsonwith workspace roots and built-in tool allowlisttranscript.mdfor human reviewmanifest.jsonfor audit metadatarun.shwith the equivalentpiper run ...command
Prompt recipes live in ~/.openpiper/recipes/*.json and define reusable prompts with optional variables, provider/model preference, workspace root requirements, and output intent.
Next workflow primitives under consideration:
- Model A/B replay and compare: run the same prompt/context against multiple providers, models, or generation settings, then compare output, timing, token use, cost, and validation results.
- Conversation branching: fork from a prior turn, label branches, compare alternatives, and mark one branch as canonical.
- Structured output workbench: request JSON output, validate it against a schema, show parse or schema errors inline, retry repair prompts, and save validated artifacts.
- Turn-level diff and artifact inspection: inspect what changed each turn, including files referenced, tools called, model/provider used, token delta, cost delta, and emitted artifacts.
- Approval policy profiles: reusable permission postures such as read-only analysis, docs-safe writer, local-dev coder, CI simulation, and high-risk manual approval.
- Workspace snapshots: bundle selected files, git diff, logs, workspace roots, and notes into a reusable context capsule.
- Session labels and searchable outcomes: tag sessions by goal, status, files, provider/model, outcome, and reusable workflow potential.
- Git-aware review mode: summarize current diffs, identify risky files, suggest commit messages, draft PR summaries, and recommend likely affected tests.
Install
npm install -g openpiperThis installs two binaries:
openpiperfor the interactive terminal UIpiperfor non-interactive runner workflows
Prerequisites
- Node.js 20.18.1 or newer
- At least one supported provider connection: Anthropic, OpenAI, Gemini, Ollama Local, or Ollama Cloud
Configuration
On first run, openpiper creates ~/.openpiper/config.json and walks through the minimum setup needed for an interactive provider connection.
You can also create the config file yourself:
mkdir -p ~/.openpiper
$EDITOR ~/.openpiper/config.jsonExample:
{
"default_provider": "anthropic",
"default_model": "claude-sonnet-4-6-20250514",
"ui": {
"theme": "openpiper"
},
"providers": {
"anthropic": {
"api_key": "sk-ant-..."
}
}
}If you are working from a source checkout, config.example.json can be copied as a starting point:
cp config.example.json ~/.openpiper/config.jsonAlternatively, set provider credentials through environment variables or use /connect inside the TUI.
Available UI themes:
openpiperforestamber
If no config file exists on first run, OpenPiper will walk you through onboarding.
Usage
# Start the interactive TUI
openpiper
# Send an initial prompt directly into the TUI
openpiper "explain how streaming works"
# Use a specific model
openpiper --model claude-haiku-4-5-20251001
# Run once and print the response
openpiper --print "summarize this repository"
# Enable debug mode (shows provider events in workspace)
openpiper --debug
# Add an external state directory with read/write tool access
openpiper --add-dir ~/.agentlab
# Non-interactive runner with JSON stdout
piper run --provider anthropic --model claude-sonnet-4-6-20250514 --user-prompt "write release notes"Workspace Roots
OpenPiper resolves relative tool paths from the current working directory. Additional directories can be added explicitly when a tool needs to read or write outside that directory.
# Interactive TUI: allow tools to read and write AgentLab state
openpiper --add-dir ~/.agentlab
# Interactive TUI: add read/write state plus read-only docs
openpiper --add-dir ~/.agentlab --include-dir ~/docs/specs
# Runner: same workspace-root flags; --workdir remains only for artifacts
piper run --model <model> --user-prompt "inspect state" --add-dir ~/.agentlabWorkspace root flags:
--add-dir <dir>grants read/write tool access to that directory and its subfolders. It is repeatable.--include-dir <dir>grants read-only tool access to that directory and its subfolders. It is repeatable.--include-directories <dirs>is a read-only, comma-separated compatibility alias.
Persistent workspace roots can also be placed in ~/.openpiper/config.json:
{
"workspace": {
"roots": [
{ "path": "~/.agentlab", "access": "read_write" },
{ "path": "~/docs/specs", "access": "read" }
]
}
}Tool approvals remain path-scoped and access-scoped. A workspace root says where tools may operate; an approval says what tool/path access the user allowed once, for the session, or always.
Prompt Recipes
Recipes are reusable prompt runbooks stored as JSON files in ~/.openpiper/recipes.
{
"name": "Review Changed Files",
"description": "Review a path or diff for risks and likely tests",
"provider": "anthropic",
"model": "claude-sonnet-4-6-20250514",
"variables": [
{ "name": "path", "default": "." },
{ "name": "mode", "default": "strict" }
],
"prompt": [
"Review {{path}} in {{mode}} mode.",
"Focus on behavioral risk, missing tests, and release notes."
],
"workspace_roots": [{ "path": ".", "access": "read_write" }],
"output": { "format": "markdown" }
}Use recipes inside the TUI:
/recipe
/recipe review-changed-files path=src mode=strictAfter a recipe produces a useful result, /export can turn that session into a runner replay package.
In-Session Commands
| Command | Description |
| --------------------------- | ----------------------------------------------- |
| /help | Show commands and key controls |
| /file <path> | Load a UTF-8 file into conversation context |
| /clear | Reset conversation history |
| /model | Open the model picker |
| /model <provider>/<model> | Switch provider and model directly |
| /theme | Open the theme picker |
| /theme <name> | Switch theme directly |
| /connect | Open provider connection setup |
| /connect <provider> <key> | Save provider credentials from the command line |
| /disconnect | Open the provider disconnect picker |
| /disconnect <provider> | Remove saved credentials for a provider |
| /export | Export the session into a runner-ready package |
| /export <dir> | Export the session into a specific directory |
| /recipe | List available prompt recipes |
| /recipe <name> key=value | Render and run a prompt recipe |
Keyboard Controls
| Key | Action |
| ----------------- | -------------------------------------------------- |
| Enter | Submit message, run command, or select modal item |
| ↑ / ↓ | Scroll conversation or move through picker items |
| PageUp / PageDown | Scroll conversation history |
| Ctrl+U / Ctrl+D | Half-page scroll up or down |
| Tab | Auto-complete command when typing / |
| Escape | Return to input mode or close an open modal |
| Ctrl+B | Toggle the workspace sidebar |
| Ctrl+T | Focus the workspace view |
| Ctrl+R | Toggle reader mode |
| Ctrl+C | Abort active work and exit |
| Mouse wheel | Scroll conversation history in supported terminals |
Development
npm run dev # Run with tsx (no build)
npm run build # Compile to dist/
npm test # Run vitest
npm run typecheck # Type-check src + tests
npm run lint # ESLint (type-checked rules)
npm run format # PrettierArchitecture
argv -> parseArgs (commander) -> config/provider resolution
-> ConversationEngine + SessionController
-> SessionController.submit() -> engine.startTurn(signal) -> ProviderAdapter.stream(signal)
-> stream events -> controller updates immutable ViewModel
-> useSyncExternalStore -> App renders from ViewModelKey patterns:
- Immutable ViewModel: Components never read from the engine. SessionController produces snapshots; React consumes them via
useSyncExternalStore. - Provider registry: Capability-driven registration. Adding a provider means implementing
ProviderAdapterand callingregistry.register(). - AbortSignal end-to-end: From controller through engine to provider SDK.
- Structured logger: Writes JSON to
~/.openpiper/logs/openpiper.log, independent of UI state.
See docs/piper-runner-plan.md for the full architecture, file layout, and migration plan.
Design
The TUI design is locked and documented in docs/design/DESIGN.md with color tokens, spacing constants, component specifications, and reference screenshots at multiple terminal widths.
External Tech Stack
OpenPiper is built as a TypeScript and Node.js terminal application. It ships two command-line binaries from one npm package: piper for non-interactive automation and openpiper for the interactive terminal UI.
| Area | Technology | | ------------------- | ------------------------------------------ | | Language | TypeScript | | Runtime | Node.js with ESM | | Package manager | npm | | CLI framework | Commander | | Terminal UI | Ink | | UI rendering model | React | | Provider networking | Undici | | LLM providers | Anthropic, OpenAI, Gemini, and Ollama APIs | | Testing | Vitest | | Code quality | ESLint and Prettier | | Development runner | tsx |
