# AGENTS.md — ForgeBucket AI Agent Guide This file is for AI coding agents (Claude Code, GitHub Copilot, etc.) working in this repository. Read it before making changes. --- ## Mission ForgeBucket is a **unified operating system for software delivery** — not a Git repository viewer with CI attached. The guiding philosophy: > Repositories are runtime systems. The dashboard is a command center. GitOps is first-class. Every feature decision should answer: does this reduce cognitive load? Does this improve operational awareness? Does this improve developer flow? The full product vision lives in [`ai_agent_master_prompt_for_building_modern_git_platform.md`](ai_agent_master_prompt_for_building_modern_git_platform.md). --- ## Architecture Map ``` cmd/forgebucket/ — binary entry point (main.go) internal/ api/ router.go — Chi router, all route definitions (60+ routes) middleware/ — auth.go, csrf.go, rbac.go, audit.go handlers/ — one file per domain area (see Key Files below) domain/ git/ — sanitized git binary wrapper (exec.Command only, no shell) binary.go — Run, Log, Tree, Diff, BlobCat, RevParse, etc. agit.go — AGit ref parsing ci/ — CI/CD execution engine (fully built — Phase 2B) orchestrator.go — NATS-driven DAG orchestrator runner_manager.go — job dispatch with Docker executor executor.go — docker run, log streaming, workspace extraction dag.go — topological sort, ReadyJobs parser.go — .forgebucket/workflows/*.yml parser types.go — WorkflowFile, WorkflowJob, WorkflowStep structs gitops/ — GitOps controller (fully built — Phase 3D) controller.go — NATS subscriptions, startup, periodic ticker drift.go — CheckDrift, handlePush, periodicCheck reconciler.go — TriggerSync, handleDeploymentSucceeded/Failed federation/ — ActivityPub / ForgeFed (DATA LAYER ONLY — Phase 3F stub) models/ — XORM structs + 13 migration files config/ — ENV-driven config, fails fast on missing secrets events/ — NATS EventBus interface + NATSBus + NoOpBus web/ — //go:embed target for the built React SPA frontend/ src/ pages/ — route-level page components components/ — shared UI (AppShell, Sidebar, Header, DiffViewer, etc.) ui/ tokens.ts — SINGLE SOURCE OF TRUTH for all design tokens hooks/ — custom React hooks api/ — typed API client (fetch wrappers) ``` **Middleware chain — this order is fixed, do not reorder:** ``` Logger → RealIP → Recoverer → CORS → CSRF → SessionAuth → AuditLog → Handler ``` --- ## Current Phase Status | Phase | Scope | Status | |-------|-------|--------| | 1 | Auth, Git HTTP, repos, PRs, issues, RBAC, webhooks, LFS, design system | **Complete** | | 2A | NATS event bus, WebSocket hub, audit log | **Complete** | | 2B | CI orchestrator, runner manager, Docker executor, artifact registry | **Complete** | | 2C | Pipeline DAG visualization, dashboard CI upgrade, command palette | **Complete** | | 3A | Environment model + deployment tracking | **Complete** | | 3B | Unified operational timeline | **Complete** | | 3C | Workspaces + secret management (Global → Workspace → Repo → Env) | **Complete** | | 3D | GitOps controller + drift detection + auto-sync | **Complete** | | 3E | Observability (Prometheus endpoint, health checks, sparklines) | **Next** | | 3F | Federation handlers (ActivityPub inbox/outbox) | Planned | | 4 | AI diagnostics, signed artifacts, OCI registry, dep/secret scanning | Planned | The `domain/federation/` directory is an intentional stub — the data model exists but no HTTP handlers should be wired until Phase 3F. --- ## Go Conventions ### Git commands — critical rule Always use `exec.Command("git", arg1, arg2, ...)` with **discrete arguments**. Never build a shell string from user input. ```go // CORRECT cmd := exec.Command("git", "clone", "--bare", repoURL, destPath) // WRONG — never do this cmd := exec.Command("sh", "-c", "git clone "+userInput) ``` This rule is non-negotiable. It prevents command injection. ### Router / handlers - Chi router. Route definitions in `internal/api/router.go`. - One handler file per domain area. Keep handlers thin — business logic belongs in domain packages. - All POST/PUT/DELETE routes require `X-CSRF-Token` header matching the session cookie. The CSRF middleware enforces this, but don't remove it from route definitions. - There is a shared `resolveRepoID(db, w, r)` function in `internal/api/handlers/repo_lookup.go` — use it instead of duplicating repo resolution logic. ### Database - XORM for all DB access. Structs in `internal/models/`. - Migrations are numbered files in `internal/models/migrations/`. Always add a new file; never edit existing ones. Current highest: **013**. - No raw SQL strings built from user input. ### Events - Publish to NATS via `bus.Publish(events.SubjectXxx, payload)` where the subject is a constant from `internal/events/subjects.go`. - Payload types are in `internal/events/types.go` — use them for type-safe unmarshaling in subscribers. - `NoOpBus` silently drops events when `NATS_URL` is unset — the app must work normally without NATS. ### Secrets and config - All secrets come from environment variables via `internal/config/`. - Never hardcode secrets, tokens, or credentials anywhere. - `SESSION_SECRET` ≥ 32 chars. `CSRF_SECRET` = exactly 32 chars. ### Error handling - Return errors up the call stack. Don't swallow them silently. - HTTP handlers use consistent JSON error responses — follow the pattern in `jsonError` / `jsonOK` in `internal/api/handlers/helpers.go`. --- ## TypeScript / React Conventions ### Design tokens — critical rule All spacing, color, and sizing values must come from `frontend/src/ui/tokens.ts`. Do not introduce new hardcoded pixel values or color hex codes. ```tsx // CORRECT — use token classes via Tailwind
// WRONG — arbitrary values
``` ### Grid system - Base unit: 8px. All spacing is multiples of 4px (`xs`) or 8px (`sm`). - Touch targets: 44px minimum height/width on all interactive elements (buttons, links, icon buttons). ### Dark mode - Use Tailwind v4 `@variant dark` — not hardcoded `dark:` classes unless inside a component that explicitly handles both. - Colors must work in both light and dark modes. Test both. ### Component patterns - `AppShell` wraps all authenticated pages. Don't bypass it. - `Sidebar` has three states: expanded (320px), collapsed (56px), mobile bottom bar. Respect all three. - Mobile-first: design for 375px, enhance for 1440px. Use the `BottomTabBar` for mobile nav — don't add new nav patterns. - Loading states: use `Skeleton` components for perceived performance, not spinners. - Mobile code review: use the `MobileComment` bottom-sheet pattern — not modals. ### API calls - Use the typed API client in `frontend/src/api/` — don't write raw `fetch` calls in components. - Always include `X-CSRF-Token` header on mutating requests (the client does this automatically via `getCSRFToken()`). --- ## What NOT to Do - **No shell string injection** — see Go conventions above; always discrete `exec.Command` args - **No hardcoded secrets** — everything via env - **No skipping CSRF** — all mutating routes require it - **No arbitrary design values** — `tokens.ts` is the law - **No new color tokens without discussion** — the existing palette covers all cases - **No modal-heavy UX** — progressive disclosure; avoid deep modal chains - **No YAML-centric UI** — pipeline and GitOps config should feel operational, not config-file editing - **No editing existing migration files** — always add a new numbered migration - **No direct `fmt.Println` for logging** — use `log.Printf` so structured logs work correctly --- ## Testing ```bash make test # Go tests (go test ./...) + Vitest (frontend unit tests) make lint # go vet + ESLint ``` - Go: test files live alongside source files (`*_test.go`) - Frontend: Vitest for unit tests, component tests alongside components - All UI changes must be manually verified at 1440px desktop and 375px mobile --- ## Key Files Reference | File | Purpose | |------|---------| | `internal/api/router.go` | All route definitions — start here for backend work | | `internal/api/handlers/repo_lookup.go` | Shared `resolveRepoID` helper | | `internal/models/` | All XORM models + 13 migration files | | `internal/config/config.go` | All env vars, fail-fast validation | | `internal/events/subjects.go` | All NATS event subject constants | | `internal/events/types.go` | Typed event payload structs | | `internal/domain/git/binary.go` | Git binary wrapper — safe exec patterns, `RevParse`, `BlobCat`, etc. | | `internal/domain/ci/orchestrator.go` | CI DAG orchestrator | | `internal/domain/ci/executor.go` | Docker job executor + log streaming | | `internal/domain/gitops/controller.go` | GitOps reconciliation controller | | `internal/domain/gitops/drift.go` | `CheckDrift`, drift detection logic | | `internal/api/handlers/environment.go` | Environment + deployment CRUD | | `internal/api/handlers/gitops.go` | GitOps config + drift HTTP endpoints | | `internal/api/handlers/secret.go` | Scoped secret management | | `internal/api/handlers/workspace.go` | Workspace + member management | | `internal/api/middleware/audit.go` | Audit log middleware | | `frontend/src/ui/tokens.ts` | Design token source of truth | | `frontend/src/components/AppShell.tsx` | Root layout wrapper | | `frontend/src/api/client.ts` | Typed API client with CSRF handling | | `.env.example` | All environment variables with documentation | | `CLAUDE.md` | Developer guide (rules overlap with this file — CLAUDE.md takes precedence on conflicts) | --- ## Running Locally ```bash cp .env.example .env # fill SESSION_SECRET and CSRF_SECRET make docker-up # PostgreSQL + NATS via Docker Compose make migrate # run XORM migrations (currently 013) make dev # Go :8080 + Vite :5173 ``` CI execution requires Docker to be running locally. If unavailable, the runner logs a warning and CI jobs are queued but not executed.