Fleet inventory for Ria (read-only survey, 2026-10-12)

Paths with no prefix are under ~/openclaw-gia/config/workspace ("WS"). Container paths /home/node/.openclaw-gia/.openclaw/... map to ~/openclaw-gia/config/... on the host, and .openclaw/workspace is WS.

Top 10 building blocks

  1. Signal podcast skill and ledger. workspace/skills/signal-daily-podcast/SKILL.md and workspace/research/briefings/signal/ledger.json. Delta-aware research, TTS, a Telegram mp3 and tap cards. Caveat: assumes Byron's lenses and steering; Ria needs her own ledger and steering file. Depends on the Gia container being up.
  2. Telegram send paths. Bot token is TELEGRAM_BOT_TOKEN in ~/openclaw-gia/.env. Use curl https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage inside the container (pattern in ~/ops/disk-sentinel/disk_sentinel.py), or Gia's message tool. Caveat: ~/openclaw-gia/.env holds every fleet key; source only the one variable (pattern in ~/quip-service/signal-pregen.sh).
  3. Gia cron scheduler. openclaw cron list --json inside the openclaw-gia container. config/cron on the host is empty; live jobs are only inspectable via the CLI in the container.
  4. Podcast pipeline. workspace/scripts/podcasts/ (transcribe.py, latest-scan.py, feeds.json) feeds generate-rai-content.py, then rai-report-* scripts and deploy-rai-report.sh. Caveat: repeats stale items (section 2).
  5. ~/ops/bin/slog and slog-card. Append-only work log (~/ops/data/worklog.jsonl) plus tappable approval cards (cards.jsonl) on the Signal Live cockpit (tailnet only, mia.tail7e4190.ts.net:8443).
  6. ~/ops/bin/gia2-dispatch. Forced-command SSH allowlist with three jobs: deploy, voice.clone, slog. The safe pattern for letting a sandboxed agent act on the host. Adding a capability means editing a security-sensitive file.
  7. Voice pipeline. ~/voice-clone/clone.sh (Chatterbox) with apply_lexicon.py. Four mandatory gates: lexicon, canonical settings, Whisper-back QA, AI-voice disclosure. Slow, runs on MPS.
  8. Motion brief pipeline. projects/byron-command/motion/2026-10-12/work/pipeline.py and render.mjs, deployed by publish.sh to trust.arnao.ai. Script hand-authored in script.json; readable() replacements hard-coded per episode.
  9. Branding Central. branding-capture.sh POSTs to /api/pieces. Image models in ~/branding-console/app/api/ai.js. Capture-only by hard rule; never create a parallel console or repoint the domain.
  10. Notify and Remote Control. notify-app/notify.sh posts to https://notify.arnao.ai/api/events with bearer token from ~/.notify-ingest-token. ~/.claude-rc/run.sh keeps nine tmux Remote Control sessions alive. Notify is web-push (only devices that installed the PWA). Remote Control watchdog can interrupt long work.

Important finding

A ria agent already exists in ~/openclaw-gia/config/openclaw.json (agents.list: main and ria, ria set to anthropic/claude-fable-5). Its workspace-ria/ holds the unfilled template. WS/projects/ria/ holds PROPOSAL.md, CRITIQUE-fable.md, audit-*.md, mockups/, motion/ and research/.

1. Telegram, SMS, push

Telegram (Gia). Gateway in Docker container openclaw-gia (image openclaw-gia:2026.7.1-2-slim, port 18802); compose ~/openclaw-gia/docker-compose.yml, ./config and ./workspace bind mounts. channels.telegram enabled with dmPolicy: "pairing". Token TELEGRAM_BOT_TOKEN (+ TELEGRAM_BOT_USERNAME) in ~/openclaw-gia/.env, loaded via env_file. Paired chat id in config/credentials/telegram-default-allowFrom.json and telegram-pairing.json (Docker volume gia-credentials); the same id is hard-coded in many cron prompts. Gia crons deliver via delivery: {mode: announce, channel: telegram, to: <chat id>} or the agent's message tool.

