# meshcp — Claude Code Skill

Use this skill when working with **meshcp**: enrolling machines, managing the orchestrator, writing agent configs, troubleshooting connectivity, or building on top of the meshcp API.

## What meshcp is

meshcp is a two-binary system:
- **`meshcp-orchestrator`** — runs on one machine (the "hub"), manages a PKI/CA, enrollment, a machine registry, and serves MCP tools to Claude via stdio.
- **`meshcp-agent`** — runs on every other machine, exposes capabilities (shell, files, system status) over mTLS gRPC.

All communication is **mTLS**: the orchestrator is the CA, every agent has a cert signed by it.

## Key paths

| Path | Purpose |
|---|---|
| `/var/lib/meshcp/` | Orchestrator data dir (CA certs, registry, server cert) |
| `/var/lib/meshcp/ca/ca.crt` | CA certificate (distribute to debug mTLS issues) |
| `/var/lib/meshcp/registry.json` | Enrolled machines |
| `/etc/meshcp/agent.yaml` | Agent config on each machine |
| `/etc/meshcp/creds/` | Agent mTLS certs (ca.crt, agent.crt, agent.key) |

## Common workflows

### Enroll a new machine

1. On the orchestrator, generate a token:
   ```bash
   meshcp-orchestrator --data-dir /var/lib/meshcp token create <machine-name> --ttl 1h
   ```
2. On the new machine, run the printed command:
   ```bash
   meshcp-agent enroll \
     --orchestrator https://<ORCHESTRATOR_IP>:7443 \
     --token <TOKEN>
   ```
3. Start the agent:
   ```bash
   meshcp-agent start
   # or as a service: systemctl start meshcp-agent
   ```
4. Verify from the orchestrator:
   ```bash
   meshcp-orchestrator --data-dir /var/lib/meshcp ping <machine-name>
   ```

### Add to Claude Code MCP config

```json
{
  "mcpServers": {
    "meshcp": {
      "command": "meshcp-orchestrator",
      "args": ["serve", "--data-dir", "/var/lib/meshcp"]
    }
  }
}
```

After restarting Claude Code, you'll have these tools: `list_machines`, `exec`, `read_file`, `write_file`, `list_files`, `system_status`.

### Check a machine's status

Use the `system_status` MCP tool, or from the CLI:
```bash
meshcp-orchestrator --data-dir /var/lib/meshcp ping <machine-name>
```

### List all enrolled machines

```bash
meshcp-orchestrator --data-dir /var/lib/meshcp machines
```

### Cross-compile the agent for a different platform

```bash
cd /path/to/meshcp
# macOS Apple Silicon
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -o bin/meshcp-agent-darwin-arm64 ./cmd/agent
# Linux x86-64
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/meshcp-agent-linux-amd64 ./cmd/agent
# Linux ARM64 (Raspberry Pi, etc.)
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o bin/meshcp-agent-linux-arm64 ./cmd/agent
```

### One-liner install on a new machine (after building releases)

```bash
curl -fsSL https://meshcp.interrupt.fr/install.sh | bash -s -- \
  --orchestrator https://<ORCHESTRATOR_IP>:7443 \
  --token <TOKEN>
```

## Agent capability config

The agent reads `/etc/meshcp/agent.yaml`. Edit it to restrict or expand what the orchestrator can do on that machine:

```yaml
machine_name: my-server
listen_addr: "0.0.0.0:7444"
creds_dir: /etc/meshcp/creds

capabilities:
  shell:
    enabled: true
    max_timeout_seconds: 300
    # Restrict to specific commands (leave empty to allow all):
    # allowed_commands: [ls, cat, docker, systemctl, journalctl]
  files:
    enabled: true
    max_file_size_mb: 50
    # Restrict to specific path prefixes (leave empty to allow all):
    # allowed_paths: [/home, /etc/nginx, /var/log]
  system:
    enabled: true
  docker:
    enabled: false
```

Restart the agent after changing config:
```bash
systemctl restart meshcp-agent
# or: meshcp-agent start --config /etc/meshcp/agent.yaml
```

## Troubleshooting

**Agent won't connect — `certificate signed by unknown authority`**
→ The agent's CA cert doesn't match the orchestrator's CA. Re-enroll with a fresh token.

**`unknown machine "x"` from MCP tools**
→ Check `machines` list. The machine may not have enrolled yet or enrollment failed.

**Enrollment fails with `token already used`**
→ Create a new token. Each token is single-use.

**Enrollment fails with `token expired`**
→ The TTL passed. Create a new token with a longer TTL: `--ttl 24h`.

**Agent unreachable (timeout on ping)**
→ Check that port 7444 is reachable on the mesh (Tailscale, etc.), and that `meshcp-agent start` is running.

## Building from source

```bash
git clone https://github.com/interrupt-engineering/meshcp
cd meshcp
make build          # builds both binaries for current platform
make release        # builds all cross-platform variants
make proto          # regenerates protobuf (requires buf)
```

## Project layout

```
cmd/orchestrator/   meshcp-orchestrator entry point
cmd/agent/          meshcp-agent entry point
internal/ca/        PKI: CA creation + cert signing
internal/enrollment/ HTTP enrollment (server + client)
internal/agent/     gRPC AgentService + capabilities (shell, files, system)
internal/orchestrator/ Machine registry + gRPC client pool
internal/mcp/       MCP server + tool handlers
proto/agent/v1/     Protobuf service definition
gen/agent/v1/       Generated Go code (buf generate)
```
