Web service contract
Which Connect service behind agni serve owns which RPC, and the contract details a caller has to know.
This page is the reference for the wire contract of agni serve. How those calls reach the engine,
and how a design reaches the browser in the first place, is on
Web app and presenter.
The services ΒΆ
Everything is Connect, proto-first, in JSON or binary, with a generated TypeScript client. The split follows resource lifetimes. Workspace navigation, one design’s rendering, checks over a design, the two-design diff, and ad-hoc datalog search are independent concerns with independent cadences.
| Service | RPC | What it does |
|---|---|---|
| Workspace | ListMounts | the mount names a tree roots on; opens drops the ones holding nothing that client can open and returns how many, so the sidebar can account for a mount an operator configured and cannot find |
| Workspace | ListDir | one directory level, each file labeled with its reader format and the kind of client that opens it (design, datasheet, or neither); opens declares what the caller can open, which drops folders with none of it anywhere beneath them (a bounded server-side walk, since one level of listing cannot see that far) and is what lets the two trees prune the same mounts to opposite answers |
| Design | GetDesign | load and summarize one design: sheet list, effective layout, available layouts, native availability |
| Design | GetSheet | one rendered sheet, where format picks PACKED (columnar bytes for WebGL), SVG (the verification backend), or NATIVE (the format’s own tool) |
| Design | HighlightSheet | resolve highlight spec layers against one sheet: PACKED yields primitive-index groups, SVG a transparent same-frame overlay document |
| Design | GetLayoutReport | how an auto-layout drew each component (glyph, box, provided symbol, or unresolved) |
| Check | ListRules | the rule catalog with tags and per-design availability, static per build, fetched once |
| Check | CheckDesign | run a rule subset and return findings, where each subject joins the packed primitive keys for highlighting |
| Check | GetExpectations | the design’s expectation sidecar as its own resource, reconciled against findings client-side |
| Check | GetCheckReport | the severity-organized report, the same shape as agni check --format report |
| Diff | DiffDesigns | semantic diff of two designs plus the highlight maps, the wire form shared with agni diff --format json |
| Query | RunQuery | evaluate an ad-hoc datalog query over the design’s fact base, returning columns and provenance-linked rows, the same engine as agni query |
| Query | ListRelations | the relation catalog with arg labels, summary, and kind, driving the panel’s click-to-insert picker |
| Check | GetNamingConvention | resolve a stored convention config into a value an OverlayConfig carries, parsed and validated |
| Review | GetReviewManifest | resolve a stored checklist into a manifest value, parsed and validated |
| Review | CreateReview | run a checklist against one design and store the result, returning the stored run |
| Review | GetReview | one stored run, by resource name |
| Review | ListReviews | stored runs newest first, paginated, filterable by design |
| Review | DeleteReview | remove a stored run |
A few contract details bite if missed.
- Effective values echo back. GetDesign returns the layout actually used, since a request for an unavailable layout resolves rather than erroring, and the client adopts the echo. The same holds for the sheet id. The client navigates by the ids GetDesign returned, never by index guesses, because sheet ids are non-numeric on purpose and a numeric selector means a positional index.
- A highlight must mirror its sheet. An overlay is only meaningful over the base render it was framed for, so the sheet, layout, and symbols in a HighlightSheet call must match the GetSheet it overlays.
- The board is a sheet. A
.kicad_pcbrenders as a synthetic “board” sheet, so navigation, deep links, and both highlight paths needed no board-specific client plumbing. - Diff is all-or-nothing. If either side fails to load, the call fails. There is no partial diff.
- Query evaluates on the server over netlist facts. RunQuery loads the design, builds the model, and runs the same evaluator the CLI runs. Serve wires no parameter directory and datasheet data is deployment-bound, so a query over the datasheet parameter relation returns no rows here. The evaluator is dependency-free Go, so a later revision could evaluate it in the browser instead.
- A design is named, a checklist is sent. CreateReview carries the review manifest as a value while the design stays an artifact URI, and the split is deliberate. A design is megabytes, needs a reader chosen by extension, and is re-requested across many calls, so re-sending it every time would be absurd. A checklist is a small declaration the caller already holds, and a service that took a path for it would need a filesystem to do its job. GetReviewManifest is the bridge for a client that holds a URI and no filesystem: it reads and validates once, and the client sends the value it got back. The CLI skips it, because reading the file the user named is its own job.
- Reviews are the one resource; everything else is a verb. A review RUN outlives the call that made it, so it has a name and the four standard methods, with paging and filtering following AIP. Every other rpc here is a pure function of files on disk, so its arguments are its whole identity and a resource name would be ceremony. That split is CONSTRAINTS C23 and is deliberate rather than drift.
- Stored runs need a volume.
agni serve --review-store <dir>names a WRITABLE directory, separate from the read-only design mounts, so persisting runs never turns a mount into a write surface. In a container it is a mounted volume. Without the flag the four review resource methods answer with a failed-precondition naming it, rather than running the checks and dropping the result. Runs stored there are visible to every client of the server;agni servehas no authentication yet. - The viewer can ask under its own vocabulary. A naming convention is picked from the mount,
resolved server-side into a value, and carried on every rule-running request as an
OverlayConfig. It REPLACES the server’s--conventionsdefault for that request rather than adding to it, so the top bar names which vocabulary produced the answers on screen. That indicator is load-bearing rather than decorative: replacement can stop a rule running, a rule that stops running produces no findings, and in a findings list that is indistinguishable from a design that got fixed. - A stored run embeds the checklist it scored. The document carries a manifest SNAPSHOT, not just the manifest’s name. A checklist is an editable file, so a name would resolve to whatever it says today, and last quarter’s review would re-render against this quarter’s questions with its outcomes intact underneath. That is the failure the snapshot exists to prevent.