Skip to content
Back to skills

Subtext Search

ASecurity

Find Subtext sessions by what happened in them — a predicate tree over page navigations, custom events, and failed network requests within a time window — then hand a match off to session review. Use when you don't have a session URL and need sessions matching a behavior, not a specific user.

  • 78 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 22, 2026
toolsrustgonode

Works with

  • cli
  • mcp

Security analysis

A100/100

Scanned September 22, 2026

npx -y skills add fullstorydev/subtext --skill subtext-search --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Subtext Search?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Subtext Search
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/fullstorydev-subtext-search/badge)](https://www.skillsdirectory.com/skills/fullstorydev-subtext-search)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: subtext-search
description: Find Subtext sessions by what happened in them — a predicate tree over page navigations, custom events, and failed network requests within a time window — then hand a match off to session review. Use when you don't have a session URL and need sessions matching a behavior, not a specific user.
---

# Search

> **PREREQUISITE:** Read `subtext-shared` for MCP conventions and `subtext-session` for the `review-*` catalog and session-identifier forms.

`review-search` finds sessions by *what happened in them* — "visited `/checkout` and got a 4xx/5xx from `checkout/pay`". It scans the org over a time window and returns sessions to hand to review.

Read the tool schema for parameters and operators; it's complete and self-describing. Below is only what the schema and its error messages don't tell you.

## When to reach for it

| You have | Use |
|----------|-----|
| A behavior or symptom, including an app URL sessions visited or requested (`/checkout`) | `review-search` |
| A Fullstory session URL, naming one recorded session | `review-open` directly — skip search |
| One known user and no behavior to filter on | `review-list-sessions` — it does no signal filtering |

**Two different things get called a URL here.** A *Fullstory session URL* identifies one recorded session, so open it directly. An *app URL* like `/checkout` or `checkout/pay` is something sessions visited or requested — that's a search predicate (`navigate.url`, `network.url`), and having one is a reason to search, not to skip it.

Then hand off: `review-search` → `review-summary` to triage candidates → `review-open` → `review-zoom` / `review-snapshot`.

## What's searchable

The index holds three kinds of signal, and nothing else:

- **Page navigations** — `navigate.url`
- **Custom events** — `custom.event_name`
- **Failed network requests** — `network.*`, but only status >= 400

Successful requests, clicks, and console messages are not indexed and can never match. A predicate over a 2xx status matches nothing at all, and a `not_has` over one is vacuously true for every session — so build absence checks over navigations or custom events instead. A session that *did* something unindexed still has it in the replay; search just can't find the session by it.

## Result ordering

Results are ordered by **last activity**, most recent first — not by when the session started, so a long-running older session can outrank one that started later. The response displays only `started`, so the sort key isn't visible in the output. On a busy org the top of the list turns over fast: an identical query re-run seconds later can return a different set.

## Gotchas

- Exactly one of `since` / `time_range` is required. Passing both is rejected, not merged.
- `and` / `or` wrap an `operands` array — `{"and": {"operands": [ … ]}}`, not a bare array.
- `operands` accept any node, including another junction, so trees nest to any depth.
- `count` is an object — `{"gte": 3}`, not `3`.
- `not_has` is a negated leaf with the same body as `has`. It takes no operand list.

The `operands`, `count`, and `not_has` shapes reject with a raw unmarshal error naming an internal type rather than the fix. Every other rule announces itself clearly, so send the query and read the error.

Reached `/checkout`, never reached `/confirmation`, and either a failed `checkout/pay` request or a `payment_declined` event:

```json
{
  "since": "7d",
  "where": { "and": { "operands": [
    { "has":     { "match": { "navigate": { "url": { "contains": "/checkout" } } } } },
    { "not_has": { "match": { "navigate": { "url": { "contains": "/confirmation" } } } } },
    { "or": { "operands": [
      { "has": { "match": { "network": { "url": { "contains": "checkout/pay" },
                                         "status": { "gte": 400 } } } } },
      { "has": { "match": { "custom":  { "event_name": { "eq": "payment_declined" } } } } }
    ] } }
  ] } }
}
```

## Check the readback

Every response echoes how the server parsed the tree:

```
Predicate: (navigate url contains "/checkout" AND NOT (navigate url contains "/confirmation") AND (network url contains "checkout/pay" and status >= 400 OR custom event_name eq "payment_declined"))
```

Read it before trusting the results. A query that parses but doesn't mean what you intended shows up there, never as an error — and zero matches is ambiguous on its own, since it could mean the predicate was wrong, the window was too narrow, or the signal isn't indexed.

## Cost

Each call charges 1 credit. Validation runs before any work, so a rejected query fails the same way every time — fix it rather than re-sending. A "retry shortly" message is the transient case and is worth another attempt.

## See Also

- `subtext-session` — the `review-*` catalog and session-identifier forms
- `subtext-review` — the structured-summary workflow once you've opened a match

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.