Expand description
§Layout
Mirrors upstream’s nested layout, so a ~/.pi/agent/ directory can be
copied to ~/.rpi/agent/ (or pointed at via RPI_CODING_AGENT_DIR) and
“just works”. The agent/ layer matches pi’s getAgentDir():
~/.rpi/ (RPI_CODING_AGENT_DIR env overrides the agent/ dir)
└── agent/
├── auth.json # persisted credentials (mode 0o600 on Unix)
├── models.json # user-defined provider/model catalog (hand-edited)
├── settings.json # saved default provider/model/thinking + theme
├── trust.json # per-cwd project trust decisions (read-only parity)
├── .setup_done # first-time-setup sentinel (extras.rs)
└── .earendil_seen # earendil-announcement sentinel (extras.rs)Flat-installed ~/.rpi/{auth.json,models.json} from older rpi releases are
migrated under agent/ on the next launch by migrate_legacy_layout
(best-effort, idempotent; only when the env override is unset).
§Concurrency
v1 is a single-process CLI, so we use atomic rename instead of upstream’s
proper-lockfile: write a sibling temp file, fs::rename over the target,
then chmod 0o600 on Unix (Windows chmod is a no-op, matching Node).
Concurrent rpi auth login from two shells could lose one update — that’s
accepted and documented; adding a file lock is deferred.
§Config-value expansion
resolve_config_value expands $ENV/${ENV}/!command inside
apiKey/headers exactly like upstream’s resolve-config-value.ts — so a
copied pi models.json/auth.json that references env vars or shell
commands resolves the same way. Applied where rpi consumes those values
(auth.json key, models.json bearer apiKey, provider/model headers).
Structs§
- Model
Definition - One model under a provider.
idis required (mirrors TSModelDefinition). - Models
Config - The
models.jsondocument. Mirrors TS{ providers: Record<id, ProviderConfig> }(core/model-config.tsModelsConfigSchema). - Provider
Config - A provider entry in
models.json. The fields mirror the TSProviderConfigone-for-one; v1 honorsbase_url/api_key/headers/auth_header/models, and ignoresapivalues other thananthropic-messages(documented).
Enums§
- Config
Error - A config-layer error (path resolution, IO, JSON). Surfaced to the user by
the
authsubcommand /provider::resolve. - Credential
- A stored credential. Mirrors the TS
Credentialunion (packages/ai/src/auth/types.ts). TheOauthvariant exists for forward compatibility but v1 never writes it (no OAuth device-code flow);resolvedoes not consume it.
Constants§
- ANTHROPIC_
DEFAULT_ BASE_ URL - The first-party Anthropic endpoint — used as the fallback
base_urlwhen a models.json provider omits it. Kept here (not imported fromrpi_ai) so the config layer never depends on the provider’s privatemodelsmodule. Public socrate::provider::resolvecan tell a gateway model (whosebase_urldiffers from this) from a built-in Anthropic model. - CONFIG_
DIR_ ENV - Env var that overrides the whole config dir (mirrors upstream
PI_CODING_AGENT_DIR). Absolute path; relative values are rejected. - CONFIG_
DIR_ NAME - The config directory name under the home dir. Upstream is
.pi; rpi uses.rpito avoid colliding with a nativepiinstall on the same machine. - DEFAULT_
PROVIDER_ ID - The provider id under which
rpi auth loginstores the Anthropic key. Mirrors upstream’s fixedanthropicprovider id.
Functions§
- agent_
dir - The rpi config directory (
~/.rpi/agentby default,RPI_CODING_AGENT_DIRoverride). Creates nothing — purely a path computation. Theagent/layer mirrors upstreamgetAgentDir()(join(homedir(), CONFIG_DIR_NAME, "agent")) so a copied~/.pi/agent/directory reads in place. The env override points at the agent dir itself (same as pi’sPI_CODING_AGENT_DIR). - auth_
path ~/.rpi/agent/auth.json.- default_
anthropic_ base_ url - Same value as
ANTHROPIC_DEFAULT_BASE_URL, as an ownedStringfor theunwrap_or_elseergonomic used byprovider_to_modelsand [crate::provider::models_json_provider_auth]. - delete_
credential - Remove
provider_idfrom the store. Returnstrueif a credential was present (and is now gone),falseif it was already absent. Always rewrites the file when the provider existed (soauth logoutreflects the new state on disk even if the map isn’t empty). - load_
models_ config - Load
~/.rpi/models.json. Missing file ⇒ empty config (no error). - migrate_
legacy_ layout - One-time best-effort migration of a pre-nesting flat layout
(
~/.rpi/{auth.json,models.json,.setup_done,.earendil_seen}) into the nested~/.rpi/agent/layout. No-op whenRPI_CODING_AGENT_DIRis set (never touch an explicit override), when the agent dir already exists, or when no flat files are present. Idempotent: a partial move resumes. Errors are swallowed (logged via the returnedResultonly so tests can observe);app::runignores them so a migration hiccup never blocks startup. - models_
path ~/.rpi/agent/models.json.- openai_
provider_ api_ key - Resolve an OpenAI-compatible provider key from its explicit config or a
known provider’s canonical environment variable. Arbitrary custom provider
ids must declare
apiKey: "$ENV": deriving an env name by normalizing the id would collapse distinct native-Pi identities such asa-banda_b. - project_
trust_ decision - Return the stored trust decision for
cwd. A missing entry (or an entry explicitly set tonull) returnsNone; callers choose their safe default. - provider_
is_ anthropic_ compatible - (
anthropic-messages, or omitted/unknown). Unknownapiis allowed through for forward-compat but flagged ignored-in-v1 in the docs. Public socrate::providercan scan models.json providers for anauthHeader:truegateway bearer source. - provider_
is_ openai_ completions - Whether a configured provider uses the OpenAI Chat Completions protocol.
- provider_
is_ openai_ responses - provider_
to_ models - Convert a
(provider_id, ProviderConfig)pair into a list of libraryModels. Provider-levelbase_url/headers/auth_headerfold into each model. ReturnsNonefor protocols that do not have a runtime provider. - read_
auth - Read the auth store. Missing file ⇒ empty store (not an error). Malformed
JSON ⇒
ConfigError::Json(we do not silently swallow a corrupt auth file). - read_
trust - Read
~/.rpi/agent/trust.json. Missing file ⇒ empty store (not an error). Malformed JSON ⇒ConfigError::Json.nulldecisions deserialize asNone; absent entries are simply not present. - resolve_
config_ value - Resolve a config value (API key, header value) that may be a shell command,
an env-var template, or a literal — mirroring pi’s
resolveConfigValue. - resolve_
config_ value_ uncached - Like
resolve_config_valuebut uncached — mirrors pi’sresolveConfigValueUncached, used when a fresh resolution is required (e.g. headers, which pi resolves uncached so a rotating token is re-read). - resolve_
headers - Resolve every header value via
resolve_config_value_uncached; drop entries that resolve toNone(mirrors piresolveHeaders). Used on models.jsonheadersmaps before folding onto a model. - set_
project_ trust - Persist the trust decision for a project directory. The path is canonical when it exists, with an absolute fallback for a project being created.
- settings_
path ~/.rpi/agent/settings.json(saved default provider/model/thinking + theme).- trust_
path ~/.rpi/agent/trust.json(per-cwd project trust decisions).- upsert_
credential - Read-modify-write: upsert a credential for
provider_id. - write_
auth - Atomically write the whole auth store (ensures the dir exists, writes a
temp sibling,
renames over the target, thenchmod 0o600on Unix).
Type Aliases§
- Auth
Store - The auth store:
providerId -> Credential. Mirrors upstreamRecord<providerId, Credential>. - Trust
Store - The trust store:
canonicalCwd -> decision(true/false/null). Mirrors pi’sTrustFile = Record<string, boolean | null | undefined>(trust-manager.ts). rpi reads this for layout parity (a copied pitrust.jsonparses + is located correctly) but does not gate any project resources behind trust in v1 — there is no trust prompt. Deferred.