|
| 1 | +# AGENTS.md - AI Agent Instructions for SBproxy |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +SBproxy is a reverse proxy and AI gateway written in Go. Single binary, Caddy-style plugin architecture, 18-layer compiled handler chain. |
| 6 | + |
| 7 | +- **Source:** https://github.com/soapbucket/sbproxy |
| 8 | +- **Docs:** https://sbproxy.dev/docs |
| 9 | +- **License:** Apache 2.0 |
| 10 | + |
| 11 | +## Repository Structure |
| 12 | + |
| 13 | +``` |
| 14 | +cmd/sbproxy/ Binary entry point |
| 15 | +pkg/ Public API (plugin interfaces, config types, events) |
| 16 | +internal/ Private implementation |
| 17 | + config/ Config loading, validation, compilation (compiler.go is key) |
| 18 | + engine/ HTTP pipeline (middleware, handlers, transport) |
| 19 | + modules/ Plugin modules (action/, auth/, policy/, transform/) |
| 20 | + middleware/ Per-origin middleware (callback, cors, waf, modifier, etc.) |
| 21 | + ai/ AI gateway (providers, routing, guardrails) |
| 22 | + extension/ Scripting (CEL, Lua, MCP) |
| 23 | + observe/ Logging, metrics, telemetry, events |
| 24 | + loader/ Config lifecycle, feature flags |
| 25 | + platform/ Infrastructure (circuit breaker, DNS, health, messenger) |
| 26 | + request/ Request context (reqctx, session, rate limit) |
| 27 | + security/ Crypto, cert pinning, PII, signatures |
| 28 | + cache/ Response and object caching |
| 29 | + service/ Server lifecycle |
| 30 | +examples/ 16 working config examples (all use test.sbproxy.dev) |
| 31 | +docs/ Architecture, configuration, scripting docs |
| 32 | +``` |
| 33 | + |
| 34 | +## Build and Test |
| 35 | + |
| 36 | +```bash |
| 37 | +go build ./... # build |
| 38 | +go test ./... # test all |
| 39 | +go test ./internal/config/ -count=1 -timeout 120s # config tests |
| 40 | +go test ./internal/modules/... -v # module tests |
| 41 | +go vet ./... # lint |
| 42 | +go test -race ./... -count=1 -timeout 180s # race detector |
| 43 | +``` |
| 44 | + |
| 45 | +## Key Architectural Concepts |
| 46 | + |
| 47 | +### Plugin System |
| 48 | +Modules register via `init()` into `pkg/plugin` registry. Five interfaces: |
| 49 | +- `ActionHandler` - what to do with a request (proxy, redirect, static, AI, etc.) |
| 50 | +- `AuthProvider` - who can access (api_key, jwt, basic_auth, etc.) |
| 51 | +- `PolicyEnforcer` - rules and limits (rate_limit, waf, cel expression, etc.) |
| 52 | +- `TransformHandler` - modify response body (json_projection, html, lua, etc.) |
| 53 | +- `RequestEnricher` - enrich request context (GeoIP, UA parsing - enterprise only) |
| 54 | + |
| 55 | +### Compiled Handler Chain |
| 56 | +`internal/config/compiler.go: CompileOrigin()` builds an 18-layer handler chain per origin. Built inside-out, executes outside-in. Zero per-request allocation. |
| 57 | + |
| 58 | +### Config Format |
| 59 | +YAML config (sb.yml) with `proxy:` (global) and `origins:` (per-hostname) top-level keys. Each origin has sibling fields: `action`, `authentication`, `policies`, `transforms`, `request_modifiers`, `response_modifiers`, `forward_rules`, `response_cache`, `on_request`, `on_response`, `compression`, `cors`, `error_pages`. |
| 60 | + |
| 61 | +**Critical rule:** `authentication`, `policies`, `transforms`, etc. are SIBLINGS of `action`, never nested inside it. |
| 62 | + |
| 63 | +### Header Normalization |
| 64 | +Two systems with different rules: |
| 65 | +- **CEL expressions:** lowercase, hyphens preserved, bracket notation: `request.headers["x-api-key"]` |
| 66 | +- **Mustache templates:** lowercase, hyphens to underscores, dot notation: `{{ request.headers.x_api_key }}` |
| 67 | + |
| 68 | +### Enterprise Boundary |
| 69 | +- OSS code must NEVER import enterprise packages |
| 70 | +- Enterprise code imports only `sbproxy/pkg/*` (never `sbproxy/internal/*`) |
| 71 | +- Enterprise features: canary, shadow, geo-blocking, OAuth, WASM, guardrails, semantic cache |
| 72 | +- Enterprise modules register via the same `plugin.Register*()` pattern |
| 73 | + |
| 74 | +## Code Style |
| 75 | + |
| 76 | +- Standard `gofmt` |
| 77 | +- Explicit `if err != nil` error handling, no panics in production |
| 78 | +- All exported types and functions must have Go doc comments |
| 79 | +- Add logical section comments at decision points, not on every line |
| 80 | +- Use `// --- Section Name ---` dividers in larger files |
| 81 | +- Do NOT use em dashes in any content |
| 82 | +- Do NOT expose internal implementation details in marketing content |
| 83 | +- All documentation files must have `*Last modified: YYYY-MM-DD*` after the title |
| 84 | + |
| 85 | +## When Making Changes |
| 86 | + |
| 87 | +1. Read the existing code before modifying |
| 88 | +2. Follow existing patterns in the package |
| 89 | +3. Run `go build ./...` after every change |
| 90 | +4. Run `go vet ./...` before committing |
| 91 | +5. Run `go test` for affected packages |
| 92 | +6. All examples use test.sbproxy.dev as the backend |
| 93 | +7. Do NOT include enterprise features in OSS code |
| 94 | + |
| 95 | +## Adding a New Module |
| 96 | + |
| 97 | +1. Create package under `internal/modules/{type}/{name}/` |
| 98 | +2. Implement the appropriate `pkg/plugin` interface |
| 99 | +3. Register via `plugin.Register*()` in `init()` |
| 100 | +4. Add blank import to `internal/modules/imports.go` |
| 101 | +5. Write tests |
| 102 | +6. Run full build and test suite |
| 103 | + |
| 104 | +## Important Files |
| 105 | + |
| 106 | +| File | Purpose | |
| 107 | +|---|---| |
| 108 | +| `internal/config/compiler.go` | Origin compilation (18-layer handler chain) | |
| 109 | +| `pkg/plugin/registry.go` | Plugin registration | |
| 110 | +| `pkg/plugin/services.go` | ServiceProvider interface | |
| 111 | +| `pkg/plugin/enricher.go` | RequestEnricher interface | |
| 112 | +| `internal/engine/middleware/middleware.go` | Global middleware chain and origin routing | |
| 113 | +| `internal/modules/imports.go` | Module activation via blank imports | |
| 114 | +| `internal/service/service.go` | Server startup sequence | |
| 115 | +| `internal/request/reqctx/types.go` | RequestData struct | |
| 116 | +| `internal/template/resolver.go` | Template resolution (9-namespace model) | |
0 commit comments