PrimaChat
Tools
Three tools the model can call, two of them read-only, and nothing else.
Live Built and working today on the surface this card describes.
What it does
The model gets exactly three tools: stone_search, stone_read and stone_engrave. There is no write, no delete, no branch, no remote and no shell. A capability the model cannot name is a capability it cannot misuse.
stone_engrave is gated twice: in the browser, where a person approves it, and again on the server, where it needs a conversation id it can distil. A model cannot invent a session.
The approval is a top-level field on the request envelope, not one of the model's own tool arguments, so an injected tool call cannot approve itself.
Which repository ids exist is decided by the person, not by the model. The tool executor is handed the caller's registry, so a tool call naming another tenant's repository resolves against the wrong registry and comes back empty.
Repository text is prepared before the model sees it: canary strings are stripped, the text is scanned for injection markers and annotated if any fired, and the whole thing is fenced in an untrusted-data block. The citation instruction stays outside that fence, where the model can trust it.
Inputs and outputs
GET /api/tools/manifest | {tools} in OpenAI tool-definition shape. |
|---|---|
POST /api/tools/execute | {name, arguments, conversationId?, repoId, confirm?} in. {content, display?, error?} back. |
stone_search | {query, limit?}. Returns sections with file, heading and line, and the instruction to cite them. |
stone_read | {path, heading?}. One file, or one section of it. |
stone_engrave | {title?}. Distils the session and commits it. |
content and display | content is what goes back to the model. display is rendered by the interface and is never seen by the model unless it is also in content. |
Configuration
| Search limit | 1 to 12 from a tool call, default 6. |
|---|---|
| Confirmation | confirm on the envelope, set by the browser host after the person approves a write. |
| Canaries | A configurable set of strings that are removed from repository content before it reaches the model, so a prompt that tries to extract them gets nothing. |
Limits
- A tool call with no repository connected returns a plain instruction to say so rather than guessing. So does a search with no matches: the tool tells the model that the repository holds nothing on the subject.
stone_readrefuses a path that resolves outside the repository, and reports it as a path escape rather than a missing file.- The manifest is the whole authority of this surface. Adding a capability means adding a tool, which is a visible change.
Example
what stone_search hands back to the model
3 sections from handbook:
[1] handbook/holidays.md § Carry-over (Line 42)
…
Cite the sections you used at the end of your answer in the format
`file § heading`. What is not in here, you do not know. Source of truth
prima-chat/server/routes/tools.ts (the manifest, the executor, the confirm envelope field, the caller-supplied registry)prima-chat/server/untrusted.ts (canary redaction, injection scan, the untrusted-data fence)prima-chat/server/engrave.ts (`authorizeEngraveWrite`, shared by the tool and the HTTP route)