Skip to main content

Run a tabletop game where some seats are AI agents — transport, session ledger, and QA/QC/UX instrumentation for hybrid tables.

Project description

table-kit

Run a tabletop game where some of the seats are AI agents — and find out afterwards how it actually went.

Three deterministic referees already exist for the rules of such a table: srdcheck for rules verdicts, charactercheck for character sheets, dmcheck for table conduct. They are libraries. The thing that makes them a table — the chat transport, the session file, the game state, and the instrumentation that turns an evening into something you can learn from — is what this repo is.

It is an example, not a framework. It is small enough to read in one sitting and it expects to be edited.

pip install tablekit
tablekit init                 # writes table.json
tablekit markers              # the card you paste at the table
python3 examples/demo_session.py   # a whole synthetic session + its report

The problem it solves

Running a hybrid table works fine for about twenty minutes. Then the specific failures start, and every one of them is invisible while it is happening:

  • A cue that is never delivered. Agent chat bridges commonly drop bot-to-bot messages that lack a literal mention. You address an agent seat by name, the message posts, the API returns 200, and the seat never receives it. Nothing errors. You conclude the agent is thinking.
  • A seat nobody addressed for forty minutes. Agents will happily carry a scene to its climax while a human player waits for an opening that never comes. Read the transcript afterwards and it looks like a good scene.
  • A roll called and never consumed. Someone rolls, the number lands in chat, the moment moves on, and the outcome is never narrated.
  • A ledger only the GM is checking. Every player who benefits from an error has an incentive to say nothing about it.

And underneath all of those, the real one: a transcript of a great session and a transcript of a session everyone endured look about the same. Whether a description landed, whether someone was bored, whether a player got to do the thing their character is for — none of it leaves a trace.

What it does

Everything a session produces goes into one append-only JSONL file, which is simultaneously the play ledger and the telemetry stream. dmcheck can be pointed straight at it, with no export step.

Four lanes of instrumentation, plus outcome pairs:

lane answers how
qa did the machinery work? automatic
qc was the refereeing correct? automatic
ux what did the seat's evening look like? automatic
uxr how did it feel from a seat? players type one token
out did any of it work? intent → payoff pairs

The uxr lane is the one that does not exist anywhere else. Six markers, typed inline in chat, no interruption to play:

!huh    I did not follow that            !drag   this is slow for me
!wait   I wanted in, the moment passed    !mine   I got to do my thing
!yes    that landed                       !off    that contradicts something

They cost nothing to drop mid-scene, they anchor to the beat that caused them, and they turn into user stories in the report:

• As brae, I wanted to follow the scene, but something in it did not parse (beat 6).
    they said: "what's a gorse"
    reacting to: "Inside, thirty-one cuts in the doorframe, and the rope is still..."

The report

tablekit report

Defects first, then what the seats said, then whether the craft moves worked, then the shape of the evening, then whether the plumbing held.

## Defects
  ✗ undeliverable_cue: beat 4: cue addresses agent seat 'Vesh' but does not
    contain its literal mention <@999...> — likely to be dropped in transit
  ✗ seat_quiet: Vesh has not said anything for 49 minutes and has not been
    checked on

## From the seats (8 markers)
  Patterns (>= 3 reports — worth acting on):
    !drag ×3 [pacing] slow for me right now — seats: brae, rowan; beats 6, 7, 7
  Individual moments (below 3 — a moment, not a tendency):
    !yes ×2   !mine ×1   !huh ×1   !off ×1

## Did it work (outcome pairs)
  cue        3/4 good  (75%)  median 60.0s
  roll       0/1 good  (n=1 — too few to state a rate; counts shown instead)

Note the order: the undeliverable cue is reported before the silence it caused. And note what is missing — there is no score at the bottom, and there is not going to be one.

Two rules this kit will not bend

1. A marker is evidence for a pattern, never a verdict on a beat.

This is a correction of a real mistake. One player asking "what's a gorse" was once read as "unfamiliar words fail at this table," and the rule written from it was wrong — their actual position was "I like the new words, sometimes I will have to ask." One report of friction tells you a moment had friction. It does not tell you the cause and it certainly does not generalise to a preference. So anything below three occurrences is reported as individual moments with their beat numbers, never as a rate or a tendency.

2. Ambiguity produces silence, not an accusation.

Every check requires positive evidence. Silence from the GM is not a finding, because a GM deliberately yielding the floor and a GM who has wandered off look identical in a log — and at professional tables, the yielded floor is the common case by a wide margin. A checker that cries wolf during play gets ignored inside twenty minutes, and then it is just noise with a maintenance cost.

Findings come in two severities and the difference is load-bearing: defects are boundary crossings (pass/fail, worth interrupting for); attention items are dosage readings (real signal, no boundary crossed).

Layout

tablekit/        the Python package — events, config, lanes, report, CLI
transport/       Discord gateway listener (JSON out; knows nothing of the schema)
engine/          optional boardgame.io combat state: initiative, HP, seeded dice
bootstrap/       a first-session kit for an agent about to GM for the first time
examples/        a full synthetic session you can run right now
docs/            INSTRUMENTATION.md is the one to read

Exit codes

Same convention as the sibling projects: 0 clean, 1 findings worth looking at, 2 refused. Exit 2 is an honest refusal — bad input, or not enough happened to say anything — and it is deliberately distinct from "the session was fine."

Docs

  • docs/QUICKSTART.md — a table running in about ten minutes
  • docs/INSTRUMENTATION.md — the four-lane contract, the event schema, and what every default was derived from
  • docs/TRANSPORT.md — mandatory mentions, the relay tax, cursor ownership, and the other things that cost an evening to learn
  • bootstrap/CORE.md — if an agent is about to GM for the first time, this is the page to hand it

For agents

tool.json at the repo root describes the command surface. tablekit schema prints the event schema, pair kinds, marker vocabulary and exit codes as JSON. The session file is JSONL with one object per line and a documented type registry; reading it needs no library.

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tablekit-0.1.3.tar.gz (43.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tablekit-0.1.3-py3-none-any.whl (38.5 kB view details)

Uploaded Python 3

File details

Details for the file tablekit-0.1.3.tar.gz.

File metadata

  • Download URL: tablekit-0.1.3.tar.gz
  • Upload date:
  • Size: 43.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for tablekit-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a29136c9ba087acbd2a78e1e38c628e798345bff75d40918dc1f4b6fcd57b35b
MD5 a9ff2213222196e9a21454535edaec38
BLAKE2b-256 38d50d18344a1c4d38a20b35d4345ed68be48591a19f858ae6ac161fa9d0b48b

See more details on using hashes here.

File details

Details for the file tablekit-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: tablekit-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 38.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for tablekit-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 8414fba181a17e35487cc8b71e511a509b98c64dac6398261b17b27ad85cca41
MD5 79258366ee161b6fedb4b3f85d89caa3
BLAKE2b-256 de55d76e3b8d6298efeb8e2dd3d80179a8c3c96ca8498902eb6f1245e9f5da04

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page