- Rust 99.4%
- Python 0.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github/workflows | ||
| crates | ||
| evals | ||
| scripts | ||
| .DS_Store | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| PEBBLE.md | ||
| README.md | ||
Pebble
Pebble is a Rust agentic coding harness with a fast, transcript-first terminal interface.
It supports:
- Nano-GPT
- Neuralwatt
- Lilac
- Grok subscriptions through the official Grok CLI
- Synthetic
- OpenAI Codex / ChatGPT plans
- OpenCode Go
Pebble is designed around an interactive REPL, local tools, managed sessions, MCP servers, and a user-controlled permission model. Web retrieval is provider-agnostic and always runs through Exa.
◆ pebble v0.4.7
gpt-5.5 on OpenAI Codex
build · workspace
~/dev/my-project
/help for commands · Tab switches mode
build ❯ find the flaky test and fix the root cause
◇ Working...
$ Shell cargo test
└ ok: 0
◆ Pebble
The retry assertion was sharing state across test cases. I isolated the fixture
and added a regression test.
✓ Done in 8.4s · 3 tools · 2 files changed · 1.8k tokens · 4% context
Check the Changelog for update/patch notes
First-run setup
1. Authenticate a model service
Pebble can prompt you for credentials interactively:
pebble login
You can also target a specific service directly:
pebble login synthetic
pebble login neuralwatt
pebble login lilac
pebble login grok
pebble login openai-codex
pebble login opencode-go
pebble login nanogpt
For API-key services, you can also pass the key inline:
pebble login opencode-go --api-key "$OPENCODE_GO_API_KEY"
pebble login neuralwatt --api-key "$NEURALWATT_API_KEY"
pebble login lilac --api-key "$LILAC_API_KEY"
openai-codex uses ChatGPT device-code auth instead of an API key. grok
launches grok login and uses the official Grok CLI's refreshable OAuth
session, so Pebble never copies or stores xAI subscription tokens. Install the
official Grok CLI before connecting it.
Pebble talks to that CLI over its ACP stdin/stdout protocol; prompts are never
placed in process arguments. Grok replies render as ACP chunks arrive, and
Ctrl+C cancels the entire active turn: HTTP streams, Grok ACP sessions, MCP
calls, hooks, and foreground shell/REPL/PowerShell tools all receive the same
cancellation signal and child processes are terminated. API-key logins are
checked before invalid credentials are saved when the provider exposes a model
catalog.
Pebble automatically disables ANSI color when output is redirected, when
NO_COLOR is set, with CLICOLOR=0, or under TERM=dumb. Set
CLICOLOR_FORCE=1 to keep color in redirected output.
Inside the REPL, the equivalent commands are:
/login
/auth
/login openai-codex
/login grok
/login opencode-go
/auth synthetic
/logout openai-codex
If you run /login or /auth without a service, Pebble opens a picker with:
nanogptneuralwattlilacgroksyntheticopenai-codexopencode-goexa
2. Save your Exa key
Pebble uses Exa for all web search and scrape functionality.
Save it with:
pebble login exa
Or from inside the REPL:
/login exa
/auth exa
You can also provide it inline:
pebble login exa --api-key "$EXA_API_KEY"
Or export it in your shell:
export EXA_API_KEY=...
Daily usage
Choose a provider and model
Run /model to open the unified picker. Left and right switch providers,
typing searches every provider at once, up and down move, and Enter selects.
The provider rail shows which services are connected. Signed-out providers
remain visible with the exact /login command they need, and a failed provider
catalog no longer prevents other providers from loading.
Provider catalogs are cached locally for instant startup and refreshed in the background after five minutes. The provider rail distinguishes fresh, cached, refreshing, and failed catalogs. Grok's model list comes from the installed official CLI, so it follows the user's subscription and CLI version.
Neuralwatt and Lilac use their OpenAI-compatible chat-completions APIs. Model
IDs are namespaced in Pebble, such as neuralwatt/zai-org/glm-5.2 and
lilac/moonshotai/kimi-k2.6, so the same upstream model can be selected from
different providers without ambiguity. Both providers stream text, reasoning,
tool calls, and usage natively; image attachments are sent as OpenAI-compatible
image inputs when the selected model supports vision.
Interactive REPL
Launch the REPL:
pebble
Useful first commands:
/help
/status
/model
/login
/logout
/sessions
Basic prompt flow:
> summarize this project
> inspect Cargo.toml and explain the workspace layout
> find the session restore logic
One-shot prompt mode
For a single command without entering the REPL:
pebble prompt "Summarize this repository"
Or:
pebble "Inspect the current Rust workspace and explain the top-level crates"
Restrict tool access
pebble --allowedTools read,glob "Summarize Cargo.toml"
Safety limits
Pebble stops runaway turns after 32 model passes. Foreground shell, REPL, and PowerShell commands default to a 10-minute timeout, and model API requests also time out after 10 minutes. Override these limits when a project needs more time:
export PEBBLE_MAX_TURN_ITERATIONS=48
export PEBBLE_BASH_TIMEOUT_MS=900000
export PEBBLE_TOOL_TIMEOUT_MS=900000
export PEBBLE_API_TIMEOUT_SECS=900
An explicit tool-call timeout still takes precedence over the default.
Eval suites and traces
Validate a suite without calling a model:
pebble eval --check evals/smoke.json
Run a suite and fail the process if any case fails:
pebble eval --fail-on-failures evals/smoke.json
Show recent eval trends:
pebble eval history
pebble eval history --suite smoke --model zai-org/glm-5.1
Eval history is rebuilt from .pebble/evals/*.json and persisted to
.pebble/evals/index.json after each run.
Replay failed eval cases from a saved report:
pebble eval replay .pebble/evals/<report>.json
pebble eval replay .pebble/evals/<report>.json --case handles-denied-write
Eval replay loads each case's saved trace and shows assertion failures, failure categories, final answer preview, artifacts, and the trace timeline.
Trace, replay, eval history, eval compare, and eval replay support --json for
machine-readable diagnostics:
pebble trace .pebble/runs/<trace>.json --json
pebble eval replay .pebble/evals/<report>.json --json
Promote a saved trace into a regression eval:
pebble eval capture .pebble/runs/<trace>.json --suite evals/regressions.json --name "handles denied write"
Captured cases use the trace input preview as the prompt and generate
assertions for required tools, tool order, permission outcomes, API/tool call
limits, and successful tool usage when present. Existing case IDs are protected
unless --force is passed.
Inspect a saved turn trace:
pebble trace .pebble/runs/<trace>.json
Replay a saved trace timeline without calling the model or tools:
pebble replay .pebble/runs/<trace>.json
Golden trace regressions protect the trace/replay renderers, JSON reports, context-window percentage display, compact tool previews, and MCP tool spec projection:
cargo test -p pebble golden
PEBBLE_UPDATE_GOLDENS=1 cargo test -p pebble golden
Use PEBBLE_UPDATE_GOLDENS=1 only when the output change is intentional.
Trace previews are redacted before persistence and again when loading older
trace files. Common API keys, bearer tokens, passwords, private keys, and
credential-bearing URLs are replaced with [REDACTED] markers.
Trace and eval report JSON files include a schema_version field. Files
written before schema versioning are treated as version 1 when loaded; newly
written files use the current schema version.
Prune generated trace and eval artifacts:
pebble gc --dry-run
pebble gc
Retention defaults keep trace JSON files for 30 days or the newest 1000 files,
eval reports for 90 days or the newest 200 reports, and CI check reports for 30
days or the newest 100 reports. Override them in .pebble/settings.json:
{
"retention": {
"traceDays": 14,
"maxTraceFiles": 500,
"evalDays": 60,
"maxEvalReports": 100,
"ciDays": 14,
"maxCiReports": 50
}
}
Validate settings without starting a REPL:
pebble config check
pebble config check --json
Config checks report malformed JSON, non-object settings files, bad field types, unsupported option values, and the settings file/field path responsible when Pebble can infer it.
Collect a redacted local support snapshot:
pebble doctor bundle
Probe every configured model provider without sending a model prompt or incurring inference usage:
pebble doctor providers
pebble doctor providers --json
The provider report checks authentication and the live model catalog, records latency and model count, and states Pebble's streaming, tool-call, and vision transport support without printing credentials.
The diagnostics bundle is written under .pebble/diagnostics/ and includes
offline doctor checks, config validation, local system metadata, session
metadata, recent trace/eval summaries, and MCP discovery status. It excludes
API keys, credentials, raw config contents, full prompts, assistant responses,
tool inputs, tool outputs, and live API/network probes.
Core REPL commands
Common commands:
/help/help auth/help sessions/help extensions/help web/status/model/login/logout/provider/route/permissions/bypass/proxy/mcp/skills/plugins/sessions/resume/resume last/session switch <id>
Notes:
/provider [name]opens model selection, optionally focused on one provider./routecontrols NanoGPT's upstream routing override and only applies to NanoGPT-backed models.Shift+EnterandCtrl+Jinsert a newline in the input editor.
Authentication and config
Pebble stores user config under:
~/.pebble/
Credentials are stored in:
~/.pebble/credentials.json
Possible stored keys:
nanogpt_api_keysynthetic_api_keyopenai_codex_authopencode_go_api_keyexa_api_key
Environment variables still take precedence over saved credentials.
Useful environment variables:
NANOGPT_API_KEYSYNTHETIC_API_KEYOPENAI_CODEX_ACCESS_TOKENOPENAI_CODEX_REFRESH_TOKENOPENAI_CODEX_ACCOUNT_IDOPENAI_CODEX_EXPIRES_ATOPENCODE_GO_API_KEYEXA_API_KEYNANOGPT_BASE_URLSYNTHETIC_BASE_URLOPENAI_CODEX_BASE_URLOPENCODE_GO_BASE_URLEXA_BASE_URLPEBBLE_CONFIG_HOME
EXA_BASE_URL defaults to https://api.exa.ai.
OPENAI_CODEX_BASE_URL defaults to https://chatgpt.com/backend-api/codex.
Sessions and restore
Pebble keeps managed sessions under:
.pebble/sessions/
Useful flows:
/sessionslists recent sessions/resumeopens the picker/resume lastrestores the most recently modified session/session switch <session-id>switches inside the REPLpebble resume [SESSION_ID_OR_PATH]resumes from the CLI
Session restore includes more than just transcript history. Pebble persists and restores:
- active model
- permission mode
- thinking toggle
- proxy tool-call toggle
- allowed tool set
That makes restored sessions behave much closer to the original live session.
Permissions
Pebble supports:
read-onlyworkspace-writedanger-full-access
Examples:
/permissions
/permissions workspace-write
/bypass
/bypass is a shortcut for danger-full-access in the current session.
Web search and scrape
Pebble keeps the tool names WebSearch and WebScrape, but both use Exa.
WebSearch
- uses Exa
POST /search - defaults to Exa search type
auto - promotes to
deepfor deeper or more structured requests - maps allowed and blocked domains into Exa domain filters
WebScrape
- uses Exa
POST /contents - supports one or more URLs
- validates URLs before sending requests
- returns normalized previews in the TUI
Check readiness
Run:
/status
Pebble reports Exa readiness separately from the active model backend.
Extensions
Pebble has three main extension surfaces:
- skills
- MCP servers
- plugins
Skills
Create a project-local skill:
/skills init my-skill
This creates:
.pebble/skills/my-skill/SKILL.md
Useful commands:
/skills
/skills help
MCP servers
Create a starter MCP server entry:
/mcp add my-server
This updates:
.pebble/settings.json
Inspect what is configured:
/mcp
/mcp tools
/mcp reload
Enable or disable a configured server locally:
/mcp disable context7
/mcp enable context7
These local toggles are written to:
.pebble/settings.local.json
That lets you keep a shared project MCP config while turning specific servers on or off per machine.
Plugins
Useful commands:
/plugins
/plugins help
/plugins install ./plugins/my-plugin
/plugins enable my-plugin-id
Pebble expects plugins to expose:
.pebble-plugin/plugin.json
Proxy mode
Pebble can run in XML proxy tool-call mode:
/proxy status
/proxy on
/proxy off
When proxy mode is enabled, tool use is expected through XML <tool_call> blocks rather than native tool schemas.
Troubleshooting
A model won’t answer
- run
/status - confirm you saved credentials with
pebble login - or export the matching
*_API_KEY - verify the active model with
/model
Web tools are unavailable
- run
pebble login exa - or export
EXA_API_KEY - check
/statusfor Exa readiness
MCP server loads but shows no tools
- run
/mcp - run
/mcp tools - run
/mcp reload - check
.pebble/settings.json - check
.pebble/settings.local.json - if the server is marked
disabled, run/mcp enable <name>
Session restore feels wrong
- inspect
/status - use
/resume lastor/session switch <id> - verify the session was saved after changing model, permissions, proxy, or thinking state
Plugin setup is unclear
- run
/plugins help - confirm the plugin root contains
.pebble-plugin/plugin.json
Install, build, and development
Build a release binary
cargo build --release -p pebble
Binary output:
./target/release/pebble
On Windows, the binary output is target\\release\\pebble.exe. Pebble resolves config and
credentials from PEBBLE_CONFIG_HOME first, then %USERPROFILE%\\.pebble when HOME is not set.
Run from source
cargo run -p pebble --
Run tests
cargo test --workspace -- --test-threads=1
cargo build -p pebble
python3 scripts/pty_smoke.py
The PTY suite drives the compiled binary through onboarding, input interrupts, login and model pickers, narrow-terminal resizing, Unicode search, model and foreground-tool cancellation, plain redirected output, and clean exit. It runs on Linux and macOS with isolated temporary configuration and no provider credentials; CI also runs a Windows redirected-console smoke check.
CI also runs the agent-harness safety checks that protect user-visible diagnostics and regression tooling:
cargo run -p pebble -- ci check
cargo run -p pebble -- ci check --json
cargo run -p pebble -- ci check --json --save-report
cargo run -p pebble -- ci history
cargo run -p pebble -- ci history --json --limit 20
cargo run -p pebble -- release check
cargo run -p pebble -- release check --json --save-report
That shared entrypoint runs golden trace regressions, config schema validation,
eval suite validation, and a diagnostics bundle redaction-contract check.
--json emits step status, durations, and the diagnostics bundle path for
tooling. --save-report writes the final JSON report under .pebble/ci/ and
includes the report path in the output. ci history summarizes saved reports
without rerunning the checks. Captured CI failures include a per-step artifact
path with stdout/stderr logs when available.
release check is the ship-readiness rollup. It summarizes the current git
branch/commit/dirty state, Pebble version, latest saved CI report, latest eval
history entry, config validation status, golden trace regression status,
diagnostics redaction status, and paths to saved reports/bundles/artifacts.
Use --save-report to write the JSON rollup under .pebble/release/.
Project config files
Common project-local files:
PEBBLE.md.pebble/settings.json.pebble/settings.local.json.pebble/skills/.pebble/sessions/
Release/update behavior
Pebble’s self-update flow targets the GitHub releases for:
nanogpt-community/pebble