Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9c70600
ft: Add AGENTS.md.tmpl for the generated projects
descholar-ceo Apr 18, 2026
e37f726
Add readme file
descholar-ceo Apr 18, 2026
2708a78
Fix AGENTS.md file
descholar-ceo Apr 18, 2026
6dedb16
Integrate agentic coding experience
descholar-ceo Apr 18, 2026
b25d06b
Implement phase 2
descholar-ceo Apr 18, 2026
25c2e6d
Add do workflow command
descholar-ceo Apr 18, 2026
b29b7d1
Add do workflow command
descholar-ceo Apr 18, 2026
d10ca78
Add schema command
descholar-ceo Apr 18, 2026
2e7fde1
Document new agentic integrations
descholar-ceo Apr 18, 2026
62f947e
Explain clearly agents how gofasta new tooling works
descholar-ceo Apr 18, 2026
90a2a41
Improve 'gofasta dev' command
descholar-ceo Apr 19, 2026
9c423b4
Improve 'gofasta dev' command
descholar-ceo Apr 19, 2026
6d9036a
Complete improving dev command
descholar-ceo Apr 19, 2026
7819a9b
Add debugging dashboard
descholar-ceo Apr 19, 2026
9c8d676
Add devtools
descholar-ceo Apr 19, 2026
0749242
Complete debugging dashboard
descholar-ceo Apr 19, 2026
da754cb
Add level 1-4 debugging tooling
descholar-ceo Apr 19, 2026
aab6a57
Add tracing and pprog
descholar-ceo Apr 19, 2026
c7d2595
Improve debugging tooling
descholar-ceo Apr 19, 2026
75199ca
Improve AGENTS.md documentation about debugging
descholar-ceo Apr 19, 2026
390b506
Complete agents debugging tooling
descholar-ceo Apr 19, 2026
7ae8ac6
Fix security issues
descholar-ceo Apr 19, 2026
d35f32c
Fix security issues
descholar-ceo Apr 19, 2026
f841b39
Increase test coverage
descholar-ceo Apr 19, 2026
74577f7
Increase test coverage
descholar-ceo Apr 19, 2026
db44bc1
Increase test coverage
descholar-ceo Apr 19, 2026
6dfa64a
Increase test coverage
descholar-ceo Apr 19, 2026
f9a9bd8
Increase test coverage
descholar-ceo Apr 19, 2026
3057614
Add new test files for coverage
descholar-ceo Apr 19, 2026
f6faa39
Increase code coverage
descholar-ceo Apr 20, 2026
0946e54
Increase code coverage
descholar-ceo Apr 20, 2026
2bbd34f
Fix test file namimngs
descholar-ceo Apr 21, 2026
c292094
Improve dev test
descholar-ceo Apr 21, 2026
3758365
Cover uncovered line
descholar-ceo Apr 21, 2026
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added
- **`gofasta verify`** — runs the full preflight gauntlet (gofmt, vet, golangci-lint, tests with the race detector, build, Wire drift, routes sanity) in one command. Fail-fast by default with `--keep-going` to report every result. Per-check structured JSON output via the global `--json` flag.
- **`gofasta status`** — offline project-drift report. Detects Wire-derived code out of sync with inputs, stale Swagger docs, pending migrations, uncommitted generated files, and `go.sum` freshness. Non-zero exit on any drift.
- **`gofasta inspect <Resource>`** — AST-parses a resource's model, DTOs, service interface, controller, and routes; emits a structured report so agents planning a modification see the full picture from one command instead of opening six files.
- **`gofasta config schema`** — emits a Draft-7 JSON Schema describing `config.yaml`. Shells out to the project-local `cmd/schema/` helper so the schema always matches the `gofasta` version pinned in the project's `go.mod`. Feed to VS Code YAML, JetBrains editors, or CI validators.
- **`gofasta do <workflow>`** — named development workflows chaining multiple gofasta commands: `new-rest-endpoint`, `rebuild`, `fresh-start`, `clean-slate`, `health-check`. Includes `--dry-run` for previewing chains without execution.
- **`gofasta ai <agent>`** — opt-in installer for AI coding agent configuration. Supports Claude Code, Cursor, OpenAI Codex, Aider, and Windsurf. Idempotent; `--dry-run` / `--force` supported; install history tracked in `.gofasta/ai.json`. Sub-commands: `gofasta ai list`, `gofasta ai status`.
- **Structured errors** — every CLI error now carries `{code, message, hint, docs}`. 38 stable error codes. Agents pattern-match on the code instead of regex-parsing English.
- **Global `--json` flag** — every structured-output command honors it, producing a single-line JSON document for agent consumption.
- **Post-generation auto-verify** — `gofasta g scaffold` automatically runs `go build ./...` after generation so template regressions surface immediately. Disable with `--no-verify`.
- **Generator `--dry-run`** — `gofasta g scaffold --dry-run` shows every file it would create and every patch it would apply without touching disk.
- **Per-resource controller test scaffolding** — `gofasta g scaffold` now emits a starter `<name>.controller_test.go` with smoke tests + a TODO placeholder, so generated resources are green on `go test` out of the box.
- **`AGENTS.md` in every scaffolded project** — comprehensive agent briefing (project overview, tech stack, every command, conventions, Wire gotcha walkthrough, "do not do" list, pre-commit self-check). Read automatically by Claude Code, OpenAI Codex, Cursor, Aider, and other MCP-aware agents.
- **Scaffold ships `cmd/schema/main.go`** — the 10-line helper binary that `gofasta config schema` shells out to. Also callable directly as `go run ./cmd/schema` for CI or IDE extensions.

