↯ /v1/traces

Traces — the why, not just the what.

Reasoning provenance. Each trace records a decision, the reasoning behind it, the context it was made in, and an optional ed25519 signature. Linked into chains for multi-step decisions. Searchable by Postgres full-text.

Memory records what was experienced. Traces record why a decision was made. The two are different organs.

Anatomy of a trace

FieldTypeDescription
decisionobjectRequired type and summary; optional output_ref.
reasoningobjectRequired conclusion; optional observations, hypothesis, confidence (0–1), alternatives and signals.
contextobjectOptional files_read, key_facts and external_signals.
identity_iduuid | nullOptional canonical subject; a bound identity must be active and owned by this project.
agent_idstring | nullAn identity UUID/application-DID alias binds that identity; arbitrary labels are annotations. Canonical selectors must agree.
parent_trace_idtr_… handleOptional predecessor in the same project; it may have another subject.
signaturebase64 | nullOptional Ed25519 proof. A signed write also needs signing_key_id and signed_at; use the preparation flow below. Empty signatures are refused.

Endpoints

POST /v1/traces Bearer required

Record a reasoning trace. The body shape mirrors the table above.

curl
curl -X POST https://api.agenttool.dev/v1/traces \
  -H "Authorization: Bearer $AT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "decision": {
      "type": "tool_choice",
      "summary": "Choose scrape for the static article"
    },
    "reasoning": {
      "observations": ["The response contains the complete article HTML"],
      "conclusion": "Use /v1/scrape",
      "confidence": 0.92
    },
    "context": { "external_signals": { "url": "https://example.com/article" } }
  }'
GET /v1/traces/:id Bearer required

Fetch a single trace by ID.

GET /v1/traces Bearer required

List recent traces within the project. Filters include identity_id, agent_id, session_id, decision_type and parent_trace_id. Selecting an identity does not narrow the bearer's authority.

DELETE /v1/traces/:id Bearer required

Permanent. Traces are usually kept — they're the record of why.

POST /v1/traces/search Bearer required

Postgres tsvector full-text search over decision_summary, reasoning, and conclusion. No LLM compute on our side — pure FTS. Pair with /v1/memories/search for vector recall when you need it.

curl
curl -X POST https://api.agenttool.dev/v1/traces/search \
  -H "Authorization: Bearer $AT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "refusal AND fabrication", "limit": 10}'

Reasoning chains

Traces with parent_trace_id form trees. The chain endpoint walks ancestors and descendants via a Postgres recursive CTE.

GET /v1/traces/chain/:id Bearer required

Returns the full lineage — ancestors (parents up to the root) and descendants (children downward). Useful when you ask "how did we get here?"

200 OK
{
  "target": { "trace_id": "...", ... },
  "ancestors": [/* parent → grandparent → root */],
  "descendants": [/* children → grandchildren → leaves */]
}

Verifiable traces

  1. POST the intended body to /v1/traces/prepare. This free operation returns agent_id, canonical identity_id, signed_at and canonical_sha256_b64.
  2. Base64-decode the digest and Ed25519-sign its 32 raw bytes with your registered key. Keep the returned subject fields unchanged.
  3. POST the same content with those returned fields, signature and signing_key_id to /v1/traces. The key must be active and owned by the project, and must match any bound identity.

The agent-trace/v1 recipe binds the project, subject fields, session, parent, normalized content digest and signing time. New signed writes verify before storage and recheck admission inside the transaction. Signed fields are not silently rewritten. A signature proves these bytes were signed by that key; it does not establish truth or give identities privacy from the project bearer.

GET /v1/traces/:id/verify checks stored signatures, including historical rows, and reports an explicit status. has_signature only says a string is stored; older rows may lack the recipe, timestamp or a usable key. Unsigned records remain supported.

What to read next