go/docs/pkg/PACKAGE_STANDARDS.md
Snider 2d52b83f60 docs: rewrite documentation suite against AX spec
Codex-authored docs covering primitives, commands, messaging,
lifecycle, subsystems, and getting started — all using the current
DTO/Options/Result API with concrete usage examples.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 10:05:04 +00:00

3 KiB
Raw Blame History

AX Package Standards

This page describes how to build packages on top of CoreGO in the style described by RFC-025.

1. Prefer Predictable Names

Use names that tell an agent what the thing is without translation.

Good:

  • RepositoryService
  • RepositoryServiceOptions
  • WorkspaceCountQuery
  • SyncRepositoryTask

Avoid shortening names unless the abbreviation is already universal.

2. Put Real Usage in Comments

Write comments that show a real call with realistic values.

Good:

// Sync a repository into the local workspace cache.
// svc.SyncRepository("core-go", "/srv/repos/core-go")

Avoid comments that only repeat the signature.

3. Keep Paths Semantic

If a command or template lives at a path, let the path explain the intent.

Good:

deploy/to/homelab
workspace/create
template/workspace/go

That keeps the CLI, tests, docs, and message vocabulary aligned.

4. Reuse CoreGO Primitives

At Core boundaries, prefer the shared shapes:

  • core.Options for lightweight input
  • core.Result for output
  • core.Service for lifecycle registration
  • core.Message, core.Query, core.Task for bus protocols

Inside your package, typed structs are still good. Use ServiceRuntime[T] when you want typed package options plus a Core reference.

type repositoryServiceOptions struct {
	BaseDirectory string
}

type repositoryService struct {
	*core.ServiceRuntime[repositoryServiceOptions]
}

5. Prefer Explicit Registration

Register services and commands with names and paths that stay readable in grep results.

c.Service("repository", core.Service{...})
c.Command("repository/sync", core.Command{...})

6. Use the Bus for Decoupling

When one package needs another packages behavior, prefer queries and tasks over tight package coupling.

type repositoryCountQuery struct{}
type syncRepositoryTask struct {
	Name string
}

That keeps the protocol visible in code and easy for agents to follow.

7. Use Structured Errors

Use core.E, core.Wrap, and core.WrapCode.

return core.Result{
	Value: core.E("repository.Sync", "git fetch failed", err),
	OK:    false,
}

Do not introduce free-form fmt.Errorf chains in framework code.

8. Keep Testing Names Predictable

Follow the repository pattern:

  • _Good
  • _Bad
  • _Ugly

Example:

func TestRepositorySync_Good(t *testing.T) {}
func TestRepositorySync_Bad(t *testing.T) {}
func TestRepositorySync_Ugly(t *testing.T) {}

9. Prefer Stable Shapes Over Clever APIs

For package APIs, avoid patterns that force an agent to infer too much hidden control flow.

Prefer:

  • clear structs
  • explicit names
  • path-based commands
  • visible message types

Avoid:

  • implicit global state unless it is truly a default service
  • panic-hiding constructors
  • dense option chains when a small explicit struct would do

10. Document the Current Reality

If the implementation is in transition, document what the code does now, not the API shape you plan to have later.

That keeps agents correct on first pass, which is the real AX metric.