Documentation for v2.9.0. Read the latest, v2.12.0.
Start
Glossary
Every term the documentation uses, defined once. Chapters link here on the first use of a term;
the vocabulary itself is kept in CONTEXT.md in the repository.
Who is who#
- Sanshain
- The registry itself: the server that stores, splits and distributes API specifications. Where a longer name is needed, Sanshain Service.
- Producer
-
A system that publishes an API spec to Sanshain. On the wire it is named by
producername. A role, not an entity type: one system is usually a Producer and a Consumer at once. - Consumer
-
A system that requires endpoints from a Producer and is recorded as depending on them. Named by
consumername. - System
-
A Producer or Consumer seen as one thing: the
serviceNameof asanshain.yaml. The catalog push and the node panel speak of systems because they do not care which role the build plays. - Tooling (client)
-
Software that speaks HTTP to Sanshain on a Producer's or Consumer's behalf: the Maven plugin,
the cargo subcommand, the Go, JavaScript and Conan clients, or plain
curl. Tooling acts for a system; it is never a domain entity itself. - Actor
- The authenticated caller behind a request, as the audit log records it. A version's "provided by" is the actor of its last provide, except that a byte-identical promotion keeps the snapshot's provider.
- Role
-
A fixed, named bundle of permissions held instance-wide (
admin,releaser, ...). The set of roles is part of the product. - Permission
-
One thing an actor may do; what every authorisation check tests. For example
release_gais the permission that publishing a GA version needs. - Releaser
-
The role that holds
release_ga: publishing a GA version, retiring a protocol family and cutting a sanshain-branch need it. Admins and root hold it implicitly. - Maintainer
- An actor responsible for a named set of Producers, with powers over those and no others: delete one of their versions, retire a family, manage the Producer's webhooks.
- Root
-
An account whose authority comes from configuration rather than from stored grants, so it cannot
be revoked from inside Sanshain.
SANSHAIN_ROOT_USERS, when set, alone names the root accounts; otherwise the initial admin (INITIAL_ADMIN_USERNAME, defaultroot) is root. Holds every permission. - Approval
- A locally registered user cannot log in until an administrator approves the account, unless the administrator switched on auto-approve on the admin page.
Versions#
- Version
-
The Producer-declared identity of a spec:
MAJOR.MINOR.PATCH, read from the spec file itself (info.version; for proto a mandatory// sanshain-version:comment). Sanshain never assigns one.v2and2.1are accepted and stored as2.0.0and2.1.0. - Version line
- The ordered set of versions one Producer has published for one API type. Diffing, compatibility checks and cleanup happen within a single line; a Producer's OpenAPI and proto lines evolve independently.
- Stability
- Which of exactly two states a stored version is in, snapshot or GA. Declared by the caller on every provide; how the caller decides is the tooling's business (the ga switch), never Sanshain's.
- Snapshot
- A version in its mutable state: re-providing it overwrites it (the user who last provided it may change it, anyone else's different content is refused with the next free minor proposed, every overwrite audited), it is never compatibility-checked, and it expires once neither provided nor required for the snapshot window.
- GA
- A version in its immutable state. Re-providing identical content is a no-op; different content is rejected with a proposed next version. A GA permanently claims its number: no snapshot may ever exist for it again, and cleanup never removes it.
- Promotion
-
The GA provide of a number that existed as a snapshot. The entry becomes GA in place and the
snapshot content is gone. The response says
"promoted": true. - Proposed version
-
The
proposed_versionfield of a409that refused a provide: the next free number of the line, bumped by what actually changed (breaking: major, additive: minor, shape-identical: patch). Set it in the spec file and republish. - Breaking change
- A change the compatibility classifier flags between two documents of one line: a removed endpoint, parameter, property, message or rpc, a type change, a new required field. A GA version that is breaking relative to the highest GA below it must bump the major.
- Deprecation
-
A per-element marker in the spec (
deprecated: true,option deprecated = true;,[deprecated = true]). Removing an element that was deprecated in the previous GA is not breaking. - Retire
-
A provide call with
retired: trueand no body: the Producer no longer provides that API family. It clears the family's capability tag, closes its trunk pins and releases its message contracts; versions and existing pins stay. Needs the releaser role or a maintainer grant. - Snapshot expiry
-
A snapshot that is neither provided nor required for
snapshot_max_age_days(default 30,0disables) is cleaned up. Use keeps it alive. GA never expires. - Instance version
-
Sanshain's own build version, answered by
GET /version. Always qualified, to keep it apart from spec versions.
Publishing and requiring#
- Provide
-
A Producer's submission of a complete spec for one version of one API type, with a declared
stability (
POST /provide,/provide/asyncapi,/provide/grpc). Because it is complete, an endpoint absent from it is absent from that version's API. - Snippet
- The part of a spec Sanshain cuts out for one endpoint: one OpenAPI operation with the schemas it references, one AsyncAPI channel with its messages, one proto service with one rpc and the messages it needs.
- Require
-
A Consumer's request for specific endpoints at its pin (
GET /require,/require/asyncapi,/require/grpc). A successful require also records the dependency; a failed one records nothing. - Bundle
-
POST /require-bundle: several endpoints of one Producer at one pin, answered as a single merged document with one copy of each shared schema. If any endpoint is absent the whole bundle fails and names the missing ones. - Pin
-
A Consumer's exact version choice for one dependency, written in its own configuration. No
ranges, no
latest, no default: what a Consumer builds against changes only when someone edits the pin. - Resolution
- Answering "what is this endpoint at this pin?". The line holds one entry per version, snapshot or GA; that entry answers, and there is no fallback to any other version. Every resolution ends in exactly one of three states: served, absent or unknown.
- Served
-
Resolution state: the pinned version exists and contains the endpoint. The
X-Sanshain-Stabilityheader says whether GA or snapshot answered. - Absent
-
Resolution state,
410 Gone: the pinned version exists and deliberately does not include this endpoint. A definitive no. - Unknown
-
Resolution state,
404 Not Found: the Producer, or the pinned version in either stability, does not exist. A configuration error on the Consumer's side, answered immediately. - Dry run
-
dry_run: trueon a provide, require or bundle: the full validation runs and nothing is stored, not even the Producer. Made for pull-request pipelines. - Idempotent no-op
-
Re-providing byte-identical content (after line endings are normalised to LF and a leading BOM
is removed) stores nothing and answers
changesall zero. CI re-runs never fight. - ETag
-
Every require answer carries an
ETag; sending it back asIf-None-Matchyields304 Not Modifiedwhen the content is unchanged. A GA pin never changes; a snapshot pin can, and the ETag is what detects it. - Sanshain-Warning
- A response header, one line per warning, on a call that succeeded but could not be recorded the way it was declared: an unknown tag, trunk and tag together, a catalog push that recorded nothing. Clients print it and fail on it only in strict mode.
- Strict mode
-
A client setting (
strict: trueinsanshain.yamlor the client's flag): missing configuration and anySanshain-Warningfail the build instead of printing a warning. - Message contract (AsyncAPI)
-
On a GA provide, every named
publishmessage registers a contract keyed by channel and message name, owned by the first Producer to publish it. The owner may widen it; another Producer may co-publish only an identical payload schema. - Harvested subscription
-
An AsyncAPI
subscribe(2.x) orreceive(3.x) operation in a provided document becomes a version-less consumer edge in the graph, resolved against the channel's message contract. No hand-written require is needed for it. - Validator
-
POST /validateand the form on the landing page: the provide-side checks (version extraction, splitting) on any document, without authentication and without storing anything.
The graph#
- Dependency graph
-
What Sanshain knows about who pins which version of which endpoint, drawn as a live SVG on
/graph.htmland answered as JSON byGET /report. - Outdated
- A dependency whose pin is below the latest GA of its line. A display state only: being outdated changes nothing about what is served.
- Snapshot-pinned
- A dependency served from a snapshot because its pin has no GA. It flags building against overwritable content; such a pin may even be ahead of the latest GA.
- Superseded
-
A snapshot below the latest GA of its line. The producers page marks it
superseded by X ga, and a pin to it counts as outdated. - Stream
-
Where a build belongs: plain calls record dev activity,
trunk: truemarks the trunk stream,tag: "<branch>"marks a sanshain-branch. Streams never change version rules or what is served; they only decide which graph records the call. - Dev graph
-
The default view: everything ever provided or required, snapshots included, thinned by the
dependency window (
dependency_max_age_days, default 30). - Trunk
- The stream of your default-branch CI. A trunk provide stamps the version as "trunk's current version"; a trunk require maintains the main graph's pin set, last write per endpoint wins.
- Main graph
- The trunk stream's view: every Producer at its trunk version, edges from trunk pins. What trunk is, deterministic after every trunk build.
- Trunk TTL
-
Trunk entries not refreshed within
trunk_max_age_days(default 90) leave the main graph; they are highlighted as stale once they pass half the window. History keeps them. - Sanshain-branch
-
A named copy of a graph at a chosen instant: the release cut. Created by a releaser from trunk
or from another branch, updated by tagged builds, diffable against main or other branches.
main,devandtrunkare reserved names. - Tag
-
The
tagparameter of a provide, require or bundle: the call updates the named sanshain-branch instead of trunk. Branches are never auto-created; an unknown tag records the call in the dev graph only and answers aSanshain-Warning. - Release cut
-
Creating a sanshain-branch:
POST /admin/brancheswith a name, optionally a source branch and anas_ofinstant. A past instant repairs a forgotten cut. - Timeline
- Trunk and branch writes are append-only, so the main graph and every branch can be rendered as they were at any past instant. The slider's markers are the instants the graph changed.
- Peripheral resource
-
Something outside Sanshain a system depends on (a database, bucket, queue), known only by its
Backstage ref
resource:<namespace>/<name>from the system's owncatalog-info.yaml. One node per ref, shared by every system that names it. - Catalog push
-
PUT /catalog/{systemname}with the system's Backstagecatalog-info.yaml, once per build. Sanshain reads the Component named like the system and of it the periphery and the catalog context; everything else is ignored. - Missing component
-
A
component:ref in a system'sdependsOnthat names no Producer and no Consumer: drawn as a dashed node with an edge from the depending system, so a dependency the graph cannot see is at least visible as a gap. It disappears the moment a system of that name provides or requires. - Origin
-
What the build that provided a version said about why: its build URL, the pull or merge request
behind it (
change_url), the ticket ids it closes and one line of intent. The latest provide that carries any of them wins; a no-op re-provide of identical bytes only fills an empty one. References, never content: the ticket itself stays in the tracker. - Catalog context
-
What the catalog push records besides the periphery: the system's owner, description, source
location, links and tags. Shown on the graph's node panel and on the Producer and Consumer
pages; a tag also focuses the graph (
tag:<name>). One present-day fact per system, not tracked per stream. - Report scope
-
?scope=dev(default),main[@instant]or<branch>[@instant]on/reportand its variants: which graph a report describes. - Audit timeline
-
The log of every provide, require and administrative action, with a diff viewer and filters by
date, action, service and stream. For holders of the
view_auditpermission: the admin and viewer roles.
Credentials and integrations#
- Session
-
What
POST /auth/loginanswers and what the web UI sends: a token that expires with the session (7 days). Sessions can mint API tokens; API tokens cannot. - API token
-
A long-lived credential (
san_+ 64 hex characters) owned by one user, minted on the account page or withPOST /auth/tokens, shown once, with a mandatory expiry. What CI, scripts and AI clients send asAuthorization: Bearer. - Token scope
-
Decided when a token is minted, immutable afterwards.
fullmay do everything its owner may;read_onlymay read reports, versions, the update streams and the MCP endpoint, and is refused with403on every route that changes the catalog. - Webhook
-
A signed
POSTSanshain sends to a registered URL for every fact it records and every provide it rejects:version.published,provide.rejected,version.deprecated,dependency.recorded,branch.cut,catalog.recorded. Registered globally by an administrator, or per Producer and Consumer on their pages. - MCP
-
The Model Context Protocol endpoint
POST /mcp: seven read-only tools that let an AI assistant list and describe services, find an endpoint, read a spec, walk the graph, diff and blame versions. API tokens only, 60 calls per minute per token, 64 KiB per answer. - Developer mode
-
A local-only switch that bypasses authentication. It needs both the admin setting (or
SANSHAIN_DEV_MODE) and theALLOW_INSECURE_DEV_MODE=truesafety gate, and fails closed otherwise.
Checked against v2.6.0.