# host.yaml Configuration

> Configure your hosted agent with a simple YAML file.

---

## Quick Start

`host.yaml` is generated by `co init` or `co create`. Edit it to customize your agent:

```yaml
# .co/host.yaml

summary: I translate text between 100+ languages
examples:
  - "Translate 'hello' to Spanish"
  - "What language is '你好' in?"

trust: careful
port: 8000
```

Then run your agent:

```python
host(create_agent)  # Reads .co/host.yaml
```

---

## File Location

```
your-project/
├── agent.py
└── .co/
    ├── host.yaml       # Configuration (required)
    ├── whitelist.txt   # Allowed addresses (optional)
    ├── blacklist.txt   # Blocked addresses (optional)
    └── logs/           # Activity logs (auto-generated)
```

---

## Configuration Priority

Settings are loaded in this order (highest priority first):

```
1. Code parameters        host(create_agent, port=9000)
   ↓ (if not provided)
2. Config file            .co/host.yaml (required)
```

**Example:**
```yaml
# .co/host.yaml
port: 8000
```

```python
# agent.py
host(create_agent, port=7000)
```

**Result:** Port **7000** is used (code wins).

---

## Complete Reference

### Agent Metadata

Used by `/info` endpoint and ANNOUNCE messages for agent discovery.

```yaml
# Natural language description of agent capabilities
# Default: First 1000 chars of agent.system_prompt
summary: I translate text between 100+ languages with cultural context

# 2-5 example prompts showing how to interact with the agent
examples:
  - "Translate 'hello' to Spanish"
  - "What language is '你好' in?"
  - "Translate this paragraph to French: The quick brown fox jumps over the lazy dog"
```

### Trust & Security

#### Simple Trust Level

```yaml
# Use built-in trust level
trust: careful  # "open", "careful", or "strict"
```

| Level | Behavior | Use Case |
|-------|----------|----------|
| `open` | Accept all requests | Development |
| `careful` | Recommend signature, accept unsigned | Staging/Default |
| `strict` | Require valid signature | Production |

#### Advanced Trust Configuration

```yaml
trust:
  # Who has access (checked in order)
  allow:
    - whitelisted  # Addresses in whitelist.txt
    - contact      # Previously promoted contacts

  # Who is blocked
  deny:
    - blocked      # Addresses in blacklist.txt

  # How strangers become contacts (onboarding)
  onboard:
    invite_code:
      - OpenOnion
      - BETA2024
    payment: 10  # Minimum credits required

  # What to do with strangers without credentials
  # Options: "allow", "deny", "ask" (ask = use LLM to evaluate)
  default: ask
```

**Fast Rules Flow:**
1. Check `deny` list → reject if blocked
2. Check `allow` list → accept if whitelisted/contact
3. Check `onboard` credentials → promote and accept if valid
4. Apply `default` action → allow/deny/ask LLM

#### Access Control Lists

**Custom paths:**
```yaml
whitelist: ./security/allowed-addresses.txt
blacklist: ./security/blocked-users.txt
```

