The `.octonode` Config Reference
Canonical Octonode repository documentation.
The .octonode Config Reference
Authority depends on the deployment mode (see ADR 001). Direct CLI commands are file-authoritative:
.octonode is read and written in place. Server/Studio deployments are
store-authoritative for environments, node configuration, and workflow topology.
There, .octonode is a versioned import/export artifact: on startup a semantic
file revision is imported deterministically, with external changes winning for
previously imported records while Studio-only records remain in the store. It may be written in
YAML (.octonode or .octonode.yaml) or JSON (.octonode.json) — the
tooling round-trips either. A published JSON Schema (octonode.schema.json)
powers editor autocomplete and validation.
Ownership model (why two-way sync is tractable)
Every field has exactly one owner. No field is ever merged from two sides.
| Field | Owner | Written by scan? | Effect of editing |
|---|---|---|---|
nodes[].signature.* | Code | yes (replace) | drift — scan/validate flag it; code wins |
nodes[].id | Config (seeded by code) | seed once | rename rebinds identity |
nodes[].runtime.* | Config | never | changes process supervision (timeout, retries, exclusive async execution) |
nodes[].presentation.* | Config | never | visual editor only |
environments.* | Config | never | injected into node processes |
workflows[].* | Config | never | builds the runtime DAG (Phase 4) |
sources | Config | never | what scan probes |
scan writes only the signature subtree. Editing .octonode never rewrites
your source code — config→code means routing/runtime, not code generation.
Shape
apiVersion: octonode.dev/v1
metadata:
name: my-project
version: 0.1.0
# Project-wide defaults (optional).
defaults:
language: typescript # used by `octonode add` when --lang is omitted
# Commands `octonode scan` probes (via describe) to discover nodes.
sources:
- node nodes/validate.cjs
- node nodes/charge.cjs
environments:
dev: { vars: { LOG_LEVEL: debug } }
prod: { inherits: dev, vars: { LOG_LEVEL: warn } } # single-level inheritance
nodes:
- id: validate # stable identity; edges reference this
signature: # CODE-OWNED — generated by scan, read-only
language: typescript
command: node nodes/validate.cjs
inputs: { type: object, properties: { order: { type: object } } }
outputs: { type: object, properties: { valid: { type: boolean } } }
checksum: sha256:… # content hash, for drift detection
runtime: { timeout_ms: 5000, retries: 2 } # CONFIG-OWNED
presentation: { icon: shield-check } # CONFIG-OWNED
workflows:
- id: main
# Explicit membership list (optional). Nodes listed here are included in the
# workflow even if they have no edges yet (useful for isolated/root nodes added
# via `octonode add`). The scheduler reads this list together with the edges
# to build the DAG.
nodes: [validate, charge]
edges:
- from: { node: validate, output: valid }
to: { node: charge, input: valid }
# Workflow invocation form (source workflows project this from function params).
inputs: { type: object, properties: { order: { type: object } }, required: [order] }
# Fixed node inputs; applied after edges and before expressions.
bindings:
charge:
currency: { kind: literal, value: USD }
evaluations:
- id: accepts-valid-order
input: { order: { id: "A-1" } }
expect:
status: ok
outputs: { charge: { charged: true } }
test_workflows:
- path: tests/main.test.ts
runner: vitest
# Workspace-owned resources attached by stable id. Values and secrets stay out of Git.
attachments:
plugins: [postgres]
variables: [DATABASE_URL]
dataTables: [customers]defaults block
| Field | Type | Description |
|---|---|---|
defaults.language | "typescript" | Fallback language for octonode add when --lang is omitted. |
The block is optional; omitting it is equivalent to no default (the user must supply --lang).
workflows[].nodes — explicit membership
A workflow's nodes list declares which node IDs participate in the workflow.
It is CONFIG-OWNED and never written by scan.
- Nodes wired together by
edgesare automatically part of the workflow even without an explicit listing;nodesis only needed for nodes with no edges yet (e.g. immediately afteroctonode add). - Duplicate entries are silently de-duplicated.
octonode add --workflow <id>appends the new instance ID idempotently.
| Field | Type | Description |
|---|---|---|
workflows[].nodes | string[] | Explicit node membership; merged with the set derived from edges. |
workflows[].inputs and bindings
inputs is a JSON Schema for starting the workflow. bindings stores fixed per-node values as either { kind: literal, value } or { kind: symbol, symbol, value }. See workflow inputs and triggers.
Promise topology
Source workflows project Promise joins into workflows[].promises as { node, mode }.
Their indexed incoming edges preserve Promise member order. A control edge orders two
nodes without copying the upstream output into the downstream input. Both fields are
code-owned for source workflows; use normal data edges for hand-authored canvas workflows.
workflows[].evaluations — workflow test cases
Evaluations are CONFIG-OWNED cases that run through the same DAG scheduler as normal executions.
They inherit the workflow's visibility and are versioned with the project config. expect.outputs
is an exact terminal-output object; omit it to check only the run status.
| Field | Type | Description |
|---|---|---|
id | string | Unique case id within the workflow. |
description | string | Optional human-readable purpose. |
input | JSON | Input passed to every workflow root. |
expect.status | "ok" | "error" | "partial" | Expected run status; defaults to ok. |
expect.outputs | JSON object | Optional exact terminal outputs keyed by node id. |
judge.workflow | string | Optional related workflow that grades the target run. |
judge.rubric | string | Explicit criteria passed to the judge workflow. |
judge.threshold | 0..1 | Minimum numeric judge score; defaults to 0.7. |
workflows[].test_workflows — linked repository tests
Studio discovers conventional *.test.* and *.spec.* files automatically. Link the files
that verify a workflow explicitly so unrelated project tests do not inherit its visibility.
| Field | Type | Description |
|---|---|---|
path | string | Project-relative test file path. |
runner | "vitest" | "jest" | "playwright" | "promptfoo" | Installed test adapter used for this file. |
A judge workflow receives { rubric, threshold, target }, where target contains the workflow id,
case id, input, expected assertions, and full candidate run trace. Its terminal output must contain
either { score: 0..1, reason?: string } or { passed: boolean, reason?: string }.
Commands
| Command | Purpose |
|---|---|
octonode init [path] | scaffold a new config (--format json|yaml, --name, --force) |
octonode scan | code→config: probe sources via describe, write signatures |
octonode scan --check | CI gate: write nothing, exit non-zero on drift |
octonode validate | schema + structural checks (duplicates, drift, orphans, edges) |
octonode invoke <id> --env <e> | config→runtime: resolve a node, inject env + runtime, run it |
Studio's project Compile action runs source discovery, synchronizes code-owned signatures, then applies the same structural checks. Errors fail Compile; warnings remain advisory.
nodes[].runtime — process supervision
| Field | Type | Description |
|---|---|---|
timeout_ms | positive integer | Hard deadline for one attempt. |
retries | non-negative integer | Retry attempts after the initial attempt. |
retry_backoff_ms | non-negative integer | Base delay between retry attempts. |
concurrency | positive integer | Reserved per-node concurrency limit. |
async | boolean | Wait for running nodes, execute alone in this workflow run, then resume parallel work. |
The Code and Documentation tabs follow .gitignore and optional .octonodeignore rules. .octonodeignore
only adds exclusions; secret files, binaries, dependencies, build output, and .git are
always hidden from the browser editor. The Code tab keeps the source editor and compile workflow.
The separate Documentation tab lists non-code text files, starting at root README.md when
available, and supports creating, renaming, deleting, and editing them up to 2 MB. Documents
stay ordinary project files rather than nodes or config records, so Git and cloud snapshots
include the same files. Markdown preview is sanitized and does not auto-load local or remote
media, while JSON/YAML previews validate and format a read-only projection without rewriting
the source.
Drift & orphans
- Drift: a
signaturewhose stored content no longer matches what code reports (or whose checksum is stale from a hand-edit).scanrewrites it (code wins);scan --checkfails;validatewarns. - Orphan: a node whose
sourceis no longer discovered.scanmarkssignature.orphaned: truerather than deleting it (so it never silently drops human-authored topology). Remove it yourself once you're sure.