返回 DeepSeek-Reasonix
CONTRIBUTING.md
根目录 / CONTRIBUTING.md
1 # Contributing to Reasonix
2
3 Thank you for your interest in contributing to Reasonix! This guide covers
4 everything you need to get started.
5
6 ## Prerequisites
7
8 - **Go 1.26+** — use the toolchain pinned in `go.mod` (`GOTOOLCHAIN=auto`)
9 - **Git** — for version control
10 - **Node.js 24+ and pnpm 10** (optional) — only if you work on the desktop app
11 (`desktop/`)
12
13 ## Getting started
14
15 ```bash
16 git clone https://github.com/esengine/DeepSeek-Reasonix.git
17 cd DeepSeek-Reasonix
18 go build ./cmd/reasonix # builds the CLI binary
19 go test ./... # runs the full test suite
20 ```
21
22 ## Project structure
23
24 | Directory | Purpose |
25 |-----------|---------|
26 | `cmd/reasonix` | CLI entry point |
27 | `internal/agent` | Agent loop, session, coordinator |
28 | `internal/cli` | TUI, subcommands, setup wizard |
29 | `internal/control` | Transport-agnostic controller |
30 | `internal/config` | TOML configuration loading |
31 | `internal/tool/builtin` | Built-in tools (bash, read_file, …) |
32 | `internal/provider` | Model-backend abstraction |
33 | `internal/provider/openai` | OpenAI-compatible provider |
34 | `internal/plugin` | MCP client (stdio + HTTP) |
35 | `internal/event` | Typed event stream |
36 | `internal/hook` | Shell hooks (PreToolUse, …) |
37 | `internal/memory` | REASONIX.md hierarchy + auto-memory |
38 | `internal/skill` | Skill discovery from Markdown |
39 | `internal/sandbox` | OS-level sandboxing |
40 | `internal/serve` | HTTP/SSE server frontend |
41 | `internal/checkpoint` | Snapshot-based rewind |
42 | `desktop/` | Electron desktop app + Go service (separate Go module) |
43 | `docs/` | Engineering spec, migration guide |
44
45 ### Dependency direction
46
47 ```
48 cli → {agent, plugin, config} → {tool, provider}
49 ```
50
51 Built-in subpackages import their parent to self-register via `init()`.
52 Parents never import children.
53
54 ## Development workflow
55
56 ### Building
57
58 ```bash
59 make build # go build ./...
60 make test # go test ./...
61 make vet # go vet ./...
62 make fmt # gofmt -w .
63 make hooks # install git hooks (pre-push: go vet)
64 make cross # cross-compile for all 6 targets
65 ```
66
67 ### Isolated development environment
68
69 A source-built binary shares no on-disk state with a stable release when launched
70 with `REASONIX_HOME` set. This gives each build its own self-contained directory
71 tree — config, credentials, sessions, cache, skills, commands, hooks, and
72 desktop tab state — so the two builds never interfere:
73
74 **CLI**
75
76 ```bash
77 REASONIX_HOME=/tmp/reasonix-dev go run ./cmd/reasonix
78 # or after building:
79 # REASONIX_HOME=/tmp/reasonix-dev ./bin/reasonix
80 ```
81
82 **Desktop**
83
84 ```bash
85 scripts/desktop-build.sh darwin/arm64 v0.0.0-dev # one platform per run
86 ```
87
88 On Windows, use `$env:REASONIX_HOME` in PowerShell or `set REASONIX_HOME=` in
89 Command Prompt; the binary extension is `.exe`.
90
91 The directory is empty on first launch; the app behaves exactly like a fresh
92 install. Every subsequent write — config saves, credential storage, session
93 logs — stays under `REASONIX_HOME`. Legacy migration, OS-home convention
94 directory scanning, and all other fallback paths are skipped so no production
95 data leaks in or out.
96
97 ### Cache-first review gate
98
99 Reasonix treats high prompt-cache hit rate as product behavior. Changes that
100 touch provider-visible system prompt construction, memory prefix, output styles,
101 skill index behavior, default tool surfaces, tool schemas, provider request
102 serialization, compaction, or MCP/tool registration need explicit cache review.
103
104 For these changes:
105
106 - Keep system prompt changes low-frequency and require explicit review.
107 - Fill the PR body `Cache-impact:` line with `none`, `low`, `medium`, or `high`
108 plus the reason.
109 - Fill the PR body `Cache-guard:` line with the focused guard test/command added
110 or run, or explain why an existing guard covers the change.
111 - Fill `System-prompt-review:` when system prompt, memory prefix, output style,
112 or skill index behavior changes.
113 - Prefer focused guard tests near the changed surface; `scripts/cache-guard.sh`
114 remains the broader release-level cache-hit check.
115
116 CI enforces this metadata for cache-sensitive paths so prompt/tool prefix churn
117 is called out before review.
118
119 ### Running tests
120
121 ```bash
122 go test ./... # all tests
123 go test ./internal/agent/ -v # verbose, one package
124 go test ./internal/tool/builtin/ -run TestGrep # one test
125 ```
126
127 Choose checks by the changed contract. Documentation-only changes need content
128 and link checks; Go changes need owning-package tests and applicable vet/lint
129 checks. Broaden to `go test ./...` for shared behavior. Desktop Go is a separate
130 module: run its affected packages or `cd desktop && go test ./...`.
131
132 For Go changes, format the changed files and use `make lint` (golangci-lint at
133 `.golangci-version` plus repolint). `go vet` does not cover all lint rules.
134 Install the pinned linter with `make lint-install` if needed. Repeat successful
135 checks only when new changes or unresolved risks justify it.
136
137 When adding an internal import, check the target package's test imports for a
138 reverse dependency and run the target package tests to catch setup cycles.
139
140 Desktop transcript scroll and history changes follow the
141 [scroll and history contract](docs/TRANSCRIPT_SCROLL_CONTRACT.md), including the
142 single writer, the bounded reading window, and deterministic regression cases via
143 `pnpm test:transcript` in `desktop/frontend/`.
144
145 Keep correctness gates deterministic. Prove concurrency and lifecycle ordering
146 with channels, injected clocks, state transitions, or emitted events instead of
147 asserting that an operation finishes within a small wall-clock interval on a
148 shared CI runner. Use a generous timeout only as a liveness watchdog. Performance
149 limits belong in an explicit benchmark that records evidence and uses the
150 benchmark's documented sampling rule; host integration probes may report an
151 advisory result when the runner cannot provide a controlled environment.
152
153 ### Code style
154
155 - `gofmt` is enforced by CI — format before committing
156 - Follow existing patterns: wrap errors with `fmt.Errorf("...: %w", err)`
157 - Library code never calls `os.Exit` or prints to stdout/stderr
158 - Only `cli/` and `main/` decide exit codes and user-facing messages
159 - Exported identifiers need useful doc comments; explain non-obvious constraints
160 rather than restating code. Mechanical limits live in
161 `tools/repolint/comments.go` and `tools/repolint/main.go`.
162 - `TODO(#nnn):` and `HACK(#nnn):` need an issue anchor; `FIXME` is rejected.
163 - Keep one responsibility per file. Repolint ratchets existing debt: an edit
164 cannot silently increase a file's recorded debt. Prefer removing redundancy
165 or extracting a coherent owner.
166 - A narrow baseline adjustment may carry existing debt through a rename or
167 extraction, or cover a small measured capacity increase whose design is clearer.
168 Explain the before/after values and rationale. Longer comments are justified
169 for non-obvious protocol, concurrency, compatibility, or recovery invariants.
170 Do not add broad slack, disable checks, or weaken correctness/security tests.
171
172 ### Commit messages
173
174 Follow [Conventional Commits](https://www.conventionalcommits.org/):
175
176 ```
177 feat(glob): add ** recursive pattern support
178 fix: replace silent error discards with structured logging
179 test(event): add comprehensive unit tests for event package
180 docs: add CONTRIBUTING.md
181 ci: add golangci-lint and govulncheck
182 ```
183
184 ### Review updates and PR metadata
185
186 Use ordinary follow-up commits and fast-forward pushes. Amend or force-push only
187 when explicitly authorized, after verifying the remote head. Keep unrelated
188 changes out of the PR.
189
190 Two CI guards read the PR body. The scripts are the source of truth and both
191 run locally: `scripts/check-cache-impact.sh`, `scripts/check-docs-impact.sh`.
192 Separators must be an ASCII `-` or `:` — an em dash fails the docs guard.
193
194 Cache-sensitive diffs (`internal/tool/`, `internal/provider/`,
195 `internal/boot/`, `internal/agent/agent.go`, and the rest of the list in the
196 script) require:
197
198 ```
199 Cache-impact: <none|low|medium|high> - <reason>
200 Cache-guard: <focused guard test/command or existing guard rationale>
201 ```
202
203 `none` is a legitimate impact when the provider-visible prefix stays
204 byte-identical; only an empty value, `todo`, or `tbd` is rejected. If the diff
205 also touches `internal/config/`, `internal/memory/`, `internal/outputstyle/`,
206 `internal/skill/`, or `internal/boot/`, add `System-prompt-review: <note>` —
207 that field additionally rejects `none` and `n/a`, so it must name the explicit
208 prompt reviewer or approval.
209
210 User-visible diffs (`cmd/reasonix/`, `desktop/`, `npm/`, and most of
211 `internal/`; tests and lockfiles are exempt) require one of these, chosen by
212 whether the same PR edited `docs/*.md`:
213
214 ```
215 Documentation-impact: updated - <what changed> # docs/*.md edited
216 Documentation-impact: none - <why the docs stay correct> # not edited
217 ```
218
219 ## Adding a new built-in tool
220
221 1. Create `internal/tool/builtin/mytool.go`
222 2. Implement the `tool.Tool` interface: `Name()`, `Description()`, `Schema()`, `ReadOnly()`, `Execute()`
223 3. Register via `func init() { tool.RegisterBuiltin(myTool{}) }`
224 4. Add tests in `internal/tool/builtin/builtin_test.go` or a separate `mytool_test.go`
225 5. The tool is automatically available — `main` blank-imports `builtin`
226
227 ## Adding a new model provider
228
229 (For MCP tool servers see `internal/plugin` instead — that's a different layer.)
230
231 1. Create `internal/provider/myprovider/`
232 2. Implement `provider.Provider`: `Name()`, `Stream()`
233 3. Register via `func init() { provider.Register("mykind", New) }`
234 4. The provider is available from config with `kind = "mykind"`
235
236 ## Adding i18n strings
237
238 1. Add the field to `internal/i18n/i18n.go` (`Messages` struct)
239 2. Add the value in `internal/i18n/messages_en.go` and `messages_zh.go`
240 3. The `TestCatalogsComplete` test will fail if you miss a locale
241
242 ## Submitting changes
243
244 1. Fork the repository
245 2. Create a feature branch from `main-v2`
246 3. Make the change and add regression coverage for affected behavior
247 4. Run the relevant checks above and satisfy required CI checks
248 5. Ensure changed Go files are formatted
249 6. Submit a pull request to `main-v2`
250
251 ## Reporting issues
252
253 Open an issue on GitHub with:
254 - Steps to reproduce
255 - Expected vs actual behavior
256 - Go version and OS
257 - Relevant logs or error messages
258
259 ## License
260
261 By contributing, you agree that your contributions will be licensed under the
262 same license as the project.
263
263 lines MARKDOWN