Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ ANTHROPIC_API_KEY=
# Overrides the default model (claude-opus-5).
ANTHROPIC_MODEL=

# The fallback chain, tried in this order: anthropic -> openai -> gemini.
# Each key is independently optional; whichever are set become the chain, and a
# provider is only skipped when it reports that it is out of budget. A capped
# key that regains access rejoins at the front with no redeploy.
OPENAI_API_KEY=
# Overrides the default model (gpt-5.5). No moving "latest" alias exists for
# the reasoning line, so bumping a generation is a config change, not a deploy.
OPENAI_MODEL=

GEMINI_API_KEY=
# Overrides the default model (gemini-flash-latest).
GEMINI_MODEL=

# -------------------------------------------------------------------- email
# Account email only — verification links. Outreach never goes through this.
#
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ export function createApp(options: AppOptions): Hono<AppEnv> {
throw new ApiError(
503,
'composer_unavailable',
'no language model is configured; set ANTHROPIC_API_KEY to enable drafting',
'no language model is configured; set ANTHROPIC_API_KEY, OPENAI_API_KEY or GEMINI_API_KEY to enable drafting',
);
}

Expand Down
21 changes: 20 additions & 1 deletion apps/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@
*/

import { closeDatabase, getDatabase, migrate, queryAll } from '@outreachgraph/db';
import { ClaudeModel, FallbackModel, GeminiModel, type FallbackEntry } from '@outreachgraph/ai';
import {
ClaudeModel,
FallbackModel,
GeminiModel,
OpenAIModel,
type FallbackEntry,
} from '@outreachgraph/ai';
import { ResendMailer } from '@outreachgraph/email';
import { createApp } from '../../api/src/app';
import { pruneSessions } from '../../api/src/auth';
Expand Down Expand Up @@ -93,6 +99,19 @@ if (process.env.ANTHROPIC_API_KEY) {
// Second, not instead of. A capped Anthropic key regains access on its own, and
// when it does the chain returns to Claude with no redeploy — which is what a
// fallback should do rather than becoming a permanent quiet substitution.
//
// OpenAI comes before Gemini because it is the closer substitute: the prompts
// and the deterministic gates were built around Claude, and a same-shaped model
// is likelier to produce a draft that still passes them.
if (process.env.OPENAI_API_KEY) {
chain.push({
name: 'openai',
model: new OpenAIModel({
...(process.env.OPENAI_MODEL ? { model: process.env.OPENAI_MODEL } : {}),
}),
});
}

if (process.env.GEMINI_API_KEY) {
chain.push({
name: 'gemini',
Expand Down
75 changes: 38 additions & 37 deletions docs/prd-implementation-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,44 @@ Where each part of the V1 PRD lives. Code comments cite section numbers

## Implemented

| PRD section | Implementation | Tests |
| ---------------------------------- | ------------------------------------------------------------------------ | --------------------------------- |
| §8 Prospect pipeline | `packages/domain/src/pipeline.ts` | — |
| §9.1–9.3 Identity graph, evidence | `packages/domain/src/person.ts` | — |
| §9.4 Confidence bands, thresholds | `packages/domain/src/confidence.ts` | `identity/src/resolver.test.ts` |
| §9.5 Resolution model | `packages/identity/src/resolver.ts`, `weights.ts` | 25 tests |
| §10.1 Provider interface | `packages/providers/src/provider.ts` | — |
| §10.2 Waterfall | `packages/providers/src/waterfall.ts` | 17 tests |
| §10.3 Provenance | `packages/domain/src/provenance.ts`, `providers/src/waterfall.ts` | included above |
| §11.1–11.2 Signal schema and types | `packages/domain/src/signal.ts` | — |
| §11.3 Signal decay | `packages/signals/src/decay.ts` | 35 tests |
| §12.1–12.6 Scoring | `packages/scoring/src/scores.ts`, `weights.ts` | 31 tests |
| §13.1 Action kinds | `packages/domain/src/networks.ts` | — |
| §13.2 Recommendation schema | `packages/domain/src/outreach.ts` | — |
| §14.1 Outreach composer | `packages/ai/src/composer.ts`, `model.ts`, `draft.ts` | 29 tests |
| §14.2 Quality checks | `packages/ai/src/checks.ts`, `packages/domain/src/outreach.ts` | 40 tests |
| §14.3 Personalised video | `packages/media/src/script.ts`, `renderer.ts`, `render.ts` | 36 tests |
| §15 Approval queue | `apps/api` `GET /recommendations` | `apps/api/src/app.test.ts` |
| §16 Platform policy | `packages/policy/src/capability-matrix.ts` | 46 tests |
| §16.2 Policy modes | `packages/policy/src/capability-matrix.ts` | included above |
| §16.3–16.6 Per-network rules | `packages/policy/src/capability-matrix.ts` | included above |
| §17.3 Suppression | `packages/domain/src/compliance.ts`, migration `0004` | `apps/api/src/app.test.ts` |
| §17.4 Sensitive categories | `packages/domain/src/compliance.ts` | — |
| §17.5 Minors | `evaluateEligibility`, policy `person_ineligible` gate | policy tests |
| §17.6 Source deletion | `packages/pipeline/src/jobs.ts` `markSourceUnavailable` | pipeline tests |
| §18 Rate limits, cooldowns | `packages/policy/src/engine.ts` | policy tests |
| §20.8 Policy engine | `packages/policy/src/engine.ts` | 46 tests |
| §21 Database model | `migrations/0000`–`0007` | `packages/db/src/migrate.test.ts` |
| §23 API endpoints | `apps/api/src/app.ts` | 61 tests |
| §34 Workspace isolation | `apps/api/src/repository.ts` | `apps/api/src/app.test.ts` |
| §37 Feature flags | `feature_flags` table, policy `feature_flag` gate | policy + API tests |
| §13 Next-best-action | `packages/recommend/src/engine.ts` | 25 tests |
| §20.6 Strategy agent | `packages/recommend` — deterministic, chooses only from `allowedActions` | included above |
| §16.6 GitHub as a signal source | `packages/providers/src/github/` | 27 tests |
| §8 Pipeline, end to end | `packages/pipeline/src/pipeline.ts`, `POST /prospects` | 11 + 8 tests, live GitHub run |
| §25.2 Prospect list and detail | `apps/web/app/prospects/`, `GET /people` | 2 API tests + build |
| §34 Email verification | `packages/email/`, `apps/api/src/auth.ts`, migration `0006` | 7 + 11 tests |
| PRD section | Implementation | Tests |
| ---------------------------------- | ------------------------------------------------------------------------ | ---------------------------------- |
| §8 Prospect pipeline | `packages/domain/src/pipeline.ts` | — |
| §9.1–9.3 Identity graph, evidence | `packages/domain/src/person.ts` | — |
| §9.4 Confidence bands, thresholds | `packages/domain/src/confidence.ts` | `identity/src/resolver.test.ts` |
| §9.5 Resolution model | `packages/identity/src/resolver.ts`, `weights.ts` | 25 tests |
| §10.1 Provider interface | `packages/providers/src/provider.ts` | — |
| §10.2 Waterfall | `packages/providers/src/waterfall.ts` | 17 tests |
| §10.3 Provenance | `packages/domain/src/provenance.ts`, `providers/src/waterfall.ts` | included above |
| §11.1–11.2 Signal schema and types | `packages/domain/src/signal.ts` | — |
| §11.3 Signal decay | `packages/signals/src/decay.ts` | 35 tests |
| §12.1–12.6 Scoring | `packages/scoring/src/scores.ts`, `weights.ts` | 31 tests |
| §13.1 Action kinds | `packages/domain/src/networks.ts` | — |
| §13.2 Recommendation schema | `packages/domain/src/outreach.ts` | — |
| §14.1 Outreach composer | `packages/ai/src/composer.ts`, `model.ts`, `draft.ts` | 29 tests |
| §14.1 Model fallback chain | `packages/ai/src/fallback.ts`, `openai.ts`, `gemini.ts` | `packages/ai/src/fallback.test.ts` |
| §14.2 Quality checks | `packages/ai/src/checks.ts`, `packages/domain/src/outreach.ts` | 40 tests |
| §14.3 Personalised video | `packages/media/src/script.ts`, `renderer.ts`, `render.ts` | 36 tests |
| §15 Approval queue | `apps/api` `GET /recommendations` | `apps/api/src/app.test.ts` |
| §16 Platform policy | `packages/policy/src/capability-matrix.ts` | 46 tests |
| §16.2 Policy modes | `packages/policy/src/capability-matrix.ts` | included above |
| §16.3–16.6 Per-network rules | `packages/policy/src/capability-matrix.ts` | included above |
| §17.3 Suppression | `packages/domain/src/compliance.ts`, migration `0004` | `apps/api/src/app.test.ts` |
| §17.4 Sensitive categories | `packages/domain/src/compliance.ts` | — |
| §17.5 Minors | `evaluateEligibility`, policy `person_ineligible` gate | policy tests |
| §17.6 Source deletion | `packages/pipeline/src/jobs.ts` `markSourceUnavailable` | pipeline tests |
| §18 Rate limits, cooldowns | `packages/policy/src/engine.ts` | policy tests |
| §20.8 Policy engine | `packages/policy/src/engine.ts` | 46 tests |
| §21 Database model | `migrations/0000`–`0007` | `packages/db/src/migrate.test.ts` |
| §23 API endpoints | `apps/api/src/app.ts` | 61 tests |
| §34 Workspace isolation | `apps/api/src/repository.ts` | `apps/api/src/app.test.ts` |
| §37 Feature flags | `feature_flags` table, policy `feature_flag` gate | policy + API tests |
| §13 Next-best-action | `packages/recommend/src/engine.ts` | 25 tests |
| §20.6 Strategy agent | `packages/recommend` — deterministic, chooses only from `allowedActions` | included above |
| §16.6 GitHub as a signal source | `packages/providers/src/github/` | 27 tests |
| §8 Pipeline, end to end | `packages/pipeline/src/pipeline.ts`, `POST /prospects` | 11 + 8 tests, live GitHub run |
| §25.2 Prospect list and detail | `apps/web/app/prospects/`, `GET /people` | 2 API tests + build |
| §34 Email verification | `packages/email/`, `apps/api/src/auth.ts`, migration `0006` | 7 + 11 tests |

## Partially implemented

Expand Down
Loading
Loading