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. Small enough to read in one sitting, and it expects to be edited.

pip install tablekit
tablekit init                      # writes table.json
python3 examples/demo_session.py   # a whole synthetic session + its report

The rule that governs the whole design

The table speaks English. Nobody at it learns a syntax.

Text RPGs solved this badly for forty years. Zork and Moria and everything after them handed you a verb list, because a parser in 1980 could not understand a sentence. That vocabulary was never a design choice — it was a workaround for a missing capability, and it is exactly what makes those games feel like operating a computer instead of sitting with someone who is running a world for you.

The capability is no longer missing. So an agent GM that asks people to learn commands has voluntarily reproduced the limitation and thrown away the only thing it has over a parser game.

Concretely, in this repo: there are no chat commands, no !tokens, no keywords, no "advanced mode". Whatever someone writes in the channel is dialogue. tests/test_no_player_commands.py enforces that, because a stated principle drifts and a test does not.

An earlier version of this kit got this wrong — it shipped a six-token feedback vocabulary. It was cut in 0.2.0 and the reasoning is preserved in tablekit/uxr.py.

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.

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? inferred from ordinary speech, then asked about at the close
out did any of it actually work? intent → payoff pairs

The uxr lane

This is the one that does not exist elsewhere, and the one the no-syntax rule shapes most. 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 quietly lost, whether a player got to do the thing their character exists for, none of it leaves a trace.

So it is captured two ways, both of them in plain English:

Inferred during play. "Can we get moving" is the signal. The agent GM is already reading every line; classification does not need a new interface, it needs the GM to record what it already understood. Six internal buckets — pacing, floor, comprehension, resonance, spotlight, continuity — never surfaced to anyone at the table. Every inferred signal stores the player's own words, so the inference is auditable by whoever was in the room.

Asked at the close. Two or three questions in your own words, the way any decent GM already ends a night. tablekit debrief prints them.

The second half is not optional politeness — it is the structural check on the first. A GM that does not notice friction cannot record friction, so inference alone inherits exactly the blind spots the lane was built to route around. An independent model pass over the same transcript (--source local) is the other check; where it and the GM disagree is itself the interesting part.

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 — 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 (5 signals)
  Patterns (>= 3 — worth acting on):
    - pacing ×3 — this stretch felt slow from that seat; seats: brae, rowan;
      beats 5, 6, 6 [dm/local]

## 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 ordering: the undeliverable cue is reported before the silence it caused. And note what is absent — there is no score at the bottom, and there is not going to be one.

Three things this kit will not do

1. Give players a command syntax. Above. It is a product non-goal, not a backlog item.

2. Let an inference accuse anyone. Signals classified from speech are advisory in every path and can never become a defect. Something a model thought someone meant does not get to be a finding.

3. State a rate from a handful of observations. Below three occurrences, the report lists individual moments with their beat numbers and refuses to describe a tendency. This is a correction of a real error: one player asking what a word meant was once generalised into "unfamiliar diction fails at this table", and their actual position was the opposite.

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 lanes, the event schema, and the provenance of every default
  • 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 describes the command surface — all of it operator-side, none of it touched by anyone at the table. tablekit schema prints the event schema, signal buckets 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.2.2.tar.gz (50.8 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.2.2-py3-none-any.whl (43.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for tablekit-0.2.2.tar.gz
Algorithm Hash digest
SHA256 2626db488c39d44694e400cd644bf9ab60de5e8773ec54d452843c7ec0893672
MD5 cf47b62ee7df2cb2f71cf8389d5e393d
BLAKE2b-256 cda25c950672f3e849d671181286862a4d3b10c8987665104f000ecdc06dc8fb

See more details on using hashes here.

File details

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

File metadata

  • Download URL: tablekit-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 43.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.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0d1dae04e3824727eac8cff35c33cc8f25619bab3dfbd077fa5c612dede75b11
MD5 34dfd12645848b984bc2bae23f30ebe3
BLAKE2b-256 da3f2f7177b55adc0f130409d5e7b891932272894dc2eef24be74ac48f581df0

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