Skip to main content

blackboardxray

Self-hosted observability for blackboardx runs. One server, one database, one interface. An application reaches it by naming an endpoint and a token, and nothing else about the application changes.

CI security PyPI Python License

A blackboard run is a set of agents writing to a shared board under an admission rule. When one goes wrong the board tells you what was written, and nothing tells you what the run did about it: who was notified, who acknowledged, what admission refused, or which delivery never arrived. This records that.

Two containers and nothing else. No cache, no queue, no object store, and no secret for you to generate.

Contents

Why it exists

blackboardx makes the record durable and leaves the run in the process. The store holds the regions, the contributions, the premise versions, the sequence, the two deadlines and the outcome. It does not hold who was notified, who acknowledged, what admission refused, or which delivery failed, and the library's logging rule forbids logging any of them on the grounds that the agent already saw them.

So the record is observable and the run is not. That is what this is for.

Run it

git clone https://github.com/MoeinRoghani/blackboardxray
cd blackboardxray
docker compose up -d

Open http://localhost:8900. The first screen makes your account, an organization, a project, and a key to send with. Everybody after you arrives by an invitation link, because this platform has no mail server and does not want one.

Two containers and nothing else. No cache, no queue, no object store, and no secret to generate: sessions are opaque identifiers held in Postgres and every credential is stored as a digest. Postgres is the only thing holding state, so it is the only thing to back up.

Without Docker:

pip install 'blackboardxray[server]'
createdb blackboardxray
export BLACKBOARDXRAY_DATABASE_URL=postgresql://localhost/blackboardxray
blackboardxray serve

Every environment variable, the proxy headers that matter, backup, upgrading and the volume ceiling are in docs/self-hosting.md.

Observe a run

from blackboardxray import Xray

xray = Xray(endpoint="http://localhost:8900", token="bxr_...")  # the key from setup

model = xray.create_model(
    board_id="incident-4471",
    store=SqliteStore("incidents.sqlite3"),
    regions=[Level("platform"), Premise("window")],
    premises={"window": ["20:00", "22:00"]},
    agents=[Agent(name="ocp", notify=investigate)],
    limits=RunLimits(wall_clock=timedelta(minutes=10), idle=timedelta(seconds=30)),
)

Every argument is the one blackboard.create_model takes and means the same thing. What comes back is the library's own model. The library is not modified and is not asked to grow a hook.

An agent deployed as its own service wraps its board instead:

board = xray.agent_board(BoardClient(base_url=..., board_id=..., agent="ocp"))

What is recorded

Ten kinds, in the blackboard's own vocabulary.

Kind When
run.opened A model was created, with its regions, premises and limits
agent.registered An agent joined, at creation or afterwards
write.admitted A level write passed admission and reached the board
write.refused A write was refused, with the cause and the rule's reason
write.conflicted A premise write named a version no longer current
premise.set A premise write reached the board
notification.dispatched A notification left for one agent
notification.acknowledged An agent reported it had stopped
notification.failed Delivery raised, so the agent never received it
run.closed The run closed, with its outcome and who did not finish

A contribution's content is recorded, truncated past 4kB. A deployment whose contributions may not leave the process passes content_limit=0, which records the size and the shape and none of the content.

Who can see what

An organization owns projects. A person is a member of an organization with a role, and a role on one project replaces it in either direction: it raises a member to admin on the project they run, and it is how somebody given none at the organization gets exactly one project and nothing else.

Role May
owner Everything, including deleting the organization
admin Projects, keys and people. Cannot touch owners
member Read every run, including what was written
viewer Read what happened, and not what was written
none Nothing, except a project they were given explicitly

A viewer is the one worth explaining. A contribution is your application's own data and may hold anything it is allowed to hold, so the lowest role that can be handed out sees that four kilobytes of an object were admitted at sequence nine, and not what was in it.

What the interface shows

blackboardxray serve serves the interface at the same address as the API.

Boards, at /p/<project>, is a chart of runs opened per interval over the record of them. Clicking a bar narrows the table to the runs that bar counted; the facet strip between them narrows by outcome, by agent, or to the runs an agent did not finish, and each facet carries the count it would leave. Selecting a board opens a panel beside the list with what happened inside it: which agent was refused, on which region, and what the rule said.

A board, at /p/<project>/boards/<board_id>, reads three ways. Graph draws what wrote to what and who was told, with a broken edge where a notification never arrived. Events is the same run as a table and is the record. Board is what was actually written. The run's own clock stays along the bottom of all three.

Every filter, the time window, the selected board and the chosen view are in the address, so a view is a link.

Reading needs an account. Ingestion needs a key. The two are separate doors: an application holds a key and may only write, and a person holds a session and may only read.

Development

make setup
make verify

make verify needs a database and skips every test that touches one without it, so name one:

createdb blackboardxray_test
BLACKBOARDXRAY_TEST_DSN=postgresql://localhost/blackboardxray_test make verify

examples/seed.py runs real models through the real client. examples/backfill.py posts a day of fabricated traffic over the ingest API, so the interface can be looked at at the volume it is for; it is a fixture and nothing in a deployment runs it.

Documentation

Self-hosting Every environment variable, proxy headers, backup and restore, upgrading, and the volume ceiling
Architecture The two halves, the wire between them, and what runs in the background
Decisions Why one database, why sessions rather than tokens, why links rather than email
Security How credentials are stored, what is in scope, and what this deliberately does not defend against
Contributing The change flow, the gates, and the two rules about a pull request body
Design system The token pipeline, the depth ladder, and why a screen may not set a value
Limits What the client does when the platform is down or slow

Status

Version 0.x. The public surface may still change, and a breaking change carries a ! and a migration note in its release. The wire format between the client and the server is versioned separately and decodes tolerantly in both directions, so a client and a server from different releases work together.

License

Apache-2.0. See LICENSE.

Metadata

Release files for blackboardxray 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for blackboardxray 0.1.0
File Size Uploaded
blackboardxray-0.1.0.tar.gz 636.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for blackboardxray 0.1.0
File Interpreter ABI Platform
blackboardxray-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.0 MB

Release files / blackboardxray-0.1.0.tar.gz

Download URL blackboardxray-0.1.0.tar.gz
Size 636.6 kB
Tags Source
SHA-256 checksum
How to use checksums
39d726fad3aca1712d82530239f1979ceac2ecb8d52bdca180add65486eac09a
BLAKE2b-256 checksum
How to use checksums
56f4244fde7932dcd0917820e17dbfddb9f2a4a1f4978fb3cd4b5af02679627c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / blackboardxray-0.1.0-py3-none-any.whl

Download URL blackboardxray-0.1.0-py3-none-any.whl
Size 398.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ee2bf3c26c103d0a3472cf4057ad26cc9a0bd977a2fbd33911562d7b2ba31d9d
BLAKE2b-256 checksum
How to use checksums
c3457c41635df394f1fbd06077ca4a2d9fc124f1e546cd97b5eb048efd5fcc6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.1

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page