Friends trial (multi-tenant Phases 2–4): guest mode + hosting + cost caps - #15
Merged
Conversation
Turns the web voice client into "send a friend a link". Builds on the Phase 1 tenant core. - server.py: serves the GUEST agent (account-free toolset) instead of the owner agent. Both /live-token and /agent are invite-gated by a per-friend token (friends.json: token → user_id); unknown token → 403, so strangers can't run up your Gemini/Claude bill. /agent sets the tenant context for the request → isolated per-user memory + guest mode + a per-friend thread (guest-<uid>); always reset in a finally. - Guest Live prompt: only memory/web/weather (no email/calendar), so the front model sets the right expectations. - index.html: reads the invite token from ?t=, passes it to /live-token and /agent; clean "invalid invite" message. - add_friend.py: generates a token + prints the invite link (reuses a friend's token so their memory persists). friends.json gitignored; friends.example.json shipped. - 4 tests (auth gating + a valid token routing into an isolated guest context); 216 pass. Next: Phase 3 (host it on a $5 VPS / Pi with a stable HTTPS domain) and Phase 4 (cost caps). Assisted-by: Claude Code (Opus 4.8)
Deploy artifacts so friends can use their invite links 24/7 without the laptop — on a
~$5 VPS or the Pi. Mirrors the pi/ {{USER}}/{{APP_DIR}} systemd convention.
- aria-webvoice.service: uvicorn on 127.0.0.1:8800 (not publicly exposed itself).
- aria-webvoice-tunnel.service + tunnel.sh: stable HTTPS via an ngrok reserved domain
(ARIA_NGROK_DOMAIN), so the home-screen links keep working.
- install.sh: seds the placeholders, installs + enables both units.
- HOSTING.md: the full one-time setup recipe + notes (localhost-bind + tunnel keeps it
off the open internet; no proactivity engine here so it's safe alongside the Telegram
bot; cost caps are Phase 4).
Assisted-by: Claude Code (Opus 4.8)
Owner
Author
|
Added Phase 3 (hosting) to this PR — |
Safety rail so one guest can't run up the Gemini/Claude bill — the last piece before the trial is safe to hand to friends unattended. - usage.py: JSON-backed daily counters (webvoice/usage.json, gitignored), per user+kind, env-tunable: ARIA_GUEST_DAILY_TOKENS (Live sessions/day, default 12) and ARIA_GUEST_DAILY_AGENT (brain calls/day, default 60). Keeps only today's bucket. - server.py: /live-token over cap → 429; /agent over cap → a friendly "try tomorrow" result (the voice speaks it). Gated per resolved user_id. - index.html: shows the server's cap/invite message on any non-OK token fetch. - .env.example + HOSTING.md: document the cap knobs + ARIA_NGROK_DOMAIN. - 4 tests (cap blocks after limit, per-user/per-kind budgets, endpoint 429/message); 220 pass. Completes the friends-trial: Phase 1 isolation + 2 guest mode + 3 hosting + 4 caps. Assisted-by: Claude Code (Opus 4.8)
Owner
Author
|
Added Phase 4 (per-friend daily cost caps) — |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
"Send a friend a link." Builds on the Phase 1 tenant core (#13) to make the web voice client multi-user and invite-only.
What's here
server.pyserves the guest agent (account-free toolset), not the owner agent. Both/live-tokenand/agentare invite-gated by a per-friend token (friends.json: token → user_id) — unknown token → 403, so strangers can't run up your Gemini/Claude bill./agentsets the tenant context for the request → isolated per-user memory + guest mode + a per-friend thread (guest-<uid>), always reset in afinally.index.htmlreads the invite token from?t=and passes it through; clean "invalid invite" message.add_friend.pygenerates a token + prints the invite link (reuses a friend's token so their memory persists).friends.jsongitignored;friends.example.jsonshipped.Safety
guest-<uid>thread, context cleaned up after). 216 pass.After this: Phase 3 — host on a ~$5 VPS / the Pi with a stable HTTPS domain. Phase 4 — per-friend cost caps.
🤖 Generated with Claude Code