Personal vs Business

Luna ships in two variants — Personal for single-user companion use and Business for team deployments with JWT auth, rate limiting, and professional persona.

Overview

Set LUNA_VARIANT in .env to choose the deployment mode. The variant affects authentication, proactive behaviour, away-state logic, persona tone, and rate limiting.

.env
LUNA_VARIANT=personal   # default — single-user companion
# or
LUNA_VARIANT=business   # team deployment with JWT and rate limiting

Feature comparison

FeaturePersonalBusiness
AuthenticationNone (localhost-only)JWT bearer tokens, configurable expiry
Multi-userSingle userMultiple users, per-user memory
Rate limitingDisabledConfigurable per-minute + burst limits
Away detectionEnabled (farewell phrases)Disabled
Proactive messagesCompanion check-ins, state alertsTask/event notifications only
ToneWarm, casual, companionProfessional, configurable
Voice pipelineFull (desktop wake-word)Configurable / optional
Personality RLFull (per-user drift)Bounded (professional floor)
Spotify / desktopEnabledDisabled by default
Persona nameLUNA_NAMELUNA_NAME + BUSINESS_NAME
DatabaseSQLite (default)PostgreSQL recommended

Personal variant

Designed for single-user, always-on companion use on a personal desktop or laptop. Prioritises warmth, proactivity, and natural conversation flow.

.env — personal
LUNA_VARIANT=personal

# Persona
LUNA_NAME=Luna
USER_NAME=Alex               # Luna uses this name when addressing the user

# No auth required — backend binds to localhost only
HOST=127.0.0.1
PORT=8899

Personal-only features

  • Away detection — farewell phrases trigger the away screen.
  • Companion check-in — LLM-generated messages after 25–180 quiet minutes.
  • State-aware proactive — morning brief, late-night nudge, back-from-work greeting.
  • Commitment follow-up — remembers interviews/exams and asks how they went.
  • Spotify control — play, pause, queue via voice or chat.
  • Desktop automation — launch apps, take screenshots, control volume/brightness.

Business variant

Designed for team deployments — multiple users sharing a Luna instance, with JWT authentication and a professional persona anchored to the organisation.

.env — business
LUNA_VARIANT=business

# Required for multi-user auth
JWT_SECRET=your-long-random-secret-here
JWT_EXPIRY_HOURS=720          # 30 days

# Rate limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=60
RATE_LIMIT_BURST=20

# Organisation persona
BUSINESS_NAME=Acme Corp
BUSINESS_DESCRIPTION=a SaaS company building developer tools
BUSINESS_TONE=professional    # professional | friendly | technical | concise
LUNA_NAME=Luna

# Production database recommended
DB_URL=postgresql+psycopg2://user:pass@db.example.com:5432/luna
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20

# Bind to all interfaces (behind a reverse proxy)
HOST=0.0.0.0
PORT=8899

Business-only features

  • JWT authentication — every API request must carry a valid bearer token.
  • Per-user memory isolation — facts, personality state, and conversation history are scoped to the authenticated user.
  • Rate limiting — per-user per-minute limits with burst allowance.
  • Professional tone floor — personality RL drift is bounded so Luna never becomes overly casual.
  • Organisation context — system prompt includes business name, description, and tone.

Authentication (JWT)

In the business variant, the backend generates JWT tokens signed withJWT_SECRET. All protected endpoints require:

request header
Authorization: Bearer <token>

Generate a token

terminal
curl -X POST http://localhost:8899/api/auth/token \
  -H "Content-Type: application/json" \
  -d '{"username": "alice", "password": "..."}'

# Response:
{ "access_token": "eyJ0eXA...", "token_type": "bearer" }

Token configuration

Env varDefaultDescription
JWT_SECRET(empty)HMAC secret for signing tokens. Set a long random string in production.
JWT_EXPIRY_HOURS720Token lifetime in hours (default: 30 days).
📌
If JWT_SECRET is empty in business variant, the backend will refuse to start — authentication without a secret is insecure.

Rate limiting

Rate limiting uses a sliding-window algorithm per authenticated user. Requests over the limit receive 429 Too Many Requests.

Env varDefaultDescription
RATE_LIMIT_ENABLEDfalseEnable/disable rate limiting.
RATE_LIMIT_PER_MINUTE60Max requests per user per minute.
RATE_LIMIT_BURST20Additional burst allowance above the per-minute limit.

Persona configuration

Both variants support persona customisation:

Env varPersonal defaultBusiness defaultDescription
LUNA_NAMEL.U.N.A.L.U.N.A.The name Luna introduces herself as.
USER_NAMEfrienduserHow Luna addresses the user (personal only).
BUSINESS_NAME(empty)Organisation name injected into the system prompt.
BUSINESS_DESCRIPTION(empty)One-sentence org description for context.
BUSINESS_TONEprofessionalprofessional | friendly | technical | concise
business persona example
LUNA_NAME=Aria
BUSINESS_NAME=Meridian Labs
BUSINESS_DESCRIPTION=a biotech company developing AI-assisted diagnostics
BUSINESS_TONE=technical

Switching variants

  1. Change LUNA_VARIANT in .env.
  2. If switching from personal → business, set JWT_SECRETand optionally add .env.business for variant-specific overrides.
  3. Restart the backend: python -m backend.main.
  4. Run alembic upgrade head if switching to a new database.
💡
Variant-specific env files (.env.personal, .env.business) are loaded on top of .env when the matching variant is active. Put variant-specific overrides there to avoid cluttering the base .env.