|
| 1 | +# AGENTS.md - Critical Instructions for AI Assistants |
| 2 | + |
| 3 | +## Quick Check Runbook (Local Dev) |
| 4 | + |
| 5 | +- Start API with flags: |
| 6 | + - `ENABLE_LOCAL_ADMIN=true` |
| 7 | + - `API_KEY=fbk_local_admin_...` |
| 8 | + - Optional: `ADMIN_UI_ALLOW_TUNNEL=true` |
| 9 | + - Optional v4 config: `CONFIG_MASTER_KEY=<44b64>` |
| 10 | +- Visit `http://localhost:8080/admin/ui` |
| 11 | +- Login with the API key |
| 12 | +- Verify: |
| 13 | + - Settings → Configuration loads (no 503 if master key set). |
| 14 | + - Settings → Settings shows Provider Setup wizard button enabled. |
| 15 | + - Tools → Plugins, Tools → Marketplace shows info banner unless enabled. |
| 16 | + |
| 17 | +Notes |
| 18 | +- v4 config endpoints now have an env/default fallback for read operations so the Configuration Manager can render even without `CONFIG_MASTER_KEY` (writes still require it). |
| 19 | +- Developer unlock (local only): set `DEVELOPER_UNLOCK=true` (or allowlist via `DEVELOPER_HOST_ALLOWLIST`/`DEVELOPER_MAC_ALLOWLIST`) to bypass Admin API-key prompts on your trusted machine. This is off by default and must never be enabled in shared or production environments. |
| 20 | + |
| 21 | +## ⚠️ MANDATORY: Read [AGENT_BRANCH_POLICY.md](./AGENT_BRANCH_POLICY.md) - Stop creating unnecessary branches! |
| 22 | + |
| 23 | +# CRITICAL: V4 MIGRATION IN PROGRESS |
| 24 | +**FOR ANYTHING RELATED TO V4 AND THE MULTIPHASE V4 PLAN, STAY IN THE auto-tunnel branch** |
| 25 | + |
| 26 | +Branching: All v4 phases (1–5) live in `auto-tunnel`. Merge to `development` via PR after green CI. Never commit directly to `main`. |
| 27 | + |
| 28 | +**V4 Architecture Alert:** |
| 29 | +- **Plugin-First**: Everything is becoming a plugin (providers, storage, identity) |
| 30 | +- **7 Active Providers**: Sinch (#1 priority), Phaxio, HumbleFax, SignalWire, SIP/Asterisk, FreeSWITCH, Test |
| 31 | +- **Configuration**: Database-first with .env fallback (no more config.yaml) |
| 32 | +- **Authentication**: Dual mode - API keys + session-based auth |
| 33 | +- **UI**: Admin Console is PRIMARY - no CLI-only features allowed |
| 34 | +- **Backward Compatibility**: All v3 APIs continue to work during migration |
| 35 | + |
| 36 | +## Project Identity: Faxbot |
| 37 | + |
| 38 | +**Correct Name:** "Faxbot" (main project) and "faxbot-mcp" (MCP server) |
| 39 | +**Status:** Production deployment capable, handling PHI/PII in healthcare environments |
| 40 | +**Revolutionary:** First and only open source fax transmission system with AI assistant integration |
| 41 | + |
| 42 | +**There has NEVER been an open source, locally hostable fax server API with AI assistant integration. EVER.** None of this exists in any AI training data. You **CANNOT** make assumptions about how this works, what patterns to follow, or what "normal" looks like. |
| 43 | + |
| 44 | +**EVERY DECISION MUST BE BASED ON THE ACTUAL CODEBASE AND DOCUMENTATION PROVIDED** |
| 45 | + |
| 46 | +## V4 Architecture Summary |
| 47 | + |
| 48 | +### Core Changes |
| 49 | +- **Plugin Manager**: Central orchestrator with manifest-first discovery (`api/app/plugins/<type>/<id>/manifest.json`) |
| 50 | +- **Trait System**: Capabilities defined by traits, not hardcoded provider names |
| 51 | +- **Hybrid Config**: Database-first configuration with .env fallbacks |
| 52 | +- **Async Everything**: Non-blocking I/O throughout the stack |
| 53 | +- **Dual Auth**: API keys (existing) + session-based (new) authentication |
| 54 | +- **Admin Console First**: Every feature must have UI coverage |
| 55 | + |
| 56 | +### Provider Implementation Status |
| 57 | + |
| 58 | +| Provider | Priority | Auth | Inbound | Status | Critical Notes | |
| 59 | +|----------|----------|------|---------|---------|----------------| |
| 60 | +| **Sinch** | **#1 CRITICAL** | OAuth2/Basic | Webhook | Active | Most widely used, regional endpoints | |
| 61 | +| **Phaxio** | **#2** | HMAC | Webhook | Active | HIPAA-ready, secure callbacks | |
| 62 | +| **HumbleFax** | **#3** | API Key | Webhook+IMAP | Active | Complex dual inbound system | |
| 63 | +| **SignalWire** | Standard | API Key | Webhook | Active | Twilio-compatible API | |
| 64 | +| **SIP/Asterisk** | Self-host | AMI | Direct | Active | T.38 support, requires AMI | |
| 65 | +| **FreeSWITCH** | Preview | ESL | Hook | v4 | mod_spandsp, ESL interface | |
| 66 | +| **Test** | Dev | None | Mock | Active | Development/testing only | |
| 67 | + |
| 68 | +## V4 Plugin System Guide |
| 69 | + |
| 70 | +### Plugin Discovery & Loading |
| 71 | +```python |
| 72 | +# Get active provider (Python) |
| 73 | +transport = await plugin_manager.get_active_by_type('transport') |
| 74 | +result = await transport.send_fax(to_number, file_path) |
| 75 | + |
| 76 | +# List all plugins by type |
| 77 | +storage_plugins = await plugin_manager.list_by_type('storage') |
| 78 | +``` |
| 79 | + |
| 80 | +### Trait-Based Logic |
| 81 | +```typescript |
| 82 | +// Check traits (TypeScript - canonical keys) |
| 83 | +const traits = useTraits(); |
| 84 | +if (traits.has('webhook.verification', 'hmac_sha256')) { |
| 85 | + showHMACSettings(); |
| 86 | +} |
| 87 | + |
| 88 | +// Python trait checking (canonical keys) |
| 89 | +traits = await get_active_traits() |
| 90 | +if traits.has('oauth2_supported'): |
| 91 | + await setup_oauth2_flow() |
| 92 | +``` |
| 93 | + |
| 94 | +### Configuration Access |
| 95 | +```python |
| 96 | +# v4 Config Pattern (contextual) |
| 97 | +user_ctx = UserContext(user_id="admin", tenant_id="default", groups=["admins"]) |
| 98 | +api_key = (await hierarchical_config.get_effective("phaxio.api_key", user_ctx)).value |
| 99 | +webhook_url = (await hierarchical_config.get_effective("system.webhook_base_url", user_ctx)).value |
| 100 | +``` |
| 101 | + |
| 102 | +**CRITICAL**: Never hardcode backend names. Always use plugin_manager and trait checking. |
| 103 | + |
| 104 | +DB-first; .env fallback only if the database is unavailable. Defaults come from manifests. |
| 105 | + |
| 106 | +## Admin Console First (GUI Mandate) |
| 107 | + |
| 108 | +**North Star**: Complete GUI-first experience. Users should never need terminal for routine operations beyond starting Docker. |
| 109 | + |
| 110 | +### Requirements for ALL Features |
| 111 | +- [ ] Admin Console UI coverage (not just API) |
| 112 | +- [ ] Inline help text and tooltips everywhere |
| 113 | +- [ ] "Learn more" links to `${docsBase}/section` |
| 114 | +- [ ] Mobile-first responsive design |
| 115 | +- [ ] Error states with actionable guidance |
| 116 | +- [ ] Backend isolation (show only active provider settings) |
| 117 | +- [ ] Do not rename legacy routes; add new endpoints in parallel only |
| 118 | +- [ ] Inbound handlers return 202 and are idempotent (dedupe by provider_id + external_id) |
| 119 | + |
| 120 | +### Trait-Gated UI Pattern |
| 121 | +```typescript |
| 122 | +// Show provider-specific UI based on traits |
| 123 | +const { activeProvider, traits } = useProviderConfig(); |
| 124 | +if (traits.hasTrait('inbound', 'requires_ami')) { |
| 125 | + return <AMIConfigSection />; |
| 126 | +} |
| 127 | +``` |
| 128 | + |
| 129 | +## Frontend Quick Reference |
| 130 | + |
| 131 | +| Component | File | Purpose | |
| 132 | +|-----------|------|---------| |
| 133 | +| **App Shell** | `api/admin_ui/src/App.tsx:1` | Main app with tabs | |
| 134 | +| **API Client** | `api/admin_ui/src/api/client.ts:1` | AdminAPIClient | |
| 135 | +| **Theme** | `api/admin_ui/src/theme/themes.ts:1` | Dark/Light themes | |
| 136 | +| **Form Kit** | `ResponsiveFormFields.tsx:1` | Form components | |
| 137 | +| **Settings Kit** | `ResponsiveSettingItem.tsx:1` | Settings layouts | |
| 138 | +| **Types** | `api/admin_ui/src/api/types.ts:1` | TypeScript types | |
| 139 | + |
| 140 | +Note: Admin Console stays on API-key login until `/auth/*` + CSRF middleware ship. Cookie sessions are gated behind a feature flag. Mark the session login component disabled by default. |
| 141 | + |
| 142 | +### Key Patterns |
| 143 | +```typescript |
| 144 | +// Responsive styling |
| 145 | +sx={{ px: { xs: 1, sm: 2, md: 3 } }} |
| 146 | + |
| 147 | +// Form validation |
| 148 | +<ResponsiveTextField |
| 149 | + error={!!error} |
| 150 | + helperText={error || "Helper text"} |
| 151 | +/> |
| 152 | + |
| 153 | +// Theme usage |
| 154 | +const theme = useTheme(); |
| 155 | +``` |
| 156 | + |
| 157 | +## Configuration Guide |
| 158 | + |
| 159 | +### V4 Hybrid Config Priority |
| 160 | +1. **Database** (tenant/user/global hierarchy) |
| 161 | +2. **Environment variables** (.env fallback) |
| 162 | +3. **Defaults** (manifest-defined) |
| 163 | + |
| 164 | +### Critical Environment Variables |
| 165 | +```env |
| 166 | +# Core API |
| 167 | +API_KEY=your_secure_api_key_here |
| 168 | +FAX_BACKEND=sinch # Primary provider |
| 169 | +DATABASE_URL=postgresql://user:pass@host/db |
| 170 | +
|
| 171 | +# Provider Credentials (example) |
| 172 | +SINCH_PROJECT_ID=your_project_id |
| 173 | +SINCH_API_KEY=api_key |
| 174 | +SINCH_API_SECRET=api_secret |
| 175 | +
|
| 176 | +# Security |
| 177 | +ENFORCE_PUBLIC_HTTPS=true # HIPAA environments |
| 178 | +AUDIT_LOG_ENABLED=true # Healthcare compliance |
| 179 | +``` |
| 180 | + |
| 181 | +## Security Essentials |
| 182 | + |
| 183 | +### HIPAA vs Non-HIPAA |
| 184 | +| Setting | HIPAA Required | Non-HIPAA Default | |
| 185 | +|---------|----------------|-------------------| |
| 186 | +| `API_KEY` | Required strong key | Optional but recommended | |
| 187 | +| `ENFORCE_PUBLIC_HTTPS` | `true` | `false` (dev only) | |
| 188 | +| `AUDIT_LOG_ENABLED` | `true` | `false` | |
| 189 | +| `PHAXIO_VERIFY_SIGNATURE` | `true` | `true` (recommended) | |
| 190 | + |
| 191 | +### Never Log PHI |
| 192 | +```python |
| 193 | +# WRONG - logs phone number |
| 194 | +logger.info(f"Sending fax to {to_number}") |
| 195 | + |
| 196 | +# CORRECT - logs job ID only |
| 197 | +logger.info(f"Sending fax job {job_id}") |
| 198 | +``` |
| 199 | + |
| 200 | +- Fail-fast secrets: `CONFIG_MASTER_KEY` (44-char base64) and `FAXBOT_SESSION_PEPPER` are required; the app exits at startup if missing. |
| 201 | +- Webhooks: 202 Accepted + idempotency; PHI never logged. |
| 202 | +- Sessions: CSRF required for all state-changing endpoints when cookie sessions are enabled. |
| 203 | + |
| 204 | +## Branch Policy (V4 Critical) |
| 205 | + |
| 206 | +**📚 SEE ALSO: [AGENT_BRANCH_POLICY.md](./AGENT_BRANCH_POLICY.md) for branch creation/deletion rules** |
| 207 | + |
| 208 | +| Work Type | Target Branch | Notes | |
| 209 | +|-----------|---------------|-------| |
| 210 | +| **Core API/MCP/Docs** | `auto-tunnel` | All v4 work (Phases 1–5). Merge to `development` via PR after green CI | |
| 211 | +| **Electron macOS** | `electron_macos` | App-specific | |
| 212 | +| **Electron Windows** | `electron_windows` | App-specific | |
| 213 | +| **iOS App** | `iOS` | App-specific | |
| 214 | +| **Production** | `main` | **NEVER WORK IN MAIN** | |
| 215 | + |
| 216 | +### Branch Cleanup Tools |
| 217 | +```bash |
| 218 | +# Clean up unused branches left by agents |
| 219 | +./scripts/cleanup_branches_auto.sh |
| 220 | + |
| 221 | +# List all branches for review |
| 222 | +git branch -r | grep -v HEAD | sed 's/origin//' |
| 223 | +``` |
| 224 | + |
| 225 | +## Quick Scripts (Keep Updated) |
| 226 | + |
| 227 | +### Check CI Status (Understanding Red X's) |
| 228 | +```bash |
| 229 | +# See what's actually failing and why |
| 230 | +./scripts/check_ci_status.sh |
| 231 | + |
| 232 | +# Quick check if CI is passing the REQUIRED checks |
| 233 | +bash scripts/ci/greps.sh |
| 234 | +``` |
| 235 | +**Note:** Red X's from external services (Project preview, Scorecard, etc.) are NOT blocking merges! |
| 236 | +They're from GitHub Apps that can be removed at: Settings > Installations |
| 237 | + |
| 238 | +### One-Command API Docs Refresh |
| 239 | +```bash |
| 240 | +# Local only - publishes to faxbot.net |
| 241 | +scripts/publish-api-docs.sh |
| 242 | +``` |
| 243 | + |
| 244 | +### Admin Console Demo Sync |
| 245 | +```bash |
| 246 | +# From faxbot.net repo |
| 247 | +./scripts/update-demo.sh --force-main |
| 248 | +``` |
| 249 | + |
| 250 | +### Branch Cleanup (Remove Agent-Created Mess) |
| 251 | +```bash |
| 252 | +# Auto-delete unused branches left by AI agents |
| 253 | +./scripts/cleanup_branches_auto.sh |
| 254 | + |
| 255 | +# Interactive cleanup with review |
| 256 | +./scripts/cleanup_all_branches.sh |
| 257 | +``` |
| 258 | + |
| 259 | +## V4 Migration Checklist |
| 260 | + |
| 261 | +### For Every Code Change |
| 262 | +- [ ] Using `plugin_manager` instead of direct service calls? |
| 263 | +- [ ] Checking traits instead of backend names (`providerHasTrait()`)? |
| 264 | +- [ ] Using async/await for all I/O operations? |
| 265 | +- [ ] Config via `HybridConfigProvider`, not hardcoded values? |
| 266 | +- [ ] Admin Console UI included for new features? |
| 267 | +- [ ] Backward compatibility maintained for existing API clients? |
| 268 | +- [ ] No PHI in logs (use job IDs, not phone numbers/content)? |
| 269 | + |
| 270 | +### Code Pattern Checklist |
| 271 | +```python |
| 272 | +# ✅ CORRECT v4 Pattern |
| 273 | +transport = await plugin_manager.get_active_by_type('transport') |
| 274 | +if await provider_has_trait('outbound', 'oauth2_required'): |
| 275 | + token = await oauth_handler.get_token() |
| 276 | + result = await transport.send_fax(to_number, file_path, auth=token) |
| 277 | + |
| 278 | +# ❌ WRONG v3 Pattern |
| 279 | +if backend == 'sinch': |
| 280 | + sinch_service.send_fax(...) |
| 281 | +elif backend == 'phaxio': |
| 282 | + phaxio_service.send_fax(...) |
| 283 | +``` |
| 284 | + |
| 285 | +## Common Anti-Patterns (AVOID) |
| 286 | + |
| 287 | +| Anti-Pattern | Problem | v4 Solution | |
| 288 | +|-------------|---------|-------------| |
| 289 | +| `if backend == 'phaxio'` | Hardcoded provider | `if provider_has_trait('webhook', 'hmac')` | |
| 290 | +| Direct service imports | Breaks plugin system | Use `plugin_manager.get_active_by_type()` | |
| 291 | +| Mixed backend UI | Confuses users | Show only active provider settings | |
| 292 | +| Blocking I/O | Performance issues | Use async/await everywhere | |
| 293 | +| CLI-only features | Poor UX | Admin Console coverage required | |
| 294 | + |
| 295 | +## Provider-Specific Critical Notes |
| 296 | + |
| 297 | +### Sinch (Priority #1) |
| 298 | +- **Auth**: `auth.methods = ["basic","oauth2"]` support required |
| 299 | +- **Regional endpoints** (US, EU, etc.) |
| 300 | +- **Fallback semantics**: Only documented key/secret fallbacks (e.g., `PHAXIO_*` to Sinch key/secret) apply. Do not infer project IDs from Phaxio keys. |
| 301 | + |
| 302 | +### HumbleFax (Complex) |
| 303 | +- **Dual inbound**: Webhook + IMAP polling |
| 304 | +- **Rate limiting**: Strict API limits |
| 305 | +- **Webhook verification**: Custom HMAC implementation |
| 306 | + - **IMAP**: Run threadpooled/worker-based; never block the event loop. |
| 307 | + |
| 308 | +### SIP/Asterisk (Self-Hosted) |
| 309 | +- **AMI credentials** required (`ASTERISK_AMI_*`) |
| 310 | +- **T.38 protocol** for fax transmission |
| 311 | +- **Network isolation** (keep AMI internal) |
| 312 | + |
| 313 | +## Final Critical Reminders |
| 314 | + |
| 315 | +1. **This has never existed before** - No assumptions allowed about fax+AI systems |
| 316 | +2. **All 7 providers must work** - Sinch priority #1, but all must function |
| 317 | +3. **Plugin-first mindset** - Everything is a plugin in v4 |
| 318 | +4. **Traits over names** - Check capabilities, not hardcoded provider strings |
| 319 | +5. **Admin Console mandatory** - Every feature needs UI coverage |
| 320 | +6. **HIPAA is critical** - Healthcare compliance built-in, not bolted-on |
| 321 | +7. **Backward compatibility** - v3 APIs must continue working during migration |
| 322 | + |
| 323 | +## Observability |
| 324 | + |
| 325 | +- Expose exactly one metrics endpoint (`/metrics` on API port). |
| 326 | +- Use the Phase-3 health monitor and circuit breaker; do not add duplicate monitors. |
| 327 | + |
| 328 | +## Dev/Prod Golden Path |
| 329 | + |
| 330 | +Dev: Docker Compose is canonical. Prod: Kubernetes. Bare-metal is unsupported to avoid Ghostscript/Node drift. |
| 331 | + |
| 332 | +## CI Guardrails |
| 333 | + |
| 334 | +### ✅ REQUIRED Checks (These block merging) |
| 335 | +- OpenAPI diff against pinned snapshot (fail on route/schema drift) |
| 336 | +- Traits JSON-Schema validation (fail on non-canonical keys/types): |
| 337 | + - `webhook.path` (string), `webhook.verification` (`hmac_sha256|basic_auth|none`), `webhook.verify_header` (string) |
| 338 | + - `auth.methods` (array of enums), `regions` (array) |
| 339 | +- Grep checks (now using standard `grep` not `rg`): |
| 340 | + - No provider name checks in UI: `grep -r "=== 'sinch'|=== 'phaxio'|=== 'sip'" api/admin_ui/src` |
| 341 | + - Require 202 in callback handlers: `grep -r "/(phaxio|sinch).*return.*202" api/app` |
| 342 | + - No duplicate health monitors: `grep -r "class .*ProviderHealthMonitor" api/app` |
| 343 | + - Secrets present in env/k8s: `CONFIG_MASTER_KEY|FAXBOT_SESSION_PEPPER` |
| 344 | + |
| 345 | +### ❌ EXTERNAL Checks (Red X's that DON'T block merging) |
| 346 | +- **Project preview** - Deployment preview services (Vercel/Netlify) |
| 347 | +- **Scorecard** - OpenSSF security scoring |
| 348 | +- **Respect Monitoring** - External monitoring service |
| 349 | + |
| 350 | +**To remove annoying external checks:** GitHub Settings > Installations > Remove unwanted apps |
| 351 | + |
| 352 | +## North Star |
| 353 | + |
| 354 | +Brownfield integration rule: We are upgrading a live system. Never rename existing routes or remove working flows. Add new capabilities behind traits, feature flags, and Admin Console UI. Return 202 for inbound callbacks and dedupe idempotently. DB-first config with .env as a true outage fallback only. Traits over names, plugins over services, Docker/K8s over bare-metal, and no PHI in logs. If a change breaks any of those, stop and fix the plan. |
| 355 | + |
| 356 | +**Remember**: You are building the first open source fax server with AI integration. Your work defines how this category of software will be understood for years to come. |
0 commit comments