Variables
Variables
Section titled “Variables”Variables are named references that are substituted with values at runtime. SFMD defines the syntax for referencing variables — storage and resolution are handled by the runtime.
Two variable types
Section titled “Two variable types”| Syntax | Type | Purpose |
|---|---|---|
{name} | Session variable | Runtime data flow between actions |
$NAME | Persistent variable | Configuration, credentials, settings |
Session variables: {name}
Section titled “Session variables: {name}”Syntax
Section titled “Syntax”{variable_name}Curly braces around an identifier.
ID rules
Section titled “ID rules”| Rule | Valid | Invalid |
|---|---|---|
| Lowercase letters | {city} | — |
| Numbers allowed | {temp2} | — |
| Underscores allowed | {current_temp} | — |
| Must start with a letter | {token} | {2token} |
Pattern: \{[a-z][a-z0-9_]*\}
Where they appear
Section titled “Where they appear”Session variables can appear in:
- Response templates (assignment and output lines)
- Action definition URIs and headers
- Action invocation arguments (AI commands)
{city} = {Response.body.city}## Weather in {city}/act.search --city {city}Persistent variables: $NAME
Section titled “Persistent variables: $NAME”Syntax
Section titled “Syntax”$VARIABLE_NAMEDollar sign followed by an identifier.
ID rules
Section titled “ID rules”| Rule | Valid | Invalid |
|---|---|---|
| Uppercase letters | $API_KEY | — |
| Numbers allowed | $KEY2 | — |
| Underscores allowed | $DEFAULT_REGION | — |
| Must start with a letter | $TOKEN | $2TOKEN |
| Lowercase allowed | $api_key | — |
Pattern: \$[a-zA-Z][a-zA-Z0-9_]*
Convention: uppercase for configuration ($API_KEY), but not
enforced.
Where they appear
Section titled “Where they appear”Persistent variables can ONLY appear in:
- Action definition blocks (
act.namecode blocks)
GET https://api.example.com/search?key=$API_KEYPersistent variables MUST NOT appear in:
- AI command arguments (use
{var}instead) - Response template assignments
This keeps a clean separation: $var is wired into action
definitions by document developers; AI uses {var} in commands.
Resolution order
Section titled “Resolution order”When the runtime encounters $NAME in an action definition (URL,
headers, or body template), it resolves the value using this cascade:
- Per-call extra env — context variables passed programmatically by the caller (tool context vars in tool blocks, etc.).
- SFMD env-store — per-user persistent values set via
/set NAME = "value". Stored encrypted on disk at~/.string/config.json. - Daemon process env —
process.envof the runningstringdprocess. Inherits from the shell that started the daemon, soexport GEMINI_API_KEY=... && string --daemon startmakes the key available to all actions. - Unresolved — if none of the above have a value, the literal
$NAMEis left in place so the failure is visible (e.g., the API sees$API_KEYas a literal and returns an auth error, which the agent can diagnose).
The process.env fallback (step 3) is a convenience for API keys and
configuration that are more naturally managed as shell environment
variables than as SFMD-specific /set values. It does NOT expose
arbitrary process env to the action — only the specific $NAME
referenced in the action definition is resolved. An action that
does not reference $HOME never sees $HOME.
Assignment syntax
Section titled “Assignment syntax”Variables are assigned in response templates:
{variable} = {expression}- Assignment is a full line:
{id} = {expression}. - Left side MUST be a session variable:
{name}. - Right side is an expression that resolves to a value.
- Assignment lines produce no output.
- Only
{variables}can be assigned.$variablescannot.
Expression types
Section titled “Expression types”| Expression | Meaning |
|---|---|
{Response.body.field} | Value from action response |
{Response.body.nested.field} | Nested response value |
{Response.status} | HTTP status code |
"literal" | Literal string value |
{other_variable} | Value of another variable |
Examples
Section titled “Examples”{city} = {Response.body.city}{temp} = {Response.body.temperature}{status} = {Response.status}{label} = "default"Reference in templates
Section titled “Reference in templates”Variables in output lines are substituted with their values:
## Weather in {city}- Temperature: {temp}°CIf a variable has no value, the reference is left as-is or replaced with an empty string (runtime-dependent).
| Variable type | Scope |
|---|---|
{variable} | Topic session — each topic has its own set |
$VARIABLE | Per-user persistent — with cascade (config > app > global) |
Session variables in a topic override persistent variables of the same name within that topic’s scope.
Rules summary
Section titled “Rules summary”- Session variables:
{name}—[a-z][a-z0-9_]*in curly braces. - Persistent variables:
$NAME—[a-zA-Z][a-zA-Z0-9_]*with$prefix. {var}can appear in templates, invocations, and action definitions.$VARcan ONLY appear in action definition blocks (URL, headers, body template).$VARresolution cascade: per-call extra env → SFMD env-store → daemon process.env → unresolved literal.- Assignment:
{var} = {expression}— full line, no output. - Only
{var}can be on the left side of assignment. {var}is session-scoped.$VARis persistent per-user (with process.env fallback).- Topic
{var}overrides$VARof the same name in that scope. - Response paths support dot-and-bracket notation:
body.items[0].name.