All docs

Docs · Core concepts

Operations

An operation is the unit of work in Thanks, Computer.

The contract is always the same:

  1. The event arrives as JSON,
  2. If the event resonates for the current step, the operations executes,
  3. The operation returns JSON,
  4. The TxCo “chassis” deep-merges into the shared document the event carries forward to the next step.
a simple hello world operation stack
input100hello_worldoutput

Each operation is gated by a resonator (its TXCL rule), so it only runs when its condition matches.

Operation execution takes a few different shapes, allowing you to run with or without existing infrastructure.

ShapeEXEC targetRunsReach for it when
Resonator-only(none)on chassis, quickestrouting, defaults, synthetic responses
Nano-opop://NAMEon chassis, nano-op, JS sandboxlogic runs in sandbox environment, no external libs needed
HTTP servicehttp(s)://…your service, any languageexisting services, heavy or stateful work, scale

Resonator-only — no code at all

The simplest operation does all its work in the chassis resonator:

WHEN @web.req.url.path == "/health"
EMIT .status = "ok", @halt = true

No dispatch, no deployment — the resonator rule itself shapes the flow. Use it for defaults, derived fields, routing, and answers that need no backend. Several built-in functions are available to handle common tasks like Base64 encoding.

Nano-op — EXEC "op://NAME"

A nano-op is JavaScript or TypeScript that runs inside the chassis’s sandbox — compiled to WebAssembly (Wasm), it is sandboxed (no filesystem, network, or ambient environment), no service to stand up:

import { op } from "@txco/op";

export default op(async ({ input }) => {
  return { tier: input.amount > 1000 ? "vip" : "standard" };
});

Drop classify.js in the same directory as its rule, reference it with EXEC "op://classify", and txco apply builds and ships it. Adding a nano-op costs kilobytes — the JS engine ships once with the chassis.

External HTTP call — EXEC "https://…"

For maximum flexibility and backwards compatibility, you can write operations using any HTTP handler in any language that supports JSON (JavaScript, Python, Java, Go, Rust, PHP, Perl, …).

// Node, no deps — a complete operation. Use your own framework if you prefer.
http.createServer((req, res) => {
  let body = "";
  req.on("data", (c) => (body += c));
  req.on("end", () => {
    const env = JSON.parse(body || "{}");
    res.end(JSON.stringify({ tier: env.amount > 1000 ? "vip" : "standard" }));
  });
}).listen(9000);

Point a rule at it — EXEC "https://api.example.com/enrich" — and its response merges into the flow like any other operation. WITH timeout = 2000 bounds the call; WITH secrets.headers.authorization.secret = "API_KEY" splices a stored credential into the request without writing it in the rule.

Start small, grow without rewiring

All three shapes speak the same JSON-merge contract. A step can begin life as a resonator-only stub, become a nano-op when it needs logic, and later point at a full service — without touching the rules around it.

During development: Mocks

There actually is a fourth type of operation, the mock. You can use mock files to simulate the response of a third party service during development so you can work on a single operation at a time without having to stand up the entire distributed stack.

Edit this page · View as markdown