**File format** (one address per line, comments with #):
```
# .co/whitelist.txt
# Trusted partners

0xgood123abc...  # Partner company
0xtrusted456def...
0xfriend789ghi...
```

### Server Settings

```yaml
# HTTP port
# Default: 8000
port: 8000

# Number of worker processes (OS-level parallelism)
# Default: 1
workers: 1

# How long to keep session results (seconds)
# Default: 86400 (24 hours)
result_ttl: 86400

# P2P relay for agent discovery
# Default: wss://oo.openonion.ai/ws/announce
# Set to null to disable relay
relay_url: wss://oo.openonion.ai/ws/announce

# Auto-reload on code changes (development only)
# Default: false
reload: false

# Path to .co directory for agent identity
# Default: ~/.co/
co_dir: null
```

### File Upload Limits

Control file upload sizes for `/input` endpoint and `/ws` WebSocket.

```yaml
# File upload limits
# Default values shown

# Maximum file size in MB (applies to both WebSocket and HTTP)
# Default: 10 - Good for screenshots, docs, images
max_file_size: 10

# Maximum number of files in one request
# Default: 10
max_files_per_request: 10
```

**Error Messages:**

When limits are exceeded, users see clear errors:

```
File too large: document.pdf (15.2MB, max: 10MB).
Increase max_file_size in host.yaml
```

```
Too many files: 15 (max: 10).
Increase max_files_per_request in host.yaml
```

**Use Cases:**

```yaml
# Image processing agent (small files)
max_file_size: 5                # 5MB
max_files_per_request: 20       # Up to 20 files

# Video analysis agent (large files)
max_file_size: 500              # 500MB
max_files_per_request: 5        # Fewer files

# Document processing (many small files)
max_file_size: 10               # 10MB (default)
max_files_per_request: 50       # Up to 50 files
```

**Logging:**

Environment and file uploads are automatically logged:

```
INFO: Loaded environment: /Users/you/my-agent/.env
INFO: Loaded global keys: /Users/you/.co/keys.env
```

Host startup banner shows configuration paths:

```
[host]  ─────────────────────────────────────
        config: /Users/you/my-agent/.co/host.yaml
        logs: /Users/you/my-agent/.co/logs
```

Activity logs written to `.co/logs/{agent_name}.log`:

```
INFO: File upload: 3 file(s), 15.23MB total - image1.png, image2.png, document.pdf
INFO: File upload validated: 3 file(s) accepted
```

```
INFO: File upload: 1 file(s), 150.50MB total - video.mp4
WARNING: File upload rejected: video.mp4 too large (150.5MB > 100MB)
```

```
INFO: File upload: 15 file(s), 45.20MB total - doc1.pdf, doc2.pdf, ...
WARNING: File upload rejected: too many files (15 > 10)
```

### Tool Permissions

Auto-approve safe tools without requiring user approval each time. Uses the unified permissions structure for granular control.

```yaml
# Tool permissions - auto-approve safe commands
permissions:
  # Simple tool name - matches any call
  "read_file":
    allowed: true
    source: config
    reason: safe read operation
    expires:
      type: never

  # Exact bash command
  "Bash(git status)":
    allowed: true
    source: config
    reason: safe read-only git command
    expires:
      type: never

  # Wildcard matching - command prefix
  "Bash(git diff *)":
    allowed: true
    source: config
    reason: safe git diff commands
    expires:
      type: never

  # Parameter matching - only specific files
  "write":
    allowed: true
    source: config
    reason: safe documentation edits
    when:
      file_path: "*.md"
    expires:
      type: never

  # Read files in specific directory
  "read_file":
    allowed: true
    source: config
    reason: safe to read docs
    when:
      file_path: "docs/**/*"
    expires:
      type: never
```

**Permission Patterns:**

| Pattern | Matches | Example |
|---------|---------|---------|
| `"read_file"` | Any call to read_file | All file reads |
| `"Bash(git status)"` | Exact command match | Only `git status` |
| `"Bash(git diff *)"` | Command prefix wildcard | `git diff`, `git diff HEAD`, etc. |
| `"Bash(git *)"` | All commands with prefix | Any git command |
| With `match` field | Parameter-level matching | `write` to `*.md` files only |

**Parameter Matching:**

Use the `match` field to approve tools based on specific parameter values:

```yaml
permissions:
  # Auto-approve writes to markdown files only
  "write":
    allowed: true
    source: config
    reason: safe documentation edits
    when:
      file_path: "*.md"
    expires:
      type: never

  # Auto-approve edits in docs directory
  "edit":
    allowed: true
    source: config
    reason: safe doc edits
    when:
      file_path: "docs/**/*.md"
    expires:
      type: never

  # Auto-approve bash with timeout limit
  "bash":
    allowed: true
    source: config
    reason: safe short commands
    when:
      timeout: "30000"  # Exact match on timeout parameter
    expires:
      type: never
```

**Unified Permission Structure:**

All permissions use the same structure:
- `allowed`: Boolean - whether to allow the tool
- `source`: String - where permission came from (`config`, `user`, `skill`, `safe`, `default`)
- `reason`: String - why this permission was granted (shown in logs)
- `match`: Object (optional) - parameter-level matching rules
- `expires`: Object - when permission expires
  - `type: never` - permanent (config-based)
  - `type: session_end` - expires when session ends (runtime approvals)
  - `type: turn_end` - expires when turn ends (skills)

**Priority Order:**

When multiple permissions could match, priority is:
1. Runtime approvals (`source: user`) - highest priority
2. Config permissions (`source: config`) - from host.yaml
3. Default permissions (`source: default`) - built-in safe tools
4. Safe tools (`source: safe`) - read-only operations (always allowed)

**Best Practices:**

```yaml
# ✅ DO: Auto-approve safe read-only commands
permissions:
  "Bash(git status)":
    allowed: true
    source: config
    reason: safe read-only
    expires:
      type: never

# ✅ DO: Use parameter matching for file operations
permissions:
  "write":
    allowed: true
    source: config
    reason: safe doc edits
    when:
      file_path: "*.md"
    expires:
      type: never

# ❌ DON'T: Auto-approve dangerous commands
permissions:
  "Bash(rm -rf *)":  # Never auto-approve destructive commands
    allowed: true

# ❌ DON'T: Auto-approve all bash commands
permissions:
  "bash":  # Too broad without match field
    allowed: true
```

**Use Cases:**

```yaml
# Development workflow - auto-approve git and tests
permissions:
  "Bash(git status)":
    allowed: true
    source: config
    reason: safe git read
    expires:
      type: never
  "Bash(git diff *)":
    allowed: true
    source: config
    reason: safe git read
    expires:
      type: never
  "Bash(pytest *)":
    allowed: true
    source: config
    reason: safe test execution
    expires:
      type: never

# Documentation agent - auto-approve doc edits
permissions:
  "write":
    allowed: true
    source: config
    reason: documentation updates
    when:
      file_path: "docs/**/*.md"
    expires:
      type: never
  "edit":
    allowed: true
    source: config
    reason: documentation updates
    when:
      file_path: "docs/**/*.md"
    expires:
      type: never

# Code review agent - read-only access
permissions:
  "read_file":
    allowed: true
    source: config
    reason: code review access
    expires:
      type: never
  "glob":
    allowed: true
    source: config
    reason: find files
    expires:
      type: never
  "grep":
    allowed: true
    source: config
    reason: search code
    expires:
      type: never
```

---

## Examples

### Minimal (Beginner)

```yaml
# .co/host.yaml

summary: I translate text between languages
examples:
  - "Translate 'hello' to Spanish"

trust: careful
```

```python
# agent.py
from connectonion import Agent, host

def create_agent():
    return Agent("translator", tools=[translate])

host(create_agent)  # Uses .co/host.yaml
```

### With Access Control

```yaml
# .co/host.yaml

summary: I translate text between languages
examples:
  - "Translate 'hello' to Spanish"

trust: careful
whitelist: whitelist.txt
blacklist: blacklist.txt
```

```
# .co/whitelist.txt
0xpartner123abc...
0xtrusted456def...
```

```
# .co/blacklist.txt
0xbad123...
0xspam456...
```

### Production

```yaml
# .co/host.yaml

summary: Production translation service with 100+ languages
examples:
  - "Translate 'hello' to Spanish"
  - "What language is '你好' in?"
  - "Translate this document to French"

trust: strict
port: 8000
workers: 4
result_ttl: 3600  # 1 hour
```

```python
# agent.py
host(create_agent)  # All settings from host.yaml
```

### Custom Trust Policy

```yaml
# .co/host.yaml

summary: I translate text
examples:
  - "Translate hello to Spanish"

trust:
  allow:
    - whitelisted
    - contact

  deny:
    - blocked

  onboard:
    invite_code: [OpenOnion, BETA2024]
    payment: 10

  default: ask  # Use LLM for unknown users

port: 8000
workers: 2
```

### Development

```yaml
# .co/host.yaml

summary: Translation agent (dev)
examples:
  - "Translate hello to Spanish"

trust: open  # Accept all requests
port: 8000
reload: true  # Auto-reload on changes
```

---

## Override in Code

You can always override config settings in code:

```python
# Override specific settings
host(create_agent,
     port=9000,           # Override config
     workers=2,           # Override config
     reload=True)         # Override config

# Config file still used for other settings (summary, examples, trust)
```

---

## Config Validation

Invalid config will show helpful errors:

```yaml
# .co/host.yaml
port: "not a number"  # ❌ Error: port must be an integer
trust: invalid_level   # ❌ Error: trust must be "open", "careful", "strict", or custom config
```

**Valid trust values:**
- String: `"open"`, `"careful"`, `"strict"`
- Object: Custom trust configuration with `allow`, `deny`, `onboard`, `default`

---

## Default Template

`co init` generates this default host.yaml:

```yaml
# Host configuration — edit these values, then run: host(create_agent)
trust: careful
port: 8000
workers: 1
result_ttl: 86400
relay_url: wss://oo.openonion.ai/ws/announce
reload: false

# File upload limits - uncomment to customize
# max_file_size: 10                 # MB per file (both WebSocket and HTTP)
# max_files_per_request: 10         # Max number of files in one request

# summary: "What your agent does"
# examples:
#   - "Example prompt 1"
#   - "Example prompt 2"
# whitelist: whitelist.txt
# blacklist: blacklist.txt
```

---

## Best Practices

### 1. Keep Secrets in .env

```yaml
# ❌ DON'T put secrets in host.yaml
openai_api_key: sk-...  # Never!

# ✅ DO use .env for secrets
```

### 2. Version Control Config

```bash
# ✅ DO commit host.yaml
git add .co/host.yaml

# ❌ DON'T commit secrets or lists
echo ".co/whitelist.txt" >> .gitignore
echo ".co/blacklist.txt" >> .gitignore
echo ".env" >> .gitignore
```

### 3. Start Simple, Add Complexity

```yaml
# Day 1: Minimal
summary: My agent
trust: careful

# Day 30: Add examples
examples:
  - "Example 1"

# Day 90: Add custom trust
trust:
  onboard:
    payment: 10
```

---

## Troubleshooting

### Config not found?

```bash
# host.yaml is required — generate it with:
co init
```

### Config not loading?

```bash
# Check if file exists
ls .co/host.yaml

# Check YAML syntax
python -c "import yaml; yaml.safe_load(open('.co/host.yaml'))"
```

### Settings not applying?

Check priority order:
1. Code parameters override everything
2. Config file values used if not overridden

```python
# Debug: print effective settings
host(create_agent, port=9000)  # This port wins!
```

### Whitelist/blacklist not working?

```bash
# Check files exist
ls .co/whitelist.txt
ls .co/blacklist.txt

# Check format (one address per line)
cat .co/whitelist.txt
```

### Trust policy not working?

```yaml
# Make sure trust is valid
trust: careful  # ✅ Valid

trust: custom   # ❌ Invalid - not a valid level

# For custom trust, use object format:
trust:
  allow: [whitelisted]
  deny: [blocked]
  default: deny
```

---

## See Also

- [host()](host.md) - Host function reference
- [Trust System](../concepts/trust.md) - Trust verification details
- [ANNOUNCE Message](protocol/announce-message.md) - Agent discovery protocol
