# Actors, Tools, and Skills — Reference

## Actor Configuration YAML

Actor YAML files go through a **two-phase preprocessing pipeline**:
1. **Jinja2 template rendering** (`{{ }}`, `{% %}`, `{# #}`) — before YAML parsing
2. **Environment variable interpolation** (`${VAR}`, `${VAR:default}`) — after YAML parsing

**Important**: `system_prompt` fields retain their Jinja2 templates for runtime evaluation (deferred rendering).

### Minimal Actor Example

```yaml
name: local/my-workflow

cleveragents:
  version: "3.0"
  default_actor: workflow_controller

actors:
  my_assistant:
    type: llm
    config:
      actor: openai/gpt-4
      temperature: 0.7
      system_prompt: |
        You are a helpful assistant.
        Current task: {{ context.task_description }}
    skills:
      - local/file-ops
      - local/git-ops

routes:
  main_workflow:
    type: graph
    entry_point: start
    nodes:
      - name: analyze
        type: agent
        agent: my_assistant
    edges:
      - source: start
        target: analyze
      - source: analyze
        target: end

context:
  global:
    task_description: "Default task"
```

### Actor Types

| Type | Description |
|------|-------------|
| `llm` | Simple LLM actor wrapping a built-in provider |
| `graph` | LangGraph composed of nodes (default for custom actors) |

### Graph Node Types

| Node Type | Description |
|-----------|-------------|
| `agent` | An actor node (references an actor by name) |
| `tool` | A tool node (direct, deterministic tool invocation) |

### Actor Jinja2 Filters

| Filter | Purpose |
|--------|---------|
| `yaml` | Serialize value to YAML string |
| `indent` | Indent text by N spaces |
| `sum` | Sum a numeric iterable |
| `selectattr` | Select attribute from sequence |

All standard Jinja2 filters also available (tojson, default, lower, upper, trim, join, replace, length, first, last, sort, unique, map, etc.)

### Context Precedence

Runtime context > plan context > session context > global_context from YAML

### Environment Variable Patterns

| Pattern | Behavior |
|---------|----------|
| `${VAR}` | Replaced with os.environ["VAR"]; ValueError if not set |
| `${VAR:default}` | Replaced with os.environ.get("VAR", "default") |

**Auto type coercion after substitution:**
- `"true"` / `"false"` → bool
- Digit-only strings → int
- Digits with single `.` → float
- Anything else → str

---

## Tool Configuration YAML

### Complete Tool YAML Structure

```yaml
cleveragents:
  version: "3.0"

tool:
  name: local/run-migrations
  description: "Run database migrations for the API service"

  source: custom  # custom | mcp | agent_skill | builtin

  # Resource bindings — what resources this tool needs
  resources:
    db:
      type: local/database
      access: read_write
      required: true
      description: "Target database for migrations"

  input_schema:
    type: object
    properties:
      direction:
        type: string
        enum: [up, down]
      count:
        type: integer
        default: 1
    required: [direction]

  capability:
    writes: true
    write_scope:
      resource_slots: [db]
    checkpointable: true
    checkpoint_scope: transaction  # file | transaction | commit | snapshot
    side_effects: [schema_mutation]
    read_only: false
    environment:          # optional: tool environment preferences
      required: container # container | host (required = fail if wrong env)
      # preferred: container (preferred = hint, but run wherever router places)
      # specific: local/api-dev (route to specific named resource)

  code: |
    import subprocess
    direction = params["direction"]
    count = params.get("count", 1)
    db = ctx.resources["db"]   # Access the bound resource
    result = subprocess.run(
        ["alembic", direction, str(count)],
        capture_output=True, text=True, cwd=db.sandbox.root
    )
    return {"stdout": result.stdout, "returncode": result.returncode}
```

### MCP Tool Example

```yaml
tool:
  name: local/create-github-issue
  source: mcp
  mcp_server:
    command: "npx @anthropic/mcp-github"
    env:
      GITHUB_TOKEN: "${GITHUB_TOKEN}"
    tool_name: create_issue  # tool name as exposed by MCP server
  capability:
    writes: true
    checkpointable: false
```

