Skip to content

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.

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:

Terminal window
raw --config raw.json vars list
raw --config raw.json vars get now

Neither command needs a model credential, and neither starts a session.

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 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.

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.

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.

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"}
  • value is required.
  • observed_at is 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.

Once an agent selects builtin/list_vars and builtin/read_var, the model can call:

  • list_vars to get each selected variable’s name, description, type, and access. It never runs a provider.
  • read_var with a name to 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.

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.

  • The cache_ttl_ms value 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 list and vars get start with an empty cache every time.
  • Each resume reads the current config. A running runtime keeps the definitions it loaded until it restarts.
Terminal window
raw [--config PATH] [--agent NAME] vars list
raw [--config PATH] [--agent NAME] vars get NAME
  • vars list prints one JSON object with the metadata of each selected variable.
  • vars get NAME prints {"name", "value", "observed_at", "cached"}.
  • vars get on a use variable fails. Check a use variable by running a command that uses it and does not print it.
  • Only --config and --agent apply 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.
  1. Run raw --config PATH config list to validate the config. This checks structure and references, and it does not run any provider.
  2. Run vars list to confirm the variable is selected by the agent.
  3. Run the provider program directly with the JSON request on stdin, and confirm that stdout contains only the JSON response.
  4. Check the exit code, the value’s type, the timestamp format, and the output size limit.