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>
138 lines
3 KiB
Markdown
138 lines
3 KiB
Markdown
# 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:
|
||
|
||
```go
|
||
// 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:
|
||
|
||
```text
|
||
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.
|
||
|
||
```go
|
||
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.
|
||
|
||
```go
|
||
c.Service("repository", core.Service{...})
|
||
c.Command("repository/sync", core.Command{...})
|
||
```
|
||
|
||
## 6. Use the Bus for Decoupling
|
||
|
||
When one package needs another package’s behavior, prefer queries and tasks over tight package coupling.
|
||
|
||
```go
|
||
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`.
|
||
|
||
```go
|
||
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:
|
||
|
||
```go
|
||
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.
|