Core configuration API
Auth, config, and identity endpoints.
Auth
GET /api/auth/whoami
Returns the identity and claims of the current request’s token. In local
mode, authenticated is always false and claims is null.
Response
{
"authenticated": true,
"claims": {
"sub": "token:operator",
"role": "operator",
"scope": { "project": "my-project" },
"iat": 1740000000,
"exp": 1740086400
},
"mode": "team"
}
POST /api/auth/token
Create a signed JWT. Requires admin permission. Rate-limited to 10
requests/min.
Request body
{
"role": "agent",
"scope": { "project": "my-project", "agent": "claude", "user": "nicholai" },
"ttlSeconds": 86400
}
role is required and must be one of admin, operator, agent,
readonly. scope is optional — an empty object creates an unscoped token.
ttlSeconds defaults to the value in authConfig.defaultTokenTtlSeconds.
Response
{
"token": "<jwt>",
"expiresAt": "2026-02-22T10:00:00.000Z"
}
Returns 400 if role is invalid or auth secret is unavailable (local
mode). Returns 400 if the request body is missing or malformed.
GET /api/auth/api-keys
List named daemon API keys. Requires admin permission. The response never
includes raw sig_sk_... key values; raw keys are only returned once at
creation time.
Response
{
"apiKeys": [
{
"id": "key_abc123",
"prefix": "1b363ad385e1",
"name": "work laptop pi",
"role": "agent",
"scope": { "agent": "pi-work-laptop" },
"permissions": ["recall", "remember", "documents"],
"connector": "pi",
"harness": "pi",
"agentId": "pi-work-laptop",
"allowedProjects": [],
"createdAt": "2026-06-11T04:02:17.922Z",
"lastUsedAt": null,
"revokedAt": null,
"expiresAt": null
}
]
}
POST /api/auth/api-keys
Create a named API key for remote connectors or other daemon clients. Requires
admin permission. The raw key is returned once in this response and is
stored hashed at rest.
Request body
{
"name": "work laptop pi",
"connector": "pi",
"role": "agent",
"agentId": "pi-work-laptop",
"scope": { "agent": "pi-work-laptop" },
"allowedProjects": [],
"expiresAt": null
}
name is required. role defaults to agent and must be one of admin,
operator, agent, or readonly when provided. connector, harness,
agentId, allowedProjects, scope, permissions, and expiresAt are
optional. agentId is connector metadata; API callers should also set
scope: { "agent": "..." } when scope-guarded API surfaces should be limited
to that agent. For connector keys, scope.agent should usually match
agentId. The Signet CLI does this automatically when you run
signet api-key create --agent-id <id>. Connector keys default to the
connector permission set: recall, remember, and documents.
Response
{
"apiKey": {
"id": "key_abc123",
"prefix": "1b363ad385e1",
"name": "work laptop pi",
"role": "agent",
"scope": { "agent": "pi-work-laptop" },
"permissions": ["recall", "remember", "documents"],
"connector": "pi",
"harness": "pi",
"agentId": "pi-work-laptop",
"allowedProjects": [],
"createdAt": "2026-06-11T04:02:17.922Z",
"lastUsedAt": null,
"revokedAt": null,
"expiresAt": null,
"key": "sig_sk_..."
}
}
Returns 400 if the request body is missing or malformed, name is empty,
role is invalid, or expiresAt is not a valid ISO timestamp.
DELETE /api/auth/api-keys/:id
Revoke an API key by id or prefix. Requires admin permission. Revocation is
idempotent for an existing key: already-revoked keys are returned with their
original revokedAt timestamp.
Response
{
"apiKey": {
"id": "key_abc123",
"prefix": "1b363ad385e1",
"name": "work laptop pi",
"role": "agent",
"scope": { "agent": "pi-work-laptop" },
"permissions": ["recall", "remember", "documents"],
"connector": "pi",
"harness": "pi",
"agentId": "pi-work-laptop",
"allowedProjects": [],
"createdAt": "2026-06-11T04:02:17.922Z",
"lastUsedAt": null,
"revokedAt": "2026-06-11T05:00:00.000Z",
"expiresAt": null
}
}
Returns 404 if the id or prefix does not match an API key.
Config
GET /api/config
Returns all .md and .yaml files from the agents directory ($SIGNET_WORKSPACE/),
sorted by priority: agent.yaml, AGENTS.md, SOUL.md, IDENTITY.md,
USER.md, then alphabetically.
Response
{
"files": [
{ "name": "agent.yaml", "content": "...", "size": 1024 },
{ "name": "AGENTS.md", "content": "...", "size": 4096 }
]
}
POST /api/config
Write a config file. File name must end in .md or .yaml and must not
contain path separators.
Request body
{
"file": "SOUL.md",
"content": "# Soul\n..."
}
Response
{
"success": true,
"auditError": "<error string when audit write fails, absent otherwise>",
"providerTransitions": [
{
"role": "extraction",
"from": "ollama",
"to": "anthropic",
"timestamp": "2026-04-12T00:00:00.000Z",
"source": "api/config:agent.yaml",
"risky": true
}
]
}
auditError is present when the config was saved successfully but the
provider-transition audit file could not be written. The config is correct but
rollback via the audit trail will not be available for the transition.
success: true can coexist with a non-empty auditError.
commentsStripped: true is present when the allowRemoteProviders: false lock
was active and the submitted config omitted the flag with only local providers
selected. The lock is re-injected into the YAML, which strips YAML comments as a
side effect of the parse→stringify round-trip. Callers should warn users that
hand-written comments in the config file may be lost when this field is present.
Returns 400 for invalid file names, path traversal attempts, or wrong file
types. YAML saves also return 400 when
memory.pipelineV2.allowRemoteProviders: false and the submitted config
selects a paid or remote extraction/synthesis provider.
Returns 403 when saving a guarded config file (agent.yaml, AGENT.yaml,
config.yaml) without admin permission in team or hybrid auth mode.
GET /api/config/provider-safety
Returns the currently configured provider-safety snapshot plus recent provider transitions recorded from config saves and rollbacks.
Response
{
"snapshot": {
"extractionProvider": "ollama",
"synthesisProvider": "ollama",
"allowRemoteProviders": true
},
"snapshotError": "Invalid YAML config",
"transitions": [],
"latestRiskyTransition": null
}
snapshotError is present when the config YAML could not be parsed; snapshot will be null in that case.
POST /api/config/provider-safety/rollback
Roll back the latest recorded provider transition with a previous provider.
Pass role: "extraction" or role: "synthesis" to restrict the rollback;
omit it to roll back the most recent provider transition of either role.
Each transition can only be rolled back once — consumed entries are marked
rolledBack: true and skipped by subsequent calls.
Note: This endpoint round-trips
agent.yamlthrough a YAML parser and serializer, which strips comments. Any hand-written comments in the file will be lost. Edit the file directly if comment preservation matters.
Request body
{ "role": "extraction" }
Response
{
"success": true,
"file": "agent.yaml",
"rolledBack": {
"role": "extraction",
"from": "ollama",
"to": "anthropic",
"timestamp": "2026-04-12T00:00:00.000Z",
"source": "api/config:agent.yaml",
"risky": true,
"rolledBack": true
},
"providerTransitions": [
{
"role": "extraction",
"from": "anthropic",
"to": "ollama",
"timestamp": "2026-04-12T00:01:00.000Z",
"source": "api/config/provider-safety/rollback",
"risky": false
}
],
"isRetry": false
}
isRetry is true when no provider transition was detected during the
rollback. This covers two cases: (1) the transition was already rolled back
in a prior request (audit write failed after config was written, so the
config is re-serialized and comments stripped again), or (2) the current
config already has the target provider (e.g. manually restored) but stale
model/endpoint fields were cleared. In both cases providerTransitions
is empty.
Returns 400 if role is present but not extraction or synthesis, if
the rolled-back config would violate allowRemoteProviders, or if the rollback
would produce no content change (e.g. synthesis rollback on a config with no
synthesis block — the audit entry is not consumed).
Returns 404 if no un-rolled-back transition exists, or if the source config
file referenced by the transition has been deleted or renamed.
The audit log retains the most recent 100 transitions. Older entries are
dropped with a logged warning — a rollback targeting a truncated entry
returns 404.
Identity
GET /api/identity
Parses IDENTITY.md and returns the structured fields.
Response
{
"name": "Aria",
"creature": "fox",
"vibe": "calm and curious"
}
Returns defaults ({ "name": "Unknown", "creature": "", "vibe": "" }) if the
file is missing or unreadable.