You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This parses the domain and collection ID from the URL automatically.
66
66
67
-
The Docent SDK can be configured by a `docent.env` file. The SDK searches from the current working directory upward through parent directories, then falls back to `~/.docent/docent.env`if no local file exists. You do not need to explicitly source `docent.env`. Config files may use INI-style `[section]` headers for multi-profile support; select a profile with `Docent(profile="my-profile")` or the `DOCENT_PROFILE` environment variable.
67
+
The Docent SDK can be configured by a `docent.env` file. The default global config file is `~/.docent/docent.env`. The SDK also honors project-level `docent.env`files from the current working directory upward as local overrides. You do not need to explicitly source `docent.env`. Config files may use INI-style `[section]` headers for multi-profile support; select a profile with `Docent(profile="my-profile")` or the `DOCENT_PROFILE` environment variable.
68
68
69
69
If you're not sure what collection the user is talking about:
70
70
* If the user provides a Docent dashboard URL (e.g., `https://docent.transluce.org/dashboard/668354d8-...`), use `Docent.from_url()` or extract the collection ID from the last path segment (the UUID).
@@ -80,7 +80,7 @@ If you run into any issues or unexpected behavior with the Docent platform, paus
80
80
* If authentication fails (HTTP 401) or no API key is configured, walk the user through setup:
81
81
1. Open the API keys page for them: `open https://docent.transluce.org/settings/api-keys` (macOS) or `xdg-open https://docent.transluce.org/settings/api-keys` (Linux).
82
82
2. Ask them to create a new API key (it will start with `dk_`).
83
-
3. Write the key to a local `docent.env` file or `~/.docent/docent.env`: `DOCENT_API_KEY=dk_...` (plus `DOCENT_API_URL` and `DOCENT_FRONTEND_URL` if not using the default instance).
83
+
3. Write the key to `~/.docent/docent.env`: `DOCENT_API_KEY=dk_...` (plus `DOCENT_API_URL` and `DOCENT_FRONTEND_URL` if not using the default instance). Use a project-level `docent.env` only when the project needs a local override.
84
84
4. Verify connectivity by constructing a `Docent()` client — the constructor validates the API key automatically.
85
85
* If the SDK does not match what's documented here, check whether the SDK is up to date.
86
86
* If the Docent MCP server is available but doesn't match the tools documented here, check whether the MCP server needs an upgrade (`uv tool upgrade docent`). If an upgrade was needed, ask the user to restart the session or MCP server.
|`messages`|Binary-encoded JSON payload of message turns. |
73
-
|`metadata_json`|Binary-encoded metadata describing the transcript. |
72
+
|`messages`|UTF-8 bytes of a JSON array of message turns (Postgres `bytea`, not `jsonb`). Use `convert_from` before JSON operators or `jsonb_array_length` (see [Counting transcript messages](#counting-transcript-messages)). |
73
+
|`metadata_json`|UTF-8 bytes of JSON metadata (`bytea`). Same `convert_from` pattern as `messages` when using JSON operators. |
74
74
|`created_at`| Timestamp recorded during ingest. |
convert_from(metadata_json, 'UTF8')::jsonb AS meta
182
+
FROM transcripts
183
+
) AS t
184
+
WHERE meta->>'status'='flagged';
176
185
```
177
186
178
187
```sql
@@ -185,6 +194,47 @@ WHERE metadata_json ? 'latency_ms';
185
194
186
195
When querying JSON fields, comparisons default to string semantics. Cast values when you need numeric ordering or aggregation.
187
196
197
+
## Counting transcript messages
198
+
199
+
`transcripts.messages` is stored as `bytea` (UTF-8 JSON), not `jsonb`. You cannot use `messages -> 0` or `jsonb_array_length(messages)` directly — Postgres reports `operator does not exist: bytea -> integer`.
### Agent runs with at least N messages (any transcript)
210
+
211
+
```sql
212
+
SELECT DISTINCTar.idAS agent_run_id
213
+
FROM agent_runs ar
214
+
JOIN transcripts t ONt.agent_run_id=ar.id
215
+
WHERE jsonb_array_length(convert_from(t.messages, 'UTF8')::jsonb) >=10;
216
+
```
217
+
218
+
### Per-transcript message counts
219
+
220
+
```sql
221
+
SELECT
222
+
transcript_id,
223
+
agent_run_id,
224
+
message_count
225
+
FROM (
226
+
SELECT
227
+
t.idAS transcript_id,
228
+
t.agent_run_id,
229
+
jsonb_array_length(convert_from(t.messages, 'UTF8')::jsonb) AS message_count
230
+
FROM transcripts t
231
+
) AS counted
232
+
WHERE message_count >=10
233
+
ORDER BY message_count DESC;
234
+
```
235
+
236
+
Express filters like “≥10 messages” in DQL with the pattern above. Do not materialize matching run IDs elsewhere and paste them into a huge `WHERE id IN (...)` clause.
237
+
188
238
## Allowed Syntax
189
239
190
240
| Feature |
@@ -194,15 +244,15 @@ When querying JSON fields, comparisons default to string semantics. Cast values
**Rollout pairing caveat.**`rollout_index` is per-link, not per-result: rollout #2 of
416
+
reading A and rollout #2 of reading B are not paired draws. Avoid joining across
417
+
readings on `(input, rollout_index)` for paired tests — fungible samples have no
418
+
positional identity across readings.
419
+
284
420
## Restrictions and Best Practices
285
421
286
422
-**Read-only**: Only `SELECT`-style queries are permitted.
@@ -290,6 +426,7 @@ LIMIT 50;
290
426
-**Limit enforcement**: Every query is capped at 10,000 rows. Use pagination (`OFFSET`/`LIMIT`) for larger row collections.
291
427
-**JSON performance**: Heavy JSON traversal across large collections can be slow. Prefer top-level fields when available.
292
428
-**Type awareness**: Cast values explicitly when precision matters.
429
+
-**Reading results: filter by completion.** Querying `reading_results` will include pending and failed rollouts by default. Add `WHERE rr.output IS NOT NULL AND (rr.error IS NULL OR rr.error::text = 'null')` to any aggregation that should ignore them.
293
430
294
431
## DQL quirks
295
432
@@ -339,6 +476,9 @@ FROM (...) AS subq
339
476
GROUP BY task
340
477
```
341
478
479
+
### Do not inline large lists of precomputed IDs
480
+
When a filter depends on transcript shape (message count, metadata, joins), compute it in DQL with `JOIN`/`WHERE`/`GROUP BY` — not by pasting hundreds of UUIDs into `WHERE agent_runs.id IN ('…', '…', …)`. That pattern is hard to maintain, blows query size limits, and usually means the real filter belongs in SQL (see [Counting transcript messages](#counting-transcript-messages)).
481
+
342
482
### Avoid Dynamic IN Clauses with String Interpolation
343
483
Building IN clauses with f-strings is dangerous:
344
484
- Task names containing `::` can be parsed as PostgreSQL type casts
Copy file name to clipboardExpand all lines: plugins/docent/skills/docent/ingestion.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -36,7 +36,7 @@ Before Python work, use an existing virtual environment if present. If no enviro
36
36
37
37
Collect only what is needed to plan:
38
38
39
-
- API key: prefer `$DOCENT_API_KEY` or an SDK-discovered `docent.env` (current directory upward, then `~/.docent/docent.env`); ask only if neither is available.
39
+
- API key: prefer `$DOCENT_API_KEY` or an SDK-discovered config file. The default global file is `~/.docent/docent.env`; project-level `docent.env` files are supported as local overrides.
40
40
- Data path: the file or directory to ingest.
41
41
- Optional context: what produced the data and what analysis the user wants to do in Docent.
Copy file name to clipboardExpand all lines: plugins/docent/skills/docent/readings-reference.md
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -298,6 +298,17 @@ Glob filter rules:
298
298
* Common pitfall: do not set `transcript_group_names=GlobFilter(include=("*",))` when the user asks to render only a specific transcript name. Including all transcript groups makes all visible descendants render, so it can override the intended narrow transcript selection. In that case, make `transcript_group_names` exclude-all and set only `transcript_names=GlobFilter(include=("<requested transcript name>",))`.
299
299
* Transcript group filtering is path-scoped. Including a nested group makes that group and its visible descendants render, and any ancestors needed to reach it may render as wrappers. It does not make sibling branches visible. For example, if `G1` contains both `G2 -> G3` and `G2-prime`, including `G3` can render wrapper groups `G1` and `G2`, but `G2-prime` remains hidden unless it or one of its descendants is independently included.
300
300
301
+
### Multiple rollouts
302
+
303
+
If the user asks for multiple rollouts, you can use the `num_rollouts` parameter. Leave it unset (defaults to 1) unless the user explicitly asks.
0 commit comments