Documentation
¶
Overview ¶
Package ax provides the Agentic Experience foundation for Go CLI tools.
The package keeps machine payloads on stdout, operational output on stderr, and exposes shared primitives for mode resolution, error envelopes, discoverability schemas, idempotency keys, logging, and trace propagation.
Index ¶
- Constants
- func DryRunFromContext(ctx context.Context) bool
- func ErrorExitCode(err error) int
- func Execute(ctx context.Context, root *cobra.Command, opts ...ExecuteOption) int
- func GRPCDial(ctx context.Context, target string, opts ...grpc.DialOption) (*grpc.ClientConn, error)
- func HTTPClient() *http.Client
- func IdempotencyKeyFromContext(ctx context.Context) (string, bool)
- func NewEntityID() (string, error)
- func NewIdempotencyKey() string
- func NewSchemaCommand(root *cobra.Command, opts ...SchemaOption) *cobra.Command
- func ParseConfig(ctx context.Context, r io.Reader, dst any, opts ...ParseConfigOption) error
- func ParseConfigFile(ctx context.Context, path string, dst any, opts ...ParseConfigOption) error
- func PatchConfig(ctx context.Context, r io.Reader, patch []byte, opts ...ParseConfigOption) ([]byte, error)
- func PatchConfigFile(ctx context.Context, path string, patch []byte, opts ...ParseConfigOption) error
- func ResolveVersion(injected string) string
- func SpanIDFromContext(ctx context.Context) string
- func TraceIDFromContext(ctx context.Context) string
- func WithDryRun(ctx context.Context, dryRun bool) context.Context
- func WithIdempotencyKey(ctx context.Context, key string) context.Context
- func WithMode(ctx context.Context, mode Mode) context.Context
- func WriteError(w io.Writer, err error) error
- func WriteJSON(w io.Writer, v any) error
- func WriteJSONLine(w io.Writer, v any) error
- type CommandSchema
- type Envelope
- type Error
- type ErrorOption
- func WithActionableFix(fix string) ErrorOption
- func WithErrorCause(err error) ErrorOption
- func WithErrorContext(fields map[string]any) ErrorOption
- func WithErrorExitCode(code int) ErrorOption
- func WithErrorTool(tool string) ErrorOption
- func WithErrorVersion(version string) ErrorOption
- func WithSuggestions(suggestions ...string) ErrorOption
- type ErrorSchemaInfo
- type ExecuteOption
- func WithEnv(env func(string) string) ExecuteOption
- func WithStderr(w io.Writer) ExecuteOption
- func WithStdin(r io.Reader) ExecuteOption
- func WithStdout(w io.Writer) ExecuteOption
- func WithStdoutIsTTY(isTTY bool) ExecuteOption
- func WithTelemetryShutdownTimeout(timeout time.Duration) ExecuteOption
- func WithVersion(version string) ExecuteOption
- type FlagSchema
- type Labels
- type Logger
- type LoggerOption
- type MCPSchema
- type MCPTool
- type Metadata
- type Mode
- type ParseConfigOption
- type Schema
- type SchemaOption
- type Telemetry
- type TelemetryOption
- func WithTelemetryEnv(env func(string) string) TelemetryOption
- func WithTelemetryServiceName(name string) TelemetryOption
- func WithTelemetryServiceVersion(version string) TelemetryOption
- func WithTelemetryShutdownBudget(d time.Duration) TelemetryOption
- func WithTelemetryStderr(w io.Writer) TelemetryOption
Examples ¶
Constants ¶
const ( // DefaultMaxConfigBytes is the default maximum config size: 1 MiB. DefaultMaxConfigBytes int64 = 1 << 20 // MaxConfigBytesCeiling is the largest valid config read limit: 1 GiB. MaxConfigBytesCeiling int64 = internalconfig.MaxConfigBytesCeiling )
const ( // ExitSuccess indicates successful completion. ExitSuccess = 0 // ExitInternal indicates an unknown or internal error. ExitInternal = 1 // ExitValidation indicates invalid input or failed validation. ExitValidation = 2 // ExitNetwork indicates a network failure or timeout. ExitNetwork = 3 // ExitAuth indicates an authentication or permission failure. ExitAuth = 4 )
const ( // ZeroTraceID is a valid zero-value W3C trace ID for no-active-span cases. ZeroTraceID = "00000000000000000000000000000000" // ZeroSpanID is a valid zero-value W3C span ID for no-active-span cases. ZeroSpanID = "0000000000000000" )
const (
// ErrorSchemaVersion is the current SemVer version of the error envelope.
ErrorSchemaVersion = "1.0.0"
)
const ModeDetectionRule = "--format flag > AGENT_MODE env > TTY detection"
ModeDetectionRule documents the ADR-0001 resolution precedence applied by ResolveMode. It is surfaced verbatim in __schema output.
const SchemaVersion = ErrorSchemaVersion
SchemaVersion is the current SemVer version for ax-native schemas.
Variables ¶
This section is empty.
Functions ¶
func DryRunFromContext ¶
DryRunFromContext reports whether dry-run behavior is active.
func ErrorExitCode ¶
ErrorExitCode maps an error to the deterministic ax-go process exit code: nil maps to ExitSuccess (0); an *Error anywhere in the chain maps to its explicit ExitCode, winning over any sentinel buried in its cause chain; a non-envelope error wrapping context.DeadlineExceeded maps to ExitNetwork (3) and one wrapping context.Canceled to ExitInternal (1); anything else maps to ExitInternal (1).
func Execute ¶
Execute wraps Cobra execution with AX mode resolution, idempotency, schema, error-envelope, and telemetry lifecycle behavior. It returns a deterministic exit code and leaves process termination to the caller.
func GRPCDial ¶
func GRPCDial(ctx context.Context, target string, opts ...grpc.DialOption) (*grpc.ClientConn, error)
GRPCDial dials target with OTel client instrumentation.
func HTTPClient ¶
HTTPClient returns an HTTP client with OTel propagation instrumentation.
func IdempotencyKeyFromContext ¶
IdempotencyKeyFromContext returns the idempotency key stored in ctx.
func NewEntityID ¶
NewEntityID returns a UUID v7 resource/entity identifier.
Example ¶
ExampleNewEntityID returns a UUID v7 resource identifier in canonical 36-character form.
package main
import (
"fmt"
ax "github.com/rshade/ax-go"
)
func main() {
id, err := ax.NewEntityID()
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(len(id))
}
Output: 36
func NewIdempotencyKey ¶
func NewIdempotencyKey() string
NewIdempotencyKey returns a UUID v4 idempotency key.
Example ¶
ExampleNewIdempotencyKey returns a UUID v4 string in canonical 36-character form, surfaced in the output envelope so retries are safe.
package main
import (
"fmt"
ax "github.com/rshade/ax-go"
)
func main() {
key := ax.NewIdempotencyKey()
fmt.Println(len(key))
}
Output: 36
func NewSchemaCommand ¶
func NewSchemaCommand(root *cobra.Command, opts ...SchemaOption) *cobra.Command
NewSchemaCommand builds the reserved __schema command.
func ParseConfig ¶
ParseConfig parses Hujson from r under a bounded read cap and unmarshals into dst.
Reads default to DefaultMaxConfigBytes and consume at most cap+1 bytes. Oversize input returns an errors.As-discoverable *Error with error_code config_too_large and exit code 2. A cap below zero or above MaxConfigBytesCeiling returns config_max_bytes_invalid and exit code 2. A nil ParseConfigOption returns config_option_invalid and exit code 2. Hujson parse and schema/type decode failures return config_invalid and exit code 2, with the underlying decode error preserved in the chain (reachable via errors.Is and errors.As through Unwrap). Invalid decode destinations, such as nil or non-pointer dst values, surface the underlying *json.InvalidUnmarshalError as caller misuse and are not classified as config_invalid. Every valid cap is at most MaxConfigBytesCeiling, so there is no unbounded read path. ctx cancellation is honored between chunk reads, not inside a single blocking Read. Wrapped context.DeadlineExceeded maps to exit code 3 via ErrorExitCode, and wrapped context.Canceled maps to exit code 1. A non-EOF source error before cap+1 bytes is returned with its chain preserved and is not classified as oversize; if the same read crosses the cap and returns a source error, the oversize validation error wins.
Example ¶
ExampleParseConfig shows the read-side Hujson asymmetry: comments and trailing commas are accepted on input, and the result decodes into a normal struct.
package main
import (
"context"
"fmt"
"strings"
ax "github.com/rshade/ax-go"
)
func main() {
const hujson = `{
// comments and trailing commas are allowed on reads
"name": "ax",
"replicas": 3,
}`
var cfg struct {
Name string `json:"name"`
Replicas int `json:"replicas"`
}
if err := ax.ParseConfig(
context.Background(),
strings.NewReader(hujson),
&cfg,
ax.WithMaxConfigBytes(1<<10),
); err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("%s x%d\n", cfg.Name, cfg.Replicas)
}
Output: ax x3
func ParseConfigFile ¶
ParseConfigFile opens path and applies ParseConfig's contract to its contents.
The file is closed before return. Open failures are returned as-is; read, cap, context-cancellation, and Hujson decode behavior match ParseConfig.
Example ¶
ExampleParseConfigFile reads and decodes a Hujson configuration file from disk, applying the same 1 MiB read cap as ParseConfig.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
ax "github.com/rshade/ax-go"
)
func main() {
dir, err := os.MkdirTemp("", "ax-config")
if err != nil {
fmt.Println("error:", err)
return
}
defer os.RemoveAll(dir)
path := filepath.Join(dir, "config.hujson")
if err := os.WriteFile(path, []byte(`{"name": "ax"}`), 0o600); err != nil {
fmt.Println("error:", err)
return
}
var cfg struct {
Name string `json:"name"`
}
if err := ax.ParseConfigFile(context.Background(), path, &cfg); err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(cfg.Name)
}
Output: ax
func PatchConfig ¶ added in v0.0.2
func PatchConfig(ctx context.Context, r io.Reader, patch []byte, opts ...ParseConfigOption) ([]byte, error)
PatchConfig reads Hujson from r, applies RFC 6902 JSON patch operations, and returns the patched Hujson content with comments preserved. Whitespace is normalized to canonical Hujson formatting; user indentation, value alignment, and blank lines are not preserved byte-for-byte.
This is the comment-preserving write path: unlike strict-JSON writes, the returned bytes remain valid Hujson so the caller can write them back to a human-maintained config file without stripping user comments. The patch document must be a strict JSON array of RFC 6902 operation objects. An invalid existing config returns config_invalid; an invalid or failing patch returns config_patch_invalid; read cap and context errors follow ParseConfig's contract.
Example ¶
ExamplePatchConfig shows the comment-preserving write path: RFC 6902 patch operations mutate the Hujson AST in place so user comments survive.
package main
import (
"context"
"fmt"
"strings"
ax "github.com/rshade/ax-go"
)
func main() {
const existing = `{
// service endpoint
"host": "localhost",
"port": 8080,
}`
patch := []byte(`[{"op":"replace","path":"/port","value":9090}]`)
patched, err := ax.PatchConfig(
context.Background(),
strings.NewReader(existing),
patch,
)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(strings.Contains(string(patched), "// service endpoint"))
fmt.Println(strings.Contains(string(patched), "9090"))
}
Output: true true
func PatchConfigFile ¶ added in v0.0.2
func PatchConfigFile(ctx context.Context, path string, patch []byte, opts ...ParseConfigOption) error
PatchConfigFile reads path as Hujson, applies RFC 6902 JSON patch operations, and writes the patched result back to path atomically, preserving comments. Whitespace is normalized to canonical Hujson formatting (see PatchConfig). The original file permissions are preserved.
Open or stat failures are returned as-is. Patch behavior matches PatchConfig. The write is atomic: a temporary file in the same directory is written and then renamed, so a partial write never corrupts the existing file. The rename guarantees atomicity, not crash durability: no fsync is issued, so a power loss immediately after return may lose the write. If path is a symlink, the rename replaces the symlink itself with a regular file; the symlink target is not modified. Concurrent external writes to path follow last-writer-wins.
Example ¶
ExamplePatchConfigFile reads a Hujson config file, applies RFC 6902 patch operations, and writes the result back atomically, preserving user comments.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
ax "github.com/rshade/ax-go"
)
func main() {
dir, err := os.MkdirTemp("", "ax-patch")
if err != nil {
fmt.Println("error:", err)
return
}
defer os.RemoveAll(dir)
path := filepath.Join(dir, "config.hujson")
initial := []byte(`{
// production endpoint
"host": "prod.example.com",
"port": 443,
}`)
if err := os.WriteFile(path, initial, 0o600); err != nil {
fmt.Println("error:", err)
return
}
patch := []byte(`[{"op":"replace","path":"/port","value":8443}]`)
if err := ax.PatchConfigFile(context.Background(), path, patch); err != nil {
fmt.Println("error:", err)
return
}
result, err := os.ReadFile(path)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(strings.Contains(string(result), "// production endpoint"))
fmt.Println(strings.Contains(string(result), "8443"))
}
Output: true true
func ResolveVersion ¶
ResolveVersion returns a non-empty tool version for agent-visible surfaces.
Resolution is deterministic for a given binary and uses this precedence: first the injected link-time value, then Go build metadata from the running binary, then the sentinel "0.0.0-unknown". The result is never empty and is never the bare strings "dev" or "unknown"; pass the returned value to WithVersion and WithLoggerLabels so __schema.version, ax.Error.version, and the logger "version" label agree.
Example ¶
ExampleResolveVersion shows the deterministic injected-version path used by release builds. When the injected value is empty, ResolveVersion falls back to the running binary's build metadata and finally to "0.0.0-unknown".
package main
import (
"fmt"
ax "github.com/rshade/ax-go"
)
func main() {
fmt.Println(ax.ResolveVersion("v1.2.3"))
}
Output: v1.2.3
func SpanIDFromContext ¶
SpanIDFromContext returns the active W3C span ID or ZeroSpanID.
func TraceIDFromContext ¶
TraceIDFromContext returns the active W3C trace ID or ZeroTraceID.
func WithDryRun ¶
WithDryRun returns a context carrying the dry-run state.
func WithIdempotencyKey ¶
WithIdempotencyKey returns a context carrying the idempotency key for the run.
func WriteError ¶
WriteError writes err as a strict minified JSON error envelope followed by a newline.
Types ¶
type CommandSchema ¶
type CommandSchema struct {
Use string `json:"use"`
Short string `json:"short,omitempty"`
Long string `json:"long,omitempty"`
Example string `json:"example,omitempty"`
Flags []FlagSchema `json:"flags,omitempty"`
Commands []CommandSchema `json:"commands,omitempty"`
}
CommandSchema describes a Cobra command and its direct children.
type Envelope ¶
Envelope is the standard bounded JSON success payload shape.
Example ¶
ExampleEnvelope shows the envelope shape directly: a typed Data field and a Metadata block. span_id is omitted when empty.
package main
import (
"fmt"
"os"
ax "github.com/rshade/ax-go"
)
func main() {
env := ax.Envelope[string]{
Data: "hello",
Meta: ax.Metadata{TraceID: ax.ZeroTraceID},
}
if err := ax.WriteJSON(os.Stdout, env); err != nil {
fmt.Println("error:", err)
}
}
Output: {"data":"hello","meta":{"trace_id":"00000000000000000000000000000000"}}
func NewEnvelope ¶
NewEnvelope wraps data with standard AX metadata from ctx.
Example ¶
ExampleNewEnvelope wraps a payload in the standard success envelope, carrying trace metadata from the context. With no active span the IDs are the zero W3C values, so the output is deterministic.
package main
import (
"context"
"fmt"
"os"
ax "github.com/rshade/ax-go"
)
func main() {
type result struct {
ID string `json:"id"`
}
env := ax.NewEnvelope(context.Background(), result{ID: "abc"})
if err := ax.WriteJSON(os.Stdout, env); err != nil {
fmt.Println("error:", err)
}
}
Output: {"data":{"id":"abc"},"meta":{"trace_id":"00000000000000000000000000000000","span_id":"0000000000000000"}}
type Error ¶
type Error struct {
ErrorCode string `json:"error_code"`
Message string `json:"message"`
TraceID string `json:"trace_id"`
Tool string `json:"tool"`
Version string `json:"version"`
SchemaVersion string `json:"schema_version"`
ActionableFix string `json:"actionable_fix,omitempty"`
Context map[string]any `json:"context,omitempty"`
Suggestions []string `json:"suggestions,omitempty"`
// contains filtered or unexported fields
}
Error is the ADR-0002 structured error envelope emitted to stderr.
Example ¶
ExampleError shows how a consumer classifies a failure: recover the *ax.Error envelope with errors.As, then branch on the stable error_code and exit code without parsing human-facing text.
package main
import (
"context"
"errors"
"fmt"
ax "github.com/rshade/ax-go"
)
func main() {
err := ax.NewError(
context.Background(),
"config_max_bytes_invalid",
"config max bytes must be between 0 and 1073741824",
ax.WithErrorExitCode(ax.ExitValidation),
)
var axErr *ax.Error
if errors.As(err, &axErr) {
fmt.Println(axErr.ErrorCode)
fmt.Println(axErr.ExitCode())
}
}
Output: config_max_bytes_invalid 2
func NewError ¶
func NewError(ctx context.Context, code, message string, opts ...ErrorOption) *Error
NewError builds a structured error envelope using trace information from ctx.
Example ¶
ExampleNewError builds a structured error envelope with an actionable fix and a deterministic exit code, then reads the exit code back out.
package main
import (
"context"
"fmt"
ax "github.com/rshade/ax-go"
)
func main() {
err := ax.NewError(
context.Background(),
"config_too_large",
"config exceeds maximum size of 1048576 bytes",
ax.WithActionableFix("reduce the config or raise the limit with WithMaxConfigBytes"),
ax.WithErrorExitCode(ax.ExitValidation),
)
fmt.Println(err)
fmt.Println(ax.ErrorExitCode(err))
}
Output: config exceeds maximum size of 1048576 bytes 2
type ErrorOption ¶
type ErrorOption func(*Error)
ErrorOption configures a structured Error.
func WithActionableFix ¶
func WithActionableFix(fix string) ErrorOption
WithActionableFix sets a best-effort remediation hint.
func WithErrorCause ¶
func WithErrorCause(err error) ErrorOption
WithErrorCause attaches the underlying source error to the envelope so errors.Is and errors.As reach it through Unwrap. The cause is never serialized into the JSON envelope; it exists only for in-process callers. Never attach a context.Canceled or context.DeadlineExceeded cause: context errors are returned raw (FR-010) so their sentinels map to exit codes only when no explicit envelope classification exists.
func WithErrorContext ¶
func WithErrorContext(fields map[string]any) ErrorOption
WithErrorContext merges domain-specific context fields into the envelope.
func WithErrorExitCode ¶
func WithErrorExitCode(code int) ErrorOption
WithErrorExitCode sets the deterministic process exit code.
func WithErrorTool ¶
func WithErrorTool(tool string) ErrorOption
WithErrorTool sets the emitting tool name.
func WithErrorVersion ¶
func WithErrorVersion(version string) ErrorOption
WithErrorVersion sets the emitting tool version.
func WithSuggestions ¶
func WithSuggestions(suggestions ...string) ErrorOption
WithSuggestions sets optional candidate recovery actions.
type ErrorSchemaInfo ¶
type ErrorSchemaInfo struct {
SchemaVersion string `json:"schema_version"`
Required []string `json:"required"`
Optional []string `json:"optional"`
}
ErrorSchemaInfo describes the shared stderr error envelope.
type ExecuteOption ¶
type ExecuteOption func(*executeConfig)
ExecuteOption configures Execute.
func WithEnv ¶
func WithEnv(env func(string) string) ExecuteOption
WithEnv sets the environment lookup used by Execute.
func WithStderr ¶
func WithStderr(w io.Writer) ExecuteOption
WithStderr sets the operational output stream.
func WithStdin ¶
func WithStdin(r io.Reader) ExecuteOption
WithStdin sets the input stream for Cobra.
func WithStdout ¶
func WithStdout(w io.Writer) ExecuteOption
WithStdout sets the machine payload output stream.
func WithStdoutIsTTY ¶
func WithStdoutIsTTY(isTTY bool) ExecuteOption
WithStdoutIsTTY overrides TTY detection, primarily for tests.
func WithTelemetryShutdownTimeout ¶
func WithTelemetryShutdownTimeout(timeout time.Duration) ExecuteOption
WithTelemetryShutdownTimeout sets the OTel shutdown timeout.
func WithVersion ¶
func WithVersion(version string) ExecuteOption
WithVersion sets the tool version reported in schema and error envelopes.
type FlagSchema ¶
type FlagSchema struct {
Name string `json:"name"`
Shorthand string `json:"shorthand,omitempty"`
Type string `json:"type"`
Default string `json:"default,omitempty"`
Usage string `json:"usage,omitempty"`
Required bool `json:"required,omitempty"`
}
FlagSchema describes a command flag.
type Logger ¶
type Logger interface {
Debug(ctx context.Context) *zerolog.Event
Info(ctx context.Context) *zerolog.Event
Warn(ctx context.Context) *zerolog.Event
Error(ctx context.Context) *zerolog.Event
WithLabels(labels Labels) Logger
Zerolog() *zerolog.Logger
}
Logger is the ADR-0009 logging surface, initially backed by zerolog.
type LoggerOption ¶
type LoggerOption func(*loggerConfig)
LoggerOption configures NewLogger.
func WithLoggerLabels ¶
func WithLoggerLabels(labels Labels) LoggerOption
WithLoggerLabels attaches low-cardinality labels to every log line.
func WithLoggerLevel ¶
func WithLoggerLevel(level zerolog.Level) LoggerOption
WithLoggerLevel sets the minimum zerolog level.
func WithLoggerWriter ¶
func WithLoggerWriter(w io.Writer) LoggerOption
WithLoggerWriter sets the logger output writer. Defaults to stderr.
type MCPSchema ¶
type MCPSchema struct {
Tools []MCPTool `json:"tools"`
}
MCPSchema is the lightweight MCP-compatible adapter shape.
func BuildMCPSchema ¶
BuildMCPSchema adapts the command tree to a simple MCP tools list.
type MCPTool ¶
type MCPTool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
InputSchema map[string]any `json:"inputSchema"`
}
MCPTool describes one command as an MCP-compatible tool.
type Metadata ¶
type Metadata struct {
TraceID string `json:"trace_id"`
SpanID string `json:"span_id,omitempty"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
DryRun bool `json:"dry_run,omitempty"`
}
Metadata carries common machine-readable envelope fields.
type Mode ¶
type Mode string
Mode describes whether output should be optimized for agents or humans.
Example ¶
ExampleMode shows agent-mode resolution: with no --format flag, no AGENT_MODE, and a non-TTY stdout, ax resolves to machine-readable JSON.
package main
import (
"fmt"
ax "github.com/rshade/ax-go"
)
func main() {
mode, err := ax.ResolveMode("", "", false)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(mode)
}
Output: json
func ModeFromContext ¶
ModeFromContext returns the resolved output mode stored in ctx.
func ResolveMode ¶
ResolveMode applies ADR-0001 precedence: explicit --format flag, then AGENT_MODE, then TTY detection.
type ParseConfigOption ¶
type ParseConfigOption func(*parseConfigOptions)
ParseConfigOption configures ParseConfig and ParseConfigFile.
func WithMaxConfigBytes ¶
func WithMaxConfigBytes(maxBytes int64) ParseConfigOption
WithMaxConfigBytes sets the maximum config bytes for one parse invocation.
The value is not global and does not affect later calls. Zero is a valid, honored limit: empty input passes the size check and then follows normal parse semantics, while any non-empty input is rejected as config_too_large. Values below zero or above MaxConfigBytesCeiling return config_max_bytes_invalid, mapped to exit code 2; there is no unbounded read path. Passing a nil ParseConfigOption is rejected as config_option_invalid, also mapped to exit code 2.
type Schema ¶
type Schema struct {
SchemaVersion string `json:"schema_version"`
Tool string `json:"tool"`
Version string `json:"version"`
ModeDetection string `json:"mode_detection"`
Command CommandSchema `json:"command"`
ErrorEnvelope ErrorSchemaInfo `json:"error_envelope"`
}
Schema is the ax-native reflective JSON tree emitted by __schema.
func BuildSchema ¶
func BuildSchema(root *cobra.Command, opts ...SchemaOption) Schema
BuildSchema reflects a Cobra command tree into the ax-native schema.
type SchemaOption ¶
type SchemaOption func(*schemaConfig)
SchemaOption configures BuildSchema and NewSchemaCommand.
func WithSchemaVersion ¶
func WithSchemaVersion(version string) SchemaOption
WithSchemaVersion sets the tool version reported by __schema.
type Telemetry ¶
type Telemetry struct {
TracerProvider *sdktrace.TracerProvider
}
Telemetry owns the OTel provider lifecycle for a short-lived CLI process.
func StartTelemetry ¶
func StartTelemetry(ctx context.Context, opts ...TelemetryOption) (context.Context, *Telemetry, error)
StartTelemetry installs W3C trace propagation and extracts TRACEPARENT.
It configures telemetry from the supplied environment lookup. An OTEL_EXPORTER_OTLP_ENDPOINT value enables OTLP HTTP export with synchronous, bounded attempts; AX_OTEL_DEBUG enables human-readable span output on the configured stderr writer. With neither set, telemetry is no-op for export while still allowing Execute to create a recording root span for log correlation.
StartTelemetry is fail-open: telemetry setup failures are reported to stderr and the returned error is reserved for signature compatibility and currently always nil.
Example ¶
ExampleStartTelemetry installs W3C propagation and configures the telemetry lifecycle with explicit stderr, service identity, and shutdown budget options.
package main
import (
"bytes"
"context"
"fmt"
"time"
ax "github.com/rshade/ax-go"
)
func main() {
var stderr bytes.Buffer
ctx, telemetry, err := ax.StartTelemetry(
context.Background(),
ax.WithTelemetryEnv(func(string) string { return "" }),
ax.WithTelemetryStderr(&stderr),
ax.WithTelemetryServiceName("example"),
ax.WithTelemetryServiceVersion("v1.2.3"),
ax.WithTelemetryShutdownBudget(50*time.Millisecond),
)
if err != nil {
fmt.Println("error:", err)
return
}
if err := telemetry.Shutdown(context.Background()); err != nil {
fmt.Println("shutdown:", err)
return
}
fmt.Println(telemetry != nil)
fmt.Println(ax.TraceIDFromContext(ctx))
fmt.Println(stderr.Len())
}
Output: true 00000000000000000000000000000000 0
type TelemetryOption ¶
type TelemetryOption func(*telemetryConfig)
TelemetryOption configures StartTelemetry.
func WithTelemetryEnv ¶
func WithTelemetryEnv(env func(string) string) TelemetryOption
WithTelemetryEnv sets the environment lookup used for telemetry configuration and trace extraction. StartTelemetry resolves OTEL_EXPORTER_OTLP_ENDPOINT and AX_OTEL_DEBUG (exporter and debug selection) as well as TRACEPARENT and TRACESTATE (inbound trace continuation) through this lookup, so a custom function controls all of them in tests and embedding scenarios.
func WithTelemetryServiceName ¶ added in v0.0.2
func WithTelemetryServiceName(name string) TelemetryOption
WithTelemetryServiceName sets the OTel resource service.name value.
The value should be a low-cardinality CLI name and must not include PII, credentials, resource IDs, or user-controlled command input.
func WithTelemetryServiceVersion ¶ added in v0.0.2
func WithTelemetryServiceVersion(version string) TelemetryOption
WithTelemetryServiceVersion sets the OTel resource service.version value.
The value should be the deterministic build-injected version reported by the adopting CLI and must not include PII or high-cardinality runtime data.
func WithTelemetryShutdownBudget ¶ added in v0.0.2
func WithTelemetryShutdownBudget(d time.Duration) TelemetryOption
WithTelemetryShutdownBudget sets the timeout budget for telemetry shutdown and synchronous exporter attempts.
Non-positive durations are ignored by StartTelemetry, which falls back to the default Execute telemetry shutdown timeout. A stuck collector maps to a fail-open stderr diagnostic rather than a command failure.
func WithTelemetryStderr ¶ added in v0.0.2
func WithTelemetryStderr(w io.Writer) TelemetryOption
WithTelemetryStderr sets the operational telemetry writer.
StartTelemetry writes fail-open diagnostics and AX_OTEL_DEBUG span output to this writer. It defaults to os.Stderr and must not be the command stdout.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
integration
command
|
|
|
internal
|
|
|
cmd/doccover
command
Command doccover enforces ExampleXxx coverage on ax-go's primary API surface.
|
Command doccover enforces ExampleXxx coverage on ax-go's primary API surface. |