# eve-agent [eve.dev](https://eve.dev) agent deployed on [eve.boxd.sh](https://eve.boxd.sh). - **Model**: OpenCode Zen `deepseek-v4-flash-free` (OpenAI-compatible Chat Completions) - **Channels**: built-in eve channel + IRC via **irc-bridge** (POST `/irc/inbound` + SSE `/irc/out`) - **AV (optional)**: **av-bridge** (Rust) — freeq MoQ media planes + internet radio (`av-bridge/`, freeq `eve-av-bridge`); stream.place **watch** (`:8792`) and **publish** (RTMP egress) - **Tools**: cowsay, ATProto, rook/thermals, Anna, Linear (eve project), `guess_emotion`, **`play_radio` / `stop_radio` / `stop_media`** (stream to freeq AV; stop_media = all planes), **`enter_voice_mode` / `exit_voice_mode` / `voice_status`** (Grok Voice duplex, default Eve timbre), **`enter_slide_mode` / `exit_slide_mode` / `slide_status`** (AV caption card: speech/text → tile only, no TTS), **`watch_stream` / `publish_stream`** (stream.place in/out), **`memory_bank_add` / `memory_bank_list`** (durable song/note list) - **Skills**: `vit`, `vit-request-watch`, `anna`, `linear`, `freeq-irc`, `irc-backlog`, `embody-emotion`, **`freeq-radio`**, **`freeq-voice`**, **`freeq-slide`** - **Schedules**: `vit-request-caps` every 10m → explore kind:request on controlled beacons → IRC `#test` - **Secrets**: API keys pulled live from OpenBao (`openbao.boxd.sh`) via `scripts/fetch-keys.sh` — never committed ## Layout ``` agent/ agent.ts # model + agent definition instructions.md channels/ # eve.ts, irc.ts (HTTP+SSE only — no IRC socket) lib/ tools/ skills/ schedules/ irc-bridge/ server.mjs # freeq IRC → POST /irc/inbound ; SSE /irc/out → PRIVMSG systemd/user/ # user unit templates (eve, irc-bridge, optional av-bridge + streamplace plane (:8792)) scripts/ prep.sh, start.sh, install-systemd.sh, fetch-keys.sh, sync-freeq-session.mjs flake.nix ``` ## rook.host tools Public (no identity): | Tool | Purpose | |------|---------| | `thermals_stats` | Board totals | | `thermals_requests` / `thermals_request` | Open work requests | | `thermals_rook` | Profile + track record by did/handle | | `thermals_leaderboard` | Ranked rooks | Local CLI ([`@solpbc/rook`](https://www.npmjs.com/package/@solpbc/rook)): | Tool | Purpose | |------|---------| | `rook_whoami` / `rook_doctor` | Identity + readiness | | `rook_enroll` | Enroll with human invite URL + handle | | `rook_profile` | Show / publish / remove thermals profile | | `rook_submit` | fork → push → pr → ship from a local clone | Optional env: `ROOK_IDENTITY_FILE`, `THERMALS_URL` (default `https://thermals.cloud`). Agent-facing docs: https://rook.host/llms.txt · https://thermals.cloud/llms.txt ## Anna's Archive tools | Tool | Purpose | |------|---------| | **`anna_search`** | Books by ISBN/title via [annas-mcp](https://github.com/iosifache/annas-mcp) → **MD5s** | | **`anna_download`** | Member API → save file under **`~/archive`** (or `ANNA_DOWNLOAD_DIR`) | | `anna_article_search` | Papers by DOI/keywords (annas-mcp) | | `openlibrary_isbn` | Open Library bibliography | | `anna_record` | Unified AA metadata for one MD5 | | `anna_fast_download` | Member API → URL only (`ANNA_API_KEY`) | | `anna_torrents` | Bulk torrent catalog (large dumps) | **Single-book flow:** `anna_search` → pick md5 → **`anna_download`** (or `anna_fast_download` for URL only). | Variable | Notes | |----------|--------| | `ANNA_API_KEY` | OpenBao membership key for JSON download API | | `ANNA_DOWNLOAD_DIR` | Default `$HOME/archive` | | `ANNAS_MCP_BIN` | Optional path to `annas-mcp` | | `ANNA_ARCHIVE_BASE` | Default `https://annas-archive.gl` | ```bash bash scripts/install-annas-mcp.sh # → ~/.local/bin/annas-mcp ``` Skill: `load_skill` → `anna`. ## Linear tools (eve project) All Linear tools are **scoped to the Linear project named `eve`** (override with `LINEAR_PROJECT_NAME` or `LINEAR_PROJECT_ID`). Issues outside that project are rejected. | Tool | Purpose | |------|---------| | **`linear_status`** | Project progress + counts by state + sample open issues | | **`linear_issues`** | List/filter issues (query, state, assignee); default open only | | **`linear_issue`** | Full detail for one identifier/UUID | | `linear_create_issue` | Create issue always on the eve project | | `linear_update_issue` | Update title/description/priority/state/assignee (eve only) | | Variable | Notes | |----------|--------| | `LINEAR_API_KEY` | OpenBao `ai-api-keys` personal API key | | `LINEAR_PROJECT_NAME` | Default `eve` | | `LINEAR_PROJECT_ID` | Optional UUID (skips name lookup) | Skill: `load_skill` → `linear`. ## Slide mode (freeform AV caption card) You say something → Eve **shows it on the freeq AV slide** only. No TTS speak-back (avoids mic feedback loops). Repeats until exit. | Trigger | Action | |---------|--------| | `eve: enter slide mode` | Start listening | | type anything / speak in call | Slide shows it (display only) | | `eve: exit slide mode` | Stop | Tools: **`enter_slide_mode`**, **`exit_slide_mode`**, **`slide_status`**. Skill: `freeq-slide`. Join freeq **AV** to see the tile. ## Voice / conversation mode (Grok Voice) Duplex speech in freeq AV via Cloudflare Workers AI `xai/grok-voice` (default spoken voice **`eve`**). | Trigger | Action | |---------|--------| | `eve: enter voice mode` / `enter conversation mode` | Start duplex + short spoken greeting | | `eve: exit voice mode` | Stop Grok session | | `eve: voice status` | Live/off probe | Tools: **`enter_voice_mode`**, **`exit_voice_mode`**, **`voice_status`**. Skill: `freeq-voice`. | Variable | Notes | |----------|--------| | `CLOUDFLARE_ACCOUNT_ID` | Workers AI account (config / runtime.env) | | `CLOUDFLARE_API_TOKEN` | From OpenBao `ai-api-keys` | | `GROK_VOICE` | Default `eve` | Users must **join the freeq voice call** in the channel. `stop_media` also ends voice mode. ## Memory bank (saved songs / notes) Host file (not the sandbox). IRC: “add song to memory bank”, “read the memory bank”. | Tool | Purpose | |------|---------| | **`memory_bank_add`** | Append one entry (usually current `now playing` / `radio_title`) | | **`memory_bank_list`** | List saved entries | | Variable | Default | |----------|---------| | `MEMORY_BANK_PATH` | `$HOME/memory-bank.txt` | Never claim a save without a tool result. Skill: `freeq-radio`. ## freeq IRC nick / SASL If the bot appears as `Guest…` or logs `SASL failed (904)`, the freeq OAuth session expired. ```bash # on the eve VM npx --yes @solpbc/rook login node scripts/sync-freeq-session.mjs # or /home/boxd/my-agent/scripts/… # restart agent (start.sh) ``` Skill: `load_skill` → `freeq-irc`. Target nick: `eve` / handle `eve.boxd.sh` (PDS `https://pds.eve.boxd.sh`). ## Local dev ```bash nix develop # or: direnv allow npm install export OPENCODE_API_KEY=… # or other provider keys npm run dev ``` ## Boxd (eve.boxd.sh) On the VM, secrets come from OpenBao. **Production path uses systemd user units** (`eve`, `eve-irc-bridge`, optional `eve-av-bridge`) — see [`systemd/README.md`](systemd/README.md). ```bash export OPENBAO_ADDR=https://openbao.boxd.sh export OPENBAO_TOKEN=… # boxd secret / service token npm install bash scripts/install-systemd.sh # once (writes units + ~/.config/eve/) # put OPENBAO_* in ~/.config/eve/openbao.env (mode 0600) loginctl enable-linger "$USER" # once, if units should survive logout npm run boxd:start # systemctl --user start eve.target ``` Legacy (no units): `bash scripts/start.sh --legacy` (prep + nohup bridge + foreground eve). Optional IRC env (defaults match freeq; set in `~/.config/eve/config.env` for units): | Variable | Default | |----------|---------| | `IRC_HOST` | `irc.freeq.at` | | `IRC_PORT` | `6697` | | `IRC_TLS` | `1` | | `IRC_NICK` | `eve` | | `IRC_CHANNEL` | `#test` | | `IRC_PASSWORD` | (unset) | | `IRC_OWNERS` | (unset) | ### vit request-cap schedule | Variable | Default | |----------|---------| | `VIT_CONTROLLED_BEACONS` | codegod100 repo beacons (comma-separated overrides) | | `VIT_CONTROLLED_BEACON_OWNERS` | `codegod100` (substring match on beacon) | | `VIT_REQUEST_REPORT_EMPTY` | unset = quiet when no matches; `1` = always report | | `VIT_EXPLORE_URL` | `https://explore.v-it.org` | `npm run boxd:start` runs `eve build && eve start` so the cron fires. Locally with `eve dev`, fire once: ```bash curl -X POST http://127.0.0.1:8000/eve/v1/dev/schedules/vit-request-caps ``` ## Framework docs See `node_modules/eve/docs/` or https://eve.dev/docs.