Configuration
OpenLimiter keeps everything in one state directory under your own user account: a configuration file, a cache, a lock, and the optional manual document. This page says where that is and what each file does.
The state directory
| platform | path |
|---|---|
| Windows | %LOCALAPPDATA%\openlimiter |
| macOS | ~/Library/Application Support/openlimiter |
| Linux | ${XDG_STATE_HOME:-~/.local/state}/openlimiter |
The directory is created with restrictive permissions where the platform supports them. A path that turns out to be a symbolic link is rejected rather than followed.
What lives in it
| file | role |
|---|---|
openlimiter-config.json | Written by openlimiter init. Records the connector list and whether each one was detected. |
openlimiter-cache.json | The one cache every command reads and every writer merges into. |
openlimiter.lock | Held by writers only. Readers never take it. |
manual.json | Optional. Quota you maintain by hand. See ingestion for the shape. |
How the cache behaves
- One schema, one file, one lock. There are no competing state files to reconcile.
- Readers never take the lock. A reader opens the file, validates that open descriptor, and reads through it, so a path swapped after the check cannot redirect the bytes.
- Writers take the lock, and the read, the merge, and the write all happen inside it. A lock older than five seconds is treated as abandoned and reclaimed.
- Every replacement flushes to stable storage before the rename, so a reader observes either the previous content or the new content and never a partial file.
Cache health is visible at any time through openlimiter doctor, which prints the cache status and how many rows were dropped for failing validation.
Claude Code settings
Use the absolute path to your clone. Forward slashes work on every platform, including Windows.
{
"statusLine": {
"type": "command",
"command": "node /absolute/path/to/openlimiter/packages/cli/dist/bin.js statusline"
},
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node /absolute/path/to/openlimiter/packages/cli/dist/bin.js hook"
}
]
}
]
}
}Which of the two writes
Only the statusline. It is the path that receives the session payload, so it is the path that updates the cache. The hook reads and never writes.
Credentials
The credential library call sits behind an interface, and the adapter is stubbed in this release, so openlimiter init cannot store a key until a driver is supplied. Nothing else on your machine is touched.
Connector detection
Detection is a pure function of the environment the CLI hands a connector. Facts only the CLI can observe, such as a manual document sitting in the state directory, arrive as explicit markers, which is why openlimiter doctor never claims a connector is ready when it could not receive data.
openlimiter doctor
CONNECTOR DETECTED FRESHNESS DRIFT
claude no unknown UNVERIFIED
openrouter no unknown UNVERIFIED
codex no unknown UNVERIFIED
antigravity no unknown UNVERIFIED
opencode no unknown UNVERIFIED
manual yes fresh UNVERIFIED
CACHE ok DROPPED 0