This is the full developer documentation for Everruns --- # Everruns Documentation > Tutorials, how-to guides, reference, and explanation for building and operating Everruns agents. Source: # Documentation Everruns is a **durable agentic harness engine** built on Rust. It provides APIs for managing agents, sessions, and long-running tasks, with real-time SSE event streaming and PostgreSQL-backed durability. Popular[Framework quickstart](https://everruns.com/docs/framework/quickstart/)[Docker Compose](https://everruns.com/docs/getting-started/docker-compose/)[Tools](https://everruns.com/docs/how-to/equip-agents-with-tools/)[Sessions API](https://everruns.com/docs/api/operations/tags/sessions/) ## Choose how you run Everruns [Start here compares the three →](https://everruns.com/docs/getting-started/introduction/) [Framework](https://everruns.com/docs/framework/quickstart/) Build and run agents inside a Rust process with the everruns crate. Nothing else to deploy. * [Quickstart](https://everruns.com/docs/framework/quickstart/) * [Agents and tools](https://everruns.com/docs/framework/agents/) * [Sessions](https://everruns.com/docs/framework/sessions/) * [Models and providers](https://everruns.com/docs/framework/models-and-providers/) `$ cargo add everruns` [Self-hosted](https://everruns.com/docs/getting-started/docker-compose/) Run the Platform (API, workers, PostgreSQL, UI) on infrastructure you control, starting with Docker Compose. * [Docker Compose quickstart](https://everruns.com/docs/getting-started/docker-compose/) * [Configure a model provider](https://everruns.com/docs/getting-started/docker-compose/#configure-llm-provider) * [Environment variables](https://everruns.com/docs/sre/environment-variables/) * [Architecture](https://everruns.com/docs/explanation/architecture/) `$ docker compose up -d` [Everruns Cloud](https://everruns.com/docs/getting-started/cloud/) Use the Platform at app.everruns.com without running it. A built-in model provider and $5 of starter credit; your own provider keys are optional. * [Get started with Cloud](https://everruns.com/docs/getting-started/cloud/) * [Personal access tokens](https://everruns.com/docs/getting-started/cloud/#3-create-a-personal-access-token) * [Credit and the spend cap](https://everruns.com/docs/getting-started/cloud/#credit-and-the-spend-cap) * [Bring your own keys](https://everruns.com/docs/getting-started/cloud/#bring-your-own-keys-optional) `https://app.everruns.com` ## What kind of help do you need? [LearnTutorialsStep-by-step lessons that end with a running agent. Start here if you're new.](https://everruns.com/docs/tutorials/run-an-agent/)[DoHow-to guidesTask-oriented recipes for common problems, when you know what you want to build.](https://everruns.com/docs/how-to/)[UnderstandExplanationBackground and design rationale: durable execution, sessions, and harnesses.](https://everruns.com/docs/explanation/)[Look upReferenceAPI endpoints, event types, the capability catalog, CLI flags, and environment variables.](https://everruns.com/docs/api/) --- # Budgets > Cap session spending in dollars, tokens, or custom credits, with soft pause thresholds and automatic enforcement. Source: Budgets let you cap how much a session (or agent, user, or organization) can spend. When a session hits its budget, Everruns stops scheduling further LLM calls. This prevents runaway costs from long-running or misbehaving agents. ![Budget Structure](https://everruns.com/docs/_astro/budget-structure.Co0JWPRZ_Z1X89MI.svg) ## How It Works After every LLM generation, Everruns computes the cost and debits it from any active budgets for that session. In subagent trees, session-scoped budgets are shared at the root session, so child and grandchild turns spend from the same pool. If the balance reaches zero, the session stops. 1. **LLM call completes**: Everruns extracts token counts (input + output). 2. **Compute debit**: Converts tokens to the budget’s currency: * `usd`: uses per-model pricing (cost per million tokens for input/output) * `tokens`: raw token count * `credits`: 1 credit = 1,000 tokens * Custom currencies fall back to token count 3. **Debit ledger**: Appends an immutable ledger entry and updates the balance. 4. **Evaluate rules**: Checks thresholds: * Balance at 20% of limit → warning event * Spending exceeds soft limit → session pauses * Balance reaches zero → session stops Enforcement is **post-hoc**: the check runs after each LLM call, not before. This avoids blocking the hot path. The last generation may slightly overshoot the limit; this is expected and by design. ## Currencies | Currency | Unit | How cost is calculated | | --------- | ----------------------- | ----------------------------------------------------------------------------- | | `usd` | US dollars | Per-model pricing from model profiles (input/output rates per million tokens) | | `tokens` | Raw tokens | Direct count of input + output tokens | | `credits` | 1 credit = 1,000 tokens | Token count divided by 1,000 | | Custom | Any string | Falls back to raw token count | USD budgets use real per-model pricing, so the same dollar limit buys far more turns on a small model than on a frontier one. These session and agent budgets are limits you set. They are separate from the prepaid credit balance of an organization on Everruns Cloud, which pays for the built-in model provider and stops it at zero balance. ## Soft Limits and Pausing A **soft limit** pauses the session before hitting the hard stop. This is useful in interactive sessions where a human can decide to top up or stop. 1. Spending exceeds `soft_limit` → budget status becomes `paused` 2. The worker detects the pause between atoms → stops scheduling the next LLM call 3. Session transitions to `paused` state 4. User can resume by increasing the limit, topping up, or calling the resume endpoint For headless sessions (no human watching), the hard limit fires at balance zero and terminates the turn. ## Stacked Budgets Multiple budgets can apply to the same session. The **most restrictive** budget wins. This lets you combine different types of limits: * A **$10 USD session budget** caps dollar cost * A **2M token budget** caps total token usage regardless of model pricing Budget stacking is enforced across the session hierarchy: root session, app channel, app, agent, user, and organization. The most restrictive matching budget wins. ## CLI Usage Set a budget when creating a session: ```bash # $10 USD budget (currency defaults to usd) everruns sessions create --budget-limit 10 # Explicit currency everruns sessions create --budget-limit usd:10 # With soft limit — pauses at $8, hard stop at $10 everruns sessions create --budget-limit usd:10 --budget-soft-limit usd:8 # Token budget everruns sessions create --budget-limit tokens:2000000 # Stacked — both limits, whichever hits first everruns sessions create --budget-limit usd:10 --budget-limit tokens:2000000 ``` ## MCP Usage The `agent_run` MCP tool accepts budget parameters directly: ```json { "name": "agent_run", "arguments": { "message": "Analyze this codebase", "agent_id": "agent_abc123", "budget_limit": 10.00, "budget_currency": "usd", "budget_soft_limit": 8.00 } } ``` Budget operations are also available as catalog commands via the `execute` tool: ```bash # Create a budget for an existing session create_budget --subject_type session --subject_id ses_xxx \ --currency usd --limit 10 --soft_limit 8 # Check a session's budget status check_session_budgets --session_id ses_xxx # Top up an exhausted budget top_up_budget --budget_id bdg_xxx --amount 5 --description "Extra allowance" # List all budgets for a session list_session_budgets --session_id ses_xxx ``` ## API ### Budget CRUD ```plaintext POST /v1/budgets Create budget GET /v1/budgets List budgets (?subject_type=&subject_id=) GET /v1/budgets/{id} Get budget with current balance PATCH /v1/budgets/{id} Update limit / soft_limit / status DELETE /v1/budgets/{id} Soft-delete (sets status=disabled) ``` ### Budget operations ```plaintext POST /v1/budgets/{id}/top-up Add credits (negative ledger entry) GET /v1/budgets/{id}/ledger Paginated ledger entries (?limit=&offset=) GET /v1/budgets/{id}/check Check budget status ``` ### Session shortcuts ```plaintext GET /v1/sessions/{id}/budgets List budgets for this session GET /v1/sessions/{id}/budget-check Check all budgets (session + hierarchy) POST /v1/sessions/{id}/resume Resume paused budgets ``` ### Create a session budget ```bash curl -X POST https://your-instance/api/v1/budgets \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subject_type": "session", "subject_id": "ses_01abc...", "currency": "usd", "limit": 10.00, "soft_limit": 8.00 }' ``` ### Top up an exhausted budget ```bash curl -X POST https://your-instance/api/v1/budgets/{budget_id}/top-up \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 5.00, "description": "Emergency top-up" }' ``` If the budget was `paused` or `exhausted` and now has positive balance, it automatically reactivates. ## Events Subscribe to budget events via SSE to react in real time: | Event | When | Key data | | ------------------ | ------------------------------- | ------------------------------------------- | | `budget.warning` | Balance at 20% of limit | `budget_id`, `balance`, `limit`, `currency` | | `budget.paused` | Spending exceeds soft limit | `budget_id`, `balance`, `soft_limit` | | `budget.exhausted` | Balance reaches zero | `budget_id`, `balance`, `limit` | | `budget.resumed` | User resumes after pause/top-up | `budget_id`, `balance`, `limit` | ## Agent Awareness The `budgeting` capability is included in the **Worker harness** by default. Any session using the Worker harness automatically gets budget-aware behavior: * The agent’s system prompt includes a “Budget Awareness” section with guidelines for efficient output when budget is constrained * The agent gets a `check_budget` tool to query remaining balance before expensive operations When budget is running low, a budget-aware agent will prioritize completing current tasks efficiently rather than exploring new directions. ## Budget Lifecycle ![Budget Lifecycle](https://everruns.com/docs/_astro/budget-lifecycle.CcFpzAwp_Z16kT5Q.svg) --- # Context Compaction > How Everruns manages LLM context windows through automatic compaction strategies, observation masking, summarization, and hierarchical memory tiers Source: Long-running agent sessions accumulate messages until they exceed the model’s context window. When that happens, the LLM rejects the request. **Context compaction** automatically reduces the conversation size so the agent can keep working without losing important information. Everruns provides multiple compaction strategies that can be combined. The default `auto` strategy cascades through all of them in order, from cheapest (free) to most expensive (LLM call), stopping as soon as the context fits. ![Context Window](https://everruns.com/docs/_astro/context-window.MRvRSZA5_Ws5VN.svg) ## How It Works Compaction operates at two points: 1. **Proactively**: before each LLM call, Everruns estimates the token count. If it exceeds a configurable budget threshold (default 85% of the model’s context window), compaction runs *before* the call is made. This avoids the latency of a failed request. 2. **Reactively**: if the LLM still returns a `RequestTooLarge` error (estimation can undercount), the compaction cascade runs and the request is retried automatically. In both cases, the same cascade of strategies executes: ![Compaction Cascade](https://everruns.com/docs/_astro/compaction-cascade.CHRb7Otd_Z2dF1WF.svg) The UI shows a divider between messages whenever compaction happens: > **Context compacted** · 142 → 38 messages · observation_masking+summarization Click the divider to see the cascade details, which strategies ran, how many messages each step produced, and the time taken. ## Strategies ### Auto (default) Runs all strategies in order. Stops as soon as context fits. This is the recommended setting for most use cases. ### Observation Masking Replaces old tool outputs with compact summaries while keeping the message structure intact. This is free (no LLM call) and preserves tool call IDs for tracing. Two summary formats: | Format | Example | When to use | | -------------------- | ----------------------------------------------------------- | --------------------------------- | | `one_line` (default) | `[read_file → 47 lines, 2340 bytes]` | Most cases, minimal footprint | | `head_tail` | First 3 lines + `... (14 lines omitted) ...` + last 3 lines | When partial output context helps | The most recent N tool outputs are always kept verbatim (default: 5). ### Native Provider Compaction Delegates compaction to the LLM provider’s own endpoint. Currently supported by OpenAI’s Responses API (`/responses/compact`). When available, this can be more intelligent than generic strategies since the provider understands its own tokenization. Everruns sends either a stateful response handle or a standalone transcript to the compact endpoint, never both. The returned ordered context is encrypted at rest as a durable checkpoint and reused across later turns and process restarts. Each request combines the latest checkpoint for the exact provider/model with raw messages written after its source boundary; changing provider or model falls back to raw history. Compaction never deletes or rewrites session events. Public `context.compacted` events contain only counts, timing, strategy, and an optional checkpoint identifier. Provider-native encrypted context remains confined to the internal provider and storage paths. ### Summarization Uses an LLM to generate a structured summary of older messages. The summary replaces those messages in context and is wrapped in `[CONVERSATION_SUMMARY]` tags so subsequent compactions can re-summarize it. You can configure: * Which model to use (default: same as the agent) * What information to preserve (decisions, files modified, errors, etc.) * Custom instructions appended to the summarization prompt ### Aggressive Trim Last resort. Drops the oldest messages to fit within the token budget. The system prompt and the most recent messages are always preserved. This is lossy, dropped messages cannot be recovered unless Infinity Context is enabled. ## Worker Harness Defaults The built-in **Worker** harness enables both `compaction` and `infinity_context` by default. Together they bound the active context while retaining older history without manual configuration. | Capability | Role | Default in Worker | | ---------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | | **Infinity Context** | Limits how many messages are loaded from the database into the prompt; provides `query_history` for retrieval | `context_budget_tokens: 100000`, `min_recent_messages: 10` | | **Context Compaction** | Reduces the size of messages that *are* in the prompt, masking tool outputs, summarizing, or trimming | `strategy: auto`, `proactive: true`, `budget_percent: 0.85` | The flow for a long-running Worker session: ![Compaction Session Flow](https://everruns.com/docs/_astro/compaction-session-flow.CE_nRiHo_1TFtua.svg) No configuration is needed, creating a session with the Worker harness gives you this behavior out of the box. To customize, override either capability’s config on the agent or session level. ## Configuration Compaction is a capability configured per agent or harness via `AgentCapabilityConfig`. ### Default (auto strategy, proactive) ```json { "capabilities": ["compaction"] } ``` ### Custom strategy and budget ```json { "capabilities": [ { "ref": "compaction", "config": { "strategy": "auto", "proactive": true, "budget_percent": 0.85 } } ] } ``` ### Observation masking only (no LLM calls) ```json { "capabilities": [ { "ref": "compaction", "config": { "strategy": "observation_masking", "observation_masking": { "keep_recent_tool_outputs": 10, "summary_format": "head_tail" } } } ] } ``` ### Summarization with a cheaper model ```json { "capabilities": [ { "ref": "compaction", "config": { "strategy": "summarization", "summarization": { "model": "claude-haiku-4-5-20251001", "preserve": ["decisions", "files_modified", "errors", "api_keys"], "instructions": "Focus on architecture decisions and API contract changes" } } } ] } ``` ### Full configuration with memory tiers ```json { "capabilities": [ { "ref": "compaction", "config": { "strategy": "auto", "proactive": true, "budget_percent": 0.80, "observation_masking": { "keep_recent_tool_outputs": 5, "summary_format": "one_line" }, "summarization": { "model": null, "preserve": ["decisions", "files_modified", "errors", "current_plan"], "instructions": null }, "memory_tiers": { "hot_messages": 20, "warm_messages": 100 } } } ] } ``` ## Configuration Reference ### Top-level | Field | Type | Default | Description | | ---------------- | ------- | -------- | -------------------------------------------------------------------------------- | | `strategy` | string | `"auto"` | Compaction strategy: `auto`, `native`, `observation_masking`, or `summarization` | | `proactive` | boolean | `true` | Compact before hitting context limits (recommended) | | `budget_percent` | float | `0.85` | Trigger proactive compaction at this fraction of the context window | For `auto` and `native`, proactive pressure invokes provider-native compaction when the driver supports it and stores the result as a durable checkpoint. The driver’s effective model context window takes precedence over the built-in profile, so external drivers can report their actual limit. Stateful `previous_response_id` requests skip local proactive pressure checks because their request body is only a delta over provider-held context; reactive too-large recovery remains available. A native result must materially reduce provider-reported tokens, or serialized bytes when token usage is unavailable: at least 5%, with a 32-unit floor for small measurements. Smaller results do not install or replace a checkpoint and do not emit `context.compacted`. A newly installed checkpoint is not proactively replaced again until a meaningful raw-message suffix has accumulated. Failed and no-op native attempts are also held behind a retry watermark until estimated input grows by both 4,096 tokens and 5%, avoiding repeated compact calls against the same source. Branch and rollback selection ignore watermarks from a different transcript lineage. When it is re-armed, the next native compact request preserves the prior opaque checkpoint items in order before appending that suffix, for both proactive and reactive compaction. ### Observation Masking | Field | Type | Default | Description | | -------------------------- | ------- | ------------ | ---------------------------------------------------------- | | `keep_recent_tool_outputs` | integer | `5` | Number of recent tool outputs to keep verbatim | | `summary_format` | string | `"one_line"` | How to summarize masked outputs: `one_line` or `head_tail` | ### Summarization | Field | Type | Default | Description | | -------------- | -------------- | ----------------------------------------------------------- | --------------------------------------------------------- | | `model` | string \| null | `null` | Model for summarization. Null = same as the agent’s model | | `preserve` | string\[] | `["decisions", "files_modified", "errors", "current_plan"]` | Information categories to preserve in summaries | | `instructions` | string \| null | `null` | Custom instructions appended to the summarization prompt | ### Memory Tiers | Field | Type | Default | Description | | --------------- | ------- | ------- | --------------------------------------------------------------- | | `hot_messages` | integer | `20` | Recent messages kept verbatim (full content) | | `warm_messages` | integer | `100` | Older messages with observation masking applied to tool outputs | Messages beyond hot + warm are in the **cold tier**: replaced with a conversation summary. If [Infinity Context](https://everruns.com/docs/capabilities/infinity-context/) is enabled, cold-tier messages remain queryable via `query_history`. ## Memory Tier Diagram ![Memory Tiers](https://everruns.com/docs/_astro/memory-tiers.DavDwkfC_Z16HEh7.svg) ## Combining with Infinity Context Compaction and [Infinity Context](https://everruns.com/docs/capabilities/infinity-context/) are complementary: * **Infinity Context** limits how many messages are loaded from the database into the prompt, and provides `query_history` for retrieval. * **Compaction** reduces the size of messages that *are* in the prompt, making tool outputs smaller, summarizing old turns, or trimming when nothing else works. For long-running sessions, enable both: ```json { "capabilities": [ "infinity_context", { "ref": "compaction", "config": { "strategy": "auto", "proactive": true } } ] } ``` With both active, the flow is: 1. Infinity Context limits messages loaded (e.g., last 100 messages) 2. Compaction masks old tool outputs in those messages 3. If still over budget, summarization or trim kicks in 4. Cold-tier messages remain accessible via `query_history` ## Events Compaction emits two SSE events: | Event | When | Key fields | | -------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `context.compacting` | Semantic compaction starts | `reason` (proactive_budget, request_too_large, manual), `strategy`, `messages_before`, optional `tokens_before` / `bytes_before` | | `context.compacted` | Material semantic reduction completes | `strategy_used`, `messages_before`, `messages_after`, optional before/after token or byte metrics, `duration_ms`, `steps[]`, optional `checkpoint_id` | Each step in the cascade is recorded with its strategy name, resulting message count, and duration. Provider-encrypted native compact content is never included in these public events. Observation masking alone remains an outbound model-view optimization and does not emit `context.compacted` because it installs no semantic checkpoint. ## Best Practices * **Start with defaults.** The `auto` strategy with `proactive: true` handles most cases well. * **Lower `budget_percent`** (e.g., 0.70) if your agents use large tool outputs frequently, this gives more headroom before the context fills. * **Increase `keep_recent_tool_outputs`** if your agent often references recent tool results across multiple turns. * **Use a cheaper model for summarization** (e.g., Haiku) to reduce cost and latency when the summarization step runs. * **Enable Infinity Context** alongside compaction for sessions that run for hours or days. * **Customize `preserve`** to match your agent’s domain, if your agent tracks database schemas or API contracts, add those to the preserve list. ## See Also * [Infinity Context](https://everruns.com/docs/capabilities/infinity-context/), Message history windowing and retrieval * [Capabilities Overview](https://everruns.com/docs/capabilities/), How capabilities are configured * [Harnesses](https://everruns.com/docs/features/harnesses/), Where capability configs are applied * [Events](https://everruns.com/docs/features/events/), SSE event streaming reference --- # ID Schema > How Everruns formats and validates public resource identifiers, Stripe-style prefixed IDs. Source: Every resource in the Everruns API (agents, sessions, skills, knowledge bases, and so on) is identified by a **prefixed public ID**. The prefix tells you at a glance what kind of resource you are looking at; the suffix is an opaque 32-character token. This pattern was popularized by Stripe (`cus_`, `sub_`, `pi_`). Treat the suffix as a meaningless string, do not parse it, sort by it, or infer information from it. The only guarantees the API makes about an ID are its format, its uniqueness within an organization, and its stability over the lifetime of the resource. ## Format All resource identifiers use the same shape: ```plaintext {prefix}_{32-hex-chars} ``` * `{prefix}` is a short lowercase token that identifies the resource type (for example `agent`, `session`, `skill`). * `_` separates the prefix from the suffix. * `{32-hex-chars}` is an opaque 32-character lowercase hexadecimal token. Example: ```plaintext agent_5c7f3a91b24e48d6a0e91f3b7c4d2e85 ``` Identifiers match a fixed pattern: the resource’s prefix, an underscore, then exactly 32 lowercase hexadecimal characters. For an `agent`, the literal regex is `^agent_[0-9a-f]{32}$`. The API rejects malformed values with `400 Bad Request`. ## Treat the suffix as opaque The suffix carries no public meaning. In particular: * **Do not sort by it.** Use `created_at` (or whatever timestamp field the resource exposes) for chronological ordering. * **Do not infer age, ordering, or shard placement from it.** The encoding may change without notice. * **Do not parse it as a UUID.** The hex format is a transport convenience; future resources may use different internal schemes while keeping the same wire format. This decoupling is intentional. The internal database key for a resource and its public ID are deliberately separate concepts, clients only ever see the public ID. ## Client-Supplied IDs For resources that accept client-supplied IDs on create, you can pass your own `id` as long as it matches the format above and uses the correct prefix for the resource type. If you omit `id`, the server assigns one. A subset of resources additionally expose `PUT /v1/{resource}/{id}` as an upsert: the same call creates the resource if it does not exist (`201 Created`) and updates it in place if it does (`200 OK`). Where supported, this makes idempotent provisioning straightforward, replay the same `PUT` and the end state is identical. The OpenAPI reference is the source of truth for which resources support this; not every resource has a `PUT` route. ## Serialization IDs are always serialized as JSON strings. The field name is `id` for the resource itself and `{resource}_id` when referenced from another resource: ```json { "id": "agent_5c7f3a91b24e48d6a0e91f3b7c4d2e85", "session_id": "session_2b8a4d12c673491fae058b7d9c1f6a40" } ``` ## Prefix Reference The prefix is part of the public contract for each resource. The most common ones are listed below; the canonical list lives in the OpenAPI specification. The prefix in the table below is the token that appears before the `_` separator, an `agent` resource has IDs that start with `agent_`. | Resource | Prefix | | -------------- | --------- | | Agent | `agent` | | Session | `session` | | Skill | `skill` | | Knowledge base | `kb` | | Memory | `mem` | | MCP server | `mcp` | | Schedule | `sched` | | Image | `img` | | Agent avatar | `avatar` | | User | `user` | | Organization | `org` | ## Design Notes | Question | Answer | | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Why prefixed IDs? | They make IDs self-describing and prevent accidentally passing, say, an agent ID where a session ID is expected. | | Why opaque suffixes? | Decoupling the wire format from internal storage gives the platform room to evolve without breaking clients, and prevents callers from leaning on accidental properties (ordering, creation time) that aren’t part of the contract. | | Why lowercase hex? | Case-insensitive matching, URL-safe, easy to copy and paste. | | Are IDs unique across organizations? | Each ID is unique within its owning organization. The same `id` value could in principle appear in two different orgs, but you only ever see IDs scoped to orgs you belong to. | --- # Network Access Control > Control which hosts and URLs agents can reach using layered allowlists and blocklists on harnesses, agents, and sessions Source: By default, agents with the `web_fetch` capability can access any public URL. **Network access lists** let you restrict which hosts and URLs an agent can reach, giving you fine-grained control over outbound network access. Access lists are configured at three levels, harness, agent, and session, and each layer can only make access *more* restrictive, never less. ## Configuration A network access list has two fields: | Field | Purpose | Default | | --------- | ---------------------------------------------- | --------------------- | | `allowed` | If non-empty, only matching URLs are permitted | `[]` (no restriction) | | `blocked` | Always denied, even if matched by `allowed` | `[]` | ### Pattern Format Patterns support three formats: | Format | Example | Matches | | --------------- | ----------------------------- | ------------------------------ | | Exact domain | `api.example.com` | Any URL on that exact domain | | Wildcard domain | `*.example.com` | The domain and all subdomains | | URL prefix | `https://api.example.com/v1/` | URLs starting with that prefix | Domain matching is case-insensitive. Blocked patterns always take precedence over allowed patterns. ### API Examples Set a network access list when creating or updating an agent: ```json POST /v1/agents { "name": "Research Agent", "system_prompt": "You are a research assistant.", "network_access": { "allowed": ["*.github.com", "api.openai.com"], "blocked": ["evil.example.com"] } } ``` Restrict a specific session further: ```json POST /v1/sessions { "agent_id": "agent_...", "network_access": { "blocked": ["internal.corp"] } } ``` To clear a network access list on update, send an empty object: ```json PATCH /v1/agents/{id} { "network_access": {} } ``` ## Layer Merging Network access lists merge across three layers using restrictive semantics, each layer can only narrow what the parent allows: ```plaintext Harness (baseline) ∩ Agent (can only restrict further) ∩ Session (can only restrict further) ``` The merge rules: | Field | Rule | Rationale | | --------- | ------------------------------------------------------------------------ | ------------------------------------------------- | | `allowed` | **Intersection**: child entries kept only if covered by a parent pattern | Child cannot grant access the parent didn’t allow | | `blocked` | **Union**: all blocked patterns combined | Child cannot un-block a parent’s block | If a child layer doesn’t set `allowed`, it inherits the parent’s list unchanged. ### Example Given this configuration: ```plaintext Harness: allowed: ["*.github.com", "*.openai.com"] Agent: allowed: ["api.github.com"], blocked: ["evil.com"] Session: blocked: ["malware.github.com"] ``` The effective policy for the session is: * **Allowed**: `["api.github.com"]`, kept because it’s a subset of `*.github.com`; `*.openai.com` dropped because the agent didn’t include it * **Blocked**: `["evil.com", "malware.github.com"]`, union of all layers Only `api.github.com` is reachable, and both `evil.com` and `malware.github.com` are explicitly denied. ### Harness Inheritance If a harness inherits from a parent harness (via `parent_harness_id`), the network access list is merged through the inheritance chain before any agent or session layer is applied. The same intersection/union rules apply. ## Enforcement The merged network access list is checked in `web_fetch` before every HTTP request. If a URL doesn’t match the effective policy, the tool returns an error: ```plaintext URL blocked by network access policy: https://blocked-domain.com/path ``` Standard SSRF protections (blocking private IPs, loopback, cloud metadata endpoints) are always enforced regardless of the network access list. These lists narrow what one agent may reach. The deployment-wide policy (`EVERRUNS_EGRESS_POLICY`), per-org grants and the optional tenant egress proxy sit underneath them; see [Outbound traffic](https://everruns.com/docs/advanced/physical-architecture/#outbound-traffic). ## Capabilities Affected | Capability | Enforced | Notes | | --------------- | -------- | --------------------------------------------- | | `web_fetch` | Yes | Checked before every HTTP request | | `bashkit_shell` | N/A | No network builtins (curl/wget not available) | --- # Physical Architecture > The physical components that make up an Everruns deployment, control plane, workers, PostgreSQL, NATS JetStream, Valkey, and the reverse proxy, and how they fit together. Source: The [getting-started architecture](https://everruns.com/docs/explanation/architecture/) page describes the *logical* shape of Everruns: a control plane, a worker tier, and a shared database. This page goes one level deeper and describes the *physical* components an operator actually deploys, what each one is for, when it is optional, and how data flows between them. ![Physical Architecture](https://everruns.com/docs/_astro/physical-architecture.imwAYMfQ_HhXX7.svg) ## Components at a glance | Component | Role | Required | Default port | | ---------------------- | -------------------------------------------------------------------------------------- | --------------------------- | --------------------------- | | Reverse proxy | TLS termination and route fan-out for `/api`, `/mcp`, `/.well-known/*`, UI | Yes (or equivalent ingress) | 443 | | Control plane (server) | REST API, SSE event streams, gRPC server for workers, owns all state | Yes | 9301 (HTTP), 9001 (gRPC) | | Worker pool | Stateless executors of the agentic loop: each leases a session and runs its whole turn | Yes | – (outbound only) | | PostgreSQL 17 | Durable storage for agents, sessions, events, durable task queue | Yes | 5432 | | NATS JetStream | Push-based ephemeral event delivery and task notifications | Optional | 4222 | | Valkey | Distributed sliding-window rate limiting across control-plane instances | Optional | 6379 | | Management UI | Operator interface for agent and provider configuration | Optional | – (served by proxy) | | Tenant egress proxy | Gives tenant outbound traffic its own address, per-org limits and usage counts | Optional | 4750 (proxy), 4751 (health) | Workers never talk to PostgreSQL, NATS, or Valkey directly. Every read and write goes through the control plane’s gRPC service on port 9001. This is what lets workers run with no database credentials, no encryption keys, and no awareness of the data tier. ## PostgreSQL, the only required stateful component PostgreSQL is the single source of truth for everything Everruns persists. There is no in-memory cache that needs warming, no secondary store that needs syncing, and no analytics database to keep consistent. If you back up PostgreSQL, you back up the entire system. What lives in PostgreSQL: * Agents, sessions, messages, and durable events * The session leases workers run turns under, and the durable task queue for background work (both claimed via `SKIP LOCKED`) * Encrypted LLM provider credentials, MCP server registrations, capability config * Per-session virtual filesystems, knowledge bases, and the event log used for SSE replay Operational requirements: * **PostgreSQL 17.** UUIDv7 is implemented via a custom SQL function; PG 18’s native `uuidv7()` will be adopted once it is widely available on managed services. * **Direct connection for `LISTEN/NOTIFY`.** Pooled or proxied endpoints (PgBouncer, Neon `-pooler`, RDS Proxy) interleave notification frames with query traffic. Set `DATABASE_URL` to the pooled endpoint for normal queries and `DATABASE_UNPOOLED_URL` to a direct session-scoped endpoint for listeners. Startup fails fast if the configured listener URL looks pooled. * **Pool sizing.** With `EXPECTED_INSTANCES=N` set, each instance sizes its pool so that `pool × instances` stays under 80% of `PG_MAX_CONNECTIONS`. * **Migrations.** Auto-applied on server startup via embedded sqlx migrations, protected by a PostgreSQL advisory lock so multiple control-plane instances can boot together without racing. See [`docs/sre/environment-variables.md`](https://everruns.com/docs/sre/environment-variables/) for the full list of database-related variables. ## NATS JetStream, optional push delivery NATS is not required, but turning it on materially reduces PostgreSQL write pressure and SSE tail latency for busy deployments. Without NATS, Everruns uses PostgreSQL for both storage *and* delivery: ephemeral events persist to PG and SSE clients poll PG with `LISTEN/NOTIFY` wakeups; workers are notified of new tasks the same way. This works, and it is the default. The cost is write amplification, every streaming-token delta lands in PG even though no client will ever re-read it. With `NATS_URL` set and JetStream enabled, Everruns rewires two hot paths: * **Ephemeral event delivery.** Delta events (`output.message.delta`, `reason.thinking.delta`, `tool.output.delta`, `llm.generation`) skip PostgreSQL entirely and flow only through NATS JetStream. SSE streams subscribe to per-session subjects with short-term retention. Durable events (`output.message.completed`, `turn.started`, `tool.completed`, etc.) still persist to PG so SSE reconnection via `since_id` continues to work, missed deltas are acceptable because the completed event carries the full content. * **Task notifications.** `task.available.{activity_type}` subjects replace PG NOTIFY for worker wakeup, dropping notification latency from \~30 ms to \~1 ms. NATS is fail-graceful: if the connection fails at startup, the control plane logs a warning and falls back to the PG-backed paths. Only the control plane connects to NATS, workers still talk to the server via gRPC. ## Valkey, optional distributed rate limiting Valkey is a Redis-compatible key-value store (a Linux Foundation fork of Redis). Everruns uses it for exactly one thing: sliding-window rate limiting that is coordinated across control-plane instances. When `VALKEY_URL` is not set, rate limiting falls back to an in-memory governor, accurate per-instance, but with N instances behind a load balancer a single IP can consume up to N× the intended budget. Set `VALKEY_URL` when you run more than one control-plane instance and need a shared budget. Connection details: * Accepts `redis://`, `rediss://` (TLS), `valkey://`, `valkeys://` (TLS) schemes * Uses atomic Lua scripts for sliding-window counters * **Fail-open:** if Valkey is unreachable, the rate limiter allows the request rather than rejecting traffic on a side-channel outage * Only the control plane connects to Valkey; workers do not need access ## Worker pool, no shared state Workers are the most operationally boring component in the deployment. They have: * No database connection * No encryption key * No NATS or Valkey access * No durable local state They claim a task from the control plane over gRPC, fetch the turn context in a single batched call, run the agentic loop (LLM calls, tool execution), and stream events back. If a worker crashes mid-task, the heartbeat stops, the control plane reclaims the task after 30 seconds, and another worker picks it up. Add workers for throughput; remove them to save cost. See [Worker authentication](https://everruns.com/docs/sre/runbooks/durable-mode-setup/) for the `WORKER_GRPC_AUTH_TOKEN` and optional mTLS setup that secures this internal channel. ## Reverse proxy contract A reverse proxy (or platform ingress that enforces the same routes) is mandatory in production: | Route | Destination | Notes | | ---------------- | ------------- | ----------------------------------- | | `/api/*` | Control plane | Disable proxy buffering for SSE | | `/mcp` | Control plane | Do **not** rewrite under `/api` | | `/.well-known/*` | Control plane | OAuth discovery; do **not** rewrite | | `/health` | Control plane | Health check target | | Everything else | UI | If UI is deployed; otherwise 404 | TLS terminates at the proxy. Worker gRPC traffic stays on the private network, never expose port 9001 publicly. See [`local/Caddyfile`](https://github.com/everruns/everruns/blob/main/local/Caddyfile) and [`examples/docker-compose-full.yaml`](https://github.com/everruns/everruns/blob/main/examples/docker-compose-full.yaml) for working configurations. ## Outbound traffic The control plane and workers both make outbound calls, and Everruns splits them in two: * **Platform traffic** is what the deployment itself owns: LLM providers, the utility model, system email, sandbox provider APIs. It always leaves directly, from the deployment’s own address. * **Tenant traffic** is what an agent, a capability, an MCP server or an integration chooses: web fetches, tool calls to third-party APIs, remote MCP servers. Every such request goes through one boundary, the egress service, which applies the policy below and writes an audit line with its org, session and decision (`everruns::egress::audit` log target). ### Egress policy `EVERRUNS_EGRESS_POLICY` decides which public hosts tenant traffic may reach: | Mode | Behavior | | ---------------- | ---------------------------------------------------------------------------------------------------- | | `open` (default) | Any public host. | | `curated-writes` | GET and HEAD reach any public host; writes, MCP and integration traffic need the built-in allowlist. | | `curated-all` | Every request needs the allowlist. | In both curated modes a built-in deny list is checked first, URLs are capped at 2048 characters and IP-literal hosts are refused. An organization can be granted extra hosts or open egress for its own traffic; see [Network Access Control](https://everruns.com/docs/advanced/network-access/). Private, loopback and cloud metadata addresses are refused in every mode, with DNS pinned so a lookup cannot be swapped between the check and the connection. ### Tenant egress proxy Set `EVERRUNS_EGRESS_PROXY_URL` and `EVERRUNS_EGRESS_PROXY_SECRET` on the control plane and workers, and tenant traffic leaves through `everruns-egress-proxy` instead of directly. Platform traffic never uses it. You get two things: * **Its own outbound address.** Give the proxy host a separate public IP. If a tenant’s traffic gets that address blocked somewhere, model calls, email and billing keep working, and the address can be replaced without touching the rest of the deployment. * **Per-org limits and usage.** Each request carries a five-minute token, signed with the shared secret, that names its org and session. The proxy verifies the token, resolves the destination again and refuses non-public addresses and SMTP ports, applies per-org caps, and counts bytes and requests per org and session each minute. The binary ships in the server image. Limits are off unless you set them, and usage goes to the log (`everruns::egress::usage` target). A control endpoint (`EGRESS_PROXY_CONTROL_URL`) can supply limits per org and receive usage instead. A proxy URL with a missing or short secret fails closed: tenant requests error rather than leave directly. Variables: [Tenant egress proxy](https://everruns.com/docs/sre/environment-variables/#tenant-egress-proxy). ```bash # Proxy host EVERRUNS_EGRESS_PROXY_SECRET=<32+ random bytes> EGRESS_PROXY_ORG_RPM=600 # optional caps EGRESS_PROXY_ORG_BYTES_PER_DAY=5000000000 everruns-egress-proxy # Control plane and workers EVERRUNS_EGRESS_PROXY_URL=http://egress-proxy:4750 EVERRUNS_EGRESS_PROXY_SECRET= ``` ## Development modes The same binaries collapse into smaller deployments for local work: * **`DEV_MODE=true` (single process).** Nothing to install or run beside the binary: the server starts a temporary PostgreSQL of its own and deletes it on exit. Execution runs in-process inside the server binary; the gRPC server is disabled. Data is lost on restart. Useful for UI iteration and API development. * **`just start-all` (full local).** Brings up PostgreSQL, Valkey, and NATS as local processes (no Docker required) and starts the server + worker against them. Mirrors production wiring on a single machine. * **Docker Compose.** The production-shaped topology in one machine; see [Docker Compose](https://everruns.com/docs/getting-started/docker-compose/). ## Multi-instance deployment Multiple control-plane instances can run behind a load balancer with no session affinity: | Concern | How it stays correct | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | Database connections | `EXPECTED_INSTANCES=N` divides the pool so `pool × instances ≤ 80% of PG_MAX_CONNECTIONS` | | SSE delivery | `LISTEN/NOTIFY` or NATS subjects fan out to every instance; reconnects are idempotent | | Turn and task claiming | `SKIP LOCKED` on session leases and the durable task queue partitions work naturally; a session’s fenced lease keeps one worker on it | | Migrations | PostgreSQL advisory lock prevents concurrent runs | | Rate limits | Valkey-backed sliding-window counters are shared; in-memory falls back to per-instance | Workers do not require coordination, add as many as you need, in as many regions as you need, as long as they can reach the control-plane gRPC port. ## Further reading * [Architecture (Getting Started)](https://everruns.com/docs/explanation/architecture/), the logical model * [Environment Variables](https://everruns.com/docs/sre/environment-variables/), every knob and its default * [Network Access Control](https://everruns.com/docs/advanced/network-access/), per-agent and per-org outbound rules * [Docker Compose](https://everruns.com/docs/getting-started/docker-compose/), a production-shaped local setup * [Custom backends](https://everruns.com/docs/framework/custom-backends/), low-level execution-host composition --- # Tool Output Pipeline > How Everruns processes tool results from execution to the model, verbosity budgets, distillation, persistence, hard limits, and where the full output lives Source: Agents generate most of their context from **tool output**: shell commands, file reads, web fetches, SQL queries, and MCP tool calls. Left unmanaged, a single verbose command (`git diff`, a 10,000-row query, an installer log) can blow past the model’s context window, drive up cost, and bury the signal the agent actually needs. Everruns runs every tool result through a **multi-stage pipeline** that shrinks what the model sees while keeping the full original recoverable. This page explains each stage, the order they run in, and, crucially, *where the full output goes* so the agent can get it back. ## The big picture ```plaintext tool runs │ ▼ raw output ──────────────────────────────────────────────┐ │ │ (full, lossless) ▼ │ 1. Verbosity budget (exec/sandbox tools only) │ │ auto/concise/normal/verbose/full │ ▼ │ 2. Capability hooks │ │ • Tool Output Distillation (non-exec tools) │ ▼ ▼ 3. Final infrastructure hooks /outputs/ │ • Persist Output (exec tools → VFS) {tool_call_id}.stdout │ • Output Hard Limit (64 KiB ceiling) {tool_call_id}.stderr ▼ ▲ inline result → stored in the session, │ shown to the model next turn ──────────────────────┘ (read_file recovers the full original) ``` Two ideas run through the whole pipeline: 1. **Storage stays lossless.** Whatever the model sees inline, the full output is written to the session filesystem (the *destination*). The inline view always carries a pointer back to it. 2. **Each stage shrinks, none deletes.** Truncation, distillation, and masking only change the *view*. The agent can always `read_file` the persisted original. ## Stage 1: Verbosity budget (exec tools) Exec and sandbox tools (`bash`, `*_exec`, sandboxed shells) clean their output (strip ANSI, collapse carriage returns) and apply a **verbosity budget** before returning. The mode is configurable per call; the default is `auto`: * **Success (`exit_code == 0`)** → collapse to a compact summary (\~512 bytes), because the full log is persisted (Stage 3) and the agent rarely needs it inline. * **Failure (non-zero exit)** → keep a larger diagnostic window (\~8 KiB) so the error stays debuggable in-loop. The full pre-truncation output is stashed on the result as `raw_output` for the persistence hook to consume. Non-exec tools (MCP, web fetch, client tools) do **not** have a verbosity budget, that gap is what Stage 2 exists for. ## Stage 2: Tool Output Distillation (non-exec tools) [Tool Output Distillation](https://everruns.com/docs/capabilities/) targets the tools Stage 1 doesn’t: **MCP tools and `web_fetch`**, whose results otherwise enter history verbatim. It runs as a capability hook, so it executes *before* the final hooks. For a large non-exec result, distillation produces a compact, **content-aware** inline view: | Output shape | What you get inline | | ---------------- | ---------------------------------------------------------------------------- | | Large JSON array | Schema-preserving sample: the first few rows + `[… N more items elided …]` | | Long string | Head + tail window (both ends preserved), with a byte-elision marker | | Unified diff | A diffstat-style summary: file + hunk headers and `+added / -removed` counts | | Nested object | Each oversized field distilled; small fields untouched | Before it replaces anything, distillation **persists the full original** to the session filesystem (same destination as Stage 3) and injects a recovery pointer. If persistence fails, or the session has no filesystem, it restores the verbatim output rather than leave a lossy result the agent can’t recover. **Reversibility is never sacrificed.** Distillation is on by default in **Worker** and the harnesses built on it. Every transform is deterministic, so identical output distills identically and the model provider’s prompt cache keeps hitting across turns. ## Stage 3: Persistence and the hard limit Two infrastructure hooks always run last, in order: 1. **Persist Output**: for tools that declare the `persist_output` hint (exec/sandbox), writes the full `raw_output` to the session VFS. When content is absent from the inline result, it adds a recovery pointer; complete inline results keep the retained file internal and do not invite a redundant read. It **skips** if a result already carries `output_files` (e.g. distillation already persisted it), so the two never double-write. 2. **Output Hard Limit**: a final, unremovable 64 KiB ceiling. By the time it runs, the result has usually already been budgeted or distilled, so it rarely fires; it’s a backstop against pathological cases. ## The destination, where full output lives Everything the pipeline elides is recoverable from the **session filesystem**: ```plaintext /outputs/{tool_call_id}.stdout ← full standard output /outputs/{tool_call_id}.stderr ← full standard error (when present) ``` When the inline result omits persisted content, it carries the recovery pointer in `output_files` and `full_output`, plus a human-readable note telling the model to use `read_file` (with `offset`/`limit`) for the missing detail. Complete inline output has no model-facing pointer. Persisted streams are capped at 1 MiB each. Deleting the session cascades and removes them. This is the key to aggressive shrinking: because the original is one `read_file` away, the inline view can be small without the agent losing the ability to drill in. ## How this relates to compaction The pipeline above operates on **individual tool results at capture time**. [Context Compaction](https://everruns.com/docs/advanced/compaction/) operates **later**, across the whole conversation, when it approaches the context window, masking or summarizing older messages at serialization time. They compose cleanly: * The pipeline keeps each result lean as it’s produced. * Compaction further masks older results when the *accumulated* history grows too large. * [Infinity Context](https://everruns.com/docs/capabilities/) adds a `query_history` tool to retrieve older *messages* that scrolled out of the window. Together: the pipeline controls per-result size, compaction controls total-history size, and both keep the full record recoverable. ## Summary | Stage | Applies to | Effect | Destination of full output | | ----------------- | -------------------------- | -------------------------------------------------------- | --------------------------------------------- | | Verbosity budget | exec/sandbox | Compact summary on success, diagnostic window on failure | `raw_output` → persisted in Stage 3 | | Distillation | MCP / web fetch / non-exec | Content-aware compact view | `/outputs/{id}.stdout` | | Persist Output | `persist_output` tools | Lossless write + pointer | `/outputs/{id}.{stdout,stderr}` | | Output Hard Limit | all | 64 KiB ceiling backstop | (already persisted) | The agent always sees a lean view and can always recover the full original with `read_file`. --- # Built-ins Overview > Built-in harness types and capabilities that ship with Everruns. Harnesses define reusable behavior; Agent Sandbox Template bindings select compute. Source: Everruns ships with built-in **harness types** and **capabilities** that provide the foundation for agent sessions. ## Harnesses A harness defines reusable session behavior: system prompt, default model, starter files, network policy, and bundled capabilities. Every session is assigned a harness. An Agent [Sandbox Template binding](https://everruns.com/docs/features/sandbox-templates/) independently selects the filesystem and compute target for new sessions. | Harness | Description | Capabilities | | -------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------- | | [Base](https://everruns.com/docs/built-ins/harnesses/base/) | System essentials every agent needs | Compaction, error disclosure, tool-call repair, loop detection, approval guidance | | [Conversation](https://everruns.com/docs/built-ins/harnesses/conversation/) | Default for dialogue, no workspace | Base + structured questions, message timestamps | | [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) | Worker without compute | Base + files, AGENTS.md, skills, long context, budgeting, subagents, tasks | | [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) | Worker with the Bashkit virtual shell | Worker + Bashkit shell, fixed Sandbox Template | | [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/) | Worker with a full sandbox | Worker + the shell of a container or managed Sandbox Template | | [Worker Base (deprecated)](https://everruns.com/docs/built-ins/harnesses/worker-base/) | Deprecated legacy bundle | Files, bash, project instructions | | [Generic (deprecated)](https://everruns.com/docs/built-ins/harnesses/generic/) | Deprecated legacy bundle | 25 configured | | [Data Analyst](https://everruns.com/docs/built-ins/harnesses/data-analyst/) | SQL databases, charts, persistent memory | Bashkit Worker + data capabilities; available as a built-in example | [Platform Chat](https://everruns.com/docs/built-ins/harnesses/platform-chat/) is a managed Agent bound to Bashkit Worker. ![Built-in harness tree](https://everruns.com/docs/_astro/harness-tree.CeZx85x1_1TFtua.svg) See the [Harnesses feature guide](https://everruns.com/docs/features/harnesses/) for harness selection, API management, and the prompt stack model. ## Harness Examples Harness examples are adoptable templates. Import them when you want a preconfigured starting point, then customize the resulting org-owned harness. | Example | Import Name | Description | | ------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | Coding | `coding` | Sandbox Worker + coding behavior and GitHub Scout; the Agent Sandbox Template binding selects Daytona, a container, or another full sandbox | | Data Analyst | `data-analyst` | Bashkit Worker + SQL databases, charts, persistent memory, and curated data knowledge | ## Capabilities Capabilities are modular units that extend what an agent can do. Each can contribute tools, system prompt additions, and UI features. Browse the full [Capabilities reference](https://everruns.com/docs/capabilities/) for the complete list organized by category. --- # Base Harness > The root of the built-in harness tree, carrying the system essentials every agent needs to run reliably. Source: The **Base** harness is the root of the [built-in harness tree](https://everruns.com/docs/features/harnesses/#built-in-harnesses). It carries only what every agent needs to run reliably, and adds no workspace, shell or chat tools. ## When to Use * Custom tool composition on a reliable foundation * Testing individual capabilities without a workspace or delegation * Building your own harness family with Base as the parent ## Configuration | Property | Value | | ----------------- | ---------------------------------------------------------------------------------------------------------- | | **Name** | `base` | | **Parent** | None | | **Capabilities** | Context compaction, error disclosure, tool-call repair, loop detection, parallel tool calls, soft approval | | **System Prompt** | None. When no harness, agent or session supplies a prompt, the runtime uses “You are a helpful assistant.” | | **Default Model** | None (inherits from agent or organization) | Soft approval is guidance, not a permission wall. It adds the approval tools and costs nothing on safe work; turn it off per agent with `{"mode": "off"}`. ## Usage Assign the Base harness when creating an agent or session: ```bash curl -X POST http://localhost:9300/api/v1/agents \ -H "Content-Type: application/json" \ -d '{ "name": "Minimal Agent", "harness_name": "base", "capabilities": ["web_fetch"] }' ``` The agent’s own capabilities are added on top. In this example `web_fetch` is the only domain tool. ```rust let harness = everruns::Harness::base(); ``` For a harness with no capabilities at all, build one with `Harness::builder` in the Framework or create a custom harness without a parent on the Platform. ## See Also * [Conversation Harness](https://everruns.com/docs/built-ins/harnesses/conversation/), the default for simple dialogue * [Worker Harness](https://everruns.com/docs/built-ins/harnesses/worker/), the worker kit without compute * [Harnesses feature guide](https://everruns.com/docs/features/harnesses/), the tree and how to choose --- # Bashkit Worker Harness > Worker plus the Bashkit virtual shell, sealed to one recoverable Bashkit virtual workspace. Source: **Bashkit Worker** extends [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) with the Bashkit shell and fixes the primary Sandbox to Everruns’ managed Bashkit Virtual Workspace. | | | | ------------------- | ----------------------------------------------- | | **Name** | `bashkit-worker` | | **Parent** | `worker` | | **Adds** | `bashkit_shell` | | **Sandbox policy** | Fixed; Agent and Session overrides are rejected | | **Primary Sandbox** | Managed Bashkit Virtual Workspace | Use Bashkit Worker for support, operations, and general assistants that need a durable virtual filesystem and Bash-like commands but do not need native packages, processes, ports, or PTYs. It needs no sandbox provider, and the logical Sandbox and workspace survive replacement of runtime compute. [Platform Chat](https://everruns.com/docs/built-ins/harnesses/platform-chat/) runs on it. Choose [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/) when an agent needs a real machine, or [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) when it needs no shell. Add `sandbox_fleet` separately when an Agent should keep its primary workspace while creating and operating multiple explicitly addressed resource Sandboxes. Custom Harnesses may inherit from Bashkit Worker, but they inherit the sealed Sandbox policy as well. Renaming the child or changing its capabilities does not make the primary Sandbox overridable. ```rust let harness = everruns::Harness::bashkit_worker(); ``` --- # Conversation Harness > The default harness for simple dialogue, with no workspace and no shell. Source: Conversation inherits [Base](https://everruns.com/docs/built-ins/harnesses/base/) and adds the two chat affordances, `ask_user` for structured questions and `message_metadata` so the model sees when each message was sent. It provides no filesystem, bash, storage, delegation or web search tools. Add [Web Search](https://everruns.com/docs/capabilities/web-search/) on the agent when an assistant should search. It is the organization default. Use it for chat assistants, support bots and Q\&A. Dad Jokes uses this harness plus `current_time`. Add task-specific capabilities on the agent when needed. Workers do not inherit Conversation: [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) builds on Base directly, so an unattended worker does not pick up chat affordances it has no one to use with. Choose `conversation` with the API’s `harness_name` or the CLI’s `--harness` option. ```rust let harness = everruns::Harness::conversation(); ``` Framework constructors load the same capability data as the hosted presets. Enable the host integrations required by the tools you use; a preset does not compile optional integrations into your application. See [Harnesses](https://everruns.com/docs/features/harnesses/) for selection and inheritance. --- # Data Analyst Harness > Data analysis harness with SQL databases, persistent memory, interactive charts, and a structured analysis pipeline inspired by OpenAI's Dash. Source: The **Data Analyst** harness extends the [Bashkit Worker harness](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) with capabilities for data analysis: SQL databases, cross-session agent memory, rich visualization via OpenUI, and a curated knowledge scaffold. Its system prompt implements a structured 6-step analysis pipeline inspired by [OpenAI’s Kepler data agent](https://openai.com/index/inside-our-in-house-data-agent/) and the open-source [Dash](https://github.com/agno-agi/dash) project. ## When to Use * Natural-language data analysis (ask questions, get SQL + charts) * Interactive data exploration with visualization * Agents that learn from corrections and remember them across sessions * Analytics workflows grounded in curated knowledge bases (table docs, business rules, validated SQL) ## Configuration | Property | Value | | ----------------- | ------------------------------------------ | | **Type** | `data-analyst` | | **System Prompt** | Structured 6-step analysis pipeline | | **Default Model** | None (inherits from agent or organization) | ## Analysis Pipeline The system prompt guides the agent through six steps on every data question: 1. **Recall**: Read `/memory/agent/` for corrections, column mappings, and business definitions from earlier sessions 2. **Inspect**: Use `sql_schema` to verify table structure before writing SQL 3. **Plan**: State the query plan: tables, joins, filters, expected grain, and potential pitfalls 4. **Execute & Validate**: Run the query, then validate (zero rows? duplicates? NULL aggregations?). Self-correct if results look wrong 5. **Visualize**: Summarize findings in plain language, then render charts and tables via OpenUI 6. **Learn**: Write corrections and patterns to a file under `/memory/agent/` for future sessions This mirrors the six-layer context pattern described in [OpenAI’s data agent blog post](https://openai.com/index/inside-our-in-house-data-agent/) and implemented by [Dash](https://github.com/agno-agi/dash). ## Bundled Capabilities All [Bashkit Worker harness capabilities](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) plus: | Capability | What it provides | | -------------------- | --------------------------------------------------------------------------------------------------------- | | Session SQL Database | `sql_execute`, `sql_query`, `sql_schema`, session-scoped SQLite databases that auto-create on first write | | OpenUI | Rich interactive charts, tables, dashboards, and KPI cards rendered inline in chat | | Todo List | `write_todos`, track multi-step analysis tasks | | Data Knowledge | Mounts `/knowledge/` scaffold with directories for table docs, business rules, and validated SQL patterns | ## Knowledge Files The harness mounts a `/knowledge/` directory scaffold in every session: ```plaintext /knowledge/ index.md tables/index.md # Add one .md per table: columns, types, gotchas business/index.md # Add metric definitions, business rules, domain terms queries/index.md # Add validated .sql files as reusable templates ``` These files are read-only scaffolds. Populate them with your organization’s curated knowledge to ground the agent’s SQL generation in reality. The agent reads these files before writing any SQL query. Combined with [agent memory](https://everruns.com/docs/features/memory-scopes/), which the server mounts at `/memory/agent` in every session of the agent and which the agent edits with its file tools, this implements the layered context pattern: | Layer | Source | | ----------------------- | ---------------------------------------- | | Table usage & schema | `sql_schema` tool + `/knowledge/tables/` | | Business annotations | `/knowledge/business/` + AGENTS.md | | Validated queries | `/knowledge/queries/` | | Institutional knowledge | MCP servers (Slack, Notion, Confluence) | | Learning memory | Files under `/memory/agent/` | | Runtime context | `sql_query` / `sql_execute` | ## Example Session ```plaintext User: Load this CSV and tell me which product category has the highest revenue Agent: [reads /memory/agent/] [inspects any existing schema] [creates table, imports data] [runs SELECT category, SUM(revenue) ... GROUP BY category] [validates: 5 categories, no NULLs, totals match] [renders bar chart via OpenUI] [appends to /memory/agent/corrections.md: "revenue is net of refunds"] ``` ## See Also * [Bashkit Worker Harness](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/), the parent harness this extends * [Capabilities overview](https://everruns.com/docs/features/capabilities/), full capability catalog including memory and OpenUI * [Harnesses feature guide](https://everruns.com/docs/features/harnesses/), harness selection and API management --- # Generic Harness (deprecated) > The default harness, bundling core capabilities for general-purpose agent sessions. Source: The **Generic** harness is deprecated. Existing agents, sessions and child harnesses retain its legacy behavior. Choose [Conversation](https://everruns.com/docs/built-ins/harnesses/conversation/) for dialogue, [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) for files, skills and delegation, or [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) or [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/) for a shell. Generic is not an alias for Worker. It configures 25 capabilities. Together they cover file operations, command execution, web access, memory, budgeting, context management, durable tool output, citations, and runtime safeguards. ## Legacy use * General-purpose assistants * Coding and scripting tasks * Research workflows * Any session where you want a solid set of defaults ## Configuration | Property | Value | | ----------------- | ------------------------------------------------------------- | | **Type** | `generic` | | **System Prompt** | Instruction hierarchy only; the agent’s own prompt follows it | | **Default Model** | None (inherits from agent or organization) | ## Bundled Capabilities | Capability | What it provides | | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [File System](https://everruns.com/docs/capabilities/file-system/) | Read, write, edit, list, grep, stat, and delete files in the session workspace (`/workspace`) | | [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/) | Sandboxed bash shell for running commands, scripts, and text processing | | [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/) | Fetch web content with file download support | | [Storage](https://everruns.com/docs/capabilities/session-storage/) | Key/value store for general data and encrypted secret storage | | [Session](https://everruns.com/docs/capabilities/session/) | Access session metadata and manage session title | | [Session Schedules](https://everruns.com/docs/capabilities/session-schedules/) | Create and manage cron-style schedules that wake the session | | [AGENTS.md](https://everruns.com/docs/capabilities/agent-instructions/) | Reads AGENTS.md from workspace and injects project-level instructions | | [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/) | Discover and activate skills from `/.agents/skills/` | | [Infinity Context](https://everruns.com/docs/capabilities/infinity-context/) | Trims older messages from the live prompt while exposing earlier history via `query_history` | | [Auto Tool Search](https://everruns.com/docs/capabilities/tool-search/#auto-tool-search) | Defers tool schema loading to reduce prompt size, using the provider’s native tool search where available | | [Context Compaction](https://everruns.com/docs/advanced/compaction/) | Auto-compacts context at 85% budget via cascading strategies | | [Budgeting](https://everruns.com/docs/capabilities/budgeting/) | Budget awareness in the system prompt and a `check_budget` tool, which currently returns a placeholder; use the REST budget-check endpoint for detailed status | | [Self-Budget](https://everruns.com/docs/capabilities/self-budget/) | Prompt-only guidance for reasoning about a user-requested indicative budget using session usage data | | [Ask User](https://everruns.com/docs/capabilities/ask-user/) | Ask the user 1–4 structured questions, or collect a credential, and wait for the answer | | Soft Approval | Prompt-level gate asking permission before a destructive, irreversible, or outward-facing action | | Tool Output Persistence | Persists full tool output to `/.outputs/` before truncation for lossless retrieval | | Tool Output Distillation | Distills large tool output before it enters the context | | [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/) | Claim-level citations for answers drawn from retrieval feeds | | [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/) | Stamps faithfulness verdicts on citations (deterministic `heuristic` mode by default) | | [Parallel Tool Calls](https://everruns.com/docs/capabilities/parallel-tool-calls/) | Prefers parallel tool calls where the provider supports them | | [Message Metadata](https://everruns.com/docs/capabilities/message-metadata/) | Annotates messages with timestamps | | Human Intent | Adds model-authored intent narration to each tool call for UI rendering | | BTW | Ephemeral side-question command for the current session | | Tool Loop Detection | Detects repeated tool loops and injects a warning to break them | | Error Disclosure | Shows full provider error detail (`detailed` mode) | Infinity Context and Context Compaction work together to bound the active context while retaining older history. See [Context Compaction](https://everruns.com/docs/advanced/compaction/#worker-harness-defaults) for details. ## See Also * [Base Harness](https://everruns.com/docs/built-ins/harnesses/base/), empty harness for full control * [Platform Chat Harness](https://everruns.com/docs/built-ins/harnesses/platform-chat/), focused operator chat built on Base * [Harnesses feature guide](https://everruns.com/docs/features/harnesses/), harness selection and API management --- # Platform Chat > The managed Agent for Everruns platform conversations, running on Bashkit Worker. Source: **Platform Chat** is a managed Agent that helps you operate your Everruns organization. It runs on [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/), which supplies a sealed, recoverable Bashkit virtual workspace. The Agent supplies its identity, instructions, platform access, introduction, conversation starters, and durable operator memory. Platform Chat is built in and read-only: you cannot edit, archive, or delete it from the UI or the API. Use **Copy** on its page to make an editable Agent from it. ## Chat and side conversations The sidebar’s **Chat** entry always opens your permanent conversation. It cannot be renamed, unpinned, archived, deleted, or reassigned. **New chat** opens a fresh side conversation with the same Agent. Its session is created when you send the first message; it starts without copied conversation history or workspace files. **All chats** lists your side conversations. Playground conversations and runs with other agents stay outside Chat. Use Playground to select an Agent or harness and test its behavior. ## Chat beside your pages Organization owners and admins can enable **Chat mode** in **Settings > Features**. Open an app page, then click **Chat** or press **Command-J** (**Ctrl-J** on Windows and Linux). The permanent conversation opens beside the current page. **Back to app** restores the full page and keeps the conversation and composer draft. Each message shares the current page’s identity with Chat. On an Agent page, Chat can read the live form, including unsaved instructions and configuration, and apply requested edits to that draft. Gold markers identify **Draft edited by Chat**. Review the result, then use **Save changes** to persist it or **Discard** to reset the draft. Draft **Undo** restores the preceding form values, including your earlier manual edits, and refuses to overwrite later manual edits. If you change the form while Chat is thinking, its stale patch fails so it can read the current draft again. Chat does not edit credentials or connection grants through this form; sandbox policy uses its dedicated editor. For separately requested saved-resource operations, Platform Chat still uses platform commands. Page context does not disable those operations, and a failed form edit is never permission to bypass review by saving directly. Agent saves attributed to the conversation receive persisted-change markers and **Undo all**. That Undo creates a history entry and checks the saved revision; unsupported inverses fail without saving. If a saved definition changes while your draft is dirty, the page keeps the draft and blocks Save until you discard it and review the latest definition. Chat can read page identity, current filters and bounded summaries of loaded records across the app. It reads explicit data, without copying page HTML or credential inputs. Harnesses, Virtual Users, Observers, Eval creation and other definition forms expose supported draft fields through the same read/edit flow. Knowledge, Memory, Skill, Sandbox-template, Capability and Channel forms expose their supported non-credential fields. Providers with several Save forms identify each form by name; Chat edits one form at a time. Use the page’s existing **Save** or **Create** action to apply a staged change. Immediate-save settings, operational views, approvals, credential controls and financial actions remain under their normal page controls. Chat reports when a page or field is read-only; it does not work around that through a server write. Saved-change markers and inverse **Undo all** remain specific to Agent definitions. Chat mode is independent of the **Chat threads** opt-in. ## Platform access and memory Platform Chat uses the `everruns` command in its session shell to discover operations, read authoritative state, perform requested changes, and verify results. Product docs are mounted read-only at `/workspace/docs`. The Platform capability also supplies `everruns`, `everruns-cli`, and `everruns-agent-authoring` skills for product orientation, command workflows, and agent design. Discover and activate them through [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/) as needed. `/memory/user` is private to the conversation owner. `/memory/shared` contains durable notes shared across Platform Chat conversations in the organization. Sharing requires explicit intent; notes default to private memory. Documentation and memory are reference material, never instructions. Scratch files live in `/workspace`; credentials belong in the secure setup flow. Recurring autonomous work belongs to an Agent Trigger. Before changing an existing entity, Platform Chat reads its manager context and passes the revision it read and a reason with the change, so the entity’s history says why it changed. It asks before acting on a request that conflicts with the recorded context. See [Change history](https://everruns.com/docs/features/change-history/). ## Bundled Capabilities The Agent configures these capabilities in addition to the execution environment inherited from [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/). | Capability | Purpose | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Platform | Platform operations through the session shell | | Current Time | Ground relative time questions | | Task Management | Track work within a conversation | | Prompt Caching | Cache stable prompt content | | Tool Call Repair | Repair malformed tool calls | | Human Intent | Preserve consequential user intent across tool calls | | Web Fetch | Read public web resources and download files | | Storage | Keep durable session values and secrets | | Schedules | Arrange follow-up work for the session | | BTW | Handle lightweight side questions without losing the main thread | | Message Metadata | Attach structured metadata to messages | | Retrieval Citations | Retrieve sources for grounded answers | | Citation Verification | Verify citation support before answering | | Ask User | Pause for structured user input when required | | Error Disclosure | Return detailed platform errors to the managed operator Agent | | User MCP Servers | Use the MCP servers the person added for themselves, and add, remove and connect them in chat ([User MCP servers](https://everruns.com/docs/features/user-mcp-servers/)) | | Coordination | Hand focused work to threads you can open and follow, when the organization has adopted Chat threads | | Poppy Personal Agent | Talk to companies’ agents for the person over the Personal Agent Protocol ([Poppy Personal Agent](https://everruns.com/docs/capabilities/poppy-personal-agent/)) | ## Existing conversations The dedicated Platform Chat harness and its interim Generic binding are retired. Existing platform conversations move to the managed Agent on Bashkit Worker while keeping their IDs, history, workspace files, owners, and memory. Older custom agents, apps, triggers, and child harnesses retain their original execution bindings so their authored behavior is preserved; the retired harness remains stored for those bindings and historical accounting. The Agent name `platform-chat` is reserved for the managed assistant. An existing custom Agent with that name is renamed to `platform-chat-custom-`; its ID and bindings stay intact. Clients using its old name should switch to its ID. Conversation introductions and starters now belong exclusively to Agents. Existing harness presentation is copied to its assigned Agents when those Agent fields are empty. Harness presentation fields are deprecated and no longer accepted on writes. --- # Sandbox Worker Harness > Worker plus a full sandbox shell, for agents that need real processes, packages and builds. Source: **Sandbox Worker** extends [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) and requires a full sandbox: a container or a managed provider such as Daytona, E2B or Modal. The Agent’s Sandbox policy chooses which one. | | | | ------------------- | ----------------------------------------------------------- | | **Name** | `sandbox-worker` | | **Parent** | `worker` | | **Sandbox policy** | Required; must name a container or managed Sandbox Template | | **Primary Sandbox** | Whatever the Agent’s policy selects | Use it for coding agents, data work that installs packages, browser automation and long builds. The [Coding](https://everruns.com/docs/how-to/customize-a-harness/) harness example builds on it. Sandbox Worker never falls back to Bashkit: * Saving an Agent whose Sandbox policy can only resolve to Bashkit is rejected. * An Agent with no Sandbox policy saves, but starting a Session on it fails with a message that names the missing policy. Choose [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) for a virtual shell that needs no provider. Custom Harnesses that inherit from Sandbox Worker inherit the requirement too. Sandbox Worker is a Platform harness. In the Framework, express the same need as an Environment requirement on your harness and bind an Environment that provides it. See [Sandbox Templates](https://everruns.com/docs/features/sandbox-templates/) for configuring providers. --- # Worker Harness > The worker kit with no compute, for agents that work through tools, MCP servers and files. Source: Worker inherits [Base](https://everruns.com/docs/built-ins/harnesses/base/) and adds everything a working agent needs except a shell: session files, project instructions (`AGENTS.md`), session tools, durable and distilled tool output, skills, history retrieval, automatic tool discovery, budget awareness, todo lists, subagents, task controls and [Web Search](https://everruns.com/docs/capabilities/web-search/) on the organization’s default provider. It runs no code. Choose it for agents that act through tools and MCP servers: triage and integration agents over Linear, Slack or GitHub, research agents over knowledge and files, and organizations that want no code execution at all. It needs no sandbox provider. Worker is also the parent of the two shell workers: * [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) adds the Bashkit virtual shell. * [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/) adds a full sandbox. An Agent on Worker may still set a Sandbox policy; the selected Sandbox Template then supplies the shell. Pick one of the shell workers when the agent always needs one. Subagents create separate child sessions. Ordinary children inherit the parent configuration; blueprints provide specialist behavior. Depth and root-tree task limits bound delegation. Assigning this harness requires permission to assign its high-risk capabilities. Web fetch, secret/KV tools, organization memory mounts and session scheduling remain opt-in. Recurring agent execution is configured with Agent Triggers. Choose `worker` with the API’s `harness_name` or the CLI’s `--harness` option. ```rust let harness = everruns::Harness::worker(); ``` Framework constructors load the same capability data as the hosted presets. Enable the host integrations required by the tools you use; a preset does not compile optional integrations into your application. Delegation also needs a host with subagent and task backends. The default in-memory framework host does not supply these services; unregistered capability references remain inert. See [Harnesses](https://everruns.com/docs/features/harnesses/) for selection and inheritance. --- # Worker Base Harness (deprecated) > Retired level kept for existing agents; new agents choose Worker, Bashkit Worker or Sandbox Worker. Source: **Worker Base** was the middle of the old single chain (Base, Conversation, Worker Base, Worker). The [harness tree](https://everruns.com/docs/features/harnesses/#built-in-harnesses) replaced it: its files and project instructions moved into [Worker](https://everruns.com/docs/built-ins/harnesses/worker/), and its shell moved into [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) and [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/). The row stays active and managed, with its name, ID, parent (Conversation) and capabilities unchanged, so agents, sessions and adopted harness examples bound to it keep working. Selectors hide it until you choose Show deprecated. | Instead of Worker Base | Choose | | --------------------------- | ------------------------------------------------------------------------------- | | Files and bash, no provider | [Bashkit Worker](https://everruns.com/docs/built-ins/harnesses/bashkit-worker/) | | Files and a real machine | [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/) | | Files and tools, no shell | [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) | In the Framework, `Harness::worker_base()` is deprecated and returns `Harness::bashkit_worker()`. --- # Read Tools > Parameters, pagination, content-type defaults, and exec output retrieval for the read-category tools. Source: Agents spend most of their context window on tool results. A single `cat` of a large file can consume thousands of tokens that crowd out reasoning space. The read-category tools are built to return the part the agent asked for and nothing else. Three tools form the read category: | Tool | Purpose | | ---------------- | ---------------------------------------------------------------------------------- | | `read_file` | Read file content with offset/limit pagination and line numbers | | `grep_files` | Search file contents by regex — returns matching lines with paths and line numbers | | `list_directory` | List files and directories with metadata (size, type) | Together they implement a **search → locate → read** workflow: `grep_files` finds where something is, `read_file` reads the relevant section, and `list_directory` provides structural context. ## read_file ### Parameters | Parameter | Type | Default | Description | | --------- | ------- | ------------ | --------------------------------------------------- | | `path` | string | *(required)* | Absolute file path (e.g., `/workspace/src/main.rs`) | | `offset` | integer | 0 | Starting line number (0-indexed) | | `limit` | integer | 2000 | Maximum lines to return | ### Response ```json { "path": "/workspace/src/main.rs", "content": "1|use std::io;\n2|use serde::Serialize;\n3|\n4|fn main() {\n...", "total_lines": 450, "lines_shown": { "start": 1, "end": 450 }, "truncated": false, "content_type": "source", "read_mode": "offset", "size_bytes": 12480, "content_hash": "sha256:a1b2c3..." } ``` Key response fields: * **`content`** — Line-numbered output in compact `N|content` format. The `N|` prefix uses minimal bytes while giving agents precise line references for edits. * **`total_lines`** — Total lines in the file. Use this to know if more content exists beyond the current window. * **`lines_shown`** — 1-based start/end of the returned window. * **`truncated`** — `true` if more content exists beyond the returned window. * **`content_type`** — Detected content type (e.g., `log`, `csv`, `minified`, `source`). Reflects the heuristic applied. * **`read_mode`** — `tail` when reading log files from the end; `offset` otherwise. * **`content_hash`** — SHA-256 hash of the file content, used by `edit_file` for compare-and-set safety. ### Content-Type Defaults When the agent doesn’t specify `offset` or `limit`, `read_file` adjusts defaults based on file extension: | Content Type | Extensions | Default Limit | Read Mode | Rationale | | ------------ | --------------------------------- | ------------- | ------------------- | ------------------------------------------------------ | | Source code | `.rs`, `.ts`, `.js`, `.py`, etc. | 2000 lines | From offset | Standard — agent usually needs context around a region | | Log files | `.log`, `.out` | 500 lines | **From end (tail)** | Errors cluster at the end — recent output matters most | | CSV/TSV data | `.csv`, `.tsv` | 100 lines | From offset | Schema + sample rows; header always included | | Config | `.json`, `.yaml`, `.yml`, `.toml` | 2000 lines | From offset | Usually need full structure | | Minified | `.min.js`, `.min.css` | 20 lines | From offset | Single-line files would blow token budgets | | Text | `.md`, `.txt`, `.rst` | 2000 lines | From offset | Standard | **Explicit parameters override only the defaults they control.** An explicit `limit` overrides the content-type default limit. An explicit `offset` does **not** change the default limit by itself; it only controls where reading starts, and for log files it disables the default tail-biased read mode in favor of reading from that offset. If both `offset` and `limit` are provided, both behaviors are explicitly controlled. For CSV files, the header row (line 1) is always included in the response, even when reading with an offset. This ensures the agent always has column names for context. ### Image and Binary Handling * **Images** (`.png`, `.jpg`, `.gif`, `.webp`) are returned as **native image content blocks**, not text. The agent sees the image directly. * **Binary files** (base64-encoded) are returned with `"encoding": "base64"` and no line formatting. * A **hard byte cap** (50 KB) acts as a safety net for pathological files like minified bundles. ## Pagination For files larger than the default window, page through with `offset` and `limit`: ```json // First read — gets lines 1-2000 { "path": "/workspace/big_file.rs" } // Response shows total_lines: 5000, truncated: true // Continue reading: { "path": "/workspace/big_file.rs", "offset": 2000, "limit": 2000 } // Gets lines 2001-4000. Continue until truncated: false. ``` The 2000-line default covers most source files entirely in a single read. For the rare cases where files are larger, the `total_lines` field tells the agent exactly how much remains. ## Keeping read results small The system prompt guides agents toward efficient reading patterns: 1. **Search before read** — Use `grep_files` to find relevant lines, then `read_file` with a targeted `offset` around the match. This avoids reading thousands of irrelevant lines. 2. **Don’t re-read** — Files already in conversation context don’t need to be read again. The agent should reference prior reads. 3. **Check `total_lines`** — When a read is truncated, the agent knows how much remains and can decide whether to continue or search within the unread portion. 4. **Use offset to continue** — After a truncated read, use `offset` to pick up where the previous read left off. ## Exec Output as Readable Files When sandbox tools (`bash`, `daytona_exec`, `e2b_exec`, etc.) produce output, the inline result is truncated based on the `output` verbosity parameter (default: `concise` \~2 KiB). But the **full output is always persisted** to the session filesystem. ### How It Works The `tool_output_persistence` capability (included in the Generic harness) writes full output before truncation: * **stdout** → `/.outputs/{tool_call_id}.stdout` * **stderr** → `/.outputs/{tool_call_id}.stderr` The truncated inline result includes metadata pointing to the persisted files: ```json { "stdout": "[truncated to 2 KiB — full output saved]", "stderr": "", "exit_code": 0, "success": true, "full_output": "/.outputs/call_abc123.stdout", "total_lines": 8450, "output_files": [ "/.outputs/call_abc123.stdout", "/.outputs/call_abc123.stderr" ] } ``` The agent can then `read_file` the persisted output selectively: ```json // Read last 100 lines of build output { "path": "/.outputs/call_abc123.stdout", "offset": 8350, "limit": 100 } ``` ### Priority-Aware Truncation When output is truncated, the system preserves error-relevant content. Lines matching error patterns (`error`, `Error`, `FAILED`, `panicked`, stack traces) are prioritized over noise like `Compiling...` or `Downloading...`. This means the inline 2 KiB concise output is more likely to contain the diagnostically useful parts. ### Output Verbosity Modes All exec tools accept an `output` parameter: | Mode | Budget | Use case | | --------- | --------- | ---------------------------------- | | `silent` | \~200 B | Fire-and-forget commands | | `concise` | \~2 KiB | Builds, installs (**default**) | | `normal` | \~8 KiB | General debugging | | `verbose` | \~16 KiB | Test failures, error investigation | | `full` | unlimited | When the agent needs every line | ## Content Hash and Edit Safety Every `read_file` response includes a `content_hash` (SHA-256). The `edit_file` tool requires this hash via its `expected_hash` parameter — if the file has changed since the read, the edit is rejected. This **compare-and-set** mechanism prevents stale edits in long conversations where the agent may have read a file many turns ago and the file has since been modified (by another tool call or external process). ```json // read_file returns content_hash { "content_hash": "sha256:a1b2c3..." } // edit_file uses it as expected_hash — rejected if file changed { "path": "/workspace/src/main.rs", "expected_hash": "sha256:a1b2c3...", "old_text": "fn main() {", "new_text": "fn main() -> Result<()> {" } ``` If an edit is rejected due to a stale hash, the agent should re-read the file to get the current content and hash, then retry the edit. ## Structural Outlines When `read_file` returns a truncated result, the response includes a **structural outline** of the unread portions — function/class/method signatures without bodies. The agent can orient itself in any file with a single partial read. ```plaintext 1|use std::collections::HashMap; 2|use serde::Serialize; ... (lines read normally) ... 100| let result = process(&input); --- Outline of lines 101-500 (not shown) --- // L105: fn process(input: &Input) -> Result { ... } // L180: fn validate(output: &Output) -> bool { ... } // L220: struct Config { ... } // L235: impl Config { ... } // L236: fn load(path: &str) -> Result { ... } // L270: fn merge(&mut self, other: &Config) { ... } // L310: #[cfg(test)] mod tests { ... } ``` ### Supported Languages | Language | Extensions | | ---------- | ----------------------------- | | Rust | `.rs` | | TypeScript | `.ts`, `.tsx`, `.mts` | | JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | | Python | `.py` | ### What Gets Outlined * **Functions/methods** — name, parameters, return type * **Structs/classes/enums** — name * **Impl blocks / trait implementations** — with nested methods * **Modules** — including `#[cfg(test)]` detection * **Interfaces and type aliases** (TypeScript) For unsupported languages, no outline is generated — the response still works, just without structural context for unread portions. --- # Capabilities Overview > Capabilities give an agent tools, system prompt fragments, and execution features. Index of every built-in capability. Source: Capabilities are modular units that extend what an agent can do. Each capability can contribute: * **Tools**: callable functions the agent can invoke during conversations * **System prompt additions**: context and instructions prepended to the agent’s prompt * **Features**: UI elements unlocked when the capability is active (e.g., Workspace tab) Agents compose capabilities; enable only what you need. ## Capability Reference Every capability a production deployment offers, with the number of tools it adds by default. Rows marked **dev-only** are registered only at the `dev` deployment grade. A `FEATURE_*` variable identifies a [rollout grade override](https://everruns.com/docs/sre/environment-variables/#feature-rollout-grades); organisation enrolment also applies before assigning or using gated capabilities. ### Core Fundamental capabilities for file operations, command execution, web access, session management, time awareness, task tracking, scheduling, and agent coordination. | Capability | ID | Tools | | ---------------------------------------------------------------------------------------------------- | --------------------------- | ----------------------------------------------------------- | | [File System](https://everruns.com/docs/capabilities/file-system/) | `session_file_system` | 10 | | [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/) | `bashkit_shell` | 1 | | [Tools in Shell](https://everruns.com/docs/capabilities/tools-in-shell/) | `tools_in_shell` | 1 (`tools`, hidden from the model; it is the shell command) | | [Host Shell](https://everruns.com/docs/capabilities/host-shell/) | `host_shell` | 1 (Framework-only) | | [Session](https://everruns.com/docs/capabilities/session/) | `session` | 2 | | [Automatic session titles](https://everruns.com/docs/capabilities/automatic-session-titles/) | `automatic_session_titles` | 0 | | [Storage](https://everruns.com/docs/capabilities/session-storage/) | `session_storage` | 2 | | [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/) | `web_fetch` | 1 | | [Web Search](https://everruns.com/docs/capabilities/web-search/) | `web_search` | 1 | | [Current Time](https://everruns.com/docs/capabilities/current-time/) | `current_time` | 1 | | [Message Metadata](https://everruns.com/docs/capabilities/message-metadata/) | `message_metadata` | 0 | | [Ask User](https://everruns.com/docs/capabilities/ask-user/) | `ask_user` | 1 | | [Task Management](https://everruns.com/docs/capabilities/task-management/) | `stateless_todo_list` | 2 | | [Schedules](https://everruns.com/docs/capabilities/session-schedules/) | `session_schedule` | 3 | | [Auto-Continue After Usage Limit](https://everruns.com/docs/capabilities/usage-limit-auto-continue/) | `usage_limit_auto_continue` | 0 | | [AGENTS.md](https://everruns.com/docs/capabilities/agent-instructions/) | `agent_instructions` | 0 | | [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/) | `skills` | 2; `FEATURE_SKILLS` grade | | Channel Thread Context | `channel_context` | 0 | | System Commands | `system_commands` | 0 | ### Orchestration Delegating work to other sessions and running it in the background. | Capability | ID | Tools | | ------------------------------------------------------------------------------------ | ---------------------- | --------------------------------------------------------- | | [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/) | `subagents` | 0 (contributes the `spawn_agent` delegation target) | | Session Tasks | `session_tasks` | 5 | | Background Execution | `background_execution` | 1 | | [Agent Handoff](https://everruns.com/docs/capabilities/agent-handoff/) | `agent_handoff` | 0 (contributes the `agent` `spawn_agent` target) | | [A2A Agent Delegation](https://everruns.com/docs/capabilities/a2a-agent-delegation/) | `a2a_agent_delegation` | 0 (contributes the `external_a2a` `spawn_agent` target) | | AG-UI Agent Delegation | `ag_ui_delegation` | 0 (contributes the `external_ag_ui` `spawn_agent` target) | | [Coordination](https://everruns.com/docs/framework/coordination/) | `coordination` | 5 | ### Sandboxes Cloud and container sandbox environments for isolated code execution. | Capability | ID | Tools | | -------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------------------------- | | Managed Environment | `session_sandbox` | 8 | | [Sandbox Desktop](https://everruns.com/docs/capabilities/computer-use/#desktop-in-a-sandbox) | `sandbox_desktop` | 1 (added by a Sandbox Template with a desktop) | | [Sandbox Fleet](https://everruns.com/docs/capabilities/sandbox-fleet/) | `sandbox_fleet` | 8 | | [Daytona](https://everruns.com/docs/capabilities/daytona/) | `daytona` | 10 | | [E2B](https://everruns.com/docs/capabilities/e2b/) | `e2b` | 6 | | [Container Sandbox](https://everruns.com/docs/capabilities/container-sandbox/) | `container_sandbox` | 8 (needs `FEATURE_CONTAINER_SANDBOX=prod`) | | [Docker Container](https://everruns.com/docs/capabilities/docker/) | `docker_container` | 5 (off by default, needs `FEATURE_DOCKER_CAPABILITY` rollout grade) | ### Browser Browser automation and web interaction capabilities. | Capability | ID | Tools | | -------------------------------------------------------------------- | -------------- | ------------------------------------------- | | [Browserless](https://everruns.com/docs/capabilities/browserless/) | `browserless` | 7 | | [Browser Use](https://everruns.com/docs/capabilities/browser-use/) | `browser_use` | 1; `FEATURE_BROWSERLESS_BROWSER_USE` grade | | [Computer Use](https://everruns.com/docs/capabilities/computer-use/) | `computer_use` | 1; `FEATURE_BROWSERLESS_COMPUTER_USE` grade | ### Data and knowledge Structured data, knowledge retrieval, and memory. | Capability | ID | Tools | | -------------------------------------------------------------------------------------- | ----------------------- | ---------------------------- | | [SQL Database](https://everruns.com/docs/capabilities/sql-database/) | `session_sql_database` | 3 | | [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/) | `citation_retrieval` | 0 | | [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/) | `citation_verification` | 0 | | [Web Citations](https://everruns.com/docs/capabilities/citation-web/) | `citation_web` | 0 | | [Data Knowledge](https://everruns.com/docs/capabilities/data-knowledge/) | `data_knowledge` | 0 | | [Knowledge](https://everruns.com/docs/capabilities/knowledge/) | `knowledge` | 2; `FEATURE_KNOWLEDGE` grade | | [Memory](https://everruns.com/docs/capabilities/memory/) | `memory` | 0; `FEATURE_MEMORY` grade | ### Media Image generation and editing workflows. | Capability | ID | Tools | | ------------------------------------------------------------------------------------------ | --------------- | ----- | | [OpenAI Image Generation](https://everruns.com/docs/capabilities/openai-image-generation/) | `gpt_image_gen` | 2 | ### Models and provider tools Provider-executed tools and model selection. | Capability | ID | Tools | | ------------------------------------------------------------------------------------------ | --------------------------- | ------------------------------------ | | [OpenAI Server Tools](https://everruns.com/docs/capabilities/openai-server-tools/) | `openai_server_tools` | 0 | | [OpenRouter Server Tools](https://everruns.com/docs/capabilities/openrouter-server-tools/) | `openrouter_server_tools` | 0 | | Model Scout | `model_scout` | 0 | | OpenRouter Workspace | `openrouter_workspace` | 2 | | OpenAI Agents API Runtime | `openai_agents_api_runtime` | 0; `FEATURE_OPENAI_AGENTS_API` grade | ### Integrations External-service capabilities and blueprint-backed workflows. | Capability | ID | Tools | | ------------------------------------------------------------------------------------ | -------------------- | ------------------------------------ | | [GitHub](https://everruns.com/docs/capabilities/github/) | `github` | 6 (7 with `allow_pull_requests`) | | [GitHub Scout](https://everruns.com/docs/capabilities/github-scout/) | `github_scout` | 0 | | [Slack](https://everruns.com/docs/capabilities/slack/) | `slack` | 4 | | Cursor | `cursor` | 9 | | [Agentic Resource Discovery](https://everruns.com/docs/integrations/ard/) | `resource_discovery` | 3 | | [AgentID Sign-In](https://everruns.com/docs/integrations/agentid/) | `agentid` | 1 | | [Brave Search](https://everruns.com/docs/integrations/brave-search/) | `brave_search` | 1 | | [DuckDuckGo](https://everruns.com/docs/integrations/duckduckgo/) | `duckduckgo` | 1 | | [Parallel Search and Fetch](https://everruns.com/docs/integrations/parallel/) | `parallel_search` | 0 (2 hosted MCP tools from Parallel) | | [Jev Decisions](https://everruns.com/docs/integrations/typesafe/) | `jev` | 1 | | [User MCP Servers](https://everruns.com/docs/capabilities/user-mcp-servers/) | `user_mcp` | 6 (only with `manage` on) | | [Poppy Personal Agent](https://everruns.com/docs/capabilities/poppy-personal-agent/) | `poppy_client` | 5 | ### Platform Agent self-management and platform control. | Capability | ID | Tools | | ------------------------------------------------------------ | ---------- | ----- | | [Platform](https://everruns.com/docs/capabilities/platform/) | `platform` | 3 | ### Generative UI Structured UI the agent renders in the chat. | Capability | ID | Tools | | ---------- | -------- | ----- | | OpenUI | `openui` | 0 | | A2UI | `a2ui` | 0 | ### Optimization Performance and cost optimization for LLM interactions. | Capability | ID | Tools | | ---------------------------------------------------------------------------------------- | --------------------- | ----------------------------------------------------------- | | [Infinity Context](https://everruns.com/docs/capabilities/infinity-context/) | `infinity_context` | 1 | | [Context Compaction](https://everruns.com/docs/advanced/compaction/) | `compaction` | 0 | | [Dreaming](https://everruns.com/docs/features/dreaming/) | `dreaming` | 0; `FEATURE_DREAMING` grade; organization Adoption opt-in | | [Auto Tool Search](https://everruns.com/docs/capabilities/tool-search/#auto-tool-search) | `auto_tool_search` | 0 (adds `tool_search` on models without native tool search) | | [OpenAI Tool Search](https://everruns.com/docs/capabilities/tool-search/#hosted-openai) | `openai_tool_search` | 0 | | [Claude Tool Search](https://everruns.com/docs/capabilities/tool-search/#hosted-claude) | `claude_tool_search` | 0 | | [Tool Search](https://everruns.com/docs/capabilities/tool-search/#client-side) | `tool_search` | 1 | | [Budgeting](https://everruns.com/docs/capabilities/budgeting/) | `budgeting` | 1 | | [Self-Budget](https://everruns.com/docs/capabilities/self-budget/) | `self_budget` | 0 | | [Parallel Tool Calls](https://everruns.com/docs/capabilities/parallel-tool-calls/) | `parallel_tool_calls` | 0 | | Native Async Tools | `native_async_tools` | 0 | | [Prompt Caching](https://everruns.com/docs/capabilities/prompt-caching/) | `prompt_caching` | 0 | ### Safety Streaming-output guardrails and runtime safety nets. | Capability | ID | Tools | | ------------------------------------------------------------------------------------------ | ------------------------- | ----- | | [Prompt Canary Guardrail](https://everruns.com/docs/capabilities/prompt-canary-guardrail/) | `prompt_canary_guardrail` | 0 | | [Tool Call Repair](https://everruns.com/docs/capabilities/tool-call-repair/) | `tool_call_repair` | 0 | | [Output Truncation](https://everruns.com/docs/capabilities/output-truncation/) | `output_truncation` | 0 | | [Guardrails](https://everruns.com/docs/capabilities/guardrails/) | `guardrails` | 0 | | [Tool Approval](https://everruns.com/docs/capabilities/tool-approval/) | `tool_approval` | 0 | | [Dry Run](https://everruns.com/docs/capabilities/dry-run/) | `dry_run` | 0 | | Progress Guard | `progress_guard` | 0 | | [Soft Approval](https://everruns.com/docs/capabilities/soft-approval/) | `soft_approval` | 3 | | [Tool Loop Detection](https://everruns.com/docs/capabilities/loop-detection/) | `loop_detection` | 0 | The [`guardrails`](https://everruns.com/docs/capabilities/guardrails/) capability runs config-driven checks over model output and tool activity, blocking or logging per check. Checks can be deterministic (regex, blocklist, tool-call patterns) or model-backed, an `llm_judge` policy or a `moderation` decision, plus delegation to an external guardrail over scoped MCP. Each check binds a rule to a stage (`output`, `tool_use`, `tool_output`) with an `on_fail` of `block` or `log`; model-backed and MCP checks send a bounded excerpt off the sync path and fail open. Use advisory mode and the `POST /v1/capabilities/guardrails/dry-run` endpoint to tune against false positives before enforcing. For ready-made starting points, list the gallery at `GET /v1/capabilities/guardrails/examples`, each preset carries a `data_egress` signal (`none` vs. `utility_llm`), and drop a preset’s `config` into the agent’s `guardrails` capability config. ### Automation Run shell commands at lifecycle and tool events. Block, mutate, or audit agent actions from outside the model. | Capability | ID | Tools | | ---------------------------------------------------------------- | ------------ | ----- | | [User Hooks](https://everruns.com/docs/capabilities/user-hooks/) | `user_hooks` | 0 | Harnesses also compose capabilities that are settings rather than features: Human Intent, BTW, Error Disclosure, and Tool Output Persistence and Distillation. The canonical [harness levels](https://everruns.com/docs/features/harnesses/) and [Platform Chat](https://everruns.com/docs/built-ins/harnesses/platform-chat/) harness pages describe them. ## Quick Start ### Enable via API ```bash curl -X POST http://localhost:9300/api/v1/agents \ -H "Content-Type: application/json" \ -d '{ "name": "My Agent", "system_prompt": "You are a helpful assistant.", "capabilities": ["session_file_system", "bashkit_shell", "web_fetch"] }' ``` ### Enable via UI 1. Navigate to the Agent detail page 2. Open the **Capabilities** section 3. Toggle capabilities on/off 4. Reorder with drag handles (order affects system prompt priority) 5. Save ### List available capabilities ```bash curl http://localhost:9300/api/v1/capabilities ``` ### Create a declarative capability Declarative capabilities are persisted capability definitions made from data: system prompt text, scoped MCP servers, text file mounts, and skill packages. They use a public resource ID like `cap_...` and a stable capability reference like `declarative:research_pack`. ```bash curl -X POST http://localhost:9300/api/v1/capabilities \ -H "Content-Type: application/json" \ -d '{ "definition": { "name": "research_pack", "display_name": "Research Pack", "description": "Default research behavior and resources.", "system_prompt": "Prefer primary sources and cite them clearly.", "risk_level": "low" } }' ``` Agents and harnesses can use the canonical reference: ```json { "ref": "declarative:research_pack" } ``` For convenience, agent and harness write APIs also accept the plain unique name when it matches a declarative capability: ```json { "ref": "research_pack" } ``` ## Key Concepts ### Dependencies Some capabilities depend on others. Dependencies are resolved automatically at runtime, you don’t need to manually add them. | Capability | Depends On | | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Tools in Shell](https://everruns.com/docs/capabilities/tools-in-shell/) | [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/) | | [Host Shell](https://everruns.com/docs/capabilities/host-shell/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Platform](https://everruns.com/docs/capabilities/platform/) | [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/), [File System](https://everruns.com/docs/capabilities/file-system/) (when embedded docs are enabled) | | [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [GitHub Scout](https://everruns.com/docs/capabilities/github-scout/) | [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/) | | Managed Environment | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [Sandbox Desktop](https://everruns.com/docs/capabilities/computer-use/#desktop-in-a-sandbox) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [Sandbox Fleet](https://everruns.com/docs/capabilities/sandbox-fleet/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [E2B](https://everruns.com/docs/capabilities/e2b/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [Daytona](https://everruns.com/docs/capabilities/daytona/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [Browserless](https://everruns.com/docs/capabilities/browserless/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [Browser Use](https://everruns.com/docs/capabilities/browser-use/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [Computer Use](https://everruns.com/docs/capabilities/computer-use/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [OpenAI Image Generation](https://everruns.com/docs/capabilities/openai-image-generation/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Data Knowledge](https://everruns.com/docs/capabilities/data-knowledge/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Knowledge](https://everruns.com/docs/capabilities/knowledge/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Memory](https://everruns.com/docs/capabilities/memory/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Dreaming](https://everruns.com/docs/features/dreaming/) | [File System](https://everruns.com/docs/capabilities/file-system/) | | [Container Sandbox](https://everruns.com/docs/capabilities/container-sandbox/) | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | [A2A Agent Delegation](https://everruns.com/docs/capabilities/a2a-agent-delegation/) | Session Tasks | | AG-UI Agent Delegation | Session Tasks | ### Features Capabilities declare UI features they contribute. The session aggregates features from all active capabilities to decide which UI tabs to render. | Feature | UI Element | Contributed By | | -------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `file_system` | Workspace tab | [File System](https://everruns.com/docs/capabilities/file-system/), [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/), [Host Shell](https://everruns.com/docs/capabilities/host-shell/) | | `secrets` | Storage tab | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | `key_value` | Storage tab | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | `schedules` | Schedules tab | [Schedules](https://everruns.com/docs/capabilities/session-schedules/) | | `sql_database` | Database tab | [SQL Database](https://everruns.com/docs/capabilities/sql-database/) | | `subagents` | Subagents tab | [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/) | | `citations` | Inline citation chips + Sources strip | [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/), [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/) | ### Ordering Capabilities are applied in the order configured on the agent. Earlier capabilities’ system prompt additions appear first. Place the most important context-setting capabilities first. ## See Also * [Concepts](https://everruns.com/docs/getting-started/concepts/), how capabilities fit into the Harness → Agent → Session model * [API Reference](https://everruns.com/docs/api/), full API documentation * [MCP Servers](https://everruns.com/docs/features/mcp/), external tool servers as virtual capabilities --- # A2A Agent Delegation > Delegate work to configured external agents over the A2A protocol through spawn_agent, in the foreground or as a background session task. Source: | | | | ---------------- | ---------------------- | | **ID** | `a2a_agent_delegation` | | **Category** | Orchestration | | **Features** | `agent_runs` | | **Dependencies** | `session_tasks` | | **Risk** | High | | **Availability** | Experimental | A2A Agent Delegation lets an agent hand work to agents that run outside Everruns and speak the [A2A protocol](https://everruns.com/docs/features/a2a/). The agents it may call are listed in the capability’s configuration, so the model can only reach URLs you configured. The capability adds the `external_a2a` target type to the shared `spawn_agent` tool, the same dispatcher that [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/) and [Agent Handoff](https://everruns.com/docs/capabilities/agent-handoff/) extend. **Experimental.** On the platform, adding the capability to an agent is the opt-in; there is no separate feature flag. In the [Framework](https://everruns.com/docs/framework/), turn on the `a2a` Cargo feature of `everruns` (it implies `local`) and add the capability by ID. See [A2A](https://everruns.com/docs/features/a2a/#a2a-in-the-framework). ## Configuration ```json { "ref": "a2a_agent_delegation", "config": { "agents": [ { "id": "research", "name": "Research agent", "description": "Researches a topic and returns notes.", "base_url": "https://agents.example.com/research" } ] } } ``` | Field | Required | Description | | ------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Yes | Stable key the model passes as `target.id` | | `name` | Yes | Human-readable name, shown in the system prompt | | `description` | No | What the agent does, shown in the system prompt | | `base_url` | One of `base_url` or `agent_card` | Where the Agent Card is fetched from (`/.well-known/agent-card.json`) | | `agent_card` | One of `base_url` or `agent_card` | An inline Agent Card, used instead of discovery | | `headers` | No | Static headers sent to the A2A endpoint. They are stored in the config, so they must not hold secrets | | `preferred_binding` | No | `JSONRPC` or `HTTP+JSON` | | `poll_interval_ms` | No | How often to poll the remote task, 100 to 60000. Default 1000 | | `allow_local_urls` | No | Allows localhost and private addresses for local development. Honored only when `DEPLOYMENT_GRADE=dev`; rejected otherwise. Default `false` | Without `allow_local_urls` (or outside `DEPLOYMENT_GRADE=dev`), `base_url` and every interface URL in an inline Agent Card must pass the safe-URL check, which refuses localhost, private ranges, and metadata addresses. At request time the same URLs are DNS-pinned and redirects are disabled. A session’s network access policy is also applied to the endpoint before and after the Agent Card is resolved. ## `spawn_agent` | Parameter | Required | Description | | -------------------- | -------- | ------------------------------------------------------------------------------------------------------------- | | `instructions` | Yes | Instructions sent to the external agent | | `target` | Yes | `{ "type": "external_a2a", "id": "" }`. `target.external_agent_id` is a deprecated spelling of `id` | | `mode` | No | `foreground` (default) or `background` | | `wait_timeout_secs` | No | How long to wait for the remote task, 1 to 86400. Default 300 | | `wake_on_completion` | No | Wake the session when a background run finishes. Default `true` | | `result_schema` | No | JSON Schema for a required structured result from the external agent | `message_schema` is not supported: a remote agent cannot call `report_task_progress`, so passing one fails. Text results are truncated to 8192 characters. `foreground` waits for the remote task and returns its reply. `background` returns a `task_id` at once. When task tracking is available, each run is a session task of kind `external_agent`, so `wait_task` collects the result, `message_task` answers a remote task that asks for input, and `cancel_task` stops it. ## See also * [A2A](https://everruns.com/docs/features/a2a/), serving agents over A2A and the delegation overview * [Agent Handoff](https://everruns.com/docs/capabilities/agent-handoff/), delegation to first-party agents * [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/), the session task tools --- # Agent Handoff > Delegate work to configured first-party agents with spawn_agent, as a background task, a blocking call, or an invited participant in the current session. Source: | | | | ---------------- | ---------------- | | **ID** | `agent_handoff` | | **Category** | Orchestration | | **Features** | `agent_handoffs` | | **Dependencies** | None | | **Risk** | High | | **Availability** | Experimental | Agent Handoff lets an agent hand work to other first-party Everruns agents. Each target is configured ahead of time with an agent and a harness, so the model can only pick from that list. The capability adds the `agent` target type to the shared `spawn_agent` tool, the same dispatcher that [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/) and [A2A Agent Delegation](https://everruns.com/docs/capabilities/a2a-agent-delegation/) extend. The child runs as its own session, or joins the current session as a member. **Experimental.** Adding the capability to an agent is the opt-in; there is no separate feature flag. For delegation to agents outside Everruns, see [A2A Agent Delegation](https://everruns.com/docs/capabilities/a2a-agent-delegation/). For ad hoc child sessions that use the parent’s own configuration, see [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/). ## Configuration ```json { "ref": "agent_handoff", "config": { "targets": [ { "id": "billing", "name": "Billing agent", "description": "Answers invoice and refund questions", "agent_id": "agent_...", "harness_id": "harness_...", "required_connections": ["github"] } ] } } ``` | Field | Required | Description | | ---------------------- | -------- | ---------------------------------------------------------------- | | `id` | Yes | Stable key the model passes as `target.id` | | `name` | Yes | Human-readable name, shown in the system prompt | | `description` | No | What the target does, shown in the system prompt | | `agent_id` | Yes | Public ID of the target agent | | `harness_id` | Yes | Public ID of the harness the target runs on | | `required_connections` | No | Provider connections that must exist before the handoff starts | | `required_scopes` | No | Non-secret scope labels recorded for audit and resource metadata | The system prompt lists every configured target by name, ID, and description. ## `spawn_agent` | Parameter | Required | Description | | ---------------- | -------- | --------------------------------------------------------------------------------------------------------- | | `name` | Yes | Name for this delegated run | | `instructions` | Yes | Instructions for the target. Must not contain credentials | | `target` | Yes | `{ "type": "agent", "id": "" }` | | `mode` | No | `background`, `foreground`, or `invite` | | `public_context` | No | Non-secret structured context, appended to the instructions | | `result_schema` | No | JSON Schema for the child’s final result. The child must call `report_result` before the task can succeed | | `message_schema` | No | JSON Schema for structured progress messages. The child gets `report_task_progress` | ### Modes | Mode | Behavior | | ------------ | -------------------------------------------------------------------------------------- | | `background` | Default when session task tracking is available. Returns a `task_id` right away | | `foreground` | Default otherwise. Blocks until the handoff finishes and returns the result | | `invite` | Adds the target agent as a member of the current session instead of starting a new one | A background handoff is tracked as a session task of kind `agent_handoff`, so the parent manages it with the session task tools (`list_tasks`, `get_task`, `message_task`, `cancel_task`, `wait_task`). Background mode fails when task tracking is not available. Invite mode does not create a child task, so it rejects `result_schema` and `message_schema`. It also refuses the invite when the target’s configuration conflicts with the current session’s: the same capability with a different config, the same mounted file path with different contents, or the same MCP server name with a different definition. ### Connections When a target lists `required_connections` and the session cannot resolve a connection for one of those providers, `spawn_agent` returns a `connection_required` result naming the provider. The client collects the credentials through the Connections flow. The system prompt tells the agent never to ask for tokens in chat or pass them in tool arguments. ## See also * [A2A Agent Delegation](https://everruns.com/docs/capabilities/a2a-agent-delegation/), delegation to external agents * [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/), child sessions from the parent’s own configuration, and the session task tools --- # AGENTS.md > Project instructions resolved hierarchically from workspace files such as AGENTS.md and injected as the leading user message on every turn. Source: | | | | ---------------- | -------------------- | | **ID** | `agent_instructions` | | **Category** | Core | | **Features** | None | | **Dependencies** | None | Resolves project instruction files hierarchically, from the session filesystem root down to the working directory, and injects them as the leading user-role message on every turn. By default it reads `AGENTS.md`, Everruns’ implementation of the [`AGENTS.md`](https://agents.md/) open convention. Configure `files` when an agent should also resolve another file such as `CLAUDE.md` at every hierarchy level. Workspace files are untrusted third-party content, so they never enter the system prompt: harness safety instructions always take precedence, and file edits never invalidate the cache-stable system prefix. ## Tools None. This capability only contributes conversation context, never system prompt. ## How it works 1. The agent receives a message. 2. Before the model call, the capability resolves the configured filenames from the filesystem root down to the working directory. A `docs/AGENTS.md` applies to work under `docs/`; deeper files override shallower ones on conflict. Files in sibling subtrees are never loaded. 3. The assembled block opens with a trust framing header and wraps each file in `` tags, broadest scope first. 4. The block is injected as the leading user-role message: visible to the model, re-resolved every turn, and below system instructions in precedence. Edits during a session apply on the next turn, with no restart. If a configured file doesn’t exist, the agent operates normally. ## Prompt order Every turn the model sees, top to bottom: 1. **System prompt**: harness safety instructions, tool guidance, role (cache-stable). 2. **Conversation context**: the resolved `AGENTS.md` hierarchy, broadest scope first. 3. **Conversation history and the latest user message**. Explicit user instructions win over project files on conflict; system instructions always win over both. ## Config ```json { "files": ["AGENTS.md", "CLAUDE.md"] } ``` `files` is optional. When omitted, Everruns resolves `AGENTS.md` at every level from the root to the working directory. A config may list at most 16 files. ## Limits * **32 KiB per file**. Longer content is truncated with a warning. * **128 KiB total per turn**, which bounds hierarchy depth. Deeper files past the budget are omitted with an explicit note. * At most 16 instruction files resolved per turn. * Plain Markdown, no required sections. ## Notes * Works with [File System](https://everruns.com/docs/capabilities/file-system/) tools, so an agent can update its own instructions. * Missing configured files are ignored, with no error. ## Do something * [Use AGENTS.md for project instructions](https://everruns.com/docs/how-to/use-agents-md/): full guide with examples. * [Equip an agent with tools](https://everruns.com/docs/how-to/equip-agents-with-tools/): adding capabilities generally. ## See also * [File System](https://everruns.com/docs/capabilities/file-system/): manage the AGENTS.md file. * [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/): another way to inject specialized instructions. * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Agent Skills > Discover and activate portable skill packages from the session workspace at runtime. Source: | | | | ---------------- | ---------------------------------------------------------------------------- | | **ID** | `skills` | | **Category** | Core | | **Features** | None | | **Dependencies** | [`session_file_system`](https://everruns.com/docs/capabilities/file-system/) | Discover and activate skills from `/.agents/skills/` in the session filesystem. Skills are portable instruction packages following the [Agent Skills](https://agentskills.io/) open specification. ## Tools ### `list_skills` Scan `/.agents/skills/` for available skills. Returns names and descriptions only (\~100 tokens per skill). ### `activate_skill` Load a skill’s full instructions by name. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------------- | | `name` | string | yes | Skill name (directory name under `/.agents/skills/`) | Returns: full SKILL.md content and list of bundled files. ## How It Works Skills use progressive disclosure to keep context efficient: 1. **Discovery** (\~100 tokens), `list_skills` returns only names and descriptions 2. **Activation** (<5000 tokens), `activate_skill` loads the full SKILL.md instructions 3. **Resources** (on-demand), bundled files accessible via [File System](https://everruns.com/docs/capabilities/file-system/) tools ## Workspace layout ```plaintext /.agents/skills/ deploy/ SKILL.md templates/ k8s-deploy.yaml code-review/ SKILL.md ``` ## Notes * Skills are per-session (uploaded to session filesystem) * Path traversal protection on skill names * Invalid SKILL.md files are reported but don’t block discovery of other skills * For organization-wide skills, see the [Skills Registry](https://everruns.com/docs/features/skills/#skills-registry) ## See Also * [Agent Skills feature guide](https://everruns.com/docs/features/skills/), detailed skills documentation * [Skills Registry](https://everruns.com/docs/features/skills/#skills-registry), API-managed skills * [AGENTS.md](https://everruns.com/docs/capabilities/agent-instructions/), simpler alternative for project context * [File System](https://everruns.com/docs/capabilities/file-system/), upload skill files * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Ask User > Let an agent ask the user a small batch of structured questions, and wait for the answer, instead of guessing or ending the turn in prose. Source: | | | | ---------------- | ---------- | | **ID** | `ask_user` | | **Category** | Core | | **Features** | None | | **Dependencies** | None | Gives the agent one tool for collecting decisions it cannot make on its own. Instead of guessing, or ending the turn with a paragraph of questions and hoping the user answers all of them, it asks 1–4 structured questions and waits. The user sees a card with the questions. Choice questions show described options, and text questions show a free-form field. Answering resumes the turn. Opt-in on the canonical levels. Included in deprecated [Generic](https://everruns.com/docs/built-ins/harnesses/generic/) and [Platform Chat](https://everruns.com/docs/built-ins/harnesses/platform-chat/) harnesses. Not on [Base](https://everruns.com/docs/built-ins/harnesses/base/), which has no interactive surface. ## When to enable it Enable it for agents that work *with* a person: anything where the agent’s first guess about intent, scope, or preference is likely to be wrong and expensive to undo. Leave it off for agents that run unattended on a schedule or a trigger. It will not hang them — a client that cannot render a choice gets the model’s declared defaults immediately, while text and secret questions are declined — but an agent nobody is watching should be built to decide, not to ask. ## Not a consent gate This is the boundary worth being clear about before enabling both: | | `ask_user` | `request_approval` | | --------- | ---------------------------------------- | --------------------------- | | For | Decisions and preferences | Permission to act | | Example | “Which environment?” | “May I delete this bucket?” | | No answer | Choice defaults; text and secret decline | Stays unresolved | Choice questions **auto-resolve**. A choice nobody answers falls back to the option the model marked as recommended. Text and secret questions are skipped instead because they have no default value. None of these outcomes grants permission, so a destructive, irreversible, or outward-facing action must go through `request_approval` (the `soft_approval` capability), whose wait does not auto-resolve. Both are enabled together on the interactive harnesses for exactly this reason: the agent needs somewhere to put a preference so it stops putting permission questions there. The system prompt states the rule, but the capability pairing is what makes it followable. ## Question kinds **Choice** — 2 to 6 options, single- or multi-select, optionally with a free-text “Something else” path. Options are ordered most-applicable-first, because that is the order a fallback follows. **Text** — one free-form answer with no options. Use it for open questions such as a branch name. An unanswered text question is declined rather than submitted as an empty answer. **Secret** — collects a credential. The value is stored encrypted in [session storage](https://everruns.com/docs/capabilities/session-storage/) and the agent receives a reference (`session:MY_TOKEN`), never the value itself, so it cannot reach the conversation history or the agent’s context. Tools resolve the reference by name. A secret question never auto-resolves: there is no such thing as a default credential, so an unanswered one is declined and proceeding without it becomes the agent’s explicit decision. Use the secret kind rather than asking for a key in chat. A key typed into an ordinary message stays in the session history in plain text. ## Tools | Tool | Description | | ---------- | ------------------------------------------------------------------------------------------ | | `ask_user` | Ask 1–4 choice or free-form questions, or collect one credential, and wait for the answer. | ## Configuration None. Limits are fixed by the contract: | Limit | Value | | --------------------------- | ------------------------------------------------------- | | Questions per call | 1–4 (a secret question must be alone) | | Options per choice question | 2–6 | | Timeout | 300 seconds, which the agent may shorten but not extend | ## What the agent is told The result says what was chosen **and who chose it** — a person, a timeout, or an unattended fallback. An agent that reads a fallback as a considered answer will act with more confidence than the answer deserves, so provenance travels with it. A declined question is a finished decision. The agent must not ask it again. ## See Also * [Session Storage](https://everruns.com/docs/capabilities/session-storage/), where a collected secret is kept * [Implementing a responder](https://everruns.com/docs/framework/ask-user/), for embedding applications * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Automatic session titles > Automatically name conversations and update titles when the primary topic changes, independently of the agent's tools. Source: | | | | ---------------- | -------------------------- | | **ID** | `automatic_session_titles` | | **Category** | Session | | **Tools** | None | | **Dependencies** | None | Enable **Automatic session titles** on a harness, agent, or session. The platform checks the conversation after a completed turn without waiting on the title model before delivering the agent’s answer. The `session` capability and its `write_session_title` tool are optional. ## Model selection By default, titles use the organization’s **Small model**, configured under **Models → Defaults**. If that setting is empty, titles inherit the session’s model, including its agent, harness, and organization defaults. In capability settings, choose **Use session model** to always inherit the session model, or select a specific model and provider. An unavailable selected model skips generation; it never switches accounts or uses deployment utility credentials. Title requests count toward session usage and budgets. ```json { "ref": "automatic_session_titles", "config": { "model_id": "session", "retitle": true } } ``` Omit `model_id` to use the organization Small model default. Set `retitle` to `false` to generate only the initial title. ## When titles change The first check follows the first completed turn with a user message. Greetings or insufficient context can leave the session untitled. Later checks require at least five minutes and new user messages: 4 after a changed title, then 8, 16, and 32 between checks if the current title stays useful. The interval stays at 32 until a title changes. Failed attempts also back off. Autonomous turn continuations do not count as new user messages. One bounded model request decides whether to keep the title or replace it. There is no separate intent-classification request on every turn. The title model sees a limited recent text transcript and no tool results or attachments. Generation is best effort: an outage leaves the existing title in place. ## Explicit titles take priority A title supplied at creation, renamed through the API or UI, or written with `write_session_title` becomes explicit and is never overwritten automatically. Writing the same text explicitly also takes ownership. An explicit rename wins even when a title request is already running. The existing [Session capability](https://everruns.com/docs/capabilities/session/) remains available for agent-directed naming. Leave its `auto_title` flag off when using this capability; enabling that flag asks the main agent to name the session explicitly, which takes priority over automatic maintenance. Title text changes emit the usual `session.title.updated` event. --- # Bashkit Shell > Run Bash commands in a sandboxed interpreter with process isolation, resource limits, streaming output, and workspace-only filesystem access. Source: | | | | ---------------- | ---------------------------------------------------------------------------- | | **ID** | `bashkit_shell` (legacy alias: `virtual_bash`) | | **Category** | Execution | | **Risk** | High, assignment requires an org **Admin** | | **Features** | `file_system` (enables the Workspace tab) | | **Dependencies** | [`session_file_system`](https://everruns.com/docs/capabilities/file-system/) | Execute bash commands in a sandboxed environment with no access to the host system. The session filesystem is mounted at `/workspace`, so commands read and write the same files as the [File System](https://everruns.com/docs/capabilities/file-system/) tools. ## About Bashkit This capability runs on [**Bashkit**](https://bashkit.sh), a virtual Bash interpreter written in Rust. It executes shell scripts in-process, with no real shell, no subprocess spawning, and no host access, which makes it suitable for running untrusted scripts in multi-tenant agent environments. Browse the source on [GitHub](https://github.com/everruns/bashkit). Bashkit provides: * **The shell language**: variables, parameter expansion, command substitution, arithmetic, pipelines, redirections, control flow, functions, arrays, globs, and here-documents. * **Built-in commands** implemented in Rust: file I/O and navigation (`cat`, `ls`, `find`, `cp`, `mv`), text processing (`grep`, `sed`, `awk`, `jq`, `sort`), archives (`tar`, `gzip`), and network commands (`curl`, `wget`). * **A pluggable virtual filesystem**: Everruns plugs in the session file store, so there is no copy step before or after a command. * **Resource limits** on command count, loop iterations, and function depth, so a runaway script cannot exhaust shared infrastructure. Because the interpreter is sandboxed by construction, bash here is **not** a shell-out to the host: there is no `/bin/bash` process, no direct network stack, and no filesystem beyond the session workspace. Outbound HTTP for `curl`/`wget` is off by default and can be enabled per agent (see **Outbound HTTP** below). ## Tools ### `bash` Execute a shell command (or a multi-line script). | Parameter | Type | Required | Description | | ------------- | ------- | -------- | -------------------------------------------------------- | | `commands` | string | yes | Shell command(s) to execute | | `working_dir` | string | no | Working directory (default: `/workspace`) | | `timeout_ms` | integer | no | Timeout in milliseconds (default: `30000`, max: `60000`) | | `output` | string | no | Output verbosity (`auto`, `normal`, …; default: `auto`) | Returns `stdout`, `stderr`, `exit_code`, and a `success` flag. Output streams live to the UI and CLI via `tool.output.delta` events while the command runs. On timeout, any partial output captured so far is returned alongside the error. This tool also supports background execution, long scripts can run detached and report progress without blocking the agent loop. ## Filesystem The interpreter exposes a single mount: * **`/workspace`** maps to the session file store. Reads and writes are live, files created by bash are immediately visible to the File System tools and vice versa. * Paths outside `/workspace` (for example `/etc`, `/home/agent`, `/tmp`) do not exist and cannot be written. * Symlinks are unsupported; `chmod` is a no-op (the session filesystem does not track Unix permissions, and files are executable by default). Default environment: `HOME=/home/agent`, `SHELL=/bin/bash`, `PATH=/usr/local/bin:/usr/bin:/bin`, `WORKSPACE=/workspace`, user and host `everruns`. ## Resource limits Every invocation runs under fixed limits to prevent runaway scripts: | Limit | Value | | -------------------- | ------------------------------------- | | Max commands per run | 1,000 | | Max loop iterations | 10,000 | | Max function depth | 100 | | Max script size | 1 MB | | Max memory | 10 MB | | Parser timeout | 5 s | | Wall-clock timeout | `timeout_ms` (default 30 s, max 60 s) | ## Outbound HTTP (optional) Set the capability config `{"enable_http": true}` to let scripts use `curl` and `wget`. Every request, including each redirect hop, is routed through the platform egress boundary, where the agent/session network access list and the deployment-wide system allowlist are enforced. Policy denials surface as curl’s native `access denied` failure (exit code 7). Without the flag, the interpreter has no network path at all. ### API keys the agent never sees A **bound secret** is an API key stored with the URL it may be sent to and how (`Authorization: Bearer`, or a named header). With outbound HTTP on, the shell sees `$NAME` as a placeholder, and the platform swaps in the real key only in that header and only for requests to the bound URL: ```bash curl -sS https://api.example.com/v1/items -H "Authorization: Bearer $EXAMPLE_API_KEY" ``` The model can never read the value: printing `$NAME` shows the placeholder, a request to any other host (including a redirect target) carries the placeholder, and the key is redacted if a response echoes it back. The bound URL still has to pass the agent’s network access list. Set one for every session of an agent on the agent’s **Credentials** tab: **Add binding**, choose **HTTP API**, and give the shell variable, the URL and how it is sent. Platform Chat or the CLI can declare it without a value, and you paste the value on that tab: ```bash everruns agents credentials create --agent-id agent_01h9 \ --env-name EXAMPLE_API_KEY --url https://api.example.com --label 'Example API key' ``` Set one for a single session with `bindings` on `PUT /v1/sessions/{session_id}/storage/secrets`. Over MCP, `session_set_secret` takes `url`, `auth`, `header` and `scope` and collects the value on a secure page, so it never passes through the MCP client. ## Security * **Sandboxed**: no direct network access (outbound HTTP is opt-in and egress-routed), no host filesystem, no subprocess spawning. * **High risk**: because it exposes arbitrary scripted code execution, assigning `bashkit_shell` to an agent requires an org **Admin**. Existing agents that already had it keep working; the gate applies to new assignments only. * Built-in observability hooks emit structured `tracing` events per builtin and on interpreter errors (tagged with the session ID) without logging argument values or command output. ## Notes * Commands operate on the same `/workspace` as [File System](https://everruns.com/docs/capabilities/file-system/) tools. * Built-in commands support ` --help`, and many also support ` --version`. * Common builtins: `cd`, `ls`, `cat`, `echo`, `grep`, `head`, `tail`, `sed`, `find`, plus shell features like pipes, redirections, and command substitution. `grep` is backed by the session’s indexed search. ## See Also * [Bashkit project](https://bashkit.sh), the interpreter powering this capability * [File System](https://everruns.com/docs/capabilities/file-system/), file operations on the same workspace * [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/), background and parallel execution * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Browser Use > Let an agent work in a browser through the page structure, with element refs, form filling, and tabs, on any model. Source: | | | | ---------------- | ---------------------------------------------------------- | | **ID** | `browser_use` | | **Category** | Browser | | **Features** | Leased resources | | **Dependencies** | `session_storage` | | **Risk** | High (the model reads and acts on whatever the page shows) | | **Availability** | Experimental | Browser use lets an agent work in a web browser through what the page is made of, not only what it looks like. The agent reads the page as an accessibility tree, where every element it can act on carries a ref such as `ref_3`. It then clicks, hovers, scrolls to, or fills that element by ref. It can still take screenshots and act on viewport coordinates when the structure is not enough, and it can open, switch, and close tabs. The `browser` tool is a regular function tool, so it works with any model. Screenshots and `zoom` need a model that accepts images; the other actions return text. It follows the action vocabulary of Claude’s `browser_toolset_20260801`. On Claude models that take that toolset, the agent uses Claude’s own browser tool instead, which those models are trained on, and reads the open tabs from the toolset’s browser state. The actions, the safety rules, and the limits are the same either way. The browser is the session’s persistent [Browserless](https://everruns.com/docs/capabilities/browserless/) browser. Connect Browserless from **Settings → Connections** first. The agent shares that browser with the Browserless tools and with [Computer Use](https://everruns.com/docs/capabilities/computer-use/), so a page one opens is a page the others see. ## Tools ### `browser` Performs one action. Every successful result carries a `browser_state` object: every open tab with its `tab_id`, title and URL, which tab is active, and in `state_changes` the tabs opened since the previous result. A target is either `{"type": "ref", "ref": "ref_3"}` or `{"type": "coordinate", "x": 412, "y": 230}`, in pixels of the viewport. | `action` | Parameters | What it does | | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `read_page` | optional `filter` (`interactive` or `all`), `depth`, `ref` | Read the page as an accessibility tree with refs. By default it lists what is in the viewport; `interactive` lists only the controls; `all` includes the rest of the page; `ref` reads one element’s subtree | | `find` | `query` | Up to 20 elements that best match a description such as `search box` or `sign up button` | | `get_page_text` | none | The page’s text, main content first | | `form_input` | `target` (a ref), `value` (text, a choice, or `true`/`false` for a checkbox) | Set a field’s value and fire its `input` and `change` events | | `left_click`, `right_click`, `middle_click`, `double_click`, `triple_click` | `target`, optional `modifiers` such as `shift` | Click the element’s center or the point | | `hover`, `mouse_move` | `target` (`mouse_move` takes a coordinate) | Move the pointer | | `left_click_drag` | `from`, `target` | Press, drag, and release | | `left_mouse_down`, `left_mouse_up` | `target` | Press or release the left button there | | `scroll` | `target`, `scroll_direction`, optional `scroll_amount` (1 to 10, default 3) | Scroll at that point | | `scroll_to` | `target` (a ref) | Scroll the element into view | | `type` | `text` | Type at the keyboard focus | | `key` | `text` (space-separated keys or combos, such as `Tab Tab Enter` or `ctrl+a`), optional `repeat` | Press keys | | `hold_key` | `text`, `duration` (seconds, up to 30) | Hold keys down, then release them | | `wait` | `duration` (seconds, up to 30) | Pause | | `screenshot` | none | Capture the viewport | | `zoom` | `region` (`[x0, y0, x1, y1]`) | That part of the viewport, enlarged to the viewport size | | `navigate` | `url`, or `back`, `forward`, `reload` | Load a page or step through history | | `new_tab`, `list_tabs` | none | Open a blank tab and make it current, or list the tabs | | `switch_tab`, `close_tab` | `tab_id` | Make a tab current, or close it | Any action also takes an optional `tab_id` to act on that tab; it becomes the current tab. Example calls: ```json { "action": "find", "query": "email field" } { "action": "form_input", "target": { "type": "ref", "ref": "ref_4" }, "value": "ada@example.com" } { "action": "left_click", "target": { "type": "ref", "ref": "ref_7" } } ``` Refs belong to the page they were read from. After a navigation, or when the page removes the element, using one returns an error that tells the agent to read the page again; a ref is never applied to a different element. `javascript_exec`, `file_upload`, `read_console`, and `read_network` are not offered. A call that asks for one is refused. ## Configuration | Field | Default | Description | | ------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | | `viewport_width` | `1280` | Viewport width in pixels (320 to 1920) | | `viewport_height` | `800` | Viewport height in pixels (320 to 1200) | | `max_actions_per_session` | `500` | Hard cap on actions in one session | | `native_tools` | `true` | Use Claude’s native browser toolset on models that have one. When off, every model uses the `browser` function tool. | When Claude sends several browser actions in one turn and one fails, the later ones are not run; each answers that an earlier action failed. ## Safety * **The model reads everything on the page.** Text, tab titles, and URLs can try to steer the agent. The capability tells the model to treat them as untrusted data and to stop and ask before typing credentials, making purchases, sending messages, or confirming irreversible actions. Add [`tool_approval`](https://everruns.com/docs/capabilities/tool-approval/) when a person must approve every `browser` call before it runs. * **Refs stay out of the page.** Everruns keeps the table that maps refs to elements; the page cannot read or move it, so a ref read as “Cancel” cannot be pointed at “Buy”. * **Page scripts cannot tamper with reads and fills.** `get_page_text` and `form_input` run in a separate script world, so a page that overrides built-in functions does not change what they read or write. * **Keep credentials out of reach.** Do not give a browser-use agent a browser that is signed in to accounts it should not use. * **Egress.** `navigate` takes only http and https addresses; an address without a scheme is read as https. It refuses private and internal addresses and follows the session’s network access list. Everruns makes every request the page makes, in every tab, and applies the same rules to each one. If a page navigates somewhere blocked on its own, it is reset to a blank page and the action reports an error. * **Budget.** `max_actions_per_session` stops runaway loops. ## Availability Browser use is experimental and ships behind the `browserless_browser_use` feature flag (`FEATURE_BROWSERLESS_BROWSER_USE` sets its rollout grade). --- # Browserless > Headless browser automation through Browserless for screenshots, DOM reading, scraping, page interaction, and persistent sessions for login-protected pages. Source: | | | | ---------------- | ---------------------------------------------------------------------------- | | **ID** | `browserless` | | **Category** | Browser | | **Features** | None | | **Dependencies** | [`session_storage`](https://everruns.com/docs/capabilities/session-storage/) | Cloud browser automation powered by [Browserless](https://www.browserless.io/). Agents can navigate pages, take screenshots, read rendered DOM content, scrape structured data, and interact with pages using click, type, keyboard, mouse, and touch events. ## Set up 1. In the [Browserless Dashboard](https://www.browserless.io/account/home), open **API Keys** in your account settings and copy your API token. 2. In Everruns, open **Settings** > **Connections**, find **Browserless**, select **Connect**, and paste the token. Once connected, agents with the Browserless capability can use the tools below. ## Two operating modes **Stateless (default).** Each tool call opens a fresh browser that is destroyed after the response. Nothing persists between calls, and no cleanup is needed. Use it for one-shot screenshots or scraping. **Persistent session (CDP).** `browserless_open_browser` creates a browser over the Chrome DevTools Protocol that stays alive between tool calls, keeping login state, cookies, and navigation history. Tools use the persistent browser automatically when one is active. A persistent browser expires after 60 seconds of inactivity by default; call `browserless_close_browser` when done for immediate cleanup. Both modes connect over the Chrome DevTools Protocol, so the Browserless token needs WebSocket (CDP) access. A Browserless cloud token without it falls back to the Browserless REST API for the stateless tools; see [Security](#security). A typical flow for a login-protected page: 1. `browserless_open_browser` with the login page URL. 2. `browserless_interact` to fill credentials and submit the form. 3. `browserless_navigate` to browse authenticated pages. 4. `browserless_screenshot` to capture the authenticated page state. 5. `browserless_close_browser` to release resources. ## Tools ### `browserless_open_browser` Open a persistent browser session via CDP. | Parameter | Type | Required | Description | | ------------ | ------- | -------- | --------------------------------------------------------------- | | `url` | string | no | Initial URL to navigate to | | `timeout_ms` | integer | no | How long the browser stays alive between calls (default: 60000) | ### `browserless_close_browser` Close the persistent browser session and release resources. Takes no parameters. ### `browserless_navigate` Navigate to a URL and return page metadata (title, links, headings, meta tags). | Parameter | Type | Required | Description | | ------------------- | ------- | -------- | ------------------------------------------- | | `url` | string | yes | The URL to navigate to | | `wait_for_selector` | string | no | Wait for this CSS selector to appear | | `wait_for_timeout` | integer | no | Wait this many milliseconds after page load | ### `browserless_screenshot` Take a PNG screenshot of a page. Returns base64-encoded image data. | Parameter | Type | Required | Description | | ------------------- | ------- | -------- | ---------------------------------------------------- | | `url` | string | yes | The URL to screenshot | | `full_page` | boolean | no | Capture the full scrollable page (default: true) | | `selector` | string | no | CSS selector to screenshot a specific element | | `wait_for_selector` | string | no | Wait for this CSS selector before taking screenshot | | `wait_for_timeout` | integer | no | Wait this many milliseconds before taking screenshot | ### `browserless_content` Get the fully rendered HTML content (DOM) of a page, including JavaScript-rendered content. | Parameter | Type | Required | Description | | ------------------- | ------- | -------- | --------------------------------------------------------------- | | `url` | string | yes | The URL to read | | `wait_for_selector` | string | no | Wait for this CSS selector before reading content | | `wait_for_timeout` | integer | no | Wait this many milliseconds before reading content | | `best_attempt` | boolean | no | Continue even if async events fail or time out (default: false) | ### `browserless_scrape` Extract structured data from a page using CSS selectors. Returns JSON with matched elements. | Parameter | Type | Required | Description | | ------------------- | ------- | -------- | ------------------------------------------- | | `url` | string | yes | The URL to scrape | | `elements` | array | yes | Array of `{selector}` objects to extract | | `wait_for_selector` | string | no | Wait for this CSS selector before scraping | | `wait_for_timeout` | integer | no | Wait this many milliseconds before scraping | ### `browserless_interact` Navigate to a URL, then perform a sequence of actions. | Parameter | Type | Required | Description | | ------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `url` | string | yes | The initial URL to navigate to | | `steps` | array | yes | Ordered list of interaction steps | | `return_screenshot` | boolean | no | Return a base64 screenshot after all steps (default: false) | | `return_content` | boolean | no | Return DOM content after all steps (default: false). With both flags true, both are returned; with neither, DOM content is returned | **Supported step actions:** | Action | Key Parameters | Description | | ------------------- | --------------------- | -------------------------------------- | | `click` | `selector` or `x`,`y` | Click element or coordinates | | `type` | `selector`, `value` | Type text into input field | | `keyboard` | `key` | Press a key (Enter, Tab, Escape, etc.) | | `mouse_move` | `x`, `y` | Move mouse to coordinates | | `touch` | `selector` | Tap element (mobile touch simulation) | | `scroll` | `value` | Scroll page by pixel amount | | `wait` | `wait_ms` | Wait for milliseconds | | `wait_for_selector` | `selector`, `wait_ms` | Wait for element to appear | | `navigate` | `value` | Navigate to a different URL | ## Uses * **Accessibility testing**: navigate pages, read the DOM, check ARIA attributes and heading structure. * **Regression testing and visual QA**: take before and after screenshots and verify content after changes. * **Login flows**: authenticate in a persistent session and test protected pages. * **Web scraping**: extract structured data from a website. ## Security * API tokens are encrypted at rest (AES-256-GCM envelope encryption). * Browser sessions are isolated on Browserless servers. * The browser has no network access of its own. Everruns makes every request the page makes, including each redirect hop, scripts, and images. Private, loopback, link-local, and cloud metadata addresses are refused, both as URLs and as DNS answers, and the session’s network access list applies to every request. A blocked page load returns an error, never the page. * WebSockets and other connections a page opens outside HTTP requests are refused. * A relayed response is limited to 10 MB. * The REST fallback for Browserless cloud tokens without CDP access runs in Browserless’ network and checks only the URL you pass. A self-hosted Browserless never falls back. * CDP session state stores only the WebSocket endpoint (no secrets), scoped per session. * Large DOM responses are truncated to 100KB to prevent context flooding. ## See also * [Browserless documentation](https://docs.browserless.io/) * [Integrations](https://everruns.com/docs/integrations/): every vendor integration. * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Budgeting > Expose active budgets to the agent so it can check the remaining balance and adjust its own spending. Source: | | | | ---------------- | -------------- | | **ID** | `budgeting` | | **Category** | Cost Control | | **Features** | `budgeting` | | **Included in** | Worker harness | | **Dependencies** | None | Makes an agent aware of its budget constraints. The agent receives budget information in its system prompt and can proactively check remaining balance before expensive operations. ## Tools ### `check_budget` Query the budget status for the current session. > **Note:** The current implementation returns a placeholder response indicating whether budgets are configured. Full budget data (balance, limit, status per budget) requires worker-side tool interception, which is planned for a future iteration. In the meantime, use the REST API (`GET /v1/sessions/{id}/budget-check`) for detailed budget status. | Parameter | Type | Required | Description | | --------- | ---- | -------- | ---------------------- | | *(none)* | | | No parameters required | ## Behavior When the `budgeting` capability is enabled: 1. **System prompt injection**: The agent’s system prompt includes a “Budget Awareness” section with the current budget status and guidelines for efficient output. 2. **Self-regulation**: When budget is running low, the agent prioritizes completing current tasks efficiently rather than exploring new directions or generating verbose output. 3. **Proactive checking**: The agent can call `check_budget` before starting expensive operations (large code generation, multi-step tool chains) to decide whether to proceed or ask the user. ## Related * [Budgets](https://everruns.com/docs/advanced/budgets/), full budgeting system documentation (limits, currencies, API, CLI) --- # Retrieval Citations > Attach claim-level citations to an agent's answer from its knowledge retrieval results, so each grounded sentence links back to the source that supports it. Source: | | | | ---------------- | -------------------- | | **ID** | `citation_retrieval` | | **Category** | Knowledge | | **Features** | `citations` | | **Dependencies** | None | Turn the sources an agent retrieves into **claim-level provenance** on its answer. When the agent grounds a reply in a knowledge search, `citation_retrieval` links each grounded sentence to the passage that backs it, and the UI renders those links as inline numbered chips with a hover preview and a deduped **Sources** strip. It contributes **no tools** and **no system prompt**, and it never rewrites the model’s answer. After the agent responds, it inspects the turn’s retrieval results, aligns each retrieved passage to the sentence it best supports, and attaches a citation there. Alignment is deterministic token overlap, no extra model call, so it is model- and provider-agnostic. ## How it looks Grounded sentences get an inline numbered chip. Hovering a chip previews the source (title, snippet, and link); a deduped **Sources** strip sits below the message. When [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/) is also enabled, each source carries a faithfulness badge. ![An assistant message with inline numbered citation chips on grounded sentences, a hover popover previewing the cited source's title, snippet, and URL, and a "Sources" strip below the message listing three deduped sources with verified / unsupported / unverified badges.](https://everruns.com/docs/_astro/citations-ui.BjQwCryu_Z1csLTC.webp) ## Feed Reads the results of the agent’s knowledge retrieval tools: | Tool | Source shape | | ------------------ | ---------------------------------------------------------------------------------------- | | `search_index` | Knowledge-index chunks (`kchk_…`), `source_uri`, `document_title`, `snippet`, `location` | | `search_knowledge` | Knowledge-base entries (`kbe_…`), `resource`, `title`, `snippet` | Both shapes are normalized into the shared citation envelope. A retrieval result with no usable snippet is skipped, there is nothing to align a claim to. > **This capability is a no-op on its own.** It cites what the agent retrieves, so it only produces citations when the agent also has a retrieval capability (a knowledge index or knowledge base) that surfaces `search_index` / `search_knowledge` results. With no retrieval feed, there is nothing to cite and the answer is unchanged. ## Configuration | Field | Type | Default | Description | | ------------- | ------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `min_overlap` | number (0–1) | `0.5` | Minimum token-overlap ratio for a retrieved passage to attach to a sentence. Overlap is `shared tokens / passage tokens`, so `0.5` means at least half the passage’s distinctive words appear in the sentence. | Raise `min_overlap` for stricter, higher-precision attachment (fewer chips, each more defensible); lower it for broader coverage when the model paraphrases retrieved text. ## Notes * **No answer rewrite**: the streamed answer is never changed; annotations attach to sentence spans after generation. * **Alignment is lexical**: a sentence that paraphrases a source heavily enough to fall below `min_overlap` will not be cited. This favors precision over recall. * **Opt-in**: add `citation_retrieval` to a canonical harness to emit citations from a retrieval feed. Deprecated Generic includes it. * **Persistence**: annotations ride the message in the event log, so they survive reload, forking, and session export, no separate store. * **Org scoping**: sources are derived only from already-authorized retrieval results, so a citation can never reference a document the requesting org cannot read. ## See Also * [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/), stamp a faithfulness verdict on each citation * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Citation Verification > Verify that each cited source actually supports the claim it is attached to, stamping a faithfulness verdict on every citation produced by any feed. Source: | | | | ---------------- | ----------------------- | | **ID** | `citation_verification` | | **Category** | Knowledge | | **Features** | `citations` | | **Guardrail** | Yes | | **Dependencies** | None | Check that each citation is **faithful**: that the source it points to actually supports the sentence it is attached to, and stamp a verdict on it. It is a guardrail capability, decoupled from the feeds: it consumes the citations collected during a turn (from [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/) or any future feed) and verifies them uniformly, so any feed can be paired with any verifier. It contributes **no tools** and **no system prompt**. The verdict renders in the UI as a badge on each source. ## Verdicts Each citation gets one of three verdicts, shown as a badge on the chip preview and in the **Sources** strip: | Verdict | Meaning | | ------------- | ---------------------------------------------------------------------------------- | | `entailed` | The source supports the claim. Rendered as a green **verified** badge. | | `unsupported` | The source does not support the claim. Rendered as an amber **unsupported** badge. | | `uncertain` | Support could not be established. Rendered as an **unverified** badge. | ![An assistant message whose Sources strip shows three cited sources with verdict badges: source 1 "verified" (green), source 2 "unsupported" (amber), and source 3 "unverified", produced by citation_verification over the retrieval feed's citations.](https://everruns.com/docs/_astro/citations-ui.BjQwCryu_Z1csLTC.webp) ## Modes | Mode | Cost | Behavior | | --------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `heuristic` (default) | Free | Deterministic lexical entailment, token overlap between the claim span and the source snippet. No model call. A weak but honest baseline, strongest on verbatim citations. | | `llm` | One utility-model call per citation | A utility-model judgement per claim/source pair (claim = hypothesis, snippet = premise). More accurate; falls back to the heuristic when no utility model is configured. | ## Configuration | Field | Type | Default | Description | | ----------- | ------------------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `mode` | `"heuristic"` \| `"llm"` | `"heuristic"` | Verification strategy (see above). | | `threshold` | number (0–1) | `0.5` | Entailment threshold for the heuristic verdict, the fraction of the claim’s distinctive tokens the source must cover to be `entailed`. | ## Notes * **Feed-agnostic**: verifies citations from any feed via the shared render contract, so evals can hold the feed fixed and vary only the verifier. * **Opt-in**: add `citation_verification` in `heuristic` mode to a canonical harness to verify citations with no model cost. Deprecated Generic includes it. * **`llm` mode needs a utility model**: with none configured it degrades gracefully to the heuristic rather than failing. * **No new data egress**: the verifier reasons only over text the feed already retrieved. ## See Also * [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/), the feed that produces the citations this verifies * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Web Citations > Attach claim-level citations to an agent's answer from its web search results, whether the web_search tool or the model's own search found them. Source: | | | | ---------------- | -------------- | | **ID** | `citation_web` | | **Category** | Knowledge | | **Features** | `citations` | | **Dependencies** | None | Turn the pages an agent found with [Web Search](https://everruns.com/docs/capabilities/web-search/) into **claim-level provenance** on its answer. Each sentence the model backed with a search result links to that page, and the chat renders the links as the same inline numbered chips, hover preview, and **Sources** strip that [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/) use. It contributes **no tools** and **no system prompt**, and it never rewrites the model’s answer. After the agent responds, it reads the turn’s search results and the citations the model provider returned, and attaches a citation to each cited sentence. No extra model call is made. ## Feed | Source | How a citation is found | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `web_search` function results (free search, Brave, Parallel) | The tool asks the model to cite each claim with a result’s `url` or `id` (`w3f9a1c`). A URL in the answer that matches a result, or a result id, cites the sentence it sits in. A citation alone after its sentence, such as `Source: https://…`, cites the sentence before it. | | Native search: Anthropic | Text blocks with `web_search_result_location` citations; the block is the cited claim. | | Native search: OpenAI, OpenRouter | `url_citation` annotations on the answer text. | | Native search: Gemini | Grounding supports and their sources. | | `brave_web_search` results | Matched by URL, like `web_search` results. | Matching is exact, never fuzzy. A URL matches when it names the same page: scheme and host compare without case, and a `#fragment` or trailing slash does not count. The path and query must be equal. A provider’s citation keeps its place only while the text it covered is still there in the final answer; otherwise it is dropped rather than attached to the wrong words. Each citation carries the page `url`, its title, a snippet (the result’s snippet, or the provider’s quoted text), and the result id as `external_id`. Native citations get the same id the `web_search` tool would give the page. > **This capability is a no-op on its own.** It cites what the agent searched, so it only produces citations when the agent also has [Web Search](https://everruns.com/docs/capabilities/web-search/) (or `brave_web_search`). Answers without search results are unchanged. ## Configuration None. ## Notes * **Opt-in**: add `citation_web` next to `web_search`. The built-in harness presets turn on Web Search but not citations. * **Verification**: pair it with [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/) to stamp a faithfulness verdict on each citation, exactly as for retrieval citations. * **No answer rewrite**: the streamed answer is never changed; annotations attach to spans after generation. * **Persistence**: annotations ride the message in the event log, so they survive reload, forking, and session export. * **Untrusted sources**: a citation links to a public web page the search returned; the page content is not checked beyond what the verification capability does. ## See Also * [Web Search](https://everruns.com/docs/capabilities/web-search/) * [Retrieval Citations](https://everruns.com/docs/capabilities/citation-retrieval/) * [Citation Verification](https://everruns.com/docs/capabilities/citation-verification/) * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Computer Use > Let an agent see a browser through screenshots and operate it with clicks, typing, scrolling, and key presses, with any model that accepts images. Source: | | | | ---------------- | ----------------------------------------------------------- | | **ID** | `computer_use` | | **Category** | Browser | | **Features** | Leased resources | | **Dependencies** | `session_storage` | | **Risk** | High (the model sees and acts on whatever the screen shows) | | **Availability** | Experimental | Computer use lets an agent work a screen the way a person does. It takes a screenshot, decides where to click or what to type, and gets a new screenshot after each action. It works on pages that selector-based browser tools cannot handle, such as canvas apps, heavy single-page apps, and custom widgets. The capability is provider-neutral. It is a regular function tool that returns images, so it works with OpenAI, Anthropic, Gemini, and any other model that accepts images in tool results. On models with a native computer tool (OpenAI GPT-5.4 and later through the Responses API, and recent Claude models with `computer_toolset_20260801`), the agent uses the provider’s own tool instead, which those models are trained on. The display, the actions, and the limits are the same either way. The display is a Chromium page on a [Browserless](https://everruns.com/docs/capabilities/browserless/) browser. Connect Browserless from **Settings → Connections** first. The agent shares one persistent browser per session with the Browserless tools, so a page opened by `browserless_open_browser` is the page `computer` sees. ## Tools ### `computer` Performs one action and returns a screenshot of the display afterwards. Coordinates are pixels in the latest screenshot, with the origin at the top left. | `action` | Parameters | What it does | | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | `screenshot` | none | Capture the display | | `left_click`, `right_click`, `middle_click`, `double_click`, `triple_click` | `coordinate` (optional `[x, y]`, defaults to the cursor), `text` (optional modifiers such as `shift` or `ctrl+shift`) | Click | | `left_click_drag` | `start_coordinate`, `coordinate`, `text` (optional modifiers held during the drag) | Press, drag, and release | | `left_mouse_down`, `left_mouse_up` | none | Press or release the left button at the cursor, for drags that need several moves | | `mouse_move` | `coordinate` | Hover without clicking | | `cursor_position` | none | Report where the cursor is, as text | | `scroll` | `scroll_direction` (`up`, `down`, `left`, `right`), `scroll_amount` (wheel clicks, 1 to 50), optional `coordinate` | Scroll | | `type` | `text` | Type text at the keyboard focus | | `key` | `text` (a key or combo such as `Return`, `Tab`, `ctrl+a`), optional `repeat` | Press keys | | `hold_key` | `text` (a key or combo), `duration` (seconds, up to 30) | Hold keys down, then release them | | `wait` | `duration` (seconds, up to 30) | Pause | | `zoom` | `region` (`[x0, y0, x1, y1]`) | Return that part of the screen enlarged to the display size, to read small text | | `navigate` | `url` | Load a page | Example call: ```json { "action": "left_click", "coordinate": [412, 230] } ``` ## Configuration | Field | Default | Description | | ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | | `display_width` | `1280` | Display width in pixels (320 to 1920) | | `display_height` | `800` | Display height in pixels (320 to 1200) | | `screenshot_after_action` | `true` | Return a screenshot after every action. When off, only `screenshot` returns an image. | | `max_actions_per_session` | `300` | Hard cap on actions in one session, screenshots included | | `native_tools` | `true` | Use the provider’s native computer tool on models that have one. When off, every model uses the `computer` function tool. | Screenshots are billed as image tokens. A smaller display, or turning off `screenshot_after_action`, lowers the cost per step. ## Safety * **The model sees everything on the screen.** Text on a page can try to steer the agent. The capability tells the model to treat screen contents as untrusted and to stop and ask before typing credentials, making purchases, sending messages, or confirming irreversible actions. Add the `soft_approval` capability when you want those confirmations recorded, and the [`tool_approval`](https://everruns.com/docs/capabilities/tool-approval/) capability when a person must approve every `computer` call before it runs. * **Soft approval, no built-in hard gate.** No `computer` call waits for a person by default, whether it clicks, types, presses Enter, navigates, or carries a provider safety check. Approval rests on the stop-and-ask rule above, recorded with `soft_approval`. Add `tool_approval` when every call must be approved before it runs. * **Keep credentials out of reach.** Do not give a computer-use agent a browser that is signed in to accounts it should not use. * **Egress.** `navigate` refuses private and internal addresses and follows the session’s network access list. Everruns makes every request the page makes and applies the same rules to each one, including redirects and DNS answers. If a page navigates somewhere blocked on its own, the page is reset to a blank page and the action reports an error. * **Budget.** `max_actions_per_session` stops runaway loops. Each screenshot shows as a thumbnail on the tool call in the session view; click it for the full frame. ## Desktop in a Sandbox To give the agent a full Linux desktop instead of a browser page, turn on **Desktop** in a Daytona or E2B [Sandbox Template](https://everruns.com/docs/features/sandbox-templates/#desktop). The Agent then gets the same `computer` tool, driving the desktop of the Session’s own Sandbox, so the shell, the files and the desktop are one machine, and the template’s outbound network rule covers the desktop too. It takes the same configuration as `computer_use`. * There is no `navigate` action: the agent opens a browser on the desktop and types the address. * A template with a desktop replaces `computer_use`: both provide the `computer` tool. Saving an agent, harness, or session with `computer_use` and `sandbox_desktop` together fails with an error naming the two. * On Daytona, every action goes through the sandbox’s Computer Use API, so typed text and key names reach the desktop as data and never pass through a shell, and `zoom` returns the region at its own size. --- # Container Sandbox > Self-hosted Linux container per session through the Docker Engine API, with shell execution, file I/O, and file transfer to session storage. Source: | | | | ---------------- | ------------------------------------------------------------------ | | **ID** | `container_sandbox` | | **Category** | Execution | | **Features** | `leased_resources` | | **Dependencies** | [Storage](https://everruns.com/docs/capabilities/session-storage/) | | **Risk** | High | Container Sandbox gives an agent a Linux container to run code in. The platform talks to a Docker Engine you operate over its REST API, so no sandbox vendor is involved. Each session gets at most one container, on its own Docker network. **Off by default.** Set `FEATURE_CONTAINER_SANDBOX=prod` on the server and on every worker to register the capability and enable it by default for organisations. Use `dev` for local development or `preview`/`adoption` for explicit enrolment. Each capability has its own grade; the Docker flag does not enable the sandbox. ## Setup 1. Run a Docker Engine the server and workers can reach. 2. Set `CONTAINER_SANDBOX_DOCKER_HOST` to its `http://` or `https://` URL, on the server and every worker. 3. Set `FEATURE_CONTAINER_SANDBOX=prod` in the same places. 4. Add `container_sandbox` to a custom agent or harness. For coding work, inherit [Sandbox Worker](https://everruns.com/docs/built-ins/harnesses/sandbox-worker/) and optionally add [GitHub Scout](https://everruns.com/docs/capabilities/github-scout/). Without `CONTAINER_SANDBOX_DOCKER_HOST` the client defaults to `unix:///var/run/docker.sock`. The client cannot use a Unix socket yet, so every tool call then fails with an error asking for an `http(s)://` host. This is deliberate: it never falls back to an unauthenticated TCP endpoint. Use `https://` with mutual TLS for any Docker daemon that is not on loopback, and never expose a plaintext Docker port on a network. ## Tools | Tool | Parameters | What it does | | -------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `sandbox_create` | `image` (optional) | Creates the session’s network and container and starts it | | `sandbox_exec` | `command`, `working_dir`, `output` | Runs a shell command and returns stdout, stderr, and the exit code | | `sandbox_read_file` | `path`, `offset`, `limit` | Reads a text file as a line window (`limit` defaults to 2000 lines). For a binary file it returns only the size | | `sandbox_write_file` | `path`, `content` | Writes text to a file, replacing it in full | | `sandbox_upload` | `session_path`, `container_path` | Copies a file from session storage into the container, byte for byte | | `sandbox_download` | `container_path`, `session_path` | Copies a file out of the container into session storage, where it outlives the container | | `sandbox_list` | none | Lists the session’s sandbox with its state | | `sandbox_manage` | `action`: `stop`, `start`, or `remove` | `stop` keeps the filesystem, `start` runs it again, `remove` deletes the container, its network, and every file that was not downloaded | The capability’s system prompt describes the lifecycle (`sandbox_create`, then exec and file tools, then `sandbox_manage` with `remove`) and tells the agent to remove the sandbox when it is done. ## Container defaults | Setting | Value | | ----------------- | ------------------------------------------------------ | | Image | `ubuntu:24.04`, unless `sandbox_create` passes `image` | | Working directory | `/workspace` | | Memory limit | 2 GiB | | CPU limit | 1 CPU | | Process limit | 256 | | Runtime | The Docker daemon’s default runtime (normally `runc`) | | Network | A bridge network per session, named after the session | These values are fixed in the platform. The capability takes no configuration, and the image is the only setting a tool call can change. Exec output and file transfers are capped at 8 MiB per response, and a single file transfer at 4 MiB. Each create, exec, and start refreshes a 20-minute lease on the container in the session’s leased resources. ## Security * Each session’s container runs on its own Docker network, and container and network names are derived from the session ID. * Memory, CPU, and process limits are applied through cgroups. * The Docker socket is never mounted into a container. * No egress filtering is applied. A container can reach whatever its bridge network routes to, including private address ranges and cloud metadata endpoints. Restrict egress at the network or firewall layer. * `runc` shares the host kernel. For untrusted or multi-tenant workloads, configure a hardened default runtime on the Docker daemon, such as `sysbox-runc`, gVisor, or Kata. ## See also * [Daytona](https://everruns.com/docs/capabilities/daytona/) and [E2B](https://everruns.com/docs/capabilities/e2b/), hosted sandbox providers * [Storage](https://everruns.com/docs/capabilities/session-storage/), where uploaded and downloaded files live * [Docker Container](https://everruns.com/docs/capabilities/docker/), an older experimental Docker capability --- # Current Time > Read the current date and time in a chosen format and timezone. Source: | | | | ---------------- | -------------- | | **ID** | `current_time` | | **Category** | Core | | **Features** | None | | **Dependencies** | None | Provides a tool to get the current date and time. Supports multiple formats and timezones. ## Tools ### `get_current_time` Get the current date and time. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | --------------------------------------------------------- | | `timezone` | string | no | IANA timezone (e.g., `America/New_York`, `Europe/London`) | | `format` | string | no | Output format: `iso8601`, `unix`, `human` | ## See Also * [Schedules](https://everruns.com/docs/capabilities/session-schedules/), schedule future tasks * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Data Knowledge > Mount a read-only /knowledge/ Open Knowledge Format scaffold for table docs, business rules, and validated SQL, used by the Data Analyst harness. Source: | | | | ---------------- | ------------------------------------------------------------------ | | **ID** | `data_knowledge` | | **Category** | Data | | **Tools** | None | | **Features** | `file_system` | | **Dependencies** | [File System](https://everruns.com/docs/capabilities/file-system/) | | **Risk** | Low | The `data_knowledge` capability mounts a read-only `/knowledge/` directory into the session and tells the agent to read it before writing SQL. The directory is shaped as an [Open Knowledge Format](https://everruns.com/docs/how-to/share-knowledge-with-okf/) (OKF) bundle: Markdown files with YAML frontmatter, navigated through `index.md` files. The [Data Analyst](https://everruns.com/docs/built-ins/harnesses/data-analyst/) harness includes it. ## What gets mounted ```text /knowledge/ index.md # OKF root index (okf_version "0.1") tables/index.md # how to document a table or data source business/index.md # how to document metrics and business rules queries/index.md # how to document validated query patterns ``` Each `index.md` explains what belongs in its directory. The mount is a fixed, read-only scaffold built into the capability: the agent cannot write to it, and the capability has no configuration for adding your own files to it. To give the agent your organization’s curated data knowledge, put it in a [Knowledge Base](https://everruns.com/docs/capabilities/knowledge-base/) (OKF bundles import directly) or in an organization [Memory](https://everruns.com/docs/capabilities/memory/) mounted under `/workspace`. ## System prompt The capability adds one instruction: curated data knowledge is mounted at `/knowledge/{tables,business,queries}`, and the agent should read it before writing SQL and treat it as ground truth for schema semantics, metrics, and validated queries. ## Configuration None. ```json { "ref": "data_knowledge" } ``` ## See also * [Data Analyst harness](https://everruns.com/docs/built-ins/harnesses/data-analyst/) * [Share knowledge with OKF](https://everruns.com/docs/how-to/share-knowledge-with-okf/) * [Knowledge Base](https://everruns.com/docs/capabilities/knowledge-base/) --- # Daytona > Run agent code in Daytona cloud sandboxes with command execution, file access, git, workspace downloads, and session-scoped lifecycle controls. Source: | | | | ---------------- | ---------------------------------------------------------------------------- | | **ID** | `daytona` | | **Category** | Sandboxes | | **Features** | None | | **Dependencies** | [`session_storage`](https://everruns.com/docs/capabilities/session-storage/) | Run code in cloud sandboxes powered by [Daytona](https://www.daytona.io/). An agent can create several isolated Linux environments per session, each with network access, then execute commands, manage files, clone repositories, and download results. The capability is marked experimental and may change. New fleet workflows This provider-specific capability remains for compatibility and advanced Daytona operations. Use [`sandbox_fleet`](https://everruns.com/docs/capabilities/sandbox-fleet/) for new workflows that should use logical Everruns Sandbox IDs and remain independent of the provider-facing tool namespace. ## Set up 1. In the [Daytona Dashboard](https://app.daytona.io), open **API Keys** in your account settings, select **Create New API Key**, and copy the key. 2. In Everruns, open **Settings → Connections**, find **Daytona**, select **Connect**, and paste the key. Once connected, agents with the Daytona capability can use the tools below. ## Tools ### `daytona_create_sandbox` Create and start a new sandbox. | Parameter | Type | Required | Description | | ------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------- | | `title` | string | no | Sandbox name | | `size` | string | no | `small` (1 vCPU, 1 GiB RAM, 3 GiB disk, default), `medium` (2 vCPU, 4 GiB, 8 GiB), or `large` (4 vCPU, 8 GiB, 10 GiB) | | `snapshot` | string | no | Daytona snapshot name; overrides `size` | | `auto_stop_minutes` | integer | no | Minutes of inactivity before auto-stop, 1 to 60 (default 5) | | `upload_files` | array | no | `{session_path, sandbox_path}` pairs to copy from session storage | ### `daytona_exec` Run a shell command in a sandbox and wait for it. | Parameter | Type | Required | Description | | ------------ | ------- | -------- | ---------------------------------------------- | | `sandbox_id` | string | yes | Target sandbox | | `command` | string | yes | Shell command to execute | | `cwd` | string | no | Working directory (default: sandbox workspace) | | `timeout` | integer | no | Timeout in milliseconds (default 300000) | ### `daytona_read_file` Read a file from a sandbox. | Parameter | Type | Required | Description | | ------------ | ------- | -------- | -------------------------------------------- | | `sandbox_id` | string | yes | Target sandbox | | `path` | string | yes | File path | | `offset` | integer | no | Zero-based line offset to start reading from | | `limit` | integer | no | Maximum number of lines to return | ### `daytona_write_file` Write a file to a sandbox. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | -------------- | | `sandbox_id` | string | yes | Target sandbox | | `path` | string | yes | File path | | `content` | string | yes | File content | ### `daytona_download_workspace` Download a sandbox directory to session storage. | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------------------ | | `sandbox_id` | string | yes | Target sandbox | | `sandbox_path` | string | no | Root path in the sandbox (default: workspace path) | | `session_path` | string | no | Destination in session storage (default: `/workspace`) | ### `daytona_list_snapshots` List available Daytona snapshots (names, CPU, memory, and disk specs, state). Use a snapshot name as the `snapshot` parameter of `daytona_create_sandbox`. Takes no parameters. ### `daytona_list_sandboxes` List all sandboxes for the current session. Takes no parameters. ### `daytona_manage_sandbox` Stop or delete a sandbox. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | ------------------ | | `sandbox_id` | string | yes | Target sandbox | | `action` | string | yes | `stop` or `delete` | ### `daytona_git_clone` Clone a git repository into a sandbox. Uses your connected GitHub credentials for private repositories. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------------------------------------- | | `sandbox_id` | string | yes | Target sandbox | | `repo_url` | string | yes | Repository URL or `user/repo` shorthand | | `branch` | string | no | Branch to clone (default: the default branch) | | `path` | string | no | Clone destination (default: `/home/daytona//`) | ### `daytona_git_credentials` Configure git credentials in a sandbox so later `git push`, `pull`, and `fetch` commands run through `daytona_exec` authenticate. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | -------------- | | `sandbox_id` | string | yes | Target sandbox | ### `daytona_api_call` (opt-in) Call any Daytona REST endpoint directly, for operations the dedicated tools do not cover. Only available when the capability config sets `enable_api_calling` to `true`. Authentication headers are injected automatically, and the Daytona OpenAPI spec is mounted at `/daytona/openapi.yaml`. | Parameter | Type | Required | Description | | --------- | --------------- | -------- | -------------------------------------------------------------------------------------- | | `method` | string | yes | `GET`, `POST`, `PUT`, `PATCH`, or `DELETE` | | `path` | string | yes | Management API path (`/sandbox/...`) or Toolbox API path (`/toolbox/{sandbox_id}/...`) | | `body` | object or array | no | JSON request body | ## Config ```json { "enable_api_calling": true } ``` `enable_api_calling` is the only setting, and it defaults to `false`. ## Git * `daytona_git_clone` uses your connected GitHub account, so private repositories clone without extra setup. When no person is in the run, or the person has not connected GitHub, it uses the agent’s GitHub connection. * For push, pull, or fetch, call `daytona_git_credentials` once after creating the sandbox, then run git commands with `daytona_exec`. * Tokens written into the sandbox only reach repository contents: `daytona_git_clone`’s token covers the cloned repository alone, and `daytona_git_credentials` covers contents of every repository the connection reaches. Neither can open issues or review pull requests. * Repository arguments accept `user/repo` shorthand instead of full URLs. ## Sandbox lifecycle Sandboxes auto-stop after 5 minutes of inactivity by default as a safety net. Delete sandboxes when you are done: stopping only pauses a sandbox, and it stays visible in your Daytona dashboard. All sandbox-scoped tools require a `sandbox_id`. The exceptions are `daytona_create_sandbox`, `daytona_list_sandboxes`, and `daytona_list_snapshots`. ## Security * API keys are encrypted at rest (AES-256-GCM envelope encryption). * Each sandbox is isolated from other sandboxes and the host. * Git credentials are short-lived and scoped to the sandbox. * Sandbox state is stored in encrypted session secrets. ## See also * [Sandbox Templates](https://everruns.com/docs/features/sandbox-templates/#desktop): start the Session Sandbox with a desktop the agent drives with the `computer` tool. * [Storage](https://everruns.com/docs/capabilities/session-storage/): API key and state persistence. * [Daytona documentation](https://www.daytona.io/docs) * [Integrations](https://everruns.com/docs/integrations/): every vendor integration. * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Docker Container Sandbox > Run agent commands and manage files in a Docker container tied to the session. Self-hosted alternative to cloud sandbox providers. Source: | | | | ---------------- | ------------------ | | **ID** | `docker_container` | | **Category** | Sandboxes | | **Features** | None | | **Dependencies** | None | Run commands and manage files in a Docker container tied to the session. The container is lazily started on first use and persists for the session duration. A self-hosted alternative to cloud sandbox providers like Daytona or E2B. > **Status:** Experimental; availability follows the configured feature rollout grade. It is off by default. Use `FEATURE_DOCKER_CAPABILITY=dev` for local development, or select `preview`, `adoption`, or `prod` to control hosted rollout. See [feature rollout grades](https://everruns.com/docs/sre/environment-variables/#feature-rollout-grades). It may change significantly in future releases. ## Tools ### `docker_exec` Execute a command inside the Docker container. | Parameter | Type | Required | Description | | ------------ | ------- | -------- | ----------------------- | | `command` | string | yes | Shell command to run | | `cwd` | string | no | Working directory | | `timeout_ms` | integer | no | Timeout in milliseconds | Returns stdout, stderr, and exit code. Container is started automatically if not already running. ### `docker_read_file` Read a text file from the container filesystem. | Parameter | Type | Required | Description | | --------- | ------- | -------- | --------------------------------- | | `path` | string | yes | File path | | `offset` | integer | no | Line offset to start reading from | | `limit` | integer | no | Maximum number of lines to return | ### `docker_write_file` Write a text file into the container filesystem. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------ | | `path` | string | yes | File path | | `content` | string | yes | File content | ### `docker_logs` Retrieve recent logs from the Docker container. | Parameter | Type | Required | Description | | --------- | ------- | -------- | ----------------------------- | | `tail` | integer | no | Number of log lines to return | ### `docker_stop` Stop the Docker container for this session. ## Configuration Configure the Docker container via the capability settings: | Setting | Description | | ------- | ----------------------------------------- | | `image` | Docker image to use (e.g. `ubuntu:24.04`) | | `env` | Environment variables to inject | | `binds` | Host path mounts | ## Notes * Only one container runs per session * The container is stopped when the session ends or `docker_stop` is called * Docker Engine must be accessible from the server running Everruns ## See Also * [Container Sandbox](https://everruns.com/docs/capabilities/container-sandbox/), the self-hosted Docker Engine sandbox * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Dry Run > Try an agent without its side effects. Read-only tools run for real; every other tool call returns a simulated result and changes nothing. Source: | | | | ---------------- | --------- | | **ID** | `dry_run` | | **Category** | Safety | | **Tools** | None | | **Features** | None | | **Dependencies** | None | Dry run lets you see what an agent would do before it does it. A session with this capability runs tools that only read, and answers every other tool call with a simulated result. Nothing is sent, written, or deleted. The **Test run** button on an agent’s page starts a session with dry run on. ## What runs for real A tool runs for real when it declares itself read-only and nothing marks it destructive or requiring approval. MCP tools declare this through their own annotations or through a [risk label](https://everruns.com/docs/reference/cli/mcp-servers/) set on the connection. Every tool that does not declare itself read-only is simulated: a dry run errs on the side of not acting. ## What a simulated call returns The call is recorded as a successful result with a `dry_run` object that names the tool and its arguments: ```json { "dry_run": { "simulated": true, "tool": "visti_send", "arguments": { "text": "main CI is red" }, "note": "Dry run: `visti_send` was not executed. Nothing was changed." } } ``` The agent is told it is in a dry run. It carries on as if simulated calls worked, so the rest of the run is exercised, and its final answer lists the actions it would have taken. The session trace marks simulated calls. ## Configuration Dry run has no settings. Add it to a session’s capabilities: ```json { "capabilities": [{ "ref": "dry_run" }] } ``` --- # E2B Sandboxes > Run agent code in isolated E2B cloud sandboxes with your own API key, command execution, file access, and session-scoped lifecycle management. Source: | | | | ---------------- | ---------------------------------------------------------------------------- | | **ID** | `e2b` | | **Category** | Sandboxes | | **Features** | None | | **Dependencies** | [`session_storage`](https://everruns.com/docs/capabilities/session-storage/) | Run code in cloud sandboxes powered by [E2B](https://e2b.dev/docs). An agent can create, pause, resume, delete, and work in several isolated Linux sandboxes per session. Sandboxes are tracked per session. You bring your own E2B API key. There is no platform-owned or environment-variable fallback, so sandbox costs and quotas stay in your own E2B account. ## Set up 1. In the [E2B Dashboard](https://e2b.dev/dashboard), create an API key and copy it. 2. In Everruns, open **Settings** > **Connections**, find **E2B**, select **Connect**, and paste the key. Every E2B operation requires a user-provided key. If none is configured, the agent shows an inline connection prompt. ## Tools ### `e2b_create_sandbox` Create a new E2B sandbox. Returns `sandbox_id` and connection details. | Parameter | Type | Required | Description | | ----------------- | ------- | -------- | ----------------------------------------------------------------- | | `title` | string | no | Human-readable sandbox name | | `template` | string | no | E2B template ID (default `base`) | | `timeout_seconds` | integer | no | Sandbox TTL in seconds (default `3600`) | | `env_vars` | object | no | Environment variables injected into the sandbox | | `upload_files` | array | no | `{session_path, sandbox_path}` pairs to copy from session storage | ### `e2b_exec` Execute a shell command in a sandbox, capturing stdout, stderr, and the exit code. | Parameter | Type | Required | Description | | ------------ | ------- | -------- | ------------------------------- | | `sandbox_id` | string | yes | Target sandbox | | `command` | string | yes | Shell command to run | | `cwd` | string | no | Working directory | | `timeout_ms` | integer | no | Command timeout in milliseconds | ### `e2b_read_file` Read a text file from a sandbox filesystem. | Parameter | Type | Required | Description | | ------------ | ------- | -------- | --------------------------------- | | `sandbox_id` | string | yes | Target sandbox | | `path` | string | yes | File path | | `offset` | integer | no | Line offset to start reading from | | `limit` | integer | no | Maximum number of lines to return | ### `e2b_write_file` Write a text file into a sandbox filesystem. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | -------------- | | `sandbox_id` | string | yes | Target sandbox | | `path` | string | yes | File path | | `content` | string | yes | File content | ### `e2b_list_sandboxes` List all E2B sandboxes created in the current session. Takes no parameters. ### `e2b_manage_sandbox` Pause, resume, or delete an E2B sandbox. | Parameter | Type | Required | Description | | ----------------- | ------- | -------- | ------------------------------ | | `sandbox_id` | string | yes | Target sandbox | | `action` | string | yes | `pause`, `resume`, or `delete` | | `timeout_seconds` | integer | no | Timeout to apply when resuming | ## How it works E2B exposes two surfaces, and the capability uses both: * **Management API** (`api.e2b.app`): sandbox lifecycle, metadata, and timeout control. * **envd sandbox endpoint**: in-sandbox file access and command execution. Per-sandbox state (sandbox ID, domain, access token, workspace path, timeout) is stored in encrypted session secrets and registered as a leased resource, so orphaned sandboxes are cleaned up on the worker side. Every sandbox is tagged with Everruns ownership metadata (session, harness, org, and agent IDs) for dashboard traceability and audit review. File operations target the sandbox filesystem, not the session workspace. Each sandbox has internet access. Use `e2b_manage_sandbox` to delete sandboxes when you are done. ## Security * API keys resolve fresh from your user connection on each tool call. They are never stored in sandbox state or env vars, and never appear in tool output. * envd access tokens are session-scoped and stored only in encrypted session secrets (AES-256-GCM envelope encryption). * Sandbox isolation depends on E2B’s runtime boundaries plus Everruns session-scoped secret lookups. * E2B timeouts and auto-pause, plus Everruns leased-resource cleanup, limit resource leaks. ## See also * [Storage](https://everruns.com/docs/capabilities/session-storage/): API key and state persistence. * [E2B documentation](https://e2b.dev/docs) * [Integrations](https://everruns.com/docs/integrations/): every vendor integration. * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # File System > Read, write, search, and manage files in an isolated per-session workspace, with glob, grep, and directory operations. Source: | | | | ---------------- | ------------------------------------- | | **ID** | `session_file_system` | | **Category** | File Operations | | **Features** | `file_system` (enables Workspace tab) | | **Dependencies** | None | Provides tools to access and manipulate files in the session workspace. Each session has an isolated filesystem rooted at `/workspace`. Files persist for the session duration. `read_file` and `write_file` return a `content_hash` (`sha256:...`) so agents can make freshness-checked `edit_file` calls. ## Tools ### `read_file` Read the contents of a file. Successful responses include `content_hash`. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------- | | `path` | string | yes | Absolute path (e.g., `/workspace/src/main.py`) | ### `read_many_files` Read 2-10 independent files in one ordered call. Only batch paths known before the call; if one file reveals another path, read it in a later call. Results keep per-file success or error details. Images return metadata only; read them individually with `read_file`. | Parameter | Type | Required | Description | | --------- | ------- | -------- | ---------------------------------------------------------- | | `paths` | array | yes | Ordered list of 2-10 absolute paths | | `offset` | integer | no | Starting line applied to every file (0-indexed, default 0) | | `limit` | integer | no | Max lines per file | ### `write_file` Create or overwrite a file. Parent directories are created automatically. Successful responses include `content_hash`. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------- | | `path` | string | yes | Absolute path | | `content` | string | yes | File content | ### `edit_file` Apply one or more exact text replacements to an existing text file. This tool is text-only, requires the current `content_hash` from `read_file` or `write_file`, and uses compare-and-set semantics so concurrent writes fail cleanly instead of clobbering newer content. | Parameter | Type | Required | Description | | --------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `path` | string | yes | Absolute path to an existing text file | | `expected_hash` | string | yes | Current `content_hash` (`sha256:...`) | | `edits` | array | yes | One or more `{ old_text, new_text }` replacements matched against the original file. Use a single-element array for one replacement. | Legacy top-level `old_text`/`new_text` are still accepted for backward compatibility, they are folded into `edits[]`, but new callers should always use `edits[]`. ### `list_directory` List files and directories at a given path. | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------- | | `path` | string | yes | Directory path | ### `grep_files` Search file contents with regex patterns. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------- | | `pattern` | string | yes | Regex pattern | | `path` | string | no | Directory to search (default: `/workspace`) | ### `glob` List files recursively under `/workspace` whose relative paths match a glob. Results are sorted and bounded. | Parameter | Type | Required | Description | | --------- | ------- | -------- | ---------------------------------------------- | | `pattern` | string | yes | Glob relative to `/workspace` | | `limit` | integer | no | Maximum matches, from 1 to 1000 (default: 200) | ### `grep` Search UTF-8 files recursively under `/workspace` with a Rust regular expression. This is the provider-neutral search name used by managed Environments; `grep_files` remains available for existing file-system agents. | Parameter | Type | Required | Description | | --------- | ------- | -------- | ---------------------------------------------- | | `pattern` | string | yes | Rust regular expression | | `glob` | string | no | Restrict searched files with a glob | | `offset` | integer | no | Skip this many matches (default: 0) | | `limit` | integer | no | Maximum matches, from 1 to 1000 (default: 200) | ### `delete_file` Delete a file or directory. | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------- | | `path` | string | yes | Path to delete | ### `stat_file` Get file metadata (size, type, timestamps). | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------ | | `path` | string | yes | Path to stat | ## `edit_file` request example ```json { "path": "/workspace/app.py", "expected_hash": "sha256:1c4d...", "edits": [ { "old_text": "return 'Hello, World!'", "new_text": "return 'Hello from Everruns!'" } ] } ``` ## Notes * All paths must be under `/workspace` * Files are session-scoped, no cross-session access * Parent directories are auto-created on write * `edit_file` only works on text files and rejects binary/base64 content * `edit_file` applies all replacements against the original file content and rejects ambiguous or overlapping matches * `edit_file` preserves the file’s existing BOM and newline style (`LF`, `CRLF`, or `CR`) * `edit_file` returns a unified diff capped to a bounded size; oversized diffs are truncated and marked as such * Shared filesystem with [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/) (same `/workspace`) ## See Also * [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/), execute commands against these files * [Storage](https://everruns.com/docs/capabilities/session-storage/), key/value and secret storage * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # GitHub > Read and review GitHub pull requests with inline comments, keep one comment per pull request up to date, and file deduplicated issues. Source: | | | | ---------------- | ------------ | | **ID** | `github` | | **Category** | Integrations | | **Features** | None | | **Dependencies** | None | The GitHub capability gives an agent what it needs to work on one pull request: read it, read its diff, review it with inline comments, and leave a comment it can keep editing. It can also file findings as issues without duplicating them. Pair it with a GitHub trigger to build a pull request reviewer, or with a schedule trigger and a sandbox to build a security scanner. The [PR Reviewer and Security Scanner templates](https://everruns.com/docs/how-to/set-up-review-and-security-agents/) do both for you. ## Tools | Tool | What it does | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `get_github_pull_request` | Title, description, author, state, branches, size, and up to 100 changed files. | | `get_github_pull_request_diff` | The unified diff, cut to `max_bytes` (default 60,000, at most 200,000). `truncated` says whether it was cut. | | `github_checkout_pull_request` | Checks the pull request out into the session’s [managed sandbox](https://everruns.com/docs/features/sandbox-templates/), private repositories included. See [Check out a pull request](#check-out-a-pull-request). | | `upsert_github_comment` | Posts a Markdown comment, or edits the one it posted earlier with the same `marker` (default `summary`). | | `submit_github_pull_request_review` | Submits one review (`COMMENT` or `REQUEST_CHANGES`; it cannot approve) with a summary and inline comments on changed lines. | | `upsert_github_issue` | Files a finding as an issue keyed by a `fingerprint`; updates the open issue for the same fingerprint, leaves a closed one closed. | | `create_github_pull_request` | Opens a pull request (draft by default) from a branch already pushed to the same repository. Only offered when `allow_pull_requests` is on. | The pull request tools take `repo` (`owner/repo`) and `number`. ### Check out a pull request `github_checkout_pull_request` fetches the pull request’s head and its base branch into `/workspace/` (or `path`, which must stay inside `/workspace`) and leaves the head checked out at a detached HEAD, so `bash` can build, test and diff it: ```json { "repo": "acme/app", "number": 42 } ``` It returns `path`, `head_sha`, `base_ref` and `base_sha`; `depth` (default 100) sets how much history is fetched. It needs the Managed Sandbox (`session_sandbox`) capability on a Sandbox Worker, and says so otherwise. Checkout requires a GitHub App installation. The trusted resolver must supply installation-mint evidence that the token covers exactly this repository, grants only **Contents: read**, **Pull requests: read** and GitHub’s implicit **Metadata: read**, and expires within one hour. Missing evidence, personal OAuth tokens and `GITHUB_TOKEN` session-secret fallbacks are refused before any credential reaches the sandbox. This also fails closed with older control planes. For personal-token workflows, use `github_get_pull_request` and `github_get_pull_request_diff` to review on the trusted host, or connect an App installation for checkout. The tool hands the admitted token with **Contents: read** and **Pull requests: read** for that one repository to a single `git fetch` through a temporary file it removes before returning, so the token is not in `.git/config`, in later `bash` commands, or in sandbox checkpoints. Plain `git fetch` in `bash` therefore works only for public repositories; call the tool again to refresh a checkout. Concurrent code in the sandbox can read the temporary file; the enforced repository, permission and expiry limits bound this accepted exposure. ### Reviews without repeats Each inline comment from `submit_github_pull_request_review` starts with a hidden `` line. Pass a short, stable `key` per finding (such as `null-deref-parse-config`); a key the agent already posted on the pull request is skipped, so a review after a new push only adds what is new. A second review of the same head commit is skipped entirely, which makes webhook redeliveries harmless. Comments on lines that are not part of the diff would make GitHub reject the whole review, so the tool moves them into the review summary instead. Only comments, reviews and issues written by a bot count as the agent’s own, so a person cannot hide a finding by pasting a marker into their own comment. ## Settings | Setting | Default | Effect | | --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | | `acts_as` | `agent` | Whose GitHub identity the tools use: `agent`, `person`, or `person_or_agent`. See [Authentication](#authentication). | | `allow_pull_requests` | `false` | Adds `create_github_pull_request`. Pushing the branch also needs the GitHub App’s **Contents: write** permission. | | `private_issues_only` | `false` | `upsert_github_issue` refuses public repositories, so a finding is never disclosed in a public issue. | `upsert_github_comment` starts the comment with a hidden `` line and looks for it on the next run, so an agent that runs on every push updates one comment instead of adding a new one each time. Use a different marker for each kind of comment. ## Authentication The tools act on GitHub as the identity `acts_as` names; only `person_or_agent` ever uses a second one: * `agent` (default) uses the agent’s own GitHub connection: its GitHub App when you connected one, so comments are posted as the agent’s bot and the tools reach only the repositories the App is installed on. An agent that chose **Use the Everruns app** acts as the shared Everruns App’s bot on the account an org admin linked. Use it for bots, and for anything triggered without a person. * `person` uses the GitHub connection of the person talking to the agent. Use it for a personal agent. A triggered run has no person, so it gets nothing. * `person_or_agent` uses the person’s connection when they have one, otherwise the agent’s. Each call gets a short-lived token limited to the one repository it names and the permissions that tool needs: the read tools ask for **Pull requests: read**, the checkout tool for **Contents: read** and **Pull requests: read**, the comment tool for **Issues** and **Pull requests: write**, the review tool for **Pull requests: write**, the issue tool for **Issues: write**, and `create_github_pull_request` for **Pull requests: write** and **Contents: read**. Without a connection for that identity the tools return `connection_required`. The session’s network access policy must allow `https://api.github.com/` when one is set. --- # GitHub Scout > Blueprint-only GitHub repository exploration capability that spawns read-only scout subagents. Source: | | | | ---------------- | ----------------------------------------------------------------- | | **ID** | `github_scout` | | **Category** | Integrations | | **Features** | None | | **Dependencies** | [`subagents`](https://everruns.com/docs/capabilities/sub-agents/) | GitHub Scout lets an agent spawn a specialist subagent for read-only GitHub repository exploration. The host agent receives `spawn_agent` with `target.type: "subagent"` through the dependency on `subagents`; monitoring and steering are handled by the generic `session_tasks` tools (`list_tasks`, `get_task`, `message_task`, `cancel_task`). The GitHub API tools stay private inside the spawned `github_scout` blueprint session. ## How to Use Enable the `github_scout` capability on an agent or harness. Then spawn the blueprint: ```json { "name": "spawn_agent", "arguments": { "name": "Scout", "instructions": "Find where authentication middleware is implemented.", "target": { "type": "subagent" }, "blueprint": "github_scout", "config": { "repos": ["fastify/fastify"] } } } ``` The optional `repos` config scopes GitHub searches to `owner/repo` repositories. Config is validated against the blueprint’s schema before the child session is created: entries that are not `owner/repo` and unrecognized config keys are rejected with a schema error instead of being silently ignored. ## Private Blueprint Tools These tools are available only inside the GitHub Scout child session: | Tool | Description | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `search_github_code` | Search code with GitHub code search qualifiers such as `repo:`, `path:`, `language:`, `symbol:`, and `filename:` | | `read_github_file` | Read a UTF-8 file from a repository by `repo`, `path`, and optional `ref` | | `search_github_issues` | Search issues and pull requests with qualifiers such as `repo:`, `is:issue`, `is:pr`, `state:`, `author:`, and `label:` | ## Authentication GitHub Scout uses the existing GitHub user connection. In local and compatibility flows, tools can also use a `GITHUB_TOKEN` session secret. Missing credentials return a connection prompt instead of asking for tokens in chat. ## Included Examples The adoptable **Coding (Daytona)** and **Coding (Container)** harness examples include `github_scout`, so coding agents based on those examples can delegate GitHub repository lookup work to Scout. ## See Also * [Sub Agents](https://everruns.com/docs/capabilities/sub-agents/), lifecycle tools used to spawn and manage Scout * [Author an agent blueprint](https://everruns.com/docs/framework/agent-blueprints/), how Scout and blueprints like it are built * [Capabilities Overview](https://everruns.com/docs/capabilities/), full capability catalog --- # Guardrails > Config-driven checks that constrain agent behavior, inspecting model output and tool activity, then blocking or logging when content matches a rule. Source: | | | | ---------------- | ------------------------------------------ | | **ID** | `guardrails` | | **Category** | Safety | | **Tools** | None | | **Dependencies** | Utility LLM (only for model-backed checks) | | **Risk** | Low | Guardrails are checks that constrain what an agent does. Where most [capabilities](https://everruns.com/docs/capabilities/) *grant* an ability, a guardrail *restricts* one: it inspects model output and tool activity, then **blocks** or **logs** when content matches a rule. Guardrails are opt-in. An agent with no guardrails is a fully supported configuration, there is no org-mandated enforcement layer. A [harness](https://everruns.com/docs/features/harnesses/) can attach guardrail capabilities as soft defaults that flow to every agent built on it, and an author can still remove them. This is the platform stance: guardrails are a default posture, not a cage. The `guardrails` capability holds no rules of its own. Its per-agent config is a declarative list of checks plus a mode; the capability compiles that config and contributes the matching runtime hooks. An empty config (or the capability being absent) contributes nothing, with zero added latency. ## Concepts A **check** binds a **rule** to a **stage** with an **on-fail action**. ### Stages | Stage | What it sees | | ------------- | ---------------------------------------------------------------------- | | `output` | Streamed assistant text | | `tool_use` | A tool call before it executes, the tool name and serialized arguments | | `tool_output` | A tool result before it enters model context | `tool_output` is the trust boundary for untrusted external content (web pages, MCP responses); indirect-injection and secret-leakage checks belong there. ### Rules | Rule (`type`) | What it matches | Valid stages | Execution | | -------------- | -------------------------------------------------------------------- | --------------- | ------------------- | | `regex` | Any of the patterns matches the stage text | all | in-process, sync | | `blocklist` | Any word/phrase appears as a substring (case-insensitive by default) | all | in-process, sync | | `tool_pattern` | The tool name matches a `*`-wildcard glob | `tool_use` only | in-process, sync | | `llm_judge` | A natural-language policy, evaluated by a system model | all | async, model-backed | | `mcp` | Decision delegated to an external guardrail served over scoped MCP | all | async, off-platform | | `moderation` | The finalized message scored against content categories | `output` only | async, model-backed | Deterministic rules (`regex`, `blocklist`, `tool_pattern`) run in the streaming and per-tool-call hot path, linear-time, no I/O, with hard limits on check count, entries, and lengths so an authored pattern can never wedge a worker. Model-backed and MCP rules run only in the async hook path (and, for `output`, on a post-generation end-of-message boundary), never on the sync hot path. On `output` they inspect the finished message once, after streaming, and a block replaces the whole message; an `mcp` check there receives `tool: null`. ### Engines The two model-backed types, `llm_judge` and `moderation`, choose which system model answers them with `engine`: * **`utility_llm`** (the default) prompts your org’s utility model for a verdict — `allow`/`block` for a judge, 0-100 scores per category for moderation. One request per check. * **`jev`** asks [Jev](https://everruns.com/docs/integrations/typesafe/), TypeSafe’s System One model, a typed question and gets a calibrated probability back. The `threshold` you configure (a percentage, default 50) decides the verdict, and every jev check on a stage is answered in a **single** request. It needs `UTILITY_TYPESAFE_API_KEY` on the deployment, or `UTILITY_DECISION_DRIVER=llm` to have the utility model answer the same questions (a yes/no label rather than a calibrated probability, so the threshold then only checks which answer it picked). ```json { "stage": "tool_use", "type": "llm_judge", "engine": "jev", "threshold": 70, "prompt": "Block any tool call that deletes customer records." } ``` Two reasons to prefer `jev` once your deployment has a key configured. It is cheaper on latency: four judge checks on a tool call cost one round trip instead of four. And the verdict is yours — the model reports how likely a violation is, your threshold decides what to do about it, and there is no written verdict to misparse. For moderation it also reads the *tail* of the distribution rather than a score: content that is probably fine but 30% likely to be a clear violation trips a 30% threshold, where an averaged score would hide it. `utility_llm` stays the default, so existing configs are unchanged. Both engines fail open, honor `on_fail` and advisory mode identically, and send the same bounded excerpt. A check set to `jev` in a deployment with no TypeSafe key configured is skipped with a warning. #### Use your organization’s decision model By default, `jev` checks use the deployment’s decision model. An organization can answer them with its own model instead: pick a **Default decision model** on the Models page, then set **System decisions** to **This organization’s model** (or `PATCH /v1/orgs/{org}` with `"system_decisions": "organization"`). The checks then run on your provider account, count against the session’s budget, and show up in its usage, the same as the `jev_decision` tool. Once you opt in, the deployment’s model is never used for your checks. If your default decision model is missing, disabled, or failing, `jev` checks fail open with a warning. Switch back with `"system_decisions": "deployment"`. ### On-fail * `block`, suppresses the matched content: an `output`/`tool_output` block replaces the content with a notice; a `tool_use` block refuses the call and feeds the reason back to the model, which can self-correct. The model’s original tokens are never persisted. * `log`, records the hit and continues. An optional per-check `replacement` customizes the block notice or user-facing refusal message. ### Mode: active vs. advisory A config-level `mode` is `active` (default) or `advisory`. **Advisory downgrades every hit to `log`**: checks run and are recorded, but nothing is blocked. Advisory is how you tune a guardrail against false positives before enforcing it. Mode is per attachment, so the same catalog entry can be advisory on one agent and active on another. ## Config shape Config is a `GuardrailsConfig` stored under the `guardrails` capability in the agent’s config. Field names are `snake_case`; each check names its rule with a `type` tag alongside the shared `stage` / `on_fail` / `replacement` fields: ```json { "mode": "active", "checks": [ { "id": "no-secrets-in-output", "stage": "output", "on_fail": "block", "replacement": "[Response withheld: appears to contain a credential.]", "type": "regex", "patterns": ["AKIA[0-9A-Z]{16}", "ghp_[A-Za-z0-9]{36}"] }, { "id": "no-shell", "stage": "tool_use", "on_fail": "block", "type": "tool_pattern", "tools": ["bash*", "*exec*"] } ] } ``` The `id` is optional but recommended, it is surfaced in reason codes and logs. ## Data egress and failure behavior * **Deterministic checks** (`regex`, `blocklist`, `tool_pattern`) run entirely in-process; no data leaves the platform. * **`llm_judge` and `moderation`** send a bounded content excerpt to a system model: with `engine: "utility_llm"`, your org’s *own* configured utility LLM, the same provider the agent already uses; with `engine: "jev"`, the deployment’s decision model, or your organization’s default decision model when **System decisions** is set to it. Either way it is an operator-configured destination, not a per-agent one. * **`mcp`** sends a bounded content excerpt to an external, operator-configured MCP guardrail endpoint. Tenant scoping is enforced by the host’s per-session scoped-MCP resolver, so a config can only reach servers scoped to its own session/org. Every async check is bounded (10 s timeout; at most 4 utility-LLM calls per tool call or finalized message, and one batched request for all `jev` checks on a stage) and **fails open**: a timeout, error, or unparseable verdict defaults to `allow`. A guardrail outage, or a hostile MCP endpoint, can only ever *allow*, never make execution more permissive than the no-guardrail baseline in a way that blocks a healthy turn. Model-backed checks flow through utility-LLM accounting, not the session model budget. ## Tuning: dry-run and advisory Two surfaces let you tune checks before enforcing them: * **`POST /v1/capabilities/guardrails/dry-run`** evaluates a config against sample text for a given stage, with no session and nothing persisted. It returns the triggered checks (id, rule type, effective action, reason code, matched excerpt) and whether the content would be blocked. It runs only deterministic checks, it never makes a network call, so it is the fast false-positive tuning loop for `regex`/`blocklist`/`tool_pattern`. * **Advisory mode** runs the full set (including model-backed checks) against real traffic in `log`-only form, so you can review what *would* have been blocked before switching to `active`. ## The gallery: ready-made presets Rather than authoring checks from scratch, list the **guardrail gallery**: a read-only catalogue of adoptable presets: ```plaintext GET /v1/capabilities/guardrails/examples ``` Each listing carries a full `config` plus trust metadata so a picker can show what a preset does before adoption: | Field | Meaning | | ------------- | ------------------------------------------------------------------------------------------- | | `check_types` | The rule-type composition (e.g. `["regex"]`, `["llm_judge"]`) | | `stages` | Which stages the preset’s checks run in | | `data_egress` | `none` for deterministic presets; `utility_llm` when a preset contains a model-backed check | `data_egress` is **derived from the check types**, not hand-authored, so it stays correct as presets mix deterministic and model-backed checks. Adoption is client-side config composition: drop a preset’s `config` into the agent’s `guardrails` capability config (merging or replacing checks). The capability settings on an agent or harness do this in the editor: add a preset to append its checks, or add a check and set its rule, stage, and what happens on a match. There is no new persisted resource and no import endpoint. Noisy presets (PII, prompt-injection heuristics) ship `log`-only so they are safe to adopt active and tune before switching individual checks to `block`. Shipped presets include secret detection, a model-backed secret-leak judge, PII detection, a profanity starter, dangerous-shell blocking, shell-access blocking, and prompt-injection heuristics. ### Worked example: deterministic vs. model-backed secret guardrails Two presets guard the same risk, a secret reaching output or leaving through a tool, by complementary means. **`secret-detection`** matches known credential *formats* by pattern. It is in-process and reports no egress: ```json { "name": "secret-detection", "check_types": ["regex"], "stages": ["output", "tool_output"], "data_egress": "none" } ``` It blocks well-known formats (AWS, GitHub, Slack, Google keys, PEM private keys) in model output and in tool results before they reach context. High-precision, safe to run active. **`secret-leak-judge`** catches secrets by *intent*, including an opaque value whose form is unknown at config time (e.g. one freshly read from a secrets manager), which a regex structurally cannot see: ```json { "name": "secret-leak-judge", "check_types": ["llm_judge"], "stages": ["tool_use", "tool_output"], "data_egress": "utility_llm" } ``` Its `llm_judge` policy blocks a tool call (or result) that would print, echo, log, or transmit secret material in cleartext, while allowing comparisons that reveal only a hash, fingerprint, or redacted form. Because it sits on `tool_use` with `on_fail: block`, a blocked call is **recoverable**: the refusal reason is fed back and the model self-corrects to a safe form (comparing a hash instead of printing the secret). It is model-backed, so `data_egress` is `utility_llm`, adopters are correctly warned that a bounded excerpt leaves the generating path for evaluation. Run it advisory first to tune false positives. The two are meant to be layered: pattern-matching for known formats, the judge for everything else. ## Reason codes Every block or log carries a stable `guardrail.` code (e.g. `guardrail.regex`, `guardrail.llm_judge`, `guardrail.moderation`). Clients localize copy from the code rather than the human-readable text. (The separate [Prompt Canary Guardrail](https://everruns.com/docs/capabilities/prompt-canary-guardrail/) capability uses its own `system_prompt_leak` code.) ## Endpoints | Method | Path | Description | | ------ | -------------------------------------- | -------------------------------------------------------- | | `GET` | `/v1/capabilities/guardrails/examples` | List adoptable gallery presets with trust metadata | | `POST` | `/v1/capabilities/guardrails/dry-run` | Evaluate a config against sample text; nothing persisted | Both are gated by the same `capability.view` policy as other capability reads. ## Related * [Prompt Canary Guardrail](https://everruns.com/docs/capabilities/prompt-canary-guardrail/), a narrow streaming-output guardrail for naive system-prompt leakage. * [Agent Checks](https://everruns.com/docs/features/agent-checks/), advisory, config-*time* review of an agent’s setup. Distinct from guardrails, which enforce at *runtime*. --- # Host Shell > Run bash commands on the machine hosting the agent, bounded by a kernel policy (Landlock and seccomp on Linux, Seatbelt on macOS). Source: | | | | ---------------- | -------------------------------------------------------------------------------------------------------- | | **ID** | `host_shell` | | **Category** | Execution | | **Risk** | High | | **Features** | `file_system` (enables the Workspace tab) | | **Dependencies** | [`session_file_system`](https://everruns.com/docs/capabilities/file-system/), backed by a real directory | **Availability:** Framework (embedder) only. Not available in self-hosted Platform or Everruns Cloud. Run bash commands as real child processes on the machine the agent is running on. Unlike [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/), the toolchain is real: compilers, package managers and test runners work. A kernel policy bounds what those processes may write and whether they may reach the network. ## When to use this instead of Bashkit Both capabilities contribute a tool named `bash` over the session workspace, so enable one or the other, not both. | | Bashkit Shell | Host Shell | | ------------------ | ------------------------------------ | ------------------------------------ | | Where commands run | In-process interpreter | This machine, as child processes | | Native binaries | No | Yes | | Workspace | Session filesystem (virtual or real) | Must be a real directory | | Boundary | The interpreter, by construction | Landlock + seccomp, or Seatbelt | | Network | Off, or egress-routed HTTP | Denied unless containment is removed | Given a virtual session filesystem, `host_shell` refuses and says so rather than inventing a host path. ## Tools ### `bash` Execute a shell command or a multi-line script. | Parameter | Type | Required | Description | | --------------------- | ------ | -------- | ------------------------------------------------------- | | `command` | string | yes | Shell command(s) to execute | | `working_dir` | string | no | Directory to run in (default: the workspace root) | | `sandbox_permissions` | string | no | `use_default` or `require_escalated` | | `justification` | string | no | User-facing reason for `require_escalated` | | `output` | string | no | Output verbosity (`auto`, `normal`, …; default: `auto`) | `commands` is accepted as an alias for `command`, so an agent written against Bashkit Shell keeps working when the backend is swapped. Returns `stdout`, `stderr`, `exit_code`, `success`, and the `containment` that was in force. A failure that the containment would explain is flagged with `containment_denial: "likely"`. Output streams live to the UI and CLI while the command runs, and long scripts can run detached. Every call is a fresh non-interactive `bash -lc` (PowerShell on Windows) rooted at the workspace, so no working directory, variable or export survives between calls. ## Containment Configured per agent, never by the model. | Mode | Reads | Writes | Network | | --------------------------- | ---------- | ------------------------------------------------- | ------- | | `read-only` | the host | private temp only | denied | | `workspace-write` (default) | the host | workspace, `/tmp`, private temp, configured roots | denied | | `danger-full-access` | everything | everything | allowed | Host **reads** are allowed in every contained mode, for toolchain compatibility. The policy stops writes and network exfiltration; it does not stop a command reading unrelated files on the machine. That is the threat model, stated rather than implied. The environment a command inherits is an allowlist: `PATH`, locale, and toolchain variables survive; `HOME` and `TMPDIR` are replaced with a private per-process directory, and everything else, including every API key and agent socket path, is dropped. Two platform differences are deliberate: * `.git` below the workspace is read-only on macOS. Landlock path rules are additive and cannot subtract it, so Linux permits Git metadata writes inside the workspace. * Windows has no containment implementation. Every mode there runs uncontained, and the capability says so. On macOS and Linux, containment fails closed: if the OS primitive is unavailable, the command returns a setup error and is not retried on the host. ## Configuration ```json { "containment": "workspace-write", "approval": "never", "writable_roots": ["/var/cache/agent"], "foreground_timeout_secs": 120, "background_timeout_secs": 86400, "max_output_bytes": 1048576 } ``` An unknown `containment` or `approval` name is rejected rather than defaulted, so a misspelled boundary cannot resolve to a wider one. `writable_roots` adds directories a build needs to write beyond the workspace, a package cache for example. It is ignored at `read-only`. ## Approvals | Policy | When a person is asked | | ----------------- | --------------------------------------------------------------------------------- | | `never` (default) | never; a request to escalate is refused | | `on-failure` | when a command fails in a way the containment would explain | | `on-request` | when the model sets `sandbox_permissions: require_escalated` with a justification | | `untrusted` | for anything outside a small read-only command set | That set is one literal command whose options cannot start another program. `rg --pre`, `rg -z`, and `rg --hostname-bin` ask for approval. `git status` asks unless the same command disables repository fsmonitor and hooks (`-c core.fsmonitor=` and `-c core.hooksPath=/dev/null`), because those settings run code during status. Every policy except `never` needs the host to supply an approval gate. Without one, a policy that would ask refuses instead: an unattended worker has nobody to ask, and a refusal is more honest than a silent escalation. Regardless of policy, a command that visibly signals the agent’s own process is refused before it is spawned. ## Deployment This is an embedder capability, not a hosted-product one. It ships in `everruns-core` (`host` feature) behind the `host-shell` feature (also reachable as `host-shell` on the `everruns` facade) and is deliberately absent from the hosted catalog: handing agents arbitrary host processes is something a CLI host, a CI runner, or an operator’s own box opts into, not something a shared multi-tenant worker should offer. On Linux the kernel policy is applied by a helper process, selected with the `launcher` config key: | `launcher` | Meaning | | ---------------------------- | -------------------------------------------------------------- | | `"discover"` (default) | find `everruns-sandbox-exec` beside the binary, then on `PATH` | | `{"helper": ""}` | run that binary | | `{"reexec_self": [""]}` | re-exec this binary with those leading arguments | `everruns-core` (`host` feature) ships `everruns-sandbox-exec` under the same feature, but cargo does not build a dependency’s binaries, so a single-binary host will not find one beside it. Such a host routes the arguments into `everruns_core::host::containment::worker::run_from_args` from its own `main` and selects `reexec_self`. See the [Host Shell Agent example](https://everruns.com/docs/framework/examples/host-shell-agent/). ## See Also * [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/), the sandboxed interpreter * [File System](https://everruns.com/docs/capabilities/file-system/), file operations on the same workspace * [Daytona](https://everruns.com/docs/capabilities/daytona/) and [E2B](https://everruns.com/docs/capabilities/e2b/), real binaries on someone else’s machine * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Infinity Context > Trim live prompt history and query older messages on demand, so conversation length is not bounded by the context window. Source: | | | | ---------------- | ------------------ | | **ID** | `infinity_context` | | **Category** | Optimization | | **Features** | None | | **Dependencies** | None | Limits the live prompt to recent conversation history while keeping older messages accessible through `query_history`. This is useful for long-running sessions where the agent should stay responsive without losing access to earlier decisions, identifiers, or requirements. ## Tools | Tool | Purpose | | --------------- | ------------------------------------------------------------ | | `query_history` | Search or retrieve earlier messages from the current session | ## How It Works 1. A message filter caps the number of recent messages sent to the model. 2. If older messages are excluded, the model sees a system notice telling it to use `query_history`. 3. The `query_history` tool can keyword-search history or fetch a specific absolute message range. ## Configuration Default configuration: ```json { "capabilities": ["infinity_context"] } ``` Custom budget: ```json { "capabilities": [ { "ref": "infinity_context", "config": { "context_budget_tokens": 80000, "min_recent_messages": 12 } } ] } ``` | Field | Type | Default | Description | | ----------------------- | ------- | -------- | ------------------------------------------------------------- | | `context_budget_tokens` | integer | `100000` | Approximate token budget reserved for message history | | `min_recent_messages` | integer | `10` | Minimum recent messages to keep even when the budget is tight | ## Limitations * Search is keyword-based, not semantic * The tool reads full session history; it does not currently restrict itself to only the trimmed portion * Budgeting uses a heuristic message-count estimate, not model-specific tokenization ## See Also * [Context Compaction](https://everruns.com/docs/advanced/compaction/), Complementary capability that reduces the size of messages in the prompt; see [Worker Harness Defaults](https://everruns.com/docs/advanced/compaction/#worker-harness-defaults) for how they work together * [Capabilities Overview](https://everruns.com/docs/capabilities/) * [Harnesses](https://everruns.com/docs/features/harnesses/) --- # Knowledge > Attach versioned file collections to agents, browse originals and extracted text, and optionally index them for keyword or hybrid retrieval. Source: Knowledge brings notes, uploaded files, repository trees and Everruns documentation into one collection model. Indexing is optional. Files remain available to browse, read and grep when indexing is off. Knowledge is an Adoption feature, available on development and hosted deployments and disabled by default. An organization owner/admin or platform operator can enable the organization’s **Knowledge** feature. Then open **Knowledge** and create a collection. Upload files or a folder with its relative paths, write Markdown with optional OKF frontmatter, or connect a source. GitHub sources reuse existing organization or virtual-user GitHub connections. Public HTTPS Git repositories work without a GitHub connection. Source roots must not overlap, and a connected source cannot overwrite a managed file. ## Attach to an agent Add the **Knowledge** capability and select collections in the agent editor, or use this capability reference: ```json { "ref": "knowledge", "config": { "collections": ["everruns-docs"], "automatic": false, "limit": 8 } } ``` `everruns-docs` is predefined, requires no credentials, and contains a snapshot of the documentation bundled with the server. Indexing starts off. Managers may enable it like any other collection. The agent sees read-only mounts: * `/knowledge/index.md`: the attached collection catalog. * `/knowledge//`: original files, with their hierarchy preserved. * `/knowledge-text//`: extracted text where available. The existing **Data Knowledge** capability keeps its read-only `/knowledge/{tables,business,queries}` scaffold. Its index and the collection catalog share `/knowledge/index.md`; collection ID subtrees always use live collection permissions, including when a collection is detached. Directory listings and grep scoped to a Knowledge path include both sources. Read indexes first, then individual files as needed. An authored `index.md` is preserved; collections without one receive a bounded generated index. Use `browse_knowledge` or `knowledge files` to page through larger directories without enabling indexing. Request metadata only when needed; metadata pages are separately bounded. Knowledge bindings belong to the calling session, including when several sessions share a workspace. Sharing workspace files does not share Knowledge attachments. ## Ownership and attachment scope Collections, their indexes and search-provider accounts belong to an organization. Users manage them through organization permissions; a personal GitHub connection supplies source credentials, not a private user index. Attach collections through the **Knowledge** capability on a harness, agent or session. Configuration follows the existing capability precedence: harness, then agent, then session. A higher layer replaces the lower layer’s configuration for that capability, so list every collection the session should retain. Collections are shared rather than copied or reindexed for each agent or session. Runtime tools, Bashkit search, automatic retrieval and mounts use the calling session’s effective collection bindings and live file visibility. There are no separate user-, agent- or session-owned Knowledge indexes, and an agent does not automatically search every collection in its organization. Sharing a workspace does not share its sessions’ Knowledge bindings. ## Search and grep Choose **Off**, **Keyword**, or **Hybrid** in collection settings. Hybrid needs an enabled embedding model and a persistent Turbopuffer backend. Keyword indexing works with Turbopuffer or the local PostgreSQL full-text fallback. PostgreSQL stores catalog rows, fragment offsets and local lexical postings, not canonical passage text or binary payloads. Collections using a remote indexer keep their postings there. The `search_knowledge` tool accepts a query, optional collection subset, path prefix, user metadata filter, result limit and `lexical_only` flag. Requested collections are always intersected with the session’s current bindings. Returned passages carry immutable file/version IDs, source locators and extracted-text offsets. Bashkit uses the same retrieval service: ```bash knowledge files --collection kn_0123456789abcdef0123456789abcdef --path /policies --limit 50 knowledge search --limit 5 'refund policy' knowledge search --collection kn_0123456789abcdef0123456789abcdef --lexical 'retention' knowledge search --metadata '{"team":"support"}' 'refund policy' grep -n 'retention' /knowledge/kn_0123456789abcdef0123456789abcdef/policies.md ``` Exact grep is independent of the index. Scope it to `/knowledge-text` to search extracted documents. Scans and returned data are bounded; narrow the path if a scan exceeds its budget. With `automatic: true`, Everruns retrieves a small amount of relevant evidence for the incoming user message before model execution. Evidence is retained by input ID for replay, checked against live visibility, and added as source data. Retrieval has a five-second timeout and does not prevent a turn from running when unavailable. Query embedding calls use session usage events; ingestion embeddings are attributed to the organization. ## Content and metadata Original bytes are retained for every format. Markkit extracts HTML, DOCX and spreadsheets. Text and code retain their original UTF-8 representation. Markdown frontmatter, including OKF fields and unknown extensions, is preserved alongside user annotations. Links and file paths remain source-relative. OKF remains a directory of original files: concept Markdown, reserved `index.md` navigation, `log.md` history and binary assets all round-trip through uploads/downloads or a Git source. Unknown frontmatter fields remain intact, including BOM/CRLF files; there is no conversion into fixed entry kinds. `GET /v1/knowledge/{collection_id}/okf` validates a page of OKF v0.2 metadata and reserved-file structure. Follow `next_cursor` to validate the rest of a large catalog. This checks metadata requirements, not every Markdown link or authored index entry. Unsupported binaries, including PDFs, images, audio and video, remain downloadable. This release does not provide PDF extraction, OCR, transcription or multimodal embeddings. Files exceeding the extraction budget remain stored and report that state rather than disappearing. Collection rules independently exclude paths from ingestion, indexing or agent reads. File controls can disable indexing or agent reads without removing the original. Managers can annotate connected files; their source content stays read-only. ## Incremental processing and storage Sync compares Git blob identities before uploading content artifacts. Changed files receive immutable versions; unchanged files retain their version and citations. Extraction is reused for metadata-only edits, and embeddings are cached by organization, model profile and passage hash. Source deletions apply only after a successful complete traversal. Leased jobs renew during source fetches and indexing, retry interrupted work, and index generations publish after the catalog’s visibility checks pass. Uploads and downloads stream in bounded segments. Content uses the configured S3-compatible blob store; local development falls back to `KNOWLEDGE_STORAGE_ROOT` (default `.local/knowledge`). Use shared object storage for multiple server replicas. Back up the database and content store together. Organization search accounts reference encrypted, write-only organization service credentials. A revoked or invalid selected credential fails closed; it never falls back to the deployment account. Embedding provider credentials are configured separately in the model catalog. ## Current bounds File catalogs paginate at up to 500 rows. Agent directory listings cap at 500 children, file reads at 1 MiB, extraction at 8 MiB, and exact grep at 5 MiB of scanned content, 5,000 candidate files and a 512 KiB per-file ceiling. Streamed originals have a 1 TiB per-file transfer ceiling; this is a safety limit, not a tested capacity claim. Git fetching streams shallow snapshot packs directly into the object store, with the existing 512 MiB pack limit. A synthetic million-file catalog and bounded streamed-original fixture qualify catalog/transfer behavior; these do not establish end-to-end terabyte indexing throughput. Source refresh is explicit. Retained versions currently have no automatic expiry; monitor content storage and keep it with database backups. Additional source adapters and document extractors can use the same collection boundary. Management APIs are under `/v1/knowledge` and `/v1/knowledge-indexers`; the generated command catalog exposes the corresponding `everruns knowledge` commands. Organization settings permissions govern management, and explicit agent/session bindings govern runtime reads. A read-only personal access token can browse, download, validate metadata and search; file changes, source refresh and configuration require a full-access token. ## Deployment storage Knowledge originals and extracted text need shared, persistent content storage on hosted replicas. `KNOWLEDGE_STORAGE_BACKEND=s3` uses the existing `STORAGE_S3_*` configuration for Knowledge alone, even while `STORAGE_BLOB_BACKEND=db` keeps workspace files and image bytes inline in PostgreSQL. It does not backfill or move existing files. The default `inherit` uses the existing shared blob backend or the local development fallback. Do not use the local fallback on ephemeral hosted containers. An invalid explicit S3 configuration fails startup; storage errors never silently switch to local disk. Organization adoption and collection permissions remain separate. --- # Knowledge Base > The undeployed split knowledge features have been consolidated into Knowledge. Source: Use [Knowledge](https://everruns.com/docs/capabilities/knowledge/) for notes, files, source trees and optional indexing. The former `knowledge_base` capability is no longer registered. --- # Knowledge Index > The undeployed split knowledge features have been consolidated into Knowledge. Source: Use [Knowledge](https://everruns.com/docs/capabilities/knowledge/) for notes, files, source trees and optional indexing. The former `knowledge_index` capability is no longer registered. --- # Tool Loop Detection > Detects an agent repeating the same tool calls, results, failed edits, or file reads, and injects a warning that tells it to change approach. Source: | | | | ---------------- | ---------------- | | **ID** | `loop_detection` | | **Tools** | None | | **Features** | None | | **Dependencies** | None | Tool loop detection watches the conversation for an agent that keeps doing the same thing without progress. When it finds a loop, it adds a short system message after the latest input telling the model what it is repeating and what to do instead: change the arguments, look at a different source, or report the blocker. It does not stop the turn, block a call, or change any tool result. The warning is rebuilt from the conversation each time messages are loaded for the model, so it is never stored in session history, and later requests replay the same prompt prefix. Conversation and both Worker levels include it, as do deprecated Generic and Platform Chat. ## What counts as a loop The checks run in this order, and the first match produces the warning: | Pattern | Triggers at | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | | A mutating tool (`edit_file`, `write_file`, `delete_file`, `bash`, or an MCP tool ending in `__` plus one of those names) failing the same way with identical arguments, in consecutive calls | `mutating_failure_threshold`, default 2 | | The same tool call returning the same result, in consecutive calls since the last user message | `threshold`, default 3 | | Repeated reads of the same file (`read_file`, `read_many_files`) at the same offset, mixed with reads of other ranges of that file | `threshold`, default 3 | | The same batch of tool calls with identical arguments in consecutive assistant messages, regardless of call order inside the batch | `threshold`, default 3 | The lower threshold for failed mutations interrupts a broken edit or command before a third identical attempt with side effects. ## Configuration ```json { "ref": "loop_detection", "config": { "threshold": 3, "mutating_failure_threshold": 2 } } ``` | Field | Default | Description | | ---------------------------- | ------- | ----------------------------------------------------------------------------------- | | `threshold` | `3` | Repetitions of the same call batch, call result, or read range that count as a loop | | `mutating_failure_threshold` | `2` | Identical failed results from a mutating tool that count as a loop | Both must be integers of at least 1. In the [Framework](https://everruns.com/docs/framework/advanced-capabilities/), add it by ID: ```rust use everruns::CapabilityRef; use serde_json::json; let agent = Agent::builder() // ... .capability(CapabilityRef::new("loop_detection").config(json!({ "threshold": 4 }))) .build()?; ``` ## See also * [Tool Call Repair](https://everruns.com/docs/capabilities/tool-call-repair/), recovery for malformed tool-call arguments * [Conversation harness](https://everruns.com/docs/built-ins/harnesses/conversation/), the default foundation that includes it --- # Memory > Mount named organization Memories into the session workspace, read-only by default or read-write as shared working memory across sessions. Source: | | | | ---------------- | ------------------------------------------------------------------ | | **ID** | `memory` | | **Category** | Memory | | **Tools** | None | | **Features** | `file_system` | | **Dependencies** | [File System](https://everruns.com/docs/capabilities/file-system/) | | **Risk** | Medium | The `memory` capability mounts organization Memories into a session’s `/workspace`. A Memory is a named, durable file store owned by the organization. Once mounted, the agent reads and writes it with the ordinary [file tools](https://everruns.com/docs/capabilities/file-system/), so the capability adds no tools of its own. Use it for reference material that many sessions share, such as runbooks or product documentation, or for working files that should outlive one session. This capability selects **organization** Memories only. Agent memory (`/memory/agent`) and user memory (`/memory/user`) are mounted by the server without this capability. [Agent and User Memory](https://everruns.com/docs/features/memory-scopes/) explains the three scopes and their privacy rules. ## Configuration ```json { "ref": "memory", "config": { "mounts": [ { "memory": "mem_0193f0c2a1b27c4e8f5d6a7b8c9d0e1f", "path": "/workspace/runbooks", "mode": "readonly" } ] } } ``` | Field | Required | Description | | ----------------- | -------- | --------------------------------------------------------- | | `mounts[].memory` | Yes | Memory ID, `mem_` followed by 32 lowercase hex characters | | `mounts[].path` | Yes | Absolute path under `/workspace` where the Memory appears | | `mounts[].mode` | No | `readonly` (default) or `readwrite` | An empty config, or no `mounts`, is valid and mounts nothing. Validation rejects: * a path outside `/workspace` * two mounts with the same path * overlapping paths, where one mount path is a parent of another (`/workspace/data` and `/workspace/data/inner`) The `/memory/*` namespace is reserved for the server-managed scopes and cannot be used as a mount path here. ## Access modes * `readonly` mounts reject writes with an error from the file tools. * `readwrite` mounts write through to the durable Memory, so later sessions see the change. * Memories synced from GitHub or Git are always read-only, whatever mode the mount asks for. The mount set is captured when the session is created. Archiving or renaming a Memory later does not change what a running session mounted. ## Managing Memories Create Memories and edit their files in the **Memory** page of the UI or through the `/v1/memories` API. The [API reference](https://everruns.com/docs/api/) has the request shapes. ## See also * [Agent and User Memory](https://everruns.com/docs/features/memory-scopes/), the three memory scopes * [Knowledge Base](https://everruns.com/docs/capabilities/knowledge-base/), curated entries the agent searches instead of reading files * [Knowledge Index](https://everruns.com/docs/capabilities/knowledge-index/), semantic search over a synced source * [File System](https://everruns.com/docs/capabilities/file-system/), the tools that read and write mounted files --- # Message Metadata > Annotate user and agent messages with metadata such as their timestamp when they are sent to the LLM, so agents can reason about timing and gaps between messages. Source: | | | | ---------------- | ------------------ | | **ID** | `message_metadata` | | **Category** | Core | | **Features** | None | | **Dependencies** | None | Annotates user and agent messages with metadata, currently each message’s timestamp (UTC), when building the LLM request. The model sees each message prefixed with an annotation like: ```plaintext [time 2026-06-11T09:15:42Z] What changed since yesterday? ``` For user messages the timestamp is when the message was received; for agent messages, when the reply was generated. This lets agents reason about timing: how long ago something was said, gaps between messages, and whether earlier statements are stale. Opt-in on the canonical levels. Included in deprecated Generic and Platform Chat. Annotations are applied only to the prompt-facing view of the conversation. Stored messages are never modified, and timestamps are stable across turns so prompt caching is unaffected. A short system prompt addition explains the annotation format to the model and instructs it not to emit annotations in its replies. ## Tools None. ## Configuration | Field | Type | Default | Description | | -------- | ----- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fields` | array | `["timestamp"]` | Metadata fields to render, in order. Supported: `timestamp`. An empty array disables annotations. More fields (e.g. the LLM model) will be added over time. | User and agent messages are always annotated; system and tool-result messages never are. ## See Also * [Current Time](https://everruns.com/docs/capabilities/current-time/), tool to get the current wall-clock time * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # OpenAI Image Generation > Generate and edit raster images with OpenAI's GPT Image API, persist artifacts, and save outputs into the session workspace. Source: | | | | ---------------- | ---------------------------------------------------------------------------- | | **ID** | `gpt_image_gen` | | **Category** | Media | | **Features** | None | | **Dependencies** | [`session_file_system`](https://everruns.com/docs/capabilities/file-system/) | Generate new raster images and edit existing ones with OpenAI’s ChatGPT Images 2.0 API model, `gpt-image-2`, by default. The capability also supports Meta’s Muse image model (`muse-image-1.0`) through Meta or OpenRouter providers. Capability config supports both model selection and a default quality used when the tool call does not specify one: ```json { "model": "gpt-image-2", "default_quality": "medium", "partial_images": 1, "fallback": "auto" } ``` If you need the previous generation model for compatibility, set `"model": "gpt-image-1"`. To use the Muse image model instead, set `"model": "muse-image-1.0"` and configure a Meta provider (served as `muse-image-1.0`) or an OpenRouter provider (served as `meta/muse-image`). When no OpenAI or Azure OpenAI credentials are configured but a Meta or OpenRouter provider is available, the capability falls back to the Muse image model if `fallback` is `"auto"` (the default). Set `fallback` to `"off"` to require OpenAI or Azure OpenAI credentials for GPT image models instead. The default quality is `medium`. That keeps latency and reliability reasonable for `gpt-image-2` while still producing polished outputs. The default `partial_images` value is `1`. For single-image requests, the capability emits `tool.progress` status updates while waiting for the final image. Set it to `0` to disable progress updates, or up to `3` for more feedback at higher token cost. This capability resolves credentials server-side, persists durable image artifacts, and can also write generated outputs into the session filesystem under `/workspace/.outputs/images/`. ## Credential Resolution The capability never reads provider credentials from session secrets or environment variables. Resolution order: 1. Default OpenAI provider credentials from the control plane 2. Default Azure OpenAI provider credentials from the control plane 3. Default Meta or OpenRouter provider credentials from the control plane (Muse image model) ## Network Policy Image requests leave through the platform’s outbound network boundary, like web fetch and MCP. The provider base URL must be allowed by the session’s network access policy and, when enabled, the system allowlist. Its hostname must resolve to public addresses only, and the connection is pinned to those addresses. Redirects from the image API are treated as errors and never followed, so the provider key is only sent to the configured host. ## Tools ### `generate_image` Generate one or more images from a prompt. | Parameter | Type | Required | Description | | -------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------- | | `prompt` | string | yes | Image generation prompt | | `size` | enum | no | `1024x1024`, `1536x1024`, `1024x1536`, `auto` | | `quality` | enum | no | `low`, `medium`, `high`, `auto`. Defaults to capability `default_quality`, which defaults to `medium` | | `background` | enum | no | `transparent`, `opaque`, `auto` | | `format` | enum | no | `png`, `jpeg`, `webp` | | `count` | integer | no | Number of images to generate (1-10) | | `save_to_session_fs` | boolean | no | Save images into the session filesystem | | `output_dir` | string | no | Filesystem output directory (default `/workspace/.outputs/images`) | | `filename_prefix` | string | no | Prefix for artifact and file names | | `persist_artifact` | boolean | no | Persist into durable image storage (default `true`) | ### `edit_image` Edit one or more existing images using a prompt. | Parameter | Type | Required | Description | | -------------------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------- | | `prompt` | string | yes | Editing prompt | | `image_id` | string | conditional | Durable image artifact ID to use as an edit source | | `path` | string | conditional | Session filesystem path to use as an edit source | | `size` | enum | no | `1024x1024`, `1536x1024`, `1024x1536`, `auto` | | `quality` | enum | no | `low`, `medium`, `high`, `auto`. Defaults to capability `default_quality`, which defaults to `medium` | | `background` | enum | no | `transparent`, `opaque`, `auto` | | `format` | enum | no | `png`, `jpeg`, `webp` | | `count` | integer | no | Number of images to produce (1-10) | | `save_to_session_fs` | boolean | no | Save outputs into the session filesystem | | `output_dir` | string | no | Filesystem output directory (default `/workspace/.outputs/images`) | | `filename_prefix` | string | no | Prefix for artifact and file names | | `persist_artifact` | boolean | no | Persist into durable image storage (default `true`) | At least one of `image_id` or `path` is required. When both are present, both source images are sent to the edit request. ## Result Shape Both tools return: * Native image blocks for direct model consumption * Structured JSON with: * `artifact_id` when durable storage is enabled * `session_file` when workspace save is enabled * `media_type`, `filename`, `size_bytes` * `revised_prompt` when OpenAI returns one ## Notes * Transparent background requires `png` or `webp` output * High quality can take substantially longer than medium or low on `gpt-image-2` * Single-image requests emit progress updates by default; multi-image batches still wait for the final response * Each additional streamed update adds extra image output tokens on the OpenAI side, so higher `partial_images` values trade cost for better perceived latency * `generate_image` and `edit_image` stay fully exposed even when OpenAI `tool_search` is enabled, so large tool lists do not defer their schemas * Session file edits must be `png`, `jpg`, `jpeg`, or `webp` * Edit sources larger than 50 MB are rejected before the API call * Saved workspace files are written as base64-encoded binary files ## See Also * [File System](https://everruns.com/docs/capabilities/file-system/), read and reuse workspace images * [Storage](https://everruns.com/docs/capabilities/session-storage/), store per-session OpenAI overrides * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # OpenAI Server Tools > Enable OpenAI's hosted tools (web search, code interpreter, hosted shell, file search, remote MCP) for agents on the OpenAI or Azure OpenAI Responses API. Source: | | | | ---------------- | ------------------------------------------------------------ | | **ID** | `openai_server_tools` | | **Category** | Tools | | **Features** | None | | **Dependencies** | None | | **Risk** | High (grants provider-executed web reach and code execution) | Enables [OpenAI’s hosted tools](https://platform.openai.com/docs/guides/tools) on agents whose model runs on the [OpenAI](https://everruns.com/docs/providers/openai/) or Azure OpenAI provider. OpenAI runs a hosted tool inside the same response: the model decides to search, OpenAI performs the search, and the answer comes back grounded in the results with its sources cited. The agent loop never dispatches the call, so there is no extra round-trip through Everruns. | Tool | What OpenAI runs | | ------------------ | ---------------------------------------------------- | | `web_search` | Searches the web and cites the pages it used | | `code_interpreter` | Python in an OpenAI-managed container | | `shell` | Shell commands in an OpenAI-managed container | | `file_search` | Retrieval over your OpenAI vector stores | | `mcp` | Calls to remote MCP servers you list, after approval | ## Tools None. This capability configures the OpenAI request, it does not provide client-side tools. Hosted calls appear in the session’s activity (see [Activity and cost](#activity-and-cost)); their results stay inside OpenAI’s response and reach the conversation only through the answer. Code interpreter and shell run in OpenAI’s container, not in the session’s Everruns sandbox: files they create are not in the session file system. Use Everruns’ own execution capabilities when the agent’s work must land there. ## Configuration ### Enable web search ```json { "capabilities": [ { "ref": "openai_server_tools", "config": { "tools": ["web_search"] } } ] } ``` ### Tune web search ```json { "capabilities": [ { "ref": "openai_server_tools", "config": { "tools": ["web_search"], "web_search_context_size": "high", "web_search_allowed_domains": ["openai.com", "everruns.com"], "web_search_user_location": { "country": "US", "city": "Chicago", "timezone": "America/Chicago" } } } ] } ``` ### Code, shell, and file search ```json { "capabilities": [ { "ref": "openai_server_tools", "config": { "tools": ["code_interpreter", "shell", "file_search"], "container_memory_limit": "4g", "file_search_vector_store_ids": ["vs_abc123"], "file_search_max_results": 8 } } ] } ``` ### Remote MCP ```json { "capabilities": [ { "ref": "openai_server_tools", "config": { "tools": ["mcp"], "mcp_servers": [ { "server_label": "deepwiki", "server_url": "https://mcp.deepwiki.com/mcp" }, { "server_label": "docs", "server_url": "https://docs.example.com/mcp", "allowed_tools": ["search"], "require_approval": "never" } ] } } ] } ``` OpenAI connects to each server and asks before every call. The turn pauses with an approval card in the chat that shows the server, the tool, and the exact arguments; **Approve** runs the call and **Deny** lets the model answer without it. API clients see the request as a `tool.call_requested` event with an `openai_mcp_approval` call and answer it through `POST /v1/sessions/{id}/tool-results` with `{"approve": true}` or `{"approve": false}`. Any other result, an error included, denies. A server can skip approval with `"require_approval": "never"`, but only for an explicit `allowed_tools` list, so every unattended call is a tool you named. A `server_url` must be `https` and must not carry a username or password, so it suits public servers. A server that needs an API key or an OAuth connection is named by `mcp_server`, the name of an MCP server registered in Everruns, instead of a URL: ```json { "server_label": "linear", "mcp_server": "linear" } ``` Its URL and credentials come from the MCP server registration and the session’s connections on every call, exactly as for the agent’s own MCP tools, and never appear in agent config, events, or logs. If the connection is missing, the turn fails with a message naming where to connect it. Servers that bind secrets to tool parameters cannot be used this way, because OpenAI calls them directly. Config rules: * `tools`, array of hosted tool names: `web_search`, `code_interpreter`, `shell`, `file_search`, `mcp`. Other names are rejected on write. * `web_search_context_size`, `low`, `medium`, or `high`: how much retrieved context the model may use per search. OpenAI defaults to `medium`. * `web_search_allowed_domains`, bare domains (no scheme or path) that limit where results may come from. * `web_search_user_location`, optional `country` (two-letter ISO code), `region`, `city`, and `timezone` (IANA name) used to localize results. * `container_memory_limit`, `1g`, `4g`, `16g`, or `64g`: memory for the container that runs `code_interpreter` and `shell`. OpenAI defaults to `1g`; larger containers cost more. * `file_search_vector_store_ids`, OpenAI vector store ids (`vs_...`) in the same OpenAI account as the provider’s API key. Required when `file_search` is on. * `file_search_max_results`, 1 to 50 results per search. * `mcp_servers`, at least one server when `mcp` is on. Each has a unique `server_label` (letters, digits, `-`, `_`), either an `https` `server_url` or a registered `mcp_server` name, optional `allowed_tools`, and `require_approval` (`always`, the default, or `never`). Each option only takes effect when its tool is in `tools`. ## Provider support Hosted tools run only on the OpenAI and Azure OpenAI Responses API. On any other provider, including OpenAI-compatible gateways, the turn fails with a message that names the provider, instead of answering without the tools. Switch the agent’s model or remove the capability. For OpenRouter models, use [OpenRouter Server Tools](https://everruns.com/docs/capabilities/openrouter-server-tools/). Each model decides which hosted tools it supports; OpenAI rejects a request that asks a model for a tool it does not offer, and that error is shown on the turn. ## Security Hosted tools send conversation content to OpenAI-side tools. Web search gives the model **provider-executed web reach**, code interpreter and shell give it **code execution in an OpenAI container**, and file search reads whatever the listed vector stores hold. Remote MCP sends the model’s tool arguments to the servers you list, which are third parties to both OpenAI and Everruns; approval shows each call before it happens. OpenAI performs the requests, so Everruns’ own egress controls do not apply, the same data-exfiltration class as client-side [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/). The capability is rated **High risk** and uses the admin-only assignment gate. Grant it only to agents you trust with outbound web access and code execution, list only vector stores whose contents every user of the agent may see, and list only MCP servers you trust with the conversation. ## Activity and cost Each hosted call shows up in the session’s activity as it happens, through the `tool.hosted_call` event, with a short detail: the search query, the first line of code, the shell commands, the file search query, or the MCP server and tool. It is not an Everruns tool call: nothing is dispatched and no tool result is stored. OpenAI bills hosted tool calls per call on top of tokens. Session usage adds them to the estimated cost at OpenAI’s list price: $10 per 1,000 web searches on GPT-5 and newer reasoning models, $25 per 1,000 on GPT-4o and GPT-4.1, and $2.50 per 1,000 file searches. Code interpreter and shell are billed by OpenAI per container session rather than per call, so they are not in the estimate; check OpenAI’s usage dashboard for them. File search also bills vector store storage. ## See Also * [OpenAI provider](https://everruns.com/docs/providers/openai/) * [OpenRouter Server Tools](https://everruns.com/docs/capabilities/openrouter-server-tools/), the OpenRouter counterpart * [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/), the client-executed equivalent * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # OpenRouter Server Tools > Enable OpenRouter's server tools (web search, web fetch, datetime, image generation and more), which OpenRouter runs before it returns the final answer. Source: | | | | ---------------- | ----------------------------------------- | | **ID** | `openrouter_server_tools` | | **Category** | Tools | | **Features** | None | | **Dependencies** | None | | **Risk** | High (grants provider-executed web reach) | Enables [OpenRouter’s provider-executed “server tools”](https://openrouter.ai/docs/guides/features/server-tools) (beta). Unlike normal [function tools](https://everruns.com/docs/features/capabilities/), these run **server-side by OpenRouter**: it loops internally and returns the final answer, so the agent loop never dispatches them. This capability contributes *request intent*, not executable tools, the selected tools are compiled into the OpenRouter request’s `tools` array as provider-executed entries. The concrete implementation lives in the focused `openrouter` feature of `everruns-integrations` crate; core carries only the provider-neutral routing contract. This is the OpenRouter counterpart to client-executed web access like [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/): the difference is *who runs the tool*. With server tools, OpenRouter performs the search or fetch and folds the results into the same generation, no extra round-trip through Everruns. Use it when your agents run on the [OpenRouter provider](https://everruns.com/docs/providers/openrouter/) and you want built-in web reach without wiring up a separate search [integration](https://everruns.com/docs/integrations/). ## Tools None, this capability configures the OpenRouter request, it does not provide client-side tools. The model invokes server tools during the generation and OpenRouter executes them; the only client-visible artifact is the final answer. ## Available server tools OpenRouter exposes these server tools. Enable any subset: | Tool | Name | What it does | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------ | | Web Search | `web_search` | Searches the web and grounds the answer in results. Accepts an optional `max_results` cap. | | Web Fetch | `web_fetch` | Fetches and reads a URL the model chooses. | | Date & Time | `datetime` | Gives the model the current date and time. | | Image Generation | `image_generation` | Generates images inline. | | Apply Patch | `apply_patch` | Applies code patches. | | Fusion | `fusion` | OpenRouter’s Fusion tool. | | Advisor | `advisor` | OpenRouter’s Advisor tool. | | Subagent | `subagent` | Delegates to an OpenRouter-run subagent. | `web_search` is the only server tool that takes parameters today (`web_search_max_results`). Availability of each tool depends on the upstream model and OpenRouter’s beta rollout, see [OpenRouter’s server-tools docs](https://openrouter.ai/docs/guides/features/server-tools) for the current list. ## How it works 1. **Capability config → request intent**: the tools you enable are compiled into the OpenRouter routing config and serialized by the OpenRouter driver into the request’s `tools` array as `{"type":"openrouter:…"}` entries. 2. **OpenRouter executes server-side**: when the model decides to call a server tool, OpenRouter runs it, loops internally, and returns the final answer. The agent loop never sees an intermediate tool call. 3. **No-op off OpenRouter**: non-OpenRouter providers ignore the routing config entirely. Enabling this capability on a non-OpenRouter agent is a harmless no-op, so it is safe to leave on for agents that may switch providers. ## Configuration ### Enable web search ```json { "capabilities": [ { "ref": "openrouter_server_tools", "config": { "tools": ["web_search"] } } ] } ``` ### Enable several tools and cap web-search results ```json { "capabilities": [ { "ref": "openrouter_server_tools", "config": { "tools": ["web_search", "web_fetch", "datetime"], "web_search_max_results": 5 } } ] } ``` Config rules: * `tools`, array of server-tool names from the table above. Unknown names are rejected on write. Duplicates are de-duplicated. * `web_search_max_results`, positive integer; only decorates `web_search`. It is ignored for every other tool and rejected when `< 1`. ## Security Enabling server tools grants the model **provider-executed web reach** (`web_search` / `web_fetch`). OpenRouter performs these requests, so Everruns’ own egress controls do not apply, the same data-exfiltration class as client-side [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/). The capability is therefore rated **High risk** and gated behind the same admin-only trust check as other outbound-web capabilities. Grant it only to agents you trust with outbound web access. ## Limitations * **OpenRouter only**: this is an OpenRouter request extension. Other providers ignore it (no error, no behavior change). * **Beta**: server tools are an OpenRouter beta; tool availability varies by upstream model and may change. * **Provider-side execution**: because OpenRouter runs the tools, their activity does not appear as Everruns tool calls. Inspect them in OpenRouter’s [dashboard logs](https://everruns.com/docs/providers/openrouter/#logs-traces-and-observability) instead. ## See Also * [OpenRouter provider](https://everruns.com/docs/providers/openrouter/), configure the provider these tools run on, plus OAuth, actual-cost reporting, and logs * [OpenRouter server-tools docs](https://openrouter.ai/docs/guides/features/server-tools), official OpenRouter guide * [Web Fetch](https://everruns.com/docs/capabilities/web-fetch/), the client-executed equivalent * [Integrations overview](https://everruns.com/docs/integrations/), search and web integrations as an alternative * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Output Truncation > Chooses what a turn does when a model response hits the output token limit in the middle of a tool call, retry with a notice, fail, or carry on. Source: | | | | ---------------- | ------------------- | | **ID** | `output_truncation` | | **Category** | Safety | | **Features** | None | | **Dependencies** | None | | **Risk** | Low | A model response that reaches its output token limit (finish reason `length`) can stop in the middle of a tool call. Everruns never runs such a call, and never runs it with empty (`{}`) arguments in place of the ones the model did not finish. This capability chooses what the turn does next. On OpenAI Responses and Bedrock it also applies when a finished call arrives with arguments that are not valid JSON. Every agent gets the default policy, `continue`, without adding the capability. Add it only to change the policy or the retry limit. ## Tools None, this capability only configures the turn loop. ## How It Works When a response loses tool calls this way: * Calls in the same response whose arguments arrived complete still run. * The cut-off calls do not run. Every provider drops them: Anthropic, OpenAI (Chat Completions and Responses), Gemini, and Bedrock. * The policy decides the turn’s next step: | Policy | What happens | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `continue` (default) | The model gets a short notice that its output hit the limit and the call was not run, and the turn runs another model call so it can retry with less output. After `max_retries` cut-off responses in a row, the turn fails with an error. | | `fail` | The turn ends with an error. | | `off` | The turn carries on as if the model had not asked for the cut-off calls: it ends on the partial answer, with stop reason `max_tokens`. | The `continue` notice appears in the conversation the model sees, right after the cut-off response and any results of the calls that did run. It is not stored as a message and is not shown in the chat. A clean model response, or a new user message, resets the count of consecutive cut-off responses. Responses that are refused or filtered (`content_filter`, `refusal`) are not retried: retrying does not fix them. ## Config ```json { "capabilities": [ { "ref": "output_truncation", "config": { "policy": "continue", "max_retries": 2 } } ] } ``` | Field | Type | Default | Description | | ------------- | ----------------------------- | ---------- | ------------------------------------------------------------------- | | `policy` | `continue` \| `fail` \| `off` | `continue` | What the turn does when a response loses tool calls | | `max_retries` | integer, 0 to 10 | `2` | Cut-off responses in a row `continue` retries before the turn fails | When the capability is set on both the harness and the agent, the agent’s config wins. ## Observability Each `llm.generation` event records how the response ended: * `finish_reasons`; * `tool_calls_dropped`; * `truncation_gate`, set to `retried` or `failed` when the policy acted. The same value is exported as the `everruns.llm.truncation_gate` span attribute and counted in the `everruns_llm_truncation_gate_total` metric. See the [event reference](https://everruns.com/docs/event-reference/#llmgeneration). ## Related * [Tool Call Repair](https://everruns.com/docs/capabilities/tool-call-repair/), recovery for tool-call arguments that are almost valid JSON * [Tool Loop Detection](https://everruns.com/docs/capabilities/loop-detection/) --- # Parallel Tool Calls > Controls whether the agent requests multiple tool calls per turn and runs them concurrently, prefer parallel, avoid (serialize), or leave the provider default. Source: | | | | ---------------- | --------------------- | | **ID** | `parallel_tool_calls` | | **Category** | Optimization | | **Features** | None | | **Dependencies** | None | | **Risk** | Low | Controls the agent’s request-level preference for parallel (multiple per turn) tool calls, and whether the local tool scheduler runs a batch concurrently. Most providers emit several tool calls in a single turn by default, and Everruns runs independent tool calls concurrently. This capability makes that behavior explicit and configurable: turn it up to actively request batching of independent reads and searches, or turn it down to force strictly one tool call at a time. ## Tools None, this capability only configures the outbound LLM request and the local tool scheduler. ## How It Works The capability resolves a `mode` into a request-level preference that threads through two places: 1. **The LLM request.** On providers that expose a wire control, the preference is sent on the request: * **OpenAI** (Chat Completions and Responses), and the OpenAI-compatible **MAI** and **Fireworks** providers, the top-level `parallel_tool_calls` boolean. * **OpenRouter**: forwarded on the Responses body; ignored by routed providers that do not support it. * **Anthropic**: `tool_choice.disable_parallel_tool_use` (sent only when the request carries tools). * **Gemini** and **Bedrock** have no equivalent request control, so nothing is sent. The local scheduler (below) still honors the preference. 2. **The local tool scheduler.** `avoid` forces the scheduler to run the turn’s tool calls strictly sequentially. This applies to **every** provider, so `avoid` is honored even where there is no wire control. Whether the preference is sent on the wire is gated per provider/model: a driver that cannot express it omits the field rather than risking an API error. ## Config ```json { "capabilities": [ { "ref": "parallel_tool_calls", "config": { "mode": "prefer" } } ] } ``` ### Modes | Mode | Provider request | Local scheduler | | ------------------ | ---------------------------------------------- | ------------------------------------- | | `prefer` (default) | Request parallel tool calls where supported | Concurrent (class-aware, the default) | | `avoid` | Ask for one tool call per turn where supported | Serialized | | `none` | Omit, provider default | Concurrent (class-aware, the default) | When the capability is enabled without an explicit `mode`, the default is `prefer`. `none` is equivalent to not enabling the capability; it is useful to neutralize a preference inherited from a parent harness. **Base** and every harness built on it, plus the deprecated **Generic** and **Worker Base**, enable this capability with `mode: "prefer"` by default. ## Precedence An explicit `parallel_tool_calls` field set directly on a harness, agent, or session is a lower-level escape hatch and takes precedence over this capability. ## When To Use * **`prefer`**: workloads that issue many independent reads or searches per turn benefit from batching (faster turns, fewer round-trips). * **`avoid`**: when tool calls must be observed and applied one at a time, or when a model produces lower-quality parallel batches for your workload. ## Limitations * **Provider gating.** `prefer` only changes the wire request on providers with a control for it (OpenAI/Anthropic families). Elsewhere providers already parallelize by default, so `prefer` is a no-op on the wire. * **Durable mode.** A harness/agent-level `mode` other than the default (`prefer`) is applied with full fidelity in the in-process runtime; in durable worker mode, harness/agent capability config falls back to the default, set the mode at the session level, or use the explicit `parallel_tool_calls` field, to override durably. (This matches other config-bearing capabilities.) ## See Also * [Capabilities](https://everruns.com/docs/features/capabilities/), the extension model this capability plugs into * [Agentic Loop](https://everruns.com/docs/explanation/agentic-loop/), how the runtime schedules a batch of tool calls --- # Platform > Discover, inspect, and manage Everruns resources through the command catalog. Source: | | | | ---------------- | ------------------------------------------------------------------------------------------------ | | **ID** | `platform` | | **Category** | Platform | | **Risk** | High | | **Tools** | `discover`, `query`, `execute` by default; `everruns` in the session shell with `surface: shell` | | **Dependencies** | `skills`; `session_file_system` when embedded docs are enabled | | **Mounts** | `/workspace/docs`, the Everruns documentation, read-only, when embedded docs are enabled | The Platform capability gives an agent the same catalog-backed command surface as Everruns’ `/mcp` endpoint. Operations come from the server’s registered command inventory, so models can discover current names and schemas instead of guessing them or relying on a separate handwritten API. Platform Chat includes this capability by default. Other agents and harnesses must be assigned it explicitly. Because `execute` can mutate platform resources, the capability is high-risk and follows the normal admin-only assignment rule. ## Interfaces and built-in skills Platform Chat uses `{"ref":"platform","config":{"surface":"shell"}}`. This exposes the same operations through `everruns ` in its shell, with progressive `--help`, JSON output, pipes, and workspace redirection. It hides the three tools described below. Omitting `surface` retains those tools. Both interfaces use the same command authorization and documentation mounts. Workspace builds also ship three read-only skills with this capability: | Skill | Purpose | | -------------------------- | ------------------------------------------------------------------------------------------------ | | `everruns` | Product concepts, Cloud and self-hosted entry points, and documentation links | | `everruns-cli` | Command usage, scripting examples, and differences between installed CLI, session shell, and MCP | | `everruns-agent-authoring` | Agent design, configuration, dependencies, and behavioral verification | The capability enables [Agent Skills](https://everruns.com/docs/capabilities/agent-skills/) for discovery and activation. Use `list_skills` and `activate_skill`; full instructions load on demand from `/workspace/.agents/skills//SKILL.md`. Follow the current session interface when a skill shows an external MCP example. Adding skills grants no additional command permissions. Like embedded docs, these product files are included from the repository at build time; standalone crate builds without the repository skills tree omit them. The external [MCP endpoint](https://everruns.com/docs/features/mcp/#skills-for-mcp-clients) serves these three skills plus `everruns-mcp`. Rust development guidance is maintained separately in the installable `everruns-framework` skill. ## Tools ### `discover` Search for operations by name, category, description, or schema terms. Results include command metadata, read-only decision, and output-shape hints. Searches with multiple matches omit schemas and return a refinement hint to keep the result compact. A query that exactly matches a command name returns only that command with its schemas and `bash_usage`, a copyable invocation with the exact supported flags. It also includes bounded `output_fields` paths for building `jq` filters without guessing field names. If expanded schemas would make the result too large, the response omits them with a notice while retaining the authoritative scripting summaries. Use `all: true` only when you truly need to list the entire scriptable catalog, not for a task-specific lookup. ```json { "query": "models" } ``` Once you find a command, discover its exact name before invoking it: ```json { "query": "create_agent" } ``` For commands with a `cli` spelling, use command-tree `--help` as directed by discovery. Flat-only builtins have no `--help`; use their `bash_usage` and returned schema. Pass array and object values as JSON text, for example `--capabilities '[{"ref":"mcp:..."}]'`. Unknown flags are rejected before a command runs. This prevents misspelled security-sensitive options, such as an authentication flag, from being silently ignored during a mutation. ### `query` Run a bounded Bashkit script with only read-only Everruns commands available as builtins. It supports pipes, variables, loops, conditionals, and `jq`. ```json { "commands": "list_models | jq '.data[] | {id, model_id, display_name}'" } ``` Commands with mutations or open-world side effects are not available in `query`. Use it to inspect current state and validate changes. ### `execute` Run a bounded Bashkit script with the full scriptable command catalog. Use it for requested create, update, delete, and other mutating operations. ```json { "commands": "create_agent --name 'support-agent' --system_prompt 'Help users.' --default_model_id 'model_...'" } ``` `execute` is not transactional. If a later command in a script fails, earlier commands may already have succeeded. Inspect the resulting state with `query` before retrying. MCP server command results include both their public resource `id` and a derived `capability_ref` in the `mcp:` form accepted by Agent capability configuration. Capture JSON results and use `jq` to pass dependent IDs or capability references to later commands in the same script. No separate MCP attachment operation is needed. ## Scope and authorization Platform tools are always bound to the current session’s organization. Their schemas do not accept `organization_id`, and an injected override is rejected. The server resolves the session’s human owner for every distributed call and applies that caller’s normal command permissions. Attaching this capability does not grant authority the owner does not already have. ## Autonomous workflows For recurring autonomous work, create an Agent and an Agent Trigger. Do not use a schedule on the Platform Chat session: that would wake the management chat, not provision an independently owned worker workflow. Credentials are not transferred from Platform Chat session secrets into a new Agent. Configure integrations through their supported Agent-scoped credential or connection flow; do not paste credentials into command scripts. ## Platform documentation When the build embeds the product documentation, this capability mounts it at `/workspace/docs` as a read-only virtual filesystem, served from memory with no database writes per session. Agents browse it with the standard file tools (`read_file`, `list_directory`, `grep`) or with `cat`, `ls`, and `grep` through Bashkit Shell. Key sections: * `/workspace/docs/getting-started/`, introduction, concepts, architecture * `/workspace/docs/features/`, SDK, CLI, UI, events, harnesses, capabilities * `/workspace/docs/capabilities/`, per-capability reference * `/workspace/docs/integrations/`, external integrations (Slack, Daytona, etc.) * `/workspace/docs/advanced/`, budgets, compaction, embedding, network access * `/workspace/docs/sre/`, environment variables, runbooks ## See also * [Platform Chat harness](https://everruns.com/docs/built-ins/harnesses/platform-chat/) * [MCP](https://everruns.com/docs/features/mcp/) * [Agent Triggers](https://everruns.com/docs/features/agent-triggers/) * [Platform Management](https://everruns.com/docs/capabilities/platform-management/), the removed predecessor --- # Platform Management (removed) > Removed capability. Its management tools are superseded by the catalog-backed Platform capability. Source: > **This capability has been removed.** Use the [Platform capability](https://everruns.com/docs/capabilities/platform/) instead. Agents and harnesses that still reference `platform_management` keep running, but the capability contributes no tools and no system prompt. | | | | --------------- | -------------------------------------------------------------- | | **ID** | `platform_management` | | **Category** | Platform | | **Status** | Retired | | **Tools** | None | | **Replacement** | [`platform`](https://everruns.com/docs/capabilities/platform/) | ## Why it was removed Its tools were hand-written alongside the API rather than derived from it, so they covered only harnesses, agents, apps, and sessions, and their schemas drifted as the platform grew. The `platform` capability exposes the same surface through `discover`, `query`, and `execute` over the server’s registered command catalog, which is the same inventory behind Everruns MCP, so it cannot drift. ## What to do Replace the capability on any agent or harness that still lists it: 1. Open the agent or harness. A removed capability is flagged in its capability list. 2. Remove `platform_management` and add `platform`. Both are high-risk, so an admin performs the change. 3. Prompts that named the old tools should name the new flow instead: find the command with `discover`, read state with `query`, mutate with `execute`. ## Tool mapping | Removed tool | Replacement | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------- | | `read_capabilities` | `list_capabilities` / `get_capability` | | `read_harnesses` | `list_harnesses` / `get_harness` | | `manage_harnesses` | `create_harness`, `update_harness`, `delete_harness`, `copy_harness` | | `read_agents` | `list_agents` / `get_agent` | | `manage_agents` | `create_agent`, `update_agent`, `delete_agent` | | `read_apps` | `list_apps` / `get_app` (read-only archive); `list_agent_channels` / `get_agent_channel` for live endpoints | | `manage_apps` | No equivalent. Apps are retired; endpoints belong to an agent. | | `manage_app_channels` | `create_agent_channel`, `update_agent_channel`, `delete_agent_channel`, `publish_agent_channel`, `unpublish_agent_channel` | | `read_sessions` | `list_sessions` / `get_session` | | `manage_sessions` | `create_session`, `delete_session` | | `session_send_message` | `create_message` | | `session_read_messages` | `list_messages` | | `session_context_report` | `get_session_context_report` | | `session_read_response` | No equivalent. It blocked until the turn finished; poll `list_messages` instead. | Run `discover` for the exact current schema of any command in that table rather than assuming the flags. ## Platform documentation The embedded documentation mount at `/workspace/docs` moved to the [Platform capability](https://everruns.com/docs/capabilities/platform/) unchanged. ## See also * [Platform](https://everruns.com/docs/capabilities/platform/), the replacement * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Poppy Personal Agent > Let an agent talk to companies' agents for the person it works for, over the Personal Agent Protocol (Poppy). Source: | | | | ---------------- | -------------- | | **ID** | `poppy_client` | | **Category** | Integrations | | **Features** | None | | **Dependencies** | None | | **Risk** | Medium | The [Personal Agent Protocol](https://personalagentprotocol.org) (“Poppy”, draft 0.1) lets a person’s own agent do business with a company: find it, start a conversation with its agent, and hand off to a person there. With this capability an Everruns agent is that personal agent. Any company that publishes `/.well-known/poppy.json` on its domain works, with nothing to register. This page covers the personal side. To make an Everruns agent the company that personal agents talk to, and for how both ends are tested, see [Personal Agent Protocol (Poppy)](https://everruns.com/docs/features/poppy/). ## When to enable * A personal assistant such as Platform Chat, where people ask the agent to check on an order, a booking or a support case with a company. Leave it off for agents that should not contact outside companies. ## Configuration None. ```json { "ref": "poppy_client", "config": {} } ``` ## Tools | Tool | What it does | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `poppy_discover` | Looks up a company by domain and says what it offers | | `poppy_send` | Sends a message to the company’s agent and waits briefly for the reply. The first message starts the conversation; `new_conversation` starts another | | `poppy_read` | Reads replies that arrived since the last answer | | `poppy_handoff` | Asks the company for a person | | `poppy_close` | Ends the conversation | ## Identity and privacy Every company sees the deployment as one personal agent named “Everruns”. Its client metadata is published at `/v1/poppy/agent.json` and its public key at `/v1/poppy/jwks.json`, under the API base URL. Each person gets a different random User ID at each company, so two companies cannot tell they talk to the same person. Nothing else about the person, the organization or the conversation is sent, beyond the messages themselves. Keys and Session Tokens stay on the server, encrypted at rest. The agent’s tools only see what the company answered. Requests go through the organization’s egress allowlist. ## In the Framework A Framework app is its own personal agent. Turn on the `poppy` feature, give the agent `PoppyPersonalAgent`, and serve its two documents at the HTTPS address you named: ```rust use everruns::poppy::{PoppyKey, PoppyPersonalAgent}; let poppy = PoppyPersonalAgent::new("https://agent.example.com", PoppyKey::generate()?); let metadata = poppy.metadata("My assistant"); // serve at /v1/poppy/agent.json let jwks = poppy.jwks(); // serve at /v1/poppy/jwks.json let agent = Agent::builder() .name("personal-agent") .model(model) .capability(poppy) .build()?; ``` The tools are the same. The app keeps the person’s User IDs, keys and Session Tokens in memory, so a restart is a new person to every company. See [the example](https://github.com/everruns/everruns/tree/main/examples/poppy-personal-agent). ## Limits * Sessions are signed out: the person does not sign in to the company yet, so a company that needs an account says so, and the agent tells the person. * Company APIs and operations are not used; only the conversation. --- # Prompt Caching > Turns on provider prompt caching for Anthropic, OpenAI, Gemini, Bedrock, OpenRouter, and Mistral requests, and records the cache mode on each llm.generation event. Source: | | | | ---------------- | ---------------- | | **ID** | `prompt_caching` | | **Category** | Optimization | | **Tools** | None | | **Features** | None | | **Dependencies** | None | Prompt caching lets a provider reuse the unchanged start of a request (system prompt, tool definitions, earlier conversation) instead of processing it again on every model call. Cached input is usually cheaper and faster. This capability sets the request options each driver needs. It adds no tools and no prompt text. Drivers that support caching translate the setting into their provider’s request fields. A driver or model without support ignores it, and the request proceeds unchanged. The [Platform Chat](https://everruns.com/docs/built-ins/harnesses/platform-chat/) harness includes it. ## What each provider gets | Provider | With `strategy: auto` (default) | With `strategy: explicit` | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Anthropic | `cache_control` breakpoints on the system prompt, the last tool definition, and the two most recent stable conversation messages, four in total | Breakpoints on the system prompt and the last tool definition only, so the conversation is never written to cache | | OpenAI | A `prompt_cache_key` derived from the session (or agent, harness, or organization), model, instructions, and tools. On models whose profile supports cache options, also `prompt_cache_options` with mode `implicit` and a 30 minute TTL | `prompt_cache_key`, and on supporting models `prompt_cache_options` with mode `explicit`: the instructions move into a developer message marked as the cache breakpoint, so only that prefix is written to cache | | Gemini | The provider’s default behavior, such as implicit caching on supported models | Same as `auto` | | Bedrock (Claude, Nova) | `cachePoint` blocks after the system prompt, after the tool definitions (Claude only; Nova does not cache tools), and on the two most recent messages | `cachePoint` blocks after the system prompt and tools only | | OpenRouter, Claude models | A top-level `cache_control`, which turns on Anthropic’s automatic caching through OpenRouter. Other OpenRouter models keep their vendor’s implicit caching | Nothing extra: automatic caching cannot exclude the conversation | | Mistral | A `prompt_cache_key` derived from the session (or agent, harness, or organization) and model, so requests sharing a prefix reach the same cache | Same as `auto` | On Gemini, setting `gemini_cached_content` sends that existing cached content resource in the request’s `cachedContent` field. On OpenAI with the explicit mode, the driver replays the full transcript instead of chaining with `previous_response_id`, so the developer prefix is not appended again on each continuation. Use `explicit` when many short, unrelated sessions share long instructions or tools, such as a support agent: caching every conversation would cost more in cache writes than it saves in reads. ## Tool changes during a session Tool definitions sit at the front of the cached prompt, so a tool list that changes mid-session (a tool revealed by [Tool Search](https://everruns.com/docs/capabilities/tool-search/), for example) used to throw the whole cache away. Sessions now record their tool list on the first model call and each later change in the conversation. On Claude Opus 5.5, Opus 5, Opus 4.8, Sonnet 5.5, Haiku 5.5 and Fable 5.1 through the Claude API, and on GPT-6 Astra, Sol, Luna and 6.1 Sol and GPT-5.6 Sol, Terra and Luna through the OpenAI API, the request keeps the first tool list and sends each change in the conversation, so the cache survives it. GPT-5.5 and GPT-5.4 keep the cache when tools are added; a revealed tool there still costs one cache write. Instructions a capability adds when it is switched on mid-session travel the same way on those models: the request keeps the first system prompt and sends the new instructions in the conversation. Other models and endpoints receive the current tool list, which costs one cache write per change. A tool that goes away there (a capability switched off, for example) stays in the list while the cache is warm and nothing else changes, and a call to it is refused; it leaves with the next change, or once the session has been idle longer than the cache retention. ## Retention `retention` sets how long the provider keeps a cached prefix after its last use. Each driver rounds it to the nearest value its provider supports. | Provider | `default`, `5m` | `30m` | `1h` | | ------------------------- | ---------------- | ---------------- | ---------------------------------------- | | Anthropic | 5 minutes | 5 minutes | 1 hour (`ttl: "1h"` on every breakpoint) | | Bedrock, Claude models | 5 minutes | 5 minutes | 1 hour (`ttl` on every cache point) | | OpenRouter, Claude models | 5 minutes | 5 minutes | 1 hour (`ttl: "1h"` on `cache_control`) | | OpenAI with cache options | 30 minutes | 30 minutes | 30 minutes | | Others | Provider default | Provider default | Provider default | A longer retention costs more per write: Anthropic bills a 1 hour cache write at 2x the input rate instead of 1.25x, and cost estimates include that. Choose `1h` for agents whose turns are often more than five minutes apart, such as agents that wait on a person or run on a schedule, where a 5 minute cache would have expired before the next turn. ## Configuration ```json { "ref": "prompt_caching", "config": { "strategy": "auto", "retention": "1h" } } ``` | Field | Default | Description | | ----------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `strategy` | `auto` | `auto` lets each driver pick its provider behavior. `explicit` caches only the stable prefix (instructions, and tools on Anthropic) on providers that support it. | | `retention` | `default` | `default`, `5m`, `30m`, or `1h`. Rounded to what the provider supports. | | `gemini_cached_content` | none | An existing Gemini cached content resource name, `cachedContents/{id}` | ## Observability Each `llm.generation` event records the request in `request_options.prompt_cache`: whether caching was enabled, the strategy, and a `provider_mode` naming what the driver did, and the `retention` it requested after rounding. The modes are `cache_control` (Anthropic), `implicit`, `explicit`, or `prompt_cache_key` (OpenAI), and `implicit` or `cached_content` (Gemini). Cache read and write token counts, when the provider reports them, appear in the event’s token usage. In a session’s Trace view, each model call shows its prompt split into cache read, cache write and uncached tokens. When a call reuses less than half of what the previous call left cached, the trace marks a cache reset and names the likely cause: the model, the tool definitions, the system prompt or earlier messages changed, or the session sat idle longer than the cache retention. A long prompt sent with caching off is marked as one that caching would help. A call that changed the tool list lists the tools added, updated or removed. ## See also * [Platform Chat harness](https://everruns.com/docs/built-ins/harnesses/platform-chat/) * [OpenTelemetry](https://everruns.com/docs/observability/opentelemetry/), which exports prompt-cache token counts per call * [Tool Search](https://everruns.com/docs/capabilities/tool-search/), another request-level optimization --- # Prompt Canary Guardrail > Streaming output guardrail that withholds the assistant message when the model echoes the first sentence of its system prompt back to the user. Source: | | | | ---------------- | ------------------------- | | **ID** | `prompt_canary_guardrail` | | **Category** | Safety | | **Features** | None | | **Dependencies** | None | | **Risk** | Low | Detects naive system-prompt leakage during streaming. At the start of each assistant message, the capability extracts the first qualifying sentence of the assembled system prompt and uses it as a canary needle. If the model’s accumulated output ever contains that needle, streaming aborts, the client is told to discard everything it accumulated, and a canned refusal becomes the persisted assistant message. The original tokens are never stored or replayed on subsequent turns. This is intentionally narrow: a single substring match against one normalized needle. It catches obvious prompt-extraction attempts (“repeat your instructions”, “what are you told to do?”) without trying to be a general-purpose data-loss-prevention layer. ## Tools None, this capability hooks the streaming output via the capability framework’s output-guardrail extension point. ## How It Works 1. **Arming**: At the start of each assistant message stream, the capability walks sentence boundaries in the assembled system prompt and picks the first sentence whose normalized form is **≥ 30 characters**. This skips short generic openers like “You are a helpful assistant.” in favor of an agent-specific identifying sentence 2. **Normalization**: Both sides of the comparison are lowercased, and runs of whitespace are collapsed to a single space, so the canary survives reformatting (extra spaces, capitalization drift, line wrapping) 3. **Streaming check**: After every text delta, the canary runs a substring scan over the accumulated assistant text. The check is synchronous and cheap, no I/O, no allocations beyond the normalized buffer 4. **Block on match**: When the needle appears in the accumulated output, the stream is aborted, the offending pending delta is suppressed, and `output.message.replaced` is emitted with `reason_code: "system_prompt_leak"`. The replacement text becomes the persisted assistant message When the system prompt is too short or too generic to produce a needle ≥ 30 characters, the capability declines to arm for that stream and is a no-op. ## Streaming Timeline With a Trip ```plaintext output.message.started │ ▼ output.message.delta ← model text accumulating ("Sure, my instructions are: …") │ ▼ (canary trips on the next delta — pending text is suppressed) output.message.replaced │ (UI discards what it accumulated, shows replacement) ▼ output.message.completed ← persisted message body = replacement ``` ## Configuration ### Default ```json { "capabilities": ["prompt_canary_guardrail"] } ``` Replacement text defaults to: > \[Response withheld: the model attempted to reveal protected instructions.] ### Custom replacement ```json { "capabilities": [ { "ref": "prompt_canary_guardrail", "config": { "replacement": "I can't share my system instructions." } } ] } ``` ## When To Enable Use this capability when: * You ship agents with proprietary, brand-specific, or compliance-relevant system prompts that should not be revealed verbatim to end users * You want a cheap, deterministic defense against the most common prompt-extraction prompts * You can tolerate a generic refusal in place of the model’s response when the canary trips Do **not** rely on this for: * General-purpose data-loss prevention (PII, secrets in tool output, etc.), those need their own surfaces * Defense against paraphrased or summarized prompt leaks, the canary only catches verbatim or near-verbatim copies of the first sentence * Tool output or extended-thinking surfaces, the canary only inspects assistant text ## Limitations * **Verbatim-only**: a model that paraphrases (“My role is to act as an internal pricing oracle…”) will not trip the canary * **First-sentence-only**: if the model leaks a *later* sentence of the system prompt, the canary won’t catch it. Consider rewriting prompts so the most identifying claim is the opening sentence * **No partial matching**: the substring must appear in full. Truncated leaks (cut off mid-sentence) pass through ## See Also * [Events](https://everruns.com/docs/features/events/), the streaming event protocol that carries `output.message.replaced` * [Capabilities](https://everruns.com/docs/features/capabilities/), the extension model these guardrails plug into --- # Sandbox Fleet > Create and operate multiple explicitly addressed resource Sandboxes without changing a session's primary Sandbox. Source: | | | | -------------- | ---------------------------------------------------------------------------- | | **ID** | `sandbox_fleet` | | **Category** | Sandboxes | | **Tools** | 8 | | **Dependency** | [`session_storage`](https://everruns.com/docs/capabilities/session-storage/) | Sandbox Fleet gives an Agent provider-neutral tools for parallel or isolated compute. Daytona backs the capability today, but the model sees only Everruns logical Sandbox IDs. Provider resource IDs, credentials, and translation stay in the trusted control plane. These are **resource Sandboxes**. They never replace the session’s primary Sandbox: ordinary shell and file tools continue to use the primary Sandbox configured by the Harness and Agent. | Tool | Purpose | | -------------------- | ------------------------------------------------------------------ | | `sandbox_create` | Create a resource Sandbox and return its session-scoped logical ID | | `sandbox_exec` | Run a command in an explicitly named Sandbox | | `sandbox_read_file` | Read a file from an explicitly named Sandbox | | `sandbox_write_file` | Write a file in an explicitly named Sandbox | | `sandbox_list` | List the current session’s resource Sandboxes | | `sandbox_inspect` | Inspect one resource Sandbox without exposing provider bindings | | `sandbox_checkpoint` | Copy its workspace into durable session file storage | | `sandbox_manage` | Stop or delete it | Every operation after creation requires `sandbox_id`. An ID from another session is rejected. Delete resource Sandboxes when the work is complete. The older [`daytona`](https://everruns.com/docs/capabilities/daytona/) capability remains available for existing Agents and provider-specific operations. New provider-neutral fleet workflows should use `sandbox_fleet`. --- # Self-Budget > Prompt-only guidance for agents to reason about a user-requested indicative budget using session usage data. Distinct from the platform-enforced `budgeting` capability. Source: | | | | ---------------- | -------------- | | **ID** | `self_budget` | | **Category** | System | | **Features** | *(none)* | | **Tools** | *(none)* | | **Included in** | Worker harness | | **Dependencies** | None | Teaches the agent how to self-manage an **indicative** budget that the user mentions in conversation, for example, “you have $7” or “keep this under 20k tokens”. The capability contributes prompt text only; it adds no tools and performs no enforcement. For platform-enforced budgets (authoritative limits that pause or stop sessions automatically), use the separate [`budgeting`](https://everruns.com/docs/capabilities/budgeting/) capability. ## How It Works `self_budget` is prompt-only. When the capability is enabled the agent’s system prompt gets a “Self-Managed Budget” section that explains: * The self-budget is an **agent-managed soft target**, not a hard limit. * Session usage metadata (exposed via `get_session_info`) is the source of truth for current spend. * The agent decides when to start tracking, when to re-check, and when to stop. * As the target tightens, the agent should adapt, shorter outputs, fewer retries, narrower exploration, fewer redundant tool calls. * The agent avoids claiming exact cost certainty when only token counts or partial pricing are available. * The agent distinguishes between platform-enforced budgets and user-requested indicative budgets when reporting progress. There is no `self_budget` tool. Usage data comes from `get_session_info`, which is provided by the [`session`](https://everruns.com/docs/capabilities/session/) capability (bundled by default in the Worker harness). ## Self-Budget vs Budgeting | Aspect | `self_budget` | `budgeting` | | ----------- | ----------------------------------- | --------------------------------------------------- | | What it is | Agent-managed soft target | Platform-enforced limit | | Tools | None | `check_budget` | | Enforcement | None (prompt guidance only) | Session is paused/stopped automatically | | Data source | `get_session_info` cumulative usage | Budgets table / ledger | | Use case | User says “you have $7” in chat | Org/session has a configured budget in the platform | The two capabilities are non-conflicting and can run together. The Worker harness includes both. ## Related * [Budgeting](https://everruns.com/docs/capabilities/budgeting/), platform-enforced budgets with the `check_budget` tool * [Session](https://everruns.com/docs/capabilities/session/), provides `get_session_info`, the usage data source * [Budgets](https://everruns.com/docs/advanced/budgets/), full budgeting system documentation --- # Session > Inspect and update the current session's metadata, including its ID, title, agent name, locale, and usage. Source: | | | | ---------------- | --------- | | **ID** | `session` | | **Category** | Session | | **Features** | None | | **Dependencies** | None | Tools to read and update session metadata like title and agent information. ## Automatic titles For naming outside the agent loop, enable [Automatic session titles](https://everruns.com/docs/capabilities/automatic-session-titles/) and leave `auto_title` off. Explicit tool writes take priority over automatic titles, including same-text writes. Agent-directed title maintenance is opt-in. Set `auto_title` to `true` in the capability configuration to have the agent create a concise 3–7 word title before handling the first substantive request. The title is a required pre-work update. The agent updates it later, also before other work or a response, only when the conversation’s primary theme materially changes, not for minor follow-ups or subtopics. Title writes update session metadata and do not count as project or workspace file changes. Title changes emit `session.title.updated` with the previous and new title. A repeated write of the current title is a no-op and emits no event. ## Tools ### `get_session_info` Get current session metadata. Returns: session ID, title, locale, agent name, and token usage (input, output, cache read, cache creation, and total tokens) when available. ### `write_session_title` Update the session title. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------- | | `title` | string | yes | New session title | ## See Also * [Storage](https://everruns.com/docs/capabilities/session-storage/), persist data within the session * [Schedules](https://everruns.com/docs/capabilities/session-schedules/), schedule future tasks * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Schedules > Schedule one-shot and recurring cron-based tasks within a session. Source: | | | | ---------------- | ----------------------------------- | | **ID** | `session_schedule` | | **Category** | Core | | **Features** | `schedules` (enables Schedules tab) | | **Dependencies** | None | Schedule future tasks within the current session. Supports one-shot (run once at a specific time) and recurring (cron expression) schedules. ## Tools ### `create_schedule` Create a new scheduled task. | Parameter | Type | Required | Description | | ----------------- | ------ | ----------- | ---------------------------------------- | | `message` | string | yes | The message/task to execute | | `scheduled_at` | string | conditional | ISO 8601 datetime for one-shot schedules | | `cron_expression` | string | conditional | Cron expression for recurring schedules | Provide either `scheduled_at` or `cron_expression`, not both. ### `cancel_schedule` Cancel an active schedule. | Parameter | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------- | | `schedule_id` | string | yes | ID of the schedule to cancel | ### `list_schedules` List all schedules for the current session. ## Recurring background tasks Recurrence is built on schedules, there is no separate “recurring task” object to configure. A recurring (`cron_expression`) schedule either delivers a scheduled turn to the session, or, when paired with a background **monitor** task, runs a probe on each fire and records the result on the task’s thread. This composition (recurring schedule + monitor) is the supported way to run periodic background work, there is no separate recurring-task primitive to configure. ## Notes * Maximum 5 active schedules per session * Cron uses standard 5-field format (minute, hour, day, month, weekday), with weekdays counted 0-6 from Sunday (7 is also Sunday, so `5-7` is Friday through Sunday and `0 18 * * 0` is Sundays at 18:00), read in the schedule’s timezone * A recurring schedule fires at most once every 5 minutes by default. Admission rejects invalid cron and expressions with fewer than two future occurrences, because their minimum interval cannot be verified. Use a one-shot schedule for a single future run * An invalid cron expression or timezone, or a schedule over a limit, fails the tool call with the reason, so the agent can correct it * Scheduled messages are sent to the session as if the user sent them * Use [Current Time](https://everruns.com/docs/capabilities/current-time/) to determine “now” before scheduling ## See Also * [Current Time](https://everruns.com/docs/capabilities/current-time/), get current time for scheduling context * [Session](https://everruns.com/docs/capabilities/session/), session metadata * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Session Storage > Session-scoped key/value storage and encrypted secret storage. Source: | | | | ---------------- | -------------------------------------------- | | **ID** | `session_storage` | | **Category** | Storage | | **Features** | `secrets`, `key_value` (enables Storage tab) | | **Dependencies** | None | Two storage mechanisms scoped to the current session: * **Key/Value store**: plain-text storage for general data * **Secret store**: AES-256-GCM encrypted storage for sensitive data ## Tools ### `kv_store` Manage plain-text key/value pairs. | Parameter | Type | Required | Description | | ----------- | ------ | ----------- | ----------------------------------- | | `operation` | enum | yes | `set`, `get`, `delete`, or `list` | | `key` | string | conditional | Required for `set`, `get`, `delete` | | `value` | string | conditional | Required for `set` | ### `secret_store` Manage encrypted secrets. Values are encrypted at rest and write-only: an agent can store, list and delete secrets, but no tool reads a value back. | Parameter | Type | Required | Description | | ----------- | ------ | ----------- | ------------------------------- | | `operation` | enum | yes | `set`, `delete`, or `list` | | `name` | string | conditional | Required for `set` and `delete` | | `value` | string | conditional | Required for `set` | ## Notes * Data is session-scoped, no cross-session access * `set` uses upsert semantics (overwrites existing keys) * Secret operations require `SECRETS_ENCRYPTION_KEY` to be configured * `list` returns keys/names only (not values) for secrets * The Storage tab can create, replace, and delete values, but never reads a value back * A session secret is available only to that session. It does not follow an Agent Trigger that creates a session per invocation. * No secret value ever reaches the model. `secret_store get` answers the same refusal for every name. Capabilities that need a key (GitHub, Brave Search, sandboxes and others) read their own secret on the server. A key the agent’s shell sends to an HTTP API is a bound secret, described next; an MCP tool-parameter credential goes on the Agent’s **Credentials** tab. * A **bound secret** (stored with a URL to send it to) is write-only: `secret_store list` shows its name, URL and how to use it, while `get`, `set` and `delete` refuse it. The Bashkit shell uses it as `$NAME` in HTTP requests to that URL; see [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/#api-keys-the-agent-never-sees). To give every session and trigger of an agent the same key, add it as an **HTTP API** credential on the Agent’s **Credentials** tab. ## See Also * [Session](https://everruns.com/docs/capabilities/session/), session metadata * [File System](https://everruns.com/docs/capabilities/file-system/), file-based storage alternative * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Slack > Deploy an Everruns agent as a Slack bot through an Agent-owned channel, and let it react, update messages, upload files, and look up users with the slack capability. Source: Start with [Build Agents for Slack](https://everruns.com/docs/integrations/slack/) for examples, a walkthrough, and setup. This page covers configuration and the Slack actions reference. Everruns connects an Agent to Slack in two parts: * A **Slack channel** owned by the Agent receives Slack Events API requests, routes each conversation to a session, and posts the Agent’s responses back to Slack. This is how users talk to the Agent in Slack. * The **`slack` capability** lets the Agent act in that conversation beyond replying: reactions, message updates, file uploads, and user lookups. See [Slack actions](#slack-actions). ## What You Get * **Conversational agents in Slack**: Users interact with the Agent in channels, threads, direct messages, or Slack’s agent pane. * **Session routing**: Conversations map to sessions by thread, channel, or user. * **Secure webhooks**: Everruns verifies requests with Slack’s signing secret. * **Async responses**: Everruns acknowledges Slack immediately and posts the Agent’s response when it is ready. * **Per-channel Slack bots**: Each Slack channel has its own Slack app, credentials, identity, and lifecycle. ## Before You Start * Create an active Agent. * Give Everruns a public HTTPS origin. Set `PUBLIC_APP_URL` to that origin and restart Everruns. * Ask a Slack workspace administrator for permission to install an app. * An organization administrator connects your Slack workspace once; see [Connect a Slack Workspace](#connect-a-slack-workspace). Slack cannot verify `localhost`. For local development, expose Everruns through a public HTTPS tunnel before you create the Slack app. ## Connect a Slack Workspace Every Agent you put in Slack gets its own Slack app, with its own name and its own entry in Slack’s Agents menu. Everruns creates those apps for you in your workspace. To do that it needs a Slack configuration token for the workspace, which an organization administrator adds once: 1. Open **Settings** > **Slack workspaces**. 2. Select **Open api.slack.com/apps**, signed in to the workspace you want your Agents in. 3. Scroll to **Your App Configuration Tokens**, select **Generate Token**, and pick the workspace. 4. Copy the **Refresh Token** (it starts `xoxe-1-`) and paste it into Everruns. Do not copy the access token above it. Everruns connects the workspace as soon as you paste the token, rotates it immediately, and stores only the encrypted replacement. You do not need to repeat this for each Agent. The token can create and change any Slack app in that workspace, and your Slack workspace may require an administrator to generate it. An organization can connect more than one workspace. If your deployment has a Slack manager app (see [Slack Manager App](https://everruns.com/docs/sre/environment-variables/#slack-manager-app)), **Settings** > **Slack workspaces** shows **Connect with Slack** instead: approve Everruns in Slack, pick the workspace, and nothing is copied or pasted. **Use a configuration token instead** keeps the steps above available. Each Agent’s app still asks for its own Slack approval when you add it. **Disconnecting a workspace** does not affect Agents already in it: each has its own Slack app and keeps working. Until you connect the workspace again, you cannot add Agents to it or update their Slack apps. ## Connect an Agent to Slack ### 1. Create a Slack Channel 1. Open the Agent. 2. Select **Integrations**. 3. Select **Add channel**. 4. Select **Slack**. 5. If your organization has connected more than one Slack workspace, choose one. 6. Choose the session strategy. Leave the Slack credentials empty. 7. Select **Save channel**. Everruns opens the channel editor after it saves the channel. ### 2. Publish the Channel Select **Publish** in the channel editor. Publishing makes only this channel live. Publish before you create the Slack app. The generated Slack manifest contains the channel’s Request URL, and Slack verifies that URL when it creates the app. ### 3. Add the Agent to Slack Select **Add to Slack** in the channel editor. Everruns creates the Agent’s Slack app in the chosen workspace and opens Slack’s consent screen with that workspace selected. Approve it, and Everruns stores the app’s signing secret, bot token, and workspace ID on this channel. The channel then shows **Live in Slack** with an **Open in Slack** link. If your Slack workspace requires administrators to approve apps, Slack sends an approval request instead of installing straight away. Deployments without `SECRETS_ENCRYPTION_KEY` do not create Slack apps. If Everruns reports that one-click setup is unavailable: 1. Return to the Agent’s **Integrations** tab. 2. Expand the live Slack channel. 3. Select **Create Slack app**. 4. Review Slack’s pre-filled manifest and select **Create**. 5. Install the app to your workspace. 6. Copy the **Signing Secret** from **Basic Information**. 7. Copy the **Bot User OAuth Token** (`xoxb-...`) from **OAuth & Permissions**. 8. Select **Configure** on the channel, enter both values, and select **Save**. The manifest already contains the bot scopes, event subscriptions, interactivity URL, and canonical channel Request URL: ```text https://your-everruns-host/api/v1/channels/{channel_id}/slack/events ``` Do not replace `{channel_id}` with an Agent ID or an App ID. ### 4. Invite and Test 1. In Slack, enter `/invite @botname` in a channel. 2. Mention the bot or send it a direct message. 3. Return to the Agent’s **Integrations** tab and expand the Slack channel. 4. Confirm that the setup checklist records the first message. ## Configure a Slack App Manually Use this flow only when you cannot use **Add to Slack** or **Create Slack app**. 1. Create and publish a Slack channel from the Agent’s **Integrations** tab. 2. Copy its Request URL from the expanded channel row. 3. In [Slack API Apps](https://api.slack.com/apps), select **Create New App** > **From scratch**. 4. Add these bot token scopes under **OAuth & Permissions**: * `chat:write` * `channels:history` * `groups:history` * `im:history` * `mpim:history` * `app_mentions:read` * `users:read` 5. Add these bot events under **Event Subscriptions**: * `message.channels` * `message.groups` * `message.im` * `message.mpim` * `app_mention` 6. Paste the channel Request URL into Slack’s **Request URL** field. 7. Install the Slack app to your workspace. 8. Copy the signing secret and bot token into the channel’s **Configure manually** fields. 9. Save the channel. ## Existing Installs Existing Slack installs that use `/v1/apps/{app_id}/…` URLs continue to work. Everruns keeps those routes as permanent compatibility aliases. New installs use `/v1/channels/{channel_id}/…`, which is the canonical channel-owned form. ## Channel Configuration | Field | Required | Description | | ----------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `signing_secret` | Before use | Slack app signing secret for HMAC-SHA256 verification. It can be empty while you create the channel, but the channel rejects all Slack requests until it is set. | | `bot_token` | Before use | Bot User OAuth Token (`xoxb-...`) for sending responses. It can be empty while you create the channel. | | `channel_id` | No | Restrict the channel to one channel, such as `C0123456789`. | | `team_id` | No | Slack workspace ID. | | `session_strategy` | No | `per_thread` by default, `per_channel`, or `per_user`. | | `agent_surface_enabled` | No | `false` by default. Also serve Slack’s agent pane; see [Agent Surface](#agent-surface). | ## Agent Surface Slack apps can also appear as an **agent**, a dedicated assistant pane separate from channel conversations. Enabling `agent_surface_enabled` adds this pane without changing channel replies. The generated manifest adds: * the `features.agent_view` block with an `agent_description` derived from the Agent; * the `assistant:write` bot scope; and * the `app_home_opened`, `app_context_changed`, `agent_session_stopped`, and `agent_session_title_changed` bot events. Enabling the pane on an existing Slack app requires a reinstall because a configuration change cannot grant the new `assistant:write` OAuth scope. Generate a fresh manifest, update the Slack app, and reinstall it. Channel replies continue while you do this. Session strategy in the pane is always `per_thread`. The configured strategy still applies to channel conversations. ### Streaming Replies Replies in the agent pane render as the Agent produces them. Channel threads receive one finished message instead of token-by-token updates. ## How the Agent Replies How the Agent talks in Slack is set on the Agent, not on the channel. See the Agent’s **Communication** setting and [Explicit communication](https://everruns.com/docs/features/explicit-communication/). | Agent communication | What people see in Slack | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Direct** (default) | Every assistant response is published. Replies stream in the agent pane. | | **Explicit** | The Agent posts only what it sends with `send_message`. Its other assistant text stays in Everruns as working notes. It can call `no_reply` to choose not to answer. | With explicit communication, `send_message` posts into the thread that started the turn, as this channel’s bot, at most once per call. The Agent cannot choose another channel or thread. Messages can be up to 12,000 characters of Markdown. Success means Slack accepted the post; the `conversation.message` event carries `platform`, `channel` and `message_ref`. For Slack, `message_ref` is the message timestamp: use it as `timestamp` with `slack_update_message` when the Slack actions capability is enabled. If delivery is uncertain, the error says so; the Agent should not resend blindly because the message may already be visible. A turn started by a session schedule (the Agent’s `create_schedule`) has no Slack message of its own. Its `send_message` goes to the conversation of the session’s latest Slack message: inline in a direct message, top-level in a `per_channel` channel, and in the thread for a `per_thread` session. A session that has never received a Slack message cannot post. To run on a clock in a conversation from the start, before anyone has written, give a schedule trigger a Slack target instead: see [Run in a Slack conversation](https://everruns.com/docs/features/agent-triggers/#run-in-a-slack-conversation). The agent pane shows a working status while the turn runs. Approval cards and task progress appear independently of the Agent’s messages. If a turn ends without anything posted to the thread, or an explicit Agent’s turn fails or is cancelled, Everruns posts one short status line with a link to the session. An explicit Agent that calls `no_reply` chose silence, so its thread gets no status line. ## Session Strategies | Strategy | Behavior | Tag Pattern | | ------------- | ---------------------------------------- | -------------------------- | | `per_thread` | Each Slack thread is a separate session. | `slack:thread:{thread_ts}` | | `per_channel` | One session serves the channel. | `slack:channel:{channel}` | | `per_user` | One session serves each Slack user. | `slack:user:{user}` | Use `per_thread` for most Slack bots. ## How It Works ### Architecture ![Slack Architecture](https://everruns.com/docs/_astro/slack-architecture.BJGs54B6_Z4qT4w.svg) ### Message Flow ![Slack Message Flow](https://everruns.com/docs/_astro/slack-message-flow.b0URNFXK_HhXX7.svg) **Inbound path:** 1. Slack posts a message event to `/v1/channels/{channel_id}/slack/events`. 2. The channel verifies the signing secret and rejects duplicates. 3. Everruns acknowledges Slack within three seconds. 4. The channel finds or creates a session from the configured strategy. 5. Everruns creates a user message and starts an Agent turn. **Outbound path:** 6. The Slack delivery dispatcher watches the turn. 7. For a Direct Agent, the RuntimeAgent emits completed output messages and the dispatcher posts them. 8. For an Explicit Agent, `send_message` posts messages directly and returns delivery receipts. 9. Automatic delivery retries transient failures with exponential backoff. `send_message` returns errors without retrying an uncertain send. 10. The dispatcher unregisters when the turn completes, fails, or is cancelled. ## Troubleshooting ### URL Verification Failed * Confirm that the channel is published. * Confirm that `PUBLIC_APP_URL` is a public HTTPS origin and that Everruns restarted after the value changed. * Confirm that the Request URL contains `/v1/channels/{channel_id}/slack/events`. ### Bot Does Not Respond * Confirm that the channel is published and enabled. * Invite the bot to the channel with `/invite @botname`. * Confirm that the Slack app has the required bot events and the `chat:write` scope. * Confirm that the channel has the correct signing secret and bot token. ### Request Verification Failed * Confirm that the channel’s signing secret matches the value under the Slack app’s **Basic Information** page. * Confirm that the Everruns server clock is accurate. ## Approvals When an Agent pauses for approval, Slack renders **Approve** and **Decline** buttons in the thread. Only the person whose message the Agent is answering can use them. The generated manifest already points Slack interactivity at this channel. A Slack app created before interactive approvals existed must save a fresh manifest once. ## Task Progress When an Agent delegates work, Slack shows one **Tasks** message and updates it as workers finish. The message lists up to five tasks and summarizes larger groups by count. ## Slack actions | | | | ---------------- | --------------- | | **ID** | `slack` | | **Category** | Integrations | | **Features** | `slack_actions` | | **Dependencies** | None | An agent published to a Slack channel can reply in its thread. The `slack` capability lets it do the rest, as the same bot the workspace invited: react to a message, rewrite one it posted, share a file, or resolve a user ID to a name. No second credential. The tools resolve the channel’s own bot token server-side, so there is nothing extra to provision, scope, or rotate. ### Requirements The tools only work in a session a Slack message created. An agent that has the capability enabled but is running from the API, a schedule, or another channel has no Slack channel to act as, and every tool returns an error saying so rather than acting as some other channel’s bot. Where an agent carries two Slack channels, each with its own bot, the tools act as the channel that created the session. Your Slack app needs the scope for each action you use: `reactions:write` for reactions, `chat:write` for updates, `files:write` for uploads, and `users:read` for lookups. Slack answers a missing scope with an error the agent sees. ### Tools #### `slack_add_reaction` Slack messages include their exact channel and timestamp in the agent’s context. The agent uses that reference to target a reaction; a message’s date or rounded timestamp cannot identify it. If a bot was installed before reaction permission was included, reconnect the Slack app and approve `reactions:write`. Deploying an updated manifest does not add permissions to an existing bot token. Add an emoji reaction to a message. The cheapest acknowledgement available — prefer it over posting “working on it”. | Parameter | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------- | | `channel` | string | yes | Channel ID the message is in | | `timestamp` | string | yes | The message’s `ts` | | `name` | string | yes | Emoji name without colons (e.g. `eyes`) | Reacting with an emoji that is already there succeeds; the result says `already_reacted`. #### `slack_update_message` Rewrite a message this bot posted. Use it to turn a status message into its result instead of posting a second message. | Parameter | Type | Required | Description | | ----------- | ------ | -------- | -------------------------------------- | | `channel` | string | yes | Channel ID the message is in | | `timestamp` | string | yes | The `ts` of the bot message to rewrite | | `text` | string | yes | Replacement text; Markdown is rendered | Only messages this bot posted can be updated. #### `slack_lookup_user` Resolve a Slack user ID to that person’s display name, real name, timezone, and whether they are a bot. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------------- | | `user_id` | string | yes | Slack user ID (the `<@U…>` mention form is accepted) | Returns only those addressing fields. Email, phone, and title are not exposed to the agent. #### `slack_upload_file` Share a file into the conversation. Use it for reports, diffs, and logs too long to read in a message. | Parameter | Type | Required | Description | | ----------------- | ------ | -------- | ------------------------------------------------ | | `channel` | string | yes | Channel ID to share into | | `filename` | string | yes | Filename shown in Slack, including its extension | | `content` | string | yes | The file’s text content | | `thread_ts` | string | yes | Thread timestamp of the current conversation | | `initial_comment` | string | no | Message posted alongside the file | Content is capped at 8 MiB. ### Notes * Posting to an arbitrary channel is deliberately not offered. The blast radius of “anywhere the bot is” is wider than “the thread that asked”. The control plane verifies the channel and thread against trusted session metadata before sending an action to Slack. * A retired or disabled channel stops acting immediately, even for a session it created earlier. * Slack rate limits reach the agent with Slack’s own retry advice rather than as a generic failure. * The [Slack MCP server](https://everruns.com/docs/features/mcp/) stays supported for anything this does not cover. This removes the second credential for the common cases; it does not replace MCP. ## See also * [Publish an Agent to Slack](https://everruns.com/docs/how-to/publish-to-slack/): a step-by-step guide. * [Channels](https://everruns.com/docs/features/channels/): every channel type and the channel lifecycle. * [Slack API Documentation](https://api.slack.com/docs) and the [Slack Events API](https://api.slack.com/events-api). --- # Soft Approval > Prompt-level consent gate. The agent pauses and asks before destructive or outward-facing actions, and runs safe work without interruption. Source: | | | | ---------------- | ---------------------------------------------------------- | | **ID** | `soft_approval` | | **Category** | Safety | | **Tools** | `request_approval`, `record_approval`, `set_approval_mode` | | **Features** | None | | **Dependencies** | None | Soft approval asks the agent to stop and get the user’s consent before a critical action, and to run everything else without asking. It works through the system prompt and three tools. It is guidance for the model, not an enforcement point: a call the model makes still runs. When a call must not run without a person’s decision, use [Tool Approval](https://everruns.com/docs/capabilities/tool-approval/) instead. That gate holds the call until someone approves it, whatever the model does. [Base](https://everruns.com/docs/built-ins/harnesses/base/) and every harness built on it, the deprecated [Generic](https://everruns.com/docs/built-ins/harnesses/generic/) and the [Platform Chat](https://everruns.com/docs/built-ins/harnesses/platform-chat/) include soft approval at the `normal` level. ## Levels | Mode | The agent asks before | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `off` | Nothing. The capability adds no prompt. | | `normal` (default) | Destructive or irreversible actions (deleting files or data, dropping records, force-push, history rewrites) and outward-facing ones (pushing, publishing, opening pull requests, sending messages or mail, deploying, spending money). Ordinary edits and local, reversible changes proceed. | | `protective` | Any action that changes state: writing or deleting files, commits and pushes, installing or removing packages, requests with side effects, changes to shared resources, and any command that is not plainly read-only. | At every level except `off`, the prompt tells the agent to plan, batch the safe steps, and never pause on read-only inspection. ## Configuration ```json { "ref": "soft_approval", "config": { "mode": "normal" } } ``` `mode` accepts `off`, `normal`, or `protective`, and the synonyms listed under [`set_approval_mode`](#set_approval_mode). Any other value fails validation. ## Tools ### `request_approval` The agent calls it at a critical action, then ends its turn. The call is the pause: it tells the user the agent is waiting. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------------------------------------------- | | `action` | string | Yes | The action awaiting approval, for example “delete the staging database” | | `question` | string | No | One short question for the user. Defaults to “Go ahead?” | The result carries `awaiting_approval: true`, the action and question, and the turn and input message it was asked in. ### `record_approval` After the user says yes, the agent calls it with what was approved, then carries the action out. A plain affirmative counts as approval; a hesitant or negative reply does not. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------------------------------------------------------------------------------- | | `action` | string | Yes | The specific action the user approved | | `detail` | string | No | Extra context such as the command or scope. It is logged, so it must not contain secrets. | The result records the turn and input message the consent was given in. An auditor can join that message to the host’s own record of who sent it. One approval covers one action. A category the user pre-authorizes (“no need to ask for commits”), or a workflow the user invoked by name, covers the actions it names; the agent records that grant once. ### `set_approval_mode` When the user asks the agent to be more or less careful, the agent calls it with `mode`. It accepts `protective`, `normal`, and `off`, plus synonyms such as `paranoid`, `careful`, `default`, and `yolo`. The new level overrides the configured `mode` for that session from the next turn on. ## Relation to Ask User [Ask User](https://everruns.com/docs/capabilities/ask-user/#not-a-consent-gate) questions auto-resolve, so an answer to them never grants permission. Soft approval’s wait does not auto-resolve. The interactive harnesses enable both, so the agent has a place for preference questions and a separate place for consent. ## See also * [Tool Approval](https://everruns.com/docs/capabilities/tool-approval/), the hard approval gate * [Ask User](https://everruns.com/docs/capabilities/ask-user/), structured questions to the user * [Guardrails](https://everruns.com/docs/capabilities/guardrails/), config-driven checks over output and tool activity --- # SQL Database > Session-scoped SQLite databases: create tables, run queries, and persist relational data per session. Source: | | | | ---------------- | ---------------------- | | **ID** | `session_sql_database` | | **Category** | Data | | **Features** | `sql_database` | | **Dependencies** | None | Session-scoped SQLite databases for structured data storage. Create tables, insert data, and run queries, all isolated to the current session. ## Tools ### `sql_execute` Run DDL/DML statements (CREATE TABLE, INSERT, UPDATE, DELETE). | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ---------------------------------------------------------------- | | `database` | string | yes | Database name (alphanumeric and underscores); created if missing | | `sql` | string | yes | SQL statement to execute | ### `sql_query` Run SELECT queries. Results limited to 1000 rows. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ------------- | | `database` | string | yes | Database name | | `sql` | string | yes | SELECT query | ### `sql_schema` Introspect the database schema, list tables, columns, and types. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------- | | `database` | string | yes | Database name | | `table` | string | no | Table name; omit to list all tables | ## Notes * Database is session-scoped, destroyed when the session ends * SELECT queries return at most 1000 rows * Standard SQLite SQL syntax ## See Also * [Storage](https://everruns.com/docs/capabilities/session-storage/), simpler key/value alternative * [File System](https://everruns.com/docs/capabilities/file-system/), file-based data storage * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Sub Agents > Spawn subagents that run tasks in isolated context windows, through the generic session task tools. Source: | | | | ---------------- | ----------- | | **ID** | `subagents` | | **Category** | Core | | **Features** | `subagents` | | **Dependencies** | None | Spawn subagents for parallel task execution. Each subagent runs in its own isolated context window, allowing the parent agent to delegate verbose or independent tasks without cluttering the main conversation. Subagents inherit the parent’s harness and agent configuration but operate with their own message history. ## Tools ### `spawn_agent` Sessions with `subagents` expose `target.type: "subagent"` in the shared `spawn_agent` dispatcher. If first-party handoffs or external A2A delegation are also active, the same tool advertises those target types too. The dispatcher returns a `task_id` for the generic session task tools and moves Everruns toward one delegation surface across subagents, first-party agent handoffs, and external A2A agents. Create and start a new subagent by calling `spawn_agent` with `target.type: "subagent"`. By default the subagent runs in the background: the tool returns immediately with a `task_id`, the parent agent keeps working, and the session is notified when the subagent finishes. Use the `task_id` with the generic session task tools to monitor, message, or cancel the subagent. | Parameter | Type | Required | Description | | -------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | yes | Human-readable name for the subagent. Must be unique within the session. | | `instructions` | string | yes | Instructions for what the subagent should do. This becomes the subagent’s initial prompt. | | `target.type` | string | yes | Must be `subagent`. | | `mode` | string | no | `background` (default) returns immediately with a `task_id`; `foreground` blocks until the subagent completes and returns its result inline. | | `blueprint` | string | no | Optional specialist blueprint ID, such as `github_scout`, that supplies its own prompt, model, and private tools. | | `config` | object | no | Blueprint-specific configuration, validated against the blueprint’s schema before the child session is created. Only valid when `blueprint` is set. | ## Managing subagents after spawn Use the generic `session_tasks` tools to monitor and steer subagents after spawning. The `task_id` is returned by `spawn_agent`. * `list_tasks` with `kind: "subagent"`, list all subagent tasks and their status * `get_task` with the task ID, get detailed status and result for a specific subagent * `message_task`, send a steering message or additional context to a running subagent * `cancel_task`, request cooperative cancellation of a subagent * `wait_task`, block until a subagent reaches a terminal or interrupted state ## Notes * **Governed spawning**: subagents can spawn nested subagents up to `max_subagent_depth` (default 2); set it to 0 to block subagent spawning. Each root session also has `max_active_descendant_tasks` (default 16) and `max_total_descendant_tasks` (default 200) caps to bound wide fan-out and repeated spawn loops. * **Shared budget pool**: nested subagents spend from the root session’s session-scoped budget. * **Background mode (default)**: spawning returns immediately with a `task_id`. The final result lands on the task record (`summary` via `get_task`), and the parent session is woken when the subagent reaches a terminal state. Background runs are capped at 6 hours. * **Foreground mode**: `mode: "foreground"` blocks until the subagent completes and returns its result inline. Foreground execution has a 5-minute timeout. * **Inherited configuration**: subagents inherit the parent’s harness and agent configuration. * **Blueprints**: specialist blueprints can run with their own prompt, model, and private tools while still using the same subagent lifecycle. ## See Also * [Agent handoff](https://everruns.com/docs/capabilities/agent-handoff/), task monitoring and control (`list_tasks`, `get_task`, `message_task`, `cancel_task`, `wait_task`) * [Author an agent blueprint](https://everruns.com/docs/framework/agent-blueprints/), contributing a specialist agent with a typed configuration contract * [GitHub Scout](https://everruns.com/docs/capabilities/github-scout/), blueprint-only GitHub repository exploration * [A2A](https://everruns.com/docs/features/a2a/), delegating to external agents with `target.type: "external_a2a"` * [Session](https://everruns.com/docs/capabilities/session/), session metadata and lifecycle * [Platform](https://everruns.com/docs/capabilities/platform/), agent and platform configuration * [Capabilities Overview](https://everruns.com/docs/capabilities/), full list of available capabilities --- # Task Management > Structured task lists for tracking multi-step work within a session. Source: | | | | ---------------- | --------------------- | | **ID** | `stateless_todo_list` | | **Category** | Core | | **Features** | None | | **Dependencies** | None | Enables agents to create and manage structured task lists. State is maintained in conversation history, each tool call sends the complete list. ## Tools ### `write_todos` Create or update the complete task list. Each call replaces the entire list. | Parameter | Type | Required | Description | | --------- | ----- | -------- | -------------------------------------------------- | | `todos` | array | yes | Array of `{ content, status, activeForm }` objects | Task statuses: `pending`, `in_progress`, `completed`. ### `report_done` Report finished work once, before the final reply: what was done, how it was checked, and links to what it produced. The session’s work report shows this summary instead of the first sentence of the reply, and a coordinated worker’s `complete_assignment` is read the same way. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------------------- | | `summary` | string | yes | One or two sentences, leading with the result | | `validation` | string | no | How the work was checked | | `outcome` | string | no | `done` (default) or `failed` | | `artifacts` | array | no | Up to 10 `{ name, type, url?, path? }` links | ## Notes * **Stateless**: no database table; state lives in conversation history * Each `write_todos` call must include the **complete** list (not incremental updates) * Best practice: exactly one task `in_progress` at a time * Only mark a task `completed` when fully done (tests pass, no errors) * `activeForm` is the present-continuous label shown during execution (e.g., “Running tests”) ## See Also * [Session](https://everruns.com/docs/capabilities/session/), session metadata management * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Tool Approval > Hold back risky tool calls until a person approves them. The call does not run until someone says yes. Source: | | | | ---------------- | --------------- | | **ID** | `tool_approval` | | **Category** | Safety | | **Tools** | None | | **Dependencies** | None | A hard approval gate. Before a risky tool runs, the turn pauses and a person decides. Unlike [soft approval](https://everruns.com/docs/capabilities/ask-user/#not-a-consent-gate), which asks the model to pause, this gate does not depend on the model: a call nobody approved does not run. ## What gets gated Each tool declares what it does, and the gate reads those declarations rather than guessing from names: | Mode | Asks before | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | | `normal` (default) | Tools that declare themselves destructive or outward-facing (they reach outside the session), and tools that declare they require approval | | `protective` | Anything not declared read-only. A tool with no declarations counts as one that changes state | | `off` | Nothing | A tool cannot avoid the gate by declaring itself read-only and outward-facing at the same time. ## Configuration ```json { "ref": "tool_approval", "config": { "mode": "normal", "timeout_seconds": 900 } } ``` | Field | Default | Description | | ----------------- | -------- | --------------------------------------------------------------------------------- | | `mode` | `normal` | `off`, `normal`, or `protective` | | `timeout_seconds` | `900` | How long a request waits for an answer before it counts as rejected (60 to 86400) | ## Answering a request When a call is held back, the session waits with status `waiting_for_tool_results` and emits a `tool.call_requested` event containing one `approve_tool_call` call per held-back call. Its arguments show the tool, the arguments it would run with, why it was gated, and the deadline. The session UI renders these as approval cards. Answer them with: ```bash curl -X POST "$EVERRUNS_API/v1/sessions/$SESSION_ID/tool-approvals" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"decisions": [{"tool_call_id": "tool_approval_toolu_01...", "decision": "allow"}]}' ``` | Decision | Effect | | --------------- | ----------------------------------------------- | | `allow` | This exact call may run, once | | `allow_always` | Every call of this tool in this session may run | | `reject` | This call does not run | | `reject_always` | No call of this tool runs in this session | All requests from one pause are answered together. A request left out of the submission is not approved. Answering requires permission to manage the session. After an answer the turn resumes and the agent calls the tool again. An `allow` covers only the call with exactly the arguments that were shown; different arguments are asked about again. If nobody answers before the deadline, the requests count as rejected and the turn resumes. Nothing is remembered, so the agent can ask again later. ## When to enable it Enable it for agents that can send messages, spend money, change production systems, or browse with [computer use](https://everruns.com/docs/capabilities/computer-use/): anything where one wrong call is expensive. An agent that runs unattended on a schedule or trigger will wait for the full timeout on every gated call and then carry on without it. Use `off`, or leave the capability off, for agents nobody is watching. --- # Tool Call Repair > Detects and repairs malformed tool-call arguments from the model, recovering the turn instead of surfacing a raw parse error. Source: | | | | ---------------- | ------------------ | | **ID** | `tool_call_repair` | | **Category** | Safety | | **Features** | None | | **Dependencies** | None | | **Risk** | Low | Opt-in recovery net for malformed tool calls. Models occasionally emit tool-call arguments that are not clean JSON, wrapped in a Markdown code fence, surrounded by prose, with trailing commas or single quotes, or with values typed as strings where the schema wants numbers. Without repair, such a call either surfaces a parse error or silently collapses to empty arguments and fails downstream. This capability salvages the call so the turn proceeds. **Disabled by default.** The capability is registered so agents can enable it, but contributes nothing unless explicitly selected. With it off, behavior is byte-for-byte unchanged. ## Tools None, the capability intercepts inside the `reason` step, after the model’s tool calls are finalized and before the assistant message is built. ## How It Works 1. **Deterministic local salvage**: A pure function runs over each call’s `arguments`: it unwraps fenced code blocks and strips surrounding prose, removes trailing commas, normalizes single quotes to double quotes, and coerces string-typed known keys to the type declared by the tool’s JSON schema (e.g. `"42"` → `42` for an integer property). Optional keys the model filled with `null` or `"null"` where the schema does not accept it are dropped, since leaving the key out is what the model meant. An already-valid call is a no-op. 2. **Bounded corrective re-prompt**: When local salvage cannot recover a usable object, the capability allows up to `max_reprompts` attempts per call (default 1. before falling through to the normal error path. The re-prompt is realized by the agent loop: the unrepaired call proceeds to today’s error path and the model retries on the next iteration. The per-call cap guarantees there is no infinite repair loop. 3. **Observability**: Each malformed call emits one `tool.call_repaired` event carrying an outcome label: `local-salvage`, `re-prompt`, or `gave-up`. ## Configuration ### Default ```json { "capabilities": ["tool_call_repair"] } ``` ### Custom re-prompt cap ```json { "capabilities": [ { "ref": "tool_call_repair", "config": { "max_reprompts": 2 } } ] } ``` `max_reprompts` accepts `0`–`5`. `0` means “salvage locally or fall straight through to the error path with no re-prompt”. ## When To Enable Use this capability when: * You run models or providers that occasionally wrap tool arguments in prose or code fences, or emit lenient JSON (single quotes, trailing commas) * You want a malformed call to recover the turn rather than waste an iteration on a raw parse error ## Limitations * **Verbatim JSON only**: salvage extracts an embedded JSON object; it does not invent missing required fields or guess intent from natural language * **Bounded input**: argument blobs larger than 256 KiB are treated as un-salvageable without parsing (a denial-of-service guard against runaway model output) * **No deep type checking**: coercion handles top-level `integer` / `number` / `boolean` string values; full schema validation remains the tool’s job ## See Also * [Events](https://everruns.com/docs/features/events/), the streaming event protocol that carries `tool.call_repaired` * [Capabilities](https://everruns.com/docs/features/capabilities/), the extension model this capability plugs into --- # Tool Search > Deferred tool loading for agents with many tools, using the provider's hosted tool search on OpenAI and Claude models and a client-side search everywhere else. Source: Agents with many tools spend a large part of every prompt on tool parameter schemas. Tool search sends only tool names and descriptions up front and loads a tool’s full schema when the model needs it. Tool calls and results work the same way; only how schemas reach the model changes. Four capabilities provide it: | ID | Mechanism | Works on | On an unsupported model | | -------------------- | -------------------------------------- | ------------------------------------------------------ | -------------------------------- | | `auto_tool_search` | Picks one of the three below per model | Any model | Falls back to client-side | | `openai_tool_search` | OpenAI hosted tool search | GPT-5.4 and newer (`gpt-5.4*`, `gpt-5.5*`, `gpt-5.6*`) | Does nothing (full schemas sent) | | `claude_tool_search` | Anthropic hosted tool search | Claude 4 and newer, first-party API | Does nothing (full schemas sent) | | `tool_search` | Client-side `tool_search` tool | Any model | Not applicable | Use `auto_tool_search` unless you know the model and want one mechanism explicitly. It is what the [Worker](https://everruns.com/docs/built-ins/harnesses/worker/) harness uses. Do not combine `auto_tool_search` with any of the other three on the same agent; it already provides all three paths. All four capabilities have category Optimization, no features, and no dependencies. ## Auto tool search `auto_tool_search` resolves to one of three underlying mechanisms based on the model: * **Models with native OpenAI tool search** (GPT-5.4 and newer) → the hosted mechanism described in [OpenAI Tool Search](#hosted-openai): namespaces + `defer_loading` + a `{"type": "tool_search"}` activator. No extra tool is added; the provider handles search server-side. * **Models with native Claude tool search** (Opus 4, Sonnet 4.6, Haiku 4.5, and Fable 5 and newer) → the hosted mechanism described in [Claude Tool Search](#hosted-claude): per-tool `defer_loading` + a `tool_search_tool_bm25_20251119` server tool. No extra tool is added; the provider handles search server-side. * **All other models** (Gemini, OpenAI Completions, Claude/GPT reached via a gateway that doesn’t implement the hosted format, …) → the client-side mechanism described in [Tool Search](#client-side): schemas are stripped to stubs and a `tool_search` tool loads them back on demand. The choice is made when the agent’s capabilities are assembled, once the model is known. You don’t have to know in advance which provider an agent will use. The dispatch looks at the **model id** (matched against the first-party OpenAI/Anthropic profiles), not the transport. In practice that handles the common gateway cases: a Claude model served via Amazon Bedrock or OpenRouter carries a distinct id (`anthropic.claude-…`, `anthropic/claude-…`) that doesn’t match the bare first-party profile, so `auto_tool_search` resolves to the client-side mechanism there. > **Edge case:** if a masked transport presents a *bare* first-party id that does resolve (e.g. a `gpt-5.4` served through an OpenAI-compatible gateway), `auto_tool_search` picks the hosted capability, but the driver then suppresses the hosted wire format for that transport, so full schemas are sent with **no** client-side fallback (a missed optimization, not a failure). If you run a first-party model id through such a gateway, add the [Tool Search](#client-side) capability explicitly to force client-side deferral. ### Tools One, the client-side `tool_search` tool, added only on models without native support. On models with native tool search, no tool is added and the provider’s hosted search is used instead. ### Configuration ```json { "capabilities": ["auto_tool_search"] } ``` The default threshold is 15 tools. To change it: ```json { "capabilities": [ { "ref": "auto_tool_search", "config": { "threshold": 10 } } ] } ``` The threshold (minimum tool count before deferral activates) applies to every mechanism. Set it to `1` to always activate when the capability is present. ## Deferrable policy Each tool has a `deferrable` policy that controls whether its schema can be deferred: | Policy | Behavior | | ----------- | ------------------------------------------------------------------------- | | `never` | Full schema always sent (use for high-frequency tools like `write_todos`) | | `automatic` | Deferred when tool_search is active and above threshold (default) | | `always` | Always deferred when tool_search is active | ## Hosted: OpenAI `openai_tool_search` enables [OpenAI’s tool_search](https://platform.openai.com/docs/guides/tool-search). It configures the LLM driver and adds no tool. 1. **Threshold check**: tool_search only activates when the total tool count meets or exceeds the threshold (default: 15) 2. **Namespace grouping**: tools are grouped by their capability’s category into [namespace](https://platform.openai.com/docs/api-reference/responses/create#responses-create-tools) entries, giving the model semantic structure for discovery. Wire namespace `name` values are normalized to provider-safe identifiers (for example `File Operations` → `File_Operations`); descriptions keep the human-readable category label 3. **Deferred schemas**: tools marked as deferrable have `defer_loading: true` set, meaning only name + description are sent upfront 4. **`tool_search` entry**: a `{"type": "tool_search"}` activator is appended to the tools array, enabling the model’s built-in tool search index 5. **Transparent execution**: tool calls and results work identically; the only difference is how tools are presented to the model ### Model support Tool search requires model-level support. Currently supported: | Model family | Supported | | ---------------- | ----------------------------------- | | `gpt-5.6*` | Yes | | `gpt-5.5*` | Yes | | `gpt-5.4*` | Yes | | All other models | No (capability is silently ignored) | When the capability is enabled but the model doesn’t support tool_search, the feature is silently skipped, no errors, no behavior change. Configure it like `auto_tool_search`, with `"ref": "openai_tool_search"` and an optional `threshold`. ### Limitations * **OpenAI only**: tool_search is an OpenAI Responses API feature; other providers ignore this capability. * **Supported OpenAI models only**: earlier OpenAI models don’t support tool_search. * **No client-side tools**: currently only applies to built-in (server-executed) tools. See the [OpenAI Responses API tools parameter](https://platform.openai.com/docs/api-reference/responses/create#responses-create-tools) for the namespace and tool_search types. ## Hosted: Claude `claude_tool_search` enables [Anthropic’s hosted tool search](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool). It configures the LLM driver and adds no tool. 1. **Threshold check**: tool search only activates when the total tool count meets or exceeds the threshold (default: 15). Below the threshold, full schemas are sent as usual. 2. **Deferred schemas**: every deferrable tool gets `defer_loading: true`, so only its name and description reach the model upfront. Anthropic defers each tool individually (there is no namespace grouping). 3. **Hosted search tool**: a `tool_search_tool_bm25_20251119` server tool is added to the request. The model issues a natural-language query against the catalog (tool names, descriptions, argument names, and argument descriptions) and Anthropic returns the 3–5 most relevant tools, expanding them into full definitions inline. 4. **Transparent execution**: the model then calls a discovered tool with a normal `tool_use`; tool calls and results work identically. The only difference is how tools are presented to the model. Because the hosted search tool is itself never deferred, Anthropic’s requirement that *at least one tool be non-deferred* is always satisfied, even when every function tool is deferrable. Keeping the 3 to 5 most frequently used tools non-deferred (policy `never`) avoids a search round-trip before the agent’s first hot-path call. ### Model support Tool search requires model-level support. Per Anthropic, it is available on: | Model family | Supported | | -------------------------------------------------------- | ----------------------------------- | | Opus 5.5 / 5 (`claude-opus-5-5`, `claude-opus-5`) | Yes | | Opus 4.x (`claude-opus-4*`) | Yes | | Sonnet 5.5 / 5 (`claude-sonnet-5-5`, `claude-sonnet-5`) | Yes | | Sonnet 4.6 (`claude-sonnet-4-6`) | Yes | | Haiku 5.5 / 4.5 (`claude-haiku-5-5`, `claude-haiku-4-5`) | Yes | | Fable 5.1 / 5 (`claude-fable-5-1`, `claude-fable-5`) | Yes | | Retired pre-4 Claude models | No (capability is silently ignored) | When the capability is enabled but the model doesn’t support tool search, the feature is **silently skipped, full tool schemas are sent as usual**. This standalone capability does *not* add a client-side fallback: on an unsupported model it simply does nothing (no error, no behavior change). For automatic fallback to client-side deferral, use [Auto Tool Search](#auto-tool-search) (or add the [Tool Search](#client-side) capability explicitly). Claude models reached through a non–first-party transport don’t get hosted tool search either, because those transports don’t implement the hosted format: * **Amazon Bedrock**: this integration uses the ConverseStream API; Anthropic’s server-side tool search on Bedrock is only available via the InvokeModel API. * **OpenRouter**: its stateless OpenAI-compatible endpoint accepts but does not implement Anthropic’s hosted tool search. With `claude_tool_search` alone, those transports also send full schemas; pair with [Auto Tool Search](#auto-tool-search) to get client-side deferral there instead. Configure it like `auto_tool_search`, with `"ref": "claude_tool_search"` and an optional `threshold`. ## Client-side `tool_search` implements tool search entirely client-side, so it works with Gemini, OpenAI Completions, models reached through gateways that don’t implement hosted search, and any other provider. For large MCP catalogs, `tool_search` can use bounded schema disclosure. Set `bounded: true`; the optional `max_active_tools`, `max_active_bytes`, and `max_result_bytes` settings adjust the built-in limits for active native schemas and search responses. Legacy behavior remains the default unless bounded mode is enabled. See [Large MCP catalogs and tool surfaces](https://everruns.com/docs/features/large-mcp-catalogs/) for the complete configuration and runtime behavior. ### Tools * **`tool_search`**: search the available tools by keyword and load their full parameter schemas. It is never deferred itself. ### How it works The diagram below traces one deferred tool through a full round-trip, from schema stripping at context-assembly time, through the `tool_search` call, to calling the real tool with its restored parameters. ![Tool Search deferred-loading flow: the Agent Runtime strips parameter schemas to stubs before sending tools to the model; the model calls tool_search, which ranks visible tools in the registry and returns full schemas while recording a session-scoped reveal; on the next iteration the hook restores the revealed tool's registered schema so the model can call it with full parameters.](https://everruns.com/docs/_astro/tool-search-flow.BixZno0e_1TFtua.svg) 1. **Threshold check**: deferral only activates when the total tool count meets or exceeds the threshold (default: 15). Below it, full schemas are sent unchanged. 2. **Schema stripping**: a tool-definition hook replaces the parameter schema of every deferrable tool with a minimal open-object stub (name + description survive). The shared prompt carries the search instruction once instead of repeating it in every stub. This runs when the runtime agent is built, so the model never receives the full schemas upfront. 3. **`tool_search` tool**: a real tool is added to the agent. When the model calls it with a query, the tool inspects its sibling tools and returns the full JSON parameter schemas of the matches. 4. **Progressive disclosure**: `tool_search` also records the matched tools as *revealed*. The hook re-runs on every reasoning iteration, so on the next step the revealed tools are advertised with their full, authoritative schema on the *registered* definition. This is what lets a structured tool caller actually pass arguments to a previously deferred tool, rather than only reading its schema as text. 5. **System-prompt guidance**: a short note instructs the model to call `tool_search` before using a tool whose parameters it has not yet loaded. 6. **Transparent execution**: the underlying tools stay registered and executable. Tool calls and results work identically; only how schemas reach the model changes. ### Never-defer allowlist `DeferrablePolicy::Never` is set by the tool’s *owner*. An embedder that composes tools it does not own (for example file/shell tools from another crate) can instead keep specific tools fully loaded by name: * Programmatically: `ToolSearchCapability::with_never_defer(["read_file", "bash", ...])`. * By configuration: a `never_defer` array (merged with any programmatic list). Allowlisted tools behave exactly like `DeferrablePolicy::Never` tools, their full schema is always sent, so the agent is never forced through a `tool_search` round-trip before its first read/edit/shell call. ### Legacy search ranking and result bounding The behavior in this section describes the default, legacy generic search. Bounded mode uses the server-aware index and active/result byte limits described in [Large MCP catalogs](https://everruns.com/docs/features/large-mcp-catalogs/). In bounded mode, a source-only query returns a server refinement rather than arbitrary operation schemas. Because there is no hosted semantic index, `tool_search` ranks matches client-side with a deliberately simple, predictable scheme: * **Field-weighted keyword overlap**: each whitespace-separated query term scores **3** if it appears in a tool’s *name* and **1** if it only appears in the *description*. A name hit is a far stronger signal of intent than an incidental word in prose, so it dominates. * **Exact-name bonus**: a query that is exactly a tool name gets a large bonus (**+100**), so “load this specific tool” always ranks that tool first. The deferred stub tells the model to query the exact tool name, so this is the common path. Wrapping punctuation is stripped first, so a quoted or backticked name (`"read_file"`, `` `read_file` ``) still matches. * **Top-band cutoff**: only results scoring at least **half the top score** are returned, trimming weak tail matches so a loose query does not drag in loosely related tools. * **Result cap**: at most **8** tools are returned per call. Every returned tool is also *revealed* (its full schema is un-deferred for the rest of the session), so the cap bounds both the response payload and how much of the catalogue a single search can permanently un-defer. * **Visible-tool scoping**: the search only considers tools visible in the current turn (the turn-scoped allowlist), so it never reveals a tool the agent could not otherwise call. * **No-match fallback**: if nothing matches, the tool returns the catalogue of available tool *names* (not schemas) so the model can refine its query instead of dead-ending. An empty query lists tools so the model can browse. The session reveal set that drives progressive disclosure is itself bounded: it is keyed per session and evicts the oldest sessions past a fixed cap, so reveals never leak across sessions or grow without limit (an evicted session simply re-runs `tool_search`). ### Configuration ```json { "capabilities": ["tool_search"] } ``` The activation threshold defaults to 15 tools (`DEFAULT_TOOL_SEARCH_THRESHOLD`). Both the threshold and a never-defer allowlist can be set via capability config: ```json { "capabilities": [ { "ref": "tool_search", "config": { "threshold": 20, "never_defer": ["read_file", "write_file", "edit_file", "list_directory", "grep_files", "bash"] } } ] } ``` `reveal` (experimental) chooses how a found tool becomes callable. With `redefine` (the default), its full schema replaces the placeholder in the tool list from the next step. With `in_result`, the tool list never changes: the model calls the tool using the schema the search returned, and every call is still checked against the tool’s real schema before it runs. On models that cannot carry tool changes inside the conversation, `in_result` keeps the prompt cache through a search. Some models call badly against a placeholder schema: in our tests Muse Spark sent numbers and objects as strings and never recovered, while GPT-6 Luna and Mistral Large 4 called as well as with `redefine`. Use it only with a model you have checked. ### Benchmarks Deferral only touches how tool *parameter schemas* reach the model, names and descriptions still go out in full, so the savings scale with how many tools an agent carries and how rich their schemas are. Measured on a representative 19-tool generic-agent surface (file, shell, web-fetch, session, storage, todo, time, scheduling, and subagent tools, plus `tool_search` itself), comparing the serialized tool list the driver sends to the model **with and without** deferral on the first turn: | Metric | Full schemas | Deferred (first turn) | Saving | | --------------------------- | ------------------------- | ----------------------- | --------------- | | Tool list sent to model | \~9.1 KB (\~2,270 tokens) | \~3.0 KB (\~740 tokens) | **67% smaller** | | Parameter-schema bytes only | \~7.2 KB | \~1.0 KB | **86% smaller** | Token figures use the \~4-chars-per-token rule of thumb for JSON. 18 of the 19 tools were deferred (`tool_search` keeps its schema). Net savings grow with tool count: an agent with dozens of MCP tools defers proportionally more. Reproduce this benchmark with: ```bash cargo test -p everruns-core --features builtins --lib benchmark_prompt_size_reduction -- --nocapture ``` The trade-off is one extra `tool_search` round-trip per deferred tool before its first use; for many-tool agents the upfront token savings dominate. ### Limitations * **Server-executed tools**: the search reads schemas from the worker-side tool registry. This includes built-in tools and MCP server tools (MCP tools are registered as first-class registry tools). Client-side tools that are not registered worker-side are not returned by `tool_search` (their stripped definition is still sent so the model knows they exist). * **Extra round-trip**: loading a schema costs one `tool_search` call before the first use of a deferred tool. The token savings outweigh this for agents with many tools. ## See also * [OpenAI Tool Search documentation](https://platform.openai.com/docs/guides/tool-search) * [Anthropic tool search tool documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool) * [Capabilities Overview](https://everruns.com/docs/capabilities/) --- # Tools in Shell > Call an agent's tools, MCP servers included, from the Bashkit shell with one tools command, so one script can chain several calls and return only what matters. Source: | | | | -------------- | ---------------------------------------------------------------------- | | **ID** | `tools_in_shell` | | **Category** | Execution | | **Risk** | High, assignment requires an org **Admin** | | **Depends on** | [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/) | | **Rollout** | Experimental; adding the capability is the opt-in | Tools in Shell adds a `tools` command inside the [Bashkit Shell](https://everruns.com/docs/capabilities/bashkit-shell/). In the default `cli` mode, eligible operations move out of the model’s direct tool list. `hybrid` mode keeps those operations available both through the shell and as native tools, with native schemas eager by default. To defer optional native schemas, also enable bounded `tool_search`. One script can call several tools, filter results with `jq`, and print only what the model needs: ```bash tools github list-pulls '{"repo":"acme/api","state":"open"}' \ | jq -r '.[] | select(.draft | not) | .number' \ | while read n; do tools github get-pull "repo=acme/api" "number=$n" | jq -c '{number, title, mergeable}' done ``` ## The `tools` command | Command | What it does | | ----------------------------------------------------- | -------------------------------------------------------------- | | `tools --help` | Lists MCP servers (with their tool counts) and the other tools | | `tools --help` | Lists one MCP server’s tools | | `tools --help`, `tools --help` | Shows the tool’s input schema | | `tools search ` | Finds tools by name and description | | `tools '{...}'` | Calls an MCP tool | | `tools '{...}'` | Calls any other tool | ### Surface mode The default `mode: "cli"` routes eligible operations through the shell. Set `mode: "hybrid"` to keep the CLI route while allowing native discovery and calls. Hybrid mode alone keeps native schemas eager. If `tool_search` is also configured with `bounded: true`, it can reveal optional native schemas within its configured limits; eager owner-required schemas remain visible. The shell source inventory is available from `tools --help` and does not change the static Bash tool description. ```json { "ref": "tools_in_shell", "config": { "mode": "hybrid" } } ``` The CLI and bounded native search use the same authorized, server-aware index. Legacy native `tool_search` remains unchanged unless configured with `bounded: true`. See [Large MCP catalogs](https://everruns.com/docs/features/large-mcp-catalogs/) for discovery bounds, search configuration, and cache and authorization behavior. MCP tools are grouped by server (`mcp_github__list_pulls` is `tools github list-pulls`); every other tool is a top-level command (`web_fetch` is `tools web-fetch`). Hyphens and underscores are interchangeable. The list is rebuilt on every shell call, so an MCP server added during a session shows up on the next one. **Input** is the same JSON object the tool takes as a direct call. It can come from stdin (`jq -n '{repo: "a/b"}' | tools github list-pulls`, or `-`), from a JSON argument, or from `key=value` and `--key value` pairs, which merge over the JSON. `--flag` alone is `true`. A value is read as JSON unless the tool’s schema says the key is a string, so `number=7` is a number and `repo=42` stays text. **Output** is the tool’s result on stdout: a text result as is, anything else as JSON. Images a tool returns are saved under `tool-images/` in the working directory, and stderr names the files. **Errors** are one JSON line on stderr with exit code 1, so a script can branch on them: ```json {"error":{"code":"needs_approval","message":"...","retryable":false}} ``` | Code | Meaning | | --------------------- | ------------------------------------------------------------------------------------------------------- | | `unknown_command` | No such server or tool | | `invalid_input` | The input is not a JSON object or does not match the tool’s schema | | `tool_error` | The tool ran and failed | | `denied` | A guardrail or hook blocked the call | | `needs_approval` | The call needs a person’s approval; the script stops here (see [Approvals](#approvals)) | | `stopped` | An earlier call stopped the script, so this one did not run | | `connection_required` | The tool or its MCP server needs a connection the person has not made | | `call_limit` | More than 50 tool calls in one shell call | | `unavailable` | The command cannot run here, or a server could not load yet (`retryable` says whether a later step can) | ## Which tools move into the shell A tool moves behind `tools` when calling it only does something and returns data: MCP tools, integration tools, search and fetch, platform and data tools. These stay direct tool calls: * the `bash` and `lua` tools themselves; * tools that pause or shape the turn: `ask_user`, approvals, `spawn_agent`, session tasks, `write_todos`, and client-side tools; * tools whose result the model must see as an image, such as screenshots, `read_file`, `computer` and `browser`; * structured file editing (`write_file`, `edit_file`); * tools listed in the `keep_visible` config. MCP servers set to “Load tools on demand” move behind `tools` too. `tools --help` lists them as `(not loaded)`; the first command that names one, such as `tools docs --help` or `tools docs search-docs q=refunds`, or a `tools search` that matches deferred server descriptions, loads its tools inside the same shell call. One `tools search` loads at most eight matching deferred servers; the others stay `(not loaded)` for a later search. A load adds that server’s tools atomically and respects the combined 10,000-tool/32 MiB shell catalog limit. Search, help and calls use only tools in the current turn’s visible scope, and loaded child tools retain the scope of their server placeholder. From the next step on a loaded server is listed like any other. Every call from a script goes through the same checks as a direct call: the turn’s guardrails and hooks run before it, the tool’s schema is checked, and the post-tool hooks see the result before the script does. ## Approvals Approval-gated and destructive tools are reachable from the shell too, and [Tool Approval](https://everruns.com/docs/capabilities/tool-approval/) judges each call from a script the same way it judges a direct call. Most scripts never ask: reads, searches, and tools a person already allowed “always” just run. Many MCP tools say nothing about whether they change anything. When the deployment has a decision service configured, such a tool is rated once the first time a script calls it: if it looks like it changes or deletes something outside the session, Tool Approval treats it as destructive and asks before it runs. The approval card then says the tool declares nothing about its risk and only looks like it changes things. A rating only ever adds a question; it never removes one, and tools that declare their own risk are not rated. An agent can turn ratings off with the `rate_unlabeled_tools` setting; such tools are then judged by what they declare, which is nothing, so in Tool Approval’s `normal` mode they run without asking. When a call written out in full in the script, such as `tools github delete-branch branch=fix-x`, needs a person’s answer, the script does not start at all: the `bash` result says so (`"before_start": true` under `stopped`, `done` is empty), the person is asked about that call, and after they answer the agent can run the same script again. Calls whose input is built while the script runs, or that read their input from stdin, are checked as they run instead. To see what a script would do before running it, pass it to `tools plan`. It runs nothing and prints each `tools` call it can see, with its input and risk: ```bash tools plan <<'EOF' tools github list-pulls state=open tools github delete-branch branch=fix-x EOF ``` ```json { "calls": [ {"tool": "tools github list-pulls", "input": {"state": "open"}, "risk": "read_only", "where": "script"}, {"tool": "tools github delete-branch", "input": {"branch": "fix-x"}, "risk": "needs_approval", "why": "destructive", "where": "script"} ], "complete": true } ``` `risk` is `read_only`, `changes` (runs without asking), `needs_approval`, `blocked`, or `checked_at_run_time` when the input is built while the script runs. A `needs_approval` call carries `why`, the reason the approval card will give: `destructive`, `open_world`, `mutating`, `policy`, or `rated_changes` when the tool declares nothing and was rated as changing things. `complete` is `false` when the script hides calls from reading, for example with `eval`. The agent uses it to describe a script accurately before asking a person about it. When a call needs a person’s answer while the script runs, it is not made and the script stops there. Nothing after it runs, and the script is never resumed or run again, because part of its work is already done and may not be safe to repeat. The `bash` result reports what happened, and the person is asked about the stopped call in the same step: ```json { "exit_code": 1, "success": false, "tools": { "done": [ {"tool": "tools linear create-issue", "input": {"title": "Flaky test"}, "ok": true, "result": {"id": "EVE-1201"}} ], "read_only_calls": 3, "stopped": { "reason": "needs_approval", "approval": "requested", "call": {"tool": "tools github delete-branch", "input": {"branch": "fix-x"}} }, "not_reached": "the stopped call and everything after it; write a new script for the rest" } } ``` `done` lists every call that may have changed something; read-only calls are counted. After the person answers, the agent writes a new script for what is left. A one-off approval covers that exact call (the tool and its input) once, so the new script can make it. The same report appears when a script stops at the call limit, or exits with an error after changing something. ## In the session timeline The model sees one `bash` call. Each tool the script called through `tools` is also recorded in the session as a [`tool.nested_call`](https://everruns.com/docs/event-reference/) event under that `bash` call, with its command, a short preview of its input, whether it completed, failed, was refused or stopped the script for approval, and how long it ran. The chat shows these as rows under the shell call. They never reach the model. ## Saved scripts An agent can keep a script it wrote and run it again later as one command: ```bash cat <<'EOF' | tools scripts save triage-prs --description 'Label new pull requests.' \ --input-schema '{"type":"object","properties":{"repo":{"type":"string"}},"required":["repo"]}' repo=$(jq -r .repo) tools github list-pulls repo="$repo" state=open | jq -r '.[].number' | while read -r n; do tools github add-labels repo="$repo" number="$n" labels='["triage"]' done EOF tools scripts # list the agent's saved scripts tools scripts triage-prs repo=a/b # run one ``` * The input is checked against the script’s schema and arrives on stdin as JSON; what the script prints is its result. * A saved script runs with the tools and identity of the agent turn that runs it, and its `tools` calls follow the same rules: approvals, guardrails, and the 50-call limit of the shell call it runs in. A call that needs approval stops the caller’s script too. * Its shell has the shell builtins and `tools`; `curl` and the `everruns` command are not available inside it. * Saved scripts can call each other, up to four deep. * Saving needs the `manage_scripts` setting. Every agent with the capability can run its saved scripts. Scripts are also managed through the `/v1/agents/{agent_id}/scripts` API and the `everruns agents scripts` command. * A schedule or webhook [trigger](https://everruns.com/docs/features/agent-triggers/#run-a-saved-script) can run a saved script without a model call. ## Tool search In the default `cli` mode, Tools in Shell replaces tool search. When both are enabled, the tool search capabilities (`tool_search`, `auto_tool_search`, `openai_tool_search`, `claude_tool_search`) contribute nothing. In `hybrid` mode, bounded `tool_search` can reveal native schemas while Tools in Shell provides the same operations through `tools`. See [Large MCP catalogs and tool surfaces](https://everruns.com/docs/features/large-mcp-catalogs/) for the shared registry model. [Agent Checks](https://everruns.com/docs/features/agent-checks/) report a redundant capability as a `capabilities.superseded` suggestion when it is not active for the selected mode. ## Configuration ```json { "capabilities": [ { "ref": "tools_in_shell", "config": { "mode": "cli", "keep_visible": ["web_fetch"] } } ] } ``` | Field | Type | Default | Meaning | | ---------------------- | ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mode` | string | `cli` | `cli` routes eligible tools through the `tools` command; `hybrid` also retains native tool discovery where configured. | | `keep_visible` | string array | `[]` | Tools the model can still call directly. They stay callable from the shell too. | | `manage_scripts` | boolean | `false` | Let the agent save scripts with `tools scripts save`. | | `rate_unlabeled_tools` | boolean | `true` | Ask the decision service whether a tool that declares nothing about its risk changes things, and ask for approval before it if so. Off: such tools run without asking in Tool Approval’s `normal` mode. | --- # Auto-Continue After Usage Limit > When an LLM subscription/plan usage limit is reached, automatically resume the interrupted work shortly after the limit resets. Source: | | | | ---------------- | --------------------------- | | **ID** | `usage_limit_auto_continue` | | **Category** | Core | | **Features** | None | | **Dependencies** | None | | **Risk** | Low | Some providers cap usage per subscription window rather than per minute. When a plan usage limit is hit, for example the ChatGPT/Codex `429` `usage_limit_reached` response, the turn fails and the session goes idle until the limit resets, often hours later. This capability makes the session resume on its own once the window clears, so long-running work is not silently stranded. It contributes **no tools**. The behavior is encapsulated behind a reusable platform boundary, the capability supplies an *LLM error hook* (an in-process capability hook, the same family as tool-call hooks and message filters) that the agent runtime invokes generically when a turn fails with a terminal error. The runtime has no special-casing for usage limits; any capability can provide the same kind of error-recovery hook. ## How It Works 1. **Decision**: The provider error is classified as `provider_usage_limit_reached`, which captures the absolute reset time (`resets_at`, unix seconds) reported by the provider. This is driver-agnostic: any driver whose error body carries the `usage_limit_reached` wording is covered. 2. **Scheduling**: When the capability is enabled and a reset time is present, a one-shot session schedule is created to fire `delay_seconds` after the reset. When it fires, the configured `prompt` is injected as a user message and the interrupted work resumes. 3. **Message copy**: The user-facing error reads *“You’re out of LLM usage limits. Your usage limit resets at \