### Agent Skill Tool Example

```yaml
tool:
  name: local/deploy-staging
  source: agent_skill
  agent_skill:
    path: ./skills/deploy-to-staging
    sandbox_policy: container
    allowed_tools: ["Bash(docker:*)", "Bash(kubectl:*)", "Read"]
  capability:
    writes: true
    checkpointable: false
    side_effects: [deploy, infrastructure]
```

### Validation YAML (Tool subtype)

```yaml
cleveragents:
  version: "3.0"

validation:  # Use 'validation' key (not 'tool')
  name: local/check-test-coverage
  description: "Verify test coverage meets threshold"
  mode: required   # required | informational

  input_schema:
    type: object
    properties:
      threshold:
        type: number
        default: 97

  # Optional: wrap an existing Tool
  # wraps: local/some-tool
  # transform: |
  #   # Python code to transform tool output into {passed, message, data}

  code: |
    threshold = params.get("threshold", 97)
    coverage = run_coverage_check()
    return {
        "passed": coverage >= threshold,
        "message": f"Coverage: {coverage}% (threshold: {threshold}%)",
        "data": {"coverage": coverage, "threshold": threshold}
    }
```

Note: Validation always has `writes: false`, `checkpointable: false` — these cannot be overridden.

---

## Skill Configuration YAML

```yaml
cleveragents:
  version: "3.0"

skill:
  name: local/my-devops-toolkit
  description: "Tools for database operations and API validation"

  # Named tool references
  tools:
    - local/run-migrations
    - name: local/validate-api-compat
      override:  # optional override at point of use
        capability:
          human_approval_required: true

  # Inline anonymous tools (same format as tool YAML body)
  anonymous_tools:
    - description: "One-off cleanup for this project"
      input_schema:
        type: object
        properties:
          table: {type: string}
      capability:
        writes: true
        checkpointable: true
      code: |
        # Python code
        return {"cleaned": count}

  # Include other skills (imports all their tools)
  includes:
    - name: local/base-devops
      tool_overrides:  # override specific tools from the included skill
        - tool: local/dangerous-operation
          override:
            capability:
              human_approval_required: true
```

### Skill Composition Rules

1. Named tool references → tool available for LLM tool-calling
2. Anonymous tools → inline, not registered, not reusable
3. Includes → inherits all tools from included skill (transitively)
4. Tool overrides in includes → shallow-merged, never persist to registry
5. Only `capability` and `description` can be overridden (never `input_schema`)

---

## LSP Integration

LSP servers provide language intelligence to actors as callable tools.

### What LSP Provides to Actors

| LSP Capability | Exposed as Tool |
|----------------|----------------|
| Diagnostics | `lsp/diagnostics` |
| Hover (type info) | `lsp/hover` |
| Go-to-definition | `lsp/definition` |
| Completions | `lsp/completions` |
| References | `lsp/references` |
| Rename | `lsp/rename` |
| Code actions | `lsp/code-actions` |

### LSP Server Configuration YAML

```yaml
cleveragents:
  version: "3.0"

lsp:
  name: local/python-lsp
  language: python
  command: pylsp
  args: []
  env: {}
  initialization_options: {}
```

### Actor LSP Binding (in actor YAML)

```yaml
actors:
  python_analyzer:
    type: llm
    config:
      actor: anthropic/claude-3-opus
    skills:
      - local/file-ops
    lsp_bindings:
      - lsp_server: local/python-lsp
        languages: [python]
        # OR: bind by language only (auto-select server for language)
        # languages: [python]
        # OR: auto-detect based on project resource languages
        # auto_detect: true
```

### LSP Behavior

- LSP servers start when actor activates, stop when actor deactivates
- Diagnostics and type annotations automatically injected into ACMS hot context
- Different graph nodes can have different LSP bindings
- `LSPRuntime` manages server lifecycle, workspace mapping, file synchronization

### Key Commands

```bash
agents lsp add --config ./lsp/python-lsp.yaml
agents lsp list [--language python]
agents lsp show local/python-lsp
agents lsp serve [--log-level INFO]  # start LSP relay service
agents lsp remove local/python-lsp
```
