Parameter Scripting
Parameter scripting lets you write expressions in parameter fields instead of static values. An expression can reference other nodes’ parameters, environment variables, secrets, subgraph inputs, and named path roots — so a value defined once can propagate through an entire pipeline without manually threading data connections everywhere.
A data connection takes precedence over an expression: if a parameter has both, the connected value is used and the expression is ignored. An expression in turn replaces the parameter’s typed value.
Common use cases:
- A project root path defined on one node, referenced by every node that needs it
- A server address or API endpoint set in one place and used across multiple HTTP calls
- Dynamic path construction:
@base.output_dir + "/renders/v002" - Scaling a numeric value from another node:
@config.timeout_ms * 2 - Referencing a personal graph library or machine-specific mount by name:
@lib/cleanup.json
Enabling Expression Mode
Expression mode is toggled per parameter via right-click:
- Right-click any parameter label or input field
- Select Set Expression from the context menu
- The parameter input switches to a monospace expression field with an fx badge
To return to a static value:
- Right-click the parameter again
- Select Clear Expression
The previous static value is restored exactly as it was — toggling off does not lose your data.
Expression Syntax
Expressions use the @ sigil to reference values. Everything else is a literal or operator.
References
@alias.param_name — another node's parameter
@env.VARIABLE_NAME — OS environment variable
@secret.KEY_NAME — value from the secrets store
@subgraph.input_name — parent subgraph's exposed input
@name/relative/path — a configured path root (note: slash, not dot)
@name/ (slash) is a path root; @name.param (dot) is a node alias. The two are disambiguated purely by what follows the name, so a root named lib and a node aliased lib can coexist in the same graph without conflict — @lib/cleanup.json always expands the root, @lib.param always resolves the alias. See “Reference: Built-in Namespaces” below for the full path root reference.
Operators
| Operator | Works on | Result |
|---|---|---|
+ | number + number | addition |
+ | string + string | concatenation |
+ | number + string | concatenation (number cast to string) |
- | number - number | subtraction |
* | number * number | multiplication |
/ | number / number | division |
% | number % number | modulo |
( ) | any | override precedence |
Path roots do not compose with operators. @alias.param, @env.VAR, @secret.KEY, and @subgraph.input are all expression operands — they can be combined with +, arithmetic, and parentheses. @name/relative/path is different: it is a textual substitution performed while scanning the raw string, not a value the expression parser produces. @lib/cleanup.json works; @lib/ + "/cleanup.json" and @lib/subdir + @config.filename do not — the root only expands as a literal prefix immediately followed by a path, written directly in the field. If you need to build a path from a root plus other parts, do the composition on the other side (e.g. bake the full relative path into the field: @lib/renders/v002/cleanup.json).
Literal values
"some/path" — string literal (use double quotes)
42 — integer
3.14 — float
true / false — boolean
Examples
Path construction
@base_node.output_path + "/renders/v002"
If base_node has a parameter output_path set to /projects/my_project, this evaluates to /projects/my_project/renders/v002.
Environment variables
@env.HOME + "/projects"
Reads the OS HOME environment variable and appends /projects.
Secrets
@secret.REMOTE_HOST + ":" + @server_config.port
Reads a secret named REMOTE_HOST from the secrets store and appends the port parameter from the server_config node.
Numeric scaling
@watcher.debounce_ms * 2
Takes the debounce_ms parameter from the watcher node and doubles it.
Grouped expressions
(@base.width + @base.padding) * @scale.factor
Parentheses control evaluation order as expected.
Node Aliases
To reference another node’s parameters, that node must have an alias — a short, stable name you assign.
Setting an alias
- Select the node on the canvas
- In the right sidebar, find the Alias field (below the node label)
- Type a short name: alphanumeric characters and underscores only (e.g.
watcher,base_config,render_settings) - Click away — the alias is saved
Rules:
- Aliases are optional — a node without an alias cannot be referenced in expressions
- Aliases must be unique within a graph
- Only alphanumeric characters and underscores:
watcher,base_config_01,render_v2 - Aliases are case-sensitive
Tip: Choose short, descriptive aliases. You will type them often.
Using an alias in an expression
Once my_node has the alias config, any other node can reference its parameters:
@config.source_path
@config.timeout_ms * 1000
@config.server_url + "/api/v1/endpoint"
Autocomplete
When typing in an expression field, autocomplete activates automatically after @:
- After
@— shows all aliased nodes in the graph plus the built-in namespaces (env.,secret.,subgraph.) - After
@alias.— shows the parameter names available on that alias - Filter by typing:
@wanarrows to aliases starting withwa
Keyboard controls:
↑/↓— navigate suggestionsTaborEnter— accept selected suggestionEsc— dismiss without selecting
Validation and Errors
While typing
Expressions are only validated when you leave the field (on blur). No errors appear while you are actively typing an incomplete expression.
After leaving the field
If the expression has a syntax problem, a red border appears with a message:
Syntax error at position 5: expected '.' after namespace
At runtime
If an expression cannot be resolved when the pipeline runs (e.g. an alias that no longer exists), a warning is logged and the parameter keeps whatever static value the node still carries. The pipeline continues — expression errors are not fatal.
For a parameter you switched to an expression in the editor, that static value is empty. Switching on expression mode replaces the old value rather than shadowing it, so there is nothing to fall back to: the node runs with an empty parameter. Treat a failed expression as a failed parameter and check the log — do not rely on the previous value still being there.
Common runtime errors and what they mean:
| Error | Cause |
|---|---|
Unknown alias 'wtacher' — did you mean 'watcher'? | Alias not found; typo suggestion shown if close match exists |
Parameter 'source_pth' not found on 'watcher' | Alias exists but the named parameter does not |
Unknown environment variable 'HOM' | @env.HOM — check spelling |
Unknown secret 'API_KEY' | Secret not configured in settings |
Type mismatch | e.g. subtracting a string from a number |
Reference: Built-in Namespaces
@env.
Reads OS environment variables at runtime on the machine running the Succession backend.
@env.HOME
@env.PATH
@env.MY_CUSTOM_VAR
Note: Environment variable names are case-sensitive on Linux and macOS.
@secret.
Reads values from the Succession secrets store (configured in Settings → Secrets).
@secret.API_KEY
@secret.DATABASE_PASSWORD
@secret.REMOTE_HOST
Secrets are never logged or displayed in the UI after being set — this is the recommended way to use sensitive values in pipelines.
@subgraph.
Inside a subgraph, references a value provided by the parent graph. This includes:
- Exposed parameters — values set on the outer Execute Subgraph or For Loop node (see Subgraph Parameters)
- Subgraph input data — the data passed to the subgraph boundary node
@subgraph.output_path
@subgraph.frame_rate
@subgraph.project_name
This is only valid inside a subgraph. Outside a subgraph context, @subgraph.* references will fail at runtime.
The recommended way to create @subgraph.* expressions is via the Expose Parameter right-click menu — this automatically sets the expression and creates the corresponding input field on the outer node. You can also write them by hand to reference values passed in at the subgraph boundary.
@name/ (path roots)
Expands to a directory you configured in Settings → Path Roots (see Settings). Use it for locations outside the current project — a personal graph library reused across unrelated projects, or a machine-specific mount:
@lib/cleanup.json
@assets/textures/brick.png
With pathRoots configured as:
"pathRoots": {
"lib": "~/.project-succession/lib",
"assets": "/Volumes/share/assets"
}
these expand to:
@lib/cleanup.json -> /Users/jere/.project-succession/lib/cleanup.json
@assets/textures/brick.png -> /Volumes/share/assets/textures/brick.png
Autocomplete knows your roots. Typing @ in an expression field lists the configured roots (as lib/, assets/) alongside the built-in namespaces (env., secret.) and node aliases — the / versus . in the suggestion is the same distinction the syntax draws. Once you accept a root, the field lists what is actually in that directory, so a shared library does not have to be memorised; accepting a subdirectory steps into it and lists again.
lib is configured by default. Every installation starts with a lib root pointing at ~/.project-succession/lib, and that folder is created on first launch — so @lib/… resolves without any setup. You can repoint or remove it in Settings like any other root. Expansion is independent of permission: the resulting path still has to be inside your allowed filesystem paths, which are granted deliberately and deny everything by default.
Use relative paths for anything inside your project. A relative path such as ./shared-graphs/cleanup.json already resolves against the referencing graph’s directory and travels with the repo unchanged for every teammate. Path roots exist only for the case relative paths cannot cover: a location with no common ancestor with the graph that references it. Reaching for a root when a relative path would do just adds a per-machine setup step for no benefit.
This is textual substitution, not an expression reference. Every other @ form on this page (@alias.param, @env.VAR, @secret.KEY, @subgraph.input) is a value the expression parser understands and can combine with + and arithmetic. @name/ is different — it is substituted directly into the raw text before the expression is parsed, so it is not an operand. @lib/cleanup.json works; @lib/ + "/cleanup.json" does not. Write the full relative path after the root directly: @lib/renders/v002/cleanup.json.
Slash, not dot. @lib/x (slash) expands the root named lib. @lib.x (dot) resolves the node alias named lib. A root and an alias with the same name coexist without conflict because the character after the name decides which one applies.
Root names must be alphanumeric-or-underscore, starting with a letter or underscore (the same rule as node aliases), and cannot be env, secret, subgraph, or input — those are reserved for the built-in namespaces above. Settings rejects an invalid or reserved name immediately, naming the offending root.
An unrecognized root is left exactly as written — this is not an error. @name/ only expands when name matches a configured root. If it doesn’t, the text passes through untouched, the same as any other @ text the expression engine doesn’t recognize (this is what keeps something like npm i @types/node working in a Run Command field even though @types looks like it could be a root). The practical consequence: a typo’d root name does not fail validation when you save the parameter. It surfaces later, at run time, as a file-not-found error containing the literal unexpanded alias — e.g. No such file: /repo/@lbi/cleanup.json for a lib root misspelled as lbi. Nothing is logged when the alias fails to match, so the file-not-found message is the only signal — read the path in it and check the spelling against Settings.
Roots are machine-local. They live in your local settings, not in the graph file. A graph that uses @assets/… only resolves on a machine where assets is configured — deploying it elsewhere needs the same root added there first. lib is the exception, being configured by default everywhere; what lives inside that folder is still per-machine.
Editor navigation follows a path root, but only as an expression. Set graphPath to @lib/cleanup.json as an expression and double-click opens it, the navigable indicator appears, and its exposed parameters load — the editor expands the root the same way the engine will. The same text typed as a static value is refused instead, with a message saying so: the engine expands roots only while evaluating expressions, so a static @lib/… is passed through literally and the graph fails to find the file at run time. Letting the editor open it would promise a resolution that never happens.
An expression that needs runtime data — @lib/@env.VARIANT.json, @config.dir + "/child.json" — has no value until the graph runs, so it does not open either, and the message names that as the reason. Cross-graph search still indexes all of these, so Find Usages locates the node even when navigation cannot follow it.
Copying a Parameter Path
Right-clicking any parameter shows Copy Parameter Path in the context menu. This copies the expression reference string for that parameter to the clipboard:
@my_alias.param_name
Use this to quickly build expressions that reference the current node’s own parameters or to copy a path for use elsewhere.
Tips and Patterns
Define shared values once
Add a dedicated “Config” node at the top of your graph, set its alias to config, and put all shared values (paths, URLs, timeouts) in its parameters. Every other node can then reference @config.value_name instead of duplicating the value.
Path building
String + is the cleanest way to build paths:
@config.project_root + "/assets/" + @config.asset_name + ".fbx"
Mixing references and literals
References and literals can be freely combined:
"https://" + @config.host + ":" + @config.port + "/api"
Numeric with units
Number-to-string coercion happens automatically when you add a number and a string. Integers are cast without a decimal point:
@config.timeout_ms + "ms" → "5000ms" (not "5000.0ms")
Subgraph reuse
When building reusable subgraphs, use the Expose Parameter right-click menu to surface the values that vary per call site. The @subgraph.* expression is set automatically, and a matching input field appears on the outer node. See Subgraph Parameters for the full workflow.
Relative paths first, path roots only when you need them
Default to a relative path (./shared/cleanup.json) for anything that lives in the same repo as the referencing graph — it needs no setup and works identically for every teammate. Reach for a path root only when the target genuinely has no common ancestor with the graph, such as a personal graph library shared across unrelated projects. See “@name/ (path roots)” above.
Scope
What expressions can and cannot reference:
| Reference | Available |
|---|---|
| Other nodes in the same graph (by alias) | Yes |
| OS environment variables | Yes |
| Succession secrets | Yes |
| Parent subgraph inputs | Yes (inside subgraphs only) |
Configured path roots (@name/) | Yes (machine-local; must be configured on each machine that runs the graph) |
| Nodes in a different graph file | No |
Conditional logic (if/else) | No |
Built-in functions (floor(), len(), etc.) | No |
Path roots combined with operators (@lib/ + "x") | No — textual substitution only, not an expression operand |
Cross-graph references and built-in functions are not supported in the current version.