Scripts that already push to Telegram: ~/ops/disk-sentinel/disk_sentinel.py (telegram(), curl inside the container; also posts to notify.arnao.ai); ~/quip-service/signal-pregen.sh (reads token from .env, Python urllib); WS/scripts/inbox/escalate.py, scripts/billing-guard/billing-guard.sh, scripts/podcasts/send-digest.py, scripts/cron/daily_briefing.sh; WS/projects/signal-public/scripts/lib-telegram.mjs POSTs {to:'telegram', content} to https://dictate.arnao.ai/api/send (sanctioned path; server at WS/projects/dictate-app/src/server.js ~line 100). ~/ops/keywatch/keywatch.py writes fleet-health.json, not a sender.

SMS. ~/ops/bin/txt '+1XXXXXXXXXX' 'message' via Twilio REST (Libeso Photography), reads TWILIO_* from .env, polls delivery ~30 s. Header says it works only once the Twilio account is upgraded and toll-free verification approved; untested. Gia cron "SMS Inbound Relay" polls sms-spambot-gateway /api/inbox every minute (WS/scripts/sms, ~/ops/twilio).

Signal (messenger): none. "Signal" is Byron's briefing brand, delivered as mp3 over Telegram and the PWA "Signal Live". ntfy / Pushover: not used.

notify.arnao.ai. WS/projects/notify-app (NOTIFY.md, notify.sh, notify.mjs, api/events.js, list.js, subscribe.js, action.js, sw.js). Vercel PWA with Web Push (VAPID). POST /api/events with Authorization: Bearer $NOTIFY_INGEST_TOKEN; fields type (login, access-request, feedback, agent-alert, test), title, body, source, priority, data. 200 = durably logged; push best-effort. Token in ~/.notify-ingest-token (600), notify-app/.notify-creds, Vercel env. Device key NOTIFY_KEY gates the inbox. Skill WS/skills/notify. Web push cannot set per-event sound.

2. Daily RAI Report and podcast transcription

Schedule. Gia cron "Daily Podcast Transcripts + Daily RAI Refresh" 30 5 America/New_York, orchestrator google/gemini-2.5-pro, 7200 s timeout, delivery none. No host crontab or launchd job for this. Host crontab: ollama-watchdog every 5 min, inbox-check every 30 min (limactl+docker), fleet-live/keepalive.sh every minute, @reboot buzzer. Gia cron "RAI On-Demand Watcher" (/5, scripts/rai/ondemand-watcher.sh, announces to Telegram).