### Fixed
- `gofasta --version` now reports the real module version for users who install via `go install`. Previously it always printed `dev` because `go install` does not apply build-time `-ldflags`. The CLI now falls back to `runtime/debug.ReadBuildInfo()` at startup to read the module version Go stamped into the binary. Pre-built binaries shipped via GitHub Releases are unaffected — they still use the `-X main.Version=<tag>` ldflag set by the release workflow.

Expand Down
98 changes: 98 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,104 @@ gofasta wire

Regenerates the Wire dependency injection code after manual changes to providers.

## Agent-friendly commands

Gofasta ships first-class integration with AI coding agents. Every command below honors the global `--json` flag for machine-parseable output, and every error carries a stable code + remediation hint + docs link.

### `gofasta verify` — one "am I done?" check

Runs the full preflight gauntlet (gofmt, vet, golangci-lint, tests with the race detector, build, Wire drift, routes) in one command. Fails fast on the first failing step; pass `--keep-going` to report every result.

```bash
gofasta verify # human table
gofasta verify --json # structured per-check JSON
gofasta verify --no-lint # skip golangci-lint on machines that don't have it
```

### `gofasta status` — project drift report

Reports whether derived artifacts (Wire, Swagger), generated files, and module state are in sync with their inputs. Complementary to `verify` — `verify` is about quality gates; `status` is about drift.

```bash
gofasta status # text table
gofasta status --json # one JSON object per check
```

### `gofasta inspect <Resource>` — resource composition at a glance

AST-parses a resource's model, DTOs, service interface, controller, and routes; emits a single structured report. Replaces opening six files by hand.

```bash
gofasta inspect User
gofasta inspect User --json | jq '.service_methods[].name'
```

### `gofasta config schema` — JSON Schema for `config.yaml`

Emits a Draft-7 JSON Schema describing `config.yaml`. Feed it to VS Code / JetBrains YAML extensions for autocomplete and inline validation, or to CI for pre-deploy checks. Shells out to a project-local `cmd/schema` helper so the schema always matches the `gofasta` version pinned in your `go.mod`.

```bash
gofasta config schema > config.schema.json

# Then, at the top of config.yaml:
# # yaml-language-server: $schema=./config.schema.json
```

### `gofasta do <workflow>` — named command chains

Pre-defined sequences of gofasta commands that together accomplish one higher-level task. Transparent (no hidden logic, each step is a command you could run by hand) but save agent round-trips and keystrokes:

```bash
gofasta do new-rest-endpoint Invoice total:float # scaffold + migrate up + swagger
gofasta do rebuild # wire + swagger
gofasta do fresh-start # init + migrate up + seed
gofasta do clean-slate # db reset + seed
gofasta do health-check # verify + status
gofasta do list # every supported workflow
```

Pass `--dry-run` to preview the chain.

### `gofasta ai <agent>` — install agent-specific configuration

Every scaffolded project ships `AGENTS.md` at the root by default (the universal file every modern agent reads). For agent-specific configuration — permission allowlists, pre-commit hooks, slash commands, conventions files — opt in with one command:

```bash
gofasta ai claude # .claude/ settings + hooks + slash commands
gofasta ai cursor # .cursor/rules/gofasta.mdc
gofasta ai codex # .codex/config.toml
gofasta ai aider # .aider.conf.yml + .aider/CONVENTIONS.md
gofasta ai windsurf # .windsurfrules
gofasta ai list # supported agents
gofasta ai status # what's currently installed in this project
```

Installs are idempotent, support `--dry-run`, and are tracked in `.gofasta/ai.json`.

### `--json` on every command

Every command that emits structured output honors the global `--json` flag, producing a single-line JSON document suitable for agent parsing, `jq` filtering, or CI consumption.

```bash
gofasta routes --json | jq '.[] | select(.method == "POST")'
gofasta --json verify | jq '.checks[] | select(.status == "fail")'
gofasta ai list --json
```

### Structured errors

Every CLI error carries `{code, message, hint, docs}` — agents pattern-match on the stable code and read the hint for the remediation. No regex-parsing English error strings.

