v1.1.0 v1.0.0 · stable roots GA · x/* families carry explicit maturity labels View release posture →

Adoption Decision

Why Plumego

Use this page when the question is whether Plumego fits your team and review expectations — before committing time to the technical details.

Agent-ready

Built for teams using AI coding tools.

This is about AI coding assistants (Claude, Copilot, Cursor) — tools that write or review code. It is not about building AI agent services; for that, see x/ai.

Plumego is the first Go HTTP toolkit designed so those coding assistants know exactly where a change belongs — before writing any code. Machine-readable specs, per-module manifests, and explicit boundary rules give agents the same routing signals a senior reviewer uses.

specs/task-routing.yaml maps work types to owning modules
specs/dependency-rules.yaml prevents agents from crossing stable-root boundaries
AGENTS.md defines the shared protocol for human + AI collaboration
See the interactive routing demo →

Four terms Plumego uses specifically.

These words have precise meanings in this repository — they are not general Go jargon.

Term One-line definition
stable root A module with a long-term API compatibility promise, part of the v1 stable-root surface: core, router, contract, middleware, security, store, health, log, metrics.
x/* family An optional capability module under the x/ directory — experimental unless labeled otherwise. Start from the owning family, not a subordinate primitive.
control plane The docs/, specs/, and tasks/ directories that hold human-readable rules and machine-readable constraints for both humans and AI coding assistants.
canonical path The default service layout defined by reference/standard-service — the one starting point every new service should compare against.

What explicit wiring looks like in review.

The core question before adopting: should route ownership, middleware order, and dependency wiring be visible in code — or managed by the framework? Plumego keeps registration in internal/app/routes.go, where it appears in every code review.

hidden behind registration calls

main.go
func main() {
    mux := http.NewServeMux()

    items.Register(mux)   // paths? middleware?
    users.Register(mux)   // must open each pkg
    orders.Register(mux)  // to find out

    // full route map not visible here
    http.ListenAndServe(addr, mux)
}

plumego: visible in routes.go

internal/app/routes.go
func (a *App) Routes() http.Handler {
    r := router.New()

    r.Use(middleware.RequestID)
    r.Use(middleware.Logger(a.log))

    r.Get("/api/items",  a.items.List)
    r.Get("/api/orders", a.orders.List)
    r.Get("/api/users",  a.users.List)

    // full route map visible here
    return r
}
internal/handler/items.go
// consistent JSON envelope from every handler
_ = contract.WriteResponse(w, r, http.StatusOK, items, nil)
// → {"data": [...], "meta": null}

_ = contract.WriteError(w, r,
    contract.NewErrorBuilder().
        Type(contract.TypeRequired).
        Message("name required").Build())
// → {"error": {"type": "required", ...}}

Fit check before architecture detail.

Plumego is a good match when the adoption question can be answered with visible engineering evidence, not framework enthusiasm.

01

reviewable wiring

route registration, middleware order, and dependencies stay visible in code review

02

shared baseline

new services start from one reference shape instead of custom bootstraps

03

maturity signal

stable roots and experimental families are separated before adoption

04

agent-ready

machine-readable specs, per-module manifests, and standardized check commands give code agents a clear operating model

05

stdlib-first

handler signature is func(w http.ResponseWriter, r *http.Request) — no custom context, all net/http middleware works without adapters

06

zero deps

the stable core imports only the Go standard library — no transitive dependency risk in the kernel layer

adoption-review.md
- route registration stays visible
- middleware order is reviewable
- reference app is the canonical service shape
- release posture limits adoption assumptions
- stdlib handler signature — no adapters needed
- zero external deps in the stable core

Where Plumego is strongest.

Plumego becomes a stronger fit when review clarity, explicit ownership, and one default service shape matter more than framework-managed convenience.

best fit

Internal APIs where reviewers need to trace request flow in code

Choose Plumego when a pull request should let you see which routes are registered, which middleware runs in order, and who owns each dependency — without reading framework source.

  • route registration must be visible in code review
  • handler ownership and middleware order must be explicit
  • the team already works comfortably with net/http

best fit

Platform services where multiple teams share one service skeleton

The framework is strongest when several teams need to start new services from the same reference shape and you want structural drift between repositories to stay low.

  • new services should inherit the same structure as existing ones
  • reviewers want a small set of accepted patterns across the codebase
  • a shared skeleton reduces onboarding cost as teams rotate

best fit

Repositories where you need clear signals about module readiness

Plumego is a strong fit when adoption decisions need to be based on explicit maturity evidence — stable, supported, or experimental — rather than inferred from package presence alone.

  • stable and experimental surfaces must be easy to distinguish
  • teams need to know what can be depended on versus what may still change
  • adoption scope should follow published evidence, not just availability

best fit

Repositories maintained by both human engineers and AI coding agents

Plumego is built for codebases where AI agents share execution and review responsibilities. Four machine-readable control planes — <code>docs/</code>, <code>specs/</code>, <code>tasks/</code>, and <code>reference/</code> — give agents a deterministic operating model: where to classify a task, which files to read first, what a correct change looks like, and which checks must pass before a contribution lands. The same structure that makes human review tractable also makes agent contributions safe to verify.

  • specs/task-routing.yaml maps task intent to owning module before any code is opened
  • specs/change-recipes/ defines ordered steps and stop conditions for 15 common change types
  • each module/module.yaml declares scope, risk, test commands, and review checklist for that package
  • internal/checks/ enforces boundary rules mechanically — the same checks run locally and in CI
  • make gates provides an agent-executable, CI-equivalent validation loop before every push

AI coding tools work more reliably with a machine-readable repository.

This section is about AI coding assistants (Copilot, Claude, Cursor) — tools that write or review code. It is not about building AI agent services; that is the scope of x/ai.

Most teams using these tools today face the same problem: the assistant has to guess where a change belongs. Plumego's control plane gives those tools the same routing signals a senior reviewer uses.

work routing

The agent knows which module owns the change before writing any code

specs/task-routing.yaml maps work types to owning modules. An agent reads the routing table when evaluating a change instead of inferring ownership by guessing directory structure.

boundary enforcement

Import violations are caught by a machine, not by reviewer memory

specs/dependency-rules.yaml and internal/checks/dependency-rules reject PRs that cross stable-root boundaries — whether the change came from a human or an AI tool.

change recipes

Common change types have a defined path, not an open prompt

specs/change-recipes/ gives agents an explicit execution sequence for known change types: new stable module, bug fix, extension promotion, deprecation. Recipes reduce hallucination surface and make agent output reviewable with the same rules as human PRs.

How task routing works in practice

Task description Routing rule Owner
Add rate limiting to inbound HTTP endpoint middleware middleware/
Add per-tenant JWT validation tenant_policy_change x/tenant/
Build AI streaming SSE endpoint extension_work → x/ai x/ai/
Update allowed import directions in specs repo_rules specs/

The full routing table covers 10 task types. The interactive demo on the docs page lets you step through each classification.

Good fit versus caution signals.

This comparison should help you decide, not merely admire the architecture. Use it when you need to know whether Plumego's explicit model actually improves the service in front of you.

Signal Good fit Slow down
Team posture You want a shared service structure before the codebase becomes too wide for one person to hold in mind. You prefer each team to optimize its own service shape without a common reference model.
Code review expectation Reviewers should be able to inspect routes, middleware, and dependency wiring directly in code. Review focuses on business logic and is comfortable letting the framework own structural decisions.
Repository structure You want docs, examples, releases, and roadmap to reinforce one visible adoption model. You are comfortable letting package presence imply maturity without a published module boundary map.

Choose by decision, not by default.

All four toolkits are built on net/http. The differences are philosophy and scope — not performance. Use the table below as a decision aid: each row answers "when should I choose this" and "when should I not."

Toolkit Choose when Pause when
Gin / Echo Your team wants fast setup, a large plugin ecosystem, and is comfortable with custom context types (gin.Context / echo.Context). Existing net/http middleware needs adapters, but the convention-first model is a worthwhile trade. You need handlers to stay as plain func(w, r) and want all existing stdlib middleware to work without wrappers.
Chi You only need routing and want to assemble everything else yourself. Chi is the right choice when you prefer minimal opinions and are happy building your own response envelope, middleware catalog, and security layer. You want a structured response contract, built-in middleware ordering, security helpers, and a canonical service shape out of the box.
Plumego Visible route ownership and review clarity matter more than framework convenience. You want stdlib handler signature (func(w http.ResponseWriter, r *http.Request)), a structured contract layer, and an explicit canonical service shape — without hidden registration. You want the framework to handle structure invisibly, or your team is already comfortable with Gin/Echo and happy with the trade-offs.

router overhead

Measured: 1.4×–4.3× vs stdlib ServeMux — knowable and bounded

Plumego's trie router adds per-request context injection, param map construction, and middleware chain wiring on top of dispatch. Overhead vs Go 1.22+ http.ServeMux ranges from 1.4× for deep param routes to 4.3× for single-param routes — 110–1,036 ns absolute. For typical handlers spending 1 ms–100 ms on I/O, router cost is 0.001%–0.1% of request time. Full benchmark table on Releases →

When to pause before adopting.

Plumego is not meant to win every comparison. If the signals below match your team's goals more closely, the explicit model may add more friction than value right now.

not a fit

Your team is invested in the Gin or Echo plugin ecosystem

Gin and Echo have large middleware catalogs, authentication plugins, and community tooling built around their custom context types. If your team depends on gin.Context or echo.Context — and the ecosystem around it — switching handler signatures imposes real migration cost with no clear upside.

not a fit

You need framework-level ORM, DI container, or auto-wiring

Plumego does not carry database access, dependency injection, or auto-registration. If your team expects the framework to provide or wire these concerns, the explicit DI pattern will feel like unnecessary overhead. Reach for a full application framework instead.

not a fit

The x/* families' maturity risk is a blocker for your organization

The 9 stable roots carry the v1 compatibility promise. The x/* extension families are experimental or beta — their APIs may still change until their own evidence is complete. If your organization requires a fully stable, versioned API across every capability you use, restrict adoption to stable roots and promoted beta surfaces only.

slow down

You want framework conventions to handle structure automatically

If the team mainly wants routing and dependency setup handled invisibly by the framework, Plumego may feel more deliberate than productive.

slow down

Every service is intentionally built with its own custom structure

The more each service must define its own startup, routing, and dependency patterns, the less a shared reference baseline can offer.

What adoption looks like over time.

Plumego is intentionally narrow at entry and explicit about where it expands. Here is what the first three stages of adoption typically involve.

Day 1

Run the canonical reference service in under 5 minutes

terminal
cd reference/standard-service
go run .
# → server started at :8080
# → GET /ping → {"data":{"message":"pong"}}

Clone the repo, run the reference service, read internal/app/routes.go. The full request path is visible without reading any framework source. Start here before evaluating further.

Day 30

Add a capability from x/* without touching stable roots

Once the stable-root baseline is working in your service, the next inflection point is whether you need a capability from the x/* layer — WebSocket, multi-tenancy, AI streaming, or edge proxying. Each x/* family attaches at the transport layer without modifying stable roots. You verify the boundary holds with go run ./internal/checks/dependency-rules.

The specs/task-routing.yaml table tells you which x/* family owns any new capability before you start. The extension layer evolves at its own pace — stable roots stay unchanged.

Day 90 and release evidence

After v1 is tagged, the upgrade path is deterministic

The 9 stable roots carry the v1 compatibility promise. After the v1 tag, the upgrade path for core, router, contract, and the other stable roots is mechanical — no handler signature changes, no breaking response envelope changes.

x/* families that remain experimental after v1 are tracked separately. Their maturity tier is explicit in the release matrix. You adopt only the capabilities that have reached beta or stable — not the whole extension catalog.

Migrating from another framework?

Plumego uses plain func(w http.ResponseWriter, r *http.Request) handlers, so existing stdlib-compatible middleware ports without adapters. The migration guides cover the most common switching paths.

Continue from here.

Fit check done. Go to Architecture to browse x/* capability families and the full layer diagram, or jump straight into implementation.