diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..32fe7f4 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,18 @@ +{ + "extraKnownMarketplaces": { + "cross-review": { + "source": { + "source": "github", + "repo": "raghubetina/cross-review" + } + } + }, + "enabledPlugins": { + "codex-review@cross-review": true + }, + "attribution": { + "commit": "", + "pr": "", + "sessionUrl": false + } +} diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 0000000..5388868 --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,6 @@ +[marketplaces.cross-review] +source_type = "git" +source = "https://github.com/raghubetina/cross-review.git" + +[plugins."claude-review@cross-review"] +enabled = true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..d590bcb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ +## Summary + + + +Docs: + + + +## Validation + +- `npm audit`: +- `npm run check`: diff --git a/.gitignore b/.gitignore index 721204b..cb5cbff 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ coverage/ node_modules/ tmp/ *.tgz +/.claude/worktrees/ diff --git a/AGENTS.md b/AGENTS.md index b0ddbd6..08c592c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,15 +5,17 @@ handled-error recovery in `docs/errors.md`, publication mechanics in `RELEASING. `CHANGELOG.md`. When behavior changes, update its owning document in the same change. - Verify with `npm run check`, which takes about 30 seconds. A fresh checkout needs `npm ci --ignore-scripts` first. +- Follow `CONTRIBUTING.md` for commit messages, pull request bodies, review setup, and landing. - To add a command, follow `docs/commands.md#add-a-command`. To change the version, follow `RELEASING.md#prepare-the-version-pull-request`, which includes the `CHANGELOG.md` entry. - Sibling repositories: `firstdraft/firstdraft` (private) owns the Service API and Plan format; `firstdraft/skills` owns the Skill and plugin packaging. - Changes to the accepted API-contract range, accepted Plan formats, command names or flags, handled `error` values, - exit statuses, `AGENTS.md`, `CLAUDE.md`, or `RELEASING.md` get an independent review through cross-review: - `codex-review` from Claude Code, `$claude-review` from Codex. Pass the service repository's `docs/review-focus.md` - as `--focus-file`, fetched with `gh api` when no sibling checkout exists. Put the reviewer, session id, and verdict - in the pull request body, and leave the findings out. + exit statuses, `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`, `RELEASING.md`, `.claude/settings.json`, or + `.codex/config.toml` get an independent review through cross-review: `codex-review` from Claude Code, + `$claude-review` from Codex. Pass the service repository's `docs/review-focus.md` as `--focus-file`, fetched + with `gh api` when no sibling checkout exists. Put the reviewer, session id, and verdict in the pull request + body, and leave the findings out. - `firstdraft plan compile` defaults to local output in the current directory. GitHub publication requires `--github`; Codespaces is a fallback. Keep Skill callers and recovery instructions aligned with this boundary. - The service repository coordinates releases and owns their approval and smoke policy. One approved coordinated diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..83b4057 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,101 @@ +# Contributing + +This page covers checks, commit messages, pull requests, independent review, and landing for the First Draft CLI. +[AGENTS.md](AGENTS.md) routes agent work and lists the changes that need independent review; the +[documentation map](docs/README.md) routes everything else. The commit, pull request, review, and landing rules +below also apply in `firstdraft/skills` and the private service repository, `firstdraft/firstdraft`. When you change +one of them, change it in all three `CONTRIBUTING.md` pages. + +## Checks + +Use the Node.js and npm versions pinned in `.tool-versions`. Before committing, run the sequence in +[Work on the repository](docs/README.md#work-on-the-repository): `npm ci --ignore-scripts` in a fresh checkout or +worktree, then `npm audit` and `npm run check`. Hosted CI repeats the tests and package checks on Node.js 22.0 on +Linux, Windows, and macOS. + +This repository keeps Codex's default `workspace-write` sandbox, which has no network access. Inside it, `npm audit` +cannot reach the npm registry, `npm ci` fails unless every package is already in your npm cache, and `npm run check` +fails because several tests start a local HTTP server on `127.0.0.1`. When Codex asks to rerun one of these commands +outside the sandbox, check the command and approve it. The sandbox also keeps `.git` read-only, so Codex asks before +it commits. + +## Commit messages + +- Write the subject in the imperative mood, in 50 characters or fewer. +- Wrap the body at 72 columns or fewer, and explain why the change was needed; the diff shows what changed. +- Squash the branch to one reviewable commit before merging, as [Landing](#landing) describes. +- Do not mention an agent. Add no `Co-authored-by` or other agent trailer to a commit, and no "Generated with" line + to a pull request body. The tracked `.claude/settings.json` turns off Claude Code's attribution. Codex adds them + when attribution is on in your Codex account settings, which override repository instructions; turn it off + there. If Codex adds a `Co-authored-by: Codex ` trailer to a commit, remove it before + pushing. If it adds the line `Generated with [Codex](https://openai.com/codex/).` to a pull request body, remove + it before opening the pull request, or edit the body if Codex opened it. + +## Pull requests + +The pull request body carries: + +- a summary of what changed and why; +- one line: `Docs: updated X` or `Docs: none, because ...`; and +- when [AGENTS.md](AGENTS.md) requires independent review, one line, `Review: , session , `, + with the findings left out. + +Use GitHub closing keywords only for completed Issues: even `does not close #123` closes #123. Say the remainder is +tracked in open Issue #123 instead. The [pull request template](.github/pull_request_template.md) holds these fields. + +## Independent review + +The reviewer is the other vendor's agent, through [cross-review](https://github.com/raghubetina/cross-review): Codex +reviews from Claude Code, and Claude Code reviews from Codex. Install both and sign in to each (`claude auth login` +and `codex login`). In Claude Code, ask for a Codex review or run `/codex-review:codex-review`; in Codex, use +`$claude-review`. Neither is a shell command. + +- **Claude Code:** the tracked `.claude/settings.json` registers the cross-review marketplace and enables + `codex-review`. It loads once you accept the workspace-trust prompt for the main checkout; linked worktrees use + that trust. A headless `claude -p` run loads it only where you have already trusted the checkout. +- **Codex:** the tracked `.codex/config.toml` declares the marketplace and enables `$claude-review` in a trusted + project. The first trusted session fetches the plugin and the next one loads it; + `codex plugin marketplace upgrade cross-review` fetches it at once. In the Codex desktop app, quit and reopen it + after the first fetch. + +If the tracked configuration does not load a plugin, install it yourself: + +```sh +claude plugin marketplace add raghubetina/cross-review +claude plugin install codex-review@cross-review +codex plugin marketplace add raghubetina/cross-review +codex plugin add claude-review@cross-review +``` + +To run a review: + +1. Start a `new` session over the branch, such as `new branch main`, or over an explicit range with + `new range ..`. +2. Pass the service repository's `docs/review-focus.md` with `--focus-file`, from a sibling `firstdraft/firstdraft` + checkout or fetched into the ignored `tmp/`: + + ```sh + mkdir -p tmp + gh api repos/firstdraft/firstdraft/contents/docs/review-focus.md \ + -H 'Accept: application/vnd.github.raw' > tmp/review-focus.md + ``` + + List the affected surfaces after `--`. + +3. When the review finishes, the host agent runs `cite` and checks each finding against the cited lines before + relaying it. +4. Record each decision after `--` as `reject F-...: reason`, `accept F-...`, or `defer F-...`. Review an amendment + in the same session with `range ..HEAD`. + +Do not merge while a required review is still running. Review third-party changes, such as Dependabot or outside +pull requests, with `--capability read-only`. + +## Landing + +Merge after hosted CI passes and any required review has finished. Squash to one reviewable commit, or more only for +logically discrete units of work, and land it with a rebase merge: `gh pr merge --rebase`. Use a merge +commit only when the integration is itself meaningful work, such as resolving substantial conflicts. After merging, +report the repository and the exact merged SHA. + +A merge does not release anything. [RELEASING.md](RELEASING.md) covers publication, which the service repository +coordinates. diff --git a/README.md b/README.md index d8ea8eb..39ed192 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ repository owns the exact command and transport behavior between them. | Change the CLI | [Agent instructions](https://github.com/firstdraft/cli/blob/main/AGENTS.md), then [documentation map](docs/README.md) | | Find a command or output contract | [Command reference](docs/commands.md) | | Interpret an error or recover safely | [Errors and recovery](docs/errors.md) | +| Commit, review, or land a change | [Contributing guide](https://github.com/firstdraft/cli/blob/main/CONTRIBUTING.md) | | Prepare or publish a package | [Release runbook](https://github.com/firstdraft/cli/blob/main/RELEASING.md) | | See what changed in a version | [Changelog](https://github.com/firstdraft/cli/blob/main/CHANGELOG.md) | | Report a vulnerability | [Security policy](SECURITY.md) | diff --git a/eslint.config.js b/eslint.config.js index 462fa3a..af111f7 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,7 +3,7 @@ import globals from "globals"; export default [ { - ignores: ["node_modules/", "tmp/"], + ignores: ["node_modules/", "tmp/", ".claude/worktrees/"], }, js.configs.recommended, { diff --git a/test/documentation.test.js b/test/documentation.test.js index 7d52ba3..58b89c4 100644 --- a/test/documentation.test.js +++ b/test/documentation.test.js @@ -17,6 +17,7 @@ const markdownFiles = [ ...[ "AGENTS.md", "CHANGELOG.md", + "CONTRIBUTING.md", "README.md", "RELEASING.md", "SECURITY.md",