feat(claw-server): searchable audit via a task summary - #2451
Conversation
Record an agent-declared, PII-scrubbed one-or-two-line task summary on name_session, persist it on the tasks row, and index it in a SQLite FTS5 table so the audit search bar finds sessions by what the task was about. - name_session gains an optional `summary` argument (last write wins), scrubbed server-side for structural PII (emails, URLs, file paths, bare domains, long digit runs) before it is stored or indexed. The summary is kept in local SQLite only and never sent to analytics. - Add tasks.task_summary plus an FTS5 task_search index, written in one transaction and excluded from the task recompute upsert so an out-of-band summary survives event replay; purge both on retention. - Extend the existing sessions search to also match summary content via the FTS5 index alongside the current title/agent/site match. - Surface the summary on the SessionSummary contract and render a two-line snippet under the target in the audit table.
Greptile SummaryThe PR adds locally stored, scrubbed task summaries and makes them available through audit search and session results.
Confidence Score: 3/5The PR is not yet safe to merge because malformed name_session summary values can still place unsanitized sensitive text in the audit timeline. The previous string-summary leak is fixed, but a non-string summary skips the scrubber and is serialized unchanged into persisted dispatch arguments. Files Needing Attention: packages/browseros-agent/apps/claw-server-rust/src/api/mcp/service.rs
|
| Filename | Overview |
|---|---|
| packages/browseros-agent/apps/claw-server-rust/src/api/mcp/service.rs | Adds summary capture and fixes the prior raw-string leak, but non-string summary values still bypass sanitization before audit persistence. |
| packages/browseros-agent/apps/claw-server-rust/src/db/audit_log.rs | Adds transactional summary/index writes, FTS-backed filtering, recompute preservation, and retention cleanup. |
| packages/browseros-agent/apps/claw-server-rust/src/db/migration.rs | Adds the nullable canonical summary column and standalone FTS5 index. |
| packages/browseros-agent/apps/claw-server-rust/src/api/http/sessions.rs | Projects stored summaries into both historical and live session API responses. |
| packages/browseros-agent/contracts/claw-api/schemas/sessions.yaml | Adds the optional taskSummary field consistently with generated Rust and TypeScript models. |
| packages/browseros-agent/apps/claw-app/screens/audit/audit.columns.tsx | Renders an optional two-line task-summary snippet beneath the task name. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A["name_session arguments"] --> B{"summary is string?"}
B -->|Yes| C["scrub_summary"]
C --> D["tasks.task_summary"]
C --> E["FTS5 task_search"]
C --> F["scrubbed audit args"]
B -->|No| G["raw_args clone"]
G --> H["audit dispatch args_json"]
D --> I["SessionSummary"]
E --> J["Audit search"]
I --> K["Audit summary snippet"]
Prompt To Fix All With AI
### Issue 1
packages/browseros-agent/apps/claw-server-rust/src/api/mcp/service.rs:197-200
**Non-string summaries bypass scrubbing**
When `name_session` receives a valid string `name` and an object or array as `summary`, `Value::as_str` returns `None`, so this branch records the original arguments unchanged. Sensitive text nested in that value is therefore persisted verbatim in the audit detail timeline instead of being scrubbed or rejected.
**How this was verified:** The unvalidated non-string value follows the `None => raw_args.clone()` branch into the dispatch recorder's `args_json`.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (2): Last reviewed commit: "fix(claw-server): scrub the summary in t..." | Re-trigger Greptile
✅ Tests passed: 2550/2553Ran 15 of 15 suites (0 not affected by this change).
|
…atch args The name_session dispatch persisted its raw arguments, so a summary the agent should have kept PII-free was scrubbed in tasks.task_summary and the search index but still surfaced verbatim in the audit detail timeline via the dispatch argsJson. Substitute the already-scrubbed summary into the recorded arguments so every audit surface shows the sanitized copy.
…oll the tab strip The detail header omitted the agent-declared summary that the audit list already shows; render it under the title. Separately, sessions that touch many browser tabs produced a tab strip wider than the page, so it spilled off-screen; make the strip scroll horizontally with each trigger at its natural width.
…g horizontal scroll
name_session now attaches the PII-scrubbed task summary to the agent_session_task_declared event so the summary is available for product analytics, not only local audit search. The analytics catalog gains its first free-text property: task_summary is optional (the declaration still sends without it) and length-bounded defensively at the boundary, with the scrub and cap already applied upstream. Update the tool description to note the summary powers search and is recorded for analytics.
What
Lets users search their audit history by what a task was about, and records that same summary in product analytics. On
name_sessionan agent declares a short, PII-scrubbed summary alongside the existing task category; the server stores it for full-text audit search, surfaces it in the audit UI, and attaches it to the task-declared analytics event.How
name_sessiongains an optionalsummaryargument (last write wins, so a later call refines it). It is scrubbed server-side for structural PII (emails, URLs, file paths, bare domains, long digit runs) before it is stored, indexed, recorded on the audit dispatch, or sent to analytics.tasks.task_summarycolumn holds the canonical value; a companion FTS5task_searchtable holds the searchable index. Both are written in one transaction. The summary is written out of band, so it is excluded from the task recompute upsert and survives event replay; both stores are purged together on retention deletes. The existing?search=path now also matches summary content through the FTS5 index (porter/unicode61 stemming forinvoicevsinvoices), alongside the current title / agent / site match.agent_session_task_declaredevent next to the category. It is the analytics catalog's one free-text property: optional (a category-only declaration still sends) and length-bounded at the boundary.SessionSummarycontract and renders as a two-line snippet under the target in the audit table and as a lead line in the task detail header. The detail-page tab strip now scrolls horizontally (scrollbar hidden) for sessions that touch many browser tabs, and the search placeholder hints that summaries are searchable.PII handling
Two layers. The tool description and agent prompt instruct the model to keep the summary free of names, emails, URLs, paths, and account numbers. Independently, the server scrubs structural PII from the summary once and uses that scrubbed value everywhere it is persisted or transmitted: the canonical column, the search index, the sessions API, the audit dispatch arguments, and the analytics event. The scrub is best-effort and structural, not a full classifier.
Testing
-D warningsclean; new tests cover the scrub, the dispatch-args substitution, recompute-survival plus retention purge, the FTS search path, and the optional free-text analytics property.