# Agents Guide

## Overview

An agent in Teletraan is a persistent Claude Code session configured with a system prompt (`CLAUDE.md`), optional MCP servers (`.mcp.json`), and lifecycle hooks (`.claude/settings.json`). The conductor is the primary agent; you can create additional specialist agents that the conductor dispatches work to.

## Creating a New Agent

Use the `create-agent.sh` template as your starting point:

```bash
# Copy and customize the template
cp core/agents/create-agent.sh.template scripts/create-my-agent.sh
chmod +x scripts/create-my-agent.sh

# Edit it to set AGENT_NAME, INSTALL_PATH, etc.
$EDITOR scripts/create-my-agent.sh

# Run it
./scripts/create-my-agent.sh
```

The template creates a directory at `<installPath>/agents/<name>/` containing:

```
agents/my-agent/
├── CLAUDE.md           # System prompt and personality
├── .env                # Environment variables (API keys, secrets)
├── .mcp.json           # MCP server configuration
└── .claude/
    └── settings.json   # Hook configuration
```

Then start the agent:

```bash
cd <installPath>/agents/my-agent
claude --dangerously-skip-permissions
```

For a PM2-managed agent, add it to your ecosystem config:

```js
// ecosystem.config.js
{
  name: 'my-agent',
  script: 'claude',
  args: '--dangerously-skip-permissions',
  cwd: '<installPath>/agents/my-agent',
  env: { /* env vars */ }
}
```

## CLAUDE.md Requirements

Every agent must have a `CLAUDE.md` at its working directory root. At minimum it should define:

```markdown
# <Agent Name>

<One paragraph describing the agent's purpose and domain.>

## Capabilities

- What this agent can and cannot do
- Which tools it may call
- Which agents it may dispatch to

## Behavior

- Communication style
- How to handle ambiguous requests
- Error escalation rules

## Environment

- CHANNEL_URL: The channel server base URL
- ONE_CHANNEL_SECRET: Bearer token for channel server auth
```

Keep `CLAUDE.md` focused. Agents that try to do everything tend to do nothing well. The conductor's `CLAUDE.md.template` in `core/agents/conductor/` is a good reference.

## MCP Server Configuration

`.mcp.json` lists the MCP servers available to the agent. The channel server exposes an MCP interface so agents can read/write messages and tasks without making raw HTTP calls.

```json
{
  "mcpServers": {
    "channel-server": {
      "command": "node",
      "args": ["<installPath>/services/channel-server/dist/server.js", "--mcp"],
      "env": {
        "ONE_CHANNEL_SECRET": "<secret>"
      }
    }
  }
}
```

Available channel server MCP tools:

| Tool | Description |
|------|-------------|
| `get_messages` | Fetch messages from a conversation |
| `send_message` | Post a message to a conversation |
| `get_tasks` | List pending tasks for this agent |
| `update_task_status` | Mark a task in progress, complete, or failed |
| `post_status_event` | Emit a custom status event to the dashboard |

## Hook System

Hooks are shell commands that Claude Code runs at lifecycle events. Configure them in `.claude/settings.json`.

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "<installPath>/agents/my-agent/hooks/status-hook.sh pre $CLAUDE_TOOL_NAME"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "<installPath>/agents/my-agent/hooks/status-hook.sh post $CLAUDE_TOOL_NAME"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "<installPath>/agents/my-agent/hooks/session-start.sh"
          }
        ]
      }
    ]
  }
}
```

### status-hook.sh

Posts PreToolUse and PostToolUse events to the channel server `/status` endpoint so the dashboard can display real-time agent activity.

```bash
#!/usr/bin/env bash
PHASE="$1"          # "pre" or "post"
TOOL_NAME="$2"      # e.g. "Bash", "Read", "Edit"

curl -s -X POST "${CHANNEL_URL}/status" \
  -H "Authorization: Bearer ${ONE_CHANNEL_SECRET}" \
  -H "Content-Type: application/json" \
  -d "{\"phase\":\"${PHASE}\",\"tool\":\"${TOOL_NAME}\",\"agent\":\"${AGENT_NAME}\"}"
```

### session-start.sh

Fetches recent conversation history from the channel server on session start so the agent has context if it was restarted.

```bash
#!/usr/bin/env bash
curl -s "${CHANNEL_URL}/conversations/main/messages?limit=50" \
  -H "Authorization: Bearer ${ONE_CHANNEL_SECRET}"
```

The output is injected into the agent's context by Claude Code.

## Agent Communication Patterns

### Conductor Dispatching to a Specialist

The conductor creates a task via MCP and waits for completion:

```
Conductor calls: update_task_status(taskId, "dispatching to my-agent")
Conductor posts: send_message(agentConversationId, "Please analyze X and return Y")
Conductor polls: get_tasks() until status == "complete"
```

### Specialist Reporting Back

The specialist processes the work and calls:

```
specialist calls: update_task_status(taskId, "complete", result)
specialist calls: send_message(conductorConversationId, "Analysis complete: ...")
```

### Telegram Bridge → Conductor

The Telegram bridge posts incoming messages directly to the channel server's conversation endpoint. The conductor's `session-start` hook picks them up on next prompt or the conductor polls periodically.

### Direct HTTP (for modules)

Service modules (calendar, status) are not Claude Code agents — they are HTTP services. They communicate by posting to the channel server:

```bash
curl -X POST $CHANNEL_URL/status \
  -H "Authorization: Bearer $ONE_CHANNEL_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"type":"alert","message":"Disk usage above 90% on host1"}'
```
