gokart

package module
v0.10.3 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 10 Imported by: 0

README

GoKart

GoKart logo

GoKart is a modular toolkit for building Go CLIs and services with practical defaults.

go install github.com/dotcommander/gokart/cmd/gokart@v0.10.2
gokart new myapp --db sqlite --example
cd myapp
go run ./cmd greet --name World

Use @latest instead only if you intentionally want the newest published version rather than a reproducible install.

The generated project is regular Go code built on Cobra and the integrations you select. Keep using GoKart's helpers, customize the generated code, or use the underlying libraries directly.

What GoKart provides

  • A project generator for structured CLI applications and single-file tools.
  • Focused packages for configuration, CLI output, HTTP services, databases, migrations, Redis, logging, files, and OpenAI.
  • Safe integration updates with dry runs, generated-file manifests, and conflict detection.
  • Independently importable Go modules for each component. Ordinary Go module transitive dependencies still apply.

Packages

  • gokart — typed configuration and JSON state persistence with Viper and the standard library.
  • gokart/cli — app building, styled output, tables, spinners, and editor integration with Cobra and Lip Gloss.
  • gokart/web — router setup, graceful serving, responses, validation, CSRF, pagination, health checks, and rate limiting with chi, templ, and validator.
  • gokart/postgres — PostgreSQL pool setup and transaction helpers with pgx/v5.
  • gokart/sqlite — zero-CGO SQLite setup, WAL defaults, and transaction helpers with database/sql and modernc SQLite.
  • gokart/migrate — SQL migrations with embedded filesystem support using goose/v3.
  • gokart/cache — Redis access, key prefixes, JSON helpers, caching, and data structures with go-redis/v9.
  • gokart/fs — atomic writes, configuration paths, and read-or-create helpers from the standard library.
  • gokart/ai — OpenAI client construction with openai-go/v3.
  • gokart/logger — structured JSON, text, and file logging with log/slog.

Many setup functions return standard or upstream types directly, including *pgxpool.Pool, *sql.DB, chi.Router, openai.Client, and *slog.Logger. Convenience types such as cli.App and cache.Cache expose their underlying Cobra or Redis client when lower-level control is needed.

Generate a project

gokart new creates a structured CLI project by default:

gokart new mycli                         # local-only CLI
gokart new mycli --example               # include a greet command and tests
gokart new mycli --flat                  # single main.go
gokart new mycli --global                # platform user config directory
gokart new mycli --db sqlite             # SQLite integration
gokart new mycli --db postgres --ai      # PostgreSQL and OpenAI
gokart new mycli --redis                 # Redis integration
gokart new mycli --dry-run --json        # machine-readable preview

Plain local scaffolds stay lightweight and do not write a management manifest. They are unmanaged and cannot use gokart add. If you expect to add integrations later, select --global or an integration during creation. Those options write .gokart-manifest.json, which lets gokart add detect edits before updating generated wiring.

Add integrations

Run gokart add from a managed, structured project:

gokart add sqlite
gokart add ai redis
gokart add postgres --dry-run

The command re-renders internal/app/context.go and internal/commands/root.go, runs go get and go mod tidy (which can change go.mod and go.sum), and refreshes .gokart-manifest.json. It refuses to overwrite modified generated wiring or existing wiring that the manifest does not track. Use --dry-run to inspect the plan first.

Destructive override (advanced): gokart add ai --force overwrites conflicting generated wiring. Use it only when you intend to discard those local edits.

See the generator reference for every flag, manifest behavior, JSON output, and exit code.

Use the libraries directly

Each component is independently importable:

package main

import (
    "log"
    "net/http"

    "github.com/dotcommander/gokart/web"
)

func main() {
    router := web.NewRouter(web.RouterConfig{
        Middleware: web.StandardMiddleware,
    })
    router.Get("/health", func(w http.ResponseWriter, _ *http.Request) {
        web.JSON(w, map[string]string{"status": "ok"})
    })

    if err := web.ListenAndServe(":8080", router); err != nil {
        log.Fatal(err)
    }
}

Component guides and runnable examples are indexed in docs/. Complete applications live in examples/. For database usage, see the maintained PostgreSQL example.

Requirements and verification

  • Go 1.26 or later.
  • just for the short contributor verification command.
  • External services are required only for the integrations that use them.

Run the repository checks across all modules and examples:

just verify

Without just, run the same checks directly:

scripts/verify-workspace.sh all

License

MIT

Documentation

Overview

Package gokart provides thin wrappers around best-in-class Go packages with sensible defaults.

GoKart is an opinionated service toolkit. Every component must justify its existence - we wrap battle-tested packages, not reinvent them.

Components

Root module (github.com/dotcommander/gokart):

  • Config: viper wrapper for config files + env vars
  • State: JSON state persistence for CLI tools

Submodules:

  • gokart/logger: slog wrapper with JSON/text formatting
  • gokart/cli: CLI framework wrapping cobra + lipgloss
  • gokart/web: HTTP router, client, templ helpers, validator
  • gokart/postgres: pgx/v5 connection pool
  • gokart/sqlite: modernc.org/sqlite (zero CGO) with WAL mode
  • gokart/cache: go-redis/v9 with convenience methods
  • gokart/migrate: goose/v3 schema migrations
  • gokart/ai: OpenAI client factory functions

