项目文件夹

文件
Asim Aslam d3c4981326
goreleaser / goreleaser (push) Has been cancelled
Enhance AI service generation with prompt-based architecture and logic (#2926)
* feat: add micro new --prompt and micro run --prompt

Add AI-powered service generation: describe a system in natural
language and get real go-micro services with proto definitions,
handlers, doc comments, and MCP support.

micro new --prompt "a contact book with notes and tags" \
  --provider anthropic

Generates:
  contacts/ — CRUD service with name, email, phone fields
  notes/    — notes linked to contacts
  tags/     — tagging system

Each service gets:
  proto/{name}.proto   — domain model + CRUD endpoints
  handler/{name}.go    — in-memory store, @example tags for MCP
  main.go              — MCP-enabled, proper imports
  go.mod + Makefile     — compiles with go mod tidy + make proto

micro run --prompt does the same then starts all services.

The LLM designs the architecture (service names, fields, endpoints,
descriptions) and returns structured JSON. Code generation uses
the existing template patterns — the output is standard go-micro
code that compiles, runs, and is immediately callable via MCP
and micro chat. No AI dependency at runtime.

* feat: LLM generates real business logic with compile-fix loop

Rebuild the generate package so the LLM writes actual handler
code with business logic, not just CRUD scaffolding.

The flow is now:
1. LLM designs architecture (service names, fields, endpoints)
   → returns structured JSON
2. Proto, main.go, go.mod, Makefile generated deterministically
   from the design (guaranteed to be correct)
3. go mod tidy + make proto compiles the protos
4. LLM generates handler code with REAL business logic
   → given the proto, endpoint descriptions, and go-micro patterns
5. go build — does it compile?
6. If no: feed errors back to LLM, get fixed code (up to 3 attempts)
7. If yes: service is ready

The handler prompt instructs the LLM to:
- Use sync.RWMutex for thread-safe in-memory state
- Include validation, edge cases, meaningful errors
- Write doc comments with @example tags for MCP
- Implement actual domain logic, not just map operations

Proto generation still uses deterministic templates (CRUD +
custom endpoints from the design spec) to guarantee correctness.
The compile-fix loop catches LLM mistakes automatically.

Both micro new --prompt and micro run --prompt use this flow.

* fix: handle edge cases in prompt-based generation

- Fix PATH for protoc-gen-micro in child processes
- Handle existing directories: skip structural files (main.go,
  go.mod, Makefile) if dir exists, always regenerate proto,
  only write placeholder handler if none exists
- Allow re-running micro new --prompt on same directory to
  iterate on business logic without clobbering user edits

Tested end-to-end: "a simple todo list with tasks and categories"
generates 2 services (task-service, category-service) with real
business logic (validation, toggle complete, etc.), compiles
after 1 fix iteration, and runs with 6 MCP tools discovered.

* feat: auto-detect modified handlers on regeneration

Instead of requiring a --keep-handlers flag, the generate package now
tracks a SHA-256 hash of each generated handler in a .micro metadata
file. On re-run, if the user has edited the handler since generation,
it's left untouched. Unmodified handlers are regenerated normally.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: add tests, fix go.mod, gitignore, proto tracking, spinner

- Add 12 tests covering helpers, proto generation, hash tracking
- Fix go.mod: write minimal module file, let go mod tidy resolve deps
- Add .gitignore to prompt-generated services
- Protect user-edited proto files (same hash tracking as handlers)
- Add spinner during LLM calls so it doesn't look hung

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: signal handling, existing service discovery, help text

- Ctrl+C during generation now cancels LLM calls immediately via
  signal-aware context; re-run picks up where it left off
- Design() scans for existing services in the working directory and
  includes their proto definitions in the prompt, so the LLM extends
  the system rather than redesigning from scratch
- Updated --prompt help text with usage examples on both new and run
- Listed all supported providers in flag descriptions
- Added discoverExisting test

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: show endpoints in run --prompt output, add micro chat hint

Print endpoint names and descriptions when designing services so users
see what was built. Add a micro chat hint to the run banner so users
know how to interact with their services after startup.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* fix: generated go.mod uses go 1.24 with explicit go-micro require

go 1.22 with no explicit require caused Go to resolve sub-packages
(gateway/mcp, client, server) as separate modules, hitting stale v1.18
tags. Pin to go 1.24 + require go-micro.dev/v5 v5.24.0 so go mod tidy
resolves all sub-packages from the root module correctly.

Tested end-to-end: 4 services generated and compiled successfully.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* fix: skip handler regeneration when proto unchanged

Compare proto hash before and after structure generation. If the proto
didn't change and the handler wasn't edited by the user, skip go mod
tidy, make proto, LLM handler generation, and compile-fix entirely.
Prints "(unchanged)" instead.

Reduces re-run of 4-service project from ~2 minutes to ~10 seconds.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: confirm design before generating code

Show the service design (names, endpoints) and prompt "Generate? [Y/n]"
before spending LLM time on handler generation. Applies to both
micro new --prompt and micro run --prompt. Default is yes (enter).

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* fix: use port :0 for MCP in generated multi-service projects

Each generated service had mcp.WithMCP(":3001") hardcoded, causing
port conflicts when running multiple services. Use :0 to auto-assign
a free port. micro run's central gateway handles unified MCP access.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: truncation detection, tool result display in chat

- Detect truncated LLM responses (unbalanced braces, doesn't end
  with '}') and retry with a conciseness hint before falling through
  to compile-fix
- Show tool call results in micro chat output (← for success, ✗ for
  errors) so users can see what the LLM did
- Add Result/Error fields to ToolCall, populated by Anthropic provider
  after tool execution
- Add isTruncated tests

Tested end-to-end with Anthropic: services generate, compile, start,
register, respond to RPC calls, and micro chat discovers and calls
tools correctly.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* fix: Anthropic tool loop, service naming, chat tool results

Anthropic provider:
- Fix tool execution loop to properly iterate (was re-processing all
  tool calls instead of only new ones each round)
- Clean assistant content blocks before sending back (strip 'id' from
  text blocks that Anthropic rejects on input)
- Include tools in follow-up requests so model can make additional calls
- Loop up to 10 rounds until model responds with text only

Service naming:
- Strip '-service' suffix from micro.New() name so services register
  as 'task', 'category' instead of 'taskservice', 'categoryservice'

Chat:
- Show tool results (← for success) and errors (✗) in chat output

Tested end-to-end: create task → list tasks works as multi-step
orchestration through micro chat with Anthropic Claude.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: blog post 13 — from prompt to production

Covers the full micro run --prompt flow: design, generate, compile-fix,
run, and chat orchestration. Positions agent-as-orchestrator as the
answer to service coordination.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* fix: timeouts, max_tokens, TTY detection, smaller services

- Add 60s timeout on design, 90s on handler generation, 60s on
  compile-fix LLM calls so hung providers don't block forever
- Bump Anthropic max_tokens from 4096 to 8192 to reduce truncation
- Add TTY detection: spinner prints static message in non-TTY (CI/pipes)
  instead of ANSI escape codes
- Tighten prompts: max 200 lines per handler, 2-4 services, 5-8 fields,
  explicit "services don't call each other" rule

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: chat suggests creating services when capabilities are missing

Update system prompt with the list of available services. When the user
asks for something no existing service can handle, the agent explains
what's available and suggests the exact micro new --prompt command to
create the missing service.

This is the natural evolution path: start with a few services, talk to
them via chat, and when the domain grows, the agent tells you what to
add. Each service stays small and focused.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: chat generates and starts services inline, drop -service suffix

Chat agent now has a micro_generate_service tool. When the user asks
for a capability that doesn't exist, the agent generates the service,
compiles it, starts it as a background process, waits for registration,
re-discovers tools, and uses the new endpoints immediately — all within
the conversation.

Service naming: design prompt now instructs LLM to return names without
'-service' suffix (e.g. 'task' not 'task-service'). buildMain keeps
TrimSuffix as safety net for backward compatibility.

Spawned processes are cleaned up when chat exits.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* docs: rewrite blog post 13 with inline service generation

Updated to reflect the full UX: services generate and start within
the chat conversation. Added the shipping example showing the agent
creating a service mid-conversation. Removed -service suffix from
all examples. Tightened the narrative around agent-as-orchestrator.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

* feat: persistent storage, README quickstart, auto-detect new services

Storage: generated handlers now use go-micro's store package instead
of in-memory maps. Data persists across restarts. The handler prompt
includes store API examples so the LLM generates correct store usage.

README: added "Generate From a Prompt" section with micro run --prompt
and micro chat examples, linking to blog post 13.

Watcher: micro run now scans for new service directories every 5s. When
micro chat generates a service, micro run detects the new directory,
builds it, starts it, and adds it to the watcher — fully automatic.
Added AddDir/Dirs methods to the watcher.

Blog: updated post 13 with persistent storage example and watcher note.

https://claude.ai/code/session_01QTp4SshuVmLAvvEGJe4TJd

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-03 20:31:01 +01:00
..
2026-05-30 14:52:22 +01:00

Micro

Go Micro Command Line

Install the CLI

Install micro via go install

go install go-micro.dev/v5/cmd/micro@v5.16.0

Create a service

Create your service (all setup is now automatic!):

micro new helloworld

Or use a template for common service patterns:

micro new contacts --template crud      # CRUD with Create/Read/Update/Delete/List
micro new events --template pubsub      # Pub/sub with broker integration
micro new gateway --template api        # API gateway with health check

This will:

  • Create a new service in the helloworld directory
  • Automatically run go mod tidy and make proto for you
  • Show the updated project tree including generated files
  • Warn you if protoc is not installed, with install instructions

Run the service

Run your service:

micro run

This starts:

Open http://localhost:8080 to see your services and call them from the browser.

Output

  ┌─────────────────────────────────────────────────────────────┐
  │                                                             │
  │   Micro                                                     │
  │                                                             │
  │   Web:     http://localhost:8080                            │
  │   API:     http://localhost:8080/api/{service}/{method}     │
  │   Health:  http://localhost:8080/health                     │
  │                                                             │
  │   Services:                                                 │
  │     ● helloworld                                            │
  │                                                             │
  │   Watching for changes...                                   │
  │                                                             │
  └─────────────────────────────────────────────────────────────┘

Options

micro run                    # Gateway on :8080, hot reload enabled
micro run --address :3000    # Gateway on custom port
micro run --no-gateway       # Services only, no HTTP gateway
micro run --no-watch         # Disable hot reload
micro run --env production   # Use production environment
micro run github.com/micro/blog  # Clone and run from GitHub

Calling Services

Via curl:

curl -X POST http://localhost:8080/api/helloworld/Helloworld.Call -d '{"name": "World"}'

Or browse to http://localhost:8080 and use the web interface.

List services:

micro services

Configuration (micro.mu)

For multi-service projects, create a micro.mu file to define services, dependencies, and environments:

service users
    path ./users
    port 8081

service posts
    path ./posts
    port 8082
    depends users

service web
    path ./web
    port 8089
    depends users posts

env development
    STORE_ADDRESS file://./data
    DEBUG true

env production
    STORE_ADDRESS postgres://localhost/db

Configuration Options

Property Description
path Directory containing the service (with main.go)
port Port the service listens on (for health checks)
depends Services that must start first (space-separated)

Environment Management

Environment variables are injected based on the --env flag:

micro run                    # Uses 'development' env (default)
micro run --env production   # Uses 'production' env
MICRO_ENV=staging micro run  # Uses 'staging' env

JSON Alternative

You can also use micro.json if you prefer:

{
  "services": {
    "users": { "path": "./users", "port": 8081 },
    "posts": { "path": "./posts", "port": 8082, "depends": ["users"] }
  },
  "env": {
    "development": { "STORE_ADDRESS": "file://./data" }
  }
}

Without Configuration

If no micro.mu or micro.json exists, micro run discovers all main.go files and runs them (original behavior).

Describe the service

Describe the service to see available endpoints

micro describe helloworld

Output

{
    "name": "helloworld",
    "version": "latest",
    "metadata": null,
    "endpoints": [
        {
            "request": {
                "name": "Request",
                "type": "Request",
                "values": [
                    {
                        "name": "name",
                        "type": "string",
                        "values": null
                    }
                ]
            },
            "response": {
                "name": "Response",
                "type": "Response",
                "values": [
                    {
                        "name": "msg",
                        "type": "string",
                        "values": null
                    }
                ]
            },
            "metadata": {},
            "name": "Helloworld.Call"
        },
        {
            "request": {
                "name": "Context",
                "type": "Context",
                "values": null
            },
            "response": {
                "name": "Stream",
                "type": "Stream",
                "values": null
            },
            "metadata": {
                "stream": "true"
            },
            "name": "Helloworld.Stream"
        }
    ],
    "nodes": [
        {
            "metadata": {
                "broker": "http",
                "protocol": "mucp",
                "registry": "mdns",
                "server": "mucp",
                "transport": "http"
            },
            "id": "helloworld-31e55be7-ac83-4810-89c8-a6192fb3ae83",
            "address": "127.0.0.1:39963"
        }
    ]
}

Call the service

Call via RPC endpoint

micro call helloworld Helloworld.Call '{"name": "Asim"}'

Create a client

Create a client to call the service

package main

import (
        "context"
        "fmt"

        "go-micro.dev/v5"
)

type Request struct {
        Name string
}

type Response struct {
        Message string
}

func main() {
        client := micro.New("helloworld").Client()

        req := client.NewRequest("helloworld", "Helloworld.Call", &Request{Name: "John"})

        var rsp Response

        err := client.Call(context.TODO(), req, &rsp)
        if err != nil {
                fmt.Println(err)
                return
        }

        fmt.Println(rsp.Message)
}

Building and Deployment

Build Binaries

Build Go binaries for deployment:

micro build                     # Build for current OS
micro build --os linux          # Cross-compile for Linux
micro build --os linux --arch arm64  # For ARM64
micro build --output ./dist     # Custom output directory

Deploy to Server

Deploy to any Linux server with systemd:

# First time: set up the server
ssh user@server
curl -fsSL https://go-micro.dev/install.sh | sh
sudo micro init --server
exit

# Deploy from your laptop
micro deploy user@server

The deploy command:

  1. Builds binaries for linux/amd64
  2. Copies via SSH to /opt/micro/bin/
  3. Sets up systemd services (micro@<service>)
  4. Restarts and verifies services are running

Named Deploy Targets

Add deploy targets to micro.mu:

deploy prod
    ssh deploy@prod.example.com

deploy staging
    ssh deploy@staging.example.com

Then:

micro deploy prod      # Deploy to production
micro deploy staging   # Deploy to staging

Managing Deployed Services

# Check status
micro status --remote user@server

# View logs
micro logs --remote user@server
micro logs myservice --remote user@server -f

# Stop a service
micro stop myservice --remote user@server

See internal/website/docs/deployment.md for the full deployment guide.

API Gateway

Run a standalone HTTP-to-RPC gateway (no dashboard, no auth, no hot reload):

micro api                    # listen on :8080
micro api --address :3000    # custom port

Routes:

  • POST /{service}/{endpoint} — proxies to an RPC call
  • GET / — lists all services and endpoints
  • GET /{service} — describes a service
  • GET /health — health check
curl -XPOST -d '{"name":"Alice"}' http://localhost:8080/greeter/Greeter.Hello

Inspecting the Framework

Every core interface has a matching CLI command:

Registry

micro registry list              # list all registered services (JSON)
micro registry get <name>        # show nodes and endpoints for a service
micro registry watch             # stream registration events

Broker

micro broker publish <topic> <message>   # publish a message
micro broker subscribe <topic>           # stream messages from a topic

Store

micro store list [prefix]        # list keys (optionally by prefix)
micro store read <key>           # read a record
micro store write <key> <value>  # write a record
micro store delete <key>         # delete a record

Config

micro config get <key>           # read a config value (dot notation → env var)
micro config dump                # print all configuration

Keys use dot notation: database.host reads from DATABASE_HOST.

AI & Agents

micro chat

Interactive LLM agent that discovers services and orchestrates them through natural language:

ANTHROPIC_API_KEY=sk-ant-... micro chat --provider anthropic
> list all users
> send a welcome email to Alice

Supports: --provider (anthropic, openai, gemini, atlascloud, groq, mistral, together), --prompt for single-shot mode, --model and --base_url for overrides.

Environment variables: MICRO_AI_PROVIDER, MICRO_AI_API_KEY, or provider-specific keys like ANTHROPIC_API_KEY.

micro flow

Event-driven LLM orchestration:

# Subscribe to events and react
micro flow run --trigger events.user.created \
  --prompt "New user: {{.Data}}. Send welcome email." \
  --provider anthropic

# One-shot execution
micro flow exec --prompt "List all users" --provider anthropic

micro mcp

Expose services as MCP tools for AI agents:

micro mcp serve              # stdio transport (for Claude Code)
micro mcp serve --address :3000  # HTTP/SSE transport
micro mcp list               # list available tools
micro mcp test <tool>        # test a tool

Protobuf

Use protobuf for code generation with protoc-gen-micro

Server

The micro server is a production web dashboard and authenticated API gateway for interacting with services that are already running (e.g., managed by systemd via micro deploy). It does not build, run, or watch services — for local development, use micro run instead.

Run it like so

micro server

Then browse to localhost:8080 and log in with the default admin account (admin/micro).

API Endpoints

The API provides a fixed HTTP entrypoint for calling services

curl http://localhost:8080/api/helloworld/Helloworld/Call -d '{"name": "John"}'

See /api for more details and documentation for each service

Web Dashboard

The web dashboard provides a modern, secure UI for managing and exploring your Micro services. Major features include:

  • Dynamic Service & Endpoint Forms: Browse all registered services and endpoints. For each endpoint, a dynamic form is generated for easy testing and exploration.
  • API Documentation: The /api page lists all available services and endpoints, with request/response schemas and a sidebar for quick navigation. A documentation banner explains authentication requirements.
  • JWT Authentication: All login and token management uses a custom JWT utility. Passwords are securely stored with bcrypt. All /api/x endpoints and authenticated pages require an Authorization: Bearer <token> header (or micro_token cookie as fallback).
  • Token Management: The /auth/tokens page allows you to generate, view (obfuscated), and copy JWT tokens. Tokens are stored and can be revoked. When a user is deleted, all their tokens are revoked immediately.
  • User Management: The /auth/users page allows you to create, list, and delete users. Passwords are never shown or stored in plaintext.
  • Token Revocation: JWT tokens are stored and checked for revocation on every request. Revoked or deleted tokens are immediately invalidated.
  • Security: All protected endpoints use consistent authentication logic. Unauthorized or revoked tokens receive a 401 error. All sensitive actions require authentication.
  • Logs & Status: View service logs and status (PID, uptime, etc) directly from the dashboard.

To get started, run:

micro server

Then browse to localhost:8080 and log in with the default admin account (admin/micro).

Note: See the /api page for details on API authentication and how to generate tokens for use with the HTTP API

Gateway Architecture

The micro run and micro server commands both use a unified gateway implementation (cmd/micro/server/gateway.go), providing consistent HTTP-to-RPC translation, service discovery, and web UI capabilities.

Key Differences

Feature micro run micro server
Purpose Development Production
Authentication Enabled (default admin/micro) Enabled (default admin/micro)
Process Management Yes (builds/runs services) No (assumes services running)
Hot Reload Yes (watches files) No
Scopes Available (/auth/scopes) Available (/auth/scopes)
Use Case Local development Deployed API gateway

Why Unified?

Previously, each command had its own gateway implementation, leading to code duplication. The unified gateway means:

  • New features (like MCP integration) benefit both commands
  • Consistent behavior between development and production
  • Single codebase to test and maintain
  • Same HTTP API, web UI, and service discovery logic

Gateway Features

Both commands provide:

  • HTTP API: POST /api/{service}/{endpoint} with JSON request/response
  • Service Discovery: Automatic detection via registry (mdns/consul/etcd)
  • Health Checks: /health, /health/live, /health/ready endpoints
  • Web Dashboard: Browse services, test endpoints, view documentation
  • Hot Service Updates: Gateway automatically picks up new service registrations
  • JWT Authentication: Tokens, user management, login at /auth/login, /auth/tokens, /auth/users
  • Endpoint Scopes: Restrict which tokens can call which endpoints via /auth/scopes
  • MCP Integration: AI tools at /mcp/tools, agent playground at /agent

Authentication & Scopes

Both micro run and micro server use the same auth.Account type from the go-micro framework. The gateway stores accounts under auth/<id> in the default store and uses JWT tokens with RSA256 signing.

Scope enforcement applies to all call paths:

Path Description
POST /api/{service}/{endpoint} HTTP API calls
POST /mcp/call MCP tool invocations
Agent playground Tool calls made by the AI agent

Scopes are configured via the web UI at /auth/scopes. Each endpoint can require one or more scopes. A token must carry at least one matching scope to call a protected endpoint. The * scope on a token bypasses all checks. Endpoints with no scopes set are open to any authenticated token.

See the Scopes section below for details.

Development Mode (micro run)

micro run  # Auth enabled, default admin/micro
  • Authentication enabled with default credentials (admin/micro)
  • Web UI requires login
  • Scopes available for testing access control
  • Ideal for development with realistic auth behavior

Production Mode (micro server)

micro server  # Auth enabled, JWT tokens required
  • JWT authentication on all API calls
  • User/token management via web UI
  • Secure by default
  • Login required: default credentials admin/micro

Programmatic Gateway Usage

You can also start the gateway programmatically in your own Go code:

import "go-micro.dev/v5/cmd/micro/server"

// Start gateway with auth (recommended)
gw, err := server.StartGateway(server.GatewayOptions{
    Address:     ":8080",
    AuthEnabled: true,
})

// Start gateway without auth (testing only)
gw, err := server.StartGateway(server.GatewayOptions{
    Address:     ":8080",
    AuthEnabled: false,
})

See internal/website/docs/architecture/adr-010-unified-gateway.md for architecture details.

Scopes

Scopes provide fine-grained access control over which tokens can call which service endpoints. They are managed through the web UI at /auth/scopes and enforced on every call through the gateway.

How It Works

  1. Define scopes on endpoints — Visit /auth/scopes and set required scopes for each service endpoint (e.g., set billing on payments.Payments.Charge)
  2. Create tokens with scopes — Visit /auth/tokens and create tokens with matching scopes (e.g., a token with billing scope)
  3. Scopes are enforced — When a token calls an endpoint, the gateway checks that the token has at least one scope matching the endpoint's required scopes

Scope Matching Rules

  • Scopes are exact string matchesbilling on a token matches billing on an endpoint
  • A token with * scope bypasses all scope checks (admin wildcard)
  • Endpoints with no scopes set are open to any valid token
  • An endpoint can require multiple scopes — the token needs to match just one
  • Scope names are free-form strings — use whatever convention fits your project

Common Patterns

Pattern Endpoint Scopes Token Scopes Result
Protect a service Set greeter on all greeter endpoints (use Bulk Set with greeter.*) Token with greeter Token can call any greeter endpoint
Restrict an endpoint Set billing on payments.Payments.Charge Token with billing Only that endpoint is restricted
Role-based Set admin on sensitive endpoints Admin token with admin, user token with user Only admin tokens can call sensitive endpoints
Full access Any Token with * Bypasses all scope checks

Relationship to Framework Auth

The gateway's scope system uses auth.Account from the go-micro framework. Scopes on accounts are the same []string field used by the framework's auth.Rules and wrapper/auth package. The gateway stores scope requirements in the default store under endpoint-scopes/<service>.<endpoint> keys and checks them on every HTTP request.

For service-level (RPC) auth within the go-micro mesh, use the wrapper/auth package which provides auth.Rules with priority-based access control. See the auth wrapper documentation for details.