Stdlib-first building blocks
core and core-ui are small Go packages, each usable on its own — no framework required. When you want more, the framework composes them for you.
Router
Built on net/http. Make a router and register routes with path patterns — the same shapes as the standard library.
r := router.New()r.Get("/", render.HTMLHandler(func(req *http.Request) render.HTML { return render.Tag("h1", nil, render.Text("Hello from core."))}))http.ListenAndServe(":8080", r)
Typed handlers
A handler that takes a typed input struct and returns a typed output struct. HandlerAdapter does the JSON binding, panic recovery, and response encoding for you.
type Pong struct{ Status string }r.Get("/api/ping", handler.HandlerAdapter( func(ctx context.Context, _ struct{}) (Pong, error) { return Pong{Status: "ok"}, nil }))
Render HTML from Go
Return HTML from a Go function. The html primitives map one-to-one to tags, and render.Text escapes text for you — no template language.
render.HTMLHandler(func(req *http.Request) render.HTML { return html.Div(html.DivConfig{Class: "card"}, html.Heading(html.HeadingConfig{Level: 2}, render.Text("Every doc · A–Z")), )})
Schema
Describe a field once — name, type, required, unique, enum values, default. The same []schema.Field drives the table, the validation, and the API.
Fields: []schema.Field{ {Name: "title", Type: schema.String, Required: true}, {Name: "status", Type: schema.Enum, Values: []string{"draft", "published"}, Default: "draft"},}
MCP server
The MCP server is a core package too — not something only entities produce. Register a tool with a name, a JSON schema, and a Go function.
s := mcp.NewServer()s.RegisterTool("greet", "Say hello", map[string]any{ "type": "object", "properties": map[string]any{"name": map[string]any{"type": "string"}},}, func(ctx context.Context, p map[string]any) (any, error) { return "hello " + p["name"].(string), nil})
Client store
Typed client state, declared in Go and namespaced so two features don't collide. This is the same store the interactivity signals read from.
company := store.New("org").String("company", "Acme Corp")cart := store.New("cart")count := cart.Int("count", 0)