Skip to content
Hoody.com

Query, read, list, export, and stream the agent’s redacted log set. Every route on this page is active-only, meaning a realm header returns 400 realm_scope_unsupported. Local sources live in an in-daemon ring (maximum page size 500); platform sources (activity, events, proxy) are queried separately and can be exported. Entries are always redacted before they leave the daemon.

Queries the active log stream. Filters ride query params; only the parameters declared below reach the daemon, and any other query key is discarded before the call. Paginate by sequence cursor, not by page. ?since and ?until are time bounds (RFC3339 or a relative 1h/30m/7d), NOT cursors; a bare number is rejected 400. ?limit=N caps the page: omitted it is 200, and any explicit value is clamped to the ring maximum of 500 (limit=0 also means 500). Source accepts one local source, or exactly one platform source (activity/events/proxy); mixing them is rejected.

NameInTypeRequiredDescription
sourcequerystringNoFilter to a log source/facet (see client.agent.logs.listSources()). One local source, or exactly one platform source (activity/events/proxy); mixing them is rejected.
levelquerystringNoFilter to a minimum log level.
hostquerystringNoFilter to a host.
sincequerystringNoLower time bound: RFC3339, or a relative duration like 1h/30m/7d. This is NOT a cursor; a bare sequence number is rejected 400 (use since_seq). Unparseable values are rejected the same way.
untilquerystringNoUpper time bound, same forms as since. Paging backwards by repeatedly lowering until works, but it is coarse (rows sharing a timestamp repeat); before_seq is the exact backwards cursor.
since_seqqueryintegerNoForward cursor: return only entries NEWER than this gateway seq. Take it from the previous reply’s latest_seq to poll incrementally without re-reading rows. A non-numeric value is rejected 400.
before_seqqueryintegerNoBackward cursor: return only entries OLDER than this seq. Take it from the seq of the oldest entry this page returned, not from oldest_seq (which is the oldest sequence still retained in the ring and is usually far older than the page you just read). Paging back from oldest_seq jumps past every entry in between and returns an empty page. A non-numeric value is rejected 400.
limitqueryintegerNoCaps this page. Omitted it is the daemon default 200; any explicit value is clamped to the ring maximum of 500, and limit=0 means 500 rather than 200. A non-numeric value is rejected 400.
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against.
session_idquerystringNoOnly entries correlated with this session id (exact match on the entry’s session_id).
run_idquerystringNoOnly entries correlated with this workflow/task run id (exact match on the entry’s run_id).
{
"entries": [
{
"seq": 1042,
"ts": "2026-01-15T10:32:18.123Z",
"level": "info",
"source": "daemon",
"host": "host-a",
"message": "tool completed",
"attrs": { "tool": "bash", "duration_ms": 42 }
},
{
"seq": 1043,
"ts": "2026-01-15T10:32:19.001Z",
"level": "warn",
"source": "daemon",
"host": "host-a",
"message": "retry",
"attrs": { "attempt": 2 }
}
],
"latest_seq": 1043,
"oldest_seq": 512
}
Terminal window
curl -X GET 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/logs?source=daemon&level=info&limit=100' \
-H 'Authorization: Bearer <token>'

Reads one log entry by ref. Entries are always redacted. The route is active-only; a realm header is rejected.

NameInTypeRequiredDescription
refpathstringYesThe ref.
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against.
{
"seq": 1042,
"ts": "2026-01-15T10:32:18.123Z",
"level": "info",
"source": "daemon",
"host": "host-a",
"message": "tool completed",
"attrs": { "tool": "bash", "duration_ms": 42 }
}
Terminal window
curl -X GET 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/logs/entries/llm:20261008_093015_482113' \
-H 'Authorization: Bearer <token>'

Lists the available log sources and facets. The route is active-only; a realm header is rejected.

NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against.
{
"sources": [
"daemon",
"session",
"tool",
"llm",
"activity",
"events",
"proxy"
]
}
Terminal window
curl -X GET 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/logs/sources' \
-H 'Authorization: Bearer <token>'

Returns log volume and level statistics. The route is active-only; a realm header is rejected.

NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against.
{
"total": 12453,
"by_level": {
"debug": 0,
"info": 10200,
"warn": 1900,
"error": 353
},
"by_source": {
"daemon": 5400,
"session": 2200,
"tool": 1800,
"llm": 1200,
"activity": 1100,
"events": 553,
"proxy": 200
}
}
Terminal window
curl -X GET 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/logs/stats' \
-H 'Authorization: Bearer <token>'

Streams the filtered, always-redacted log set as a download (Content-Disposition: attachment). The media type follows ?format: jsonl (the default, one wire row per line) is served as application/x-ndjson, and txt (human-readable) as text/plain; charset=utf-8. Local sources export a point-in-time-consistent snapshot of the in-daemon ring (bounded at the seq observed when the export starts); source=activity|events|proxy exports one platform query page (default limit 2000) and marks the export partial when more remained. The route is active-only; a realm header returns 400 realm_scope_unsupported.

