Skip to main content
WorkTruck’s shape is small on purpose. Every operation an agent performs maps cleanly onto eight entity types and one universal relationships table.

The eight entities

Temporal classes

WorkTruck tracks history at four different fidelities:
  • Bitemporal (People, Organizations, Notes) — both valid-time and system-time tracked. Every edit writes a history row; “what did this person look like on Tuesday at 3pm” is answerable.
  • Unitemporal (Tasks) — valid-time only. History rows on every edit; system-time of the edit isn’t preserved.
  • Type 0 (Events, Messages) — no history. Designed for high-volume streams where the cost of full history would dominate the table.
  • Event-log (Relationships) — insert-only. Updates and deletes are recorded as new rows with a kind discriminator.
The choice per entity is deliberate; see docs/schema-review/temporal.md for the rationale.

Relationships are first-class

Almost every meaningful connection in WorkTruck is a row in the relationships table — Person attends Event, Note is about Task, File attached to Message, Organization employs Person. The relationship’s relationship_type field is a typed enum; the matrix of which (from-entity-type, to-entity-type, relationship_type) tuples are allowed lives in internal/relationships/matrix.go as the authority, with a Postgres CHECK constraint as defense-in-depth. Agents query relationships in either direction — “all tasks about this Person”, “all Files attached to this Message” — without needing to know the underlying join.

Two write paths: API and worker

Agents write to WorkTruck two ways:
  1. Synchronous via HTTP / MCP / CLI — direct CRUD. Fast, immediate, used by the dashboard and ad-hoc operator tooling.
  2. Asynchronous via the worker — reconciler jobs (email → person, message → thread), scheduled agent runs, retention/cleanup. Worker is river-backed; jobs are durable.
Reads are always synchronous over the API or MCP.