Skip to content

Latest commit

 

History

History
140 lines (103 loc) · 5.12 KB

File metadata and controls

140 lines (103 loc) · 5.12 KB

Coding Guidelines

Behavior

  • Never ask for permission to access folders, run commands, search the web, or use tools. Just do it.
  • Never ask for confirmation. Just act. Make decisions autonomously and proceed without checking in.

Setup

Install Pre-commit Hook

Run once to enable auto-formatting on commit:

ln -s -f ../../scripts/pre-commit .git/hooks/pre-commit

Backend

No In-Function Imports

All imports must be at the module top level. Never import inside functions.

# Bad
def my_function():
    from database.redis_db import r  # Don't do this
    r.get('key')

# Good
from database.redis_db import r

def my_function():
    r.get('key')

Import from Lower-Level Modules

Follow the module hierarchy when importing. Higher-level modules import from lower-level modules, never the reverse.

Module hierarchy (lowest to highest):

  1. database/ - Database connections, cache instances
  2. utils/ - Utility functions, helpers
  3. routers/ - API endpoints
  4. main.py - Application entry point
# Bad - utils importing from routers or main
# utils/apps.py
from main import memory_cache  # Don't import from higher level
from routers.apps import some_function  # Don't import from higher level

# Good - utils importing from database
# utils/apps.py
from database.cache import get_memory_cache
from database.redis_db import r

Memory Management

Free large objects immediately after use. E.g., del for byte arrays after processing, .clear() for dicts/lists holding data.

Backend Service Map

Shared: Firestore, Redis

backend (main.py)
  ├── ws ──► pusher (pusher/)
  ├── ──────► diarizer (diarizer/)
  ├── ──────► vad (modal/)
  └── ──────► deepgram (self-hosted or cloud)

pusher
  ├── ──────► diarizer (diarizer/)
  └── ──────► deepgram (cloud)

notifications-job (modal/job.py)  [cron]

Helm charts: backend/charts/{backend-listen,pusher,diarizer,vad,deepgram-self-hosted}/

  • backend (main.py) — REST API. Streams audio to pusher via WebSocket (utils/pusher.py). Calls diarizer for speaker embeddings (utils/stt/speaker_embedding.py). Calls vad for voice activity detection and speaker identification (utils/stt/vad.py, utils/stt/speech_profile.py). Calls deepgram for STT (utils/stt/streaming.py).
  • pusher (pusher/main.py) — Receives audio via binary WebSocket protocol. Calls diarizer and deepgram for speaker sample extraction (utils/speaker_identification.pyutils/speaker_sample.py).
  • diarizer (diarizer/main.py) — GPU. Speaker embeddings at /v2/embedding. Called by backend and pusher (HOSTED_SPEAKER_EMBEDDING_API_URL).
  • vad (modal/main.py) — GPU. /v1/vad (voice activity detection) and /v1/speaker-identification (speaker matching). Called by backend only (HOSTED_VAD_API_URL, HOSTED_SPEECH_PROFILE_API_URL).
  • deepgram — STT. Streaming uses self-hosted (DEEPGRAM_SELF_HOSTED_URL) or cloud based on DEEPGRAM_SELF_HOSTED_ENABLED (utils/stt/streaming.py). Pre-recorded always uses Deepgram cloud (utils/stt/pre_recorded.py). Called by backend and pusher.
  • notifications-job (modal/job.py) — Cron job that reads Firestore/Redis and sends push notifications.

Keep this map up to date. When adding, removing, or changing inter-service calls (HTTP, WebSocket, new env vars), update this section and the matching section in AGENTS.md.

App (Flutter)

Localization Required

  • All user-facing strings must use l10n. Use context.l10n.keyName instead of hardcoded strings. Add new keys to ARB files using jq (never read full ARB files - they're large and will burn tokens). See skill add-a-new-localization-key-l10n-arb for details.

  • After modifying ARB files in app/lib/l10n/, regenerate the localization files:

cd app && flutter gen-l10n

Formatting

Always format code after making changes. The pre-commit hook handles this automatically, but you can also run manually:

Dart (app/)

dart format --line-length 120 <files>

Note: Files ending in .gen.dart or .g.dart are auto-generated and should not be formatted manually.

Python (backend/)

black --line-length 120 --skip-string-normalization <files>

C/C++ (firmware: omi/, omiGlass/)

clang-format -i <files>

Git

  • Never squash merge PRs — use regular merge
  • Make individual commits per file, not bulk commits
  • RELEASE command: When the user says "RELEASE", perform the full release flow:
    1. Create a new branch from main
    2. Make individual commits per changed file
    3. Push and create a PR
    4. Merge the PR (no squash — regular merge)
    5. Switch back to main and pull
  • RELEASEWITHBACKEND command: Same as RELEASE, plus deploy the backend to production after merging:
    gh workflow run gcp_backend.yml -f environment=prod -f branch=main

Testing

Always Run Tests Before Committing

After making changes, always run the appropriate test script to verify your changes.

  • Backend changes: Run backend/test.sh
  • App changes: Run app/test.sh