30 KiB
AGENTS.md
This file provides guidance to AI coding assistants (Cursor, Copilot, Codex, etc.) 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
│ ├── ner/ # spaCy engine
│ ├── observability/# OpenTelemetry tracing, usage tracking
│ ├── metrics/ # Metric collection
│ ├── logging/ # Log buffer utilities
│ └── platform/ # Platform-specific code
├── grpc/ # gRPC server and client
│ ├── server/ # Server entry point (__main__.py, __init__.py)
│ ├── service.py # NoteFlowServicer (composes mixins)
│ ├── client.py # Python gRPC client wrapper
│ ├── _mixins/ # Modular RPC implementations
│ │ ├── streaming/ # ASR streaming (package)
│ │ │ ├── _mixin.py # Main StreamingMixin class
│ │ │ ├── _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 # Type definitions
│ │ ├── diarization/ # Speaker diarization (package)
│ │ │ ├── _mixin.py # Main DiarizationMixin class
│ │ │ ├── _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 # Type definitions
│ │ ├── meeting/ # Meeting lifecycle (package)
│ │ │ ├── meeting_mixin.py
│ │ │ ├── _project_scope.py
│ │ │ └── _stop_ops.py
│ │ ├── summarization.py # Summary generation
│ │ ├── annotation.py # Segment annotations CRUD
│ │ ├── export.py # Document export
│ │ ├── entities.py # Named entity extraction
│ │ ├── calendar.py # Calendar sync
│ │ ├── webhooks.py # Webhook management
│ │ ├── preferences.py # User preferences
│ │ ├── observability.py # Usage tracking, metrics
│ │ ├── sync.py # State synchronization
│ │ ├── identity.py # Identity operations
│ │ ├── projects.py # Project operations
│ │ ├── oidc.py # OIDC operations
│ │ ├── converters.py # Protobuf ↔ domain converters
│ │ ├── errors.py # gRPC error helpers
│ │ ├── protocols.py # ServicerHost protocol
│ │ └── _audio_helpers.py # Audio utilities
│ ├── _client_mixins/ # Python client mixins
│ │ ├── streaming.py
│ │ ├── meeting.py
│ │ ├── diarization.py
│ │ ├── export.py
│ │ ├── annotation.py
│ │ ├── converters.py
│ │ └── protocols.py
│ ├── interceptors/ # gRPC server interceptors
│ │ └── identity.py # Identity context propagation
│ └── proto/ # Protobuf definitions and generated stubs
├── 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/ # Configuration
├── settings/ # Pydantic settings (_base, _features, _server, _security, etc.)
├── constants.py # Application constants
└── feature_flags.py
Client Architecture (client/src/)
client/src/
├── api/ # API layer with adapters
│ ├── 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 definition
│ └── types/ # API type definitions
│ ├── core.ts
│ ├── meetings.ts
│ ├── segments.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
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.
Configuration & Security
- Runtime settings from
.envorNOTEFLOW_environment variables - Settings module:
src/noteflow/config/settings/ - Keep secrets and credentials out of the repo
- Use
.envfor local development configuration
Commit & Pull Request Guidelines
- Use Conventional Commits:
feat:,fix:,chore:,docs:,refactor:,test: - Include concise scope when helpful:
feat(grpc): add streaming backpressure - PRs should:
- Describe the change clearly
- Link related issues/specs
- Note any DB or proto changes
- Include UI screenshots for client changes
- Pass all quality checks (
make quality)
Fast Apply: IMPORTANT: Use edit_file over str_replace or full file writes. It works with partial code snippets—no need for full file content.
Warp Grep: warp-grep is a subagent that takes in a search string and tries to find relevant context. Best practice is to use it at the beginning of codebase explorations to fast track finding relevant files/lines. Do not use it to pin point keywords, but use it for broader semantic queries. "Find the XYZ flow", "How does XYZ work", "Where is XYZ handled?", "Where is coming from?"