# Answer Support Tickets from a PocketBase Codebase

Yes. Your backend sends each ticket to the API, an agent traces the answer through your PocketBase Go code, and a typed JSON reply comes back on your webhook.

[Run this on Rush](https://cloud.getrush.ai/run/answer-support-tickets-from-code/pocketbase/), in a Project that has your repository.

## What the agent does

Your help desk receives a ticket and your backend starts one run for it: the repository in `resources`, the customer's question in `input`. The agent clones the code into its own cloud sandbox and answers from the Go source, not from the docs site. In a PocketBase codebase like `pocketbase/pocketbase`, it sees from `go.mod` that the module is `github.com/pocketbase/pocketbase`, finds the record routes registered under `/collections/{collection}/records` in `apis/record_crud.go`, and the shared list and search logic in `tools/search/provider.go`.

For the ticket "why does a list request return only 30 records when I asked for 500?", the agent follows the request from the route to the query. `recordsList` in `apis/record_crud.go` builds a `search.NewProvider` and hands it the raw URL query through `ParseAndExec`. In `tools/search/provider.go`, `Parse` reads exactly five parameters by their constant names: `page`, `perPage`, `sort`, `filter` and `skipTotal`. The provider starts with `perPage` set to `DefaultPerPage`, which is `30`, and `Exec` clamps any value above `MaxPerPage`, which is `1000`. So 500 is allowed, and a page of 30 means the server never saw a `perPage` of 500.

That points to the request, and the agent says which mistakes produce it. `url.ParseQuery` and `params.Get` match names exactly, so `limit=500`, `per_page=500` or `perpage=500` are all ignored and the default of 30 applies. A value that is not an integer makes `strconv.Atoi` fail and the whole request returns a 400, not 30 items, which rules that case out. The agent also notes the two server-side places that could change the answer: an `OnRecordsListRequest` hook (declared in `core/app.go`) that a project's own Go or JS hooks can use to rewrite the result, and the collection's `ListRule`, which filters rows before pagination and can make fewer rows exist than the customer expects.

It then writes the reply the prompt asks for: two short paragraphs a customer can read, the files and line ranges that prove each claim, and a confidence level. It changes no code. Where more than one cause fits, the answer names the check that tells them apart, here the `perPage` field in the JSON response, which echoes the value the server actually used.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "A customer asks: why does a list request return only 30 records when I asked for 500? Find the answer in this repository's code, not its docs: start at the records list route in apis/record_crud.go and follow the query string into Parse and Exec in tools/search/provider.go. Say which parameter names are read, what the default and maximum page sizes are, and whether a hook or a list rule could change the count. Reply with JSON: answer (two short paragraphs a customer can read), files (paths and lines that prove it), and confidence. Do not change code.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is the agent's final answer, the JSON object the prompt names. `answer` tells the customer in plain words that the page size parameter is `perPage`, spelled exactly that way, that the default is 30 and the ceiling is 1000, and how to check the response's own `perPage` field. `files` points at `tools/search/provider.go` for the constants and the `Parse` function, and at `apis/record_crud.go` for the handler that passes the query through. `confidence` is the agent's own rating, with the question that would raise it when it is low, such as the exact URL the customer called.

Your webhook receives the object as `data.result` in the `run.completed` payload, which carries results up to 16 KiB, well over what this reply needs. Your backend parses and validates it, attaches it to the ticket as a draft, and leaves the send to a person. Before sending, the support person opens the cited lines and checks them against the customer's report: the URL they used, whether their project registers its own list hooks, and the collection's list rule.

The session keeps the whole investigation in its transcript at `GET /o/{org}/sessions/{id}/messages`: each file the agent opened, each search it ran, in order. When an engineer is asked to confirm the reply, they read that record instead of repeating the search.

## Run it on every new support ticket

Each ticket your help desk creates calls `POST /o/{org}/sessions` once, with the question in `input` and the repository in `resources`. Send the ticket id as the `Idempotency-Key` header so a help desk that delivers its webhook twice still starts one run, and store the returned `execution_id` on the ticket.

With a webhook set on the API key, your backend hears back when each turn finishes, with the reply in `data.result`. When the customer writes back with the URL they called, send it as a follow-up to `POST /o/{org}/sessions/{id}/messages`: the parked sandbox wakes with the clone and its earlier reading still there.

## Why run it on Rush?

Answering a PocketBase behaviour question from code means a checkout, a Go-aware search through `apis/` and `tools/`, and someone who knows where the defaults live. A Rush run has the repository cloned in its own sandbox when it starts, reads as far as the question needs, and gives your backend a typed answer. No support engineer has to stop and pull the repository.

Tickets arrive in bursts, and each one gets its own run, up to the key's limit of runs in progress, instead of a queue behind one engineer. Every reply carries file and line citations plus the session's full record, so a support person can send a code-based answer with confidence and engineering sees only the tickets that are real bugs.

## Frequently asked questions

### Will the agent change my PocketBase code?

The prompt says not to, and the request asks for an answer, not a pull request. The transcript records every command the agent ran, so you can confirm it only read files.

### What if my project extends PocketBase with its own hooks?

Point `resources` at your own application repository rather than the framework. The agent reads your `main.go` and any `pb_hooks` scripts, can run `go mod download` to read the PocketBase version your `go.mod` pins, and the reply says when one of your hooks, such as a records list handler, is the cause.

### How do I get the reply as structured data?

Ask for JSON in the prompt, as this request does, and parse `data.result` from the webhook or `result` from `GET /o/{org}/sessions/{id}`. Validate the parsed object against your own schema before it reaches a person or a customer.

### Can the agent see my customers' records?

Only what you send. This request has the repository and the question, and nothing from your PocketBase database. If a ticket needs the customer's collection rules or a sample URL, include them in `input`.
