Tricks

A trick is a TypeScript script the box owns, run with bbx trick <name>. It packages an operation the box repeats: a fetch, an export, a conversion, a search-and-summarize. Tricks live under src/tricks/scripts/<name>/index.ts and run as child processes of the engine with their own npm dependencies.

Every trick is a directory with an index.ts. A .ts file placed directly in scripts/ is not a trick and does not list. The box's src/tricks/scripts/AGENTS.md shows the directory layout and holds this box's own conventions for tricks.

Script interface

A trick is a standalone program. The engine provides context through the environment and the argument list:

import * as fs from "node:fs/promises";
import * as path from "node:path";

export const description = "Short description shown in bbx trick list";

const boxRoot = process.env.BBX_BOX_ROOT!;
const trickName = process.env.BBX_TRICK_NAME!;
const args = process.argv.slice(2);

const inboxDir = path.join(boxRoot, "_content/inbox");
console.log("Done!");

bbx trick reads the export const description line without executing the file, so keep it a plain string literal.

Use node:fs/promises and node:path for files. For card operations, run bbx commands through child_process; a trick does not import engine internals. The subprocess cwd is src/tricks/, so package resolution and relative imports of lib/ work without configuration. There is no build step.

Running

How the engine runs a trick

Facts a trick author needs and cannot see from inside the script:

Secrets

If the trick needs a credential, declare it in a secrets.json beside index.ts:

[{"name":"openai-images","reason":"image-generation","env":"OPENAI_API_KEY"}]

The boxholder supplies and grants the secret; you never see the value in the tree. bbx trick <name> resolves each declaration at launch and injects the value only into that trick process under the declared environment name. Every resolve is logged with the reason. A refusal or unreachable server is reported without the value; relay the message rather than trying a raw curl (which prints the credential into the transcript). Never write a resolved value to a file, an argument, or a log. How secrets are granted and why they never live in the box is in the agent guide's "API keys & secrets" section.

Dependencies and shared code

Install packages into the tricks directory, where every trick can import them:

cd src/tricks && pnpm add <package>

Put reusable helpers in src/tricks/lib/ and import them by relative path:

import { helper } from "../../lib/helper.js";

Keeping a trick small

A trick does one task. When a trick grows a second job, split it. When an operation is one-off, run it by hand instead.