maestro

command module
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 1 Imported by: 0

README

maestro

maestro

CI

Maestro is a CLI tool that scaffolds scalable Go microservice projects. It follows an opinionated design pattern - go.work, per-service go.mod, Dockerfiles, docker-compose, hot reload, secrets, databases, and Taskfiles. Managing growing projects in Go can be tough, but with a single task up command you can get it up and running immediately.

Unlike a one-shot generator, maestro reconciles: project.toml is the source of truth, and maestro refresh brings every generated file back in line on demand - without clobbering your edits.

Built on top of the project.toml philosophy: one workspace, many services under it, each in its own module, all reconciled from a single project.toml

What it does

  • Bootstraps a workspace with go.work, a shared common/go module with handy starter code, dev and prod compose files, Dockerfiles, Air hot-reload, .gitignore, and a root Taskfile.

  • Generates services in four shapes (bare, http, grpc, worker), each with its own cmd/, internals, Taskfile, and (optionally) sqlc/goose wiring for Postgres or SQLite — in Docker or against a live URL.

  • Refreshes the project state via refresh — change project.toml, run one command, and all generated files (compose, Taskfile, go.mod replace directives) catch up. User edits are preserved.

  • Stays out of your secrets. Doppler is the only built-in provider. Maestro writes doppler.yaml and reads via doppler secrets download. It never creates projects or pushes secrets.

Install

The quickest path is go install. Prebuilt binaries are on the releases page for machines without a Go toolchain.

From a release

Download a prebuilt binary straight from the releases page, or fetch it with gh:

Linux / macOS

gh release download --repo Zagforge-Org/maestro \
    --pattern '*Linux_x86_64.tar.gz'              # or *Darwin_arm64.tar.gz, etc.
tar xzf maestro_*.tar.gz
sudo mv maestro /usr/local/bin/
maestro version

Windows (PowerShell)

gh release download --repo Zagforge-Org/maestro --pattern '*Windows_x86_64.zip'
Expand-Archive maestro_*.zip -DestinationPath .
# Drop maestro.exe somewhere on PATH (create the dir + add to PATH if needed):
Move-Item maestro.exe "$Env:LOCALAPPDATA\Programs\maestro\maestro.exe"
maestro version

Available archives per release: Linux_x86_64, Linux_arm64, Darwin_x86_64, Darwin_arm64, Windows_x86_64, Windows_arm64.

From source

Requires a Go toolchain:

go install github.com/Zagforge-Org/maestro@latest

Quickstart

mkdir my-project && cd my-project
maestro init              # interactive: name, repo owner, optional Doppler project
maestro service api       # interactive: shape (bare/http/grpc/worker), optional DB
task api:dev                  # hot-reloaded local dev for that one service
task up                       # bring every service up via docker-compose

To check that all required tools are installed:

maestro doctor

Non-interactive mode

Both init and service launch a TUI wizard by default. Pass -y (or --yes) and the flag values become the source of truth - handy for CI, setup scripts, and reproducible playbooks.

# Scaffold a project without touching the wizard
maestro init -y \
  --name my-project \
  --repo-owner yourname \
  --doppler-project my-project \
  --ci --license

# Generate an HTTP service with Postgres in Docker
maestro service api -y --shape http --db postgres

# Generate a worker that talks to an existing Postgres (the URL is pinged, not stored)
maestro service ingest -y \
  --shape worker --db postgres --db-mode live \
  --db-url "postgres://user:pass@host:5432/dbname"

Required with -y: --name and --repo-owner for init; --shape for service. Everything else has a sensible default - port auto-assigns to the next free slot in the shape's range, --db defaults to none, --db-mode defaults to docker. Live URLs are pinged before scaffolding; a failed ping is a hard error.

Commands

