Skip to main content
Synced from the repo — do not edit here

Canonical source: docs/claude/operations.md. This page is generated by docs/scripts/sync-handbook.mjs. Edit the source file in the repo; changes appear here on the next build.

Operations Guide — Autonomous Development & Deployment

This document describes how the Basis platform's automated development pipeline, monitoring, and deployment processes work together. It is the single source of truth for the end-to-end flow from bug report to production.


System Overview

Client reports bug ──► Slack Support Agent ──► GitHub Issue (agent:triage)

Sentry error ──► error-to-bug workflow ────────────────┤

ROADMAP.md task ──► Nightly Orchestrator ───────────────┤

Triage Agent (Haiku)
Classifies P0-P3, area, complexity

┌────────────┴────────────┐
▼ ▼
Low complexity High/sensitive
auto: agent:build label: needs-human


Build Agent (Sonnet)
Creates branch, applies fix
Runs lint/typecheck/build


Opens PR (auto-generated)

┌───────────┼───────────┐
▼ ▼ ▼
QA Agent Risk Review Staging Deploy
(Haiku) (pr-risk) (Firebase preview)
│ │ │
└───────────┴───────────┘


Human Review + Merge


Production Deploy
(firebase-hosting-merge.yml)


Health Check (every 30 min)
PostHog analytics
Sentry error tracking

1. Issue Sources — How Work Enters the Pipeline

A. Client Support (Slack → GitHub)

The Slack support agent monitors client messages. When it identifies a bug or feature request:

  1. It creates a GitHub issue using the bug-report.yml template
  2. The template auto-applies labels ['bug', 'agent:triage']
  3. The agent:triage label triggers the Triage Agent

B. Error Monitoring (Sentry → GitHub)

Sentry captures Python Cloud Function errors. Sentry's GitHub integration links errors to commits and source code.

For automated issue creation, external systems can call:

curl -X POST https://api.github.com/repos/OWNER/basis/dispatches \
-H "Authorization: token $PAT" \
-d '{"event_type":"error_alert","client_payload":{"title":"...","error":"...","severity":"P1"}}'

This triggers error-to-bug.yml, which creates a deduplicated GitHub issue with ['bug', 'auto-error', 'agent:triage'] labels.

C. Nightly Orchestrator (ROADMAP → GitHub)

Schedule: Every night at 2:00 AM UTC (9 PM EST) Workflow: nightly-orchestrator.ymlnightly_orchestrator.py

  1. Parses ROADMAP.md for YAML task blocks
  2. Filters tasks: agent: true, status not complete/in_progress/skipped, dependencies met
  3. Sorts by priority (P0 > P1 > P2 > P3), then phase, then ID
  4. Checks budget: pauses if 5+ open auto-generated issues exist
  5. Creates 1 GitHub issue per night with labels ['agent:triage', 'auto-generated']

ROADMAP.md task format:

- id: "1.3"
title: "Add loading skeletons to dashboard"
phase: 1
status: pending
agent: true
priority: P2
area: frontend
description: "Replace spinner with skeleton loaders"
files: ["hybrid/basisflow-web/app/(main)/dashboard/page.tsx"]
depends_on: ["1.1"]

D. Manual Issues

Anyone can create a GitHub issue. To enter the automated pipeline, add the agent:triage label.


2. Triage Agent

Workflow: triage-agent.ymltriage_agent.py Trigger: agent:triage label added to an issue Model: Claude Haiku (~$0.003/run)

What it does:

  1. Reads the issue title + body + CLAUDE.md context
  2. Classifies: severity (P0-P3), area, complexity (LOW/MEDIUM/HIGH), affected files, acceptance criteria
  3. Posts a detailed triage comment with a ready-to-copy Claude Code prompt
  4. Auto-escalation: Forces needs-human for sensitive areas (auth, billing, permissions, stripe, HIPAA) or sensitive files (firestore.rules, storage.rules, payment functions)
  5. Auto-build: If LOW/MEDIUM complexity + not sensitive → adds agent:build label

Labels applied: severity (P0-P3), area:{area}, complexity:{level}, status:ready


3. Build Agent

