The evidence graph of an Arkitekt hub: the graph that ties samples,
images and measurements together. It does not store answers ("this cell is an AIS"). It
stores who claimed what, when, through which app and on what evidence, and lets each graph
decide which of those claims it shows. It is registered as live.arkitekt.kraph and has a
python client, kraph.
Three layers, in the order data moves through them:
| Layer | What it is | Code |
|---|---|---|
| The log | Every claim anyone records: this exists, these two are the same, this measured 45.2, this no longer exists. Claims are appended, never edited or deleted. The log is the source of truth. | evidence/ |
| The view | A Graph and its categories. Each category has a rule that says which claims it admits. Nobody writes "into" a graph: a claim names a word, and a view can be declared over history it did not witness. |
core/ |
| The projection | Each view's drawing of the log, in ordinary Postgres tables with a SQL/PGQ property graph per view. It is a cache: it can be dropped and rebuilt from the log. | graph_engine/ |
api/ holds the GraphQL layer over all three.
GraphQL is served at /graphql (HTTP and WebSocket), with the SDL at /schema. The SDL is
also committed as test.graphql, and a test holds the two equal.
| Operations | What they do |
|---|---|
assert…Exists, assertSameInstance, assertDifferentInstance, assertParticipation, assertMetricValues |
Record a claim. A write returns the act it recorded. |
retract…, supersede…, attest… |
Claims about claims: withdraw one, replace one, vouch for one. |
createGraph, create…Category, createTerm |
Declare a view and its rules. |
nodes, node, entities, structures, relations, metrics |
Read a view. |
assertions, changes, standings, instance, link |
Read the log. |
createGraphTableQuery, renderGraphTable, createScatterPlot |
Saved table queries over a view, and plots of them. |
assertionRecorded (subscription) |
Each claim as it is recorded. |
Declared in kraph_server/contract.py:
- Scopes:
kraph_read,kraph_write,kraph_query,read,write. - Roles:
admin,user,editor,viewer. - Needs: tokens issued by lok, and the storage kinds
media,zarrandbigfile.
It has no peers. Other services' objects are named in claims by their structure identifier
(@mikro/roi), not reached over the network.
The image is jhnnsrs/kraph. Started with no command it only says what it is; to run it:
arkitekt-service run migrate # once per release: wait for the database, apply migrations
arkitekt-service serve # serve on :80 (daphne)
arkitekt-service standalone # both, for one image run on its ownEvery write draws inside its own request. What a request could not finish is finished by a
later pass (manage.py reproject --incremental --all). Nothing runs that pass on a timer
at the moment: the runner that did was a second process of this image and is gone, and the
pass is to become a rekuest worker. Until then it is run by hand, or by whatever schedules
it.
arkitekt-service debug migrates and serves with Django's autoreloading server, for development.
It needs PostgreSQL 19 (for SQL/PGQ), Redis and an S3 object store.
The service reads config.yaml, or the file named by ARKITEKT_CONFIG_FILE; any value can
be overridden by an environment variable (POSTGRES__HOST). python manage.py validate_settings prints the configuration as the service reads it, with secrets redacted.
See CONFIG.md for every value.
uv sync
uv run pytest # everything, about 2½ minutes
uv run pytest tests/guards # no database, secondsThe suite runs against a real stack, brought up by dokker
from tests/integration/docker-compose.yaml: Postgres 19, Redis and seaweedfs, on ports
Docker picks. It needs a running Docker daemon. The suite is laid out by the property of the
model each test holds; tests/README.md is the map.
- docs/BIOLOGIST.md: why an evidence graph, for the people who use one.
- docs/EXAMPLE.md: one lab's schema, and what it makes of the log.
- docs/VOCABULARY.md: one word per concept, sorted by layer.
- docs/LOG.md: what a claim can say. The current-state document.
- docs/RULES.md: how a category decides which evidence it shows.
- docs/REMATERIALIZATION.md: when a vertex is redrawn, and by whom.
- docs/rfcs/: the design decisions, each with its status.
- docs/ARCHITECTURE.md: historical; the reasoning that led here.
Releases are tags: a push to main cuts a stable version, a push to next a release
candidate. Each one publishes jhnnsrs/kraph under its version (X.Y.Z, X.Y, X), plus
latest from main and next from next. The version in pyproject.toml is a
placeholder. Release notes are on
GitHub Releases; CHANGELOG.md is
frozen.