Hackorda Docs
Flows

F 14 Anthropic Ai

Status: ๐ŸŸข ready to test Owner: Adilet Last updated: 2026-05-08 Last verified on production: โ€”

Goal

An admin stores the Anthropic API key in the database (no env var required), tests it from the admin UI, and three fire-and-forget AI agents (intake / run summary / cycle close) light up across the platform. Errors are categorised into 8 friendly modes with retry buttons.

Actors

  • Primary โ€” Admin (configures + retries)
  • Secondary โ€” Anthropic API; downstream agents that auto-run

Preconditions

  • Admin is signed in.
  • A working Anthropic API key (starts with sk-ant-).

Trigger

Admin opens /app/admin/integrations and clicks the "Configure" CTA on the Anthropic card.

Happy path โ€” configure key

#ActorUI surfaceActionAPI callDB writesSide effectsSuggested event
1Admin/app/admin/integrationsClick "Configure" on Anthropic cardโ€”โ€”โ€”โ€”
2Adminedit formPaste API key (password input, data-1p-ignore)โ€”โ€”โ€”โ€”
3Adminedit formClick "Test"POST /api/admin/integrations/anthropic/test body { apiKey }โ€”calls client.models.list({ limit: 20 }) (free, no token spend)โ€”
4Anthropicโ€”Returns OK or 401/402โ€”โ€”โ€”โ€”
5Adminedit form"Save"PUT /api/admin/integrations/anthropic body { apiKey }upsert organization_integrations row with provider_slug='anthropic', config={ api_key }, status='active'invalidate module-level Anthropic SDK client cacheintegration.configured
6Frontendconfigured-state cardshows "Active" w/ masked key + Test/Edit/Disconnectโ€”โ€”โ€”โ€”

Happy path โ€” three downstream agents fire

Once configured, three agents auto-run on respective triggers:

AgentTriggerOutputFailure mode
intake_issueF-08 โ€” non-draft issue POSTissues.ai_suggestions (title / severity / bug_type / confidence)Surfaced via aiLatestFailure on issue detail
run_summaryF-07 โ€” run PATCH status=completedtest_runs.ai_summaryStored in test_runs.ai_summary_failure_reason
cycle_reportCycle PATCH status=closedNew cycle_documents row, kind='report'Logged in ai_runs

All three call Anthropic with claude-sonnet-4-20250514. Vision uses { type: 'image', source: { type: 'url', url } } directly with public DO Spaces URLs (no base64). Capped at 3 images per intake call.

Happy path โ€” retry intake

#ActorUI surfaceActionAPI callDB writesSide effectsSuggested event
1Admin/Leadissue detail AiSuggestionsCard (failure state)Click "Retry"POST /api/test-cycles/:id/issues/:issueId/intakenew row in ai_runs; UPDATE issues SET ai_suggestions = โ€ฆ if successโ€”ai.intake_retried

