DocsConfigure
Profiles & workflows
Design how agents work in the Behaviors editor, and understand the plain JSON files behind it.
A single agent loop decides its own path. A workflow decides it for the agent: which steps run, what each may use, what must be verified, and what happens on failure. Each agent step runs under a profile that sets its instructions, tools, limits and completion checks.
Both are edited in the Behaviors tab and stored as plain JSON in your workspace:
| Kind | Location |
|---|---|
| Profiles | .rusty/profiles/<id>.json |
| Workflows | .rusty/workflows/<id>.json |
Note
Rusty ships with 12 profiles and 15 workflows, available in every project. Choose one from the Mode menu in Agent Mode. They are read-only, so they always stay in a known-good state. To change one, choose Customize a copy: you get your own editable copy, saved in your workspace. This page is about customizing and writing your own. To learn what the built-in ones do and how to run them, start with Workflows.
The Behaviors editor
Open Behaviors in the left rail. A switch at the top left toggles between Workflows and Profiles, and the list beside it shows what you have. The built-in workflows and profiles are tagged Built-in.
- The workflow view draws steps as nodes and their connections as edges. The buttons above the canvas add steps: Input, Agent, Verify and Output. Select a step or an edge to edit it in the inspector, drag from a step's right handle to another step to connect them, and drill into an agent step to see its profile.
- The profile view draws profiles as nodes, with
switch_profilerules drawn as edges between them. - Steps show the state of the latest run, such as succeeded or running, and a badge such as Last run cancelled summarizes it.
- Run in Agent Mode starts the selected workflow from Agent Mode, with that chat's model and tools. New workflow creates one.
- Edits are validated as you make them, and a step or profile with a validation problem is flagged.
- A dot marks unsaved changes, and the button at the top right reads Saved when everything is written.
For a built-in workflow the inspector is read-only and says Built into Rusty · available in every project, with Customize a copy at the top.
The workflow inspector
With nothing selected, the inspector at the right edits the workflow itself:
| Field | Meaning |
|---|---|
| Name and Description | How the workflow is listed and described. |
| Revision | A number you can bump as you change it. |
| Status | Draft, Published or Deprecated. |
| Optional limits | Budgets for a whole run. Leave a field empty for no limit. |
The optional limits are Steps, Total attempts, Duration (seconds), Model requests, Tool calls, Tokens and Cost (USD). You can also stop a running workflow at any time.
Because the documents are plain JSON, fields the editor does not know about survive a load and save. Use the JSON toggle in the inspector header to see and edit a document's raw JSON. Canvas positions are stored under metadata.editor.position, which the engine ignores.
Run a workflow
In Agent Mode, the Mode menu above the message box picks what the chat follows: Single agent, a Stage, a Workflow, or Auto. See Workflows for how to run one and how stages build on each other, and Auto flows for letting Rusty choose.
While a chat follows a workflow, the skill menu stays on build and reads tools set per step: each step's profile decides its tools.
Built-in profiles and workflows
The 12 built-in profiles (Research, Analyze, Plan, Architect, Debug, Build, Verify, Review, Security, Document, Refactor and Optimize) and 15 built-in workflows are described in Built-in workflows, including what each step can do. Their IDs start with rusty-ide.builtin.. Customize a copy to start from any of them.
Profiles
A profile describes what one agent step may do. This is the built-in Plan profile, trimmed. (In the app its ID is rusty-ide.builtin.plan; your own profiles use the IDs you give them.)
{
"schema_version": 1,
"id": "plan",
"revision": 3,
"name": "Plan",
"description": "Read-only investigation. Explores the workspace and produces a concrete plan.",
"status": "draft",
"instructions": {
"mode": "append",
"text": "Investigate the request and write an actionable implementation plan..."
},
"tools": {
"type": "allow_list",
"tools": ["read_file", "list_files", "search_codebase", "web_search", "web_extract", "report_progress", "ask_user_question"]
},
"rules": [
{
"id": "plan-read-only",
"on": "PreToolUse",
"when": { "tool": ["write_file", "run_command"] },
"do": { "deny": { "reason": "The plan step is read-only. Describe the change in the plan instead of making it." } }
}
],
"completion_gate": {
"checks": [
{
"id": "explored-first",
"require": { "calls": { "tool": ["read_file", "list_files", "search_codebase"], "gte": 1 } },
"feedback": "You have not looked at the code yet. Explore the relevant files before proposing a plan."
}
],
"max_continuations": 2,
"on_exhausted": "fail"
}
}
Profile fields
| Field | What it does |
|---|---|
id, name, description, revision, status |
Identity and bookkeeping. Built-in profiles have IDs starting with rusty-ide.builtin.. |
instructions |
Text added to the agent's instructions. mode: "append" adds to the base instructions. |
tools |
Which tools the step may use. { "type": "inherit" } keeps whatever the surrounding session allows. { "type": "allow_list", "tools": [...] } limits it to the named tools. |
tool_overrides |
Adjusts how a tool is described to the model, for example description_append to add a guideline to write_file. |
limits |
Optional turn and tool-call limits. Unset in the built-in flow. |
rules |
Event-driven rules that steer the agent. See below. |
completion_gate |
Checks the agent must satisfy before it is allowed to finish. See below. |
children |
Settings for subagents this step starts. { "type": "inherit" } is the default. |
Rules
A rule reacts to an event and takes an action.
{
"id": "build-failed-tool",
"on": "PostToolUseFailure",
"do": { "inject": { "text": "That tool call failed. Read the error and fix the cause; do not repeat the same call unchanged." } },
"max_fires": 8
}
| Part | Values |
|---|---|
on (event) |
RunStart, BeforeModelRequest, PreToolUse, PostToolUse, PostToolUseFailure, ProfileEntered |
when (optional filter) |
For example { "tool": ["write_file"] } to match specific tools, or { "turn": { "gte": 3 } } to match after a number of turns. |
do (action) |
inject, deny, ask, allow, stop_run, switch_profile, rewrite_args, rewrite_result |
max_fires |
Optional cap on how many times the rule can trigger. |
Which actions are valid depends on the event:
| Action | Effect | Valid on |
|---|---|---|
inject |
Adds guidance text to the conversation. | Any event |
deny |
Blocks the tool call, with a reason the agent sees. | PreToolUse |
ask |
Asks you first. | PreToolUse |
allow |
Allows the call to proceed. | PreToolUse |
rewrite_args |
Merges values into the call's arguments. | PreToolUse |
rewrite_result |
Edits a tool's result before the agent sees it. | PostToolUse, PostToolUseFailure |
stop_run |
Ends the run, with a reason. | Any event |
switch_profile |
Hands the run to another profile. | Any event except ProfileEntered |
Completion gates
A completion gate stops an agent from declaring victory too early. Each check has a require condition and a feedback message the agent receives when the check fails. The agent is sent back to keep working up to max_continuations times; if it still fails, on_exhausted: "fail" fails the step.
The built-in Build profile uses this to require that any edit is followed by a check:
{
"id": "checked-after-editing",
"require": {
"any": [
{ "calls": { "tool": "write_file", "eq": 0 } },
{ "since_last_call": { "of": "write_file", "called": ["run_command", "read_file"], "gte": 1 } }
]
},
"feedback": "You changed files but have not checked them since your last edit. Run the project's tests or type-check, or read the changed file back, then report."
}
In words: either no files were written, or since the last write the agent ran a command or read a file at least once.
Workflows
A workflow is a graph of steps. This is the shape of the built-in flow, abbreviated. Customize a copy starts you from exactly this:
{
"schema_version": 1,
"id": "plan-build-verify",
"name": "Plan, build, verify",
"status": "draft",
"nodes": [
{ "id": "input", "name": "Request", "type": "input" },
{
"id": "plan", "name": "Plan", "type": "agent",
"config": {
"instructions": "Investigate the request and write an actionable implementation plan...",
"tools": { "type": "inherit" },
"context_mode": "isolated_child",
"structured_output": "text",
"profile": { "id": "plan" }
},
"input_bindings": [
{ "target": "request", "source": { "type": "run_input", "pointer": "/request" } }
]
},
{
"id": "build", "name": "Build", "type": "agent",
"config": { "context_mode": "isolated_child", "structured_output": "text", "profile": { "id": "build" } },
"input_bindings": [
{ "target": "request", "source": { "type": "run_input", "pointer": "/request" } },
{ "target": "plan", "source": { "type": "node_output", "node_id": "plan", "pointer": "" } }
]
},
{
"id": "verify", "name": "Verify", "type": "agent",
"config": { "context_mode": "isolated_child", "structured_output": "text", "profile": { "id": "verify" } },
"input_bindings": [
{ "target": "request", "source": { "type": "run_input", "pointer": "/request" } },
{ "target": "plan", "source": { "type": "node_output", "node_id": "plan", "pointer": "" } },
{ "target": "build", "source": { "type": "node_output", "node_id": "build", "pointer": "" } }
]
},
{
"id": "output", "name": "Result", "type": "output",
"config": { "source": { "type": "node_output", "node_id": "verify", "pointer": "" } }
}
],
"edges": [
{ "id": "input-plan", "source": "input", "target": "plan", "condition": "on_success" },
{ "id": "plan-build", "source": "plan", "target": "build", "condition": "on_success" },
{ "id": "build-verify", "source": "build", "target": "verify", "condition": "on_success" },
{ "id": "verify-output", "source": "verify", "target": "output", "condition": "on_success" }
]
}
Steps
Step type |
Purpose |
|---|---|
input |
Receives the request that starts the run. |
agent |
Runs an agent, optionally under a profile. |
verify |
Validates a previous step's output against checks, for example a schema. |
output |
Picks which step's output becomes the workflow's result. |
Every agent step runs in a fresh, isolated session (context_mode: "isolated_child") that inherits your workspace, active model and permission policies. Steps hand work to each other as ordinary text or Markdown, not a fixed JSON schema. A finished workflow means the sequence finished, not that its review approved the implementation, so read the Verify step's verdict.
Inputs and edges
input_bindingssay where each named input to a step comes from: the run's input (run_input) or another step's output (node_output).edgesconnect steps.conditionison_successfor the normal path oron_failureto route a failure somewhere else.retryon a step sets a bounded number of attempts (max_attempts).
Limits and timeouts
Workflow budgets (see the inspector fields above), profile turn and tool-call limits, and step timeouts are all optional, and none is set in the built-in flow. The editor offers numeric fields for them, checkboxes for context, and a selector for the result source. Workflows written as raw JSON keep working through the advanced settings.
Choosing and switching flows
Two optional fields in a workflow's metadata (which the engine ignores) let Auto and flow switching work with it. The built-in workflows set them; your own can too.
"metadata": {
"route": { "when": "The user wants to understand how existing functionality works before deciding anything." },
"switch_to": ["diagnose", "security-audit"]
}
| Field | Meaning |
|---|---|
route.when |
When this workflow is the right one for a message, in a sentence or two. The decision model reads it. A workflow without it is never picked by Auto. |
switch_to |
Ids of the workflows this one may hand over to when flow switching is on. Use the workflow's id; for a built-in workflow, the id without rusty-ide.builtin.. A workflow without it never hands over. |
Whether a workflow can change files is not declared: Rusty reads it from the profiles its steps use. A workflow edits unless every agent step's profile either has an allow-list without write_file, or has a PreToolUse rule that denies write_file. Auto and flow switching ask before starting one that does.
The built-in workflows hand over only to the read-only stages. For example Plan, build, verify may hand over to Research & analyze, Debug & plan a fix or Security audit & fix plan.
Tips
Tip
Start from Customize a copy of the built-in flow rather than writing from scratch. Change a profile's instructions, add a
denyrule for a command you never want run, or tighten the tool allow-list, and watch how the next run behaves.
- Commit
.rusty/profiles/and.rusty/workflows/so your team shares the same behavior. - Keep completion-gate feedback specific. It is the message the agent acts on.
- Use
denyandaskrules for guardrails. See Permissions & safety.