> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reasonos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent SDK

> Extend the RBS coding agent with custom tools, prompts, teammate roles, subagents, and slash commands — all defined in the RBS DSL

# Agent SDK

The Agent SDK lets you customize and extend the RBS coding agent with project-specific capabilities. Define custom tools, system prompts, teammate roles, subagents, and slash commands — all in your `WORKSPACE.rbs` or `BUILD.rbs` files using the RBS DSL.

## Overview

| Extension          | API                                   | Purpose                                        |
| ------------------ | ------------------------------------- | ---------------------------------------------- |
| **Tools**          | `native.define_agent_tool()`          | Custom actions the agent can take.             |
| **Prompts**        | `native.define_agent_prompt()`        | Specialized system prompts with linked tools.  |
| **Subagents**      | `native.define_agent_subagent()`      | One-shot specialist agents for isolated tasks. |
| **Teammate roles** | `native.define_agent_teammate_role()` | Reusable roles for multi-agent teams.          |
| **Skills**         | `native.define_agent_skill()`         | Slash commands for common workflows.           |

## Loading built-in tools

Load the built-in agent tools (Git status, Git log, file analysis, etc.) in your workspace:

```python theme={null}
# WORKSPACE.rbs
load("@rbs//agent/tools.rbs", "AGENT_TOOLS_LOADED")
```

## Custom tools

### Basic tool with a shell command

```python theme={null}
native.define_agent_tool(
    name = "list_processes",
    description = "List running processes on the system",
    shell_cmd = "ps aux | head -20",
)
```

### Tool with parameters

```python theme={null}
native.define_agent_tool(
    name = "search_code",
    description = "Search for a pattern in source files",
    attrs = {
        "pattern": attr.string(
            doc = "The regex pattern to search for",
            mandatory = True,
        ),
        "file_type": attr.string(
            doc = "File extension to search (e.g., 'py', 'java')",
            default = "",
        ),
    },
    shell_cmd = "rg '{pattern}' --type {file_type}",
)
```

### Tool with implementation function

For complex logic, use an implementation function with full `ctx` access:

```python theme={null}
def _analyze_file_impl(ctx):
    """Analyze a file and return statistics."""
    path = ctx.attr.path

    # Read file content
    content = ctx.file.read(path)
    if content == None:
        return ctx.output.error("File not found: " + path)

    # Calculate statistics
    lines = content.split("\n")
    line_count = len(lines)
    char_count = len(content)

    # Run additional analysis
    result = ctx.shell.capture(command = "wc -w " + path)
    word_count = result.strip().split()[0] if result else "0"

    return ctx.output.success(
        message = "File analyzed",
        data = {
            "path": path,
            "lines": line_count,
            "characters": char_count,
            "words": word_count,
        },
    )

native.define_agent_tool(
    name = "analyze_file",
    description = "Analyze a file and return statistics (line count, word count, etc.)",
    attrs = {
        "path": attr.string(
            doc = "Path to the file to analyze",
            mandatory = True,
        ),
    },
    implementation = _analyze_file_impl,
)
```

## The `ctx` object for tools

When using `implementation`, your function receives a `ctx` object with these modules:

### `ctx.attr` — Access parameters

```python theme={null}
def _my_tool(ctx):
    path = ctx.attr.path           # String attribute
    count = ctx.attr.count         # Integer attribute
    files = ctx.attr.files         # List attribute
    options = ctx.attr.options     # Dict attribute
```

### `ctx.file` — File operations

```python theme={null}
def _my_tool(ctx):
    content = ctx.file.read("path/to/file.txt")       # Read a file
    ctx.file.write("output.txt", "Hello World")        # Write a file
    exists = ctx.file.exists("config.json")            # Check existence
    files = ctx.file.glob("src/**/*.py")               # List files matching pattern
```

### `ctx.dir` — Directory operations

```python theme={null}
def _my_tool(ctx):
    entries = ctx.dir.list("src/")                     # List directory
    ctx.dir.create("output/reports")                   # Create directory
    exists = ctx.dir.exists("build/")                  # Check existence
    ctx.dir.delete("tmp/", recursive = True)           # Delete directory
```

### `ctx.shell` — Execute commands

```python theme={null}
def _my_tool(ctx):
    output = ctx.shell.capture(command = "git status --short")     # Capture output
    exit_code = ctx.shell.run(command = "make build")              # Run without capturing
    output = ctx.shell.capture(command = "npm test", cwd = "frontend/") # With working dir
```

### `ctx.path` — Path manipulation

```python theme={null}
def _my_tool(ctx):
    full_path = ctx.path.join("src", "main", "app.py")    # Join paths
    dir_name = ctx.path.dir("src/main/app.py")             # Get directory
    base = ctx.path.base("src/main/app.py")                # Get base name
    ext = ctx.path.ext("app.py")                           # Get extension
    abs_path = ctx.path.abs("relative/path")               # Absolute path
```

### `ctx.json` — JSON operations

