Agents
What an agent is, how it's configured, and how a job runs.
An agent is a named, persistent AI persona you create in the dashboard. The catalog ships skills and connectors — never agents. Every agent comes from you.
Configuration
| Field | What it does |
|---|---|
| Name / slug / avatar | UI identity, and the handle orchestrators use to delegate |
| System prompt | the Markdown injected at the top of every job |
| Model | any configured provider key — each agent picks its own |
| Skills | inject guidance and unlock gated built-in tools |
| Connectors | OAuth / API-key integrations (Gmail, Notion, Airtable…) |
| MCP servers | HTTP or stdio servers whose tools are namespaced per job |
| Workspaces | filesystem paths the agent can read and write |
| Channels | optional connections for inbound + outbound messages (Telegram, Discord, Slack, WhatsApp) |
| Role | agent (worker), orchestrator, or system (reserved) |
How a job runs
A job is one unit of work — a chat message, a cron tick, an API call, or an inbound Telegram message. The runner loads the agent's config, builds the tool whitelist and system prompt for that job, then enters the LLM loop.
The tool whitelist is computed per job — there are no defaults
The runner unions the always-on builtins with every tool unlocked by the agent's assigned skills
(via requiredBuiltins), its connectors, and its MCP servers. An agent with no skills gets only
the always-on set. A tool that isn't in the whitelist is never offered to the model.
Always-on built-in tools
Every agent gets these tools on every job, regardless of skills (ALWAYS_ON_TOOLS in packages/tools/src/builtin/index.ts). The count used to be written out here and went stale the first time a tool was added, so it is gone: the built-in tools reference is generated from the runtime and is the one that counts.
return_result— set the job's final answer.ask_user— stop and ask you a question the agent cannot answer on its own.skill_view— read the full content of an assigned skill on demand.list_models— list the models available to this agent.list_schedules— list the agent's cron automations.save_memory,query_memory,mark_memory_helpful,mark_memory_outdated— the memory tools (write, recall, and rate persistent facts).search_history— full-text recall across all of this workspace's past jobs and conversations, including ones run by other agents.nodal_docs— search this documentation: what Nodal-Agents can do and where in the dashboard it is done. Offline, no model, no network.web_search— search the web, using the agent's configured Tavily/Firecrawl provider if any, otherwise a free best-effort search.dashboard_publish— publish the agent's substantive output to the dashboard (it becomes the job'sresult).file_read,file_write,file_edit,file_list,file_search— read and edit files in the agent's workspaces.register_project— declare a folder it worked in as a project.declare_verification— declare the commands that prove what it just built, so Nodal runs and records them. Requires approval by default, exactly likerun_command. See Proof.
The complete registry — always-on, skill-gated, grant-gated and channel tools — is generated from the runtime itself on the built-in tools reference.
Anti-loop guards
Every job is bounded. When a limit is hit the job fails loud with a clear code — never a silent fallback.
| Guard | Limit |
|---|---|
| Max turns per job | 50 |
| Max tool calls per turn | 50 |
| Max self-chain resumes | 15 |
| Max delegation depth | 3 |
| Max total tokens per job | 1,500,000 |
| Max cost per job | $2.00 |
| Max consecutive delivery-only turns | 3 |
| Max identical no-progress turns | 12 |
Autonomy
Tool calls with real-world side-effects (like run_command) can require approval before they run. You configure rules per-agent or per-tool:
- Run without asking — run immediately.
- Ask for approval — pause the job and wait for your approval in the dashboard.
- Block — never allow this tool.
Built-in tools can be restricted too
The always-on built-ins are listed on the agent's Approvals tab under Built-in tools, with the same three settings as every other tool.
Before this, they were on and unlisted, and the only way to restrain one was the read-only preset — which blocks five write tools at once. There was no way to say "may read files, may not search the web". Now there is.
One tool cannot be blocked: return_result, which is how a job reports that it finished or got stuck. Blocking it would leave every job of that agent unable to end, with no way to tell you why. The dashboard says so on the row rather than simply refusing.
Blocking a tool leaves it visible to the agent and refuses the call, telling the model the restriction is deliberate. That wording is the point: an agent told "this is not available to you" reports the limit back to you, while an agent that simply sees a failure tends to try to work around it.
An agent does not recompose its own team
A per-agent setting, may_change_team, decides whether an agent may use the three meta-tools that change who is on its team: create_agent, attach_agent and detach_agent.
It is off by default, and the migration turned it off for every agent that already existed. With it off, those three are not in the list the runner computes for the job, so the model never sees them — this is not a refusal at call time.
Two gates, deliberately stacked: a ROOT grant says what the workspace allows, and this setting says whether this agent may rearrange its own team. The setting can only take away; it never adds a tool a disabled grant already refused.
The workspace brake
Settings → Safety → Auto-run brake pauses every auto-run at once, in every auth mode.
While it is engaged, any auto_approve rule on a code-execution tool is dropped for the job, and an explicit require_approval rule is injected so a blanket wildcard cannot sweep the tool back in. Nothing is deleted from the database: releasing the brake re-arms the rules exactly as they were. The brake also outranks the agent's autonomy level, so fully_autonomous cannot auto-approve past it.