Robutler

Configuration

Three places, three jobs: AGENT.md describes an agent, config.json configures the CLI, and environment variables carry keys.

CLI Settings (config.json)

The CLI reads ./.webagents/config.json in the current directory first, then ~/.webagents/config.json, then its built-in defaults. Under --profile <name> the global file is ~/.webagents-<name>/config.json instead, and the chat's history, sessions, checkpoints and log (logs/repl.log) live in that folder too. An agent's signing keys stay in ~/.webagents/keys whatever the profile: the key is the agent's identity on this machine, not a platform setting (WEBAGENTS_KEYS_DIR moves it).

webagents config get                                   # every key, as JSON, after every layer
webagents config set platform.url https://robutler.ai  # global
webagents config validate                              # unknown keys and bad values
webagents config path                                  # which files are read
KeyWhat it sets
platform.urlThe platform login and publish talk to. ROBUTLER_API_URL outranks it; see Publish
daemon.host, daemon.portWhere the local daemon listens, and where the chat and every daemon command look for it (default 127.0.0.1:8765). A --host or --port flag outranks them. daemon.host must be an address on this machine (127.0.0.1, ::1 or localhost); see Daemon
link.agentId, link.agentNameThe platform agent this directory publishes to, written by link and publish

Values can reference environment variables as ${VAR} or ${VAR:-fallback}. Both CLIs read the same files.

Agent Configuration (AGENT.md)

YAML front matter configures the agent, and the markdown below it is the agent's instructions:

---
name: my-assistant
description: Answers questions about the project's data
model: openai/gpt-4o-mini
fallback_models:
  - anthropic/claude-haiku-4-5
intents:
  - answer questions about the sales data
skills:
  - openai
  - anthropic
  - filesystem:
      whitelist:
        - ./data
  - shell
  - memory
  - mcp:
      sqlite:
        command: uvx
        args: ["--with", "mcp<2", "mcp-server-sqlite", "--db-path", "./data.db"]
agent_skills:
  - ./skills
access:
  groups:
    analysts:
      - domain:analytics.example
  tools:
    analysts: [filesystem]
sandbox:
  preset: strict
  allowed_folders:
    - ./data
observability:
  otel: true
---

# Instructions

You are a helpful assistant...
KeyWhat it does
nameThe agent's name; on Robutler, the part after your username
descriptionOne line about the agent, shown on its card
namespaceA grouping label for the agent
intentsWhat the agent can do, for discovery on Robutler
modelprovider/model; see Models
fallback_modelsModels to try, in order, when model does not answer; see Models
skillsThe coded skills the agent loads, by the names webagents skills list shows, each with its own settings
agent_skillsFolders of SKILL.md skills beyond .agents/skills/; see SKILL.md skills
accessWho may call the agent and which tools each group gets; see Who can call your agent
sandboxWhat the agent's shell commands can read, write and reach (preset, allowed_folders, network, env_passthrough); see Sandbox
cronSchedules the daemon runs; see Daemon
max_tool_roundsThe tool rounds one turn may run, a whole number from 1 to 1000 (default 50). At the limit the agent makes one last call with tools off and answers from what it gathered; --max-tool-rounds and the chat's /rounds take precedence
compactionWhen and how a long conversation is compacted to fit the model's context; see Context compaction
observability{otel: true} records runs as OpenTelemetry spans; see Observability
scopesThe agent's own scopes (Python)

A skill's settings go under its own entry in skills:, as with filesystem and mcp above. For mcp, each key is a server name.

The loaders are strict, so a mistake is reported where it is instead of running as something else:

  • An unknown top-level key is an error with a "did you mean": skils: is reported, not ignored. So is a mistyped key inside sandbox:, observability:, compaction:, a cron: schedule, or the memory skill's settings.
  • Front matter that is not valid YAML is refused with the line and column.
  • The old string form of cron: is refused with the list form it takes.
  • An agent file that is a symbolic link is refused: an agent file must be a regular file in its folder.

A few keys (tools, visibility, version, author, tags, mcp_servers, watch) are accepted so that older files still load, but they do nothing, and webagents doctor says so.

Context Compaction

