Authentication¶
methodic authenticates to Chronicle using a Bearer token in Authorization: Bearer. The Chronicle constructor takes the token as api_key regardless of its actual format — the server's middleware figures out which kind it is.
Configuring the client¶
You can pass server_url + api_key to the constructor directly, but most
code — including every Chronicle skill — uses Chronicle.from_env(), which
resolves credentials from the ambient environment so you never hard-code a key.
from_env() resolves each setting from the first source that provides it,
highest precedence first:
- Explicit keyword arguments —
Chronicle.from_env(api_key="sk_..."). - Environment variables (below).
- YAML files under
~/.methodic/—config.yamlthencredentials.yaml(or a single file via$CHRONICLE_CONFIG). - Built-in defaults —
server_urlfalls back tohttps://api.methodiclabs.ai.
api_key has no default; if no source provides one, from_env() raises
ChronicleConfigError before any network call.
Environment variables¶
| Variable | Required | Default | Meaning |
|---|---|---|---|
CHRONICLE_API_KEY |
yes | — | Bearer token (sk_user_…, sk_agent_…, sk_worker_…, or an Auth0 JWT) |
CHRONICLE_SERVER_URL |
no | https://api.methodiclabs.ai |
Base URL of the Chronicle server |
CHRONICLE_TIMEOUT |
no | 30 |
Per-request timeout, seconds |
CHRONICLE_MAX_UPLOAD_WORKERS |
no | 2 |
Threads for async asset uploads |
CHRONICLE_ORGANIZATION_ID |
no | — | Default organization for calls that take an organization_id (resolve yours via chronicle.me.scopes()); pass methodic.PERSONAL on a call to override back to personal scope |
CHRONICLE_ORGANIZATION_SLUG |
no | — | The same default-organization setting named by slug instead of id — resolved to the id via /v1/me/scopes on first use. Set this or CHRONICLE_ORGANIZATION_ID, not both |
CHRONICLE_CONFIG |
no | ~/.methodic/config.yaml + credentials.yaml |
Path to a single YAML config file (overrides the ~/.methodic/ files) |
Chronicle-managed menlo_park workers receive CHRONICLE_SERVER_URL and
CHRONICLE_API_KEY automatically — the daemon injects them into the container,
so Chronicle.from_env() just works inside a run.
Config files¶
For interactive use, keep your settings under ~/.methodic/ instead of
exporting variables. The secret is split into its own file so it can be
permissioned and rotated separately:
~/.methodic/config.yaml — non-secret settings:
server_url: https://api.methodiclabs.ai
timeout: 30 # optional
max_upload_workers: 2 # optional
organization_id: 1111… # optional — default org for org-scoped calls
# (experiments/datasets create under this org unless
# the call passes organization_id, or methodic.PERSONAL
# to force personal scope)
organization_slug: acme # …or name the same default org by slug instead of id
# (resolved to the id via /v1/me/scopes on first use).
# Set one of organization_id / organization_slug, not both.
~/.methodic/credentials.yaml — the API key, on its own:
Both files are optional and may hold any subset of settings (a single
credentials.yaml with just api_key is enough). credentials.yaml wins
over config.yaml on any overlap, environment variables win over both, and
explicit keyword arguments win over everything. To load explicit files and
ignore the environment entirely, use the same split:
Either argument is optional (a combined file can be passed as config). To
point from_env() at a single combined file instead, set CHRONICLE_CONFIG.
Logging in from the terminal¶
methodic auth login writes the ~/.methodic files for you instead of
hand-editing them:
$ methodic auth login
Credential (API key or JWT, input hidden):
Organizations you belong to:
1. acme — Acme Research
Default organization (number or slug; Enter to keep current): 1
Logged in as Jane Doe (https://api.methodiclabs.ai).
Wrote ~/.methodic/credentials.yaml (chmod 600).
Default organization: 2f1c… (recorded in ~/.methodic/config.yaml).
The stored credential can be an sk_... API key or an Auth0 JWT — the
server routes by prefix, so a JWT lets an agent bootstrap and then mint its
own appropriately-restricted keys via chronicle.api_keys. It verifies the
credential live (--no-verify to skip), resolves --organization <id-or-slug>
against your memberships, clears the default with --personal, and persists
--server-url for self-hosted servers. config.yaml is merge-written
(hand-added settings survive a re-login); credentials.yaml is overwritten
(re-running login is key rotation). methodic auth status prints what the
SDK would resolve, with the key masked.
Keep keys out of version control
credentials.yaml holds a live credential. Keep it under ~/.methodic/
(consider chmod 600), never in a checked-in working tree.
Token formats¶
| Format | Holder | Lifetime |
|---|---|---|
| Auth0 access token (RS256 JWT) | Interactive researcher / web UI | Auth0 session lifetime |
sk_user_... |
Researcher API key, minted via POST /api-keys with an Auth0 token |
Configurable, default 90 days |
sk_agent_... |
An agent or developer | Configurable, default 90 days |
sk_worker_... |
A worker on a provisioned instance; minted by Chronicle during provisioning | Tied to the run |
Provisioning paths¶
Chronicle-managed runners (menlo-park)¶
The agent calls POST /experiments/{id}/variations/{n}/runs/{r}/provision. Chronicle spins up the instance, mints a sk_worker_ key scoped to that run, and injects it as CHRONICLE_API_KEY:
import os
from methodic import Chronicle
chronicle = Chronicle(
server_url=os.environ["CHRONICLE_SERVER_URL"],
api_key=os.environ["CHRONICLE_API_KEY"],
)
run = chronicle.run(
os.environ["CHRONICLE_EXPERIMENT_ID"],
int(os.environ["CHRONICLE_VARIATION"]),
int(os.environ["CHRONICLE_RUN"]),
)
Self-managed runners¶
The agent mints a long-lived sk_agent_ key once, then your runner uses it for any number of runs:
curl -X POST https://chronicle.example.com/api-keys \
-H "Authorization: Bearer $AUTH0_TOKEN" \
-d '{"description": "my custom runner", "scopes": [...]}'
The response includes the full key — Chronicle only ever returns it once. Store it somewhere safe (a secret manager).
Researcher (interactive)¶
Hand-paste an Auth0 access token from the web UI dev tools, or grab one programmatically via Auth0's password grant (CI accounts). Same constructor:
Revocation¶
API keys are revocable immediately via DELETE /api-keys/{id}. Chronicle's auth middleware uses an LRU cache for performance but reflects revocations within seconds. If methodic starts getting AuthenticationError (401), the key is no longer valid — there is no automatic refresh.