Tablebox's programs
Tablebox runs five programs for every project. They connect to Relay as participants do and serve their own trees of paths, so an app uses them with the same calls it uses for everything else.
| Program | An app reads | to | Page |
|---|---|---|---|
| Aggregation | .aggregation/{name} |
merge what many writers write under {name} |
Aggregation |
| Persistence | .persistence/{path} |
keep {path}'s JSON saved and get the saved document |
Persistence |
| Egress | .egress/{source}/{dest} |
record {source} or send it to a streaming service |
Egress |
| Agent | .agent/{source} |
talk with an AI that hears {source} |
Agent |
| Ingress | (none) | publish a stream from streaming software at a path | Ingress |
Calling a program
Calling a program is reading a path in its tree: the first read starts it, every reader of the path shares it, and it stops 20 s after its last reader leaves (Aggregation also runs while a writer is there). A session whose subscribe patterns match the path may call it. Grant a tree as you grant its input: reading .persistence/{path} shows what {path} holds, and reading .egress/{source}/… sends {source} out of the project. A token with subscribe ** calls every program on everything under its root.
Trees seen from a root
A session rooted below the project root at R reads .aggregation/{rest} as the project's .aggregation/{R}/{rest}, and the same for .persistence, .egress and .agent; a session rooted at the project root reads them as they are. So an app uses the same paths at any root, and two roots never share a program's output. These trees are read-only: only the program writes there.
Variables
The keys and destinations the programs need are the project's environment variables, set on Console's Variables screen or through the management API. Values are write-only. Changes reach the programs within 5 s; each program's page says what it does while one it needs is missing.
| Program | Variables |
|---|---|
| Aggregation | Persistence's storage variables, for the merged document |
| Persistence | STORAGE_BUCKET, STORAGE_ACCESS_KEY_ID, STORAGE_SECRET_ACCESS_KEY, STORAGE_ENDPOINT, STORAGE_REGION, STORAGE_PREFIX |
| Egress | EXPORT_{NAME}_URL for each streaming destination, and the storage variables for recordings |
| Agent | AGENT_PROVIDER, OPENAI_API_KEY or GEMINI_API_KEY, AGENT_MODEL, AGENT_VOICE, AGENT_INSTRUCTIONS, AGENT_TOOLS |
| Ingress | None |
Refusals and status
A program refuses a request or a track with the serving codes: bad-request, missing-variable, failed or too-large. A refusal carries only its code, so Egress and the Agent also publish a status.json track, a JSON snapshot with state and, when something went wrong, code and message (naming a missing variable, for example).
How they run
- Programs number their groups by the time they start, in milliseconds since the Unix epoch, so a reader that reads again after another instance takes over gets groups that follow those it had.
- Each project is served by one instance of each program at a time, and instances split the projects among them. When one stops, its reads end and reading again reaches the instance that takes over; each program's page says what that loses. Ingress takes any stream on any instance.
- While Manager is down, the programs keep working with the last variables they read.
To write a program of your own, serve a prefix of your paths with the SDK (Serving).