PrimaChat
Stone, engrave
Distil a session into one markdown file, commit it, push it. A transcript is written only when the distillation fails, and the file says so.
Live Built and working today on the surface this card describes.
What it does
The session is distilled into a note with a title, a summary, a body and the files it cited. Then that note is written, committed and pushed. The distillation is one /chat/completions call to prima-core, billed to the person's own key like any other call.
When that call fails, or the model answers in a shape the parser cannot read, the fallback is written instead: the first 8,000 characters of the raw transcript under a heading that says it is not distilled, with distilled: false in the front matter and a summary saying a shortened transcript was stored. A person reading the repository can tell the two apart from the front matter alone.
The file lands at sessions/<year>/<month>/<date>-<slug>.md, with front matter carrying the title, the date, the session id, the model, the source and whether the model produced the distillation or the fallback did.
If the repository keeps a meta/changelog.md, the note is appended to that day's entry there as well.
A session with nothing lasting in it is skipped, with the reason given back. An empty entry is worse than none.
The note also lists the repository files the session cited, under a sources heading, so an engraving points back at what it was built from.
Everything written is passed through a redactor first. Gateway keys, provider keys, GitHub tokens, AWS keys, JWTs, private key blocks and credentials embedded in URLs are replaced, regardless of what was discussed.
Inputs and outputs
POST /api/conversations/:id/engrave | {repoId?, title?, body?, summary?, confirm?, preview?} in. {path, commit, pushed, needsReview?, draft, repo} back. |
|---|---|
| Preview | ?preview=1 or preview: true returns the draft and writes nothing. |
| Skipped | {skipped: true, reason} when the session holds nothing worth keeping. |
needsReview | Set when the commit happened but the push did not, for example when there is no remote. The commit is not gated on it; a person sees it later. |
| 403 / 429 | shared_engrave_disabled · confirmation_required · engrave_rate_limited, the last with a Retry-After. |
Configuration
PRIMA_ALLOW_AGENT_SHARED_ENGRAVE | 1 permits automatic engraving into a repository whose writes leave this server. Off by default, in which case a person has to commit that contribution themselves. |
|---|---|
| Confirmation | Required for a shared repository even when the setting above is on. The confirmation is an envelope field set by the browser after the person approves, never something the model can put in its own arguments. |
PRIMA_ENGRAVE_RPM | Engravings per minute per person, across both write paths. Default 5. |
| Location | One convention for now, overridable per repository later. |
Limits
- The rate limit meters git pushes, not gateway spend, and it is one budget shared by the HTTP route and the model's tool. Switching entry points does not reset it.
- Engraving into a repository id belonging to someone else is not refused, it is not found. The write path has the same isolation as the read path because it is the same registry.
- There is no pull request. The note is committed on the branch and pushed.
- A push that fails leaves a local commit and a
needsReviewline. Nothing is rolled back. - The fallback transcript passes through the same redactor as everything else, but it is a transcript. If the distillation call is failing, engraving is writing raw conversation into the repository, and the front matter is where that shows.
Example
the front matter of an engraved note
---
title: "Carry-over rules for unused holiday"
date: 2026-09-10
engraved_at: 2026-09-10T14:03:11.412Z
session: conv_…
model: "prima-core"
source: chat.prima.li
tags: ["holidays", "policy"]
distilled: true
--- Source of truth
prima-chat/server/engrave.ts (`distil`: one `prima-core` call on the person's credential, the 8,000-character transcript fallback with `distilled: false`; `renderNote`, `engrave`, the redaction patterns, `authorizeEngraveWrite`, the write limiter)prima-chat/server/routes/conversations.ts (the engrave route, preview, the skip reason)prima-chat/server/env.ts (`PRIMA_ALLOW_AGENT_SHARED_ENGRAVE`, `PRIMA_ENGRAVE_RPM` default 5)prima-chat/server/git.ts (`needsReview` when the push does not happen)