Workflow: build-agent.ymlanthropics/claude-code-action@v1 (the old build_agent.py single-call script was DELETED) Trigger: agent:build label added to an issue (applied by the Triage Agent's suitability gate or by George — never self-applied) Model: --model claude-sonnet-4-6 --max-turns 150 Timeout: 30 minutes Branch: agent/issue-{number}-{timestamp} (prefix agent/ only — the action appends issue-<n>-<ts>)

What it does:

  1. Mark building: adds agent:building + status:in-progress; sets the board Status field to In Progress (needs AGENT_PAT project scope)
  2. Runs the full Claude Code CLI autonomously — reads CLAUDE.md, explores, implements, verifies (py_compile / npm run build), commits, and pushes the branch (up to 150 turns)
  3. On success: the action pushes the branch but does NOT open a PR itself — the workflow finds the pushed branch and runs gh pr create → labels auto-generated,agent:qa, sets the issue status:in-review + buildoutcome:success, moves the board card to Human Review
  4. On failure: categorizes the failure (buildfail:<max-turns|python-compile|frontend-build|no-changes|api-error|other>), posts a scope-instead-of-fail handoff (root cause + files + step plan), labels needs-human,agent:build-failed
  5. Queue-drain (always): kicks the next eligible agent:build issue so work doesn't stall behind the concurrency lock

Merged ≠ live: merging the PR closes the issue (board → Done) but the code still needs a ship.sh deploy.

Important: uses AGENT_PAT (not GITHUB_TOKEN) so its pushes/PRs trigger downstream workflows and it can move the project board. Weekly agent-learning-digest.yml clusters buildfail:* outcomes back into classifier fixes.


4. PR Review Pipeline

When a PR is opened (manually or by the build agent), three checks run in parallel:

A. QA Agent

Workflow: qa-agent.ymlqa_agent.py Trigger: PR with label agent:qa or auto-generated Model: Claude Haiku (~$0.005/run)

  • Analyzes the diff for issues, HIPAA violations, and sensitive file changes
  • Verdict: PASS → approves PR + qa:pass label; FAIL → requests changes + qa:fail; NEEDS_HUMANneeds-human-review
  • Always forces NEEDS_HUMAN if sensitive files are touched

B. PR Risk Review

Workflow: pr-risk-review.ymlpr_risk_review.py Trigger: All PRs (opened/synchronized/reopened)

  • Scores changed files against risk weights (sensitive paths +3, protected files +5, secrets patterns +3, etc.)
  • Posts a risk summary comment and adds a risk label
  • Sends to Slack if high risk

C. Staging Deploy

Workflow: staging-deploy.yml Trigger: PRs with label auto-generated or deploy:staging

  • Builds basisflow-web and deploys to a Firebase preview channel (staging-pr-{number}, 7-day expiry)
  • Posts preview URL as a PR comment
  • Runs Python syntax verification on all Cloud Functions

D. CI Checks

Workflow: ci.yml Trigger: All PRs + pushes to master

  • Runs lint + typecheck + build for both basisflow-web and basisweb

5. Human Review & Merge

Every PR requires human review before merging. The automated pipeline assists but never auto-merges.

Merge checklist (from QA_GUIDE.md):

  • QA Agent passed (qa:pass label)
  • Risk review posted (check risk level)
  • Staging preview tested (if applicable)
  • CI checks green
  • At least 1 human approval
  • No needs-human or needs-human-review labels remaining

For agent-generated PRs: Always review the diff manually. The build agent can make mistakes — treat its output like a junior developer's PR.


6. Production Deployment

Automatic (Frontend Only)

Workflow: firebase-hosting-merge.yml (auto-generated by Firebase CLI) Trigger: Push/merge to master branch

  • Builds basisflow-web (npm ci && npm run build)
  • Deploys to Firebase Hosting live channel

Also: production-deploy.yml sends Slack notifications on deploy success/failure.

Manual (Cloud Functions)

Cloud Functions are never auto-deployed. Always deploy individually:

cd /Users/G/basis/basis-functions
firebase deploy --only functions:function_name --force

Manual (Firestore/Storage Rules)

firebase deploy --only firestore:rules
firebase deploy --only storage

Manual (basisweb / Client Portal)

basisweb deploys to Netlify automatically on git push to the deployed branch. Ensure Netlify env vars are up to date.


7. When You Deploy Manually

If you build and deploy locally (outside git/CI), follow this process to keep everything in sync:

  1. Before deploying: Ensure your local changes are committed (or at least stashed) so git reflects what's live
  2. After deploying frontend manually:
    • Commit the changes to git
    • Push to the remote so the build agent, CI, and other workflows operate on the correct code
  3. After deploying Cloud Functions manually:
    • Commit any Python changes to git
    • Note: Function deploys don't trigger GitHub workflows, but the code must be in git for the build agent to read
  4. After deploying Firestore/Storage rules:
    • Commit rule changes to git
    • Hard-refresh (Cmd+Shift+R) any open browser tabs to clear cached permission denials

Why this matters: The build agent reads source code from GitHub. If git is behind production, the agent will propose changes against stale code, causing conflicts or regressions.


8. Monitoring & Alerting

Health Checks (Synthetic)

Workflow: health-check.yml Schedule: Every 30 minutes

Checks three endpoints:

  • https://platform.basishealth.io — HTTP 200
  • https://web.basishealth.io — HTTP 200
  • https://us-central1-basis-hybrid.cloudfunctions.net/health_check — non-000

On failure: Creates P0 GitHub issue with health-check-failure label On recovery: Auto-closes the issue

Sentry (Error Tracking)

DSN: Configured in Firebase Secret Manager (SENTRY_DSN) Platform: Python (Vanilla) — captures Cloud Function errors GitHub Integration: Links errors to commits and source code (free plan)

PostHog (Product Analytics)

Project Key: Set via NEXT_PUBLIC_POSTHOG_KEY env var Integrated in: basisflow-web (staff platform) + basisweb (client portal) HIPAA-safe config: All inputs masked, $ip stripped, identified_only person profiles

Tracked events:

  • Automatic pageviews on route changes
  • Signup funnel: signup_clinic_created, signup_billing_started, signup_billing_complete
  • User identification on login (UID only, no PII)

Slack Notifications

Webhook: Stored in both Firebase Secret Manager and GitHub Secrets as SLACK_WEBHOOK_URL Channel: #bug-channel

Sends notifications for:

  • Production deploy success/failure
  • High-risk PR alerts
  • Cloud Function errors (via error_reporter.py)

9. GitHub Secrets & Variables Reference

Secrets (Settings → Secrets → Actions)

SecretUsed byPurpose
AGENT_PATbuild-agent.ymlGitHub PAT for pushing branches + creating PRs
ANTHROPIC_API_KEYtriage/build/qa agentsClaude API access
SLACK_WEBHOOK_URLproduction-deploy, pr-riskSlack notifications
FIREBASE_SERVICE_ACCOUNTstaging-deploy, ciFirebase preview deploys
FIREBASE_SERVICE_ACCOUNT_BASIS_HYBRIDfirebase-hosting-*.ymlFirebase CLI auto-generated deploys

Variables (Settings → Variables → Actions)

VariableUsed byPurpose
BUILD_AGENT_BASE_BRANCHbuild-agent.ymlBranch to base agent work on (default: master)

Firebase Secrets (Secret Manager)

SecretUsed byPurpose
SENTRY_DSNCloud FunctionsSentry error reporting
SLACK_WEBHOOK_URL14+ Cloud FunctionsSlack error/notification posting

10. Key Labels Reference

LabelMeaningTriggers
agent:triageNeeds AI triagetriage-agent.yml
agent:buildReady for AI implementationbuild-agent.yml
agent:buildingBuild agent is working (concurrency lock)
agent:qaNeeds AI QA reviewqa-agent.yml
auto-generatedCreated by automated pipelinestaging-deploy.yml, budget checks
needs-humanRequires human decisionBlocks auto-build
needs-human-reviewQA flagged for human review
qa:passQA agent approved
qa:failQA agent rejected
agent:build-failedBuild agent couldn't fix it
deploy:stagingRequest staging previewstaging-deploy.yml
health-check-failureUptime check failedhealth-check.yml
auto-errorCreated from error alerterror-to-bug.yml

11. Cost Estimates

ComponentCostFrequency
Triage Agent (Haiku)~$0.003/issuePer issue
Build Agent (Sonnet)~$0.05-$0.30/issuePer agent:build issue
QA Agent (Haiku)~$0.005/PRPer PR
Nightly Orchestrator~$0.003/nightDaily
GitHub ActionsFree tier (2000 min/mo)
Firebase Hosting previewsFree7-day expiry
SentryFree (Developer plan)
PostHogFree tier + credits

Monthly budget cap: ~$300 for build agent (configurable via issue volume + the 5-open-issue budget gate in the nightly orchestrator).