NameInTypeRequiredDescription
sourcequerystringNoLog source to export (see client.agent.logs.listSources(); one local source, one platform source, or omitted for all local sources).
min_levelquerystringNoMinimum log level (debug/info/warn/error).
compquerystringNoComponent filter (daemon source).
session_idquerystringNoSession id filter.
textquerystringNoCase-insensitive substring filter over message+attrs.
sincequerystringNoLower time bound (RFC3339 or relative like 1h/7d).
untilquerystringNoUpper time bound (RFC3339 or relative).
eventquerystringNoSession lifecycle event filter (session source).
toolquerystringNoTool name filter (tool source).
modelquerystringNoModel filter (llm source).
statusquerystringNoTool outcome filter: ok/error/cancelled (tool source).
methodquerystringNoHTTP method filter (activity source).
min_statusqueryintegerNoMinimum HTTP status (activity source).
max_statusqueryintegerNoMaximum HTTP status (activity source).
errors_onlyquerybooleanNoOnly error rows (activity source; true/false).
event_typequerystringNoEvent type filter (events source).
resource_typequerystringNoResource type filter (events source).
containerquerystringNoContainer filter (proxy source; empty = all running realm containers). Maps to the daemon’s container_id filter.
kindquerystringNoProxy row kind: request/response/event (proxy source).
hostquerystringNoProxy URL host filter (exact or dot-aligned suffix).
since_seqqueryintegerNoExclusive lower seq bound for incremental exports (local sources).
limitqueryintegerNoTotal row cap across the export (default: everything the snapshot matches; platform default 2000).
formatquerystringNoExport format: jsonl (default) or txt.
filenamequerystringNoDownload filename override (reduced to a safe basename).
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against.

The export body, served as application/x-ndjson for the default jsonl form or text/plain; charset=utf-8 for ?format=txt. The default form below shows two redacted log rows followed by the in-band terminator:

{"seq":1042,"ts":"2026-01-15T10:32:18.123Z","level":"info","source":"daemon","host":"host-a","message":"tool completed","attrs":{"tool":"bash","duration_ms":42}}
{"seq":1043,"ts":"2026-01-15T10:32:19.001Z","level":"warn","source":"daemon","host":"host-a","message":"retry","attrs":{"attempt":2}}
{"_hoody_export":{"rows":2,"gap":0,"partial":false,"complete":true}}
Terminal window
curl -X GET 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/logs/export?source=daemon&format=jsonl&since=1h' \
-H 'Authorization: Bearer <token>' \
-o logs.jsonl

Tails the active log stream over Server-Sent Events. Pagination advances each round (since_seq is set to the previous reply’s next_seq), so no row is skipped under load. The tail uses the same seq/replay convention as the session stream: an entry event per redacted row carrying id: <seq> (so a reconnecting client resumes via the Last-Event-ID header, which overrides ?since_seq), a lagged event with code:replay_gap when the caller’s cursor fell behind the ring, periodic heartbeats, and end on disconnect. Filters ride query params (source, level, host, since_seq, …); ?limit caps each poll batch. Local sources only. The route is active-only; a realm header returns 400 realm_scope_unsupported. Entries are always redacted.

NameInTypeRequiredDescription
sourcequerystringNoFilter the tail to a log source/facet.
levelquerystringNoFilter to a minimum log level.
hostquerystringNoFilter to a host.
since_seqqueryintegerNoInitial resume cursor (the Last-Event-ID header overrides it). A non-numeric value is rejected 400.
limitqueryintegerNoCaps each poll batch. A non-numeric value is rejected 400.
Last-Event-IDheaderstringNoSSE resume cursor: the gateway int64 seq to resume from. OVERRIDES the ?since_seq query param. Sent automatically by an SSE client on reconnect.
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against.
session_idquerystringNoOnly entries correlated with this session id.
run_idquerystringNoOnly entries correlated with this workflow/task run id.

SSE stream of the redacted log tail. The body is a text/event-stream feed: event: entry with an id: line carrying the row seq, periodic heartbeats (lines beginning with :), a lagged event when the caller’s cursor falls behind the ring, and an end event on disconnect.

event: entry
id: 1042
data: {"seq":1042,"ts":"2026-01-15T10:32:18.123Z","level":"info","source":"daemon","host":"host-a","message":"tool started","attrs":{"tool":"bash"}}
: heartbeat
event: entry
id: 1043
data: {"seq":1043,"ts":"2026-01-15T10:32:19.250Z","level":"info","source":"daemon","host":"host-a","message":"tool completed","attrs":{"tool":"bash","duration_ms":248}}
event: end
data: {}
Terminal window
curl -X GET 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/logs/stream?source=daemon&since_seq=1042' \
-H 'Authorization: Bearer <token>' \
-H 'Accept: text/event-stream'