Design Principles

  • Thin wrappers: No business logic, just factory functions
  • Sensible defaults: Zero-config works for development and production
  • Best-in-class: Wrap proven packages, don't reinvent
  • Fight for inclusion: stdlib-sufficient things stay in stdlib

Quick Start

// Logger
log := logger.New(logger.Config{Level: "info", Format: "json"})

// Config
cfg, err := gokart.LoadConfig[AppConfig]("config.yaml")

// Router (gokart/web)
router := web.NewRouter(web.RouterConfig{Middleware: web.StandardMiddleware})

// PostgreSQL (gokart/postgres)
pool, err := postgres.Open(ctx, "postgres://localhost/mydb")

// Cache (gokart/cache)
c, err := cache.Open(ctx, "localhost:6379")

// Migrations (gokart/migrate)
migrate.Postgres(ctx, db, "migrations")

CLI Subpackage

For CLI applications, use the gokart/cli subpackage which wraps cobra and lipgloss:

import "github.com/dotcommander/gokart/cli"

app := cli.NewApp("myapp", "1.0.0").
    WithDescription("My application").
    WithStandardFlags()
app.Run()

Not Included

GoKart intentionally excludes things where stdlib is sufficient:

  • Error handling: use errors.Is/As and fmt.Errorf("%w", err)
  • File operations: use os, io, filepath
  • String manipulation: use strings
  • Environment variables: viper.AutomaticEnv() handles this

Domain-specific features belong in separate modules so applications only import the dependencies they use.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetBool added in v0.10.3

func GetBool(config map[string]any, key string, defaultValue bool) bool

GetBool returns the bool value for key or defaultValue when the key is absent or has another type.

func GetFloat added in v0.10.3

func GetFloat(config map[string]any, key string, defaultValue float32) float32

GetFloat returns the numeric value for key as a float32.

func GetInt added in v0.10.3

func GetInt(config map[string]any, key string, defaultValue int) int

GetInt returns the numeric value for key as an int. Values decoded from JSON maps commonly arrive as float64, so those and int64 values are accepted.

func GetString added in v0.10.3

func GetString(config map[string]any, key, defaultValue string) string

GetString returns the string value for key or defaultValue when the key is absent or has another type.

func LoadConfig

func LoadConfig[T any](paths ...string) (T, error)

LoadConfig loads configuration from the first available file path into type T.

Features:

  • Supports multiple config paths (first found wins)
  • Automatic environment variable binding
  • DOT to UNDERSCORE env key mapping (e.g., db.host → DB_HOST)

Supported formats: JSON, YAML, TOML, HCL, envfile, Java properties

Example:

type Config struct {
    DB struct {
        Host string `mapstructure:"host"`
        Port int    `mapstructure:"port"`
    } `mapstructure:"db"`
}
cfg, err := gokart.LoadConfig[Config]("config.yaml", "config.json")

func LoadConfigWithDefaults

func LoadConfigWithDefaults[T any](defaults T, paths ...string) (T, error)

LoadConfigWithDefaults loads configuration with default values pre-populated.

The defaults parameter provides fallback values that will be overridden by values from config files or environment variables.

Example:

defaults := Config{
    DB: struct{Host string; Port int}{
        Host: "localhost",
        Port: 5432,
    },
}
cfg, err := gokart.LoadConfigWithDefaults(defaults, "config.yaml")

func LoadState

func LoadState[T any](appName, filename string) (T, error)

LoadState loads typed state from the platform user config directory.

Returns zero value and os.ErrNotExist if the file doesn't exist. This allows callers to distinguish between missing file and parse errors.

Example:

state, err := gokart.LoadState[AppState]("myapp", "state.json")
if errors.Is(err, os.ErrNotExist) {
    // First run, use defaults
    state = AppState{WindowSize: 800}
} else if err != nil {
    return err
}

func MustParseConfig added in v0.10.2

func MustParseConfig[T any](config map[string]any) T

MustParseConfig is ParseConfig for initialization paths where invalid configuration is a programmer error.

func ParseConfig added in v0.10.2

func ParseConfig[T any](config map[string]any) (T, error)

ParseConfig converts a config map to a typed struct. The config tag names fields, default supplies missing scalar values, and required marks fields that must be present after defaults are applied. Anonymous structs are flattened.

func SaveState

func SaveState[T any](appName, filename string, data T) error

SaveState saves typed state under the platform user config directory.

The file is written as indented JSON for human readability. Directory is created with 0755, files with 0600 permissions.

Example:

type AppState struct {
    LastOpened string `json:"last_opened"`
    WindowSize int    `json:"window_size"`
}
err := gokart.SaveState("myapp", "state.json", AppState{
    LastOpened: "/path/to/file",
    WindowSize: 1024,
})

func StatePath

func StatePath(appName, filename string) string

StatePath returns the full path to a state file.

Returns empty string if the user config directory cannot be determined.

Example:

path := gokart.StatePath("myapp", "state.json")
// macOS: ~/Library/Application Support/myapp/state.json
// Linux: ~/.config/myapp/state.json

Types

This section is empty.

Directories

Path Synopsis
cache module
cli module
cmd
gokart module
internal
logger module
migrate module
postgres module
sqlite module
web module

Jump to

Keyboard shortcuts

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