Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# AGENTS.md

## Command pattern - always use RegisterCLICommand

All new commands must use the struct-based pattern.
**Do not copy the old flat `var cmd = &cobra.Command{...}` commands** - they
exist in `cmd/storage/`, `cmd/dns/`, `cmd/dbaas/` and are legacy.

Read this file before writing any new command:
`cmd/aiservices/deployment/deployment_create.go`

Skeleton:

```go
type myResourceCreateCmd struct {
exocmd.CliCommandSettings `cli-cmd:"-"`

_ bool `cli-cmd:"create"`

Name string `cli-arg:"#" cli-usage:"NAME"` // required positional
Tag string `cli-arg:"?" cli-usage:"TAG"` // optional positional
Zone string `cli-short:"z" cli-usage:"zone"` // becomes --zone / -z flag
}

func (c *myResourceCreateCmd) CmdAliases() []string { return exocmd.GCreateAlias }
func (c *myResourceCreateCmd) CmdShort() string { return "Create a resource" }
func (c *myResourceCreateCmd) CmdLong() string { return "..." }

func (c *myResourceCreateCmd) CmdPreRun(cmd *cobra.Command, args []string) error {
exocmd.CmdSetZoneFlagFromDefault(cmd)
return exocmd.CliCommandDefaultPreRun(c, cmd, args)
}

func (c *myResourceCreateCmd) CmdRun(_ *cobra.Command, _ []string) error {
// c.Name, c.Zone are already populated here
return nil
}

func init() {
cobra.CheckErr(exocmd.RegisterCLICommand(parentCmd, &myResourceCreateCmd{
CliCommandSettings: exocmd.DefaultCLICmdSettings(),
}))
}
```

Supported struct tags:

| Tag | Purpose |
|---|---|
| `cli-cmd:"-"` | Exclude field from CLI processing |
| `cli-cmd:"name"` | Sets the cobra command name (use on a `_ bool` field) |
| `cli-arg:"#"` | Required positional argument |
| `cli-arg:"?"` | Optional positional argument; `[]string` becomes variadic |
| `cli-flag:"flag-name"` | Override the auto-derived kebab-case flag name |
| `cli-short:"z"` | Single-character shorthand |
| `cli-usage:"text"` | Flag usage string; also used as positional arg label in help |
| `cli-hidden:""` | Mark flag hidden |
| `cli-deprecated:"msg"` | Mark flag deprecated |

Supported field types: `string`, `int64`, `bool`, `[]string`, `map[string]string`.
Any other type panics at startup.

Global alias vars to use for `CmdAliases()`:
`exocmd.GListAlias`, `GShowAlias`, `GCreateAlias`, `GDeleteAlias`, `GRemoveAlias`.

## Folder layout

New command group:

```
cmd/<domain>/<subdomain>/
<subdomain>.go <- var Cmd; init -> parent.AddCommand(Cmd)
<subdomain>_list.go
<subdomain>_show.go
<subdomain>_create.go
<subdomain>_delete.go
<subdomain>_list_test.go
...
```

Then add a blank import to `cmd/subcommands/init.go` - nothing else needs wiring.

## Tests

Tests live in the same package (white-box). Construct the struct directly and
call `CmdRun(nil, nil)`. Use `pkg/testutils` for HTTP test servers and client
setup. See `cmd/aiservices/deployment/deployment_create_test.go`.

## File header on every AI-touched file

Add a comment at the top of every file you create or modify. Use the
appropriate syntax for the language, and pick the right verb:

```go
// AI-generated by claude-sonnet-4.6 - not reviewed yet // new file
// AI-modified by claude-sonnet-4.6 - not reviewed yet // existing file
```
```yaml
# AI-generated by claude-sonnet-4.6 - not reviewed yet
# AI-modified by claude-sonnet-4.6 - not reviewed yet
```
```html
<!-- AI-generated by claude-sonnet-4.6 - not reviewed yet -->
<!-- AI-modified by claude-sonnet-4.6 - not reviewed yet -->
```

The reviewer removes the line once they have read and approved the file.
It must be the very first line (before `package`, shebangs, etc.) except
where the language requires otherwise (e.g. after `<?xml` declarations).

## Marking AI-assisted commits and PRs

Add these trailers to every commit that contains agent-generated code:

AI-assisted: true
Co-authored-by: copilot-swe-agent <203248971+copilot-swe-agent@users.noreply.github.com>

This makes AI-touched commits greppable across history:

git log --grep="AI-assisted"

and shows Copilot as a co-author in GitHub's commit view.

For PRs, append this footer to the description (after a `---`), listing only categories that apply:

```
> [!NOTE]
> AI assistance: PR description, test scaffolding, boilerplate code.
```

Omit categories that don't apply. Omit the footer entirely if AI contributed nothing.

## Before opening a PR or issue

Use the existing templates - don't replace them with free-form text:
- PRs: `.github/pull_request_template.md`
- Issues: `.github/ISSUE_TEMPLATE/` (bug-report, feature_request, other_request)

Keep every heading, fill each section in.

## Before opening a PR

```
make build
make test-verbose
golangci-lint run --timeout 4m
```

Update `CHANGELOG.md` under `## Unreleased` with the PR number.