A conversation that fills the model's context is compacted, cheapest step first: the long outputs of earlier tool calls are cleared (each call keeps a one-line note of what it returned); if that is not enough, everything before the recent part becomes one summary written by the model; and if no summary can be made, the oldest whole turns are dropped, with a note saying how many. The system prompt is never touched, and the cut never separates a tool call from its results. Every agent does this, with or without the memory skill.

compaction:
  at: 0.8                 # compact past 80% of the model's context
  keep: 0.25              # the recent part kept as it is
  instructions: Keep every figure in the budget discussion.
KeyDefaultWhat it does
autotrueCompact without being asked; false leaves it to /compact and the API
at0.8When to compact: a part of the model's context (0 to 1), or a number of tokens
keep0.25How much of the recent conversation stays as it is, the same way
hard0.95Inside one long turn, the point a run compacts at by itself, leaving the turn in progress whole; above at
clear_tool_resultstrueClear the outputs of earlier tool calls first, which needs no model call
modelthe agent'sThe model that writes the summary, from the same provider
instructionsnoneWhat the summary should also keep
windowfrom the modelThe context window in tokens, for a model the SDK does not know (128,000 otherwise)

The chat compacts before a message would take the conversation past at, says so, and keeps the whole conversation in its file; /compact and /context are described in Chat. Tokens are estimated as a quarter of the characters, the same in both SDKs, so at is a budget, not an exact count. The memory skill's older compaction: {threshold: ...} setting is still read when the agent file has no compaction: block. For the API, see Lifecycle.

Shared Context with WEBAGENTS.md (Python)

The Python loader gives every agent under a folder the context in a WEBAGENTS.md there: its body is prepended to the agent's instructions under a ## Background Context heading, and namespace, model and visibility are applied where the agent does not set them. skills and tools accumulate. The nearer file wins, and the agent's own file wins over every context file.

The search walks upward from the agent file and stops at the top of the project, the first folder holding a .git or a .webagents. It never reads your home folder. The TypeScript loader reads the agent file alone.

Why not AGENTS.md

AGENTS.md is a separate, cross-vendor standard for instructing coding agents about a repository: how to build it, how to run its tests, what conventions to follow. webagents does not read it. The two files answer different questions, and merging a repository's build instructions into a running agent's system prompt is not what either is for. Keep both if you need both.

Observability

observability: {otel: true} (or observability: true) records each run as OpenTelemetry spans that follow the GenAI semantic conventions: invoke_agent <agent> for the run, chat <model> for each model call (with the provider, the model and the token counts), execute_tool <tool> for each tool call, and settle_payment for a settle (with the credits). The metrics gen_ai.client.token.usage and gen_ai.client.operation.duration are recorded beside them. No message text, tool arguments or tool results are ever put in an attribute.

WEBAGENTS_OTEL=1 (or true, on, yes) switches it on without touching the file; the file wins when it says something. The SDK adds no dependency: spans are recorded when the OpenTelemetry API is installed (@opentelemetry/api in TypeScript, opentelemetry-api in Python) and a tracer provider is configured, as any OpenTelemetry exporter setup does, and nothing happens otherwise.

Environment Variables

Model keys, one per provider. An exported variable always wins; webagents secrets set <VAR> keeps one for later runs instead, and each CLI uses the keys it stored in the chat, -p, serve, the daemon, cron run, acp and mcp serve. Signed in with webagents login and without the key, the chats run the agent's model through Robutler instead.

ProviderVariable
OpenAIOPENAI_API_KEY
AnthropicANTHROPIC_API_KEY
GoogleGOOGLE_API_KEY, else GOOGLE_GEMINI_API_KEY, else GEMINI_API_KEY
xAIXAI_API_KEY
FireworksFIREWORKS_API_KEY
Ollamanone; OLLAMA_BASE_URL if the server is not at http://localhost:11434/v1

OPENAI_BASE_URL points the OpenAI skill at any OpenAI-compatible endpoint when the file names none; - openai: {base_url: ...} does the same for one agent. ROBUTLER_API_URL selects the platform. WEBAGENTS_DEBUG=1 adds tracebacks to CLI errors.

WEBAGENTS_AGENT_TOKEN is the agent's own platform key, for containers and CI. On a machine where you ran webagents publish in the agent's directory it is not needed: the SDKs find the key that command stored. The older names WEBAGENTS_API_KEY (platform skills) and ROBUTLER_API_KEY (TypeScript payments) are still read.

On this page