Command Purpose
maestro init Scaffold a new workspace (interactive wizard).
maestro service <name> Generate a new service (interactive shape + DB picker).
maestro preset apply <preset> <service> Scaffold a curated feature (e.g. auth-jwt, api-gateway) and deposit its reusable libs into common/go. See docs/PRESETS.md.
maestro preset list List the available presets.
maestro secrets keygen Print a dev ES256 keypair + app secrets to load into a provider or .secrets/.
maestro refresh Reconcile generated files with project.toml. Preserves user edits.
maestro rename <old> <new> Rename a service across the workspace — directory, module path, sibling imports, Dockerfiles, Air configs, project.toml, go.work. Reverse with maestro rename <new> <old>.
maestro delete <name> Remove a service — its directory, its go.work entry, its compose entries, its project.toml section.
maestro doctor Verify that git, task, go, docker, air (and sqlc/goose/buf when relevant) are on PATH.

What gets generated

After maestro init + maestro service api --shape=http:

my-project/
├── project.toml            # source of truth for `refresh`
├── go.work                 # multi-module workspace
├── docker-compose.yaml     # prod compose, regenerated by refresh
├── docker-compose.dev.yaml # dev compose with bind-mounts + Air
├── Taskfile.yaml           # root Taskfile, regenerated by refresh
├── Taskfile.local.yaml     # optional, user-owned, never touched
├── .gitignore              # includes .secrets/, tmp/, etc.
├── common/go/              # shared module — imports resolve here under Docker too
└── api/
    ├── cmd/api/main.go
    ├── internal/server/    # Gin + zap, /health + /ready
    ├── docker/
    │   ├── dev.Dockerfile
    │   └── prod.Dockerfile
    ├── go.mod              # with replace ../common/go
    └── Taskfile.yaml       # api:dev, api:up, api:down, api:proto:generate, …

Add --shape=grpc and you also get buf.yaml, buf.gen.yaml, and proto/<ident>/v1/<ident>.proto in a layout that satisfies buf lint (PACKAGE_DIRECTORY_MATCH).

