API7 Docs

a6 CLI conventions for Apache APISIX

Core skill for working with the a6 CLI — the Apache APISIX command-line tool. Provides project conventions, command patterns, architecture overview, and…

What is a6

a6 is a Go CLI wrapping the Apache APISIX Admin API. It provides imperative CRUD for all 14 APISIX resources, declarative config sync, context management for multiple APISIX instances, and debug tooling.

  • Binary: a6
  • Module: github.com/api7/a6
  • Go: 1.22+
  • Pattern: noun-verb (a6 <resource> <action> [flags])

Project Layout

a6/
├── cmd/a6/main.go                  # Entry point
├── pkg/cmd/                        # Command implementations
│   ├── root/root.go                # Root command, registers all subcommands
│   ├── factory.go                  # DI: IOStreams, HttpClient, Config
│   ├── route/                      # a6 route list|get|create|update|delete
│   ├── upstream/                   # a6 upstream list|get|create|update|delete|health
│   ├── service/                    # a6 service ...
│   ├── consumer/                   # a6 consumer ...
│   ├── ssl/                        # a6 ssl ...
│   ├── plugin/                     # a6 plugin list|get
│   ├── config/                     # a6 config sync|diff|dump|validate
│   └── context/                    # a6 context create|use|list|delete|current
├── pkg/api/                        # Admin API HTTP client + types
│   ├── client.go                   # Thin net/http wrapper with auth
│   └── types_*.go                  # Go structs per resource (Route, Upstream, etc.)
├── pkg/iostreams/                  # I/O abstraction (TTY detection)
├── pkg/cmdutil/                    # Shared utilities (errors, exporter, flags)
├── pkg/tableprinter/               # Table rendering
├── pkg/httpmock/                   # HTTP mock for unit tests
├── internal/config/                # Context/config file management
├── test/fixtures/                  # JSON fixtures for unit tests
├── test/e2e/                       # E2E tests (build tag: e2e)
├── skills/                         # AI agent skill files
└── docs/                           # Project documentation

Architecture Patterns

Factory Pattern (Dependency Injection)

Every command receives a *cmd.Factory containing IOStreams, HttpClient(), and Config(). No global state. This enables full test isolation.

type Factory struct {
    IOStreams   *iostreams.IOStreams
    HttpClient func() (*http.Client, error)
    Config     func() (config.Config, error)
}

Command Pattern (Options + NewCmd + Run)

Every command follows the same structure:

type Options struct {
    IO     *iostreams.IOStreams
    Client func() (*http.Client, error)
    Config func() (config.Config, error)
    // command-specific fields
}

func NewCmdXxx(f *cmd.Factory) *cobra.Command { ... }
func xxxRun(opts *Options) error { ... }

Output Pattern

  • TTY → table output (human-friendly)
  • Non-TTY → JSON (machine-readable)
  • --output json|yaml|table overrides detection

Testing Pattern

  • Unit tests: httpmock stubs + test IOStreams. Zero real network calls.
  • E2E tests: //go:build e2e, real APISIX in Docker, binary invocation.
  • Fixtures: test/fixtures/*.json for realistic mock responses.

Adding a New Command

  1. Read the API spec: docs/admin-api-spec.md
  2. Create types: pkg/api/types_<resource>.go with both json: and yaml: tags
  3. Create parent command: pkg/cmd/<resource>/<resource>.go
  4. Create action: pkg/cmd/<resource>/<action>/<action>.go (follow docs/golden-example.md)
  5. Add tests: *_test.go in same package (TTY, non-TTY, filter, error cases)
  6. Add fixture: test/fixtures/<resource>_<action>.json
  7. Register: add to pkg/cmd/root/root.go
  8. Update docs: docs/user-guide/<resource>.md

Common Commands

make build          # Build to ./bin/a6
make test           # Unit tests (excludes e2e)
make test-e2e       # E2E tests (requires running APISIX)
make lint           # golangci-lint
make fmt            # gofmt
make check          # fmt + vet + lint + test
make docker-up      # Start local APISIX stack
make docker-down    # Stop local APISIX stack

Code Conventions

  • gofmt + goimports formatting
  • Error messages: lowercase, no trailing punctuation
  • camelCase locals, PascalCase exports
  • No any or interface{} — use concrete types or generics
  • All struct fields need both json: and yaml: tags
  • Never suppress errors; always handle and propagate

Resource Types Covered

ResourceKey FieldAPI Path
Routeid/apisix/admin/routes
Serviceid/apisix/admin/services
Upstreamid/apisix/admin/upstreams
Consumerusername/apisix/admin/consumers
SSLid/apisix/admin/ssl
Global Ruleid/apisix/admin/global_rules
Plugin Configid/apisix/admin/plugin_configs
Consumer Groupid/apisix/admin/consumer_groups
Stream Routeid/apisix/admin/stream_routes
Protoid/apisix/admin/protos
Secretid/apisix/admin/secrets/{manager}/{id}
Plugin Metadataplugin_name/apisix/admin/plugin_metadata/{name}
Plugin (read-only)name/apisix/admin/plugins
Credentialid/apisix/admin/consumers/{username}/credentials

Config Sync Workflow

The declarative config system (a6 config sync/diff/dump/validate) manages resources via YAML files:

version: "1"
routes:
  - id: my-route
    uri: /api/*
    upstream_id: my-upstream
upstreams:
  - id: my-upstream
    type: roundrobin
    nodes:
      "httpbin:8080": 1

Sync processes resources in dependency order: upstreams/services first, routes/stream_routes last. Deletes happen in reverse order. Transient "still referenced" errors during delete are retried with exponential backoff.


This page is generated from a6-shared/SKILL.md in the api7/a6 repository. Browse all skills on the AI Agent Skills page.