From b909e4ecf5d60ec36b146eb4ccfb7aa04d2a896e Mon Sep 17 00:00:00 2001 From: Jeppe Lillevang Salling Date: Sat, 18 Jul 2026 01:26:06 +0200 Subject: [PATCH] docs: polish README and fix staleness across docs/ Documentation quality pass over the README and docs/ tree. No behavior changes. README: - Tighter intro that leads with what the tool is and does; fix "Claude Cowork" capitalization. - New Quickstart section (the two primary commands) near the top. - De-duplicate "What it's for" against the Quickstart; keep the non-destructive `--agents-only` point and the sandbox/verify principles. - Move a slimmed Documentation index below the Flavors table (the table already links each flavor doc) and add the missing releases.md pointer. Accuracy fixes (the `iac` flavor was added but several docs predate it): - docs/cli.md: "six subcommands" -> seven; add `iac` to the list-flavors example and the unknown-flavor error example. - docs/engine/flavor-hooks.md: "all three code flavors" -> four (iac). - docs/README.md: add flavors/iac.md to the layout tree; mark all flavor docs done; the backlog is now just the four engine-capability docs. Stale source line refs refreshed to current locations (scaffold.go grew to 513 lines): Run 31->62, createSymlinks 209->335, NextSteps print 272-289->printNextSteps:470, codeFlavorSymlinks registry.go 70-76->145-151, and the flavor.go field/type refs in flavor-hooks.md and claude-cowork.md. Verified example output against the built binary (list-flavors, the unknown-flavor error, the seven-command help). TestHelpFlagsMatchDocs and the full test suite pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 50 +++++++++++++++++------------------ docs/README.md | 35 +++++++++++------------- docs/cli.md | 7 ++--- docs/engine/flavor-hooks.md | 10 +++---- docs/flavors/claude-cowork.md | 2 +- 5 files changed, 50 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 1d99f6f..c4c2a49 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,28 @@ # agent-init -`agent-init` adds an agentic development workflow to a Go, TypeScript, or Infrastructure-as-Code project — primarily by enhancing one you already have, optionally by bootstrapping a new repo from scratch. +`agent-init` sets a repository up for sandboxed agentic development. It drops in a devcontainer, an `AGENTS.md`/`CLAUDE.md` house-rules pair, a `check.sh` "done-gate", a `Justfile`, pre-commit hooks, and a codebase map — all tuned to a chosen project flavor. -It also supports project management workspaces, by bootstrapping agents and folder structures as well as MCP integrations for Azure DevOps, Jira or GitHub. +The primary use is **adding this envelope to a project you already have**; it can also bootstrap a fresh repo from scratch. Beyond code, it scaffolds two non-code workspaces: a **project-management** workspace (epics, decisions, stakeholders, plus MCP tracker integrations for Jira, Azure DevOps, or GitHub) and a **Claude Cowork** folder for document-centred analysis and design work. -In addition you can bootstrap a workspace for claude cowork, useful for projects centered around documents, analysis and design rather than implementation. +## Quickstart -## Documentation - -This README is the front door. The full reference lives under [`docs/`](./docs/): - -- [`docs/README.md`](./docs/README.md) — the docs index and per-feature documentation convention. -- [`docs/cli.md`](./docs/cli.md) — full CLI reference: every subcommand, flag, and exit behavior. -- [`docs/engine/flavor-hooks.md`](./docs/engine/flavor-hooks.md) — the per-flavor engine hooks (`Symlinks`, `NextSteps`, `CommonTemplates`) that let one engine serve code and non-code flavors. +```bash +# Add the agentic envelope to an existing Go CLI — none of your source is touched. +agent-init init go-cli --agents-only ~/repos/my-cli -One page per flavor: +# Or scaffold a brand-new project from a flavor. +agent-init init go-cli ./my-new-tool -- [`docs/flavors/fullstack.md`](./docs/flavors/fullstack.md) — TypeScript/Node frontend + backend, Playwright recording, OpenAPI clients. -- [`docs/flavors/go-cli.md`](./docs/flavors/go-cli.md) — Go command-line tool; includes a worked `--agents-only` example. -- [`docs/flavors/go-backend.md`](./docs/flavors/go-backend.md) — Go HTTP backend with `/healthz`. -- [`docs/flavors/iac.md`](./docs/flavors/iac.md) — combined Terraform + Ansible scaffold. -- [`docs/flavors/claude-cowork.md`](./docs/flavors/claude-cowork.md) — OneDrive-backed document-collaboration workspace. -- [`docs/flavors/project-management.md`](./docs/flavors/project-management.md) — project-management workspace; ships five skills and tracker integrations. +# See every flavor, or drill into any command. +agent-init list-flavors +agent-init --help +``` ## What it's for -The primary use case is **adding agents to existing projects**. Most code already exists. Run: - -```bash -agent-init init --agents-only ./your-existing-repo -``` - -…and the scaffold drops in just the agentic envelope — a devcontainer, an `AGENTS.md`/`CLAUDE.md` pair (the agent's house rules), helper scripts, a `Justfile`, and pre-commit hooks — **without touching** your `go.mod`, `package.json`, `main.go`, or any existing source. The "fresh project" mode (omit `--agents-only`) is supported and useful when you genuinely are starting from zero, but it's the secondary path. +Adding agents to a project you already have is the main path, and the scaffold is careful about it. `--agents-only` drops in just the envelope — devcontainer, `AGENTS.md`/`CLAUDE.md` house rules, helper scripts, `Justfile`, pre-commit hooks — **without touching** your `go.mod`, `package.json`, `main.go`, or any existing source. Omit the flag and you also get the flavor's full fresh-project layout, useful when you're starting from zero. -Two things this is trying to enforce: +Two things the envelope is built to enforce: - **Sandbox the agent.** The devcontainer is the work surface. Agents run inside it with a bounded toolchain (Go, Node, lint, security scanners — whatever the chosen flavor needs) and write only into the mounted workspace. Credentials, host SSH keys, and cloud configs are explicit opt-in mounts — commented out in `devcontainer.json` by default so the agent doesn't pick them up unless you choose to share them. - **Force agents to verify.** Every scaffolded project ships a `check.sh` "done-gate" that runs codemap regeneration, formatting, linting, type-checking, tests, and (per flavor) cross-builds, vulnerability scans, or security scans. The agent's contract — encoded in the generated `AGENTS.md` — is: don't declare a task complete until `./.agent/scripts/check.sh` passes. This is the simplest mechanism we've found that stops agents from cutting work short with "I think it's done." @@ -49,6 +38,17 @@ Two things this is trying to enforce: | [`project-management`](./docs/flavors/project-management.md) | Project-management workspace (epics, meetings, decisions, stakeholders, time plans). Ships five skills (`/intake-meeting`, `/break-down-epic`, `/log-decision`, `/track-stakeholder`, `/sync-tracker`) and supports MCP tracker integrations via `agent-init add-tracker {jira\|ado\|gh}`. | | [`iac`](./docs/flavors/iac.md) | Combined Terraform + Ansible scaffold. Ships `terraform/` (root module, `modules/`) and `ansible/` (`inventory/`, `playbooks/`, `roles/`) trees, a devcontainer with `terraform` + `tflint` + `tfsec` + `trivy` + `ansible-core` + `ansible-lint` + `yamllint`, and a Justfile whose recipes auto-detect which toolchain is present. Cloud-credential and `~/.ssh` mounts are commented out by default with a warning. | +## Documentation + +This README is the front door. The full reference lives under [`docs/`](./docs/): + +- [`docs/cli.md`](./docs/cli.md) — full CLI reference: every subcommand, flag, and exit behavior. +- [`docs/engine/flavor-hooks.md`](./docs/engine/flavor-hooks.md) — the per-flavor engine hooks (`Symlinks`, `NextSteps`, `CommonTemplates`) that let one engine serve code and non-code flavors. +- [`docs/engine/releases.md`](./docs/engine/releases.md) — the tag-driven release and build-provenance flow. +- [`docs/README.md`](./docs/README.md) — the docs index and per-feature documentation convention. + +Each flavor has its own page under [`docs/flavors/`](./docs/flavors/), linked from the table above. + ## Build ```bash diff --git a/docs/README.md b/docs/README.md index f32b7eb..c5fc634 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,38 +23,33 @@ docs/ ├── cli.md # subcommands + flags (DONE) ├── engine/ │ ├── flavor-hooks.md # Symlinks, NextSteps, CommonTemplates (DONE) -│ ├── templates.md # .tmpl content substitution -│ ├── path-templating.md -│ ├── common-overlay.md -│ ├── done-gate.md -│ └── releases.md # tag-driven release flow (DONE) +│ ├── releases.md # tag-driven release flow (DONE) +│ ├── templates.md # .tmpl content substitution (TODO) +│ ├── path-templating.md # {{.ProjectName}} in file paths (TODO) +│ ├── common-overlay.md # common/ fallback layer (TODO) +│ └── done-gate.md # what check.sh runs downstream (TODO) └── flavors/ + ├── fullstack.md # (DONE) + ├── go-cli.md # (DONE — worked --agents-only example) + ├── go-backend.md # (DONE) + ├── iac.md # (DONE — Terraform + Ansible) ├── claude-cowork.md # (DONE) - ├── project-management.md # (DONE — with worked examples) - ├── fullstack.md - ├── go-cli.md - └── go-backend.md + └── project-management.md # (DONE — worked skill examples) ``` -Not all of these exist yet. The backlog below lists what's needed. +Every flavor and subcommand is documented. The four engine docs marked `TODO` are the remaining gap; the backlog below tracks them. ## Backlog -Features that exist in the code but don't yet have a doc entry. The next agent to touch one of these is on the hook to write its doc. +Features that exist in the code but don't yet have a doc entry. The next agent to touch one of these is on the hook to write its doc. Every flavor is documented; the remaining gap is four engine-capability docs. ### Engine -- [ ] `engine/templates.md` — `.tmpl` opt-in for content substitution. Source: [internal/scaffold/scaffold.go:155-167](../internal/scaffold/scaffold.go#L155-L167). -- [ ] `engine/path-templating.md` — `{{.ProjectName}}` in file paths; the `.tmpl` workaround for `cmd/{{.ProjectName}}/` directories. Source: [internal/scaffold/scaffold.go:169-182](../internal/scaffold/scaffold.go#L169-L182). -- [ ] `engine/common-overlay.md` — `internal/flavors/common/` as a fallback layer; flavor-first conflict resolution. Source: [internal/flavors/common/flavor.go](../internal/flavors/common/flavor.go), [internal/scaffold/scaffold.go:80-114](../internal/scaffold/scaffold.go#L80-L114). +- [ ] `engine/templates.md` — `.tmpl` opt-in for content substitution. Source: [scaffold.go:306-318](../internal/scaffold/scaffold.go#L306-L318) (content render) and the `.tmpl` strip in [walkLayer, scaffold.go:163](../internal/scaffold/scaffold.go#L163). +- [ ] `engine/path-templating.md` — `{{.ProjectName}}` in file paths; the `.tmpl` workaround for `cmd/{{.ProjectName}}/` directories. Source: [renderPath, scaffold.go:320](../internal/scaffold/scaffold.go#L320). +- [ ] `engine/common-overlay.md` — `internal/flavors/common/` as a fallback layer; flavor-first conflict resolution. Source: [Overlay, scaffold.go:102](../internal/scaffold/scaffold.go#L102) and [walkLayer, scaffold.go:163](../internal/scaffold/scaffold.go#L163). - [ ] `engine/done-gate.md` — what `check.sh` runs in scaffolded projects and how `maybe_step` skips missing recipes. Source: [internal/flavors/common/templates/.agent/scripts/check.sh](../internal/flavors/common/templates/.agent/scripts/check.sh). -### Flavors - -- [x] `flavors/fullstack.md` — TypeScript/Node frontend + backend; supports `--agents-only`. -- [x] `flavors/go-cli.md` — fresh-project Go CLI scaffold + `--agents-only` mode for existing projects. -- [x] `flavors/go-backend.md` — Go HTTP backend scaffold + `--agents-only` mode. - ## Style - Plain prose. No emojis. No marketing adjectives ("powerful", "elegant", "seamless"). diff --git a/docs/cli.md b/docs/cli.md index ca08882..48f0926 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,6 +1,6 @@ # CLI -`agent-init` is a small CLI with six subcommands. Source: [internal/cli/cli.go](../internal/cli/cli.go). +`agent-init` is a small CLI with seven subcommands. Source: [internal/cli/cli.go](../internal/cli/cli.go). ``` agent-init init [flavor] [target-dir] @@ -44,7 +44,7 @@ agent-init ./my-tool # path-only form; implies fullstack - With `--visibility=local`: after the scaffold is written (symlinks and `git init` included — visibility controls tracking, not creation), a fenced block is appended to the committed `.gitignore`, creating it if absent. The block covers the agentic envelope (`.agent/`, `/AGENTS.md`, `/CLAUDE.md`, `.devcontainer/`, `/Justfile`, `.pre-commit-config.yaml`). It is delimited by `# >>> agent-init (private) >>>` / `# <<< agent-init <<<` markers, so re-running replaces it in place (never duplicates) and it can be removed by hand to undo. `init` prints the absolute path it edited. `--dry-run` previews the path and block, writing nothing. Block management lives in [internal/gitignore](../internal/gitignore/gitignore.go). - With `--visibility=hidden` (or `--private`): the identical block is written to `.git/info/exclude` instead of `.gitignore`, creating the `.git/info` directory if absent. `.git/info/exclude` is git's per-repo, never-committed ignore file, so a teammate cloning the repo sees no agent-init trace. The mode is otherwise the same as `local`: idempotent in-place replacement, the absolute path is announced, `--dry-run` previews and writes nothing, and the symlink trio is still created (visibility controls tracking, not creation). Because `.git/info/exclude` does not appear in `git diff`, remember to remove the fenced block by hand to undo. - With `--visibility=global-default`: the **same** fenced block is written to your machine-wide git excludes file instead of a repo file, so the scaffold is ignored in **every** git repository on the machine. **This is action-at-a-distance.** The command prints a loud machine-wide warning on stderr and always announces the absolute path it edited. The target file is `git config --global core.excludesfile` if set (honored even when it points somewhere unusual); otherwise `${XDG_CONFIG_HOME:-~/.config}/git/ignore`, which is created and set as `core.excludesfile` only when no global excludes is configured. No other global-config key is touched. Idempotent (the marked block is replaced in place) and reversible (remove the block by hand). `--dry-run` resolves and prints the target path and the block but writes nothing and touches no git config. To commit the scaffold openly in a specific repo despite the global default, force-add it there — `git add -f .agent AGENTS.md CLAUDE.md .devcontainer Justfile .pre-commit-config.yaml` — since git never re-ignores a tracked file (gitignore negation cannot re-include a file under an excluded directory, so force-add is the documented override). The global excludes-file resolution lives in [internal/gitconfig](../internal/gitconfig/gitconfig.go); the block content is shared from [internal/gitignore](../internal/gitignore/gitignore.go). -- Source: [scaffold.go:31](../internal/scaffold/scaffold.go#L31) (`Run`), [cli.go:applyVisibility](../internal/cli/cli.go). +- Source: [scaffold.go:62](../internal/scaffold/scaffold.go#L62) (`Run`), [cli.go:applyVisibility](../internal/cli/cli.go). ### Output @@ -137,6 +137,7 @@ claude-cowork Shared document-collaboration folder ... fullstack TypeScript/Node frontend and backend ... go-backend Go HTTP backend scaffold ... go-cli Go command-line tool scaffold ... +iac Combined Terraform + Ansible scaffold ... project-management Project-management workspace ... ``` @@ -229,7 +230,7 @@ Invalid input prints a short hint and points the user at `--help`, then exits non-zero. Specific cases worth knowing: - **Unknown subcommand** prints `unknown command "foo"` followed by `Run 'agent-init --help' for usage`. -- **Unknown flavor** prints the list of known flavors: `unknown flavor "foo" (known: claude-cowork, fullstack, go-backend, go-cli, project-management)`, then the init `--help` hint. +- **Unknown flavor** prints the list of known flavors: `unknown flavor "foo" (known: claude-cowork, fullstack, go-backend, go-cli, iac, project-management)`, then the init `--help` hint. - **Unknown tracker** prints the list of known trackers, then the add-tracker `--help` hint. - **`add-tracker` on a target without `.mcp.json`** suggests the corresponding `init` command. diff --git a/docs/engine/flavor-hooks.md b/docs/engine/flavor-hooks.md index 72f85fb..d442b5f 100644 --- a/docs/engine/flavor-hooks.md +++ b/docs/engine/flavor-hooks.md @@ -6,9 +6,9 @@ Per-flavor customization points on the `Flavor` struct that let one engine suppo | Field on `Flavor` | Type | Default when nil/empty | Source | |---|---|---|---| -| `Symlinks` | `[]Symlink` | No symlinks created | [flavor.go:37-40](../../internal/flavors/flavor.go#L37-L40) | +| `Symlinks` | `[]Symlink` | No symlinks created | [flavor.go:25](../../internal/flavors/flavor.go#L25) (field); [flavor.go:55-58](../../internal/flavors/flavor.go#L55-L58) (type) | | `NextSteps` | `func(target string) string` | Default code-project message (devcontainer + just check) | [flavor.go:30](../../internal/flavors/flavor.go#L30) | -| `CommonTemplates` | `fs.FS` | No common-overlay layer walked | [flavor.go:18-19](../../internal/flavors/flavor.go#L18-L19) | +| `CommonTemplates` | `fs.FS` | No common-overlay layer walked | [flavor.go:22](../../internal/flavors/flavor.go#L22) | ## Symlinks @@ -19,9 +19,9 @@ type Symlink struct { } ``` -`createSymlinks` ([scaffold.go:209](../../internal/scaffold/scaffold.go#L209)) iterates `opts.Flavor.Symlinks` and creates each in order. `Target` is written verbatim — relative-path conventions like `.agent/AGENTS.md` survive into the scaffolded tree. The engine creates parent directories as needed but won't replace existing directories with symlinks (returns an error instead). +`createSymlinks` ([scaffold.go:335](../../internal/scaffold/scaffold.go#L335)) iterates `opts.Flavor.Symlinks` and creates each in order. `Target` is written verbatim — relative-path conventions like `.agent/AGENTS.md` survive into the scaffolded tree. The engine creates parent directories as needed but won't replace existing directories with symlinks (returns an error instead). -**Code-flavor convention.** All three code flavors share `codeFlavorSymlinks()` in [registry.go:70-76](../../internal/flavors/registry.go#L70-L76): +**Code-flavor convention.** All four code flavors (`fullstack`, `go-cli`, `go-backend`, `iac`) share `codeFlavorSymlinks()` in [registry.go:145-151](../../internal/flavors/registry.go#L145-L151): ```go {Path: "AGENTS.md", Target: ".agent/AGENTS.md"}, @@ -39,7 +39,7 @@ Four entry points (root `AGENTS.md`, root `CLAUDE.md`, `.agent/AGENTS.md`, `.age NextSteps func(target string) string ``` -If set, the engine calls `flavor.NextSteps(target)` after writing and prints the returned string verbatim ([scaffold.go:272-289](../../internal/scaffold/scaffold.go#L272-L289)). If nil, the engine prints its default code-project message — devcontainer up, devcontainer exec, just check. +If set, the engine calls `flavor.NextSteps(target)` after writing and prints the returned string verbatim (`printNextSteps`, [scaffold.go:470](../../internal/scaffold/scaffold.go#L470)). If nil, the engine prints its default code-project message — devcontainer up, devcontainer exec, just check. The signature takes the scaffold target so flavors can interpolate paths into shell commands the user is about to copy: diff --git a/docs/flavors/claude-cowork.md b/docs/flavors/claude-cowork.md index 61a2068..00cc29e 100644 --- a/docs/flavors/claude-cowork.md +++ b/docs/flavors/claude-cowork.md @@ -50,7 +50,7 @@ The post-scaffold message ([flavor.go:25-43](../../internal/flavors/claudecowork These differences are flavor-controlled, not engine-hardcoded. The relevant engine hooks: -- **Symlinks** are declarative via `Flavor.Symlinks` ([flavor.go:25](../../internal/flavors/flavor.go#L25); type definition at [flavor.go:37-40](../../internal/flavors/flavor.go#L37-L40)); claude-cowork sets it to nil. +- **Symlinks** are declarative via `Flavor.Symlinks` ([flavor.go:25](../../internal/flavors/flavor.go#L25); type definition at [flavor.go:55-58](../../internal/flavors/flavor.go#L55-L58)); claude-cowork sets it to nil. - **Next-steps message** is a per-flavor `NextSteps func(target string) string` hook ([flavor.go:26-30](../../internal/flavors/flavor.go#L26-L30)); claude-cowork supplies its own. - **`CommonTemplates`** is optional; flavors that don't set it skip the overlay.