Variables
A variable is a named, read-only value that an agent can use at runtime. Examples are the current time, a host name, or a token that a command needs. An agent can list a variable’s metadata, read its value, or pass a reference to a tool without ever seeing the value.
Variables are not mutable state, and they are not an encrypted vault.
A complete example
Section titled “A complete example”This config uses no external services. Replace the model placeholder before you send a prompt.
{ "default_agent": "raw", "models": { "local": { "provider": "ollama", "method": "openai-chat-completions", "model_id": "YOUR_INSTALLED_MODEL" } }, "vars": { "project": { "description": "Project settings", "access": "read", "source": { "kind": "literal", "value": { "name": "raw-cli" } } }, "now": { "description": "Current UTC time", "access": "read", "source": { "kind": "provider", "name": "system.time" } }, "token": { "description": "API credential", "access": "use", "source": { "kind": "env", "name": "MY_API_TOKEN" } } }, "agents": { "raw": { "model": "local", "vars": ["project", "now", "token"], "tools": { "use": ["builtin/list_vars", "builtin/read_var", "builtin/bash"] } } }}Save this as raw.json, then run:
raw --config raw.json vars listraw --config raw.json vars get nowNeither command needs a model credential, and neither starts a session.
Declare a variable
Section titled “Declare a variable”Variables are declared under the root vars object. Names must match [a-z][a-z0-9_.-]{0,63}. The names constructor and prototype are reserved, and __proto__ is invalid.
| Field | Required | Meaning |
|---|---|---|
description |
Yes | A nonempty description. The model sees it in list_vars. |
access |
Yes | read or use. See below. |
source |
Yes | Where the value comes from. See below. |
type |
No | string, number, boolean, object, array, null, or json. Declared types are checked against the resolved value. |
cache_ttl_ms |
No | Integer from 0 to 2147483647. Default 0, which resolves the value on every read. |
Access
Section titled “Access”| Access | The model can read the value | The model can pass a reference to Bash or a tool |
|---|---|---|
read |
Yes | Yes |
use |
No | Yes |
Use use for secrets that a command needs but the model should not see. The use setting is not an operating-system secrecy boundary. A command you run can still print the value, and a trusted plugin can read it.
Sources
Section titled “Sources”Each source has a kind, and each kind has its own fields.
| Kind | Fields | Notes |
|---|---|---|
literal |
value |
Any JSON value. The type is inferred unless you declare one. |
env |
name |
An environment variable. An unset variable is an error. An empty value is valid. |
file |
path, optional format (text or json) |
Relative paths resolve from the config file’s directory. The file must be regular, strict UTF-8, and at most 65536 bytes. |
provider |
name, optional params |
Calls a provider. system.time is built in and returns the current UTC time as a string. |
Select variables for an agent
Section titled “Select variables for an agent”An agent lists the variables it can use in vars, by exact name. There is no wildcard. A variable that is not listed is invisible to that agent.
To let the model discover and read variables, also select builtin/list_vars and builtin/read_var in tools.use. raw config init does this for its starter agent, and it also declares a now variable.
Write an executable provider
Section titled “Write an executable provider”A provider is a program that answers a single request. Declare it under the root var_providers object.
| Field | Required | Default | Notes |
|---|---|---|---|
command |
Yes | None | An executable name on PATH, or a path. |
args |
No | [] |
Literal arguments. |
cwd |
No | The config file’s directory | Working directory for the program. |
timeout_ms |
No | 5000 |
From 1 to 2147483647. |
max_output_bytes |
No | 65536 |
From 1 to 1048576. Limits stdout and stderr combined. |
Raw writes one JSON line to the program’s stdin and closes stdin:
{"protocol_version":1,"name":"hostname","params":{"field":"hostname"}}The program must exit 0 and print exactly one JSON object on stdout:
{"value":"workstation","observed_at":"2026-09-26T10:00:00.000Z"}valueis required.observed_atis optional. It must be a UTC timestamp. If it is missing, Raw uses the time the value was produced.- Extra fields, or a second JSON object on stdout, cause an error.
- Write logs to stderr. Raw counts their bytes but does not return them to the model.
A working example is in examples/providers/host-info. Copy the folder and run the commands from its README.
Let a model read variables
Section titled “Let a model read variables”Once an agent selects builtin/list_vars and builtin/read_var, the model can call:
list_varsto get each selected variable’s name, description, type, and access. It never runs a provider.read_varwith anameto get the value, along with when it was observed and whether it came from the cache.
A use variable cannot be read this way. The model can only pass its reference to a command.
Pass a variable to Bash without showing it
Section titled “Pass a variable to Bash without showing it”A Bash command can receive a variable as an environment variable, without the value appearing in the command text. Put the mapping in env_refs on a command.
{ "commands": [ { "command": "test -n \"$TOKEN\"", "env_refs": { "TOKEN": "token" } } ]}Raw resolves the value just before that command starts, and it sets the value only in that command’s environment. The model’s arguments keep the reference, not the value. If a resolution fails, the commands after it do not run, but the commands before it keep their results.
Use a variable in a custom tool
Section titled “Use a variable in a custom tool”Every local tool that an agent selects receives context.vars. The handler can use these methods:
list()returns metadata only.read(name, { signal })returns a value.validateEnvRefs(refs)checks names and types without reading values.resolveEnv(refs, { signal })returns environment bindings for trusted code.
const refs = { TOKEN: args.token_ref };context.vars.validateEnvRefs(refs);const env = await context.vars.resolveEnv(refs, { signal: context.signal });const response = await fetch(args.url, { headers: { Authorization: `Bearer ${env.TOKEN}` }, signal: context.signal});MCP servers do not receive variable references. Their env and headers values are literal.
Freshness
Section titled “Freshness”- The
cache_ttl_msvalue is measured from when a read completes, not from the provider’s timestamp. Only successful reads are cached. - The cache lives in memory for one runtime. It is not saved to disk and is not shared between sessions.
- The CLI commands
vars listandvars getstart with an empty cache every time. - Each resume reads the current config. A running runtime keeps the definitions it loaded until it restarts.
Check variables from the command line
Section titled “Check variables from the command line”raw [--config PATH] [--agent NAME] vars listraw [--config PATH] [--agent NAME] vars get NAMEvars listprints one JSON object with the metadata of each selected variable.vars get NAMEprints{"name", "value", "observed_at", "cached"}.vars geton ausevariable fails. Check ausevariable by running a command that uses it and does not print it.- Only
--configand--agentapply to these commands.
| Exit code | Meaning |
|---|---|
0 |
Success. |
1 |
The value could not be read, or access was refused. |
2 |
Invalid config or arguments. |
130 |
Cancelled. |
Troubleshoot a provider
Section titled “Troubleshoot a provider”- Run
raw --config PATH config listto validate the config. This checks structure and references, and it does not run any provider. - Run
vars listto confirm the variable is selected by the agent. - Run the provider program directly with the JSON request on stdin, and confirm that stdout contains only the JSON response.
- Check the exit code, the value’s type, the timestamp format, and the output size limit.
Related
Section titled “Related”- Tools covers the variable tools and the
env_refsfield in Bash. - Configuration reference lists the variable fields.