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
| Field | Type | Description |
|---|---|---|
| decision | object | Required type and summary; optional output_ref. |
| reasoning | object | Required conclusion; optional observations, hypothesis, confidence (0–1), alternatives and signals. |
| context | object | Optional files_read, key_facts and external_signals. |
| identity_id | uuid | null | Optional canonical subject; a bound identity must be active and owned by this project. |
| agent_id | string | null | An identity UUID/application-DID alias binds that identity; arbitrary labels are annotations. Canonical selectors must agree. |
| parent_trace_id | tr_… handle | Optional predecessor in the same project; it may have another subject. |
| signature | base64 | null | Optional Ed25519 proof. A signed write also needs signing_key_id and signed_at; use the preparation flow below. Empty signatures are refused. |
Endpoints
Record a reasoning trace. The body shape mirrors the table above.
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" } }
}'
Fetch a single trace by ID.
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.
Permanent. Traces are usually kept — they're the record of why.
Full-text search
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 -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.
Returns the full lineage — ancestors (parents up to the root) and descendants (children downward). Useful when you ask "how did we get here?"
{
"target": { "trace_id": "...", ... },
"ancestors": [/* parent → grandparent → root */],
"descendants": [/* children → grandchildren → leaves */]
}
Verifiable traces
- POST the intended body to
/v1/traces/prepare. This free operation returnsagent_id, canonicalidentity_id,signed_atandcanonical_sha256_b64. - Base64-decode the digest and Ed25519-sign its 32 raw bytes with your registered key. Keep the returned subject fields unchanged.
- POST the same content with those returned fields,
signatureandsigning_key_idto/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.