Agent manifest
The tools vocabulary, what each key grants and its permission gate, read scopes, limits, and how a draft test differs from a saved run.
An agent manifest is JSON or YAML with these top-level keys:
kind: agent
name: report-extractor
description: Extracts structured data from uploaded reports.
model: <a model from the org's catalog>
system: |
You extract ...
tools:
app_files: [report-console]
app_data_write: [report-console]
limits:
max_tokens_total: 2000000Anything else is rejected.
Three things that are not manifest keys:
visibilityis a sibling field. Set it with--visibility org|personaloncreate/update/test.triggers/ cron: a schedule is a separate resource under the agent.input_schemais not supported. Agent input is free-form:input_jsonreaches the model unvalidated, and thesystemprompt is the input contract.
The CLI has no local schema validator. create / update / test send the manifest
straight to the API. Treat server validation and ratification warnings as authoritative.
Confirm the live shape with railcode agent pull on an existing agent.
tools keys
| Key | Type | Grants | Permission gate |
|---|---|---|---|
saved_queries | string[] | query(name, params) | Must be a ratified saved query in the org |
connectors | {connector: endpoint[]} | connector(name, method, path, body) | Each connector:endpoint must be ratified |
docs | string[] | docs(connector), which reads that connector's stored docs | Connector must exist |
email | bool or {emails, domains} | email(to, subject, html/text, cc, bcc) | email grant (org default *); recipients restricted to the allowlist when one is set |
adhoc_sql | string[] | sql(connection, text, params): raw SQL, no firewall | connector grant, plus a ratification warning |
app_data | string[] (app slugs) | app_kv_get, app_kv_query, app_kv_count | can_access_app, the same bar as opening the app |
app_data_write | string[] (app slugs) | app_kv_set, app_kv_delete, publish_artifact_to_app | can_manage_app: the app's owner or an org admin only. Declaring it for an app you do not manage is a hard save failure |
app_files | string[] (app slugs; no wildcard) | search_app_files (metadata only) and load_app_file | can_access_app |
agent_kv | bool | agent_kv_get/set/query/delete against the agent's own private, cross-run store | None beyond holding the agent |
personal_connectors | string[] of toolkit names or toolkit:tool pairs | personal_tools(toolkit) and personal_call(toolkit, tool, args) | visibility: personal only. A save with this key on an org agent is a hard failure |
load_app_file(app, name) downloads one object into the sandbox at
/workspace/in/apps/{app}/{name}. It returns the local path plus metadata to the model, never
bytes, object keys, or storage URLs. Loading the same path again in one run is idempotent.
Tool slugs are lowercase and case-sensitive. Copy them from discovery output rather than guessing:
railcode connector list
railcode connector tools <name>
railcode query list
railcode db listA save that adds authority you do not hold fails with the missing operations named. Get the
grant first, or drop it from the manifest. personal_connectors is the one exception. There
is no resource for a third party to be granted, so the only save gate is
visibility: personal. Execution then uses the owner's connected account, and returns a 403
if it is not connected.
Read scopes
App KV and files hold three parallel scopes: shared, user, and role. Every app read
tool takes an optional scope argument (shared, the default; user, the principal's own;
or role:<role_id>). Results report the scope they were read from, so a key that exists in
more than one scope stays unambiguous. app_scopes_list(app) discovers which scopes the
agent may read.
The principal is a personal agent's owner. An org agent has no user principal, so it reads
shared only. Scope selection is authorized exactly like a human caller, with the admin
cross-scope override disabled on the agent path. So an agent can never reach another user's
scope.
Writes take no scope argument. Each agent writes to one fixed scope: shared for an org
agent, the owner's user scope for a personal one.
limits
| Field | Default | Max |
|---|---|---|
max_steps | 300 | 300 |
timeout_seconds | 1200 | 1200 |
max_tool_calls | 300 | 600 |
max_tokens_total | 150000 | 6000000 |
max_tokens_turn | 150000 | 200000 |
max_tokens_total is the cumulative run budget (input and output across all turns).
max_tokens_turn is the per-turn output ceiling. max_tokens is a legacy alias for
max_tokens_total.
Sizing them
Use the narrowest useful tool set, but size limits the other way. A run that exhausts any
cap dies as limit_exceeded and loses the work in flight. An unused ceiling costs nothing.
Limits are caps rather than reservations, so set them high.
Token usage is dominated by what flows through the model. Every turn resends the conversation, and every tool result lands in it.
- Light tasks (classify a record, draft a short reply, one saved-query lookup) fit the defaults.
- Document editing and file analysis use far more tokens than you expect. Loaded file
content, sandbox command output, and repeated re-reads all count against
max_tokens_total. A long rewritten document pushesmax_tokens_turn. Raisemax_tokens_totalinto the millions rather than leaving the 150k default. - If a test run ends
limit_exceededor stops atmax_steps, raise the ceiling first rather than trimming the task.
max_steps and timeout_seconds already default to their maximums. Tokens are the knob that
needs sizing.
Draft tests behave differently
railcode agent test runs a draft with no saved agent row, so persistent storage behaves
differently than under a saved run:
app_data_writeis simulated, not persisted.app_kv_set/app_kv_deleteare validated exactly as a saved run would be, then recorded into a per-run in-memory overlay. Within that same test run,app_kv_getreads the overlay first (read-your-writes, scoped to the one run).app_kv_query/app_kv_countstill compile to SQL over the live store and do not reflect the run's simulated writes.publish_artifact_to_appis validated and accepted but marks nothing, because a draft has no run-end artifact sink.agent_kvtools are omitted entirely, since there is no agent row to key that store on.
So an untouched store after test is expected. Verify persistence with agent create +
agent run.
Managed agents
Server-side AI with a code sandbox and durable, auditable runs. What they're for, what they can't do, and how they differ from the backend LLM.
Building an agent
Scope, author, test a draft, publish, verify what landed, and schedule, plus how to write a system prompt that survives revision.