Configuration & Environment Variables
#Precedence
Peekaboo resolves settings in this order (highest → lowest):
- Command-line arguments
- Environment variables (never copied into files)
- Credentials file (
~/.peekaboo/credentials: API keys or OAuth tokens) - Configuration file (
~/.peekaboo/config.json) - Built-in defaults
#Available Options
| Setting | Config File | Environment Variable | Description |
|---|---|---|---|
| AI Providers | aiProviders.providers | PEEKABOO_AI_PROVIDERS | Comma-separated list (openai/gpt-5.6,anthropic/claude-opus-5,grok/grok-4.3,ollama/llava:latest). First healthy provider wins. |
| Agent Model | agent.defaultModel | PEEKABOO_AGENT_MODEL | Default model for peekaboo agent; CLI --model wins. |
| Agent Temperature | agent.temperature | - | Sampling temperature shared by the app and CLI (default 0.7); clamped or omitted for models that restrict it. |
| Agent Max Tokens | agent.maxTokens | - | Requested output-token budget shared by the app and CLI (default 16384, accepted range 1...128000); clamped to provider capability. |
| OpenAI API Key | credentials file | OPENAI_API_KEY | Required for OpenAI models. |
| Anthropic API Key | credentials file | ANTHROPIC_API_KEY | Required for Claude models (API-key path). |
| Anthropic OAuth | credentials file | ANTHROPIC_REFRESH_TOKEN, ANTHROPIC_ACCESS_TOKEN, ANTHROPIC_ACCESS_EXPIRES | Created by config login anthropic; no API key stored. |
| Grok API Key | credentials file | GROK_API_KEY / X_AI_API_KEY / XAI_API_KEY | Required for Grok (xAI). Env alias resolves to Grok. |
| Gemini API Key | credentials file | GEMINI_API_KEY | Required for Gemini. |
| MiniMax API Key | credentials file | MINIMAX_API_KEY | Required for MiniMax international; also works as fallback for MiniMax China. |
| MiniMax China API Key | credentials file | MINIMAX_CN_API_KEY | Optional China-specific key for minimax-cn/... models. |
| Kimi API Key | credentials file | MOONSHOT_API_KEY / KIMI_API_KEY | Required for Kimi models; MOONSHOT_API_KEY takes precedence. |
| Ollama URL | aiProviders.ollamaBaseUrl | PEEKABOO_OLLAMA_BASE_URL, OLLAMA_BASE_URL | Native Ollama server base; precedence is Peekaboo env, Ollama env, config, then http://localhost:11434. Do not append /v1. |
| Default Save Path | defaults.savePath | PEEKABOO_DEFAULT_SAVE_PATH | Directory for screenshots (supports ~). |
| Log Level | logging.level | PEEKABOO_LOG_LEVEL | trace, debug, info, warn, error, fatal (default info). |
| Log Path | logging.path | PEEKABOO_LOG_FILE | Custom log destination (default /tmp/peekaboo-mcp.log for MCP; CLI uses stderr). |
| CLI Binary Path | - | PEEKABOO_CLI_PATH | Override bundled CLI when testing custom builds. |
| GameBridge manifest budget | - | PEEKABOO_GAMEBRIDGE_MAX_MANIFEST_BYTES | Optional positive byte limit for Firestaff accessibility manifests. Unset or empty preserves unlimited size; invalid values disable GameBridge detection. |
| Auto daemon socket | - | PEEKABOO_DAEMON_SOCKET | Override the socket used for auto-started daemons (mainly tests/dev). |
| Auto daemon idle timeout | - | PEEKABOO_DAEMON_IDLE_TIMEOUT_SECONDS | Seconds before an auto-started daemon exits while idle (default 300). |
| Tool allow-list | tools.allow | PEEKABOO_ALLOW_TOOLS | CSV or space list. If set, only these tools are exposed (env replaces config). |
| Tool deny-list | tools.deny | PEEKABOO_DISABLE_TOOLS | CSV or space list. Always removed; env list is additive with config. |
| UI input strategy | input.* | PEEKABOO_INPUT_STRATEGY and per-verb variants | Choose action invocation versus synthetic input. Built-in policy prefers actions for click/scroll/background typing and focused background Cmd+A; ordinary hotkeys and legacy SDK typing remain synthFirst. |
| Element detection boxes | visualizer.elementDetectionEnabled | PEEKABOO_VISUAL_ELEMENT_BOXES | Draw a bounding box per accessibility element during peekaboo see. Default false (visually noisy); env var overrides config. The Peekaboo.app settings toggle writes the same config key. |
#GameBridge manifest budget
Set PEEKABOO_GAMEBRIDGE_MAX_MANIFEST_BYTES=1048576 to limit Firestaff manifests to 1 MiB. The limit is inclusive and applies before loading or decoding the file, including growth after opening. An oversized or invalid manifest is ignored and normal Accessibility detection can proceed. Firestaff must publish immutable frames by atomic rename; detected size or timestamp changes are refused. Unset or empty keeps the existing unlimited-size default.
The environment belongs to the process performing detection. Use --no-remote for a standalone CLI invocation, or set the variable when starting the Bridge host. A CLI environment override is not forwarded to an already-running host.
#API Key Storage
- Environment variables – supported for existing automation, but keep values out of command arguments.
- Credentials file –
peekaboo config credential set OPENAI_API_KEYprompts without echo and stores the value in~/.peekaboo/credentials(chmod 600). Scripts should pipe one line with--credential-stdin --no-inputor use an owner-only--credential-file. - Config file – avoid storing keys here unless absolutely necessary. OAuth tokens are never written to
config.json.
The macOS app and CLI use this same file as the ongoing authority for saved API keys, including when PEEKABOO_CONFIG_DIR changes the configuration root. Settings reloads it when the provider pane opens; use Reload keys after a CLI rotation while the pane stays open. There is no credential-path Keychain storage or importer and no password or biometric prompt for app credential persistence.
The directory is owner-only (0700) and the file is owner-readable/writable (0600), including temporary files before publication. This deliberately accepts file-level protection to avoid authentication prompts: the keys are plaintext, and other processes running as your user can read them. Do not share this file. Sequential app/CLI edits preserve unrelated keys and OAuth entries; concurrent edits by separate processes, including Tachikoma, are not serialized.
Old app preferences are never imported automatically, even if the file is missing, empty, or deleted. Import saved app keys explicitly recovers legacy-only keys; existing file values win, including CLI changes made since the pane opened. Successful saves, clears, and imports retire only the corresponding legacy entries. Failed imports leave those entries available for another explicit attempt. Showing a credential field or receiving an unchanged binding value never saves the draft or retires legacy keys. App edits and legacy imports trim surrounding whitespace and newlines; interior newlines and NUL remain invalid. Whitespace-only app input clears a populated field but leaves an already empty field unchanged; blank legacy entries remain stored without offering recovery.
A failed save keeps the draft marked Not saved and leaves the previous effective credential unchanged. A failed clear does not claim deletion or environment fallback. Retry is explicit after failure, and reload preserves failed drafts. A durability warning means publication already happened; reload to check instead of blindly repeating the write. Environment overrides, config fallbacks, OAuth sessions, and the international MiniMax fallback for MiniMax China remain runtime-only and are not implicitly saved.
#Provider Variables
PEEKABOO_AI_PROVIDERS:provider/modelCSV. Example:openai/gpt-5.6,anthropic/claude-opus-5,grok/grok-4.3,ollama/llava:latest.OPENAI_API_KEY,ANTHROPIC_API_KEY,GROK_API_KEY|X_AI_API_KEY|XAI_API_KEY,GEMINI_API_KEY,MINIMAX_API_KEY,MINIMAX_CN_API_KEY,MOONSHOT_API_KEY|KIMI_API_KEY: required for their respective providers when using API keys.- Ollama native endpoint precedence:
PEEKABOO_OLLAMA_BASE_URL>OLLAMA_BASE_URL>
aiProviders.ollamaBaseUrl > http://localhost:11434. Set the server base without /api/chat or /v1; see the Ollama provider guide.
#Defaults & Paths
PEEKABOO_DEFAULT_SAVE_PATH: screenshot destination (created automatically).PEEKABOO_CLI_PATH: point Peekaboo at a debug build (.build/debug/peekaboo) without copying binaries around.
#Agent generation settings
The macOS Settings UI and peekaboo agent share agent.temperature and agent.maxTokens through ~/.peekaboo/config.json:
{
"agent": {
"defaultModel": "anthropic/claude-fable-5",
"temperature": 0.7,
"maxTokens": 128000
}
}
maxTokens is an upper request, not a promise: Peekaboo clamps it to the selected model's advertised output limit. Fable 5 supports up to 128K output and a 1M context window. Anthropic-compatible custom providers inherit known Fable limits from the model ID, while custom model entries can advertise their own maxTokens.
Temperature is clamped to 0...1 for Anthropic-compatible models and 0...2 elsewhere. Peekaboo omits it entirely for models that reject sampling controls, including GPT-5-compatible endpoints and current Anthropic adaptive-thinking models.
#UI Input Strategy
Input strategy controls whether UI interactions use accessibility action invocation or synthetic input. The built-in policy keeps the global default, legacy SDK typing, and ordinary hotkeys at synthFirst, selects actionFirst for click, scroll, background typing, and focused background Cmd+A, and exposes setValue/performAction as action-only operations. An explicit global strategy overrides the built-in click/scroll/type/select-all preferences unless a more specific configured override wins.
The Cmd+A built-in preference is limited to focused text selection: unsupported selection falls directly back to targeted events, never to a new process-menu action. Explicit global, hotkey, and per-app selections remain authoritative; synthetic choices skip AX selection entirely. The resolved policy records this separately as backgroundSelectAllDefault, not in the typing preference or generic hotkey override. Concrete SDK policies and older resolved JSON without the new preference retain their declared strategy. Action-based selection and menus do not implement key holding; choose a synthetic strategy when a physical hold is required.
Precedence is --input-strategy CLI flag, then environment, then config file, then built-in default. The CLI flag forces local execution because the current bridge protocol does not forward per-call strategy overrides.
Valid values:
actionFirst: try accessibility action invocation, fall back to synthetic input when unsupported.synthFirst: use synthetic input first.actionOnly: use action invocation only.synthOnly: use synthetic input only.
For background typing, actionOnly forbids keyboard events and both synthetic strategies skip AX value/selection edits. actionFirst falls back per unsupported unit, never after an accepted or uncertain write. Local native text edits can work with Accessibility alone; local Event Synthesizing permission is checked only before needed events. Bridge-hosted targeted typing still requires Post Event permission at admission, including native edits.
The legacy SDK type(text:target:clearExisting:typingDelay:snapshotId:) keeps its shipped synthFirst default, including named-target focus and per-character keyboard delivery. Default calls do not probe AX replacement eligibility. Explicit global, type, and per-app strategies retain their existing precedence on both SDK and background paths. Direct AX replacement under an explicitly selected action strategy requires clearExisting: true, zero typingDelay, and a fresh check proving the named target is the current keyboard receiver; cached focus or a frontmost app/window alone is insufficient. A requested positive delay or a successfully read focus mismatch makes the action route unsupported: actionFirst uses the existing synthetic focus/clear/type path, while actionOnly refuses without dispatch. An unreadable or uncertain focus check instead stops before input under either action strategy, without fallback. Permission failures, cannotComplete, missing or malformed focus values, and timeouts are errors, not evidence that the target is unfocused. Explicit synthFirst and synthOnly retain their existing synthetic behavior. These SDK eligibility checks do not change the global/per-app strategy precedence or the CLI foreground action-array path.
Zero-delay SDK replacement also requires bounded, same-process ancestry proving a native rather than web receiver. Known AXWebArea descendants take the existing keyboard route under actionFirst and refuse under actionOnly, before any AX value write; unprovable ancestry instead stops without input or fallback. This avoids treating AX value readback as proof of page input-event behavior and leaves explicit set-value semantics unchanged.
Config example:
{
"input": {
"defaultStrategy": "synthFirst",
"click": "actionFirst",
"scroll": "actionFirst",
"type": "actionFirst",
"hotkey": "synthFirst",
"setValue": "actionOnly",
"performAction": "actionOnly",
"perApp": {
"com.googlecode.iterm2": {
"hotkey": "synthOnly"
}
}
}
}
Environment variables:
PEEKABOO_INPUT_STRATEGYPEEKABOO_CLICK_INPUT_STRATEGYPEEKABOO_SCROLL_INPUT_STRATEGYPEEKABOO_TYPE_INPUT_STRATEGYPEEKABOO_HOTKEY_INPUT_STRATEGYPEEKABOO_SET_VALUE_INPUT_STRATEGYPEEKABOO_PERFORM_ACTION_INPUT_STRATEGY
CLI override:
peekaboo click --on "$ELEMENT_ID" --input-strategy actionFirst
When an input-policy override selects caller-local execution, combining that policy with --bridge-socket or PEEKABOO_BRIDGE_SOCKET fails with BRIDGE_UNAVAILABLE before constructing local services or sending input; Peekaboo does not silently ignore the selected host. Remove the CLI, environment, and config input-policy overrides to use that host, or pass --no-remote to deliberately run locally. Without an explicit socket, policy-local routing remains available. Concrete snapshot references still resolve their unique producer first; --no-remote restricts that check to the caller.
#Logging & Troubleshooting
PEEKABOO_LOG_LEVEL=debug(ortrace) surfaces verbose input-path logs.PEEKABOO_LOG_FILE=/tmp/peekaboo.logpersists logs for sharing.- Tool filters: env
PEEKABOO_ALLOW_TOOLSreplaces configtools.allow; envPEEKABOO_DISABLE_TOOLSis additive withtools.deny. Deny wins if a tool appears in both. See docs/security.md for examples and risk guidance.
#Setting Variables
# Single command
PEEKABOO_AI_PROVIDERS="ollama/llava:latest" peekaboo see --analyze "Describe this UI" --path img.png
# Session exports
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export X_AI_API_KEY="xai-..."
# Shell profile
echo 'export OPENAI_API_KEY="sk-..."' >> ~/.zshrc
When in doubt, run peekaboo config show --effective to see the merged view from every layer.