Files
spark-mcp/CLAUDE.md
T
tao.chenandClaude 210aeb1315 docs: CLAUDE.md 补 project-specific 工作流校准
~/.claude/CLAUDE.md 已经定义 Codex-first 路由、Codex MCP 强制参数、
Linus 三问、4-phase 工作流、prompt 模板、auto-confirm/pause 边界。本
文件不重复这些全局规则, 只加项目级校准:

- 路由表: 用本仓库实际任务举例 (GIN_MODE 接线 / loadDotenv 新增 /
  S1017 修 / .gitignore 行 / CLAUDE.md 自身 / 注释 typo / .env.example
  标题), 给出"trivial 阈值"在本项目的具体判据
- Codebase 模式: 指向 internal/httpclient/redirect_test.go (httptest
  + "127.0.0.1" 白名单), internal/logging/tool_call_test.go
  (bytes.Buffer + slog.NewJSONHandler 捕获), internal/mcp/tools/
  目录约定, 让未来 agent 进包前先读已有测试文件
- 预提交检查 (项目级): 强调 deferred-behavior test 是 gap-locking
  不是回归, 公共签名变更必须在 commit body 解释兼容性
- commit 消息规约: 从 git log 实际样本里抽出 <package>: 中文动词
  开头 + body 回答"gap / fix / 风险 / 锁定测试" + Co-Authored-By
- 项目坑: .env 不透明 / internal/ Go 强制 / multiHandler 双写
  (新事件 = 一次 base.Info 调用) / TestDoWithRedirect_DeferredRFC9110Gaps
  是 gap 测试不是 bug 报告

仅改 CLAUDE.md, 0 代码变更, 无需 build/test 验证.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-13 18:14:40 +08:00

