# GoFr — guide for AI coding assistants For Claude Code, Cursor, Aider, Codex, etc. Hand [https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your assistant when working on a GoFr project. It points at the specific docs you'll actually need rather than inlining everything. GoFr is an opinionated Go framework for microservices. Apache 2.0. Requires Go 1.26+. Repo: . ## Core rules an assistant must know 1. **One handler signature** for HTTP / gRPC / GraphQL / WebSocket / cron / CLI: `func(c *gofr.Context) (any, error)`. Return value → `{"data": ...}`. Return error → error response. 2. **Path params use `{name}`**, not `:name`. `app.GET("/users/{id}", h)`. 3. **`c.PathParam("id")`** for path; **`c.Param("q")`** for query; **`c.Bind(&v)`** for body. 4. **Don't manually wire OpenTelemetry, Prometheus, or structured logging.** `gofr.New()` does it. 5. **Pass `*gofr.Context`** (not `context.Background()`) to every downstream call so trace propagation and cancellation work. 6. **Configuration comes from `configs/.env`** via `c.Config.Get(key)`. No hardcoded ports / hosts / secrets. 7. **No ORM bundled.** Use plain SQL via `c.SQL`, or pair with `sqlc`/`gorm` yourself. 8. **Middleware is standard `net/http`**: `func(http.Handler) http.Handler`, registered with `app.UseMiddleware(...)`. 9. **Health is auto-exposed** at `/.well-known/health` and `/.well-known/alive`. Don't hand-roll `/healthz`. 10. **Don't `panic()` for control flow.** Return errors. ## Minimal app ```go package main import "gofr.dev/pkg/gofr" func main() { app := gofr.New() app.GET("/hello", func(c *gofr.Context) (any, error) { return "Hello, world", nil }) app.Run() } ``` ## Migrations (schema + seed data, versioned) GoFr has a built-in migration runner — use it instead of `golang-migrate` / `goose`. Works for SQL, Redis, Mongo, Cassandra, ClickHouse, DGraph, SurrealDB. **Before writing a migration, fetch the full reference:** . Runnable shape: . Five rules to keep in your head so you don't have to re-fetch on every change: 1. Files live in `migrations/_.go`. Versions are `int64`, monotonic. Use `date +%s` for new ones. 2. `migrations/all.go` exports `All() map[int64]migration.Migrate`. Wire with `a.Migrate(migrations.All())` once in `main.go`. 3. Each migration is `migration.Migrate{ UP: func(d migration.Datasource) error { ... } }`. Inside `UP`, act on `d.SQL`, `d.Redis`, `d.MongoDB`, `d.Cassandra`, `d.Clickhouse`, `d.DGraph`, `d.SurrealDB`, `d.Logger`. 4. Each migration runs **exactly once** per environment — don't add idempotent guards. There is **no down migration**; rollback = new forward migration. 5. One purpose per file. Don't combine "create table + backfill + drop column" in one `UP`. ## AI features: LLMs and MCP GoFr ships LLM and agent support. Use it instead of importing a provider SDK or hand-rolling HTTP, tracing and metrics around model calls. **Before writing this code, fetch the full guides:** and . Runnable shape: . Rules to keep in your head so you don't have to re-fetch on every change: 1. **Register a model once** with `app.AddLLM(&llm.Client{Provider: llm.Groq, Model: "..."})` (`gofr.dev/pkg/gofr/ai/llm`). Providers: `llm.OpenAI`, `llm.Groq`, `llm.DeepSeek`, `llm.Together`, `llm.Ollama`; set `BaseURL` for any other OpenAI-compatible endpoint. Or skip the call and set `LLM_PROVIDER`, `LLM_MODEL` and `LLM_API_KEY` (optional `LLM_BASE_URL`) in `configs/.env`. 2. **Never hardcode the API key.** It comes from `LLM_API_KEY`, then the provider's own variable (`OPENAI_API_KEY`, `GROQ_API_KEY`, ...). 3. **Call the model through `c.LLM()`**: `Generate`, `Chat`, `Stream`, `Embed`. It is already traced and metered. Extra models: `app.AddLLM(m, gofr.WithName("fast"))`, used as `c.LLM("fast")`. Not every provider supports every method; handle `ai.ErrEmbedNotSupported` / `ai.ErrStreamNotSupported` as ordinary errors. 4. **Stream tokens** by returning `response.Stream{Source: stream}` from the handler (`gofr.dev/pkg/gofr/http/response`). 5. **Expose handlers to agents with `app.EnableMCP()`.** It serves the *read-only* handlers (`GET`, `HEAD`, `OPTIONS`, `QUERY`) as MCP tools. `POST`/`PUT`/`PATCH`/`DELETE` are never exposed. Hide a route with `gofr.WithExcludedRoutes("/internal/{id}")`. 6. **MCP binds to loopback on `MCP_PORT` (default `8200`).** `MCP_PORT=0` turns the transport off but keeps tools available in-process. A port that cannot be claimed fails startup. `8200` is also Vault's default port. 7. **Build agent loops in your own handler** with `c.LLM().Tools()` (`List`, `Call`, `Only`). GoFr has no built-in agent loop; turns, stopping conditions and memory stay in your code. ```go package main import ( "gofr.dev/pkg/gofr" "gofr.dev/pkg/gofr/ai/llm" ) func main() { app := gofr.New() app.AddLLM(&llm.Client{Provider: llm.Groq, Model: "llama-3.3-70b-versatile"}) app.EnableMCP() // exposes the GET handlers below to MCP clients app.GET("/products/{id}", func(c *gofr.Context) (any, error) { return map[string]any{"id": c.PathParam("id")}, nil }) app.POST("/summarize", func(c *gofr.Context) (any, error) { var in struct { Text string `json:"text"` } if err := c.Bind(&in); err != nil { return nil, err } return c.LLM().Generate(c, "Summarize the following:\n"+in.Text) }) app.Run() } ``` ## Where to look (fetch only what you need) Each link is a self-contained doc page. Fetch lazily. - Quick start: - Configuration: - Routing + REST handlers: - Context reference (the central abstraction): - Configs reference (every env var): - Testing patterns + mocks: - Observability (auto-wired): - Custom OTel spans: - Custom Prometheus metrics: - Datasources index (MySQL, Postgres, Mongo, Redis, Cassandra, ClickHouse, etc.): - Pub/Sub (Kafka, NATS, GCP, MQTT, SQS, Azure): - gRPC: - GraphQL: - WebSockets: - Cron: - Service-to-service HTTP w/ circuit breaker: - Auth (Basic / API key / OAuth-JWT): - RBAC (config-driven): - Migrations (SQL + NoSQL, versioned): - File storage (local / S3 / GCS / Azure / FTP / SFTP): - Startup hooks: - Errors: - Custom DB drivers: - Calling LLMs (`app.AddLLM`, `c.LLM()`, env config, multiple models, embeddings): - MCP server and agent loops (`app.EnableMCP`, `c.LLM().Tools()`): - Streaming responses (SSE / NDJSON, `response.Stream`): ## Migrating to GoFr Each migration page has the full mapping table for that source framework — fetch only the one that matches: - From Gin: - From Fiber: - From Echo: handler shape similar to Gin; see - From Chi: see - From Express (Node.js): - From Flask (Python): - From Spring Boot (Java): ## Other entry points - Examples (runnable projects): - Full docs index: - Concatenated full docs (one plaintext file): - Curated link index: - Changelog: