Octonode Playbook

Development — build, test, run

Canonical Octonode repository documentation.

Development — build, test, run

Build & test (Node ≥ 24, Yarn 4)

yarn install            # workspace links + deps
yarn build              # tsc -b across all packages (project references; only changed pkgs recompile)
yarn rebuild            # tsc -b --clean && tsc -b   (when references get stale)
yarn test               # vitest run
yarn test:watch         # vitest (watch mode)
  • The engine is TypeScript on Node ≥ 24. This repo runs Node 24, which cannot execute .ts directly — for the runtime/CLI always run from built JS (packages/*/dist), not source.
  • Run the CLI from the build: node packages/cli/dist/index.js <command>.
  • Tests run on Vitest. vitest.config.ts aliases each @octonode/* package to its src/index.ts and transpiles on the fly, so unit tests need no yarn build and import source directly. Add tests/*.test.ts that import from @octonode/*. Tests that spawn a process (such as MCP and CLI subprocess tests) still launch built dist binaries — keep those dist paths, and yarn build before running them.

Running the app (server + Studio)

Two processes. The server owns the engine; Studio is a Vite client that proxies to it.

yarn build                                                            # build packages first

# 1. API + SSE server on :4000 (point it at a demo project)
node packages/cli/dist/index.js serve --config examples/workflows-demo/.octonode.yaml

# 2. Studio dev server on :5173 (proxies /api and /ws → localhost:4000)
yarn workspace @octonode/studio dev

Open http://localhost:5173. If apps/studio/dist exists, octonode serve will also serve the built UI from its own origin on :4000 (single-origin production mode). API reference: Swagger UI at http://localhost:4000/api/docs.

The repository-owned Playbook can run locally through the OpenNext Cloudflare adapter or deploy to the Worker configured in apps/playbook/wrangler.jsonc:

yarn workspace @octonode/playbook preview
yarn workspace @octonode/playbook deploy

The private coding-assistant process is separate and is never called by Studio directly:

export OPENAI_API_KEY="..."
export OCTONODE_CHAT_MODEL="..."
export OCTONODE_CHAT_SERVICE_TOKEN="..."
export OCTONODE_API_URL="http://127.0.0.1:4000"
yarn workspace @octonode/chat-service start

It binds to 127.0.0.1:4101 by default. /v1/runs accepts only the server-to-service bearer plus a separate project-scoped caller token, rejects browser origins, and streams normalized NDJSON. Readiness performs an Octonode MCP tool/resource handshake without calling OpenAI. Configure the Cloudflare backend with OCTONODE_CHAT_SERVICE_URL and the same OCTONODE_CHAT_SERVICE_TOKEN; neither value is exposed to Studio.

Node process execution is a trusted local-profile capability. A production server accepts authenticated API traffic but rejects node invocation, workflow runs, and native materialization with 503 rather than launching a host child process. Deploy runnable production workflows only through a sandbox-backed worker.

Before opening a PR

  1. yarn build is clean.
  2. yarn test passes — add tests for new behavior.
  3. node packages/cli/dist/index.js scan --check --config <touched example> passes (CI drift gate).
  4. If you touched the IPC contract or config shape, update docs/ and octonode.schema.json.
  5. If you changed a server route's request/response shape, regenerate the client (yarn workspace @octonode/studio openapi) and commit apps/studio/openapi.json + apps/studio/src/api/gen/. See api-codegen.md.
  6. If you added or changed a Studio component, it has a *.stories.tsx and yarn workspace @octonode/studio build-storybook is clean.

Deployment validation, canary promotion, release evidence, and rollback follow the release contract.

Quick smoke test

CLI="node packages/cli/dist/index.js"
CFG="--config examples/workflows-demo/.octonode.yaml"
$CLI scan $CFG
$CLI run etl $CFG                                  # TypeScript workflow ⇒ {"load":{"loaded":2}}
$CLI run fan-out-fan-in --input '{"n":5}' $CFG     # parallel branches ⇒ {"combine":{"sum":25}}

On this page