~/.observal/) and in each harness’s config directory.
Client-side: ~/.observal/
config.json schema
observal auth. The config set command accepts only server_url, timeout, update_check, update_check_interval, and update_check_repo. Supported environment variables override persisted values for the current invocation; see Environment variables.
Durable session outbox
Python session exporters persist each observed batch intelemetry_buffer.db before network delivery. OpenCode and Pi use per-session files under their native outbox directories because their TypeScript runtimes cannot call the Python SQLite engine. All follow the same protocol: pending data survives process restarts and failed attempts, and the source line advances only when the server’s contiguous checkpoint covers the complete batch. Observal does not silently evict unacknowledged records at capacity.
sync_state.json is a cache of acknowledged local positions, not the authority for delivered history. If it is missing, corrupt, or stale, recovery validates and restores positions from the authenticated server checkpoint. Finalized sessions also send a SHA-256 audit manifest; hashing is not performed on ordinary incremental uploads.
Use observal ops telemetry status to inspect pending batch count, disk use, oldest pending time, and last successful acknowledgement.
aliases.json schema
@.
last_results.json schema
harness-side
Claude Code
Kiro
Cursor
VS Code
Codex CLI
Pi
Two mutually exclusive installation modes are supported:
- npm:
npm:observal-piis configured in~/.pi/agent/settings.json(with or without a pinned version, and whether or not Pi has downloaded it yet). Observal never installsextensions/observal.tsin this mode —observal doctoronly reports when a pinned version is older than the installed CLI, with api update npm:observal-pireminder. Pi loads a localextensions/observal.tsin addition to the npm package, so if one is left over from local mode every session is sent twice;observal doctor patchremoves a local copy it recognizes as its own (keeping it asobserval.ts.bak) and leaves a file Observal did not write alone. - local: no npm package is configured.
observal auth loginandobserval doctor patchinstall the extension bundled with the CLI directly toextensions/observal.ts, recording the installed CLI version in the adjacent manifest. A later CLI upgrade rewrites each of those files atomically — the two are written in sequence, not as a single atomic unit — and prints a reminder to restart Pi or run/reload; a newer local install than the current CLI is left alone. If the file still carries the current version but its contents have drifted from the bundled source — an edited working copy, say — doctor restores it and keeps the previous contents asobserval.ts.bak.
observal.ts.bak (.bak.1, .bak.2, … if that name is taken). The copy does
not end in .ts, so Pi does not load it; delete it once you are satisfied with
the result.
There are two cases where no copy is made, because nothing is lost: adopting a
file whose contents already match the bundle, where only the manifest is
written, and observal doctor cleanup removing a tracked install that still
matches what Observal wrote. Every other refresh, restore, migration and
duplicate removal keeps one — a manifest records which CLI version wrote an
install, not that its bytes are still unedited.
Migrating installs from before version tracking
CLI versions before the manifest existed wroteextensions/observal.ts with nothing beside it. Those installs are recognized by the doc header every Observal extension carries, and observal auth login or observal doctor patch migrates them: the existing file is copied to observal.ts.bak (.bak.1, .bak.2, … if that name is taken), the current extension is written in its place, and the manifest is created. The backup does not end in .ts, so Pi does not load it; delete it once you’re satisfied with the upgrade.
If extensions/observal.ts exists without a matching manifest, doesn’t match the bundled source, and carries no Observal header, Observal treats it as unmanaged and never overwrites or removes it — remove or move the file aside, then re-run observal doctor patch --harness pi to let Observal manage it.
Safe writes
observal doctor patch and observal doctor cleanup write each managed configuration file atomically and preserve unrelated entries. Use --dry-run --output json to review planned harness changes before writing. Agent Pull reports every created or merged file in its result.
File permissions
Client-side files under~/.observal/ are created with mode 0600 (owner read/write only). This holds your access token, so don’t loosen the permissions.
Related
- Environment variables - supported runtime overrides
observal config, CLI surface for editing

