Skip to content
ThinkWatch
Start typing to search the docs.
ThinkWatch Core · Crate layers

Crate layers#

ThinkWatch Core consists of seventeen crates and one binary, twcore. The workspace divides the crates in two: the four that ThinkWatch Enterprise depends on, and the crates of the gateway that twcore runs, which ThinkWatch Enterprise does not use. Within the second part, the crates are grouped by role.

tw-dialect · tw-guard · tw-breaker · tw-bedrock                      ← shared with ThinkWatch Enterprise
tw-types · tw-engine · tw-pricing · tw-yaml · tw-secret · tw-watch   ← domain logic
tw-api · tw-link                                                     ← control-plane contract
tw-config · tw-store · tw-observe                                    ← assembly
tw-gateway · tw-control                                              ← data plane / control plane

No crate depends on a group below its own.

GroupCrateRole
Shared with ThinkWatch Enterprisetw-dialectConversion of requests, responses and streams between Anthropic Messages, OpenAI Chat Completions, OpenAI Responses and Gemini; usage parsing
tw-guardOutbound redaction and restoration, inspection of the tool calls an upstream returns, and the content filter, with the settings, built-in rules, validation, rule listings and trials of all three
tw-breakerThe circuit-breaker state machine
tw-bedrockAmazon Bedrock on the wire: SigV4 signing, event-stream framing, addresses and the model catalog
Domain logictw-typesMessages for people: a stable code, its arguments and the English sentence
tw-engineThe routing rule engine and strategy groups
tw-pricingThe public price table, price sheets, and cost in three states: measured, estimated and unpriced
tw-yamlMinimal edits to YAML text that keep comments and layout
tw-secretEnvironment variable interpolation, credentials from commands, and secret masking
tw-watchDirectory watching with one signal per burst of changes
Control-plane contracttw-apiRequest and response types of the control plane, and a client
tw-linkThe handshake and encryption of the control channel (Noise NNpsk0)
Assemblytw-configConfiguration schema, loading and validation
tw-storeRequest history and runtime state on SQLite and the file system
tw-observeThe event bus
Data plane / control planetw-gatewayThe gateway’s HTTP server
tw-controlThe control-plane API over a unix socket, a loopback port on Windows, and the optional remote control port

Shared with ThinkWatch Enterprise#

ThinkWatch Enterprise depends on the first group and nothing else: format conversion and usage parsing (tw-dialect), the guards and their rules (tw-guard), the circuit breaker (tw-breaker) and Amazon Bedrock’s wire protocol (tw-bedrock). These four depend only on each other, which a test in tw-dialect enforces, and CI builds ThinkWatch Enterprise against every change to them. A component that only one product uses lives in that product’s repository rather than in Core.

Used by ThinkWatch Lite#

ThinkWatch Lite bundles the twcore binary of a Core release and compiles tw-api, tw-link, tw-types, tw-yaml, tw-guard and tw-watch from the same tag: the app and the binary speak one control-plane protocol, so both have to come from one commit.

Configuring AI clients to use the gateway, editing their MCP servers and scanning their configuration are part of the desktop app, not of Core. They change files on the machine the app runs on, which need not be the machine that runs core. Core only issues a client its own gateway key.

The single-machine implementation#

The assembly group and the data plane and control plane form the single-machine implementation: SQLite, the local control channel and the optional remote control port. They are intentionally not shared. Single-machine SQLite and multi-tenant Postgres differ too much for one abstraction to serve both.

Prices in tw-pricing#

tw-pricing embeds a pinned snapshot of a public price table, so that a fresh installation and a machine without network access can price requests. At runtime, the control plane refreshes the table once a day unless pricing.auto_update is false, and whichever copy is newer prices requests. Price sheets in config.yaml apply a multiplier, or prices per model, to the upstreams that select them.

A refresh or an edited price sheet changes the price of later requests, never of those already recorded. Each request stores its cost and where the price came from, so a figure can be explained afterwards. See The price list for how the snapshot is updated.

Last updated 2026-10-03 Edit on GitHub