Yichus / Reference / API MCP tools
api_report
Build the program-report-2.0 map from the typed IR for whatever style of program the sources are (CRUD, flow, dist, escrow, unrouted IO). overview.surfaces names the present IR surfaces; needed names missing declarations with snippets. Pass format html for a self-contained HTML document.
Kind: Report. Origin: Yichus/Mcp::catalog.
CLI: yichus api report — the program-map report with the same detail levels.
Parameters
protocol_case(optional, object) — Optional protocol-case-1.0 JSON; attaches a separate bounded protocol verdict without changing universal proof claims.sources(required, array) — JSON array of {fileName, source} Bosatsu files for the module.instances(optional, string) — Deployment topology: 1 for a single engine instance, many (default) for multiple instances sharing one DB.format(optional, string) — json (default) for the raw report, html for a self-contained HTML document.title(optional, string) — Optional title for the HTML document.detail(optional, string) — summary (default) keeps shape to per-package counts plus the IO/notable bindings; full enumerates every binding.
Example
This response was produced by calling this tool with the displayed request when these docs were generated. Analysis examples use the owner-scoped notes specimen; scaffold examples supply a resource specification.
Request
{
"sources": [
{
"fileName": "notes-api.bosatsu",
"source": "package Demo/Service/NotesApi\n\n# Owner-scoped notes API. One row per caller, keyed by Principal.user_id.\n# `yichus api verify` / api_access_check prove the scoping from Matchless IR.\n\nfrom Yichus/IO import IO, flat_map\nfrom Yichus/Access import Principal, AccessRule, AccessSpec, OwnerScoped\nfrom Yichus/Data import Db, Table, table, db_read, db_write, db_delete\nfrom Yichus/Service import handler, route, service_def, ReadPerm, WritePerm, DeletePerm\n\nexport (notes_api, access_rules, Note())\nexposes (Yichus/Access, Yichus/Service)\n\nstruct Note(title: String)\n\naccess_rules = AccessSpec([\n AccessRule(\"notes\", OwnerScoped),\n])\n\ndef notes_table(db: Db) -> Table[List[Note]]:\n table(db, \"notes\")\n\ndef list_notes(db: Db, p: Principal) -> IO[List[Note]]:\n Principal(uid, _) = p\n db_read(notes_table(db), uid)\n\ndef put_notes(db: Db, p: Principal, items: List[Note]) -> IO[List[Note]]:\n Principal(uid, _) = p\n db_write(notes_table(db), uid, items)\n\ndef add_note(db: Db, p: Principal, item: Note) -> IO[List[Note]]:\n Principal(uid, _) = p\n items <- flat_map(db_read(notes_table(db), uid))\n db_write(notes_table(db), uid, [item, *items])\n\ndef clear_notes(db: Db, p: Principal) -> IO[Unit]:\n Principal(uid, _) = p\n db_delete(notes_table(db), uid)\n\nnotes_api = service_def(\n \"notes\",\n [\n route(\"/notes\", handler(\"list_notes\", list_notes), [ReadPerm(\"notes\")]),\n route(\"/notes/put\", handler(\"put_notes\", put_notes), [WritePerm(\"notes\")]),\n route(\"/notes/add\", handler(\"add_note\", add_note), [ReadPerm(\"notes\"), WritePerm(\"notes\")]),\n route(\"/notes/clear\", handler(\"clear_notes\", clear_notes), [DeletePerm(\"notes\")]),\n ]\n)\n"
}
],
"instances": "1"
}
Response
{
"ok": true,
"tool": "api_report",
"artifactClass": "program-report-2.0",
"topology": "single-instance",
"detail": "summary",
"headline": {
"class": "crud-api",
"counts": {
"routes": 4,
"bindings": 4,
"tables": 1,
"cells": 0,
"flows": 0,
"abstractions": 1,
"packages": 1
},
"liminal": {
"unrouted": 0,
"undeclared": 0,
"needed": 1
}
},
"proven": true,
"overview": {
"surfaces": [
"tables",
"routes",
"shared-cells"
],
"routeCount": 4,
"handlerCount": 4,
"tableCount": 1,
"effectCount": 0,
"tables": [
{
"name": "notes",
"policy": "OwnerScoped",
"status": "holds",
"rowType": "Note",
"writerCount": 3
}
],
"concurrencySurface": [
"notes"
],
"facts": [
"surfaces: tables, routes, shared-cells",
"4 route(s), 4 handler(s)",
"1 table(s)",
"1 shared cell(s)",
"notes: OwnerScoped (holds, row Note)",
"add_note: read-modify-write on notes",
"every op on notes keys by the caller",
"1 missing declaration(s); call api_add_artifact"
]
},
"map": {
"nodes": [
{
"id": "needed:FrontendSpec",
"zone": "surface",
"size": 0,
"status": "needed"
},
{
"id": "route:/notes",
"zone": "surface",
"size": 1
},
{
"id": "route:/notes/add",
"zone": "surface",
"size": 1
},
{
"id": "route:/notes/clear",
"zone": "surface",
"size": 1
},
{
"id": "route:/notes/put",
"zone": "surface",
"size": 1
},
{
"id": "abstraction:notes_table",
"zone": "work",
"size": 5
},
{
"id": "binding:add_note",
"zone": "work",
"size": 2,
"cond": [
"guarantee:rmw-transactions"
]
},
{
"id": "binding:clear_notes",
"zone": "work",
"size": 1
},
{
"id": "binding:list_notes",
"zone": "work",
"size": 1
},
{
"id": "binding:put_notes",
"zone": "work",
"size": 1
},
{
"id": "table:notes",
"zone": "state",
"size": 4,
"status": "violated",
"cond": [
"invariant:race-free:notes"
]
}
],
"edges": {
"routes_to": [
[
"route:/notes",
"binding:list_notes"
],
[
"route:/notes/add",
"binding:add_note"
],
[
"route:/notes/clear",
"binding:clear_notes"
],
[
"route:/notes/put",
"binding:put_notes"
]
],
"reads": [
[
"binding:add_note",
"table:notes"
],
[
"binding:list_notes",
"table:notes"
]
],
"writes": [
[
"binding:add_note",
"table:notes"
],
[
"binding:put_notes",
"table:notes"
]
],
"deletes": [
[
"binding:clear_notes",
"table:notes"
]
],
"covers": [
[
"needed:FrontendSpec",
"route:/notes"
],
[
"needed:FrontendSpec",
"route:/notes/add"
],
[
"needed:FrontendSpec",
"route:/notes/clear"
],
[
"needed:FrontendSpec",
"route:/notes/put"
]
]
}
},
"needed": [
{
"artifact": "FrontendSpec",
"kind": "frontend",
"because": "4 route(s) are declared but no FrontendSpec binding selects them",
"unlocks": "api_frontend",
"tool": "api_add_artifact",
"snippet": "from Yichus/Frontend import View, FrontendSpec, ListView, Form, Action\n\napp = FrontendSpec(\n \"App\",\n [\n View(\"/notes\", \"list_notes\", ListView),\n View(\"/notes/add\", \"add_note\", Form),\n View(\"/notes/clear\", \"clear_notes\", Action),\n View(\"/notes/put\", \"put_notes\", Form),\n ]\n)"
}
],
"dataModel": {
"tables": [
{
"name": "notes",
"policy": "OwnerScoped",
"status": "holds",
"rowType": "Note",
"fields": [
{
"name": "title",
"type": "String",
"read": false
}
],
"readers": [
"add_note",
"list_notes"
],
"writers": [
"add_note",
"put_notes"
],
"deleters": [
"clear_notes"
],
"keyDiscipline": "every DB operation keys by the caller's Principal.user_id",
"operations": [
{
"binding": "list_notes",
"operation": "db_read",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"binding": "put_notes",
"operation": "db_write",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"binding": "add_note",
"operation": "db_read",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"binding": "add_note",
"operation": "db_write",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"binding": "clear_notes",
"operation": "db_delete",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
}
]
}
]
},
"surface": {
"routes": [
{
"path": "/notes",
"handler": "list_notes",
"handlerBinding": "list_notes",
"authority": "authenticated",
"declared": [
"Read(notes)"
],
"inferred": [
"Read(notes)"
],
"status": "match",
"tables": [
"notes"
],
"effect": "pure-read",
"narrative": [
"reads notes"
],
"params": [
"db: return-data",
"p: return-data"
]
},
{
"path": "/notes/add",
"handler": "add_note",
"handlerBinding": "add_note",
"authority": "authenticated",
"declared": [
"Read(notes)",
"Write(notes)"
],
"inferred": [
"Read(notes)",
"Write(notes)"
],
"status": "match",
"tables": [
"notes"
],
"effect": "read-modify-write",
"narrative": [
"reads notes → writes notes"
],
"rmw": [
{
"resource": "notes",
"readAt": "notes_api:33:21",
"writeAt": "notes_api:34:3"
}
],
"params": [
"db: return-data",
"item: return-data",
"p: return-data"
]
},
{
"path": "/notes/clear",
"handler": "clear_notes",
"handlerBinding": "clear_notes",
"authority": "authenticated",
"declared": [
"Delete(notes)"
],
"inferred": [
"Delete(notes)"
],
"status": "match",
"tables": [
"notes"
],
"effect": "delete",
"narrative": [
"deletes notes"
],
"params": [
"db: return-data",
"p: return-data"
]
},
{
"path": "/notes/put",
"handler": "put_notes",
"handlerBinding": "put_notes",
"authority": "authenticated",
"declared": [
"Write(notes)"
],
"inferred": [
"Write(notes)"
],
"status": "match",
"tables": [
"notes"
],
"effect": "blind-write",
"narrative": [
"writes notes"
],
"params": [
"db: return-data",
"items: return-data",
"p: return-data"
]
}
]
},
"concurrency": {
"bound": 8,
"truncatedOps": 0,
"interleavingsExplored": 60,
"uniqueOutcomes": 25,
"complete": true,
"causalConsistency": {
"id": "causal-consistency",
"status": "holds",
"kind": "built-in",
"origin": "complete-causal-graph",
"detail": "the complete causal graph over 5 effect operations admits an ordering; schedule exploration remains separately bounded"
},
"cells": [
{
"stateRef": "notes",
"writers": [
"add_note",
"clear_notes",
"put_notes"
],
"readers": [
"add_note",
"list_notes"
],
"invariants": [
{
"id": "race-free:notes",
"status": "violated",
"kind": "built-in",
"origin": "built-in-interleaving",
"detail": "6 valid orderings over 'notes' produce differing effect sequences",
"counterexample": [
[
{
"index": 0,
"binding": "list_notes",
"primitive": "db_read",
"stateRef": "notes",
"location": "notes_api:25:3"
},
{
"index": 1,
"binding": "put_notes",
"primitive": "db_write",
"stateRef": "notes",
"location": "notes_api:29:3"
},
{
"index": 2,
"binding": "add_note",
"primitive": "db_read",
"stateRef": "notes",
"location": "notes_api:33:21"
},
{
"index": 3,
"binding": "add_note",
"primitive": "db_write",
"stateRef": "notes",
"location": "notes_api:34:3"
},
{
"index": 4,
"binding": "clear_notes",
"primitive": "db_delete",
"stateRef": "notes",
"location": "notes_api:38:3"
}
]
]
}
]
}
],
"topologySensitivity": {
"declared": "single-instance",
"other": "multi-instance",
"flips": [
{
"id": "integrity",
"atDeclared": "warning",
"atOther": "violated"
},
{
"id": "rmw-transactions",
"atDeclared": "warning",
"atOther": "violated"
}
]
}
},
"shape": {
"packages": [
{
"name": "Demo/Service/NotesApi",
"bindingCount": 7,
"ioBindingCount": 5,
"structCount": 0,
"bindings": [
{
"name": "add_note",
"type": "(Yichus/Data::Db, Yichus/Access::Principal, Note) -> Yichus/IO::IO[List[Note]]",
"role": "terminal-io",
"params": [
"db: return-data",
"item: return-data",
"p: return-data"
],
"reads": [
"DbRead"
],
"writes": [
"DbWrite"
],
"touches": [
"notes"
]
},
{
"name": "clear_notes",
"type": "(Yichus/Data::Db, Yichus/Access::Principal) -> Yichus/IO::IO[()]",
"role": "terminal-io",
"params": [
"db: return-data",
"p: return-data"
],
"writes": [
"DbDelete"
],
"touches": [
"notes"
]
},
{
"name": "list_notes",
"type": "(Yichus/Data::Db, Yichus/Access::Principal) -> Yichus/IO::IO[List[Note]]",
"role": "terminal-io",
"params": [
"db: return-data",
"p: return-data"
],
"reads": [
"DbRead"
],
"touches": [
"notes"
]
},
{
"name": "notes_table",
"type": "Yichus/Data::Db -> Yichus/Data::Table[List[Note]]",
"role": "pure",
"params": [
"db: return-data"
],
"signals": [
"literal-root"
]
},
{
"name": "put_notes",
"type": "(Yichus/Data::Db, Yichus/Access::Principal, List[Note]) -> Yichus/IO::IO[List[Note]]",
"role": "terminal-io",
"params": [
"db: return-data",
"items: return-data",
"p: return-data"
],
"writes": [
"DbWrite"
],
"touches": [
"notes"
]
}
]
}
]
},
"abstractions": {
"shared": [
{
"name": "notes_table",
"type": "Yichus/Data::Db -> Yichus/Data::Table[List[Note]]",
"role": "pure",
"useCount": 5,
"callerCount": 4,
"useSites": [
"add_note applied/1 @notes_api:33:29",
"add_note applied/1 @notes_api:34:12",
"clear_notes applied/1 @notes_api:38:13",
"list_notes applied/1 @notes_api:25:11",
"put_notes applied/1 @notes_api:29:12"
],
"routes": [
"/notes",
"/notes/add",
"/notes/clear",
"/notes/put"
],
"tables": [
"notes"
]
}
]
},
"guarantees": [
{
"id": "compiles",
"claim": "parses and type-checks",
"status": "proven",
"evidence": "guarantees",
"degree": {
"topology": "single-instance"
}
},
{
"id": "access-spec-declared",
"claim": "an AccessSpec binding declares every table's policy",
"status": "proven",
"evidence": "dataModel.tables",
"degree": {
"topology": "single-instance"
},
"details": [
"notes: OwnerScoped"
]
},
{
"id": "access-coverage",
"claim": "every DB operation touches a declared resource",
"status": "proven",
"evidence": "dataModel.tables",
"degree": {
"topology": "single-instance"
}
},
{
"id": "access:notes",
"claim": "every DB operation on \"notes\" keys by the caller's Principal.user_id",
"status": "proven",
"evidence": "dataModel.tables.notes",
"degree": {
"topology": "single-instance"
},
"assumptions": [
"engine binds Principal; handlers never construct it"
]
},
{
"id": "route-permissions",
"claim": "declared route permissions equal handler effects recovered from the IR",
"status": "proven",
"evidence": "surface.routes",
"degree": {
"topology": "single-instance"
}
},
{
"id": "route-authority",
"claim": "Route authority declarations are enforceable",
"status": "proven",
"evidence": "guarantees",
"degree": {
"topology": "single-instance"
},
"details": [
"/notes: authenticated",
"/notes/add: authenticated",
"/notes/clear: authenticated",
"/notes/put: authenticated"
]
},
{
"id": "rmw-transactions",
"claim": "add_note reads then writes \"notes\"",
"status": "warning",
"evidence": "surface.routes",
"degree": {
"topology": "single-instance",
"bound": 8,
"truncatedOps": 0,
"complete": true,
"interleavingsExplored": 60
},
"assumptions": [
"engine binds Principal; handlers never construct it",
"single engine instance runs each request's IO plan atomically"
],
"details": [
"Demo/Service/NotesApi::add_note reads then writes \"notes\"; with multiple instances on one DB, run this handler in a transaction (or a single-writer queue) to avoid lost updates (accepted: instances=1 declared; one instance runs each request's IO plan atomically)"
]
},
{
"id": "integrity",
"claim": "bounded interleaving over shared cells is race-free",
"status": "warning",
"evidence": "concurrency.cells",
"degree": {
"topology": "single-instance",
"bound": 8,
"truncatedOps": 0,
"complete": true,
"interleavingsExplored": 60
},
"assumptions": [
"engine binds Principal; handlers never construct it",
"single engine instance runs each request's IO plan atomically"
],
"details": [
"race-free:notes: 6 valid orderings over 'notes' produce differing effect sequences (accepted: instances=1 declared; one instance runs each request's IO plan atomically)"
]
}
]
}
Run tools in the browser: api-mcp.html?webmcp=1.
Read the result according to this tool’s scope: static checks, bounded execution checks, and descriptive diagrams answer different questions. A successful call is not a general approval of the program. The safety and permissions guide compares the checks and provides editable ownership, guard, and role examples.