129 lines
8.6 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Status
**This repository is freshly initialized.** The only Go source file is `main.go`, which is still the GoLand "Hello, gopher" template. The `go.mod` and `go.sum` already pin the intended runtime dependencies, but no application code has been written yet.
Intended purpose (inferred from module name and pinned dependencies): an **MCP (Model Context Protocol) server for Apache Spark**, written in Go, with HTTP transport, MongoDB-backed persistence, and a local `data/` directory for Spark connection state and pending job state (per `.gitignore`).
When working here, expect to be **building from scratch**, not modifying existing logic.
## Build, Test, Run
Standard Go toolchain (Go 1.25.5 per `go.mod`). All commands run from the repo root.
| Task | Command |
|---|---|
| Build | `go build ./...` |
| Run | `go run .` (currently just prints the template `main`) |
| Test (all) | `go test ./...` |
| Test (single test by name regex) | `go test -run TestName ./...` |
| Test (single test verbose) | `go test -v -run TestName ./path/to/pkg` |
| Test (with coverage) | `go test -cover ./...` |
| Vet (static analysis) | `go vet ./...` |
| Format | `gofmt -w .` |
| Tidy modules | `go mod tidy` |
| Download deps | `go mod download` |
There is no `Makefile`, no `golangci-lint` config, and no test files yet — do not assume they exist.
Cross-compile outputs are gitignored via the pattern `spark-mcp-*-*` (see `.gitignore`); do not commit stray build artifacts.
## Key Pinned Dependencies
`go.mod` declares these as `// indirect` (they will become direct once code is added that imports them):
- **`github.com/mark3labs/mcp-go v0.56.0`** — MCP server framework. This is the core library; all MCP tool/resource/prompt definitions will be built on top of it.
- **`github.com/gin-gonic/gin v1.12.0`** — HTTP router. Likely the transport layer that exposes the MCP server over HTTP (SSE / streamable HTTP).
- **`go.mongodb.org/mongo-driver/v2 v2.5.0`** — MongoDB client. Likely for persisting connection profiles, session state, and job history.
- **`github.com/bytedance/sonic v1.15.0`** — High-performance JSON encoder used internally by Gin.
## Layout Conventions
- Module path: `spark-mcp-go` (see `go.mod:1`). Local package import paths use this prefix.
- Runtime data directory: `data/` at the repo root, **gitignored**. Used for "persisted Spark connections / pending jobs" (per `.gitignore` comment). Anything that needs to survive across process restarts but should not go to MongoDB belongs here.
- IDE config: `.idea/` is gitignored — JetBrains (GoLand / IntelliJ) workspace files. Safe to delete; not part of the project.
## Things To Confirm Before Coding
The codebase is empty enough that a few decisions are not yet pinned down and will affect every subsequent file. Confirm with the user before assuming:
1. **MCP transport** — stdio, HTTP+SSE, or streamable HTTP? The Gin dependency suggests HTTP, but `mark3labs/mcp-go` supports both.
2. **Spark connectivity** — does this server submit jobs to an existing Spark cluster (REST / Livy / Spark Connect), or does it embed a Spark session (likely not — Spark itself is JVM/Scala and won't run in a Go binary)?
3. **Persistence split** — what goes in MongoDB vs. the local `data/` directory? The `.gitignore` implies both will be used.
4. **Configuration** — env vars? config file (YAML/JSON)? CLI flags? Nothing is wired up yet.
## Memory
This is a fresh repo with no `MEMORY.md` or project-level memory file. Decisions made during early development (transport choice, Spark backend interface, persistence schema) are worth recording once they are made — see the `claude-md-management` skill conventions.
---
# Working in this Repo
The rules in `~/.claude/CLAUDE.md` apply (Codex-first routing, mandatory Codex MCP invocation parameters, Linus three-question review, 4-phase workflow, Codex prompt template, auto-confirm vs pause boundaries). This section adds the **project-specific calibration** for applying them here.
## Routing: Codex vs CC
| Task in this repo | Executor | Why |
|---|---|---|
| Edit `main.go` to wire `cfg.GinMode` | Codex | One-line code change in production path |
| Add `loadDotenv` to `internal/config/config.go` | Codex | New function, real logic |
| Add a new test file | Codex | Even small, code generation is the strength |
| Edit `internal/httpclient/ssrf.go` to silence S1017 | Codex | Behavior must stay identical — needs verification |
| Update `.gitignore` line | CC | Single-line, no logic, mechanical |
| Update this `CLAUDE.md` | CC | Pure docs |
| Fix typo in a comment | CC | <20 lines, no logic |
| Update `.env.example` header comment | CC | Single line of prose |
**Threshold for "trivial enough for CC" in this repo:** purely textual, no code generation, <20 lines, no risk of subtle behavior change. When in doubt, default to Codex — the cost difference is small and Codex is more consistent at preserving invariants.
## Codebase Patterns to Reuse
When working in a package, **read the package's existing test file first** to see the established style before writing new code:
- **HTTP client mocks** — `internal/httpclient/redirect_test.go` uses `httptest.NewServer` with path-switch handlers. For SSRF / redirect tests, pass `"127.0.0.1"` as the allowed host.
- **slog capture in tests** — `internal/logging/tool_call_test.go` shows the pattern: `bytes.Buffer` + `slog.NewJSONHandler`, decode each line with `json.Unmarshal`, assert on `rec["msg"]`, `rec["level"]`, `rec["tool"]`. Reuse this for any new logger test.
- **MCP tool registration** — every tool lives in `internal/mcp/tools/<name>.go`. Schema is the first arg, handler is a method on the package's client struct. The tool's Go test file goes in the same directory.
## Pre-Commit Checklist (project-specific)
In addition to the global acceptance list, this repo's convention is:
- [ ] `go build ./...` — zero errors
- [ ] `go vet ./...` — zero warnings (catches the stringsseq / S1017 family)
- [ ] `go test ./...` — all green; new tests added for new behavior
- [ ] `gofmt -l .` — empty output (no diffs pending)
- [ ] No stray `spark-mcp-*-*` binary in repo root
- [ ] If behavior gap is intentionally deferred: add a deferred test that **locks the current behavior** (so a future fix must update the test deliberately) and a `TODO(<area>)` comment in the source with rationale
- [ ] If a public function signature changed: explain backward compatibility in the commit body
## Commit Message Convention
Observed in this repo's recent history:
```
<package>: <verb-led summary in Chinese>
<optional body: motivation, design tradeoffs, why-not-fix-X, what tests were added>
<optional "未提交: <file>" trailer for intentionally uncommitted artifacts>
Co-Authored-By: Claude <noreply@anthropic.com>
```
- Subject line: `<package>:` prefix (e.g. `httpclient:`, `rm:`, `admin:`, `config:`, `logging:`, `gitignore:`), then a short verb-led summary in Chinese.
- Body in Chinese; technical English terms (RFC numbers, status codes, test names, package paths) are fine in code form.
- Always end with the `Co-Authored-By` trailer.
- Body should answer: *what was the gap, why this fix, what could it have broken, what tests lock it in.* This is what makes the commit history a useful design record.
## Project-Specific Gotchas
- **`.env` is uncommitted and gitignored** — never try to read it, and never claim to know what's in it. Treat its existence as opaque.
- **Cross-compile artifacts** — `go build -o spark-mcp-linux-amd64 .` and similar produce files covered by the `spark-mcp-*-*` gitignore. Don't try to `git add` them.
- **`internal/` is enforced** — Go's `internal/` rule means sub-packages of `spark-mcp-go/internal/...` are importable only by `spark-mcp-go/...`. Cross-repo imports will fail; design packages accordingly.
- **Deferred-behavior tests are intentional** — `TestDoWithRedirect_DeferredRFC9110Gaps` is a *gap-locking* test, not a regression test. The assertions verify the gap, not the fix. Read the comment block above the test before "fixing" what looks like a bug.
- **YARN / SHS API surface is the source of truth** — the upstream REST API behavior (e.g. amContainerLogs being a 307 redirect, not a 303) drives the design. Don't invent redirect semantics; check what the cluster actually returns.
- **`log/slog` uses a `multiHandler` for dual terminal+file writing** — the `base *slog.Logger` passed to `StartToolCall` already routes through the main logger. Adding a new event is one `base.Info(...)` call; do not add a separate handler.