```bash
$ gofasta --json g scaffold 2>&1 >/dev/null | jq .
{
"code": "INVALID_NAME",
"message": "missing resource name",
"hint": "pass a PascalCase resource name — e.g. `gofasta g scaffold Product`",
"docs": "https://gofasta.dev/docs/cli-reference/generate/scaffold"
}
```

## How It Works

The CLI is a standalone Go binary. It does **not** import the gofasta library — it only manipulates files on disk.
Expand Down
143 changes: 143 additions & 0 deletions internal/clierr/clierr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Package clierr defines the structured error type emitted by the CLI at
// the command boundary. Every returning error wrapped with clierr.New or
// clierr.Wrap carries a stable machine-readable code, a human-readable
// message, a remediation hint, and a documentation URL — so AI agents and
// CI systems can act on failures programmatically instead of regex-parsing
// English prose.
//
// The Error type satisfies the standard error interface, so it composes
// with errors.Is / errors.As and wrapping helpers unchanged. When the root
// command runs with --json the Execute handler renders the error via its
// MarshalJSON method; otherwise the Error() string (message plus optional
// cause) is written to stderr, identical to the pre-clierr behavior.
package clierr

import (
"encoding/json"
"errors"
"fmt"
)

// Error is a structured CLI error. Construct with New / Wrap / From — the
// helpers look up Hint and Docs from the code registry so callers don't
// have to repeat remediation text at every call site.
type Error struct {
// Code is a stable machine-readable identifier. Agents and integrations
// rely on codes for programmatic handling, so once shipped a code must
// not be renamed — only deprecated.
Code string `json:"code"`

// Message is a one-line human-readable summary of what failed. Follows
// staticcheck ST1005: lowercase, no trailing punctuation.
Message string `json:"message"`

// Hint is a short sentence describing how to recover. Looked up from
// the registry at construction time.
Hint string `json:"hint,omitempty"`

// Docs is a URL to the most relevant documentation page.
Docs string `json:"docs,omitempty"`

// Cause holds the underlying error so errors.Unwrap / errors.Is / errors.As
// work across the structured-error boundary. Not serialized directly —
// its text is folded into Message during JSON rendering via MarshalJSON.
Cause error `json:"-"`
}

// Error returns a human-readable rendering: "message" by itself, or
// "message: cause" when a cause is set. Kept short so chained errors do
// not accumulate redundant prose.
func (e *Error) Error() string {
if e == nil {
return ""
}
if e.Cause != nil {
return e.Message + ": " + e.Cause.Error()
}
return e.Message
}

// Unwrap exposes the wrapped cause so errors.Is / errors.As traverse
// through the structured layer.
func (e *Error) Unwrap() error {
if e == nil {
return nil
}
return e.Cause
}

// MarshalJSON serializes the error as {code, message, hint, docs}. The
// message includes the cause's text if one is set, so consumers reading
// the JSON do not need a separate "cause" field.
func (e *Error) MarshalJSON() ([]byte, error) {
type alias struct {
Code string `json:"code"`
Message string `json:"message"`
Hint string `json:"hint,omitempty"`
Docs string `json:"docs,omitempty"`
}
a := alias{
Code: e.Code,
Message: e.Error(),
Hint: e.Hint,
Docs: e.Docs,
}
return json.Marshal(a)
}

// New constructs a new structured error for code with message. Hint and
// Docs are looked up from the registry; callers that need to override
// either can set the field after construction.
func New(code Code, message string) *Error {
meta := lookup(code)
return &Error{
Code: string(code),
Message: message,
Hint: meta.Hint,
Docs: meta.Docs,
}
}

// Newf is New with a format string for the message.
func Newf(code Code, format string, args ...any) *Error {
return New(code, fmt.Sprintf(format, args...))
}

// Wrap wraps cause with a structured error carrying code and message.
// Use this at every `return err` site where a structured code adds
// context agents or CI can act on.
func Wrap(code Code, cause error, message string) *Error {
e := New(code, message)
e.Cause = cause
return e
}

// Wrapf is Wrap with a format string for the message.
func Wrapf(code Code, cause error, format string, args ...any) *Error {
return Wrap(code, cause, fmt.Sprintf(format, args...))
}

// From returns err as a *Error when it already is one (pass-through) or
// wraps it with code and the err's own text otherwise. Intended for use
// at command boundaries that receive an arbitrary error from a helper.
func From(code Code, err error) *Error {
if err == nil {
return nil
}
var structured *Error
if errors.As(err, &structured) {
return structured
}
return Wrap(code, err, err.Error())
}

// As is a convenience wrapper around errors.As for *clierr.Error so
// callers can unwrap without importing the errors package just for
// the assertion.
func As(err error) (*Error, bool) {
var structured *Error
if errors.As(err, &structured) {
return structured, true
}
return nil, false
}
Loading
Loading