- Revised AGENTS.md to provide comprehensive guidance for AI coding assistants, including project overview, architecture, and development commands. - Enhanced CLAUDE.md by adding the `auth` directory to the infrastructure section, clarifying the project's structure and components. - Improved formatting and organization of both documentation files for better readability and usability.
33 KiB
CLAUDE.md
This file provides guidance to Claude Code when working with code in this repository.
Project Overview
NoteFlow is an intelligent meeting notetaker: local-first audio capture + navigable recall + evidence-linked summaries. It is a client-server system built around a gRPC API for bidirectional audio streaming and transcription. The repository includes:
- Python backend (
src/noteflow/) — gRPC server, domain logic, infrastructure adapters - Tauri + React desktop client (
client/) — Rust for IPC, React UI (Vite)
The gRPC schema is the shared contract between backend and client; keep proto changes in sync across Python, Rust, and TypeScript.
Quick Orientation
| Entry Point | Description |
|---|---|
python -m noteflow.grpc.server |
Backend server (src/noteflow/grpc/server/__main__.py) |
cd client && npm run dev |
Web UI (Vite) |
cd client && npm run tauri dev |
Desktop Tauri dev (requires Rust toolchain) |
src/noteflow/grpc/proto/noteflow.proto |
Protobuf schema |
client/src/api/tauri-adapter.ts |
TypeScript → Rust IPC bridge |
client/src-tauri/src/commands/ |
Rust Tauri command handlers |
Build and Development Commands
# Install (editable with dev dependencies)
python -m pip install -e ".[dev]"
# Run gRPC server
python -m noteflow.grpc.server --help
# Run Tauri + React client UI
cd client && npm install && npm run dev
cd client && npm run tauri dev # Desktop (requires Rust)
# Tests
pytest # Full suite
pytest -m "not integration" # Skip external-service tests
pytest tests/domain/ # Run specific test directory
pytest -k "test_segment" # Run by pattern
# Docker (hot-reload enabled)
docker compose up -d postgres # PostgreSQL with pgvector
python scripts/dev_watch_server.py # Auto-reload server
Forbidden Docker Operations (without explicit permission)
docker compose build/up/down/restartdocker stop/docker kill- Any command that would interrupt the hot-reload server
Quality Commands (Makefile)
Always use Makefile targets instead of running tools directly.
Primary Quality Commands
make quality # Run ALL quality checks (TS + Rust + Python)
make quality-py # Python: lint + type-check + test-quality
make quality-ts # TypeScript: type-check + lint + test-quality
make quality-rs # Rust: clippy + lint
Python Quality
make lint-py # Basedpyright lint → .hygeine/basedpyright.lint.json
make type-check-py # Basedpyright strict mode
make test-quality-py # pytest tests/quality/
make lint-fix-py # Auto-fix Ruff + Sourcery issues
TypeScript Quality
make type-check # tsc --noEmit
make lint # Biome linter → .hygeine/biome.json
make lint-fix # Auto-fix Biome issues
make test-quality # Vitest quality tests
Rust Quality
make clippy # Clippy linter → .hygeine/clippy.json
make lint-rs # Code quality script → .hygeine/rust_code_quality.txt
make fmt-rs # Format with rustfmt
make fmt-check-rs # Check rustfmt formatting
Formatting
make fmt # Format all code (Biome + rustfmt)
make fmt-check # Check all formatting
E2E Tests
make e2e # Playwright tests (requires frontend on :5173)
make e2e-ui # Playwright tests with UI mode
make e2e-grpc # Rust gRPC integration tests
Architecture
src/noteflow/
├── domain/ # Entities, ports, value objects
│ ├── entities/ # Meeting, Segment, Summary, Annotation, NamedEntity, Integration, Project, Processing, SummarizationTemplate
│ ├── identity/ # User, Workspace, WorkspaceMembership, roles, context
│ ├── auth/ # OIDC discovery, claims, constants
│ ├── ports/ # Repository protocols
│ │ ├── repositories/
│ │ │ ├── transcript.py # MeetingRepository, SegmentRepository, SummaryRepository
│ │ │ ├── asset.py # AssetRepository
│ │ │ ├── background.py # DiarizationJobRepository
│ │ │ ├── external/ # WebhookRepository, IntegrationRepository, EntityRepository, UsageRepository
│ │ │ └── identity/ # UserRepository, WorkspaceRepository, ProjectRepository, MembershipRepository, SummarizationTemplateRepository
│ │ ├── unit_of_work.py # UnitOfWork protocol (supports_* capability checks)
│ │ ├── async_context.py # Async context utilities
│ │ ├── diarization.py # DiarizationEngine protocol
│ │ ├── ner.py # NEREngine protocol
│ │ └── calendar.py # CalendarProvider protocol
│ ├── webhooks/ # WebhookEventType, WebhookConfig, WebhookDelivery, payloads
│ ├── triggers/ # Trigger, TriggerAction, TriggerSignal, TriggerProvider
│ ├── summarization/# SummarizationProvider protocol
│ ├── rules/ # Business rules registry, models, builtin rules
│ ├── settings/ # Domain settings base
│ ├── constants/ # Field definitions, placeholders
│ ├── utils/ # time.py (utc_now), validation.py
│ ├── errors.py # Domain-specific exceptions
│ └── value_objects.py
├── application/ # Use-cases/services
│ ├── services/
│ │ ├── meeting/ # MeetingService (CRUD, segments, annotations, summaries, state)
│ │ ├── identity/ # IdentityService (context, workspace, defaults)
│ │ ├── calendar/ # CalendarService (connection, events, oauth, sync)
│ │ ├── summarization/ # SummarizationService, TemplateService, ConsentManager
│ │ ├── project_service/ # CRUD, members, roles, rules, active project
│ │ ├── recovery/ # RecoveryService (meeting, job, audio recovery)
│ │ ├── webhook_service.py
│ │ ├── ner_service.py
│ │ ├── export_service.py
│ │ ├── trigger_service.py
│ │ ├── retention_service.py
│ │ ├── auth_service.py
│ │ ├── auth_workflows.py
│ │ ├── auth_integration_manager.py
│ │ ├── auth_token_exchanger.py
│ │ ├── auth_types.py
│ │ ├── auth_constants.py
│ │ └── protocols.py
│ └── observability/ # Observability ports
├── infrastructure/ # Implementations
│ ├── audio/ # sounddevice capture, ring buffer, VU levels, playback, writer, reader
│ ├── asr/ # faster-whisper engine, VAD segmenter, streaming, DTOs
│ ├── auth/ # OIDC discovery, registry, presets
│ ├── diarization/ # Session, assigner, engine (streaming: diart, offline: pyannote)
│ ├── summarization/# CloudProvider, OllamaProvider, MockProvider, parsing, citation verifier, template renderer
│ ├── triggers/ # Calendar, audio_activity, foreground_app providers
│ ├── persistence/ # SQLAlchemy + asyncpg + pgvector
│ │ ├── database.py # create_async_engine, create_async_session_factory
│ │ ├── models/ # ORM models (core/, identity/, integrations/, entities/, observability/, organization/)
│ │ ├── repositories/ # Repository implementations
│ │ │ ├── meeting_repo.py
│ │ │ ├── segment_repo.py
│ │ │ ├── summary_repo.py
│ │ │ ├── annotation_repo.py
│ │ │ ├── entity_repo.py
│ │ │ ├── webhook_repo.py
│ │ │ ├── preferences_repo.py
│ │ │ ├── asset_repo.py
│ │ │ ├── summarization_template_repo.py
│ │ │ ├── diarization_job/
│ │ │ ├── integration/
│ │ │ ├── identity/
│ │ │ ├── usage_event/
│ │ │ └── _base/ # BaseRepository with _execute_scalar, _execute_scalars, _add_and_flush
│ │ ├── unit_of_work/
│ │ ├── memory/ # In-memory implementations
│ │ └── migrations/ # Alembic migrations
│ ├── security/ # Keystore (keyring + AES-GCM), protocols, crypto/
│ ├── crypto/ # Cryptographic utilities
│ ├── export/ # Markdown, HTML, PDF (WeasyPrint), formatting helpers
│ ├── webhooks/ # WebhookExecutor (delivery, signing, metrics)
│ ├── converters/ # ORM ↔ domain (orm, webhook, ner, calendar, integration, asr)
│ ├── calendar/ # Google/Outlook adapters, OAuth flow
│ ├── auth/ # OIDC registry, discovery, presets
│ ├── ner/ # spaCy NER engine
│ ├── observability/# OpenTelemetry tracing (otel.py), usage event tracking
│ ├── metrics/ # Metric collection utilities
│ ├── logging/ # Log buffer and utilities
│ └── platform/ # Platform-specific code
├── grpc/ # gRPC layer
│ ├── proto/ # noteflow.proto, generated *_pb2.py/*_pb2_grpc.py
│ ├── server/ # Bootstrap, lifecycle, setup, services, types
│ ├── service.py # NoteFlowServicer
│ ├── client.py # Python gRPC client wrapper
│ ├── meeting_store.py
│ ├── stream_state.py
│ ├── interceptors/ # Identity context propagation
│ ├── _mixins/ # Server-side gRPC mixins (see below)
│ └── _client_mixins/# Client-side gRPC mixins
├── cli/ # CLI tools
│ ├── __main__.py # CLI entry point
│ ├── retention.py # Retention management
│ ├── constants.py # CLI constants
│ └── models/ # Model commands (package)
│ ├── _download.py
│ ├── _parser.py
│ ├── _registry.py
│ ├── _status.py
│ └── _types.py
└── config/ # Pydantic settings (NOTEFLOW_ env vars)
├── settings/ # _main.py, _features.py, _triggers.py, _calendar.py, _loaders.py
└── constants/
gRPC Server Mixins (grpc/_mixins/)
_mixins/
├── streaming/ # ASR streaming (package)
│ ├── _mixin.py # Main StreamingMixin
│ ├── _session.py # Session management
│ ├── _asr.py # ASR processing
│ ├── _processing/ # Audio processing pipeline
│ │ ├── _audio_ops.py
│ │ ├── _chunk_tracking.py
│ │ ├── _congestion.py
│ │ ├── _constants.py
│ │ ├── _types.py
│ │ └── _vad_processing.py
│ ├── _partials.py # Partial transcript handling
│ ├── _cleanup.py # Resource cleanup
│ └── _types.py
├── diarization/ # Speaker diarization (package)
│ ├── _mixin.py # Main DiarizationMixin
│ ├── _jobs.py # Background job management
│ ├── _refinement.py# Offline refinement
│ ├── _streaming.py # Real-time diarization
│ ├── _speaker.py # Speaker assignment
│ ├── _status.py # Job status tracking
│ └── _types.py
├── summarization/ # Summary generation (package)
│ ├── _generation_mixin.py
│ ├── _templates_mixin.py
│ ├── _consent_mixin.py
│ ├── _template_crud.py
│ ├── _template_resolution.py
│ ├── _summary_generation.py
│ ├── _consent.py
│ └── _context_builders.py
├── meeting/ # Meeting lifecycle (package)
│ ├── meeting_mixin.py
│ ├── _project_scope.py
│ └── _stop_ops.py
├── project/ # Project management (package)
│ ├── _mixin.py
│ ├── _membership.py
│ └── _converters.py
├── oidc/ # OIDC authentication (package)
│ ├── oidc_mixin.py
│ └── _support.py
├── converters/ # Proto ↔ domain converters (package)
│ ├── _domain.py
│ ├── _external.py
│ ├── _timestamps.py
│ ├── _id_parsing.py
│ └── _oidc.py
├── errors/ # gRPC error helpers (package)
│ ├── _abort.py # abort_not_found, abort_invalid_argument
│ ├── _require.py # Requirement checks
│ ├── _fetch.py # Fetch with error handling
│ ├── _parse.py # Parsing helpers
│ └── _constants.py
├── servicer_core/ # Core servicer protocols
├── servicer_other/ # Additional servicer protocols
├── annotation.py # Segment annotations CRUD
├── export.py # Markdown/HTML/PDF export
├── entities.py # Named entity extraction
├── calendar.py # Calendar sync operations
├── webhooks.py # Webhook management
├── preferences.py # User preferences
├── observability.py # Usage tracking, metrics
├── identity.py # User/workspace identity
├── sync.py # State synchronization
├── diarization_job.py# Job status/management
├── protocols.py # ServicerHost protocol
├── _types.py
├── _audio_processing.py
├── _repository_protocols.py
└── _servicer_state.py
gRPC Client Mixins (grpc/_client_mixins/)
_client_mixins/
├── streaming.py # Client streaming operations
├── meeting.py # Meeting CRUD operations
├── diarization.py # Diarization requests
├── export.py # Export requests
├── annotation.py # Annotation operations
├── converters.py # Response converters
└── protocols.py # ClientHost protocol
Client Architecture (Tauri + React)
client/src/
├── api/ # API layer
│ ├── tauri-adapter.ts # Main Tauri IPC adapter
│ ├── mock-adapter.ts # Mock adapter for testing
│ ├── cached-adapter.ts # Caching layer
│ ├── connection-state.ts # Connection state machine
│ ├── reconnection.ts # Auto-reconnection logic
│ ├── interface.ts # Adapter interface
│ ├── transcription-stream.ts
│ ├── types/ # Type definitions
│ │ ├── core.ts # Core types (Meeting, Segment, etc.)
│ │ ├── enums.ts # Enum definitions
│ │ ├── errors.ts # Error types
│ │ ├── projects.ts # Project types
│ │ ├── diagnostics.ts
│ │ ├── requests.ts
│ │ ├── features/ # Feature-specific types
│ │ │ ├── webhooks.ts
│ │ │ ├── calendar.ts
│ │ │ ├── ner.ts
│ │ │ ├── sync.ts
│ │ │ ├── identity.ts
│ │ │ ├── oidc.ts
│ │ │ └── observability.ts
│ │ └── requests/ # Request types by domain
│ └── cached/ # Cached adapter implementations
│ ├── base.ts
│ ├── meetings.ts
│ ├── projects.ts
│ ├── diarization.ts
│ ├── annotations.ts
│ ├── templates.ts
│ ├── webhooks.ts
│ ├── calendar.ts
│ ├── entities.ts
│ ├── preferences.ts
│ ├── observability.ts
│ ├── triggers.ts
│ ├── audio.ts
│ ├── playback.ts
│ ├── apps.ts
│ └── readonly.ts
├── hooks/ # Custom React hooks
│ ├── use-diarization.ts
│ ├── use-cloud-consent.ts
│ ├── use-webhooks.ts
│ ├── use-oauth-flow.ts
│ ├── use-calendar-sync.ts
│ ├── use-entity-extraction.ts
│ ├── use-audio-devices.ts
│ ├── use-project.ts
│ ├── use-project-members.ts
│ ├── use-oidc-providers.ts
│ ├── use-auth-flow.ts
│ ├── use-integration-sync.ts
│ ├── use-integration-validation.ts
│ ├── use-secure-integration-secrets.ts
│ ├── use-guarded-mutation.ts
│ ├── use-panel-preferences.ts
│ ├── use-preferences-sync.ts
│ ├── use-meeting-reminders.ts
│ ├── use-recording-app-policy.ts
│ ├── use-post-processing.ts
│ ├── use-toast.ts
│ ├── use-mobile.tsx
│ └── post-processing/
├── contexts/ # React contexts
│ ├── connection-context.tsx # gRPC connection context
│ ├── connection-state.ts
│ ├── workspace-context.tsx # Workspace context
│ ├── workspace-state.ts
│ ├── project-context.tsx # Project context
│ └── project-state.ts
├── components/ # React components
│ ├── ui/ # Reusable UI components (shadcn/ui)
│ ├── recording/ # Recording-specific components
│ ├── settings/ # Settings panel components
│ ├── analytics/ # Analytics visualizations
│ ├── projects/ # Project components
│ ├── icons/ # Icon components
│ └── ... # Top-level components
├── pages/ # Route pages
│ ├── Home.tsx
│ ├── Meetings.tsx
│ ├── MeetingDetail.tsx
│ ├── Recording.tsx
│ ├── Projects.tsx
│ ├── ProjectSettings.tsx
│ ├── Settings.tsx
│ ├── settings/ # Settings sub-pages
│ ├── People.tsx
│ ├── Tasks.tsx
│ ├── Analytics.tsx
│ ├── Index.tsx
│ └── NotFound.tsx
├── lib/ # Utilities
│ ├── config/ # Configuration (server, defaults, app-config, provider-endpoints)
│ ├── cache/ # Client-side caching (meeting-cache)
│ ├── format.ts
│ ├── utils.ts
│ ├── time.ts
│ ├── crypto.ts
│ ├── cva.ts
│ ├── styles.ts
│ ├── tauri-events.ts
│ ├── preferences.ts
│ ├── preferences-sync.ts
│ ├── entity-store.ts
│ ├── speaker-utils.ts
│ ├── ai-providers.ts
│ ├── ai-models.ts
│ ├── integration-utils.ts
│ ├── default-integrations.ts
│ ├── status-constants.ts
│ ├── timing-constants.ts
│ ├── object-utils.ts
│ ├── error-reporting.ts
│ ├── client-logs.ts
│ ├── client-log-events.ts
│ ├── log-groups.ts
│ ├── log-converters.ts
│ ├── log-messages.ts
│ ├── log-summarizer.ts
│ └── log-group-summarizer.ts
├── types/ # Shared TypeScript types
└── test/ # Test utilities
Rust/Tauri Backend (client/src-tauri/src/)
src-tauri/src/
├── commands/ # Tauri IPC command handlers
│ ├── recording/ # capture.rs, device.rs, audio.rs, app_policy.rs
│ ├── playback/ # audio.rs, events.rs, tick.rs
│ ├── triggers/ # audio.rs, polling.rs
│ ├── meeting.rs
│ ├── diarization.rs
│ ├── annotation.rs
│ ├── export.rs
│ ├── summary.rs
│ ├── entities.rs
│ ├── calendar.rs
│ ├── webhooks.rs
│ ├── preferences.rs
│ ├── observability.rs
│ ├── sync.rs
│ ├── projects.rs
│ ├── identity.rs
│ ├── oidc.rs
│ ├── connection.rs
│ ├── audio.rs
│ ├── audio_testing.rs
│ ├── apps.rs
│ ├── apps_platform.rs
│ ├── diagnostics.rs
│ ├── shell.rs
│ └── testing.rs
├── grpc/ # gRPC client
│ ├── client/ # Client implementations by domain
│ │ ├── core.rs
│ │ ├── meetings.rs
│ │ ├── annotations.rs
│ │ ├── diarization.rs
│ │ ├── identity.rs
│ │ ├── projects.rs
│ │ ├── preferences.rs
│ │ ├── calendar.rs
│ │ ├── webhooks.rs
│ │ ├── observability.rs
│ │ ├── oidc.rs
│ │ ├── sync.rs
│ │ └── converters.rs
│ ├── types/ # Rust type definitions
│ │ ├── core.rs
│ │ ├── enums.rs
│ │ ├── identity.rs
│ │ ├── projects.rs
│ │ ├── preferences.rs
│ │ ├── calendar.rs
│ │ ├── webhooks.rs
│ │ ├── observability.rs
│ │ ├── oidc.rs
│ │ ├── sync.rs
│ │ └── results.rs
│ ├── streaming/ # Streaming converters
│ └── noteflow.rs # Generated protobuf types
├── state/ # Runtime state management
│ ├── app_state.rs
│ ├── preferences.rs
│ ├── playback.rs
│ └── types.rs
├── audio/ # Audio capture and playback
├── cache/ # Memory caching
├── crypto/ # Cryptographic operations
├── events/ # Tauri event emission
├── triggers/ # Trigger detection
├── error/ # Error types
├── identity/ # Identity management
├── config.rs # Configuration
├── constants.rs # Constants
├── helpers.rs # Helper functions
├── oauth_loopback.rs # OAuth callback server
├── main.rs # Application entry point
└── lib.rs # Library exports
Database
PostgreSQL with pgvector extension. Async SQLAlchemy with asyncpg driver.
# Alembic migrations
alembic upgrade head
alembic revision --autogenerate -m "description"
Connection via NOTEFLOW_DATABASE_URL env var or settings.
ORM Models (persistence/models/)
| Directory | Models |
|---|---|
core/ |
MeetingModel, SegmentModel, SummaryModel, AnnotationModel, DiarizationJobModel |
identity/ |
UserModel, WorkspaceModel, WorkspaceMembershipModel, ProjectModel, ProjectMembershipModel, SettingsModel |
integrations/ |
IntegrationModel, IntegrationSecretModel, CalendarEventModel, MeetingCalendarLinkModel, WebhookConfigModel, WebhookDeliveryModel |
entities/ |
NamedEntityModel, SpeakerModel |
observability/ |
UsageEventModel |
organization/ |
SummarizationTemplateModel, TaskModel, TagModel |
Testing Conventions
- Test files:
test_*.py, functions:test_* - Markers:
@pytest.mark.slow(model loading),@pytest.mark.integration(external services) - Integration tests use testcontainers for PostgreSQL
- Asyncio auto-mode enabled
- React unit tests use Vitest; e2e tests use Playwright in
client/e2e/
Test Quality Gates (tests/quality/)
After any non-trivial changes, run:
pytest tests/quality/
This suite enforces:
| Check | Description |
|---|---|
test_test_smells.py |
No assertion roulette, no conditional test logic, no loops in tests |
test_magic_values.py |
No magic numbers in assignments |
test_code_smells.py |
Code quality checks |
test_duplicate_code.py |
No duplicate code patterns |
test_stale_code.py |
No stale/dead code |
test_decentralized_helpers.py |
Helpers consolidated properly |
test_unnecessary_wrappers.py |
No unnecessary wrapper functions |
test_baseline_self.py |
Baseline validation self-checks |
Global Fixtures (tests/conftest.py)
Do not redefine these fixtures:
| Fixture | Description |
|---|---|
reset_context_vars |
Reset logging context variables |
mock_uow |
Mock Unit of Work |
crypto |
Crypto utilities |
meetings_dir |
Temporary meetings directory |
webhook_config |
Single-event webhook config |
webhook_config_all_events |
All-events webhook config |
sample_datetime |
Sample datetime |
calendar_settings |
Calendar settings |
meeting_id |
Sample meeting ID |
sample_meeting |
Sample Meeting entity |
recording_meeting |
Recording-state Meeting |
sample_rate |
Audio sample rate |
mock_grpc_context |
Mock gRPC context |
mockasr_engine |
Mock ASR engine |
mock_optional_extras |
Mock optional extras |
mock_oauth_manager |
Mock OAuth manager |
memory_servicer |
In-memory servicer |
approx_float |
Approximate float comparison |
approx_sequence |
Approximate sequence comparison |
Code Style
Python
- Python 3.12+, 100-char line length
- 4-space indentation
- Naming:
snake_casemodules/functions,PascalCaseclasses,UPPER_SNAKE_CASEconstants - Strict basedpyright (0 errors, 0 warnings, 0 notes required)
- Ruff for linting (E, W, F, I, B, C4, UP, SIM, RUF)
- Module soft limit 500 LoC, hard limit 750 LoC
- Generated
*_pb2.py,*_pb2_grpc.pyexcluded from lint
TypeScript
- Biome for linting and formatting
- Single quotes, 100 char width
- Strict TypeScript (noEmit checks)
Rust
rustfmtfor formattingclippyfor linting (warnings treated as errors)
Type Safety (Zero Tolerance)
Forbidden Patterns (Python)
| Pattern | Why Blocked | Alternative |
|---|---|---|
# type: ignore |
Bypasses type safety | Fix the actual type error |
# pyright: ignore |
Bypasses type safety | Fix the actual type error |
Any type annotations |
Creates type safety holes | Use Protocol, TypeVar, TypedDict, or specific types |
| Magic numbers | Hidden intent | Define typing.Final constants |
| Loops in tests | Non-deterministic | Use @pytest.mark.parametrize |
| Conditionals in tests | Non-deterministic | Use @pytest.mark.parametrize |
| Multiple assertions without messages | Hard to debug | Add assertion messages |
Type Resolution Hierarchy
When facing dynamic types:
Protocol— For duck typing (structural subtyping)TypeVar— For genericsTypedDict— For structured dictionariescast()— Last resort (with comment explaining why)
Validation Requirements
After any code changes:
source .venv/bin/activate && basedpyright src/noteflow/
Expected output: 0 errors, 0 warnings, 0 notes
Automated Enforcement (Hookify Rules)
Protected Files (Require Explicit Permission)
| File/Directory | What's Blocked |
|---|---|
Makefile |
All modifications |
tests/quality/ (except baselines.json) |
All modifications |
pyproject.toml, ruff.toml, pyrightconfig.json |
All edits |
biome.json, tsconfig.json, .eslintrc* |
All edits |
.rustfmt.toml, .clippy.toml |
All edits |
Quality Gate Requirement
Before completing any code changes:
make quality
All quality checks must pass.
Policy: No Ignoring Pre-existing Issues
If you encounter lint errors, type errors, or test failures—even if they existed before your changes—you must either:
- Fix immediately (for simple issues)
- Add to todo list (for complex issues)
- Launch a subagent to fix (for parallelizable work)
Proto/gRPC
Proto definitions: src/noteflow/grpc/proto/noteflow.proto
Regenerate after proto changes:
python -m grpc_tools.protoc -I src/noteflow/grpc/proto \
--python_out=src/noteflow/grpc/proto \
--grpc_python_out=src/noteflow/grpc/proto \
src/noteflow/grpc/proto/noteflow.proto
Then run stub patching:
python scripts/patch_grpc_stubs.py
Sync Points (High Risk of Breakage)
When changing proto:
- Python stubs — Regenerate
*_pb2.py,*_pb2_grpc.py - Server mixins — Update
src/noteflow/grpc/_mixins/ - Python client — Update
src/noteflow/grpc/client.py - Rust types — Generated by
client/src-tauri/build.rs - Rust commands — Update
client/src-tauri/src/commands/ - TypeScript types — Update
client/src/api/types/ - TypeScript adapter — Update
client/src/api/tauri-adapter.ts
Key Subsystems
Speaker Diarization
- Streaming: diart for real-time speaker detection
- Offline: pyannote.audio for post-meeting refinement
- gRPC:
RefineSpeakerDiarization,GetDiarizationJobStatus,RenameSpeaker
Summarization
- Providers: CloudProvider (Anthropic/OpenAI), OllamaProvider (local), MockProvider (testing)
- Templates: Configurable tone, format, verbosity
- Citation verification: Links summary claims to transcript evidence
- Consent: Cloud providers require explicit user consent
Export
- Formats: Markdown, HTML, PDF (via WeasyPrint)
- Content: Transcript with timestamps, speaker labels, summary
Named Entity Recognition (NER)
- Engine: spaCy with transformer models
- Categories: person, company, product, technical, acronym, location, date, other
- Segment tracking: Entities link to source
segment_ids
Trigger Detection
- Signals: Calendar proximity, audio activity, foreground app
- Actions: IGNORE, NOTIFY, AUTO_START
Webhooks
- Events:
meeting.completed,summary.generated,recording.started,recording.stopped - Delivery: Exponential backoff retries
- Security: HMAC-SHA256 signing
Authentication
- OIDC: OpenID Connect with discovery
- Providers: Configurable via OIDC registry
Feature Flags
| Flag | Default | Controls |
|---|---|---|
NOTEFLOW_FEATURE_TEMPLATES_ENABLED |
true |
AI summarization templates |
NOTEFLOW_FEATURE_PDF_EXPORT_ENABLED |
true |
PDF export format |
NOTEFLOW_FEATURE_NER_ENABLED |
false |
Named entity extraction |
NOTEFLOW_FEATURE_CALENDAR_ENABLED |
false |
Calendar sync |
NOTEFLOW_FEATURE_WEBHOOKS_ENABLED |
true |
Webhook notifications |
Access via get_feature_flags().<flag_name> or get_settings().feature_flags.<flag_name>.
Common Pitfalls Checklist
When Adding New Features
- Update proto schema first (if gRPC involved)
- Regenerate Python stubs
- Run
scripts/patch_grpc_stubs.py - Implement server mixin
- Update Python client wrapper
- Update Rust commands
- Update TypeScript adapter
- Update TypeScript types
- Add tests (both backend and client)
- Run
make quality
When Changing Database Schema
- Update ORM models in
persistence/models/ - Create Alembic migration
- Update repository implementation
- Update UnitOfWork if needed
- Update converters in
infrastructure/converters/
When Modifying Existing Code
- Search for all usages first
- Update all call sites
- Run
make quality - Run relevant tests
Known Issues & Technical Debt
See docs/triage.md for tracked technical debt.
See docs/sprints/ for feature implementation plans.
MCP Tools Reference
Firecrawl (Web Scraping & Search)
| Tool | Use Case |
|---|---|
firecrawl_scrape |
Extract content from a single URL (markdown, HTML, screenshots) |
firecrawl_search |
Web search with optional content extraction; supports operators (site:, inurl:, -exclude) |
firecrawl_map |
Discover all URLs on a website before scraping |
firecrawl_crawl |
Multi-page crawl with depth/limit controls (use sparingly—token-heavy) |
firecrawl_extract |
LLM-powered structured data extraction with JSON schema |
Workflow: Search first without scrapeOptions, then scrape relevant URLs individually.
Sequential Thinking (Reasoning)
| Tool | Use Case |
|---|---|
sequentialthinking |
Break down complex problems into numbered thought steps; supports revision, branching, and hypothesis verification |
When to use: Multi-step analysis, design decisions, debugging with course-correction, architecture planning.
Context7 (Library Documentation)
| Tool | Use Case |
|---|---|
resolve-library-id |
Convert package name → Context7 library ID (required first step) |
query-docs |
Fetch up-to-date docs with specific query |
Workflow: resolve-library-id("fastapi") → query-docs(libraryId="/tiangolo/fastapi", query="how to handle dependencies").
Serena (Semantic Code Tools)
Navigation (prefer over grep/read for code):
| Tool | Use Case |
|---|---|
get_symbols_overview |
List top-level symbols in a file (classes, functions, variables) |
find_symbol |
Search by name path pattern; use depth for children, include_body for source |
find_referencing_symbols |
Find all references to a symbol across the codebase |
search_for_pattern |
Regex search across files (for non-symbol searches) |
Editing (atomic symbol-level changes):
| Tool | Use Case |
|---|---|
replace_symbol_body |
Replace entire symbol definition |
insert_before_symbol / insert_after_symbol |
Add code adjacent to a symbol |
rename_symbol |
Rename across entire codebase |
Memory (persistent cross-session knowledge):
| Tool | Use Case |
|---|---|
list_memories |
Show available project memories |
read_memory / write_memory |
Retrieve or store project knowledge |
Guardrails (call before major actions):
| Tool | Use Case |
|---|---|
think_about_collected_information |
Validate research completeness after search sequences |
think_about_task_adherence |
Verify alignment before editing code |
think_about_whether_you_are_done |
Confirm task completion |
Principle: Use symbolic tools over file reads; retrieve symbol bodies only when needed for understanding or editing.