CLI
The octo command: run, invoke, eval, schema, and version.
The octo binary starts integrations, calls flows directly, evaluates CEL
expressions, and emits the capability catalogue the editor and documentation
tooling consume.
octo — run and invoke octo integration flows
Usage:
octo [run] --config <path> [--watch] Start connectors and flows (default)
octo invoke --config <path> --flow <name> [--data <json>] [--vars <json>]
Call one flow and print its result
octo eval --expr <cel> [--data <json>] Evaluate a CEL expression and print the result
octo schema [--out <path>] Print the editor capability schema as JSON
octo version Print the version and build date
octo --help Show this helpFlags accept one or two dashes: --config and -config are equivalent.
Running octo with no arguments prints the help page above.
Subcommands
| Subcommand | Purpose |
|---|---|
run | Start the configured connectors and flows until interrupted (the default subcommand). |
invoke | Load a config, call one flow by name with a JSON body, and print its result. Use --break-at to stop at a block and inspect the message there. |
eval | Evaluate a CEL expression against an ad-hoc message, without a config. |
schema | Emit the capability catalogue (blocks and connectors) as JSON. capabilities is an alias. |
version | Print the release version and build date. |
octo run
Starts every connector and flow declared in the config and keeps them running
until the process receives SIGINT (Ctrl-C) or SIGTERM. run is the default
subcommand, so octo --config app.yaml is the same as
octo run --config app.yaml.
octo run --config samples/hello-world.yaml| Flag | Type | Default | Description |
|---|---|---|---|
--config | path | (required) | Path to the runtime config: a YAML file or a directory. |
--watch | bool | false | Reload the runtime when the config changes. |
--storage-dir | path | ./octo-store | Directory the object store is serialized into, so objects survive a restart. An empty value keeps the whole store in memory. Volatile and secret objects are never written there. |
--observability | bool | true | Serve liveness and readiness probes on the admin port. --observability=false binds nothing. |
--observability-addr | address | :39999 | Admin listen address for the probes and metrics. An address already in use is logged and the run continues without them. |
--metrics | bool | false | Also serve Prometheus metrics at /metrics on the admin port. |
--metrics-blocks | addresses | (none) | Comma-separated block addresses to add per-block timings for, or * for every block. |
--traces | bool | false | Record a trace of every message. Development feature with significant overhead. |
--traces-blocks | addresses | * | Comma-separated block addresses to trace, or * for every block. |
--traces-file | path | (auto) | Where the standalone runtime writes its JSONL trace. Defaults to octo-trace-<time>-<pid>.jsonl in the working directory. |
--traces-bodies | bool | true | Include message bodies in trace records. |
--traces-vars | bool | true | Include message variables in trace records. |
--traces-max-payload | bytes | 32768 | Drop a captured body or variable map larger than this. |
--traces-buffer | int | 4096 | How many records to queue before dropping. |
These configure the observability runtime service,
which serves on a port of its own, separate from any http connector. Each flag
defaults to the environment variable of the same name (see
below), so passing the flag always wins.
--metrics exports per-flow rate, errors and duration, the in-flight count per
flow, and the Go runtime and process collectors. It is off by default because
per-flow accounting is real work on the flow's own goroutine. --metrics-blocks
adds per-block timings for the blocks you name, in the same address grammar
--spies accepts:
octo run --config app.yaml --metrics \
--metrics-blocks 'orders.charge,orders.fanout[audit].log-it'Metrics tell you a flow is slow. --traces tells you what happened to one
message: every flow it entered, every block it passed through, the model turns
an agent took, joined by one id that survives flow-refs, splits, aggregates and
the hop between processes.
octo run --config app.yaml --traces --traces-file /tmp/run.jsonl
jq -c '{seq,kind,traceId,path,durationNs}' /tmp/run.jsonlTracing is a development feature, and the run says so at startup. With the defaults it records two events per block per message and marshals the payload for each, on the flow's own goroutine: around 700ns and 30 allocations per block, against 15ns and none when payload capture is off. See Tracing.
Per-block timings are taken on the flow's own goroutine, so they land on the
message's critical path. The counters are exact (nothing is queued or dropped, at
any load) and blocks you did not name cost one comparison each. * watches every
block in every flow, which makes it a debugging tool rather than a steady-state
setting.
When --config points to a directory, every .yaml/.yml file directly in it
(sorted by name, subdirectories ignored) is loaded and merged into one config.
The config's directory also becomes the resource root that relative resource
ids (templates, env files) resolve against.
Files ending in _test.yaml are skipped. orders_test.yaml is a test suite
for the flows in orders.yaml, the way orders_test.go tests orders.go.
Once every connector and flow has started, the runtime prints a ready banner to stdout:
time=... level=INFO msg="starting runtime" version=0.11.7 connectors=1 flows=1╭────────────────────────────────────────────────╮│ 🐙 octo v0.11.7 is up and ready to roll! 🐙 ││ 1 flow · 1 connector serving │╰────────────────────────────────────────────────╯Watch mode
With --watch, the runtime watches the config path (and the .env files it
consults) and rebuilds on every change: the current generation is stopped, the
config is reloaded, and a new generation starts. Failures are not fatal. A config
that fails to load, build, or start logs an error and waits for the next change.
Runtime services (connections, leases) are built once and reused across
reloads.
octo invoke
Loads a config, starts the flows in invoke mode (sources are not started, so no ports are bound and no schedules fire), calls the named flow once with the given body, prints the result message as JSON on stdout, and exits.
octo invoke --config samples/hello-invoke.yaml --flow greet --data '{"name": "Ada"}'{"event_id":"5c12a0e3f47b4d19a6c8f0b21d3e4a97","body":{"greeting":"hello, Ada!"}}The result is the whole message (event_id, variables, body), not the body
alone, because the variables a flow builds up with set-variable, enrich or
foreach are as much its result as the payload. variables is omitted when the
flow set none. To pipe just the payload onward:
octo invoke --config orders.yaml --flow orders --data '{"orderId": 42}' | jq '.body'| Flag | Type | Default | Description |
|---|---|---|---|
--config | path | (required) | Path to the runtime config (file or directory). |
--flow | string | (required) | Name of the flow to invoke. |
--data | JSON | stdin | JSON request body. When omitted, piped stdin is read instead. |
--content-type | MIME | (none) | Treat --data as a raw body of this type instead of JSON. See Raw bodies. |
--vars | JSON | (none) | JSON object seeding the message variables. |
--storage-dir | path | (in memory) | Directory the object store is serialized into. Unlike octo run this defaults to an in-memory store, so repeated invokes are reproducible; pass it (or set OCTO_STORAGE_DIR) to read or seed the objects a run left behind. |
--timeout | duration | 30s | Maximum time to wait for the flow (Go duration, e.g. 10s, 2m). |
--break-at | address | (none) | Run until this block, print the message it produced, and stop. See Breakpoints. |
--spies | addresses | (none) | Comma-separated blocks to record every message that crosses. See Spies. |
--mocks | JSON | (none) | Blocks to answer for instead of running. See Mocks. |
--run-debug-config | path | (none) | A file holding the whole run. See Debug config. |
--envelope | bool | false | Always print the outcome envelope, reporting a flow failure in it rather than exiting non-zero. |
--envelope-out | string | (none) | Write the envelope to this file instead of stdout (implies --envelope). Use it when the flow itself prints. |
--traces | bool | false | Record a trace of the run: the message entering and leaving every block. |
--traces-file | path | octo-trace-<time>-<pid>.jsonl | Where the trace is written. The other --traces-* flags apply too. |
The body can also arrive on stdin. --data and a pipe are interchangeable:
echo '{"name": "Grace"}' | octo invoke --config samples/hello-invoke.yaml --flow greet{"event_id":"9f1c3b0e7a5d4e2b8c6f0a1d2e3f4b5c","body":{"greeting":"hello, Grace!"}}Stdin is only read when it is piped or redirected, never from an interactive
terminal, and it must be valid JSON. When the flow drops the message (a filter
rejected it, or a block returned nothing), invoke logs
flow dropped the message and prints no result. Any flow is callable this way,
including one without a source: (see
Flow File).
Raw bodies
--content-type opts the body out of JSON, for a flow fed by a
raw-content source (XML, CSV, form-encoded). The bytes
of --data become the message body verbatim, tagged with the MIME type you give,
exactly as an HTTP source configured with rawBody: true would receive them.
octo invoke --config orders.yaml --flow intake \
--content-type application/xml \
--data '<order><id>42</id></order>'Inside the flow the body takes the raw-content shape (body.contentType and
body.rawData) rather than a parsed object; see
Raw Content. Without --content-type the body is parsed
as JSON.
Seeding variables
--data only fills the body, and invoke starts no sources, so nothing
populates the message variables for you: the HTTP source is what normally copies
request headers into them (see
State and Data). A
flow that reads vars needs them supplied with --vars:
octo invoke --config orders.yaml --flow orders \
--data '{"orderId": 42}' \
--vars '{"x-api-key": "dev-key"}'The flow now sees vars["x-api-key"] exactly as it would behind a real request.
Without --vars, an expression reading a variable that was never set fails with
a missing-key error.
Breakpoints
--break-at shows what the message looked like at one point in the flow. The
runtime wraps the block you address, runs the flow until it reaches that block,
records the message the block produced, and stops. The rest of the chain never
runs.
octo invoke --config samples/builtins-demo.yaml --flow demo \
--data '{"firedAt": "2026-07-10T12:00:00Z"}' \
--break-at 'demo.set-threshold'{"reached":true,"block":"demo.set-threshold","message":{
"event_id":"5c12…","variables":{"threshold":100},
"body":{"firedAt":"2026-07-10T12:00:00Z","orders":[{"id":1,"amount":50},{"id":2,"amount":250}]}}}The snapshot is the message after the addressed block ran, which is what the next block would have received: the body and every variable set so far.
Breakpoints are a debugging aid for invoke only. They are not a block you can
write in a flow, they never appear in the editor palette, and they are refused
outside invoke mode.
The debug envelope
A run that was asked to observe itself, with --break-at or --spies or
both, prints one JSON envelope instead of the result message, wrapping what it
saw:
| Field | Meaning |
|---|---|
reached | Whether execution ever got to the block. Present only under --break-at. |
block | The address you asked for, echoed back. |
message | The message the block produced. Present only when reached is true. |
result | The flow's own result message. Present when it was not stopped at a breakpoint. |
dropped | The flow filtered the message out and returned nothing. |
spies | What each spied block saw. See Spies. |
error | The flow's failure, when it failed before reaching the block. |
A --mocks-only run prints its result message, like any other invoke, because
mocking produces no observations to wrap. Ask for the envelope outright with
--envelope.
The outcome envelope
--envelope prints the same envelope for any run, even one that observed
nothing. Use it when a program, rather than a person, reads the output.
A plain invoke reports its three outcomes three ways: a flow that completed
prints its message, one that dropped the message prints nothing, and one that
failed prints nothing and exits 1 with the error in a log line. --envelope
says all three in one shape:
octo invoke --config samples/builtins-demo.yaml --flow demo --data '{"firedAt":"x"}' --envelope{"result":{"event_id":"6708a609…","body":{"firedAt":"x","orders":[…]}}}{"dropped":true}
{"error":"block \"seed-orders\": upstream exploded"}Under --envelope, a flow that fails exits 0: the failure is the answer,
not a failure of the CLI. A run that could not start (an unresolvable block
address, a broken config) still exits non-zero, because there is no outcome to
report.
--envelope-out <path>: when the flow itself prints
stdout is not the CLI's alone. A log block writes through
a logger connector, whose output defaults to stdout, so a flow that logs
interleaves its own JSON with the envelope, and it cannot be quieted from outside
(the connector takes its level and destination from the config).
--envelope-out writes the envelope to a file instead, leaving stdout to the
flow.
octo invoke --config samples/multi-transform.yaml --flow order \
--data '{"orderId":"A-1","qty":3,"price":10.0}' --envelope-out outcome.json
# stdout is the flow's own log line:
{"time":"…","level":"INFO","msg":"order A-1 subtotal=30 total=33"}
# the answer is in the file:
cat outcome.json
{"result":{"event_id":"…","body":{"orderId":"A-1","subtotal":30,"total":33}}}This is what dolphin, the test runner, reads, which is why it can test a flow
that logs.
A block that is never reached is a normal result, not an error. If the flow
takes the other branch of an if, matches a different switch case, or drops
the message first, you get reached: false and exit code 0:
{"reached":false,"block":"demo.any-orders[else].log"}An address that does not resolve is a mistake in your command, so invoke
exits non-zero and prints no envelope. The error lists what is there:
no block "nosuchblock" in that chain (blocks: seed-orders, set-threshold, any-orders, each-order, drop-threshold)
has no branch "nope" (branches: then, else)Addressing a block
An address starts with the flow name and walks down to the block, one segment per step:
<flow>.<block>
<flow>.<composite>[<branch>].<block>
<flow>.<composite>[<branch>].<composite>[<branch>].<block>A bracket names the branch to descend into. Every segment but the last names a composite and the branch to follow; the last names the target block.
Naming a block
Within a chain, a block is matched by its name, else its type, else its
ref, in that order. An unnamed block is still addressable as long as it is the
only one of its kind in that chain:
process:
- type: set-payload
name: seed-orders # -> demo.seed-orders
- type: log # -> demo.log (only one `log` in this chain)
- ref: shared-http # -> demo.shared-httpIf two blocks in the same chain would match, the address is rejected rather
than guessed at. Give the one you want a name:.
Naming a branch
Every composite exposes its branches by name:
| Composite | Branch names |
|---|---|
if | then, else |
foreach, enrich, cache-scope | body |
handle-errors, ai-retry | process, error |
validate | onReject |
split, aggregate | buildResponse |
fork | each branch's name, or its index (0, 1, …) |
switch | each case's name, or its index, plus default |
ai-router | each route's name, plus default |
mcp-router | each tool's name |
ai-agent | each tool's name, plus events, nameThread and default |
A bracket on the flow itself selects its error chain: orders[error].notify.
Examples
Given this flow:
flows:
- name: orders
process:
- type: set-payload
name: seed
- type: if
name: check-header
condition: "size(body.orders) > 0"
then:
process:
- type: rest
name: charge
else:
process:
- type: log
- type: foreach
name: each-order
items: "body.orders"
as: order
body:
process:
- type: switch
name: classify
cases:
- when: "vars.order.amount >= 100"
process:
- type: log
default:
process:
- type: log
- type: fork
name: fanout
branches:
- name: audit
process:
- type: log
name: log-it
- name: notify
process:
- type: rest
error:
- type: log
name: notify-failure| Address | Breaks on |
|---|---|
orders.seed | The set-payload, in the flow's own chain. |
orders.check-header[then].charge | The rest inside the if's then branch. |
orders.check-header[else].log | The log inside the else branch. Reports reached: false whenever the condition is true. |
orders.each-order[body].classify | The switch, on the first iteration of the loop, where vars.order is the first item. |
orders.each-order[body].classify[0].log | The log inside the switch's first case. The loop keeps going until a message actually reaches it, so this fires on whichever iteration first matches amount >= 100. |
orders.each-order[body].classify[default].log | The log in the switch's default branch. |
orders.fanout[audit].log-it | A block inside a fork branch, addressed by the branch's name. |
orders.fanout[1].rest | The same, by branch index. |
orders[error].notify-failure | A block on the flow's error chain. Reports reached: false unless the flow fails. |
The address may name a flow other than the one you invoke, which is how you break
inside a flow reached through flow-ref. The stop folds back through the call,
so the calling flow halts too:
octo invoke --config ./flows --flow caller --break-at 'sub.step'Things worth knowing
- The block after the breakpoint never runs, so no downstream side effects fire.
- The block you break on does run. The snapshot is taken after it. If it fails or
drops the message there is nothing to show, so you get
reached: falsewith the failure inerror. - In a
foreach, the breakpoint fires on the first iteration that reaches it and the loop stops there. - In a
cache-scope, a cache hit skips the body entirely, so a breakpoint inside the body correctly reportsreached: false. Nothing is written to the cache when a breakpoint halts the body. - A
fork's sibling branches still run to completion. A breakpoint in one branch does not cancel the others; the flow halts after the fork joins. - Numbers in the printed body are JSON numbers, so integers may show as floats.
Spies
--spies records every message that crosses a block and, unlike a breakpoint,
leaves the run alone. It takes a comma-separated list of
block addresses. A test suite
takes the same addresses and adds assertions over what was recorded:
octo invoke --config samples/builtins-demo.yaml --flow demo \
--data '{"firedAt": "2026-07-10T12:00:00Z"}' \
--spies 'demo.set-threshold,demo.each-order[body].classify-order'The envelope grows a spies array, one entry per address, in the order you gave
them. Each entry holds the crossings in the order they happened:
| Field | Meaning |
|---|---|
address | The address you asked for, echoed back. |
records | One entry per crossing. Empty when the flow never reached the block. |
records[].seq | Orders records across every spy, so a multi-block trace reads in the order things actually happened. |
records[].at | When the crossing was recorded. |
records[].input | The message the block received. |
records[].output | The message it returned. Absent when it dropped or failed. |
records[].dropped | The block filtered the message out. |
records[].error | The block failed, with this message. |
A block that runs many times (inside a foreach body, a fork branch, a
cache-scope) reports one record per crossing.
A fork runs each branch on a clone and discards the branch's message, so a
block inside one has no way to report through the flow's result. A spy's records
leave out of band, which is the only way to see what that block did.
Mocks
--mocks replaces a block with a canned answer, so its real work (an HTTP
call, an LLM, a database write) never happens. It takes one JSON object keyed by
block address. A test suite takes the same spec in
YAML, which is the usual way to keep one:
octo invoke --config samples/error-handling.yaml --flow charge-flowlevel \
--data '{"amount": 250}' \
--mocks '{"charge-flowlevel.call-charge":{
"cases":[{"when":"body.amount > 100","body":{"id":"ch_1"}}],
"default":{"error":"unexpected input"}}}'For anything real, put the spec in a debug config file instead of on argv.
The mock spec
| Field | Type | Meaning |
|---|---|---|
cases | array | Tried in order; the first whose when holds is applied. |
default | case | Applied when no case matched. Has no when. |
Each case has a condition and exactly one outcome:
| Field | Type | Meaning |
|---|---|---|
when | CEL | Evaluated against the message the block received (body, vars, env, …). Required on a case, forbidden on the default. |
body | any | The body the block returned. A literal value, not an expression. |
vars | object | Variables the block set, alongside its body, for blocks that report through a variable such as an HTTP call setting vars.status. Only valid with a body. |
error | string | Fail the block with this message. |
drop | bool | Filter the message out, as a filter block would. |
Things worth knowing
- A mock replaces the block; it does not wrap it. A wrapped HTTP call would still fire.
- No matching case and no
defaultfails the block. It does not fall through to the real one, which is gone from the flow, so a "mocked" call can never reach the network. Add adefault, or a trailing case withwhen: "true". - A mocked failure is indistinguishable from a real one. The mock takes the
target's label, so the error reads
block "call-charge": card declinedand an error path branching onvars.error.blockbehaves exactly as in production. - Mocking a composite removes everything inside it, which is how you cut out a whole sub-tree. A spy or breakpoint addressed inside a mocked block is rejected rather than silently reporting nothing.
Combining the three flags
They compose on the same block, and the nesting is fixed:
breakpoint[ spy[ mock ] ]A spy on a mocked block shows you what the flow fed it and what the mock answered, and a breakpoint on top stops the flow there. The mock is innermost because it replaces its target, and the breakpoint outermost because it halts the flow by marking the message, which a spy wrapped around it would record as part of the block's output.
Debug config file
--run-debug-config reads a whole debugging run from one file, so a session is
reproducible instead of a page of flags to retype:
input:
data: { amount: 250 }
vars: { x-api-key: dev-key }
breakAt: orders.charge
spies:
- orders.validate
- orders.fanout[audit].log-it
mocks:
orders.charge:
cases:
- when: 'body.amount > 100'
error: card declined
default:
drop: trueocto invoke --config orders.yaml --flow orders --run-debug-config debug.yaml| Section | Equivalent flag |
|---|---|
input.data | --data |
input.vars | --vars |
breakAt | --break-at |
spies | --spies |
mocks | --mocks |
Every section is optional. It is YAML, and JSON is accepted too, so a --mocks
blob pastes straight in.
A flag overrides its section, whole. --spies replaces the file's list
rather than adding to it.
For the body the order is --data, then the file's input.data, then piped
stdin. The file comes before stdin, unlike a bare invoke, so a run fully
described in a file never waits on a pipe. A file with no input.data still
falls through to stdin.
Unknown keys are rejected, so a misspelled spys: says so rather than
silently recording nothing:
parse debug config "debug.yaml": field spys not found in type main.debugConfigPrint the file's JSON Schema with
octo schema --kind debug-config.
octo eval
Evaluates a CEL expression against an ad-hoc message. No config and no runtime services are involved, so it is the fastest way to try an expression before pasting it into a flow; see CEL Expressions.
octo eval --expr '1 + 2'{"ok":true,"result":3}| Flag | Type | Default | Description |
|---|---|---|---|
--expr | string | (required) | The CEL expression to evaluate. |
--data | JSON | stdin | JSON object bound to the body variable. When omitted, piped stdin is read instead. |
--vars | JSON | {} | JSON object bound to the vars variable. |
--env | JSON | {} | JSON object bound to the env variable. |
The remaining message variables get defaults: eventID is a fresh id,
correlationID is empty, and now is the evaluation time.
octo eval --expr 'body.orders.filter(o, o.amount >= vars.min).map(o, o.id)' \
--data '{"orders": [{"id": 1, "amount": 50}, {"id": 2, "amount": 250}]}' \
--vars '{"min": 100}'{"ok":true,"result":[2]}The output is always a one-line JSON envelope:
{"ok":true,"result":<value>}
{"ok":false,"result":null,"error":"<message>"}ok distinguishes a successful evaluation from a compile or evaluation failure;
result is always present so a legitimate false/0/null result is not
confused with its absence. Both outcomes exit 0, so scripts should parse the
envelope rather than inspect exit codes:
octo eval --expr '1 +'{"ok":false,"result":null,"error":"compile expression \"1 +\": ERROR: <input>:1:4: Syntax error: mismatched input '<EOF>' ..."}eval runs without a loaded config, so the templateResource() function has
no resources to render and calling it reports resource: not found. Every
other part of the expression environment behaves exactly as it does inside a
flow. See Octo Extensions.
octo schema
Generates the capability catalogue, the machine-readable description of every
registered block and connector (types, labels, categories, settings fields,
defaults), and prints it as JSON. octo capabilities is an alias.
octo schema # print to stdout
octo schema --out capabilities.json| Flag | Type | Default | Description |
|---|---|---|---|
--kind | enum | capabilities | Which schema: capabilities, or debug-config for a debug config file. |
--format | enum | json | Print it as json or yaml. |
--out | path | stdout | Write it to a file instead of stdout. |
The output is an object with two arrays:
{
"blocks": [
{
"type": "ai-mapping",
"label": "AI Mapping",
"category": "processor",
"group": "AI & LLM",
"icon": "Sparkles",
"description": "...",
"fields": [ ... ]
}
],
"connectors": [ ... ]
}This catalogue powers the visual editor's block palette and property forms, and
CI's documentation drift check reads octo schema and compares it against the
reference pages: every registered block and connector type must be documented by
exactly one page.
The debug-config schema
--kind debug-config prints the JSON Schema of a
--run-debug-config file, so an editor can complete it:
octo schema --kind debug-config --out debug.schema.json
octo schema --kind debug-config --format yaml # same document, as YAML$schema: https://json-schema.org/draft/2020-12/schema
$id: https://octo.run/schemas/debug-config.json
title: octo debug config
type: object
additionalProperties: false
properties:
input: …
breakAt: …
spies: …
mocks: …octo version
Prints the release version and, when available, the build timestamp.
octo versionocto 0.11.7 (built 2026-07-09T06:11:43Z)octo --version and octo -version print the same line. The build date is
stamped at link time for released binaries; a go build binary falls back to the
VCS commit time, and the suffix is omitted when neither exists.
Environment variables
| Variable | Description |
|---|---|
LOG_LEVEL | Log verbosity for the process logger: debug, info (default), warn, or error. An invalid value logs a warning and falls back to info. Logs are written to stderr. |
OCTO_ENV_FILE | Path to an extra .env file loaded in addition to ./.env, overlaying it. See Flow File: env. |
OCTO_STORAGE_DIR | Default for --storage-dir: the directory the object store is serialized into. For octo run it defaults to ./octo-store; for the one-shot octo invoke it defaults to an in-memory store, so a probe is reproducible. Set it to an empty value to keep run's store in memory too. See KV Store and Persistence. |
OCTO_OBSERVABILITY | Default for --observability. Accepts true/false, 1/0, on/off, yes/no (case-insensitive). An unparseable value logs a warning and is ignored. |
OCTO_OBSERVABILITY_ADDR | Default for --observability-addr. |
OCTO_METRICS | Default for --metrics. Same accepted values as OCTO_OBSERVABILITY. |
OCTO_METRICS_BLOCKS | Default for --metrics-blocks: comma-separated block addresses, or * for every block. |
OCTO_TRACING | Default for --traces. Same accepted values as OCTO_OBSERVABILITY. This is how tracing is enabled in a deployed pod, which passes no arguments. |
OCTO_TRACING_FILE | Default for --traces-file. |
OCTO_TRACING_BLOCKS | Default for --traces-blocks. |
OCTO_TRACING_BODIES | Default for --traces-bodies. |
OCTO_TRACING_VARS | Default for --traces-vars. |
OCTO_TRACING_MAX_PAYLOAD | Default for --traces-max-payload. |
OCTO_TRACING_BUFFER | Default for --traces-buffer. |
The OCTO_OBSERVABILITY*, OCTO_METRICS*, OCTO_TRACING* and
OCTO_STORAGE_DIR variables are read from the process environment only, not
from a .env file: they are resolved when octo run parses its flags, before
any config (and therefore any .env) is loaded. Passing the flag wins over the
variable.
Config-declared environment variables (the env: section of a flow file) are
resolved with the precedence OS environment > .env file > declared default;
see Flow File for the full rules.