Custom Code Workflow

> The fastest Brickr custom code loop is: edit locally, test locally, sync shared assets, publish to dev, validate in the Builder, then promote to prod.

This page focuses on the practical authoring loop rather than the API surface. If you need command syntax or SDK references, read CLI and SDK first.

1. Run brickr dev. 2. Edit a node in src/nodes. 3. Watch the local output, logs, and generated test values. 4. If you changed enums, structures, or secrets, run brickr assets sync. 5. Publish with brickr deploy dev. 6. Open the Builder and test the dev version of the node in a real flow. 7. Promote with brickr deploy prod when the behavior is ready for production.

Project conventions that matter

File naming

Brickr only discovers node files that match:

  • src/**/*.br.ts
  • src/**/*.br.js

If you create src/nodes/send-email.ts, Brickr ignores it. If you create src/nodes/send-email.br.ts, Brickr loads it.

One node per file

Keep each file focused on one default-exported node definition. This keeps selector matching, source control, and debugging simple.

Stable nodeKey

Treat nodeKey like an API name. You can rename the Builder label later, but changing nodeKey creates a new identity from Brickr's point of view.

Local authoring

Start watch mode

brickr dev

This gives you a terminal loop that:

  • scans the current project for .br.ts / .br.js files
  • runs each node locally
  • prints generated inputs
  • prints returned output
  • shows any ctx.log(...) calls
  • reruns on file changes

For focused work on one node:

brickr dev my-node

Use the most specific selector you have, especially once the project grows.

Write code for the deployed runtime, not only for local dev

brickr dev is convenient because it runs on your machine, but the deployed contract is stricter. When you write code nodes, optimize for the cloud runtime first:

  • assume Worker-style execution, not a Node.js server
  • assume no direct access to the raw execution-engine env
  • assume workspace secrets must come through ctx.secret(...)
  • assume shared schemas should come through Brickr enums and structures

This prevents the classic mistake where code works in local dev only because it accidentally depends on a local-only environment detail.

If you plan to call external services from code, validate that node in the workspace dev channel early instead of assuming that anything which runs locally is automatically portable.

Portable code checklist

Before publishing, the safest custom code node looks like this:

  • all pins are declared explicitly
  • output keys exactly match the declared outputs
  • secrets are read via ctx.secret(...)
  • shared object types use t.struct(...)
  • shared enum values use t.enumValue(...)
  • brickr.config.ts contains the matching enum / structure / secret definitions
  • the node does not depend on Node.js-only APIs

If you want the Builder, the SDK, and the runtime to agree with each other, the node definition and brickr.config.ts should be treated as one unit in code review.

Designing local-friendly nodes

Because brickr dev auto-generates inputs, your nodes are easier to test if you define sensible defaults:

inputs: {
  baseUrl: t.string().default("https://example.com"),
  timeoutMs: t.number().default(5000),
  enabled: t.boolean().default(true)
}

Benefits:

  • local runs are immediately meaningful
  • output is easier to inspect
  • the Builder gets better default behavior too

If a pin has no default, Brickr falls back to a type-based placeholder. For complex nodes, that often means {}, [], or null, which may not be enough for a useful run.

If a node depends on specific object shape, define that structure in brickr.config.ts and set a realistic input default where possible.

Handling secrets cleanly

Use workspace secrets for real credentials and local environment variables for brickr dev.

Typical pattern:

1. Create the workspace secret:

brickr secret create

2. Reference it in code:

const apiKey = ctx.secret("OPENAI_API_KEY");

3. Export it from brickr.config.ts if you want the secret definition to be code-managed:

import { defineSecret } from "@brickr/sdk";

export default {
  projectName: "main",
  enums: [],
  structures: [],
  secrets: [
    defineSecret({
      name: "OPENAI_API_KEY",
      description: "Workspace key for AI requests"
    })
  ]
};

4. Set the matching environment variable locally before running brickr dev.

If the environment variable is missing, local execution fails fast instead of silently returning bad output.

Managing shared types in code

If multiple nodes need the same enum or structure, keep it in brickr.config.ts and sync it explicitly:

brickr assets sync

Do this whenever you change:

  • enum values
  • structure fields
  • code-managed secret definitions

brickr status warns when Brickr detects drift between code-managed assets in your workspace and the local config.

This is what makes the docs, Builder, and runtime line up cleanly for both humans and AI agents. Instead of guessing object shapes or secret names from free text, an agent can load:

  • the node pin contract
  • the synced enum definitions
  • the synced structure definitions
  • the named secret definitions

and generate correct code against those sources of truth.

Publish flow

Publish to dev first

brickr deploy dev

This uploads the latest local node bundles and manifests to your workspace dev channel. At this point the Builder can use and test the latest version.

Validate in the Builder

After a dev publish:

1. Open the Builder 2. Find the node by category or search 3. Add it to a real route or function 4. Test the surrounding flow 5. Verify real inputs, outputs, and runtime behavior

Local tests are fast, but Builder tests still matter because they exercise the node inside an actual Brickr flow.

Promote to production

brickr deploy prod

This promotes the current dev versions to production. Do not skip the dev step if you care about stable rollout discipline.

Useful inspection commands

See what is deployed

brickr status

Good for:

  • confirming the linked workspace
  • checking dev/prod versions
  • spotting asset drift

List node versions only

brickr nodes list

Useful when you want the compact deployed-state view without the rest of the project metadata.

Common failure cases

"No workspace connected. Run: brickr init"

The current directory is not linked. Run:

brickr init

or reconnect an existing project with:

brickr link

"No .br.ts / .br.js nodes found"

Brickr did not find any matching node files. Check:

  • the file is inside src/
  • the filename ends in .br.ts or .br.js
  • the module default-exports defineCodeFunctionNode(...)

Missing local secret

If ctx.secret("NAME") fails during brickr dev, set the matching environment variable:

export NAME=value
brickr dev

In deployed code, do not replace this with process.env.NAME. The correct production path is still ctx.secret("NAME").

Node selector is ambiguous

Your brickr dev [node] selector matched more than one node. Use the exact nodeKey or a more precise filename.

Asset drift warning

If brickr status warns about drift, Brickr detected that a code-managed enum, structure, or secret was changed in the workspace outside your current local source. Re-sync the intended local state with:

brickr assets sync

Local code works, deployed code does not

Usually this means the node accidentally depended on something local-only. Check:

  • did you use process.env instead of ctx.secret(...)?
  • did you assume access to raw Worker bindings or internal env values?
  • did you depend on Node.js-only APIs?
  • did you depend on runtime-heavy globals such as fetch() without validating the deployed dev version?
  • did you change enums or structures locally without syncing them?

Team workflow recommendations

  • Keep one Brickr project per logical node package or workspace.
  • Review node source and brickr.config.ts together in pull requests.
  • Use local defaults so teammates can run brickr dev without reconstructing every input manually.
  • Keep secret names stable across environments.
  • Promote to prod only from tested dev versions, not directly from untested local edits.
  • Prefer explicit, machine-readable contracts over implicit conventions so AI tooling can generate correct nodes consistently.

A complete example sequence

npx brickr
brickr dev
brickr assets sync
brickr deploy dev
brickr status
brickr deploy prod
brickr update

What's next?

| Topic | Description | |-------|-------------| | Overview | Architecture and lifecycle | | CLI | Command reference | | SDK | Node and asset authoring API |