返回 CodeWhale
CONTRIBUTING.md
根目录 / CONTRIBUTING.md
1 # Contributing to codewhale
2
3 Thank you for your interest in contributing to codewhale! This document provides guidelines and instructions for contributing.
4
5 ## Getting Started
6
7 ### Prerequisites
8
9 - Rust 1.88 or later (edition 2024)
10 - Cargo package manager
11 - Git
12
13 ### Setting Up Development Environment
14
15 1. Fork and clone the repository:
16 ```bash
17 git clone https://github.com/YOUR_USERNAME/CodeWhale.git
18 cd CodeWhale
19 ```
20
21 2. Build the project:
22 ```bash
23 cargo build
24 ```
25
26 3. Run tests:
27 ```bash
28 cargo test --workspace --all-features
29 ```
30
31 4. Run with development settings:
32 ```bash
33 cargo run --bin codewhale
34 ```
35
36 ## Development Workflow
37
38 ### Code Style
39
40 - Run `cargo fmt` before committing to ensure consistent formatting
41 - Run `cargo clippy` and address all warnings
42 - Follow Rust naming conventions (snake_case for functions/variables, CamelCase for types)
43 - Add documentation comments for public APIs
44
45 ### Testing
46
47 - Write tests for new functionality
48 - Ensure all existing tests pass: `cargo test --workspace --all-features`
49 - Colocate unit tests beside the code they cover (standard Rust `#[cfg(test)]`
50 modules), and add integration tests under the owning crate's `tests/`
51 directory (for example `crates/tui/tests/` or `crates/state/tests/`). The
52 repository root `tests/` directory is not used
53
54 ### Pre-push verification
55
56 Run these before every push. They match what CI enforces on pull
57 requests, so passing locally means the PR lanes should pass too:
58
59 ```bash
60 cargo fmt --all -- --check
61 cargo clippy --workspace --all-features --locked -- \
62 -D warnings \
63 -A clippy::uninlined_format_args \
64 -A clippy::too_many_arguments \
65 -A clippy::unnecessary_map_or \
66 -A clippy::collapsible_if \
67 -A clippy::assertions_on_constants
68 cargo test --workspace --all-features --locked
69 ```
70
71 The release lane runs a stricter clippy that also lints test, bench, and
72 example targets. The PR template checklist asks for this form, and it is
73 the right command before requesting review or doing release-bound work,
74 because `--all-features` alone skips lints that will fail the release
75 lane later:
76
77 ```bash
78 cargo clippy --workspace --all-targets --all-features --locked -- \
79 -D warnings \
80 -A clippy::uninlined_format_args \
81 -A clippy::too_many_arguments \
82 -A clippy::unnecessary_map_or \
83 -A clippy::collapsible_if \
84 -A clippy::assertions_on_constants
85 ```
86
87 Some suites are slow, platform-bound, or intentionally excluded from the
88 default run; treat them as documented isolation cases rather than
89 failures of the normal gate:
90
91 - **PTY snapshots** (`cargo test -p codewhale-tui --test qa_pty
92 --locked`) are Unix-only and internally serialized. One recovery-boot
93 case is `#[ignore]`d for a documented input-starvation issue. When a
94 PTY case fails, rerun that exact case in isolation and diagnose the
95 rendered frame before calling it a flake; `run_verifiers_background_*`
96 is the one known full-suite-parallelism flake that passes in
97 isolation.
98 - **Release runtime QA** (`cargo test -p codewhale-tui --test
99 release_runtime_qa --locked`) includes an `#[ignore]`d 32-worker storm
100 benchmark that is only run explicitly for evidence gathering.
101 - **OCR** (`image_ocr`) uses the macOS Vision framework or a locally
102 installed `tesseract`; its platform-specific paths are
103 `cfg(target_os = "macos")`-gated and depend on host tooling.
104 - **Seatbelt sandbox** tests are macOS-only (`cfg(target_os =
105 "macos")` at the module level) and do not run elsewhere.
106
107 #### Local git hooks are optional
108
109 This repository does not install git hooks, and no hook installer
110 exists; CI is the enforced gate. If you want a local `pre-push` hook
111 that runs the commands above, add it yourself (`.git/hooks/pre-push` or
112 `git config core.hooksPath`). Constraints for any local hook:
113
114 - A hook must never push, tag, publish, deploy, mutate credentials, or
115 rewrite the working tree (no auto-fix commits or silent file
116 modification). It may only verify and report.
117 - To bypass your own hook for a knowingly documented reason (for
118 example, pushing work-in-progress to your own fork branch), use
119 `git push --no-verify` and say so in the PR description. Bypassing a
120 local hook does not make the gates pass — CI still runs them, and a
121 bypassed gate must never be reported as a passing one.
122 - Release publication (tags, GitHub Releases, crates/npm artifacts) is a
123 separate, owner-approved gate. Neither local hooks nor a green local
124 run authorize any publication step.
125
126 ### Commit Messages
127
128 Use clear, descriptive commit messages following conventional commits:
129
130 - `feat:` New feature
131 - `fix:` Bug fix
132 - `docs:` Documentation changes
133 - `refactor:` Code refactoring
134 - `test:` Adding or updating tests
135 - `chore:` Maintenance tasks
136
137 Example: `feat: add doctor subcommand for system diagnostics`
138
139 When a commit harvests code from a community PR (see "How Your Contribution
140 Lands" below), include a `Harvested from PR #N by @author` line in the commit
141 body. An auto-close workflow watches for this pattern and closes the
142 referenced PR with credit so the contributor gets a clear signal that
143 their work shipped.
144
145 ## How Your Contribution Lands
146
147 We follow a deliberate "land what's useful, credit the contributor" model
148 that occasionally surprises new contributors. Two paths:
149
150 ### Path 1 — Direct merge
151
152 If your PR is well-scoped, passes CI, doesn't touch the trust-boundary
153 surface (auth / sandbox / publishing / branding), and doesn't conflict
154 with main, a maintainer merges it directly. This is the most common
155 outcome for small bug fixes and well-tested feature additions.
156
157 ### Path 2 — Harvest
158
159 If your PR is large, mixes scope, conflicts with main, or needs polish
160 that's faster for the maintainer to apply than to round-trip with the
161 contributor, the maintainer may **harvest** the useful commits or hunks
162 into a new commit on `main` rather than merging the PR directly. This is
163 **not a rejection** — it means your code landed.
164
165 When this happens:
166
167 - The harvested commit's message includes `Harvested from PR #N by
168 @your-handle`. This is the contract: that line is your credit and the
169 signal that your contribution shipped.
170 - If the maintainer copies or adapts your code, the harvested commit also
171 keeps attribution with the original author identity when possible: either by
172 preserving the commit author on a cherry-pick or by adding a
173 `Co-authored-by: Name <id+login@users.noreply.github.com>` trailer. This is
174 what lets GitHub's contribution surfaces recognize more than prose credit.
175 Maintainers should use `.github/AUTHOR_MAP`, or run
176 `gh api users/<login> --jq '"\(.id)+\(.login)@users.noreply.github.com"'`,
177 rather than copying raw, `.local`, or old-style noreply emails from a
178 contributor's machine.
179 - The `CHANGELOG.md` entry for the next release credits you by handle.
180 - The auto-close workflow closes your PR with a templated thank-you and
181 a link to the commit on `main`.
182
183 When a maintainer closes a harvested PR by hand, the closing comment
184 follows this template (the pattern set on PR #2634):
185
186 ```text
187 Closing with harvest credit, @handle — <what landed> landed via
188 <commit sha(s) or PR #N>. <If work remains:> The remainder is tracked
189 in #NNN — follow-ups welcome there.
190 Thank you for <one specific thing the contribution got right>.
191 ```
192
193 Three required elements: the contributor's handle, the exact commits or
194 PRs where their work landed, and — when the PR contained more than what
195 landed — a tracking issue for the remainder. A harvested PR is never
196 closed with a bare "superseded".
197
198 To make a future contribution land via the faster Direct-Merge path
199 instead of the Harvest path, the highest-leverage things you can do are:
200
201 1. **Keep PRs single-purpose.** One bug fix per PR; one feature per PR.
202 Don't mix a refactor with a feature.
203 2. **Rebase onto current `main` before opening the PR**, and after CI
204 feedback. Conflicts force the harvest path even when the change is
205 small.
206 3. **Include tests** with new behavior. The maintainer often harvests
207 PRs without tests because adding the test is faster than asking the
208 contributor for one.
209 4. **Avoid the trust-boundary surface** without prior maintainer
210 sign-off. That includes auth/credential flows, sandbox policy,
211 publishing/release plumbing, and `prompts/` content. PRs that touch
212 these without prior discussion are unlikely to merge directly even
213 when the change is well-implemented.
214
215 ## Layered and EPIC-Sized Work
216
217 Some architecture work is too large for one PR but still needs to be built in
218 dependent layers. For those changes, use this workflow:
219
220 1. Start with a tracking issue or EPIC when the work spans multiple PRs. Name
221 the intended slices and state what each slice is not trying to close yet.
222 2. Keep each implementation PR focused on one behavior boundary.
223 3. Later layers may stay in your fork or open as draft PRs while the lower
224 layer is still moving. Draft stacked PR titles or descriptions should say
225 `Draft / depends on #NNNN`.
226 4. A dependent PR is not ready for merge review until the lower layer has
227 landed, the branch has been rebased onto current `main`, and the PR targets
228 `main`.
229 5. The PR body should identify which earlier PR it builds on, what is in scope,
230 what is explicitly out of scope, which issues it references, and which local
231 commands were run.
232 6. Use `Closes #...` only when the slice fully satisfies an issue. Use
233 `Refs #...` with a short `(partial)` note when the PR advances a broad issue
234 but leaves follow-up work.
235 7. Structured commits are fine during review. Maintainers may squash or harvest
236 at merge time, with contributor credit preserved through authorship,
237 co-author trailers, changelog entries, or PR/issue comments. When the merge
238 commit itself carries a `Harvested from PR #N by @author` line, that PR is
239 merged with rebase or a merge commit rather than squashed, so the line
240 reaches `main` intact and the auto-close credit fires.
241
242 Before asking for merge review on a layered PR, check that it is:
243
244 - rebased onto current `main`
245 - marked ready for review, not draft
246 - focused to one behavior boundary
247 - backed by local command evidence in the PR body
248 - green in CI, or has any remaining red lane clearly explained
249 - covered by round-trip or migration-preservation tests when it changes config
250 or schema behavior
251 - referencing broad issues as partial unless it really closes them
252
253 For layered work, a useful PR description shape is:
254
255 ```text
256 Summary:
257 Scope:
258 Not in this slice:
259 Builds on:
260 Issues:
261 Validation:
262 ```
263
264 ## The Stewardship Branch
265
266 Large refactors and architecture work stage on
267 `codex/v0.9.0-stewardship` before reaching `main`. The branch exists so
268 that multi-layer series (like the command-group refactor) can land layer
269 by layer against a stable base, get validated by their parity harnesses,
270 and then flow to `main` in periodic stewardship merges — instead of each
271 layer racing `main`'s daily churn.
272
273 What this means for you:
274
275 - **Base layered/EPIC-sized refactor PRs on `codex/v0.9.0-stewardship`**
276 and target the PR there (see #2888 for the model). Ordinary bug fixes
277 and features still target `main`.
278 - Maintainers merge the stewardship branch into `main` periodically;
279 your work reaches `main` with its history and credit intact.
280 - If you're unsure which base to use, ask in your tracking issue — the
281 default for anything that isn't a multi-PR series is `main`.
282
283 ## Contribution Gate
284
285 Codewhale uses a maintainer-managed contribution gate for the community front
286 door. Maintainers and collaborators bypass this gate automatically. The gate
287 workflows default to dry-run / comment-only mode so maintainers can observe the
288 signal before changing contributor flow.
289
290 The maintainer posture is documented in
291 [docs/AGENT_ETHOS.md](docs/AGENT_ETHOS.md): automation should reduce load while
292 keeping good-faith contributors seen, credited, and able to keep helping.
293
294 Issues are never auto-closed by the contribution gate. Unapproved external
295 issues receive a short welcome note that asks for reproduction details and then
296 remain open for maintainer triage. Codewhale depends on real edge cases from
297 real users, so issue intake should stay warm and open.
298
299 Pull requests are different because they can touch code, CI, release plumbing,
300 auth, sandboxing, provider policy, and other trust-boundary surfaces. The PR
301 gate can be switched from dry-run to enforcement when maintainers decide they
302 need that safety control, but it should be treated as a review-load control,
303 not a judgment on contributor quality. Before enabling PR enforcement, seed the
304 allowlist broadly enough for active external contributors who should not be
305 interrupted by the rollout.
306
307 The allowlist is scoped:
308
309 - `pr:username` allows pull requests.
310 - `issue:username` allows issues.
311 - `all:username` allows both.
312
313 A maintainer can approve someone by commenting `/lgtm` on a pull request for PR
314 access, or `/lgtmi` on an issue for issue access. The exact bare commands
315 `lgtm` and `lgtmi` are also accepted for compatibility, but the prefixed forms
316 are preferred because they are harder to trigger accidentally in ordinary review
317 discussion.
318
319 Approvals do not edit `main` directly. The approval workflow opens a small
320 allowlist update PR so the new entry is reviewable before it takes effect.
321
322 If the PR gate fires on a good contributor incorrectly, use the same approval
323 flow to restore them: comment `/lgtm`, merge the generated allowlist PR, then
324 reopen the affected pull request. If GitHub will not allow the closed PR to be
325 reopened, ask the contributor to resubmit after the allowlist PR is merged.
326
327 ## Agent-Assisted Improvements
328
329 Codewhale is allowed to help improve Codewhale, but the contribution still has
330 to be shaped for human review. The recommended workflow is the
331 [recursive self-improvement prompt](docs/RECURSIVE_SELF_IMPROVEMENT.md): run it
332 from a fresh fork or branch, let the agent find exactly one small friction point,
333 and stop after one patch. DeepSeek V4 Pro is the reference path for this loop
334 today, but any configured provider works — the review shape matters more than
335 the provider.
336
337 Agents and maintainers should follow the stewardship posture in
338 [docs/AGENT_ETHOS.md](docs/AGENT_ETHOS.md): use automation for evidence,
339 verification, and narrow patches while keeping the final community decision
340 human-reviewed.
341
342 The useful output is not "ideas for improvement." The useful output is a
343 specific reproduction, a minimal diff, focused checks, and a PR description that
344 explains the trade-off. Do not use an agent to touch auth, credentials, sandbox
345 policy, publishing/release plumbing, provider policy, telemetry, sponsorship,
346 branding, or global prompts without prior maintainer sign-off.
347
348 ## Project Structure
349
350 codewhale is a Cargo workspace. The live runtime and the majority of TUI,
351 engine, and tool code currently live in `crates/tui/src/`. Smaller workspace
352 crates provide shared abstractions that are being extracted incrementally.
353
354 ```
355 crates/
356 ├── tui/ codewhale-tui binary (interactive TUI + runtime API)
357 ├── cli/ codewhale binary (dispatcher facade)
358 ├── app-server/ HTTP/SSE + JSON-RPC transport
359 ├── core/ Agent loop / session / turn management
360 ├── protocol/ Request/response framing
361 ├── config/ Config loading, profiles, env precedence
362 ├── state/ SQLite thread/session persistence
363 ├── tools/ Typed tool specs and lifecycle
364 ├── mcp/ MCP client + stdio server
365 ├── hooks/ Lifecycle hooks (stdout/jsonl/webhook)
366 ├── execpolicy/ Approval/sandbox policy engine
367 ├── agent/ Model/provider registry
368 ```
369
370 See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the live data flow across
371 these crates, including the bottom-up build order.
372
373 ## Submitting Changes
374
375 1. Create a feature branch from `main`:
376 ```bash
377 git checkout -b feat/your-feature
378 ```
379
380 2. Make your changes and commit them
381
382 3. Run the pre-push verification commands (see
383 [Pre-push verification](#pre-push-verification) above for the exact
384 gate and the stricter release clippy form)
385
386 4. Push your branch and create a Pull Request
387
388 5. Describe your changes clearly in the PR description
389
390 ## Pull Request Guidelines
391
392 - Use the [pull request template](.github/PULL_REQUEST_TEMPLATE.md) when opening
393 a PR — it includes the Summary, Testing, and Checklist sections reviewers
394 expect
395 - Keep PRs focused on a single change
396 - Update documentation if needed
397 - Add tests for new functionality
398 - Ensure CI passes before requesting review
399
400 ## Shape of a Typical PR
401
402 A well-structured PR follows a consistent pattern. Recent exemplars include:
403
404 - **#386** — `/init` command: new `crates/tui/src/commands/groups/project/init.rs` module, project-type detection,
405 AGENTS.md generation, command registration in `commands/mod.rs`, localization strings.
406 - **#389** — Inline LSP diagnostics: LSP subsystem in `crates/tui/src/lsp/`, engine hooks in
407 `crates/tui/src/core/engine/lsp_hooks.rs`, config toggle, test coverage.
408 - **#387** — Self-update: new `crates/cli/src/update.rs` module, CLI subcommand registration,
409 HTTP download + SHA256 verification + atomic binary replacement.
410 - **#393** — `/share` session URL: new `crates/tui/src/commands/groups/project/share.rs`, HTML rendering,
411 `gh gist create` integration, command registration.
412 - **#343/#346** — (v0.8.5) Runtime thread/turn timeline and durable task manager refactors.
413
414 Typically each PR touches 1–3 new files, modifies 2–5 existing files for wiring
415 (registries, dispatch matches, localization), and adds or updates tests. Changes
416 are scoped to a single feature or fix — if you discover related work that needs
417 doing, open a separate issue rather than expanding the PR scope.
418
419 Before submitting, run the commands in
420 [Pre-push verification](#pre-push-verification).
421
422 ## Reporting Issues
423
424 When reporting issues, please use one of the issue templates:
425
426 - [Bug report](.github/ISSUE_TEMPLATE/bug_report.md) — for reproducible problems
427 or regressions
428 - [Feature request](.github/ISSUE_TEMPLATE/feature_request.md) — for ideas and
429 improvements
430
431 Issue reports should include:
432
433 - Operating system and version
434 - Rust version (`rustc --version`)
435 - codewhale version (`codewhale --version`)
436 - Steps to reproduce the issue
437 - Expected vs actual behavior
438 - Relevant error messages or logs
439
440 ## Security
441
442 If you discover a security vulnerability, please do **not** open a public issue.
443 See [SECURITY.md](SECURITY.md) for the responsible disclosure process and
444 contact information.
445
446 ## Code of Conduct
447
448 Be respectful and inclusive. We welcome contributors of all backgrounds and
449 experience levels. See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for the full
450 code of conduct.
451
452 ## License
453
454 By contributing to codewhale, you agree that your contributions will be licensed under the MIT License.
455
456 ## Questions?
457
458 Feel free to open an issue for any questions about contributing.
459
459 lines MARKDOWN