10 KiB
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.
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.
// 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-Tokenheader 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 ininternal/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 frominternal/events/subjects.go. - Payload types are in
internal/events/types.go— use them for type-safe unmarshaling in subscribers. NoOpBussilently drops events whenNATS_URLis 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/jsonOKininternal/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.
// CORRECT — use token classes via Tailwind
<div className="p-sm gap-xs">
// WRONG — arbitrary values
<div style={{ padding: "12px" }}>
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 hardcodeddark:classes unless inside a component that explicitly handles both. - Colors must work in both light and dark modes. Test both.
Component patterns
AppShellwraps all authenticated pages. Don't bypass it.Sidebarhas three states: expanded (320px), collapsed (56px), mobile bottom bar. Respect all three.- Mobile-first: design for 375px, enhance for 1440px. Use the
BottomTabBarfor mobile nav — don't add new nav patterns. - Loading states: use
Skeletoncomponents for perceived performance, not spinners. - Mobile code review: use the
MobileCommentbottom-sheet pattern — not modals.
API calls
- Use the typed API client in
frontend/src/api/— don't write rawfetchcalls in components. - Always include
X-CSRF-Tokenheader on mutating requests (the client does this automatically viagetCSRFToken()).
What NOT to Do
- No shell string injection — see Go conventions above; always discrete
exec.Commandargs - No hardcoded secrets — everything via env
- No skipping CSRF — all mutating routes require it
- No arbitrary design values —
tokens.tsis 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.Printlnfor logging — uselog.Printfso structured logs work correctly
Testing
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
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.