```python theme={null}
def _my_tool(ctx):
    data = ctx.json.parse('{"name": "test", "count": 42}')    # Parse JSON
    json_str = ctx.json.stringify({"result": "success"})       # Serialize
    pretty = ctx.json.stringify(data, indent = 2)              # Pretty print
```

### `ctx.output` — Return results

```python theme={null}
def _my_tool(ctx):
    # Success with message and data
    return ctx.output.success(
        message = "Found 5 files",
        data = {"files": ["a.py", "b.py"], "count": 5},
    )

    # Error
    return ctx.output.error("File not found: " + path)
```

## Custom prompts

Create specialized system prompts with linked tools:

```python theme={null}
native.define_agent_prompt(
    name = "code_reviewer",
    system_prompt = """You are a code review expert. Your role is to:
1. Analyze code for bugs and issues
2. Suggest improvements and best practices
3. Check for security vulnerabilities
4. Ensure code follows project conventions

Always explain your reasoning and provide specific examples.""",
    tools = [
        "read_files",
        "code_search",
        "analyze_file",
    ],
)
```

## Custom subagents

Create subagent types for one-shot, isolated specialist tasks:

```python theme={null}
native.define_agent_subagent(
    name = "security_auditor",
    description = "Performs security analysis of code changes",
    when_to_use = "When reviewing code for security vulnerabilities",
    system_prompt = """You are a security auditor. Analyze the provided code for:
1. SQL injection vulnerabilities
2. XSS attack vectors
3. Authentication bypass risks
4. Sensitive data exposure
5. Dependency vulnerabilities

Report findings with severity levels and remediation steps.""",
    tools = ["read_files", "code_search", "run_terminal_command"],
    read_only = True,
)
```

| Parameter       | Type        | Required | Description                                  |
| --------------- | ----------- | -------- | -------------------------------------------- |
| `name`          | string      | Yes      | Unique subagent name.                        |
| `description`   | string      | Yes      | What the subagent does.                      |
| `when_to_use`   | string      | No       | Guidance for when to invoke this subagent.   |
| `system_prompt` | string      | Yes      | System prompt for the subagent.              |
| `tools`         | string list | No       | Tools the subagent can use.                  |
| `read_only`     | bool        | No       | If `True`, the subagent cannot modify files. |

## Custom teammate roles