Add a database and you also get sqlc.yaml, internal/db/ (with a hand-authored conn.go exposing db.Open(ctx, url); sqlc's generated code lands alongside it as db.go + models.go + queries.sql.go when you run task <svc>:generate), internal/migrate/, and - if you chose Docker mode - a <name>-db sidecar with a managed DATABASE_URL in the compose env.

The DB workflow is migrate-first: sqlc reads its schema from internal/migrate/, so the cycle is task <svc>:migrate:create -- <name> → write your CREATE TABLE … into the generated file → task <svc>:migrate:up → write queries into internal/db/queries.sqltask <svc>:generate. Writing a query against a table that has no migration is the most common cause of a confusing sqlc generate error.

Every file in a scaffolded project falls into one of three categories - managed (regenerated by refresh), user-owned (scaffolded once, then yours), or project.toml (the source of truth you edit by hand). The full inventory lives in docs/MANAGED_FILES.md.

Service shapes

Shape Generated
bare cmd/<svc>/main.go printing "Hello".
http Gin server with /health, /ready, structured request logging via zap, graceful shutdown.
grpc grpc.NewServer() with health + reflection, buf-managed proto layout, signal-driven GracefulStop.
worker Long-running loop over ctx.Done() + ticker, exits cleanly on SIGINT/SIGTERM.

All shapes use zap.NewProduction() with ReplaceGlobals so libraries can log via zap.L().

Presets

Shapes are empty skeletons; presets are working features scaffolded on top. Applying one (maestro preset apply <preset> <service>) generates the feature's services and deposits the reusable libraries it's built from into your common/go, so you build your own services on those building blocks rather than being locked into the preset's code.

Preset What it scaffolds
auth-jwt JWT auth service — email-OTP verify, password , MFA, MFA-gated staff roles with RBAC, refresh rotation — plus a cleanup worker.
api-gateway Stateless edge — reverse proxy, edge JWT validation, signed gateway-to-service identity via internalauth, Redis rate limiting, CORS, API versioning.

The end-to-end walkthrough — standing up auth behind the gateway, running it out of the box, and writing your own service that reads the gateway-injected caller via the identity lib — is in docs/PRESETS.md.

Configuration: project.toml

[project]
  name = "my-project"
  repo_owner = "yourname"

[dev]
  containerized = true   # generate Dockerfiles + compose entries
  hot_reload = true      # generate .air.toml + Air step in dev compose

[secrets]
  provider = "doppler"   # or omit / "none"
  doppler_project = "my-project"

[service]
  [service.api]
    shape = "http"
    db = "postgres"
    db_mode = "docker"
  [service.worker]
    shape = "worker"

Edit it, run maestro refresh, and every managed file catches up. The wizards write this file for you; or you can also edit it by hand.

Requirements

maestro doctor will tell you what's missing. The full set:

  • Required: Git, Task, Go, Docker, Air
  • For DB services: sqlc, goose
  • For gRPC services: buf

Status

Pre-1.0 and MIT licensed. The core flow (init → service → refresh → up) is solid and covered by both unit tests and end-to-end smoke tests (go test -tags=e2e ./...), including a refresh-idempotency invariant that fails if a second refresh against a freshly-scaffolded project produces any diff at all. Per-service Dockerfiles are scaffolded once and treated as user-owned thereafter - refresh warns when they no longer reflect [dev] hot_reload or [service.<name>] db but never rewrites them; regenerating is maestro delete <svc> && maestro service <svc>. maestro rename is its own inverse - a partial run is reversed by running it backwards. Pieces still on the roadmap:

  • Partial-failure rollback in service if a downstream step bombs mid-scaffold

License

MIT — see LICENSE. Copyright © 2026 Anze and Zagforge.

Documentation

Overview

Copyright © 2026 Anze and Zagforge <forgezag@gmail.com> All rights reserved. See LICENSE.

Directories

Path Synopsis
internal
preset
Package preset loads and applies curated scaffolds ("presets") on top of an existing maestro project.
Package preset loads and applies curated scaffolds ("presets") on top of an existing maestro project.
preset/presets/api-gateway/main/internal/auth
Package auth verifies the access tokens where the gateway upstream services are behind.
Package auth verifies the access tokens where the gateway upstream services are behind.
preset/presets/api-gateway/main/internal/gateway
Package gateway is the reverse-proxy core of api gateway preset which routes inbound requests to upstream services by longest-matching path prefix.
Package gateway is the reverse-proxy core of api gateway preset which routes inbound requests to upstream services by longest-matching path prefix.
preset/presets/api-gateway/main/internal/server
Package server wires the api-gateway: request logging, local health probes, and the reverse proxy as the catch-all for everything else.
Package server wires the api-gateway: request logging, local health probes, and the reverse proxy as the catch-all for everything else.
preset/presets/auth-jwt/cleanup/internal/worker
Package worker is the cleanup target for the auth-jwt preset.
Package worker is the cleanup target for the auth-jwt preset.
preset/presets/auth-jwt/main/internal/auth
Authenticated symmetric encryption for the auth-jwt preset.
Authenticated symmetric encryption for the auth-jwt preset.
preset/presets/auth-jwt/main/internal/db
Package db owns the database connection for this service.
Package db owns the database connection for this service.
preset/presets/auth-jwt/main/internal/email
Package email builds the typed mailer.Message values the auth service sends.
Package email builds the typed mailer.Message values the auth service sends.
preset/presets/auth-jwt/main/internal/requests
Package requests holds the typed JSON bodies every auth route expects, with go-playground/validator constraints declared inline via Gin's `binding:` tags.
Package requests holds the typed JSON bodies every auth route expects, with go-playground/validator constraints declared inline via Gin's `binding:` tags.
preset/presets/auth-jwt/main/internal/responses
Package responses holds the typed JSON bodies the auth routes return on success.
Package responses holds the typed JSON bodies the auth routes return on success.
preset/presets/auth-jwt/main/internal/routes
Always-on base of the auth-jwt preset's API.
Always-on base of the auth-jwt preset's API.
preset/presets/auth-jwt/main/internal/server
Package server wires the auth-jwt service: opens the database, builds the auth service container (JWT + OTP configs + sqlc queries), attaches middleware + base routes, and registers the feature routes collected in internal/routes.
Package server wires the auth-jwt service: opens the database, builds the auth service container (JWT + OTP configs + sqlc queries), attaches middleware + base routes, and registers the feature routes collected in internal/routes.
preset/presets/auth-jwt/main/internal/services
Always-on auth services for the auth-jwt preset: refresh and logout, used by every sign-in method.
Always-on auth services for the auth-jwt preset: refresh and logout, used by every sign-in method.
scaffold/ciworkflow
Package ciworkflow scaffolds a starter GitHub Actions pipeline at `.github/workflows/ci.yml`.
Package ciworkflow scaffolds a starter GitHub Actions pipeline at `.github/workflows/ci.yml`.
scaffold/commongo
Package commongo embeds the per-language seed packages dropped into every new maestro project under <project>/common/go/.
Package commongo embeds the per-language seed packages dropped into every new maestro project under <project>/common/go/.
scaffold/commongo/envx
Package envx contains small environment-variable helpers used by service main packages.
Package envx contains small environment-variable helpers used by service main packages.
scaffold/commongo/errs
Package errs defines the project's typed error envelope.
Package errs defines the project's typed error envelope.
scaffold/commongo/ginx
Bearer-token authentication middleware for Gin-based services.
Bearer-token authentication middleware for Gin-based services.
scaffold/commongo/grpcx
Package grpcx wraps the gRPC-server boilerplate every gRPC service main would otherwise duplicate: bind a listener, Serve in a goroutine, wait for ctx to cancel, then GracefulStop.
Package grpcx wraps the gRPC-server boilerplate every gRPC service main would otherwise duplicate: bind a listener, Serve in a goroutine, wait for ctx to cancel, then GracefulStop.
scaffold/commongo/httpx
Package httpx wraps the HTTP-server boilerplate every service main would otherwise duplicate: build an http.Server, run ListenAndServe in a goroutine, wait for ctx to cancel, then Shutdown within a deadline.
Package httpx wraps the HTTP-server boilerplate every service main would otherwise duplicate: build an http.Server, run ListenAndServe in a goroutine, wait for ctx to cancel, then Shutdown within a deadline.
scaffold/commongo/identity
Package identity reads the trusted caller an api-gateway injects, so a service behind the gateway can know who's calling without re-validating a token or importing any auth machinery.
Package identity reads the trusted caller an api-gateway injects, so a service behind the gateway can know who's calling without re-validating a token or importing any auth machinery.
scaffold/commongo/ids
Package ids hosts typed wrappers for cross-service entity IDs.
Package ids hosts typed wrappers for cross-service entity IDs.
scaffold/commongo/internalauth
Package internalauth is the gateway <-> service identity assertion: the gateway mints a short-lived ES256 token asserting the verified caller, and services verify it with the gateway's PUBLIC key before trusting that identity.
Package internalauth is the gateway <-> service identity assertion: the gateway mints a short-lived ES256 token asserting the verified caller, and services verify it with the gateway's PUBLIC key before trusting that identity.
scaffold/commongo/jwtx
Package jwtx is the shared token contract for an asymmetric JWT scheme.
Package jwtx is the shared token contract for an asymmetric JWT scheme.
scaffold/commongo/logger
Package logger builds the project's standard zap logger.
Package logger builds the project's standard zap logger.
scaffold/commongo/mailer
Env-driven factory for the mailer.
Env-driven factory for the mailer.
scaffold/commongo/proxyx
Package proxyx is a small reverse-proxy engine for an edge service: it builds an httputil.ReverseProxy to a single upstream that strips a leading API-version segment, forwards X-Forwarded-* headers, and maps upstream failures to clean gateway status codes.
Package proxyx is a small reverse-proxy engine for an edge service: it builds an httputil.ReverseProxy to a single upstream that strips a leading API-version segment, forwards X-Forwarded-* headers, and maps upstream failures to clean gateway status codes.
scaffold/commongo/ratelimitx
Package ratelimitx is a distributed request limiter built on a Redis token bucket, with a circuit-breaker-guarded in-memory fallback.
Package ratelimitx is a distributed request limiter built on a Redis token bucket, with a circuit-breaker-guarded in-memory fallback.
scaffold/commongo/rdb
Package rdb is the shared Redis connector: it parses a REDIS_URL into a go-redis client.
Package rdb is the shared Redis connector: it parses a REDIS_URL into a go-redis client.
scaffold/database
Package database scaffolds the per-service files needed to use sqlc and goose: sqlc.yaml, a starter queries.sql, an empty migrations directory and a minimal connection helper at internal/db/conn.go (kept out of db.go so sqlc's generator does not overwrite it on `task generate`).
Package database scaffolds the per-service files needed to use sqlc and goose: sqlc.yaml, a starter queries.sql, an empty migrations directory and a minimal connection helper at internal/db/conn.go (kept out of db.go so sqlc's generator does not overwrite it on `task generate`).
scaffold/devsecrets
Package devsecrets seeds local development secrets for projects that don't use a secrets provider (provider = "none").
Package devsecrets seeds local development secrets for projects that don't use a secrets provider (provider = "none").
scaffold/doppler
Package doppler scaffolds the per-service doppler.yaml repo config that pins each service to its Doppler project and config.
Package doppler scaffolds the per-service doppler.yaml repo config that pins each service to its Doppler project and config.
scaffold/editorconfig
Package editorconfig scaffolds the project-root .editorconfig.
Package editorconfig scaffolds the project-root .editorconfig.
scaffold/gitignore
Package gitignore scaffolds the project's .gitignore — most importantly the .secrets/ exclusion, so secrets fetched from Doppler are never committed.
Package gitignore scaffolds the project's .gitignore — most importantly the .secrets/ exclusion, so secrets fetched from Doppler are never committed.
scaffold/golangci
Package golangci scaffolds the project-root .golangci.yml — the configuration golangci-lint v2 reads when teams run `task lint`.
Package golangci scaffolds the project-root .golangci.yml — the configuration golangci-lint v2 reads when teams run `task lint`.
scaffold/gomod
Package gomod keeps Go module paths in step with the project's identity.
Package gomod keeps Go module paths in step with the project's identity.
scaffold/license
Package license scaffolds the project-root LICENSE file.
Package license scaffolds the project-root LICENSE file.
scaffold/projectreadme
Package projectreadme scaffolds the per-project README.md at the workspace root.
Package projectreadme scaffolds the per-project README.md at the workspace root.
scaffold/servicetemplate
Package servicetemplate writes the starter source files for a new service: the entrypoint at cmd/<svc>/main.go and any helper packages that match the chosen shape (HTTP server, gRPC server, worker loop).
Package servicetemplate writes the starter source files for a new service: the entrypoint at cmd/<svc>/main.go and any helper packages that match the chosen shape (HTTP server, gRPC server, worker loop).
scaffold/servicetemplate/templates
Package templates embeds the service-shape templates the servicetemplate scaffolder renders.
Package templates embeds the service-shape templates the servicetemplate scaffolder renders.
scaffold/taskfile
Package taskfile scaffolds the project's Task runner files: a per-service Taskfile.yaml and the root Taskfile.yaml that includes them.
Package taskfile scaffolds the project's Task runner files: a per-service Taskfile.yaml and the root Taskfile.yaml that includes them.
tui/dbwizard
Package dbwizard is the interactive picker that runs when `maestro service <name>` is called.
Package dbwizard is the interactive picker that runs when `maestro service <name>` is called.
tui/presetwizard
Package presetwizard is the interactive TUI for `maestro preset`.
Package presetwizard is the interactive TUI for `maestro preset`.
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL