Blame · Line-by-line history
BUILD_BIBLE.md
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 9ab6971 | 1 | # GLUECRON BUILD BIBLE |
| 2 | ||
| 3 | **This file is the single source of truth for the GlueCron build.** | |
| 4 | ||
| 5 | **Every Claude agent MUST read this file in full before touching code. No exceptions.** | |
| 6 | ||
| 7 | GlueCron is a GitHub replacement — AI-native code intelligence, green ecosystem enforcement, git hosting, automated CI. It is production infrastructure for multiple downstream platforms. Production cannot stop. | |
| 8 | ||
| 9 | --- | |
| 10 | ||
| 11 | ## 1. AGENT POLICY (READ FIRST, FOLLOW ALWAYS) | |
| 12 | ||
| 13 | ### 1.1 Required reads at session start | |
| 14 | 1. `BUILD_BIBLE.md` (this file) — complete | |
| 15 | 2. `CLAUDE.md` — stack + architecture | |
| 16 | 3. `README.md` — user-facing overview | |
| 17 | 4. Most recent commit on the current branch (`git log -1 --stat`) | |
| 18 | ||
| 19 | ### 1.2 Do-not-undo rule | |
| 20 | - Anything listed in **§4 LOCKED BLOCKS** is shipped and must not be deleted, renamed, or semantically altered without the owner's explicit written permission in the current session. | |
| 21 | - "Refactor" is not permission. "Clean up" is not permission. "Simplify" is not permission. | |
| 22 | - If a locked file seems wrong, open an issue in the plan and keep going on a new block. | |
| 23 | ||
| 24 | ### 1.3 Continuous-build rule | |
| 25 | - The owner runs many parallel projects. Do not stop work to ask for clarification that can be inferred from this file. | |
| 26 | - Default behaviour when a block is partially complete: **finish it, run tests, commit, push, start the next block**. | |
| 27 | - Only stop for genuinely blocking decisions: destructive operations, architectural reversals, requests outside this plan, or repeated test failures you can't diagnose. | |
| 28 | - Never stop because "the session might run out." Commit what works and keep building. | |
| 29 | ||
| 30 | ### 1.4 Branch + commit rules | |
| 31 | - Development branch: whatever the current session was told (check session opening message). Fall back to `main` if none given. | |
| 32 | - One commit per completed block. Message format: `feat(BLOCK-ID): <summary>`. | |
| 33 | - Push after every commit with `git push -u origin <branch>`. | |
| 34 | - Never force-push. Never `--no-verify`. Never amend published commits. | |
| 35 | ||
| 36 | ### 1.5 Quality bars (non-negotiable) | |
| 37 | - `bun test` must pass before every commit. | |
| 38 | - New features ship with tests in `src/__tests__/`. | |
| 39 | - New routes use `softAuth` or `requireAuth` middleware. | |
| 40 | - New DB tables have a corresponding migration in `drizzle/`. | |
| 41 | - AI features use `isAiAvailable()` guards and degrade gracefully without `ANTHROPIC_API_KEY`. | |
| 42 | - Every user-facing failure mode has a fallback — no 500s reach the UI. | |
| 43 | ||
| 44 | ### 1.6 Green-ecosystem-by-default | |
| 45 | - Every new repo auto-configures: gates on, branch protection on, labels seeded, CODEOWNERS synced, welcome issue posted. | |
| 46 | - Users can opt out per feature but defaults are maximum-green. | |
| 47 | - Nothing broken ever reaches production, the website, or the customer. | |
| 48 | ||
| 49 | --- | |
| 50 | ||
| 51 | ## 2. GITHUB PARITY SCORECARD | |
| 52 | ||
| 53 | Legend: ✅ shipped · 🟡 partial · ❌ not built | |
| 54 | ||
| 55 | ### 2.1 Repository hosting | |
| 56 | | Feature | Status | Notes | | |
| 57 | |---|---|---| | |
| 58 | | Git Smart HTTP (clone / push / fetch) | ✅ | `src/routes/git.ts`, `src/git/protocol.ts` | | |
| 59 | | SSH keys | ✅ | `ssh_keys` table, `src/routes/settings.tsx` | | |
| 60 | | Public / private visibility | ✅ | `repositories.isPrivate` | | |
| 61 | | Forking | ✅ | `src/routes/fork.ts` | | |
| 62 | | Stars | ✅ | `stars` table, `/:owner/:repo/star` | | |
| 63 | | Topics | ✅ | `repo_topics` table | | |
| 64 | | Archive / disable repo | ❌ | schema has flags; no UI | | |
| 65 | | Repository transfer | ❌ | — | | |
| 66 | | Template repositories | ❌ | — | | |
| 67 | | Repository mirroring | ❌ | — | | |
| 68 | ||
| 69 | ### 2.2 Code browsing | |
| 70 | | Feature | Status | Notes | | |
| 71 | |---|---|---| | |
| 72 | | File tree browser | ✅ | `src/routes/web.tsx` | | |
| 73 | | Syntax highlighting | ✅ | 40+ languages, `src/lib/highlight.ts` | | |
| 74 | | Commit history | ✅ | | | |
| 75 | | Diffs | ✅ | | | |
| 76 | | Blame | ✅ | | | |
| 77 | | Raw file download | ✅ | | | |
| 78 | | Branch switcher | ✅ | | | |
| 79 | | Tag listing | ✅ | new this build | | |
| 80 | | Code search (ILIKE) | ✅ | per-repo + global | | |
| 81 | | Semantic / embedding search | ❌ | pgvector not wired | | |
| 82 | | Symbol / xref navigation | ❌ | — | | |
| 83 | ||
| 84 | ### 2.3 Collaboration | |
| 85 | | Feature | Status | Notes | | |
| 86 | |---|---|---| | |
| 87 | | Issues (CRUD / comments / labels / close) | ✅ | | | |
| 88 | | Milestones | ✅ | `src/routes/insights.tsx` | | |
| 89 | | Pull requests (CRUD / review / merge) | ✅ | | | |
| 90 | | PR inline comments | ✅ | file+line anchored | | |
| 6fc53bd | 91 | | Draft PRs | ✅ | create as draft, ready-for-review toggle, dedicated tab, merge blocked until ready | |
| 92 | | Reactions (emoji) | ✅ | 8 reactions, toggle via `POST /api/reactions/:t/:id/:emoji/toggle` on issues + PRs + comments | | |
| 9ab6971 | 93 | | Mentions + notifications | ✅ | `src/routes/notifications.tsx` | |
| 94 | | Code owners | ✅ | `src/lib/codeowners.ts` | | |
| 24cf2ca | 95 | | Issue templates | ✅ | `.github/ISSUE_TEMPLATE.md` auto-prefills new issues; frontmatter stripped; `src/lib/templates.ts` | |
| 96 | | PR templates | ✅ | `.github/PULL_REQUEST_TEMPLATE.md` auto-prefills new PRs; `src/lib/templates.ts` | | |
| 97 | | Saved replies | ✅ | per-user canned comments, unique-shortcut, `/settings/replies`, `/api/user/replies` | | |
| 9ab6971 | 98 | | Discussions / forums | ❌ | | |
| 99 | | Wikis | ❌ | | | |
| 100 | | Projects / kanban | ❌ | | | |
| 101 | ||
| 102 | ### 2.4 Automation + AI | |
| 103 | | Feature | Status | Notes | | |
| 104 | |---|---|---| | |
| ad6d4ad | 105 | | Webhooks (outbound, HMAC signed) | ✅ | `src/routes/webhooks.tsx` | |
| 106 | | GateTest inbound callback | ✅ | `POST /api/hooks/gatetest`, bearer or HMAC | | |
| 107 | | Backup PAT-auth gate ingest | ✅ | `POST /api/v1/gate-runs` | | |
| 9ab6971 | 108 | | Gate runs (test / secret / AI review) | ✅ | `gate_runs` table, `src/routes/gates.tsx` | |
| 109 | | Branch protection | ✅ | `branch_protection` table + UI | | |
| 110 | | Auto-repair engine | ✅ | `src/lib/auto-repair.ts` | | |
| 111 | | Secret scanner | ✅ | 15 patterns, `src/lib/security-scan.ts` | | |
| 112 | | AI security review | ✅ | Sonnet 4, `src/lib/security-scan.ts` | | |
| 113 | | AI commit messages | ✅ | `src/lib/ai-generators.ts` | | |
| 114 | | AI PR summaries | ✅ | | | |
| 115 | | AI changelogs | ✅ | auto on release create | | |
| 116 | | AI code review | ✅ | `src/lib/ai-review.ts` | | |
| 117 | | AI merge conflict resolver | ✅ | `src/lib/merge-resolver.ts` | | |
| 118 | | AI chat (global + repo) | ✅ | `src/routes/ask.tsx` | | |
| 119 | | GitHub Actions equivalent (workflow runner) | ❌ | GateTest integrated, no generic runner | | |
| 120 | | Dependabot equivalent (AI dep bumper) | ❌ | | | |
| 121 | | Code scanning UI | 🟡 | data exists, no dedicated UI page | | |
| 122 | | Copilot code completion | ❌ | | | |
| 123 | ||
| 124 | ### 2.5 Platform | |
| 125 | | Feature | Status | Notes | | |
| 126 | |---|---|---| | |
| 127 | | Dashboard | ✅ | `src/routes/dashboard.tsx` | | |
| 128 | | Explore / discover | ✅ | | | |
| 129 | | Global search | ✅ | repos / users / issues / PRs | | |
| 130 | | Insights (graph, contributors, green rate) | ✅ | `src/routes/insights.tsx` | | |
| 131 | | Releases + tags | ✅ | AI changelog | | |
| 132 | | Personal access tokens | ✅ | SHA-256 hashed | | |
| 133 | | OAuth app provider | ❌ | | | |
| 134 | | GitHub Apps equivalent | ❌ | | | |
| 135 | | GraphQL API | ❌ | REST only | | |
| 6563f0a | 136 | | Organizations + teams | 🟡 | schema + routes shipped (B1): `/orgs`, `/orgs/new`, `/orgs/:slug/people`, `/orgs/:slug/teams`, last-owner guard, audit logged. Org-owned repos = B2 next | |
| 9ab6971 | 137 | | Enterprise SAML / SSO | ❌ | | |
| 138 | | 2FA / TOTP | ❌ | | | |
| 139 | | Passkeys / WebAuthn | ❌ | | | |
| 140 | | Packages registry (npm / docker / etc) | ❌ | | | |
| 141 | | Pages / static hosting | ❌ | | | |
| 142 | | Gists | ❌ | | | |
| 143 | | Sponsors | ❌ | | | |
| 144 | | Marketplace | ❌ | | | |
| 24cf2ca | 145 | | Environments / deployment tracking | ✅ | `src/routes/deployments.tsx` — grouped by env, success-rate rollup, per-deploy detail | |
| 9ab6971 | 146 | | Merge queues | ❌ | | |
| 147 | | Required checks matrix | 🟡 | branch_protection has single flag, no matrix | | |
| 148 | ||
| 149 | ### 2.6 Observability + safety | |
| 150 | | Feature | Status | Notes | | |
| 151 | |---|---|---| | |
| 152 | | Rate limiting | ✅ | `src/middleware/rate-limit.ts` | | |
| 153 | | Request-ID tracing | ✅ | `src/middleware/request-context.ts` | | |
| 154 | | Health / readiness / metrics | ✅ | `/healthz` `/readyz` `/metrics` | | |
| 155 | | Audit log (table) | ✅ | `audit_log` table | | |
| 6fc53bd | 156 | | Audit log UI | ✅ | `/settings/audit` (personal) + `/:owner/:repo/settings/audit` (per-repo, owner-only) | |
| 9ab6971 | 157 | | Traffic analytics per repo | ❌ | | |
| 24cf2ca | 158 | | Email notifications | ✅ | opt-in per kind (mention/assign/gate-fail) via `/settings`; provider-pluggable `src/lib/email.ts` (log default, resend in prod) | |
| 9ab6971 | 159 | | Email digest | ❌ | | |
| 160 | | Mobile PWA | 🟡 | responsive CSS, no manifest | | |
| 161 | | Native mobile apps | ❌ | | | |
| 6fc53bd | 162 | | Dark mode | ✅ | default | |
| 163 | | Light-mode toggle | ✅ | `/theme/toggle` + `theme` cookie, pre-paint script avoids FOUC, nav sun/moon icon | | |
| 9ab6971 | 164 | | Keyboard shortcuts | ✅ | `/shortcuts` page | |
| 165 | | Command palette | 🟡 | Cmd+K → Ask AI, no generic palette | | |
| 166 | ||
| 167 | --- | |
| 168 | ||
| 169 | ## 3. BUILD PLAN (BLOCKS) | |
| 170 | ||
| 171 | Each block is a self-contained unit. Order matters for dependencies. Each block ends with tests + commit + push. | |
| 172 | ||
| 173 | ### BLOCK A — Hardening the current surface | |
| 174 | Polish what's shipped before adding more. **Priority: do this first if parity gaps are minor.** | |
| 6fc53bd | 175 | - **A1** — Dark/light theme toggle (cookie, CSS variable swap) ✅ |
| 176 | - **A2** — Audit log UI page (`/settings/audit` + `/:owner/:repo/settings/audit`) ✅ | |
| 177 | - **A3** — Reactions UI on issues / PRs / comments (data exists) ✅ | |
| 178 | - **A4** — Draft PR toggle + filter ✅ | |
| 24cf2ca | 179 | - **A5** — Issue + PR templates (`.github/*_TEMPLATE.md` auto-prefill) ✅ |
| 180 | - **A6** — Saved replies per user ✅ | |
| 181 | - **A7** — Environments + deployment history UI (`deployments` table) ✅ | |
| 182 | - **A8** — Email notifications (opt-in, provider-pluggable) ✅ | |
| 183 | ||
| 184 | **BLOCK A COMPLETE.** Next: BLOCK B (Identity + orgs). | |
| 9ab6971 | 185 | |
| 186 | ### BLOCK B — Identity + orgs | |
| 6563f0a | 187 | - **B1** — Organizations (schema: `organizations`, `org_members`, `teams`, `team_members`) ✅ |
| 188 | - Helpers in `src/lib/orgs.ts`: slug validation, role rank, reserved-slug set, loaders | |
| 189 | - Routes in `src/routes/orgs.tsx`: list / create / profile / people / teams / team detail | |
| 190 | - Role-based guards: admin adds members, owner grants owner, last-owner demote/remove blocked | |
| 191 | - All sensitive actions `audit()`'d (org.create, member.add/role/remove, team.create, team.member.add/remove) | |
| 9ab6971 | 192 | - **B2** — Repos owned by orgs (nullable `repositories.orgId`) |
| 193 | - **B3** — Team-based CODEOWNERS (`@org/team` resolution) | |
| 194 | - **B4** — 2FA / TOTP (enroll, recovery codes) | |
| 195 | - **B5** — WebAuthn / passkeys | |
| 196 | - **B6** — OAuth 2.0 provider (third-party apps can request access) | |
| 197 | ||
| 198 | ### BLOCK C — Runtime + hosting | |
| 199 | - **C1** — Actions-equivalent workflow runner | |
| 200 | - Workflow YAML parser (`.gluecron/workflows/*.yml`) | |
| 201 | - Job queue + worker pool (Bun subprocesses) | |
| 202 | - Artifact storage + log streaming | |
| 203 | - Integrates with gates | |
| 204 | - **C2** — Package registry (npm + container protocol) | |
| 205 | - **C3** — Pages / static hosting (`gh-pages` branch → served at `<owner>.<repo>.pages.gluecron.com`) | |
| 206 | - **C4** — Environments (prod/staging/preview) with protected approvals | |
| 207 | ||
| 208 | ### BLOCK D — AI-native differentiation | |
| 209 | This is where GlueCron beats GitHub outright. **Priority: ship these loud.** | |
| 210 | - **D1** — Semantic code search (pgvector + Claude embeddings) | |
| 211 | - **D2** — AI dependency updater (reads lockfile, opens PRs, verifies green) | |
| 212 | - **D3** — AI PR triage agent (auto-assigns reviewers, labels, milestones) | |
| 213 | - **D4** — AI incident responder (on deploy failure, opens issue with root cause) | |
| 214 | - **D5** — AI code reviewer that blocks merges (enforced via branch protection "AI approval required") | |
| 215 | - **D6** — AI "explain this codebase" on repo landing (auto-generated, cached) | |
| 216 | - **D7** — AI changelog for every commit range (`/:owner/:repo/ai/changelog?from=...&to=...`) | |
| 217 | - **D8** — AI-generated test suite (reads public API, generates failing tests) | |
| 218 | - **D9** — Copilot-style completion endpoint for IDE plugins | |
| 219 | ||
| 220 | ### BLOCK E — Collaboration parity | |
| 221 | - **E1** — Projects / kanban boards (`projects`, `project_items`, `project_fields`) | |
| 222 | - **E2** — Discussions (forum threads per repo) | |
| 223 | - **E3** — Wikis (git-backed, separate bare repo per repo) | |
| 224 | - **E4** — Gists (user-owned tiny repos) | |
| 225 | - **E5** — Merge queues (serialised merge with re-test) | |
| 226 | - **E6** — Required status checks matrix (multiple named checks per branch protection rule) | |
| 227 | - **E7** — Protected tags | |
| 228 | ||
| 229 | ### BLOCK F — Observability + admin | |
| 230 | - **F1** — Traffic analytics per repo (views, clones, unique visitors) | |
| 231 | - **F2** — Org-wide insights (green rate across all repos) | |
| 232 | - **F3** — Admin / superuser panel (user moderation, repo audit) | |
| 233 | - **F4** — Billing + quotas (storage, AI tokens, bandwidth) | |
| 234 | ||
| 235 | ### BLOCK G — Mobile + client | |
| 236 | - **G1** — PWA manifest + service worker | |
| 237 | - **G2** — GraphQL API mirror of REST | |
| 238 | - **G3** — Official CLI (`gluecron` binary in Bun) | |
| 239 | - **G4** — VS Code extension | |
| 240 | ||
| 241 | ### BLOCK H — Marketplace | |
| 242 | - **H1** — App marketplace (install third-party apps against a repo) | |
| 243 | - **H2** — GitHub Apps equivalent (bot identities with scoped permissions) | |
| 244 | ||
| 245 | --- | |
| 246 | ||
| 247 | ## 4. LOCKED BLOCKS (DO NOT UNDO) | |
| 248 | ||
| 249 | Everything below is committed, tested, and load-bearing. **Do not delete, rename, or semantically change without owner permission.** | |
| 250 | ||
| 251 | ### 4.1 Infrastructure (locked) | |
| 252 | - `src/app.tsx` — route composition, middleware order, error handlers | |
| 253 | - `src/index.ts` — Bun server entry | |
| 254 | - `src/lib/config.ts` — env getters (late-binding) | |
| 255 | - `src/db/schema.ts` — 27 tables. New tables only via new migration. | |
| 256 | - `src/db/index.ts` — lazy proxy DB connection | |
| 257 | - `src/db/migrate.ts` — migration runner | |
| 258 | - `drizzle/0000_initial.sql`, `drizzle/0001_green_ecosystem.sql` — migrations | |
| 259 | ||
| 260 | ### 4.2 Git layer (locked) | |
| 261 | - `src/git/repository.ts` — tree / blob / commits / diff / branches / blame / search / raw / tags / commitsBetween | |
| 262 | - `src/git/protocol.ts` — Smart HTTP pkt-line | |
| 263 | - `src/hooks/post-receive.ts` — CODEOWNERS sync, gates, auto-deploy, webhook fan-out | |
| 264 | ||
| 265 | ### 4.3 Auth + security (locked) | |
| 266 | - `src/lib/auth.ts` — bcrypt, session tokens | |
| 267 | - `src/middleware/auth.ts` — softAuth + requireAuth | |
| 268 | - `src/middleware/rate-limit.ts` — fixed-window limiter | |
| 269 | - `src/middleware/request-context.ts` — request-ID | |
| 270 | - `src/lib/security-scan.ts` — `SECRET_PATTERNS` (exported) + `scanForSecrets` + `aiSecurityScan` | |
| 271 | - `src/lib/codeowners.ts` — parser + `ownersForPath` (last-match-wins) | |
| 272 | ||
| 273 | ### 4.4 AI layer (locked) | |
| 274 | - `src/lib/ai-client.ts` — Anthropic client + model constants | |
| 275 | - `src/lib/ai-generators.ts` — commit / PR / changelog / issue-triage | |
| 276 | - `src/lib/ai-chat.ts` — conversational chat | |
| 277 | - `src/lib/ai-review.ts` — PR code review | |
| 278 | - `src/lib/auto-repair.ts` — worktree-backed repair commits | |
| 279 | - `src/lib/merge-resolver.ts` — AI merge conflict resolution | |
| 280 | ||
| 281 | ### 4.5 Platform (locked) | |
| 24cf2ca | 282 | - `src/lib/notify.ts` — notification creation + audit log (swallow-failures pattern). Also fans out email to opted-in recipients for `mention|review_requested|assigned|gate_failed`. Exports `__internal` for tests. |
| 283 | - `src/lib/email.ts` — provider-pluggable email sender (`log`|`resend`). `sendEmail()` never throws. `absoluteUrl()` joins paths against `APP_BASE_URL`. | |
| 284 | - `src/lib/templates.ts` — `loadIssueTemplate` / `loadPrTemplate`. Checks standard paths (`.github/`, `.gluecron/`, root, `docs/`) on the default branch, strips YAML frontmatter, 16KB cap, returns null on any failure. | |
| 9ab6971 | 285 | - `src/lib/unread.ts` — unread count helper (never throws) |
| 286 | - `src/lib/repo-bootstrap.ts` — green defaults on repo creation | |
| 287 | - `src/lib/gate.ts` — gate orchestration + persistence | |
| 288 | - `src/lib/cache.ts` — LRU cache, git-cache invalidation | |
| 6fc53bd | 289 | - `src/lib/reactions.ts` — `summariseReactions`, `toggleReaction`, `ALLOWED_EMOJIS`, `EMOJI_GLYPH`, `isAllowedEmoji`, `isAllowedTarget` |
| 9ab6971 | 290 | |
| 291 | ### 4.6 Routes (locked endpoints — behaviour must be preserved) | |
| 292 | - `src/routes/git.ts` — Smart HTTP (clone/push) | |
| 293 | - `src/routes/api.ts` — REST (`POST /api/repos`, `GET /api/users/:u/repos`, `GET /api/repos/:o/:n`, `POST /api/setup`) | |
| ad6d4ad | 294 | - `src/routes/hooks.ts` — `POST /api/hooks/gatetest` (bearer/HMAC), `GET /api/hooks/ping`, `POST /api/v1/gate-runs` (PAT backup), `GET /api/v1/gate-runs`. See `GATETEST_HOOK.md`. |
| 6fc53bd | 295 | - `src/routes/theme.ts` — `GET /theme/toggle`, `GET /theme/set?mode=`. Writes `theme` cookie (`dark`|`light`, 1-year). Layout reads via pre-paint inline script. |
| 296 | - `src/routes/audit.tsx` — `GET /settings/audit` (personal) + `GET /:owner/:repo/settings/audit` (owner-only). | |
| 24cf2ca | 297 | - `src/routes/saved-replies.tsx` — `GET/POST /settings/replies`, `POST /settings/replies/:id`, `POST /settings/replies/:id/delete`, `GET /api/user/replies`. Unique constraint `saved_replies_user_shortcut`. |
| 298 | - `src/routes/deployments.tsx` — `GET /:owner/:repo/deployments` (grouped by env, success-rate rollup), `GET /:owner/:repo/deployments/:id` (detail). | |
| 6fc53bd | 299 | - `src/routes/reactions.ts` — `POST /api/reactions/:targetType/:targetId/:emoji/toggle` (authed, form- or fetch-compatible), `GET /api/reactions/:targetType/:targetId`. Targets: `issue|pr|issue_comment|pr_comment`. Emojis: 8 canonical. |
| 9ab6971 | 300 | - `src/routes/auth.tsx` — register / login / logout |
| 301 | - `src/routes/web.tsx` — home / new / browse / blob / commits / raw / blame / star / search / profile | |
| 302 | - `src/routes/issues.tsx` — issue CRUD + comments + labels + lock | |
| 303 | - `src/routes/pulls.tsx` — PR CRUD + review + merge + close | |
| 304 | - `src/routes/editor.tsx` — web file editor | |
| 305 | - `src/routes/compare.tsx` — base...head diff | |
| 24cf2ca | 306 | - `src/routes/settings.tsx` — profile + password + email notification preferences (`POST /settings/notifications`) |
| 9ab6971 | 307 | - `src/routes/repo-settings.tsx` — repo settings + delete |
| 308 | - `src/routes/webhooks.tsx` — webhook CRUD + test + `fireWebhooks` | |
| 309 | - `src/routes/fork.ts` — fork | |
| 310 | - `src/routes/explore.tsx` — discover | |
| 311 | - `src/routes/tokens.tsx` — personal access tokens | |
| 312 | - `src/routes/contributors.tsx` — contributor list | |
| 313 | - `src/routes/notifications.tsx` — inbox + unread API | |
| 314 | - `src/routes/dashboard.tsx` — authed home (`renderDashboard` exported) | |
| 315 | - `src/routes/ask.tsx` — global + repo AI chat + explain | |
| 316 | - `src/routes/releases.tsx` — tags + AI changelog | |
| 317 | - `src/routes/gates.tsx` — history + settings + branch protection UI | |
| 318 | - `src/routes/insights.tsx` — insights + milestones | |
| 319 | - `src/routes/search.tsx` — global search + `/shortcuts` | |
| 320 | - `src/routes/health.ts` — `/healthz` `/readyz` `/metrics` | |
| 6563f0a | 321 | - `src/routes/orgs.tsx` — `/orgs` list, `/orgs/new` create, `/orgs/:slug` profile, `/orgs/:slug/people` + add/role/remove, `/orgs/:slug/teams` + create, `/orgs/:slug/teams/:teamSlug` + member add/remove. All require auth. Role guards via `orgRoleAtLeast`; last-owner cannot be demoted or removed; every write path `audit()`'d. |
| 322 | - `src/lib/orgs.ts` — `isValidSlug` (rejects reserved + too-short/long + consecutive/leading/trailing hyphens), `normalizeSlug`, `orgRoleAtLeast` (owner>admin>member), `isValidOrgRole`, `isValidTeamRole`, `loadOrgForUser`, `listOrgsForUser`, `listOrgMembers`, `listTeamsForOrg`, `listTeamMembers`, `__test` export for unit tests. | |
| 9ab6971 | 323 | |
| 324 | ### 4.7 Views (locked contracts) | |
| 325 | - `src/views/layout.tsx` — `Layout` accepts `title`, `user`, `notificationCount` | |
| 326 | - `src/views/components.tsx` — `RepoHeader`, `RepoNav` (active: `code|issues|pulls|commits|releases|gates|insights|...`), `RepoCard`, etc. | |
| 6fc53bd | 327 | - `src/views/reactions.tsx` — `ReactionsBar` (no-JS compatible, form-per-emoji) |
| 328 | - Nav links: logo · search · theme-toggle · Explore · Ask · Notifications · New · Profile (or Sign in / Register) | |
| 9ab6971 | 329 | - Keyboard chords: `/`, `Cmd+K`, `?`, `n`, `g d`, `g n`, `g e`, `g a` |
| 330 | ||
| 331 | ### 4.8 Tests (locked) | |
| 332 | - `src/__tests__/green-ecosystem.test.ts` — secret scanner, codeowners, AI fallback, health, rate-limit headers, `/shortcuts`, `/search` | |
| 333 | - All other existing test files — do not delete without owner permission | |
| 334 | ||
| 335 | ### 4.9 Invariants (never break these) | |
| 336 | - `isAiAvailable()` guard returns true fallback strings when no ANTHROPIC_API_KEY. AI features degrade gracefully. | |
| 337 | - `getUnreadCount` never throws; returns 0 on any error. | |
| 338 | - Rate-limit middleware adds `X-RateLimit-Limit` + `X-RateLimit-Remaining` to every response, including 500s. | |
| 339 | - `c.header("X-Request-Id", ...)` set by request-context on every response. | |
| 340 | - Secret scanner skips binary/lock paths (`shouldSkipPath`). | |
| 341 | - `SECRET_PATTERNS` is an exported array. Its shape is `{ type, regex, severity }`. | |
| 6fc53bd | 342 | - Theme routes live outside `/settings/*` (they must work for logged-out visitors). Cookie name: `theme`, values: `dark|light`. |
| 343 | - Draft PRs cannot be merged — `/pulls/:n/merge` returns a redirect with the draft error when `pr.isDraft=true`. | |
| 344 | - Reactions API accepts only `ALLOWED_EMOJIS` and `ALLOWED_TARGETS`. Toggle is idempotent per (user, target, emoji). | |
| 24cf2ca | 345 | - `sendEmail()` never throws — always resolves to `{ ok, provider, ... }`. Email failures never break notification delivery or the primary request path. |
| 346 | - Email fan-out in `notify()` is scoped to kinds in `EMAIL_ELIGIBLE` (mention / review_requested / assigned / gate_failed). Each eligible kind maps to exactly one user preference column. | |
| 347 | - Issue + PR template loading must return `null` on any git-subprocess failure (templates are a convenience, not a requirement). Forms always render. | |
| 9ab6971 | 348 | |
| 349 | --- | |
| 350 | ||
| 351 | ## 5. OPERATIONAL NOTES | |
| 352 | ||
| 353 | ### 5.1 Running locally | |
| 354 | ```bash | |
| 355 | bun install | |
| 356 | bun dev # hot reload | |
| 24cf2ca | 357 | bun test # 99 tests currently pass |
| 9ab6971 | 358 | bun run db:migrate |
| 359 | ``` | |
| 360 | ||
| 361 | ### 5.2 Environment | |
| 362 | - `DATABASE_URL` — Neon Postgres | |
| 363 | - `ANTHROPIC_API_KEY` — unlocks AI features | |
| 364 | - `GIT_REPOS_PATH` — default `./repos` | |
| 365 | - `PORT` — default 3000 | |
| 24cf2ca | 366 | - `EMAIL_PROVIDER` — `log` (default, stderr-only) or `resend` |
| 367 | - `EMAIL_FROM` — sender address for outbound mail | |
| 368 | - `RESEND_API_KEY` — required when `EMAIL_PROVIDER=resend` | |
| 369 | - `APP_BASE_URL` — canonical URL used to build absolute links in emails | |
| 9ab6971 | 370 | |
| 371 | ### 5.3 Models | |
| 372 | - `claude-sonnet-4-20250514` — code review, security, chat | |
| 373 | - `claude-haiku-4-5-20251001` — commit messages, summaries, light tasks | |
| 374 | - Swap via `MODEL_SONNET` / `MODEL_HAIKU` constants in `src/lib/ai-client.ts` | |
| 375 | ||
| 376 | ### 5.4 Deployment | |
| 377 | - `railway.toml` / `fly.toml` present | |
| 378 | - Crontech deploy on green push to default branch (can opt out via `autoDeployEnabled`) | |
| 379 | ||
| 380 | --- | |
| 381 | ||
| 382 | ## 6. SESSION WORKFLOW (WHAT THE NEXT AGENT DOES) | |
| 383 | ||
| 384 | 1. Read this file, `CLAUDE.md`, `README.md`, `git log -1 --stat`. | |
| 385 | 2. Check `git status` + current branch. | |
| 386 | 3. Pick the next unfinished block from §3 (lowest letter + number first, unless owner specifies). | |
| 387 | 4. Create a todo list that mirrors the sub-items of that block. | |
| 388 | 5. Build. Write tests. Run `bun test`. | |
| 389 | 6. Commit with `feat(<BLOCK-ID>): ...`. | |
| 390 | 7. Push. | |
| 391 | 8. Update this file: | |
| 392 | - Move the block's row in §2 to ✅ where applicable. | |
| 393 | - Add the block's files to §4 LOCKED BLOCKS. | |
| 394 | - Commit + push again. | |
| 395 | 9. Start the next block. **Do not stop to ask.** | |
| 396 | ||
| 397 | If a block is too large for a single session, split it into a sub-plan at the top of the session, ship what you can, and document what's left at the end of this file under a `## 7. IN-FLIGHT` section. | |
| 398 | ||
| 399 | --- | |
| 400 | ||
| 401 | ## 7. IN-FLIGHT | |
| 402 | ||
| 403 | (Intentionally empty. Add here if a block is partially complete at session end.) |