返回 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 #### Fast local loop
88
89 The full gate above is what CI enforces, but you do not need it for every
90 edit. `crates/tui` is a ~750k-line crate, so the loop that stays fast is
91 the one that avoids rebuilding it more than necessary (numbers and the
92 reasoning are in [`docs/BUILD_PERFORMANCE.md`](docs/BUILD_PERFORMANCE.md)):
93
94 ```bash
95 # 1. Type-check first (seconds after the first build; no codegen, no link).
96 scripts/dev-cargo.sh check -p codewhale-tui
97
98 # 2. Run only the tests near your change (one crate, one filter).
99 scripts/dev-test.sh tui fleet_setup
100 # or: scripts/dev-test.sh crates/tui/src/elapsed.rs
101
102 # 3. Run a whole crate's unit suite. scripts/dev-test.sh uses nextest when
103 # it is installed (one process per test, all cores busy, slow tests
104 # named; ~100 s here vs ~270 s with libtest).
105 cargo install cargo-nextest --locked # once
106 scripts/dev-test.sh tui
107 scripts/dev-cargo.sh nextest run --workspace --all-features --locked
108
109 # 4. Before pushing, run the authoritative gate exactly as CI does:
110 cargo test --workspace --all-features --locked
111 ```
112
113 `.config/nextest.toml` already serializes the PTY suite and bounds the
114 integration tests that spawn the real binary, so `cargo nextest run` is
115 safe to use on the whole workspace (nextest does not run doctests; the
116 authoritative `cargo test` gate does). Tests must not depend on running in
117 the same process as another test (nextest gives every test its own
118 process); if a test needs the rustls crypto provider, install it in that
119 test as production does at startup.
120
121 On a machine with less than 16 GB of RAM (or when cross-compiling, e.g.
122 for OHOS), build one rustc at a time: `CARGO_BUILD_JOBS=1` (or `-j1`), one
123 crate at a time, `--lib` for tests, never `--workspace`/`--all-targets`.
124 The tui library needs ~6 GB for its own rustc and its unit-test build ~8 GB;
125 `cargo test --workspace` runs both at once. Numbers and the full recipe:
126 [`docs/BUILD_PERFORMANCE.md`](docs/BUILD_PERFORMANCE.md#low-memory-build-recipe-machines-with--16-gb-cross-builds).
127
128 If you work in several worktrees, do **not** share one `CARGO_TARGET_DIR`
129 by default: two cargos on the same target flock and serialize. Use
130 `scripts/dev-cargo.sh` / `scripts/dev-test.sh`, which give each workspace
131 its own Cargo `build-dir` (`{workspace-path-hash}` under
132 `${CODEWHALE_CACHE_ROOT:-${XDG_CACHE_HOME:-$HOME/.cache}/codewhale}`).
133 `CODEWHALE_DEV_CACHE=local` keeps `./target` if you want that.
134 `sccache` wraps rustc only when incremental compilation is already off
135 (`CARGO_INCREMENTAL=0` or `CODEWHALE_SCCACHE=1`) and `sccache` is on
136 `PATH`; a missing binary is a printed fallback, not an error. Override
137 the cache root with `CODEWHALE_CACHE_ROOT` — there is no machine-specific
138 default. A single shared `CARGO_TARGET_DIR` remains valid only for
139 serialized trunk work. See
140 [`docs/BUILD_PERFORMANCE.md`](docs/BUILD_PERFORMANCE.md).
141
142 Some checks are platform-bound or intentionally excluded from an ordinary
143 change. Choose them for the risk they answer rather than treating every
144 available suite as ritual. Visible TUI behavior is accepted in the actual
145 terminal at the sizes and interaction path affected by the change; the former
146 full-screen PTY assertion suite was removed because it froze layout and copy
147 while missing product quality.
148
149 - **Long-running process acceptance** should use a sealed local home, local
150 fixtures, and the real binary. Record the terminal size, inputs, visible
151 result, and any filesystem side effect instead of adding a full-screen
152 golden.
153 - **OCR** (`image_ocr`) uses the macOS Vision framework or a locally
154 installed `tesseract`; its platform-specific paths are
155 `cfg(target_os = "macos")`-gated and depend on host tooling.
156 - **Seatbelt sandbox** tests are macOS-only (`cfg(target_os =
157 "macos")` at the module level) and do not run elsewhere.
158
159 #### Local git hooks are optional
160
161 This repository does not install git hooks, and no hook installer
162 exists; CI is the enforced gate. If you want a local `pre-push` hook
163 that runs the commands above, add it yourself (`.git/hooks/pre-push` or
164 `git config core.hooksPath`). Constraints for any local hook:
165
166 - A hook must never push, tag, publish, deploy, mutate credentials, or
167 rewrite the working tree (no auto-fix commits or silent file
168 modification). It may only verify and report.
169 - To bypass your own hook for a knowingly documented reason (for
170 example, pushing work-in-progress to your own fork branch), use
171 `git push --no-verify` and say so in the PR description. Bypassing a
172 local hook does not make the gates pass — CI still runs them, and a
173 bypassed gate must never be reported as a passing one.
174 - Release publication (tags, GitHub Releases, crates/npm artifacts) is a
175 separate, owner-approved gate. Neither local hooks nor a green local
176 run authorize any publication step.
177
178 ### Commit Messages
179
180 Use clear, descriptive commit messages following conventional commits:
181
182 - `feat:` New feature
183 - `fix:` Bug fix
184 - `docs:` Documentation changes
185 - `refactor:` Code refactoring
186 - `test:` Adding or updating tests
187 - `chore:` Maintenance tasks
188
189 Example: `feat: add doctor subcommand for system diagnostics`
190
191 **Changelog entries are written on `main` at merge time, not in PRs.** Do not
192 edit `CHANGELOG.md` or `crates/tui/CHANGELOG.md` on a branch: every PR
193 touching them re-conflicts with every other PR touching them. The release
194 manager writes one batched "receipts" commit per merge session, and
195 `./scripts/sync-changelog.sh` keeps the packaged slice in sync. A PR that
196 carries changelog hunks will be asked to strip them
197 (`git checkout origin/main -- CHANGELOG.md crates/tui/CHANGELOG.md`).
198
199 **AI-assistant co-author trailers are fine.** Using an assistant is welcome and
200 needs no disclosure, and CI no longer rejects an auto-appended
201 `Co-authored-by: <some tool>` line. What we do care about is that the humans who
202 did the work are named — `Co-authored-by` feeds the GitHub contribution graph.
203 Remove an auto-appended line only if you want to:
204
205 ```bash
206 git rebase -i origin/main # reword each commit, delete the Co-authored-by line
207 ```
208
209 Co-author a *person* freely; the address must be their GitHub-linked one
210 (`id+login@users.noreply.github.com`) or the credit does not register.
211
212 When a commit harvests code from a community PR (see "How Your Contribution
213 Lands" below), include a `Harvested from PR #N by @author` line in the commit
214 body. An auto-close workflow watches for this pattern and closes the
215 referenced PR with credit so the contributor gets a clear signal that
216 their work shipped.
217
218 ## How Your Contribution Lands
219
220 We follow a deliberate "land what's useful, credit the contributor" model
221 that occasionally surprises new contributors. Two paths:
222
223 ### Path 1 — Direct merge
224
225 If your PR is well-scoped, passes CI, doesn't touch the trust-boundary
226 surface (auth / sandbox / publishing / branding), and doesn't conflict
227 with main, a maintainer merges it directly. This is the most common
228 outcome for small bug fixes and well-tested feature additions.
229
230 ### Path 2 — Harvest
231
232 If your PR is large, mixes scope, conflicts with main, or needs polish
233 that's faster for the maintainer to apply than to round-trip with the
234 contributor, the maintainer may **harvest** the useful commits or hunks
235 into a new commit on `main` rather than merging the PR directly. This is
236 **not a rejection** — it means your code landed.
237
238 When this happens:
239
240 - The harvested commit's message includes `Harvested from PR #N by
241 @your-handle`. This is the contract: that line is your credit and the
242 signal that your contribution shipped.
243 - If the maintainer copies or adapts your code, the harvested commit also
244 keeps attribution with the original author identity when possible: either by
245 preserving the commit author on a cherry-pick or by adding a
246 `Co-authored-by: Name <id+login@users.noreply.github.com>` trailer. This is
247 what lets GitHub's contribution surfaces recognize more than prose credit.
248 Maintainers should use `.github/AUTHOR_MAP`, or run
249 `gh api users/<login> --jq '"\(.id)+\(.login)@users.noreply.github.com"'`,
250 rather than copying raw, `.local`, or old-style noreply emails from a
251 contributor's machine.
252 - The `CHANGELOG.md` entry for the next release credits you by handle.
253 - The auto-close workflow closes your PR with a templated thank-you and
254 a link to the commit on `main`.
255
256 When a maintainer closes a harvested PR by hand, the closing comment
257 follows this template (the pattern set on PR #2634):
258
259 ```text
260 Closing with harvest credit, @handle — <what landed> landed via
261 <commit sha(s) or PR #N>. <If work remains:> The remainder is tracked
262 in #NNN — follow-ups welcome there.
263 Thank you for <one specific thing the contribution got right>.
264 ```
265
266 Three required elements: the contributor's handle, the exact commits or
267 PRs where their work landed, and — when the PR contained more than what
268 landed — a tracking issue for the remainder. A harvested PR is never
269 closed with a bare "superseded".
270
271 To make a future contribution land via the faster Direct-Merge path
272 instead of the Harvest path, the highest-leverage things you can do are:
273
274 1. **Keep PRs single-purpose.** One bug fix per PR; one feature per PR.
275 Don't mix a refactor with a feature.
276 2. **Rebase onto current `main` before opening the PR**, and after CI
277 feedback. Conflicts force the harvest path even when the change is
278 small.
279 3. **Include tests** with new behavior. The maintainer often harvests
280 PRs without tests because adding the test is faster than asking the
281 contributor for one.
282 4. **Avoid the trust-boundary surface** without prior maintainer
283 sign-off. That includes auth/credential flows, sandbox policy,
284 publishing/release plumbing, and `prompts/` content. PRs that touch
285 these without prior discussion are unlikely to merge directly even
286 when the change is well-implemented.
287
288 ## Layered and EPIC-Sized Work
289
290 Some architecture work is too large for one PR but still needs to be built in
291 dependent layers. For those changes, use this workflow:
292
293 1. Start with a tracking issue or EPIC when the work spans multiple PRs. Name
294 the intended slices and state what each slice is not trying to close yet.
295 2. Keep each implementation PR focused on one behavior boundary.
296 3. Later layers may stay in your fork or open as draft PRs while the lower
297 layer is still moving. Draft stacked PR titles or descriptions should say
298 `Draft / depends on #NNNN`.
299 4. A dependent PR is not ready for merge review until the lower layer has
300 landed, the branch has been rebased onto current `main`, and the PR targets
301 `main`.
302 5. The PR body should identify which earlier PR it builds on, what is in scope,
303 what is explicitly out of scope, which issues it references, and which local
304 commands were run.
305 6. Use `Closes #...` only when the slice fully satisfies an issue. Use
306 `Refs #...` with a short `(partial)` note when the PR advances a broad issue
307 but leaves follow-up work.
308 7. Structured commits are fine during review. Maintainers may squash or harvest
309 at merge time, with contributor credit preserved through authorship,
310 co-author trailers, changelog entries, or PR/issue comments. When the merge
311 commit itself carries a `Harvested from PR #N by @author` line, that PR is
312 merged with rebase or a merge commit rather than squashed, so the line
313 reaches `main` intact and the auto-close credit fires.
314
315 Before asking for merge review on a layered PR, check that it is:
316
317 - rebased onto current `main`
318 - marked ready for review, not draft
319 - focused to one behavior boundary
320 - backed by local command evidence in the PR body
321 - green in CI, or has any remaining red lane clearly explained
322 - covered by round-trip or migration-preservation tests when it changes config
323 or schema behavior
324 - referencing broad issues as partial unless it really closes them
325
326 For layered work, a useful PR description shape is:
327
328 ```text
329 Summary:
330 Scope:
331 Not in this slice:
332 Builds on:
333 Issues:
334 Validation:
335 ```
336
337 ## Which branch to target
338
339 **`main`, for everything.** There is no separate staging branch. An earlier
340 version of this guide pointed layered refactors at `codex/v0.9.0-stewardship`;
341 that branch no longer exists, so please ignore any instruction you find
342 elsewhere to base work on it.
343
344 For a multi-PR series or anything that will collide with other in-flight work,
345 maintainers may land your branch on an `integration/<topic>-<pr>-<date>` branch
346 first and merge from there. That is our bookkeeping, not extra work for you —
347 you still open the PR against `main`, and your commits reach `main` with their
348 history and authorship intact.
349
350 **We do not expect you to rebase around our churn.** If your PR conflicts only
351 because `main` moved while it was in review, say so and a maintainer resolves
352 it. If your branch is in a fork we cannot push to, we land the resolved merge
353 on an integration branch rather than asking you to redo the work.
354
355 ## Contribution Gate
356
357 Codewhale uses a maintainer-managed contribution gate for the community front
358 door. Maintainers and collaborators bypass this gate automatically. The gate
359 workflows default to dry-run / comment-only mode so maintainers can observe the
360 signal before changing contributor flow.
361
362 The maintainer posture is documented in
363 [docs/AGENT_ETHOS.md](docs/AGENT_ETHOS.md): automation should reduce load while
364 keeping good-faith contributors seen, credited, and able to keep helping.
365
366 Issues are never auto-closed by the contribution gate. Unapproved external
367 issues receive a short welcome note that asks for reproduction details and then
368 remain open for maintainer triage. Codewhale depends on real edge cases from
369 real users, so issue intake should stay warm and open.
370
371 Pull requests are different because they can touch code, CI, release plumbing,
372 auth, sandboxing, provider policy, and other trust-boundary surfaces. The PR
373 gate can be switched from dry-run to enforcement when maintainers decide they
374 need that safety control, but it should be treated as a review-load control,
375 not a judgment on contributor quality. Before enabling PR enforcement, seed the
376 allowlist broadly enough for active external contributors who should not be
377 interrupted by the rollout.
378
379 The allowlist is scoped:
380
381 - `pr:username` allows pull requests.
382 - `issue:username` allows issues.
383 - `all:username` allows both.
384
385 A maintainer can approve someone by commenting `/lgtm` on a pull request for PR
386 access, or `/lgtmi` on an issue for issue access. The exact bare commands
387 `lgtm` and `lgtmi` are also accepted for compatibility, but the prefixed forms
388 are preferred because they are harder to trigger accidentally in ordinary review
389 discussion.
390
391 Approvals do not edit `main` directly. The approval workflow opens a small
392 allowlist update PR so the new entry is reviewable before it takes effect.
393
394 If the PR gate fires on a good contributor incorrectly, use the same approval
395 flow to restore them: comment `/lgtm`, merge the generated allowlist PR, then
396 reopen the affected pull request. If GitHub will not allow the closed PR to be
397 reopened, ask the contributor to resubmit after the allowlist PR is merged.
398
399 ## Agent-Assisted Improvements
400
401 Codewhale is allowed to help improve Codewhale, but the contribution still has
402 to be shaped for human review. The recommended workflow is the recursive self-improvement prompt
403 in the private `codewhale-ops` repo: run it
404 from a fresh fork or branch, let the agent find exactly one small friction point,
405 and stop after one patch. DeepSeek V4 Pro is the reference path for this loop
406 today, but any configured provider works — the review shape matters more than
407 the provider.
408
409 Agents and maintainers should follow the stewardship posture in
410 [docs/AGENT_ETHOS.md](docs/AGENT_ETHOS.md): use automation for evidence,
411 verification, and narrow patches while keeping the final community decision
412 human-reviewed.
413
414 The useful output is not "ideas for improvement." The useful output is a
415 specific reproduction, a minimal diff, focused checks, and a PR description that
416 explains the trade-off. Do not use an agent to touch auth, credentials, sandbox
417 policy, publishing/release plumbing, provider policy, telemetry, sponsorship,
418 branding, or global prompts without prior maintainer sign-off.
419
420 ## Project Structure
421
422 Codewhale is a Cargo workspace with one Engine implementation in
423 `crates/tui/src/core/engine/`. The public `codewhale` executable links the
424 TUI/runtime library; interactive sessions, noninteractive runs and the Runtime
425 API share that Engine.
426
427 | Path | Purpose |
428 | --- | --- |
429 | `crates/cli/` | Public command entrypoint, configuration commands and runtime dispatch |
430 | `crates/tui/` | Interactive terminal, Engine, tools, Runtime API and embedded local web client |
431 | `crates/core/`, `crates/protocol/`, `crates/state/` | Request construction, session/turn types, protocol framing and persistence |
432 | Other `crates/` | Shared configuration, credentials, telemetry, hooks, workflow and packaging support; see each Cargo manifest |
433 | `web/` | Public Next.js website and documentation; separate from the embedded Runtime web client |
434 | `telemetry-ingest/` | Telemetry service, schemas and service tests |
435 | `extensions/`, `integrations/` | Editor integration and external-service bridges |
436 | `npm/`, `packaging/`, `nix/` | npm wrappers/SDK and platform installation definitions |
437 | `computer/snapshots/` | Cloud Computer image definitions, pinned independently of the source checkout |
438 | `deploy/` | Deployment templates consumed by setup scripts, including Tencent Lighthouse services |
439 | `fleets/`, `workflows/` | Distributed Fleet definitions and workflow examples |
440 | `brand/` | Source artwork and generated brand variants used by the README, website and terminal |
441 | `docs/` | User/developer documentation, schemas, fixtures and referenced release material |
442 | `scripts/`, `.github/`, `.cnb.yml` | Development, validation, CI and release tooling |
443 | `patches/` | Vendored dependency fixes, including their licensing files |
444
445 Generated files that the product embeds or validates, such as model catalogs,
446 website facts and schemas, remain tracked with their generators. Platform
447 mirrors such as `.winget/` are retained when their packaging tools require them.
448 Keep local critique output, temporary verification reports and personal
449 operator instructions outside the tracked product tree; describe the change
450 and its validation in the pull request. Do not copy workspace-level operator
451 `AGENTS.md` or `CLAUDE.md` files into this repository.
452
453 See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the runtime data flow and
454 [the build guide](docs/BUILD_PERFORMANCE.md) for crate dependencies and local
455 verification.
456
457 ## Submitting Changes
458
459 1. Create a feature branch from `main`:
460 ```bash
461 git checkout -b feat/your-feature
462 ```
463
464 2. Make your changes and commit them
465
466 3. Run the pre-push verification commands (see
467 [Pre-push verification](#pre-push-verification) above for the exact
468 gate and the stricter release clippy form)
469
470 4. Push your branch and create a Pull Request
471
472 5. Describe your changes clearly in the PR description
473
474 ## Pull Request Guidelines
475
476 - Use the [pull request template](.github/PULL_REQUEST_TEMPLATE.md) when opening
477 a PR — it includes the Summary, Testing, and Checklist sections reviewers
478 expect
479 - Keep PRs focused on a single change
480 - Update documentation if needed
481 - Add tests for new functionality
482 - Ensure CI passes before requesting review
483
484 ## Shape of a Typical PR
485
486 A well-structured PR follows a consistent pattern. Recent exemplars include:
487
488 - **#386** — `/init` command: new `crates/tui/src/commands/groups/project/init.rs` module, project-type detection,
489 AGENTS.md generation, command registration in `commands/mod.rs`, localization strings.
490 - **#389** — Inline LSP diagnostics: LSP subsystem in `crates/tui/src/lsp/`, engine hooks in
491 `crates/tui/src/core/engine/lsp_hooks.rs`, config toggle, test coverage.
492 - **#387** — Self-update: new `crates/cli/src/update.rs` module, CLI subcommand registration,
493 HTTP download + SHA256 verification + atomic binary replacement.
494 - **#393** — `/share` session URL: new `crates/tui/src/commands/groups/project/share.rs`, HTML rendering,
495 `gh gist create` integration, command registration.
496 - **#343/#346** — (v0.8.5) Runtime thread/turn timeline and durable task manager refactors.
497
498 Typically each PR touches 1–3 new files, modifies 2–5 existing files for wiring
499 (registries, dispatch matches, localization), and adds or updates tests. Changes
500 are scoped to a single feature or fix — if you discover related work that needs
501 doing, open a separate issue rather than expanding the PR scope.
502
503 Before submitting, run the commands in
504 [Pre-push verification](#pre-push-verification).
505
506 ## Reporting Issues
507
508 When reporting issues, please use one of the issue templates:
509
510 - [Bug report](.github/ISSUE_TEMPLATE/bug_report.md) — for reproducible problems
511 or regressions
512 - [Feature request](.github/ISSUE_TEMPLATE/feature_request.md) — for ideas and
513 improvements
514
515 Issue reports should include:
516
517 - Operating system and version
518 - Rust version (`rustc --version`)
519 - codewhale version (`codewhale --version`)
520 - Steps to reproduce the issue
521 - Expected vs actual behavior
522 - Relevant error messages or logs
523
524 ## Security
525
526 If you discover a security vulnerability, please do **not** open a public issue.
527 See [SECURITY.md](.github/SECURITY.md) for the responsible disclosure process and
528 contact information.
529
530 ## Code of Conduct
531
532 Be respectful and inclusive. We welcome contributors of all backgrounds and
533 experience levels. See [CODE_OF_CONDUCT.md](.github/CODE_OF_CONDUCT.md) for the full
534 code of conduct.
535
536 ## License
537
538 By contributing to codewhale, you agree that your contributions will be licensed under the MIT License.
539
540 ## Questions?
541
542 Feel free to open an issue for any questions about contributing.
543
543 lines MARKDOWN