(Retry is admin/lead only โ€” testers can't burn budget.)

Failure categorisation

src/lib/ai/intake.ts โ†’ categoriseError() maps Anthropic errors to:

failure_reasonTriggerUI copy
out_of_credits402 / "credit balance""Top up at console.anthropic.com"
auth_failed401 / 403"API key invalid or revoked"
rate_limited429"Will retry on next issue"
context_limitinput too large"Issue + attachments too large"
service_errorAnthropic 5xx"Anthropic having issues right now"
timeoutnetwork"Try again in a moment"
parse_errormodel didn't call tool"Re-running may help"
unknownfallbackGeneric

Acceptance criteria

  • AC-1 โ€” Given the admin saves an Anthropic key, when the next issue is filed, then within 60s issues.ai_suggestions is populated AND the ai_runs row's status='done' with cost_usd_cents set.
  • AC-2 โ€” Given a bad key, when "Test" is clicked, then the response surfaces "auth_failed" friendly copy and Save is blocked (or save anyway depending on UX โ€” verify on prod).
  • AC-3 โ€” Given the key is removed (DELETE /api/admin/integrations/anthropic), when the next issue is filed, then isAiEnabled() returns false, no Anthropic call is made, and the issue still saves cleanly.
  • AC-4 โ€” Given a vision-bearing issue with 5 images, when intake runs, then only the first 3 images are sent to the model (cap).
  • AC-5 โ€” Given a model fails to call the submit_intake_analysis tool, when the response is parsed, then ai_runs.failure_reason='parse_error' and the AiSuggestionsCard shows "Re-running may help" with a Retry button (admin/lead only).
  • AC-6 โ€” Given a non-admin views the AiSuggestionsCard's failure state, then there is no Retry button visible.
  • AC-7 โ€” Given a cycle is set to status='closed', when the cycle-close agent finishes, then a new cycle_documents row exists with kind='report' and the body is the AI's summary.
  • AC-8 โ€” Given the SDK client cache is in-memory and keyed on the resolved API key, when an admin rotates the key, then subsequent calls use the new key without a server restart.

Test data / fixtures

  • Baseline seed
  • A working Anthropic API key with at least $0.10 of credit
  • An active cycle with an open run + a tester ready to file an issue

Negative paths

#ScenarioExpected behavior
N-1Save without testingAllowed; first intake call would surface failure if invalid
N-2Out of creditsfailure_reason='out_of_credits', friendly copy
N-3Multiple rapid issue filingsSome will hit 429; categorised as rate_limited; retry button on each
N-4Anthropic latency >30sCategorised as timeout; upstream doesn't block (fire-and-forget)
N-5Tester clicks RetryUI hides the button; API would 403 if hit directly

Manual QA checklist

  • As admin, open /app/admin/integrations
  • Confirm Anthropic card shows "Not configured"
  • Click Configure โ†’ paste valid key โ†’ click Test โ†’ green
  • Click Save โ†’ card flips to "Active" with masked key
  • As tester, file a new issue with 1 screenshot (F-08)
  • Wait ~30s, refresh issue detail โ†’ AiSuggestionsCard shows suggested title / severity / bug_type
  • Verify ai_runs table has a row with kind='intake_issue', status='done', cost_usd_cents > 0
  • Edit the Anthropic config โ†’ paste an invalid key โ†’ save โ†’ next issue shows the failure card with auth_failed friendly copy
  • Restore valid key
  • As admin, click Retry on a failed AiSuggestionsCard โ†’ new ai_runs row, suggestions populate
  • As tester, sign in and view a failed AiSuggestionsCard โ†’ confirm Retry button is not visible (admin/lead only)
  • Close a cycle (status='closed') โ†’ wait ~60s โ†’ new cycle_documents row appears with kind='report'
  • Disconnect the integration โ†’ confirm subsequent issues file with no AI call (no ai_runs row created)

Automated test outline

test.describe("F-14 anthropic ai", () => {
  test("admin configure โ†’ test โ†’ save", async ({ page }) => { โ€ฆ });
  test("intake populates suggestions", async ({ request }) => { โ€ฆ });
  test("retry intake (admin only)", async ({ request }) => { โ€ฆ });
  test("disconnect short-circuits agents", async ({ request }) => { โ€ฆ });
  test("8 failure modes categorised", async ({ request }) => { /* one test per mock */ });
});

Code references

  • UI: src/components/admin/integrations/AnthropicIntegrationCard.tsx, src/components/test-cycles/AiSuggestionsCard.tsx
  • Pages: src/app/app/admin/integrations/page.tsx
  • API:
    • src/app/api/admin/integrations/anthropic/route.ts (GET/PUT/DELETE)
    • src/app/api/admin/integrations/anthropic/test/route.ts
    • src/app/api/test-cycles/[id]/issues/[issueId]/intake/route.ts (retry)
  • Lib:
    • src/lib/ai/client.ts (getAnthropic, isAiEnabled, loadAnthropicConfig, invalidateAnthropicCache, readAnthropicIntegrationStatus)
    • src/lib/ai/intake.ts (runIntakeForIssue, categoriseError, AI_FAILURE_REASONS)
    • src/lib/ai/run-summary.ts
    • src/lib/ai/cycle-close.ts
  • Schema: organization_integrations (provider_slug='anthropic'), ai_runs, AI_RUN_KINDS, AI_RUN_STATUSES, issues.ai_suggestions + issues.ai_intake_run_id, test_runs.ai_summary

Events emitted (proposed)

  • integration.configured โ€” { provider: 'anthropic', configured_by }
  • integration.tested โ€” { provider, success, error_code }
  • integration.disconnected โ€” { provider, disconnected_by }
  • ai.intake_completed โ€” { issue_id, latency_ms, cost_usd_cents, suggested_severity, confidence, image_count }
  • ai.intake_failed โ€” { issue_id, failure_reason }
  • ai.intake_retried โ€” { issue_id, retried_by }
  • ai.run_summary_completed / _failed
  • ai.cycle_report_completed / _failed

Open questions / known gaps

  • Cost cap per cycle: ai_runs.cost_usd_cents is logged but not enforced (no hard ceiling). Flagged in feature-matrix.md ยง5.2.
  • Run-summary has no retry button (only intake does).
  • No "regenerate cycle report" button โ€” only fires once on close.
  • Vision is image-only โ€” no video frame extraction.
  • Encrypted credentials store deferred; key is in plain organization_integrations.config.api_key jsonb.

On this page