167 lines
4.6 KiB
Cheetah
167 lines
4.6 KiB
Cheetah
# CODEX.md
|
|
|
|
Instructions for Codex when working in this workspace.
|
|
|
|
Read these files in order:
|
|
1. `CODEX.md`
|
|
2. `.core/reference/RFC-025-AGENT-EXPERIENCE.md`
|
|
3. `.core/reference/docs/RFC.md`
|
|
4. `AGENTS.md` if present
|
|
|
|
## Overview
|
|
|
|
This workspace follows RFC-025 Agent Experience (AX) design. Prefer predictable names, named Actions, Core primitives, usage-example comments, and behavioural tests over terse APIs. Use `.core/reference/*.go` as the local implementation reference.
|
|
|
|
## Core Registration Pattern
|
|
|
|
Register services through `core.New` and `WithService`, not ad hoc globals.
|
|
|
|
```go
|
|
c := core.New(
|
|
core.WithOption("name", "my-service"),
|
|
core.WithService(myservice.Register),
|
|
)
|
|
c.Run()
|
|
```
|
|
|
|
## Service Pattern
|
|
|
|
Services should be Result-native and register capabilities by name.
|
|
|
|
```go
|
|
func Register(c *core.Core) core.Result {
|
|
svc := &Service{
|
|
ServiceRuntime: core.NewServiceRuntime(c, Options{}),
|
|
}
|
|
return core.Result{Value: svc, OK: true}
|
|
}
|
|
|
|
func (s *Service) OnStartup(ctx context.Context) core.Result {
|
|
c := s.Core()
|
|
|
|
c.Action("workspace.create", s.handleWorkspaceCreate)
|
|
c.Task("workspace.bootstrap", core.Task{
|
|
Steps: []core.Step{
|
|
{Action: "workspace.create"},
|
|
},
|
|
})
|
|
|
|
return core.Result{OK: true}
|
|
}
|
|
|
|
func (s *Service) OnShutdown(ctx context.Context) core.Result {
|
|
return core.Result{OK: true}
|
|
}
|
|
```
|
|
|
|
## Core Accessors
|
|
|
|
| Accessor | Purpose |
|
|
|----------|---------|
|
|
| `c.Options()` | Input configuration |
|
|
| `c.Config()` | Runtime settings and feature flags |
|
|
| `c.Data()` | Embedded assets |
|
|
| `c.Fs()` | Filesystem I/O |
|
|
| `c.Process()` | Managed process execution |
|
|
| `c.API()` | Remote streams and protocol handles |
|
|
| `c.Action(name)` | Named callable registration and invocation |
|
|
| `c.Task(name)` | Composed Action sequence |
|
|
| `c.Entitled(name)` | Permission check |
|
|
| `c.RegistryOf(name)` | Cross-cutting registry lookup |
|
|
| `c.Cli()` | CLI command framework |
|
|
| `c.IPC()` | Message bus |
|
|
| `c.Log()` | Structured logging |
|
|
| `c.Error()` | Panic recovery |
|
|
| `c.I18n()` | Internationalisation |
|
|
|
|
## Named Actions And Tasks
|
|
|
|
Actions are the primary communication pattern. Register by name, invoke by name.
|
|
|
|
```go
|
|
c.Action("workspace.create", func(ctx context.Context, opts core.Options) core.Result {
|
|
name := opts.String("name")
|
|
path := core.JoinPath("/srv/workspaces", name)
|
|
return core.Result{Value: path, OK: true}
|
|
})
|
|
|
|
r := c.Action("workspace.create").Run(ctx, core.NewOptions(
|
|
core.Option{Key: "name", Value: "alpha"},
|
|
))
|
|
```
|
|
|
|
Use Tasks to compose orchestration declaratively.
|
|
|
|
```go
|
|
c.Task("deploy", core.Task{
|
|
Steps: []core.Step{
|
|
{Action: "docker.build"},
|
|
{Action: "docker.push"},
|
|
{Action: "deploy.ansible", Async: true},
|
|
},
|
|
})
|
|
```
|
|
|
|
## Core Primitives
|
|
|
|
Route recurring concerns through Core primitives instead of the raw standard library.
|
|
|
|
```go
|
|
var fs = (&core.Fs{}).NewUnrestricted()
|
|
|
|
statusPath := core.JoinPath("/srv/workspaces", "alpha", "status.json")
|
|
read := fs.Read(statusPath)
|
|
|
|
run := c.Process().RunIn(ctx, repoDir, "git", "log", "--oneline", "-20")
|
|
if run.OK {
|
|
output := core.Trim(run.Value.(string))
|
|
core.Print(nil, output)
|
|
}
|
|
```
|
|
|
|
## Mandatory Conventions
|
|
|
|
- Use UK English in comments and docs.
|
|
- Use `core.E("pkg.Method", "message", err)` for errors. Never use `fmt.Errorf` or `errors.New`.
|
|
- Use `c.Fs()` or a package-level `fs` helper for file I/O. Never use raw `os.ReadFile`, `os.WriteFile`, or `filepath.*`.
|
|
- Route external commands through `c.Process()`. Never import `os/exec`.
|
|
- Use Core string and path helpers such as `core.Contains`, `core.Trim`, `core.Split`, `core.Concat`, and `core.JoinPath` instead of raw `strings.*` or path concatenation.
|
|
- Prefer `core.Result{Value: x, OK: true}` over `(value, error)` pairs in Core-facing code.
|
|
- Comments should show HOW with real values, not restate the signature.
|
|
- Use predictable names such as `Config`, `Service`, and `Options`; avoid abbreviations.
|
|
- Keep paths self-describing. Directory names should tell an agent what they contain.
|
|
- Prefer templates for recurring generated files and config shapes.
|
|
|
|
## AX Quality Gates
|
|
|
|
Treat these imports as review failures in production Go code:
|
|
|
|
- `os`
|
|
- `os/exec`
|
|
- `fmt`
|
|
- `log`
|
|
- `errors`
|
|
- `encoding/json`
|
|
- `path/filepath`
|
|
- `strings`
|
|
- `unsafe`
|
|
|
|
## Testing
|
|
|
|
Use AX test naming and keep example coverage close to the source.
|
|
|
|
```text
|
|
TestFile_Function_Good
|
|
TestFile_Function_Bad
|
|
TestFile_Function_Ugly
|
|
```
|
|
|
|
Where practical, keep one focused `_example_test.go` alongside each source file so the tests double as usage documentation.
|
|
|
|
## Build & Test
|
|
|
|
```bash
|
|
go build ./...
|
|
go test ./... -count=1 -timeout 60s
|
|
go vet ./...
|
|
```
|