Create reusable roles for [multi-agent teams](/agent-builder#multi-agent-teams):

```python theme={null}
native.define_agent_teammate_role(
    name = "ml_engineer",
    description = "Machine learning specialist for model training and optimization",
    system_prompt = """You are an ML engineer specializing in:
- PyTorch and distributed training (DDP, FSDP)
- Model architecture design and optimization
- Training pipeline development
- Hyperparameter tuning and experiment tracking

Always validate training code with small samples before full runs.""",
    tools = ["read_files", "write_file", "run_terminal_command", "code_search"],
    capabilities = ["model_training", "data_pipelines", "optimization"],
)
```

| Parameter       | Type        | Required | Description                                 |
| --------------- | ----------- | -------- | ------------------------------------------- |
| `name`          | string      | Yes      | Role name (used in `spawn_teammate`).       |
| `description`   | string      | Yes      | What this role specializes in.              |
| `system_prompt` | string      | Yes      | System prompt for teammates with this role. |
| `tools`         | string list | No       | Tools available to this role.               |
| `capabilities`  | string list | No       | Declared capabilities for role matching.    |

Custom roles are automatically available when spawning teammates:

```bash theme={null}
rbs agent "Spawn an ml_engineer teammate to optimize the training pipeline"
```

## Custom skills (slash commands)

Create slash commands for common workflows:

```python theme={null}
native.define_agent_skill(
    name = "deploy",
    description = "Deploy the application to staging or production",
    usage = "/deploy [staging|production]",
    prompt = """Deploy the application. Steps:
1. Run all tests
2. Build the production binary
3. Push to the container registry
4. Apply Kubernetes manifests
5. Verify the deployment is healthy

Target environment: {args}""",
    tools = ["run_terminal_command", "read_files"],
)
```

| Parameter     | Type        | Required | Description                                   |
| ------------- | ----------- | -------- | --------------------------------------------- |
| `name`        | string      | Yes      | Skill name (becomes a `/command`).            |
| `description` | string      | Yes      | What the skill does.                          |
| `usage`       | string      | No       | Usage example.                                |
| `prompt`      | string      | Yes      | Prompt template. Use `{args}` for user input. |
| `tools`       | string list | No       | Tools the skill can use.                      |

## Long-term memory

The coding agent has a **persistent memory system** that remembers things across sessions — design patterns, user corrections, file-specific notes, and architectural decisions. Memory is stored as human-editable markdown in `.rbs/memory/`.

### How memory works

```
Session Start
  ├─→ Load rules (.agent-rules/, .cursorrules, etc.)
  ├─→ Load general memory (.rbs/memory/general.md)
  └─→ Agent loop
        ├─→ read_files("src/api.py")
        │     → File content returned
        │     + .rbs/memory/src/api.py.md (auto-injected)
        │     + .rbs/memory/src/_package.md (auto-injected)
        ├─→ Agent discovers pattern → memory_save(...)
        ├─→ User corrects agent → agent saves correction
        └─→ Session ends → memory persists
```

### Memory file format

Memory files are plain markdown, stored alongside your code:

```
.rbs/memory/
├── general.md                   # Project-wide notes
├── src/
│   └── api.py.md                # Notes about src/api.py
└── services/
    └── auth/
        ├── _package.md          # Notes about the auth package
        └── handler.py.md        # Notes about handler.py
```

Each entry uses `## [m-xxxxxxxx]` headers:

```markdown theme={null}
# General Project Memory

## [m-abc12345] 2026-02-17 10:30
> Tags: architecture, convention

This project uses dependency injection throughout.
Never create singletons — pass dependencies through constructors.

## [m-def67890] 2026-02-17 14:15
> Tags: user-correction

User correction: Use interfaces for the repository pattern,
not concrete implementations.
```

### Memory tools

| Tool            | Description                            |
| --------------- | -------------------------------------- |
| `memory_save`   | Save a new memory entry.               |
| `memory_recall` | Recall memories for a file or package. |
| `memory_update` | Update an existing entry by ID.        |
| `memory_delete` | Delete a stale or incorrect entry.     |
| `memory_search` | Search across all memory files.        |
| `memory_list`   | List all stored memory files.          |

### Editing memory directly

Memory files are just markdown. You can read, edit, add, and delete entries directly in your editor — the agent respects your changes.

```markdown theme={null}
## [m-user0001] 2026-02-17 16:00
> Tags: convention

We use dependency injection throughout the project.
Never create singletons or global state.
```

## Complete example

```python theme={null}
# WORKSPACE.rbs
load("@rbs//agent/tools.rbs", "AGENT_TOOLS_LOADED")

# Custom tool: Check test coverage
def _coverage_check_impl(ctx):
    result = ctx.shell.capture(command = "rbs test //... --coverage")
    if result == None:
        return ctx.output.error("Failed to run tests")

    return ctx.output.success(
        message = "Coverage report generated",
        data = {"output": result},
    )

native.define_agent_tool(
    name = "check_coverage",
    description = "Run tests and check code coverage",
    implementation = _coverage_check_impl,
)

# Custom tool: Generate changelog
native.define_agent_tool(
    name = "changelog",
    description = "Generate changelog from recent git commits",
    attrs = {
        "since": attr.string(
            doc = "Git ref to start from (e.g., 'v1.0.0', 'HEAD~10')",
            default = "HEAD~10",
        ),
    },
    shell_cmd = "git log --oneline {since}..HEAD",
)

# Custom prompt for this project
native.define_agent_prompt(
    name = "project_assistant",
    system_prompt = """You are an assistant for this codebase.

Key conventions:
- Write tests for all new code
- Use dependency injection
- Update CHANGELOG.md for changes

When making changes, always run tests first.""",
    tools = [
        "read_files",
        "write_file",
        "str_replace",
        "run_terminal_command",
        "check_coverage",
        "changelog",
    ],
)

# Custom teammate role
native.define_agent_teammate_role(
    name = "data_engineer",
    description = "Data pipeline and preprocessing specialist",
    system_prompt = "You build efficient data loading and preprocessing pipelines.",
    tools = ["read_files", "write_file", "run_terminal_command"],
    capabilities = ["data_loading", "preprocessing", "augmentation"],
)

# Custom skill
native.define_agent_skill(
    name = "release",
    description = "Create a release",
    usage = "/release [version]",
    prompt = "Create release {args}: run tests, update changelog, tag, build, and publish.",
    tools = ["run_terminal_command", "read_files", "write_file"],
)
```

## Attribute types reference

| Type                 | Description         | Example              |
| -------------------- | ------------------- | -------------------- |
| `attr.string()`      | String value.       | `"hello"`            |
| `attr.int()`         | Integer value.      | `42`                 |
| `attr.bool()`        | Boolean value.      | `True`               |
| `attr.string_list()` | List of strings.    | `["a", "b"]`         |
| `attr.label()`       | Build target label. | `"//pkg:target"`     |
| `attr.label_list()`  | List of labels.     | `["//a:x", "//b:y"]` |
| `attr.string_dict()` | String dictionary.  | `{"key": "value"}`   |

All attribute types support:

* `doc` (string) — Description shown to the AI model.
* `mandatory` (bool) — Whether the parameter is required.
* `default` (any) — Default value.

## Best practices

1. **Clear descriptions** — Write descriptions that help the AI model understand when to use the tool.
2. **Document parameters** — Use `doc` for all attributes.
3. **Handle errors** — Always check for errors and return meaningful messages.
4. **Keep tools focused** — Each tool should do one thing well.
5. **Define roles for your team** — Create custom teammate roles matching your project needs.
6. **Use subagents for isolation** — Use read-only subagents for analysis tasks.
7. **Create skills for workflows** — Turn common multi-step workflows into slash commands.
