Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
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.

BUILD_BIBLE.mdBlame511 lines · 1 contributor
9ab6971Claude1# 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
7GlueCron 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
141. `BUILD_BIBLE.md` (this file) — complete
152. `CLAUDE.md` — stack + architecture
163. `README.md` — user-facing overview
174. 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
15e65d2Claude49### 1.7 Parallelism rule (added per owner request)
50- **Default to spawning sub-agents whenever work can be parallelised.** Owner-cost of an idle main thread is high; owner-cost of an extra agent is near-zero.
51- Independent files = parallel agents. Schema-only edits, new route files, doc updates, test additions, codebase research — all of these run in parallel by default unless they collide.
52- Coordinate file ownership: one agent per file. Never let two agents edit the same file. Mounting + middleware integration stay on the main thread to avoid merge conflicts.
53- When launching multiple agents, send them in a single message with multiple Agent tool calls so they actually run concurrently.
54- The main thread is responsible for: reviewing each agent's output before integrating, running the test suite, and committing. Trust-but-verify — read the changes, don't just rely on the agent's summary.
55
9ab6971Claude56---
57
58## 2. GITHUB PARITY SCORECARD
59
60Legend: ✅ shipped · 🟡 partial · ❌ not built
61
62### 2.1 Repository hosting
63| Feature | Status | Notes |
64|---|---|---|
65| Git Smart HTTP (clone / push / fetch) | ✅ | `src/routes/git.ts`, `src/git/protocol.ts` |
66| SSH keys | ✅ | `ssh_keys` table, `src/routes/settings.tsx` |
67| Public / private visibility | ✅ | `repositories.isPrivate` |
68| Forking | ✅ | `src/routes/fork.ts` |
69| Stars | ✅ | `stars` table, `/:owner/:repo/star` |
70| Topics | ✅ | `repo_topics` table |
71cd5ecClaude71| Archive / disable repo | ✅ | I1 — `src/routes/repo-settings.tsx` archive toggle; `RepoHeader` renders an "Archived" badge when `is_archived=true`. |
72| Repository transfer | ✅ | I3 — `src/routes/repo-settings.tsx` transfer form + `POST /:owner/:repo/settings/transfer`; ownership change recorded in `repo_transfers` audit table. Reject conflicts (target owner already has a repo by that name) with a redirect. |
73| Template repositories | ✅ | I2 — `drizzle/0022_repo_templates.sql` adds `is_template`. `src/routes/templates.ts` serves `POST /:owner/:repo/use-template` (git clone --bare into caller's namespace). "Use this template" CTA rendered on the public repo page. |
9ab6971Claude74| Repository mirroring | ❌ | — |
75
76### 2.2 Code browsing
77| Feature | Status | Notes |
78|---|---|---|
79| File tree browser | ✅ | `src/routes/web.tsx` |
80| Syntax highlighting | ✅ | 40+ languages, `src/lib/highlight.ts` |
81| Commit history | ✅ | |
82| Diffs | ✅ | |
83| Blame | ✅ | |
84| Raw file download | ✅ | |
85| Branch switcher | ✅ | |
86| Tag listing | ✅ | new this build |
87| Code search (ILIKE) | ✅ | per-repo + global |
3cbe3d6Claude88| Semantic / embedding search | ✅ | D1 — `code_chunks` table + lexical fallback, optional Voyage `voyage-code-3`; `src/lib/semantic-search.ts`, `src/routes/semantic-search.tsx` |
9ab6971Claude89| Symbol / xref navigation | ❌ | — |
90
91### 2.3 Collaboration
92| Feature | Status | Notes |
93|---|---|---|
94| Issues (CRUD / comments / labels / close) | ✅ | |
95| Milestones | ✅ | `src/routes/insights.tsx` |
96| Pull requests (CRUD / review / merge) | ✅ | |
97| PR inline comments | ✅ | file+line anchored |
6fc53bdClaude98| Draft PRs | ✅ | create as draft, ready-for-review toggle, dedicated tab, merge blocked until ready |
99| Reactions (emoji) | ✅ | 8 reactions, toggle via `POST /api/reactions/:t/:id/:emoji/toggle` on issues + PRs + comments |
9ab6971Claude100| Mentions + notifications | ✅ | `src/routes/notifications.tsx` |
101| Code owners | ✅ | `src/lib/codeowners.ts` |
24cf2caClaude102| Issue templates | ✅ | `.github/ISSUE_TEMPLATE.md` auto-prefills new issues; frontmatter stripped; `src/lib/templates.ts` |
103| PR templates | ✅ | `.github/PULL_REQUEST_TEMPLATE.md` auto-prefills new PRs; `src/lib/templates.ts` |
104| Saved replies | ✅ | per-user canned comments, unique-shortcut, `/settings/replies`, `/api/user/replies` |
1e162a8Claude105| Discussions / forums | ✅ | E2 — categorised threads, pinned/locked, q-and-a answers. `src/routes/discussions.tsx` + `drizzle/0013_discussions.sql` |
106| Wikis | ✅ | E3 — markdown pages per repo with revision history + revert. DB-backed v1. `src/routes/wikis.tsx` + `drizzle/0016_wikis.sql` |
107| Projects / kanban | ✅ | E1 — per-repo boards with auto-seeded To Do/In Progress/Done columns. Notes or linked issues/PRs. `src/routes/projects.tsx` + `drizzle/0015_projects.sql` |
108| AI incident responder | ✅ | D4 — auto-issues on deploy fail, `src/lib/ai-incident.ts` |
109| AI-generated test stubs | ✅ | D8 — `src/lib/ai-tests.ts`, `/:owner/:repo/ai/tests` |
9ab6971Claude110
111### 2.4 Automation + AI
112| Feature | Status | Notes |
113|---|---|---|
ad6d4adClaude114| Webhooks (outbound, HMAC signed) | ✅ | `src/routes/webhooks.tsx` |
115| GateTest inbound callback | ✅ | `POST /api/hooks/gatetest`, bearer or HMAC |
116| Backup PAT-auth gate ingest | ✅ | `POST /api/v1/gate-runs` |
9ab6971Claude117| Gate runs (test / secret / AI review) | ✅ | `gate_runs` table, `src/routes/gates.tsx` |
118| Branch protection | ✅ | `branch_protection` table + UI |
119| Auto-repair engine | ✅ | `src/lib/auto-repair.ts` |
120| Secret scanner | ✅ | 15 patterns, `src/lib/security-scan.ts` |
121| AI security review | ✅ | Sonnet 4, `src/lib/security-scan.ts` |
122| AI commit messages | ✅ | `src/lib/ai-generators.ts` |
123| AI PR summaries | ✅ | |
3cbe3d6Claude124| AI changelogs | ✅ | auto on release create; arbitrary-range viewer at `/:owner/:repo/ai/changelog?from=&to=` (D7) |
9ab6971Claude125| AI code review | ✅ | `src/lib/ai-review.ts` |
126| AI merge conflict resolver | ✅ | `src/lib/merge-resolver.ts` |
127| AI chat (global + repo) | ✅ | `src/routes/ask.tsx` |
3cbe3d6Claude128| AI explain-this-codebase | ✅ | D6 — per-commit cached markdown, `GET /:owner/:repo/explain`, `src/lib/ai-explain.ts` + `src/routes/ai-explain.tsx` |
129| AI PR triage | ✅ | D3 — Claude Haiku suggests labels/reviewers/priority as an AI comment on PR create; `triagePullRequest` in `src/lib/ai-generators.ts`, wired in `src/routes/pulls.tsx` |
5e888b7Claude130| GitHub Actions equivalent (workflow runner) | ✅ | `src/lib/workflow-parser.ts`, `src/lib/workflow-runner.ts`, `src/routes/workflows.tsx`; `.gluecron/workflows/*.yml` auto-discovered on push; Bun subprocess executor, per-step timeouts, size-capped logs |
3cbe3d6Claude131| Dependabot equivalent (AI dep bumper) | ✅ | D2 — `dep_update_runs` table, npm registry fetch, plan + apply bumps, creates `gluecron/dep-update-*` branch + PR row via git plumbing. `src/lib/dep-updater.ts`, `src/routes/dep-updater.tsx`, settings UI at `/:owner/:repo/settings/dep-updater`. |
9ab6971Claude132| Code scanning UI | 🟡 | data exists, no dedicated UI page |
3cbe3d6Claude133| Copilot code completion | ✅ | D9 — `POST /api/copilot/completions` (PAT/OAuth/session), `GET /api/copilot/ping`. `src/lib/ai-completion.ts`, `src/routes/copilot.ts`. LRU-cached, rate-limited 60/min. |
134| Semantic code search | ✅ | D1 — see 2.2 |
9ab6971Claude135
136### 2.5 Platform
137| Feature | Status | Notes |
138|---|---|---|
139| Dashboard | ✅ | `src/routes/dashboard.tsx` |
140| Explore / discover | ✅ | |
141| Global search | ✅ | repos / users / issues / PRs |
142| Insights (graph, contributors, green rate) | ✅ | `src/routes/insights.tsx` |
143| Releases + tags | ✅ | AI changelog |
144| Personal access tokens | ✅ | SHA-256 hashed |
058d752Claude145| OAuth app provider | ✅ | `src/routes/oauth.tsx`, `src/routes/developer-apps.tsx`, `src/lib/oauth.ts`; `oauth_apps` + `oauth_authorizations` + `oauth_access_tokens` tables |
06139e6Claude146| GitHub Apps equivalent | ✅ | H2 — `src/lib/marketplace.ts` `generateBearerToken`/`verifyInstallToken` (1h TTL, `ghi_` prefix, sha256 hashed). Each app gets a `<slug>[bot]` identity (`app_bots`). Permissions enforced via `hasPermission` (write implies read). |
71cd5ecClaude147| GraphQL API | ✅ | G2 — see 2.6 |
058d752Claude148| Organizations + teams | ✅ | B1+B2+B3 shipped: `src/routes/orgs.tsx`, `src/lib/orgs.ts`; org-owned repos (`repositories.orgId`); team-based CODEOWNERS (`@org/team` resolution) |
9ab6971Claude149| Enterprise SAML / SSO | ❌ | |
058d752Claude150| 2FA / TOTP | ✅ | `src/routes/settings-2fa.tsx`, `src/lib/totp.ts`; `user_totp` + `user_recovery_codes` tables |
151| Passkeys / WebAuthn | ✅ | `src/routes/passkeys.tsx`, `src/lib/webauthn.ts`; `user_passkeys` + `webauthn_challenges` tables |
25a91a6Claude152| Packages registry (npm / docker / etc) | ✅ | `src/lib/packages.ts`, `src/routes/packages-api.ts`, `src/routes/packages.tsx`; npm protocol (packument, tarball, publish, yank); PAT (`glc_`) auth via Authorization header; container registry deferred |
153| Pages / static hosting | ✅ | `src/lib/pages.ts`, `src/routes/pages.tsx`; serves blobs from bare git at latest `gh-pages` commit; per-repo settings (source branch/dir, custom domain); short-cache headers |
1e162a8Claude154| Gists | ✅ | E4 — multi-file tiny repos with per-revision JSON snapshots + stars. `src/routes/gists.tsx` + `drizzle/0014_gists.sql` |
9ab6971Claude155| Sponsors | ❌ | |
06139e6Claude156| Marketplace | ✅ | H1 — `src/routes/marketplace.tsx` + `src/lib/marketplace.ts`, `drizzle/0021_marketplace_and_apps.sql` (5 tables: `apps`, `app_installations`, `app_bots`, `app_install_tokens`, `app_events`). Public `/marketplace` directory, `/marketplace/:slug` detail + install, `/settings/apps` personal installs, `/developer/apps-new` registration, `/developer/apps/:slug/manage` event log + token issuance. |
25a91a6Claude157| Environments / deployment tracking | ✅ | `src/routes/deployments.tsx` — grouped by env, success-rate rollup, per-deploy detail. Protected environments (`src/routes/environments.tsx`, `src/lib/environments.ts`) with reviewer-gated approval, branch-glob restrictions, approve/reject decisions recorded in `deployment_approvals` |
a79a9edClaude158| Merge queues | ✅ | E5 — serialised merge with re-test. `src/lib/merge-queue.ts`, `src/routes/merge-queue.tsx`, `drizzle/0017_merge_queue.sql`; per `(repo, base_branch)` queue, owner-only process-next re-runs gates against latest base before merging. |
159| Required checks matrix | ✅ | E6 — per branch-protection named check list. `src/routes/required-checks.tsx`, `drizzle/0018_required_checks.sql`; `listRequiredChecks` + `passingCheckNames` helpers in `src/lib/branch-protection.ts`; merge handler verifies every required name has a passing gate_run or workflow_run. |
160| Protected tags | ✅ | E7 — owners can mark tag patterns (`v*`, `release-*`) protected. `src/lib/protected-tags.ts`, `src/routes/protected-tags.tsx`, `drizzle/0019_protected_tags.sql`; advisory enforcement via post-receive audit log (v1). |
9ab6971Claude161
162### 2.6 Observability + safety
163| Feature | Status | Notes |
164|---|---|---|
165| Rate limiting | ✅ | `src/middleware/rate-limit.ts` |
166| Request-ID tracing | ✅ | `src/middleware/request-context.ts` |
167| Health / readiness / metrics | ✅ | `/healthz` `/readyz` `/metrics` |
168| Audit log (table) | ✅ | `audit_log` table |
6fc53bdClaude169| Audit log UI | ✅ | `/settings/audit` (personal) + `/:owner/:repo/settings/audit` (per-repo, owner-only) |
8f50ed0Claude170| Traffic analytics per repo | ✅ | F1 — `src/lib/traffic.ts` + `src/routes/traffic.tsx`, `drizzle/0020_analytics_and_admin.sql`; owner-only 7/14/30/90d windows, ascii-bar daily chart. SHA-256-truncated IP for unique visitors. Fire-and-forget wiring in `web.tsx` + `git.ts`. |
171| Org insights dashboard | ✅ | F2 — `src/routes/org-insights.tsx`; `computeOrgInsights(orgId)` rollup of gate green-rate + PR/issue counts + per-repo breakdown. `GET /orgs/:slug/insights`. |
172| Site admin panel | ✅ | F3 — `src/lib/admin.ts` + `src/routes/admin.tsx`, tables `site_admins` + `system_flags`. Bootstrap rule (oldest user wins until `site_admins` populated). Flags: registration_locked, site_banner_*, read_only_mode. |
173| Billing + quotas | ✅ | F4 — `src/lib/billing.ts` + `src/routes/billing.tsx`, tables `billing_plans` + `user_quotas` seeded free/pro/team/enterprise. `/settings/billing` personal view + `/admin/billing` site-admin override. |
24cf2caClaude174| Email notifications | ✅ | opt-in per kind (mention/assign/gate-fail) via `/settings`; provider-pluggable `src/lib/email.ts` (log default, resend in prod) |
9ab6971Claude175| Email digest | ❌ | |
eae38d1Claude176| Mobile PWA | ✅ | G1 — `src/routes/pwa.ts` serves `/manifest.webmanifest` + `/sw.js` + `/icon.svg`; Layout injects manifest link + SW registration. Offline-capable (network-first for HTML). |
177| GraphQL API | ✅ | G2 — `src/lib/graphql.ts` parser + executor, `src/routes/graphql.ts` endpoint at `POST /api/graphql`, GraphiQL-lite explorer at `GET /api/graphql`. Queries only (viewer/user/repository/search/rateLimit). |
178| Official CLI | ✅ | G3 — `cli/gluecron.ts` Bun-compilable single binary. REST + GraphQL client, `~/.gluecron/config.json` 0600. |
179| VS Code extension | ✅ | G4 — `vscode-extension/` with commands for explain / open-on-web / semantic search / generate tests. |
9ab6971Claude180| Native mobile apps | ❌ | |
6fc53bdClaude181| Dark mode | ✅ | default |
182| Light-mode toggle | ✅ | `/theme/toggle` + `theme` cookie, pre-paint script avoids FOUC, nav sun/moon icon |
9ab6971Claude183| Keyboard shortcuts | ✅ | `/shortcuts` page |
71cd5ecClaude184| Command palette | ✅ | I4 — `src/views/layout.tsx` injects a Cmd+K palette with ~20 canonical destinations, arrow-key navigation + fuzzy match. Backdrop click or Esc closes. |
9ab6971Claude185
186---
187
188## 3. BUILD PLAN (BLOCKS)
189
190Each block is a self-contained unit. Order matters for dependencies. Each block ends with tests + commit + push.
191
192### BLOCK A — Hardening the current surface
193Polish what's shipped before adding more. **Priority: do this first if parity gaps are minor.**
6fc53bdClaude194- **A1** — Dark/light theme toggle (cookie, CSS variable swap) ✅
195- **A2** — Audit log UI page (`/settings/audit` + `/:owner/:repo/settings/audit`) ✅
196- **A3** — Reactions UI on issues / PRs / comments (data exists) ✅
197- **A4** — Draft PR toggle + filter ✅
24cf2caClaude198- **A5** — Issue + PR templates (`.github/*_TEMPLATE.md` auto-prefill) ✅
199- **A6** — Saved replies per user ✅
200- **A7** — Environments + deployment history UI (`deployments` table) ✅
201- **A8** — Email notifications (opt-in, provider-pluggable) ✅
202
203**BLOCK A COMPLETE.** Next: BLOCK B (Identity + orgs).
9ab6971Claude204
205### BLOCK B — Identity + orgs
058d752Claude206- **B1** — Organizations (schema: `organizations`, `org_members`, `teams`, `team_members`) → ✅ shipped (`6563f0a`)
6563f0aClaude207 - Helpers in `src/lib/orgs.ts`: slug validation, role rank, reserved-slug set, loaders
208 - Routes in `src/routes/orgs.tsx`: list / create / profile / people / teams / team detail
209 - Role-based guards: admin adds members, owner grants owner, last-owner demote/remove blocked
210 - All sensitive actions `audit()`'d (org.create, member.add/role/remove, team.create, team.member.add/remove)
058d752Claude211- **B2** — Repos owned by orgs (nullable `repositories.orgId`) → ✅ shipped (`7437605`)
212- **B3** — Team-based CODEOWNERS (`@org/team` resolution) → ✅ shipped (`40d3e3f`)
213- **B4** — 2FA / TOTP (enroll, recovery codes) → ✅ shipped (`7298a17`)
214- **B5** — WebAuthn / passkeys → ✅ shipped (`2df1f8c`)
215- **B6** — OAuth 2.0 provider (third-party apps can request access) → ✅ shipped (pending final commit)
9ab6971Claude216
217### BLOCK C — Runtime + hosting
5e888b7Claude218- **C1** — Actions-equivalent workflow runner → ✅ shipped (`eafe8c6`)
219 - Workflow YAML parser (`src/lib/workflow-parser.ts`) — hand-rolled subset
220 - Background worker (`src/lib/workflow-runner.ts`) — Bun.spawn, size-capped logs, SIGTERM→SIGKILL timeouts
221 - Auto-discovery from `.gluecron/workflows/*.yml` on default-branch push
222 - UI at `/:owner/:repo/actions` with manual trigger + cancel
25a91a6Claude223- **C2** — Package registry (npm protocol) → ✅ shipped
224 - Packument + tarball + publish + yank via `PUT /npm/<name>` + `GET /npm/<name>`
225 - PAT (`glc_`) bearer auth for CLI clients; add `//host/npm/:_authToken=<PAT>` to .npmrc
226 - Container registry deferred (schema ready for it)
227- **C3** — Pages / static hosting → ✅ shipped
228 - Serves `/:owner/:repo/pages/*` from the latest successful `pages_deployments` row
229 - Auto-records on push to the repo's configured source branch (default `gh-pages`)
230 - Settings UI at `/:owner/:repo/settings/pages` + manual redeploy
231- **C4** — Environments with protected approvals → ✅ shipped
232 - Per-repo `environments` with reviewer list + branch-glob allowlist
233 - Auto-deploy on main is gated by `requiresApprovalFor()`; pending rows show status `pending_approval`
234 - Approve/reject at `POST /:owner/:repo/deployments/:id/approve|reject`
9ab6971Claude235
236### BLOCK D — AI-native differentiation
237This is where GlueCron beats GitHub outright. **Priority: ship these loud.**
3cbe3d6Claude238- **D1** — Semantic code search → ✅ shipped. `src/lib/semantic-search.ts` + `src/routes/semantic-search.tsx`. `code_chunks` table stores chunk embeddings as JSON (upgrade path to `pgvector`). Embedding provider: Voyage AI `voyage-code-3` when `VOYAGE_API_KEY` is set, otherwise deterministic 512-dim hashing fallback. Index via `POST /:owner/:repo/search/semantic/reindex` (owner-only).
239- **D2** — AI dependency updater → ✅ shipped. `src/lib/dep-updater.ts` + `src/routes/dep-updater.tsx`. `dep_update_runs` table tracks run history. Parses `package.json`, queries `registry.npmjs.org`, plans bumps (skips workspace/github specs + downgrades), writes an `gluecron/dep-update-<ts>` branch via git plumbing (`hash-object` + `mktree` + `commit-tree` + `update-ref`), inserts a pull_requests row with a markdown bump table. Settings UI at `/:owner/:repo/settings/dep-updater` with "Run now".
240- **D3** — AI PR triage → ✅ shipped. `triagePullRequest` in `src/lib/ai-generators.ts`; hooked into PR create in `src/routes/pulls.tsx` (fire-and-forget). Posts a non-applied "## AI Triage" comment with suggested labels, reviewers, priority, and risk area. Suggestions only — PR author stays in control.
1e162a8Claude241- **D4** — AI incident responder → ✅ shipped. `src/lib/ai-incident.ts` exports `onDeployFailure(args)` — on deploy-fail hooks, samples ~10 recent commits, calls Sonnet 4 for a structured root-cause JSON, opens an issue (number via `serial`), best-effort attaches `incident` label, sets `deployments.blockedReason="auto-issue #N"`. Wired from `src/hooks/post-receive.ts triggerCrontechDeploy` (fire-and-forget) and from `POST /:owner/:repo/deployments/:id/retry-incident` (owner-only re-run button on the deployment detail page). Never throws; degrades to deterministic body when no `ANTHROPIC_API_KEY`.
242- **D5** — AI code reviewer blocks merges → ✅ shipped. `src/lib/branch-protection.ts` exports `matchProtection(repoId, branch)` (exact > glob, reuses `matchGlob` from environments.ts), `evaluateProtection(rule, ctx)` pure decision helper (checks `requireAiApproval` / `requireGreenGates` / `requireHumanReview` / `requiredApprovals`), and `countHumanApprovals(prId)` (LGTM/`+1`/approved heuristic on non-AI PR comments). Wired into `src/routes/pulls.tsx` merge handler after the existing hard-gate filter — blocks merge with readable reasons when rule fails. 8 unit tests in `src/__tests__/branch-protection.test.ts`.
3cbe3d6Claude243- **D6** — AI "explain this codebase" → ✅ shipped. `src/lib/ai-explain.ts` + `src/routes/ai-explain.tsx`. Samples up to ~25 representative files (~60KB cap), generates a Markdown explanation via Sonnet 4, caches per (repo, commit sha) in `codebase_explanations`. `GET /:owner/:repo/explain` + owner-only `POST /:owner/:repo/explain/regenerate`. Explain link added to `RepoNav`.
244- **D7** — AI changelog for every commit range → ✅ shipped. `src/routes/ai-changelog.tsx`. `GET /:owner/:repo/ai/changelog?from=&to=(&format=markdown)` — runs `git log` on the range, calls existing `generateChangelog`, renders form + rendered Markdown + copy-box; `format=markdown` returns `text/markdown` for CLI/CI consumers. Caps at 500 commits.
1e162a8Claude245- **D8** — AI-generated test suite → ✅ shipped. `src/lib/ai-tests.ts` exports `detectLanguage(path)`, `detectTestFramework(repo tree)`, `buildTestsPrompt(...)`, `suggestedTestPath(...)`, `generateTestStub({path, content, framework, language})` (returns `{code:"", framework:"fallback"}` when AI unavailable), `contentTypeFor(path)`. Route `src/routes/ai-tests.tsx` adds `GET /:owner/:repo/ai/tests` (form + file picker), `GET /:owner/:repo/ai/tests?format=raw` (raw text with correct MIME), `POST /:owner/:repo/ai/tests/generate` (requireAuth, renders highlighted source + generated failing test, copy button). Stubs are intentionally failing so the author fills them in.
3cbe3d6Claude246- **D9** — Copilot-style completion endpoint → ✅ shipped. `src/lib/ai-completion.ts` + `src/routes/copilot.ts`. `POST /api/copilot/completions` (requireAuth accepts PAT/OAuth/session), `GET /api/copilot/ping`. Claude Haiku; in-memory LRU (size 200, 5-min TTL); code-fence stripping; 60/min rate limit per caller.
9ab6971Claude247
248### BLOCK E — Collaboration parity
1e162a8Claude249- **E1** — Projects / kanban boards → ✅ shipped. `src/routes/projects.tsx`, tables `projects`/`project_columns`/`project_items` (migration 0015). Create creates three default columns (To Do/In Progress/Done); cards carry note or issue/pr link; one-click move between columns; owner-only close.
250- **E2** — Discussions (forum threads per repo) → ✅ shipped. `src/routes/discussions.tsx`, tables `discussions`/`discussion_comments` (migration 0013). Categorised (general/q-and-a/ideas/announcements/show-and-tell), pinnable, lockable, q-and-a answers.
251- **E3** — Wikis → ✅ shipped as DB-backed v1. `src/routes/wikis.tsx`, tables `wiki_pages`/`wiki_revisions` (migration 0016). Slug auto-derived; every edit bumps revision + appends a revision row; owner can revert. Git-backed mirror deferred.
252- **E4** — Gists → ✅ shipped. `src/routes/gists.tsx`, tables `gists`/`gist_files`/`gist_revisions`/`gist_stars` (migration 0014). Multi-file; each edit takes a JSON snapshot into `gist_revisions` keyed on revision number; stars toggle; secret gists hidden from non-owners.
a79a9edClaude253- **E5** — Merge queues → ✅ shipped. `src/lib/merge-queue.ts`, `src/routes/merge-queue.tsx`, table `merge_queue_entries` (migration 0017). Per `(repo, base_branch)` FIFO queue; `POST /:owner/:repo/pulls/:n/enqueue` adds from the PR page; owner-only `POST /queue/process-next` re-runs gates against latest base before merging the head. Entries have queued | running | merged | failed | dequeued states.
254- **E6** — Required status checks matrix → ✅ shipped. `src/routes/required-checks.tsx`, table `branch_required_checks` (migration 0018); helpers `listRequiredChecks` + `passingCheckNames` in `src/lib/branch-protection.ts`. Settings UI at `/:owner/:repo/gates/protection/:id/checks`; merge handler (`src/routes/pulls.tsx`) loads required names + computes passing set from `gate_runs` (passed/repaired) + `workflow_runs` (success) and blocks if any required name is missing.
255- **E7** — Protected tags → ✅ shipped. `src/lib/protected-tags.ts`, `src/routes/protected-tags.tsx`, table `protected_tags` (migration 0019). Settings CRUD at `/:owner/:repo/settings/protected-tags`; patterns use same glob syntax as branch protection. v1 enforcement is advisory: post-receive logs audit entries (`protected_tags.{create|update|delete}_violation_candidate`) so owners can see violations; pre-receive blocking is future work.
9ab6971Claude256
257### BLOCK F — Observability + admin
8f50ed0Claude258- **F1** — Traffic analytics per repo → ✅ shipped. `src/lib/traffic.ts` + `src/routes/traffic.tsx`, table `repo_traffic_events` (migration 0020). `track`/`trackView`/`trackClone`/`trackByName` are fire-and-forget; SHA-256 of IP truncated to 16 chars for unique-visitor approximation. Owner-only `GET /:owner/:repo/traffic` renders 7/14/30/90 day windows with an ascii-bar daily chart. Wired into `src/routes/web.tsx` repo overview + `src/routes/git.ts` git-upload-pack handler.
259- **F2** — Org-wide insights → ✅ shipped. `src/routes/org-insights.tsx` exports `computeOrgInsights(orgId)`. `GET /orgs/:slug/insights` requires org membership; aggregates gate green-rate, open/merged PR counts, open issue count, and per-repo rows sorted by activity. No new tables — live rollup across existing `repositories`, `gate_runs`, `pull_requests`, `issues`.
260- **F3** — Admin / superuser panel → ✅ shipped. `src/lib/admin.ts` + `src/routes/admin.tsx`, tables `site_admins` + `system_flags` (migration 0020). `isSiteAdmin(userId)` with bootstrap rule (empty `site_admins` table → oldest user wins); `KNOWN_FLAGS` = { registration_locked, site_banner_text, site_banner_level, read_only_mode }. Routes: `GET /admin` (dashboard), `GET /admin/users` + toggle grant/revoke, `GET /admin/repos` + nuclear delete, `GET /admin/flags` + save. All mutations audit-logged.
261- **F4** — Billing + quotas → ✅ shipped. `src/lib/billing.ts` + `src/routes/billing.tsx`, tables `billing_plans` + `user_quotas` (migration 0020, seeded with free/pro/team/enterprise). `FALLBACK_PLANS` mirror the seeds so billing works pre-migration. Helpers: `getUserQuota` (auto-initialises free row on first read), `bumpUsage`, `checkQuota` (fail-open), `wouldExceedRepoLimit`, `resetIfCycleExpired`. Routes: `GET /settings/billing` (personal view with usage bars + plan cards), `GET /admin/billing` (site-admin plan override), `POST /admin/billing/:userId/plan`.
9ab6971Claude262
263### BLOCK G — Mobile + client
eae38d1Claude264- **G1** — PWA manifest + service worker → ✅ shipped. `src/routes/pwa.ts` serves `/manifest.webmanifest`, `/sw.js`, `/icon.svg`; `Layout` injects `<link rel="manifest">` + a tiny SW registration script. Service worker is network-first for HTML + skips `.git/`/`/api/`/`/login*` routes.
265- **G2** — GraphQL API mirror of REST → ✅ shipped. `src/lib/graphql.ts` is a dependency-free recursive-descent parser + executor over a fixed schema (viewer, user, repository, search, rateLimit). `src/routes/graphql.ts` serves `POST /api/graphql` + a GraphiQL-lite explorer at `GET /api/graphql`. Queries only; writes stay on REST.
266- **G3** — Official CLI (`gluecron`) → ✅ shipped. `cli/gluecron.ts` is a Bun-compilable single-file CLI. Commands: `login`, `whoami`, `repo ls/show/create`, `issues ls`, `gql`, `host`, `version`. Config in `~/.gluecron/config.json` (0600). Talks to the server via REST + GraphQL.
267- **G4** — VS Code extension → ✅ shipped. `vscode-extension/` contains package.json + `src/extension.ts`. Commands: `gluecron.explainFile`, `gluecron.openOnWeb`, `gluecron.searchSemantic`, `gluecron.generateTests`. Detects Gluecron remotes via `git config remote.origin.url`. Settings: `gluecron.host` + `gluecron.token`.
9ab6971Claude268
71cd5ecClaude269### BLOCK I — Filling parity gaps
270- **I1** — Archive / unarchive repository → ✅ shipped. `src/routes/repo-settings.tsx` archive/unarchive toggle (existing `repositories.is_archived` column). `RepoHeader` surfaces an "Archived" badge.
271- **I2** — Template repositories → ✅ shipped. `drizzle/0022_repo_templates.sql` adds `is_template` column + partial index. `src/routes/templates.ts` serves `POST /:owner/:repo/use-template` (git clone --bare into caller's namespace, fresh `activity_feed` entry). Settings UI gains a "Mark as template" toggle. Public repo page renders a prominent "Use this template" CTA for non-owners.
272- **I3** — Repository transfer → ✅ shipped. `drizzle/0022_repo_templates.sql` adds `repo_transfers` audit table. `src/routes/repo-settings.tsx` `POST /:owner/:repo/settings/transfer` (validate target user exists, reject name conflicts, update `owner_id`, log to `repo_transfers`).
273- **I4** — Generic command palette → ✅ shipped. `src/views/layout.tsx` injects a Cmd+K palette with ~20 canonical destinations (Dashboard, Explore, Notifications, Ask AI, Create repo, Marketplace, Installed apps, Register app, Shortcuts, Settings, 2FA, Passkeys, PATs, Billing, Audit, Gists, GraphQL, Admin, Theme). Fuzzy-match, arrow-key navigation, Esc/backdrop to close.
274
9ab6971Claude275### BLOCK H — Marketplace
06139e6Claude276- **H1** — App marketplace → ✅ shipped. `src/routes/marketplace.tsx` + `src/lib/marketplace.ts` + `drizzle/0021_marketplace_and_apps.sql` (5 tables: `apps`, `app_installations`, `app_bots`, `app_install_tokens`, `app_events`). Routes: `GET /marketplace` (public directory with search), `GET /marketplace/:slug` (detail + install CTA), `POST /marketplace/:slug/install` (user-target install in v1), `POST /marketplace/installations/:id/uninstall`, `GET /settings/apps` (personal list), `GET+POST /developer/apps-new` (register), `GET /developer/apps/:slug/manage` (event log + install count), `POST /developer/apps/:slug/tokens/new` (show-once token). Install idempotent via soft-update on existing non-uninstalled row.
277- **H2** — GitHub Apps equivalent (bot identities + installation tokens) → ✅ shipped. Same schema as H1: every app gets a `<slug>[bot]` row in `app_bots`. `generateBearerToken()` produces `ghi_`-prefixed bearers; `hashBearer` (sha256) is the only form persisted. `verifyInstallToken(token)` returns `{installation, app, botUsername, permissions}` or `null` (checks revoked/expired/uninstalled/suspended). Permission vocabulary: `contents:read/write`, `issues:read/write`, `pulls:read/write`, `checks:read/write`, `deployments:read/write`, `metadata:read` — `hasPermission` implements write→read implication.
9ab6971Claude278
279---
280
281## 4. LOCKED BLOCKS (DO NOT UNDO)
282
283Everything below is committed, tested, and load-bearing. **Do not delete, rename, or semantically change without owner permission.**
284
285### 4.1 Infrastructure (locked)
286- `src/app.tsx` — route composition, middleware order, error handlers
287- `src/index.ts` — Bun server entry
288- `src/lib/config.ts` — env getters (late-binding)
71cd5ecClaude289- `src/db/schema.ts` — 79 tables. New tables only via new migration.
9ab6971Claude290- `src/db/index.ts` — lazy proxy DB connection
291- `src/db/migrate.ts` — migration runner
292- `drizzle/0000_initial.sql`, `drizzle/0001_green_ecosystem.sql` — migrations
058d752Claude293- `drizzle/0004_org_owned_repos.sql` (Block B2) — migration, never edited in place
294- `drizzle/0005_totp_2fa.sql` (Block B4) — migration, never edited in place
295- `drizzle/0006_webauthn_passkeys.sql` (Block B5) — migration, never edited in place
296- `drizzle/0007_oauth_provider.sql` (Block B6) — migration, never edited in place
5e888b7Claude297- `drizzle/0008_workflows.sql` (Block C1) — migration, never edited in place
25a91a6Claude298- `drizzle/0009_packages.sql` (Block C2) — migration, never edited in place
299- `drizzle/0010_pages.sql` (Block C3) — migration, never edited in place
300- `drizzle/0011_environments.sql` (Block C4) — migration, never edited in place
3cbe3d6Claude301- `drizzle/0012_ai_native.sql` (Block D) — migration, never edited in place. Adds `codebase_explanations`, `dep_update_runs`, `code_chunks`.
1e162a8Claude302- `drizzle/0013_discussions.sql` (Block E2) — migration, never edited in place. Adds `discussions`, `discussion_comments`.
303- `drizzle/0014_gists.sql` (Block E4) — migration, never edited in place. Adds `gists`, `gist_files`, `gist_revisions`, `gist_stars`.
304- `drizzle/0015_projects.sql` (Block E1) — migration, never edited in place. Adds `projects`, `project_columns`, `project_items`.
305- `drizzle/0016_wikis.sql` (Block E3) — migration, never edited in place. Adds `wiki_pages`, `wiki_revisions`.
a79a9edClaude306- `drizzle/0017_merge_queue.sql` (Block E5) — migration, never edited in place. Adds `merge_queue_entries` (with partial unique index on `pull_request_id WHERE state IN ('queued','running')`).
307- `drizzle/0018_required_checks.sql` (Block E6) — migration, never edited in place. Adds `branch_required_checks`.
308- `drizzle/0019_protected_tags.sql` (Block E7) — migration, never edited in place. Adds `protected_tags`.
8f50ed0Claude309- `drizzle/0020_analytics_and_admin.sql` (Block F) — migration, never edited in place. Adds `repo_traffic_events`, `system_flags`, `site_admins`, `billing_plans` (seeded free/pro/team/enterprise), `user_quotas`.
06139e6Claude310- `drizzle/0021_marketplace_and_apps.sql` (Block H) — migration, never edited in place. Adds `apps`, `app_installations` (partial unique index on `(app_id, target_type, target_id) WHERE uninstalled_at IS NULL`), `app_bots` (one-per-app, `<slug>[bot]` username), `app_install_tokens` (sha256 hash, expires_at, revoked_at), `app_events` (audit trail).
71cd5ecClaude311- `drizzle/0022_repo_templates.sql` (Block I2+I3) — migration, never edited in place. Adds `repositories.is_template` (partial index where true) + `repo_transfers` audit table.
9ab6971Claude312
313### 4.2 Git layer (locked)
314- `src/git/repository.ts` — tree / blob / commits / diff / branches / blame / search / raw / tags / commitsBetween
315- `src/git/protocol.ts` — Smart HTTP pkt-line
316- `src/hooks/post-receive.ts` — CODEOWNERS sync, gates, auto-deploy, webhook fan-out
317
318### 4.3 Auth + security (locked)
319- `src/lib/auth.ts` — bcrypt, session tokens
25a91a6Claude320- `src/middleware/auth.ts` — softAuth + requireAuth. Accepts three auth inputs: session cookie (web), OAuth access token (`glct_` prefix, Block B6), and personal access token (`glc_` prefix, Block C2). Invalid bearer → 401 JSON. Cookie flow → /login redirect.
9ab6971Claude321- `src/middleware/rate-limit.ts` — fixed-window limiter
322- `src/middleware/request-context.ts` — request-ID
323- `src/lib/security-scan.ts` — `SECRET_PATTERNS` (exported) + `scanForSecrets` + `aiSecurityScan`
058d752Claude324- `src/lib/codeowners.ts` — parser + `ownersForPath` (last-match-wins); team expansion helpers for `@org/team` (Block B3)
325- `src/lib/totp.ts` (Block B4) — TOTP enroll / verify / recovery codes
326- `src/lib/webauthn.ts` (Block B5) — WebAuthn registration + assertion helpers
327- `src/lib/oauth.ts` (Block B6) — OAuth 2.0 provider: authorization code grant, token issuance, scope enforcement
5e888b7Claude328- `src/lib/workflow-parser.ts` (Block C1) — YAML subset parser for `.gluecron/workflows/*.yml`. Exports `parseWorkflow(src)` returning `{ ok, workflow | error }`. Never throws.
329- `src/lib/workflow-runner.ts` (Block C1) — shell executor. Exports `executeRun`, `drainOneRun`, `enqueueRun`, `startWorker`. Clones repo to tmpdir, runs each job via `Bun.spawn(["bash","-c",step.run])` with SIGTERM→SIGKILL timeouts, size-capped stdout/stderr, cleans up in `finally`.
25a91a6Claude330- `src/lib/packages.ts` (Block C2) — npm protocol helpers: `parsePackageName`, `computeShasum` (sha1), `computeIntegrity` (sha512 base64), `buildPackument`, `resolveRepoFromPackageJson`, `parseRepoUrl`, `tarballFilename`. Pure functions.
331- `src/lib/pages.ts` (Block C3) — `onPagesPush` (never throws), `resolvePagesPath` (probe list including pretty URLs + traversal strip), `contentTypeFor` (MIME).
332- `src/lib/environments.ts` (Block C4) — `matchGlob`, `listEnvironments`, `getOrCreateEnvironment`, `getEnvironmentByName`, `isReviewer`, `reviewerIdsOf`, `allowedBranchesOf`, `computeApprovalState`, `reduceApprovalState`, `recordApproval`, `requiresApprovalFor`. Empty reviewers list → repo owner approves. Any rejection hard-stops.
9ab6971Claude333
334### 4.4 AI layer (locked)
335- `src/lib/ai-client.ts` — Anthropic client + model constants
3cbe3d6Claude336- `src/lib/ai-generators.ts` — commit / PR / changelog / issue-triage / **pull-request-triage (D3)**
9ab6971Claude337- `src/lib/ai-chat.ts` — conversational chat
338- `src/lib/ai-review.ts` — PR code review
339- `src/lib/auto-repair.ts` — worktree-backed repair commits
340- `src/lib/merge-resolver.ts` — AI merge conflict resolution
3cbe3d6Claude341- `src/lib/ai-explain.ts` (Block D6) — `explainCodebase(...)` + `getCachedExplanation(...)`. Samples up to ~25 representative files (~60KB cap), Sonnet 4, upserts into `codebase_explanations`. Fallback to README-ish synthesis when no key. Never throws.
342- `src/lib/ai-completion.ts` (Block D9) — `completeCode({prefix, suffix?, language?, maxTokens?, repoHint?})` via Haiku. Inline LRU (size 200, 5-min TTL) keyed on sha256 of prefix+suffix+language. Code-fence stripping. Never throws. `__test` bundle exposed.
343- `src/lib/dep-updater.ts` (Block D2) — `parseManifest`, `queryNpmLatest`, `planUpdates` (injectable `fetchLatest`), `applyBumps`, `runDepUpdateRun`. Creates `gluecron/dep-update-<ts>` branch via git plumbing + opens a PR row. Never throws.
344- `src/lib/semantic-search.ts` (Block D1) — `tokenize`, `hashEmbed` (512-dim L2-normalised FNV-1a + sign trick), `embedBatch` (Voyage `voyage-code-3` when `VOYAGE_API_KEY` set, else fallback), `chunkFile`, `isCodeFile`, `indexRepository`, `searchRepository`, `cosine`, `isEmbeddingsProviderAvailable`, `__test` bundle.
1e162a8Claude345- `src/lib/ai-incident.ts` (Block D4) — `onDeployFailure({deploymentId, reason, logs?})` and pure helper `summariseCommitsForIncident(commits)`. Sonnet 4 structured JSON RCA → opens `issues` row, attaches `incident` label if present, sets `deployments.blockedReason`. Never throws; deterministic fallback body when no API key. Wired from `post-receive.ts triggerCrontechDeploy` + `deployments.tsx retry-incident`.
346- `src/lib/ai-tests.ts` (Block D8) — pure helpers `detectLanguage`, `detectTestFramework`, `buildTestsPrompt`, `suggestedTestPath`, `generateTestStub`, `contentTypeFor`. Returns `{code:"", framework:"fallback"}` on no API key. Never throws.
347- `src/lib/branch-protection.ts` (Block D5) — `matchProtection(repoId, branch)` (exact wins; deterministic glob sort), `evaluateProtection(rule, ctx)` (pure — checks `requireAiApproval | requireGreenGates | requireHumanReview | requiredApprovals`), `countHumanApprovals(prId)` (LGTM/+1/approved heuristic). Never throws. Enforcement is in `src/routes/pulls.tsx` merge handler, after existing hard-gate filter.
9ab6971Claude348
349### 4.5 Platform (locked)
24cf2caClaude350- `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.
351- `src/lib/email.ts` — provider-pluggable email sender (`log`|`resend`). `sendEmail()` never throws. `absoluteUrl()` joins paths against `APP_BASE_URL`.
352- `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.
9ab6971Claude353- `src/lib/unread.ts` — unread count helper (never throws)
354- `src/lib/repo-bootstrap.ts` — green defaults on repo creation
355- `src/lib/gate.ts` — gate orchestration + persistence
356- `src/lib/cache.ts` — LRU cache, git-cache invalidation
6fc53bdClaude357- `src/lib/reactions.ts` — `summariseReactions`, `toggleReaction`, `ALLOWED_EMOJIS`, `EMOJI_GLYPH`, `isAllowedEmoji`, `isAllowedTarget`
9ab6971Claude358
359### 4.6 Routes (locked endpoints — behaviour must be preserved)
360- `src/routes/git.ts` — Smart HTTP (clone/push)
361- `src/routes/api.ts` — REST (`POST /api/repos`, `GET /api/users/:u/repos`, `GET /api/repos/:o/:n`, `POST /api/setup`)
ad6d4adClaude362- `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`.
6fc53bdClaude363- `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.
364- `src/routes/audit.tsx` — `GET /settings/audit` (personal) + `GET /:owner/:repo/settings/audit` (owner-only).
24cf2caClaude365- `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`.
366- `src/routes/deployments.tsx` — `GET /:owner/:repo/deployments` (grouped by env, success-rate rollup), `GET /:owner/:repo/deployments/:id` (detail).
6fc53bdClaude367- `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.
9ab6971Claude368- `src/routes/auth.tsx` — register / login / logout
369- `src/routes/web.tsx` — home / new / browse / blob / commits / raw / blame / star / search / profile
370- `src/routes/issues.tsx` — issue CRUD + comments + labels + lock
371- `src/routes/pulls.tsx` — PR CRUD + review + merge + close
372- `src/routes/editor.tsx` — web file editor
373- `src/routes/compare.tsx` — base...head diff
24cf2caClaude374- `src/routes/settings.tsx` — profile + password + email notification preferences (`POST /settings/notifications`)
9ab6971Claude375- `src/routes/repo-settings.tsx` — repo settings + delete
376- `src/routes/webhooks.tsx` — webhook CRUD + test + `fireWebhooks`
377- `src/routes/fork.ts` — fork
378- `src/routes/explore.tsx` — discover
379- `src/routes/tokens.tsx` — personal access tokens
380- `src/routes/contributors.tsx` — contributor list
381- `src/routes/notifications.tsx` — inbox + unread API
382- `src/routes/dashboard.tsx` — authed home (`renderDashboard` exported)
383- `src/routes/ask.tsx` — global + repo AI chat + explain
384- `src/routes/releases.tsx` — tags + AI changelog
385- `src/routes/gates.tsx` — history + settings + branch protection UI
386- `src/routes/insights.tsx` — insights + milestones
387- `src/routes/search.tsx` — global search + `/shortcuts`
388- `src/routes/health.ts` — `/healthz` `/readyz` `/metrics`
6563f0aClaude389- `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.
058d752Claude390- `src/lib/orgs.ts` (Block B1) — `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.
391- `src/routes/settings-2fa.tsx` (Block B4) — TOTP enroll / verify / disable + recovery codes UI. All require auth.
392- `src/routes/passkeys.tsx` (Block B5) — WebAuthn passkey registration / assertion / management. All require auth.
393- `src/routes/oauth.tsx` (Block B6) — OAuth 2.0 authorize + token + userinfo endpoints.
394- `src/routes/developer-apps.tsx` (Block B6) — developer-facing OAuth app CRUD (`/settings/developer/apps`), client secret rotation, audit-logged.
5e888b7Claude395- `src/routes/workflows.tsx` (Block C1) — Actions UI. `GET /:owner/:repo/actions`, `GET /:owner/:repo/actions/runs/:runId`, `POST /:owner/:repo/actions/:workflowId/run` (auth+owner), `POST /:owner/:repo/actions/runs/:runId/cancel` (auth+owner). Manual runs are `event=manual`, ref=default branch.
25a91a6Claude396- `src/routes/packages-api.ts` (Block C2) — npm protocol: `GET/PUT/DELETE /npm/*` (packument, tarball, publish, yank); JSON helpers at `/api/packages/:owner/:repo/...`. PAT (`glc_`) bearer auth.
397- `src/routes/packages.tsx` (Block C2) — UI: `/:owner/:repo/packages` list + `/:owner/:repo/packages/:pkgName` detail.
398- `src/routes/pages.tsx` (Block C3) — `GET /:owner/:repo/pages/*` serves static files from latest gh-pages commit (binary via `getRawBlob`, text via `getBlob`). `GET/POST /:owner/:repo/settings/pages` settings + redeploy.
399- `src/routes/environments.tsx` (Block C4) — settings CRUD at `/:owner/:repo/settings/environments`; approval endpoints at `/:owner/:repo/deployments/:id/{approve,reject}`.
3cbe3d6Claude400- `src/routes/ai-explain.tsx` (Block D6) — `GET /:owner/:repo/explain` (softAuth), `POST /:owner/:repo/explain/regenerate` (requireAuth, owner-only).
401- `src/routes/ai-changelog.tsx` (Block D7) — `GET /:owner/:repo/ai/changelog` (softAuth). Form + rendered output; `?format=markdown` returns `text/markdown`.
402- `src/routes/copilot.ts` (Block D9) — `POST /api/copilot/completions` (requireAuth, 60/min rate limit), `GET /api/copilot/ping` (public).
403- `src/routes/dep-updater.tsx` (Block D2) — `GET /:owner/:repo/settings/dep-updater` + `POST /:owner/:repo/settings/dep-updater/run` (requireAuth, owner-only).
404- `src/routes/semantic-search.tsx` (Block D1) — `GET /:owner/:repo/search/semantic?q=` (softAuth) + `POST /:owner/:repo/search/semantic/reindex` (requireAuth, owner-only).
1e162a8Claude405- `src/routes/ai-tests.tsx` (Block D8) — `GET /:owner/:repo/ai/tests` (softAuth form + picker), `GET /:owner/:repo/ai/tests?format=raw` (raw text w/ MIME), `POST /:owner/:repo/ai/tests/generate` (requireAuth, renders highlighted source + AI-generated failing test with copy button).
406- `src/routes/discussions.tsx` (Block E2) — full discussion CRUD + categories + q-and-a answers + lock/pin. Exports `isValidCategory(c)` helper. Owner-only lock/pin; owner-or-author can close/toggle.
407- `src/routes/gists.tsx` (Block E4) — `GET /gists` discover, `/gists/new|:slug|:slug/edit|:slug/delete|:slug/star|:slug/revisions|:slug/revisions/:rev` + `/:username/gists`. Exports `generateSlug()` (8-hex) and `snapshotOf(files)` JSON serializer. Retries on slug collision up to 5x.
408- `src/routes/projects.tsx` (Block E1) — kanban board CRUD. Auto-seeds three default columns on project create. `/:owner/:repo/projects/:number/items/:itemId/move` recomputes position via `max+1` of target column.
409- `src/routes/wikis.tsx` (Block E3) — DB-backed wiki with revision history + revert. Exports `slugifyTitle(title)` (lowercase alphanumerics joined by single dashes, trimmed). Every edit appends a `wiki_revisions` row; revert creates a new revision.
a79a9edClaude410- `src/routes/merge-queue.tsx` (Block E5) — `GET /:owner/:repo/queue` list, `POST /:owner/:repo/pulls/:n/enqueue` (requireAuth), `POST /:owner/:repo/queue/:id/dequeue` (owner-or-enqueuer), `POST /:owner/:repo/queue/process-next?base=X` (owner-only, re-runs gates against base then updates base ref). PR page has an extra "Add to merge queue" button.
411- `src/lib/merge-queue.ts` (Block E5) — `enqueuePr`, `dequeueEntry`, `peekHead`, `markHeadRunning`, `completeEntry`, `isQueued`, `queueDepth`, `listQueue`, `listQueueWithPrs`. No side effects beyond the `merge_queue_entries` table; callers own gate execution + git updates.
412- `src/routes/required-checks.tsx` (Block E6) — `/:owner/:repo/gates/protection/:id/checks` CRUD (owner-only, requireAuth). "Required checks" link added on gates settings UI next to each branch protection rule.
413- `src/lib/branch-protection.ts` extends for E6 — `listRequiredChecks(branchProtectionId)`, `passingCheckNames(repositoryId, commitSha)` (scans `gate_runs` + `workflow_runs`), and `evaluateProtection(rule, ctx, requiredChecks[])` now takes a third param + reports `missingChecks`.
414- `src/routes/protected-tags.tsx` (Block E7) — `/:owner/:repo/settings/protected-tags` CRUD (owner-only, requireAuth).
415- `src/lib/protected-tags.ts` (Block E7) — `matchProtectedTag`, `isProtectedTag`, `canBypassProtectedTag`, `listProtectedTags`, `addProtectedTag`, `removeProtectedTag`, `userIdFromUsername`. Matching uses `matchGlob` from environments.ts with `refs/tags/` prefix stripped. Post-receive hook writes audit log entries (`protected_tags.{create|update|delete}_violation_candidate`) on matched pushes.
8f50ed0Claude416- `src/lib/traffic.ts` (Block F1) — `track`, `trackView`, `trackClone`, `trackByName(owner, repo, kind, meta)`, `summarise(repoId, windowDays=14)`, pure `bucketDaily(events)`. SHA-256-truncated IP hashing (16 hex) for unique-visitor approximation. All callers use `.catch(() => {})` fire-and-forget.
417- `src/routes/traffic.tsx` (Block F1) — `GET /:owner/:repo/traffic` (owner-only) with 7/14/30/90d windows, ascii-bar daily chart, top referers, unique visitors.
418- `src/routes/org-insights.tsx` (Block F2) — exports `computeOrgInsights(orgId)` returning `OrgInsightsSummary` (repoCount, gateRunsTotal, greenRate, openIssues, openPrs, mergedPrs30d, perRepo[]). `GET /orgs/:slug/insights` requires org membership. No new tables.
419- `src/lib/admin.ts` (Block F3) — `isSiteAdmin(userId)` with bootstrap rule (empty `site_admins` → oldest user wins), `listSiteAdmins`, `grantSiteAdmin`, `revokeSiteAdmin`, `getFlag`, `setFlag`, `listFlags`, `KNOWN_FLAGS = { registration_locked, site_banner_text, site_banner_level, read_only_mode }`. All helpers swallow DB errors.
420- `src/routes/admin.tsx` (Block F3) — `GET /admin` dashboard (user/repo/admin counts + recent signups), `/admin/users` + toggle grant/revoke, `/admin/repos` + nuclear delete, `/admin/flags` form. All mutations audit-logged via `audit()`. Gated through a `gate(c)` helper that returns `{user} | Response`.
421- `src/lib/billing.ts` (Block F4) — plan + quota helpers. `FALLBACK_PLANS` (free/pro/team/enterprise) mirror the seed rows. `getUserQuota(userId)` auto-initialises free row. `bumpUsage`, `checkQuota` (fail-open), `wouldExceedRepoLimit`, `resetIfCycleExpired`, `formatPrice`. Never throws into request path.
422- `src/routes/billing.tsx` (Block F4) — `GET /settings/billing` (personal view with usage bars + plan cards), `GET /admin/billing` (site-admin user/plan table), `POST /admin/billing/:userId/plan` (override plan, audit-logged).
eae38d1Claude423- `src/routes/pwa.ts` (Block G1) — `/manifest.webmanifest`, `/sw.js`, `/icon.svg`. Exports `MANIFEST`, `SERVICE_WORKER_SRC`, `PWA_REGISTER_SNIPPET` for testing. SW deliberately skips `.git/`, `/api/`, `/login*`, `/register`, `/logout`.
424- `src/lib/graphql.ts` (Block G2) — hand-rolled recursive-descent parser (`parseQuery`) + executor (`execute`) over a fixed schema. Zero dependencies. Root fields: viewer, user, repository, search, rateLimit. No mutations.
425- `src/routes/graphql.ts` (Block G2) — `POST /api/graphql` JSON endpoint + `GET /api/graphql` GraphiQL-lite explorer (Cmd+Enter to run).
426- `cli/gluecron.ts` (Block G3) — single-file Bun CLI. Exports `dispatch(argv, out)` for programmatic use, `HELP` constant, `loadConfig`/`saveConfig`. Config at `~/.gluecron/config.json` (0600). Compile: `bun build cli/gluecron.ts --compile --outfile gluecron`.
427- `vscode-extension/` (Block G4) — VS Code extension with `package.json` declaring four commands (explainFile, openOnWeb, searchSemantic, generateTests) + `gluecron.host` / `gluecron.token` settings. Detects Gluecron remotes via `git config remote.origin.url`.
06139e6Claude428- `src/lib/marketplace.ts` (Block H1+H2) — marketplace + app identity surface. `KNOWN_PERMISSIONS` (10 scopes), `KNOWN_EVENTS` (8 kinds). Pure helpers: `slugify` (40-char cap), `botUsername` (`<slug>[bot]`), `normalisePermissions` (drops unknown, de-dupes), `parsePermissions` (JSON), `hasPermission` (write→read implication), `permissionsSubset`, `generateBearerToken` (`ghi_` prefix + 24-byte hex), `hashBearer` (sha256). DB helpers: `listPublicApps(query)`, `getAppBySlug`, `createApp` (retries slug collisions, creates matching bot row), `installApp` (idempotent soft-update), `uninstallApp` (revokes all tokens), `issueInstallToken` (1h TTL default), `verifyInstallToken` (checks revoked/expired/uninstalled/suspended), `listInstallationsForApp`, `listInstallationsForTarget`, `listEventsForApp`, `countInstalls`. Never throws into request path.
429- `src/routes/marketplace.tsx` (Block H1+H2) — public marketplace + developer UX. `GET /marketplace` (directory + search), `GET /marketplace/:slug` (detail + install form), `POST /marketplace/:slug/install` (v1 user-target only), `POST /marketplace/installations/:id/uninstall` (installer-only), `GET /settings/apps` (personal list), `GET+POST /developer/apps-new` (register), `GET /developer/apps/:slug/manage` (event log + install count, owner-only), `POST /developer/apps/:slug/tokens/new` (show-once `ghi_` token). All mutations audit-logged.
9ab6971Claude430
431### 4.7 Views (locked contracts)
432- `src/views/layout.tsx` — `Layout` accepts `title`, `user`, `notificationCount`
3cbe3d6Claude433- `src/views/components.tsx` — `RepoHeader`, `RepoNav` (active: `code|issues|pulls|commits|releases|actions|gates|insights|explain|changelog|semantic`), `RepoCard`, etc.
6fc53bdClaude434- `src/views/reactions.tsx` — `ReactionsBar` (no-JS compatible, form-per-emoji)
435- Nav links: logo · search · theme-toggle · Explore · Ask · Notifications · New · Profile (or Sign in / Register)
9ab6971Claude436- Keyboard chords: `/`, `Cmd+K`, `?`, `n`, `g d`, `g n`, `g e`, `g a`
437
438### 4.8 Tests (locked)
439- `src/__tests__/green-ecosystem.test.ts` — secret scanner, codeowners, AI fallback, health, rate-limit headers, `/shortcuts`, `/search`
440- All other existing test files — do not delete without owner permission
441
442### 4.9 Invariants (never break these)
443- `isAiAvailable()` guard returns true fallback strings when no ANTHROPIC_API_KEY. AI features degrade gracefully.
444- `getUnreadCount` never throws; returns 0 on any error.
445- Rate-limit middleware adds `X-RateLimit-Limit` + `X-RateLimit-Remaining` to every response, including 500s.
446- `c.header("X-Request-Id", ...)` set by request-context on every response.
447- Secret scanner skips binary/lock paths (`shouldSkipPath`).
448- `SECRET_PATTERNS` is an exported array. Its shape is `{ type, regex, severity }`.
6fc53bdClaude449- Theme routes live outside `/settings/*` (they must work for logged-out visitors). Cookie name: `theme`, values: `dark|light`.
450- Draft PRs cannot be merged — `/pulls/:n/merge` returns a redirect with the draft error when `pr.isDraft=true`.
451- Reactions API accepts only `ALLOWED_EMOJIS` and `ALLOWED_TARGETS`. Toggle is idempotent per (user, target, emoji).
24cf2caClaude452- `sendEmail()` never throws — always resolves to `{ ok, provider, ... }`. Email failures never break notification delivery or the primary request path.
453- 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.
454- Issue + PR template loading must return `null` on any git-subprocess failure (templates are a convenience, not a requirement). Forms always render.
9ab6971Claude455
456---
457
458## 5. OPERATIONAL NOTES
459
460### 5.1 Running locally
461```bash
462bun install
463bun dev # hot reload
71cd5ecClaude464bun test # 549 tests currently pass
9ab6971Claude465bun run db:migrate
466```
467
468### 5.2 Environment
469- `DATABASE_URL` — Neon Postgres
470- `ANTHROPIC_API_KEY` — unlocks AI features
471- `GIT_REPOS_PATH` — default `./repos`
472- `PORT` — default 3000
24cf2caClaude473- `EMAIL_PROVIDER` — `log` (default, stderr-only) or `resend`
474- `EMAIL_FROM` — sender address for outbound mail
475- `RESEND_API_KEY` — required when `EMAIL_PROVIDER=resend`
476- `APP_BASE_URL` — canonical URL used to build absolute links in emails
3cbe3d6Claude477- `VOYAGE_API_KEY` — optional; when set, D1 semantic search uses Voyage `voyage-code-3` embeddings. Otherwise falls back to a deterministic 512-dim hashing embedder.
9ab6971Claude478
479### 5.3 Models
480- `claude-sonnet-4-20250514` — code review, security, chat
481- `claude-haiku-4-5-20251001` — commit messages, summaries, light tasks
482- Swap via `MODEL_SONNET` / `MODEL_HAIKU` constants in `src/lib/ai-client.ts`
483
484### 5.4 Deployment
485- `railway.toml` / `fly.toml` present
486- Crontech deploy on green push to default branch (can opt out via `autoDeployEnabled`)
487
488---
489
490## 6. SESSION WORKFLOW (WHAT THE NEXT AGENT DOES)
491
4921. Read this file, `CLAUDE.md`, `README.md`, `git log -1 --stat`.
4932. Check `git status` + current branch.
4943. Pick the next unfinished block from §3 (lowest letter + number first, unless owner specifies).
4954. Create a todo list that mirrors the sub-items of that block.
4965. Build. Write tests. Run `bun test`.
4976. Commit with `feat(<BLOCK-ID>): ...`.
4987. Push.
4998. Update this file:
500 - Move the block's row in §2 to ✅ where applicable.
501 - Add the block's files to §4 LOCKED BLOCKS.
502 - Commit + push again.
5039. Start the next block. **Do not stop to ask.**
504
505If 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.
506
507---
508
509## 7. IN-FLIGHT
510
511(Intentionally empty. Add here if a block is partially complete at session end.)