# Her Desktop Agent

Tiny local desktop agent for letting Her AI control a Mac through HTTP APIs.

This first version is intentionally small and conservative:

- No npm dependencies
- Token required for every control endpoint
- macOS support first
- Safe command allowlist instead of arbitrary shell execution

## Start on macOS

```bash
cd desktop-agent
npm start
```

By default the agent listens on `127.0.0.1:8787`, which is only reachable from the Mac itself.

For local network use:

```bash
HER_AGENT_HOST=0.0.0.0 npm start
```

Then open Her > `连接 Mac`, paste one of the printed LAN URLs, and enter the printed token.

For Her in-app connection, use:

```bash
cd desktop-agent
./scripts/start-local.sh
```

Then open Her > `连接 Mac`, paste one of the printed URLs, and enter the printed token.

The first run creates a token in `~/.her-desktop-agent/config.json` and prints it in the terminal.

You can override the config directory for testing:

```bash
HER_AGENT_CONFIG_DIR=/tmp/her-desktop-agent npm start
```

## Cloudflare Tunnel For Public Access

This gives your phone a temporary public HTTPS URL. The URL changes every time you restart the tunnel.

Install Cloudflare Tunnel:

```bash
brew install cloudflared
```

Then start the agent and tunnel together:

```bash
cd desktop-agent
./scripts/start-cloudflare-tunnel.sh
```

The terminal prints two important things:

- `Token: ...`
- an `https://....trycloudflare.com` URL from `cloudflared`

The script also copies a ready-to-open Her app link to your Mac clipboard:

```text
her://mac-control?url=...
```

Send that link to your phone and open it with Her.

Manual values are also printed:

```text
Address: https://....trycloudflare.com
Token:   ...
```

Paste those values into Her's `连接 Mac` page manually if you do not use the Her app link.

Keep the terminal open. Closing it stops remote control.

For this mode, the agent only listens on `127.0.0.1`; Cloudflare Tunnel is the public entry point.

## Test With curl

Replace `TOKEN` with the printed token.

```bash
curl http://127.0.0.1:8787/health

curl -X POST http://127.0.0.1:8787/api/notify \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Her","body":"Connected from phone"}'

curl -X POST http://127.0.0.1:8787/api/open-app \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Safari"}'

curl -X POST http://127.0.0.1:8787/api/run \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command":"uptime"}'
```

## API

### `GET /health`

Returns basic status and local network URLs.

### `POST /api/open-app`

Body:

```json
{ "name": "Safari" }
```

### `POST /api/notify`

Body:

```json
{ "title": "Her", "body": "Hello from Her" }
```

### `POST /api/screenshot`

Returns a PNG screenshot as base64 JSON:

```json
{ "ok": true, "mime": "image/png", "base64": "..." }
```

macOS may ask for Screen Recording permission.

### `POST /api/run`

Runs one of the allowed commands:

- `pwd`
- `whoami`
- `uptime`
- `sw_vers`
- `ls-home`
- `ls-desktop`
- `ls-downloads`
- `ls-documents`
- `lock-screen`

Body:

```json
{ "command": "sw_vers" }
```

### `POST /api/terminal-run`

Runs a command for AI terminal control. This endpoint is enabled by `./scripts/start-local.sh`.

Body:

```json
{ "command": "pwd && ls -la", "mode": "exec" }
```

Use `"mode": "terminal"` to open macOS Terminal and run the command visibly.

## Next Steps

- Add a Her Android control screen.
- Add WebSocket sessions for streaming logs and screenshots.
- Wrap this agent in a macOS menu bar app.
- Add Windows and Linux adapters behind the same API.