Steps.

  1. PODCAST_MAX_PER_RUN=8 WHISPER_BACKEND=local python3 scripts/podcasts/transcribe.py → research/transcripts/<podcast-id>/YYYY-MM-DD-<slug>.txt, state research/state/podcast-state.json. Local Whisper (skills/whisper-transcribe), OpenAI whisper-1 fallback.
  2. scripts/podcasts/latest-scan.py 8 → research/podcasts/latest-YYYY-MM-DD.json (top 5 per feed, last 8 days).
  3. scripts/generate-rai-content.py → analysis/rai-feed.json, analysis/rai-brief.md. Inputs: transcripts (14 d), briefings (3 d), Brave search, analysis/rai-pov.md (Byron's lens), Signal ledger, research/youtube/rai/latest.json. LLM claude-sonnet-4-6 (env RAI_MODEL), Gemini 2.5 Flash fallback. stdout must report nonzero "live signal-ledger entries".
  4. strip-emdash-feed.py, render-rai-html.py, gen-today-html.py, deploy/PREFLIGHT.sh, deploy/deploy-static.sh analysis rai-analysis rai.arnao.ai.
  5. Daily 3-minute episode: podcasts/rai-report-episode.py (Gemini 2.5 Flash, reads steering.md, rotates a Top-10 topic list) → rai-report-tts.py (Gemini multi-speaker TTS) → podcast-out/rai-report-YYYY-MM-DD.mp3 → deploy-rai-report.sh (copies mp3 to analysis/, npx vercel --prod, self-verifies) = theraireport.arnao.ai.

Feeds. WS/scripts/podcasts/feeds.json: 20 entries (id, rss, cadence, priority, ai_filter, ai_keywords, rai_focus): Nate B. Jones, AI Daily Brief, Everyday AI, Hard Fork, Lex Fridman, Lenny's, Big Technology, Pivot, Latent Space, Dwarkesh, All-In, Acquired, Into AI Safety, For Humanity, CSIS AI Policy, Eye on AI, Cognitive Revolution, TWIML, Matthew Berman (YouTube RSS), 80,000 Hours (added 2026-09-25). Also sources.json, steering.md; scripts/podcasts/youtube-rai-scan.py handles YouTube.

Stale-item defect (code reading). rai-report-episode.py takes rai-feed.json stories[:4] and the 4 newest transcripts by mtime, with no memory of what already aired; only the topic rotates. rai-feed.json is rebuilt daily from a 14-day transcript window and 8-day scan, so the same stories resurface. History in WS/memory: 2026-06-26 May-27 seed silently recycled; 2026-07-05 episode/TTS/deploy steps lost in a cron consolidation; 2026-08-21 generator ignored the Signal ledger; 2026-09-15 stale check used UTC dates. The Signal ledger (research/briefings/signal/ledger.json) has mention_log.angle_covered per signal; reuse that design for Ria.

3. Morning Brief

Cron "Morning Brief Prefetch" 45 5 runs scripts/brief/prefetch-brief.sh → research/brief/brief-input.json (gog calendar, gog gmail, cron list, OB1 recall via scripts/ob1.js, latest digest and podcast scan, spend-guard and fleet cost, LinkedIn drafts state; fetchers fail soft). scripts/brief/assemble-brief.py assembles; brief-spec-v2.md is the design. Cron "One Morning Brief v2" 5 6 on google/gemini-2.5-flash, announces to Telegram (900 s), writes research/briefings/morning-brief-YYYY-MM-DD.md then one Telegram message under 3000 chars. Sections: RAI, AI innovation, fleet spend, legislation, inbox, deployments, open loops. Sources: analysis/rai-feed.json, newest research/podcasts/latest-.json, research/finance/cost-log/true-cost-.jsonl, cron list, Gmail unread, today's calendar, deployments find + git log, legislation web search, new research files. brief.arnao.ai from scripts/brief-site/build-brief-page.py → projects/brief-site (cron unverified). Caveat: brief and RAI report ingest the same sources separately (memory/MODEL-ROUTING-POLICY.md).

4. Signals pipeline

Gia crons (America/New_York): Signal AM Podcast 50 5 (Fable 5 with fallbacks, 1500 s); Signal AM Watchdog 15 7 ; Signal PM Update 0 18 (delivers only if ≥2 new signals or 1 urgent); Signal Weekly Public Draft 0 7 * 5 (SSH to host with credentials/ssh/whisper-bridge, runs projects/signal-public/scripts/weekly-draft.sh). Delivery: one Telegram message with mp3, caption ≤160 chars, retry/failure ladder. Outputs research/briefings/signal/YYYY-MM-DD-{am,pm}.md, -script.txt, .mp3; ledger.json (+backups/), steering.md, byron-todos.json (derived by slog), fleet-health.json (keywatch), actions.jsonl (scripts/actions/actions.py).

Host LaunchDaemons: com.byron.fleet-keywatch 05:10 (~/ops/keywatch/keywatch.py tests every credential, writes fleet-health.json, ~/ops/keywatch/state.json); ai.arnao.signal-pregen 05:45 (~/quip-service/signal-pregen.sh, pre-renders Signal Live in clone voice, Telegram alert on failure); ai.arnao.signal-aircheck Mondays 05:30 (signal-public/scripts/air-check.sh); ai.arnao.signal-talk KeepAlive (~/signal-talk/server.py). Signal Live served by ~/quip-service/server.js (/signal routes, data ~/quip-service/signal-data/) at mia.tail7e4190.ts.net:8443/signal.

Public Signal (WS/projects/signal-public): make-episode.mjs drafts, Fable risk judge + council.mjs, files into Branding Central queue; publish-episode.mjs human-gated (--confirm), renders clone mp3, rebuilds feed.xml/episodes.json, redeploys. One episode ever; last three Friday drafts held by the council.

signals.json for command.arnao.ai: WS/projects/byron-command/scripts/build-signals.py → src/data/signals.json from local transcripts via Ollama gemma3:12b at 192.168.5.2:11434 (keyword fallback), SIGNAL_SCOPE recent/week/month, cache scripts/.signals-cache.json. Gia cron "Byron Command Telemetry Refresh" (15 min) runs projects/byron-command/scripts/refresh-all.sh; scripts/deploy.sh deploys. "Byron Command Consumer" (5 min) runs scripts/byron-command/consume-commands.py; queue in OB1 Postgres; allowlist ping, diagnostics, logs, restart, draft_linkedin and a few others.

5. Benchmark harness (fleet.arnao.ai)

WS/scripts/fleet-bench/: bench_v3.py, lib/store.py, lib/graders.py, fleet-bench-versions.json, build-fleet-page.py → WS/projects/fleet-site/index.html. Tasks math, code, summarize, creative, vision (TASKS dict); objective graders (math substring; code AST + 6 unit tests; summarize 50±2 words; vision/creative own graders). Run python3 bench_v3.py code summarize, --trials 3, --only-cloud. Providers: Anthropic, Google, OpenAI, xAI, OpenRouter, Ollama via env keys. Results append-only WS/research/state/fleet/history.jsonl; run_key = sha1(model, task, task version, grader version, harness version).

To add an eval: add prompt to TASKS; grader to GRADERS in lib/graders.py; version entry in fleet-bench-versions.json; task name to TASK_ORDER and TASK_LABEL in build-fleet-page.py; run bench; run build-fleet-page.py. Caveats: claude-fable-5 404s on direct Anthropic, needs OpenRouter; a glm-5.2 run blocked by OpenRouter credit cap; "37 models x 8 providers" unverified (DOSSIER cites 23 x 5). Related: WS/projects/benchmarks/ (router-bench), scripts/benchmarks/image-bench.py.

6. Media generation

Image bench: WS/scripts/benchmarks/image-bench.py (skill skills/image-bench), --list, --model <slug>; results workspace/benchmarks/images/YYYY-MM-DD/results.json. 2026-07-11 standings: winner xai/grok-imagine-image-quality (~$0.05, 6 s); runner-up Nano Banana Pro (gemini-3-pro-image-preview, ~$0.134, 19.5 s); budget gemini-2.5-flash-image. Gia imageModel wired winner → NB Pro → 2.5-flash-image → local.

Branding console ~/branding-console: Vercel branding-central, Blob-backed /api/pieces, deploy ~/branding-console/deploy.sh. app/api/ai.js articles via Fable → Opus 4.8 → Gemini Pro; graphics grok-imagine → Nano Banana Pro (nano-banana-pro-preview) → Imagen 4. Envs GEMINI_API_KEY, XAI_API_KEY, ANTHROPIC_API_KEY, BLOB_READ_WRITE_TOKEN, OWNER_KEY. publish.js fails closed with LINKEDIN_ACCESS_TOKEN (dead since 2026-09-15). skill/branding-capture.sh capture-only.

MuseTalk ~/musetalk: stock Tencent README (audio-driven lip-sync, inference.sh, scripts/inference.py), not integrated; check CUDA assumptions. ~/fasterliveportrait-mlx is the Apple-silicon alternative (unread).

7. Voice and motion pipelines

Voice: clone.sh --text ... --out x.mp3 wraps clone-voice.py (Chatterbox mono EN, ~/chatterbox-env, sample ~/voice-samples/byron-voice-sample.wav), canonical --device mps --exaggeration 0.5 --cfg 0.4, VBR q3, 24 kHz. apply_lexicon.py + pronunciation-lexicon.json, standup-voice-watcher.sh. Container reaches it via gia2-dispatch voice.clone (4000 chars, 900 s). Servers ai.arnao.voice-pod (~/voice-pod), com.byron.transcribe-server (~/transcribe-server).

Motion brief: script.json → batch.json → sN.mp3 → pipeline.py (atempo 1.07, gaps, loudnorm -16, timeline.json injected into motion.template.html) → render.mjs (headless frames) → ffmpeg mp4 + poster.jpg; capture*.mjs screenshot cards; gen-page.py → index.html; publish.sh copies to ria/motion/<date>-command/ and deploys. ~5 min for 3539 frames.

8. Headless Claude automation

Scheduled claude -p: only ~/audit-central/run-monthly.sh (launchd com.byron.inventory-audit, 1st of month 06:40, --permission-mode bypassPermissions --max-turns 80) and ~/audit.sh (one-off). Gia → host Claude: skill dispatch-to-claude pipes a task over SSH (credentials/ssh/whisper-bridge → byronarnao@host.docker.internal) to ~/gia-dispatch/dispatch.sh; judge-gated (judge.js), budget GIA_DISPATCH_BUDGET_USD (default $5), Max-plan OAuth (unsets ANTHROPIC_API_KEY); logs ~/gia-dispatch/.

Remote Control fleet: LaunchDaemon com.byron.claude-rc (+ LaunchAgent ai.arnao.claude-rc) runs ~/.claude-rc/start.sh then run.sh at load and every 300 s; one tmux window per line of ~/.claude-rc/projects.txt (name|dir) running claude --remote-control <name> (--continue on restart). Sessions: openclaw-stack, audit-central, buzz-block, clone-absorb, clone-mvp, workspace, byron-command, city-app, voice-pod (+ "Mac Mini" host window). Watchdog restarts on version/credential changes and disconnects (max 3/hour/window); daily controlled npm install -g @anthropic-ai/claude-code@latest after 04:00 when idle (~/.claude-rc/no-auto-update disables). Add a session = add a line to projects.txt.

~/ops/bin/harness-worker: T0-only Python worker, launchd ai.arnao.harness-worker every 2700 s; reads byron-todos.json, worklog.jsonl, cards, memory/intent.v1.md; emits ≤3 question cards and "make it a rule?" cards; audit line to work log; never acts externally.

~/ops/bin/gia2-dispatch: forced command for the gia2-broker SSH key; gia2 stack ~/openclaw-gia2 (containers gia2-broker, openclaw-gia2, gia2-egress, gia2-edge); broker secrets ~/openclaw-gia2/secrets/broker (APPROVAL_HMAC_KEY, BROKER_API_TOKEN, CLOUDFLARE_*, VERCEL_TOKEN); policy broker/policy.json.

Others: ~/ops/bin/upgrade-agent, rc-restart, comedy-killswitch, chaperone-hook (Claude Code hook routing screening to Jev via OpenRouter; shadow mode). LaunchDaemons: career-triage, fleet-audit (06:15), security-sentinel, portfolio-discovery (06:45), gia-sync (hourly). ~/.claude/skills: fable-critique, project-lookup, proposal-publish, skill-scan, skill-scout, vercel-deploy.

9. Secrets conventions (names and paths only)

~/openclaw-gia/.env is the master fleet env: ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY, XAI_API_KEY, DEEPSEEK_API_KEY, OPENROUTER_API_KEY, BRAVE_API_KEY, TELEGRAM_BOT_TOKEN, TELEGRAM_BOT_USERNAME, TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE_NUMBER, CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN, CLOUDFLARE_TUNNEL_ID, GODADDY_API_KEY, GODADDY_API_SECRET, VERCEL_TOKEN, GOG_ACCOUNT, GOG_KEYRING_PASSWORD, OPENCLAW_GATEWAY_TOKEN, XDG_CONFIG_HOME. Injected via env_file; host scripts read single lines (grep/sed) or source it.

In-container config/credentials/ (volume gia-credentials, root-only): ssh/whisper-bridge, gogcli/, linkedin/, branding/, gitea/, pulse/, ob1-db.url, arnao-auth-secrets.txt, mentor-app-role-passwords.txt, browser-extension-relay.secret, Telegram files. Single-file tokens: ~/.notify-ingest-token, ~/security-guardian/sentinel/.feed-token, notify-app/.notify-creds, ~/openclaw-gia2/secrets/{agent,broker,broker-creds}. Claude Code uses Max-plan OAuth in ~/.claude. No ~/.secrets. Caveats: a database password sits in plaintext in ~/openclaw-gia/docker-compose.yml (OB1_DB_URL) and WS/scripts/inbox/escalate.py (DB_URL); ops/twilio/browser-profile may hold session data.

10. Work log and byron-todos

~/ops/bin/slog --id X --title ... --summary ... --decision ... --status {done|open|needs-byron|in_progress} --importance 1-3 --project P --link "Label|https://..." appends to ~/ops/data/worklog.jsonl (latest per id wins; flock-safe; stdlib-only), re-renders ~/ops/render/session.html, re-derives WS/research/briefings/signal/byron-todos.json (DERIVED; env SLOG_TODOS overrides). ~/ops/bin/slog-card emit|resolve → ~/ops/data/cards.jsonl; taps POST to /signal/session/act on quip-service. Signal AM/PM crons read byron-todos.json; ~/quip-service/server.js serves it to Signal Live (~line 757). Convention: every Claude job ends with a slog call.

11. Google Drive and Gmail

Gmail, Calendar, Contacts via the gog CLI (v0.17.0) inside openclaw-gia; two accounts (gmail.com, arnao.com), scopes calendar,contacts,gmail; creds config/credentials/gogcli/, keyring GOG_KEYRING_PASSWORD. Used by morning brief, prefetch-brief.sh, skills/email-monitor, skills/signal-daily-podcast, scripts/gmail-both-accounts.py, collect-gmail.sh; unified inbox check every 30 min (run-inbox-check.sh). Examples: gog gmail search "is:unread newer_than:1d" --limit 20 --json, gog calendar events --all --today. Drive has no gog scope on the Mini; only the Claude desktop session has Drive/Gmail connectors. ~/.config/gogcli on the host is empty.

Other facts

Tailnet host mia.tail7e4190.ts.net. Colima docker socket ~/.colima/default/docker.sock; shells need LIMA_HOME=$HOME/.colima/_lima. Containers running: openclaw-gia, openclaw-gateway (Mia), openclaw-tia, openclaw-cia, openclaw-gia2 + sidecars. Deploy ~/.claude/skills/vercel-deploy/deploy.sh <dir> <subdomain>; deploy-static.sh, PREFLIGHT.sh in WS/scripts/deploy. Cost logging WS/scripts/cost/cost_logger.py (log_call, project tags like signal-podcast, rai-daily), ledger research/finance/cost-log/. Gia model guard cron pins anthropic/claude-opus-5 as primary, co-owned with scripts/health/self-heal.sh (EXPECTED_PRIMARY); change both together. Gia cron prompts: do not set host=sandbox, do not pass agentId=gia (use main).