From 08106b0c3771ef5b4a5aa176acccd460e88b7325 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sun, 16 Aug 2026 15:18:33 +0900 Subject: [PATCH] docs: add hierarchical AGENTS.md knowledge base Root knowledge base plus complexity-scored subdirectory files for the rust/ workspace, its five highest-mass crates (runtime, rusty-claude-cli, api, tools, commands, plugins), and the src/ Python porting workspace. Generated via init-deep: 13 parallel explore agents, LSP/ast-grep code map, centrality-scored placement. Snapshot in .omo/init-deep.json (local). --- AGENTS.md | 92 ++++++++++++++++++++++++++ rust/AGENTS.md | 80 ++++++++++++++++++++++ rust/crates/api/AGENTS.md | 39 +++++++++++ rust/crates/commands/AGENTS.md | 37 +++++++++++ rust/crates/plugins/AGENTS.md | 39 +++++++++++ rust/crates/runtime/AGENTS.md | 46 +++++++++++++ rust/crates/rusty-claude-cli/AGENTS.md | 60 +++++++++++++++++ rust/crates/tools/AGENTS.md | 47 +++++++++++++ src/AGENTS.md | 69 +++++++++++++++++++ 9 files changed, 509 insertions(+) create mode 100644 AGENTS.md create mode 100644 rust/AGENTS.md create mode 100644 rust/crates/api/AGENTS.md create mode 100644 rust/crates/commands/AGENTS.md create mode 100644 rust/crates/plugins/AGENTS.md create mode 100644 rust/crates/runtime/AGENTS.md create mode 100644 rust/crates/rusty-claude-cli/AGENTS.md create mode 100644 rust/crates/tools/AGENTS.md create mode 100644 src/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..19789100 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,92 @@ +# PROJECT KNOWLEDGE BASE + +**Generated:** 2026-08-16 +**Commit:** b71afdd +**Branch:** main + +## OVERVIEW +Claw Code: public Rust implementation of the `claw` CLI agent harness (Claude-Code-style). Canonical code lives in `rust/`; the repo is an agent-managed exhibit (harnesses plan/execute/verify per README), not a hand-operated product. `src/` is a companion Python porting/parity workspace, not production code. + +## STRUCTURE +``` +claw-code/ +├── rust/ # canonical Cargo workspace: 11 crates, `claw` binary +├── src/ # Python porting workspace + reference_data/ parity snapshots +├── tests/ # Python unittest validation of src/ + scripts/ (stdlib unittest) +├── docs/ # g0XX gate verification maps + topic docs +├── scripts/ # fmt.sh, dogfood-build.sh, roadmap/board helpers +├── assets/ # README images only +└── install.sh, Containerfile, docker-compose.yml +``` + +## WHERE TO LOOK +| Task | Location | Notes | +|------|----------|-------| +| CLI subcommands | rust/crates/rusty-claude-cli/src/main.rs | hand-rolled parser; CliAction enum ~L1162; dispatch in run() L995-1158 | +| Sessions/permissions/MCP | rust/crates/runtime/src/ | 47 flat modules | +| Provider clients | rust/crates/api/src/providers/ | anthropic.rs + openai_compat.rs | +| Tool definitions | rust/crates/tools/src/lib.rs | 55-tool spec table L484-1348 | +| Slash commands | rust/crates/commands/src/lib.rs | 120+ spec table L60-1047 | +| Plugins/hooks | rust/crates/plugins/src/ | manifest = .claude-plugin/plugin.json | +| Lean agent harness | rust/crates/claw-analog/src/lib.rs | lib+bin; tool loop over api+runtime | +| RAG HTTP service | rust/crates/claw-rag-service/src/ | axum; SQLite + optional Qdrant | +| Test mock server | rust/crates/mock-anthropic-service/ | SCENARIO_PREFIX scripted responses | +| Python porting CLI | src/main.py | argparse: manifest, parity-audit, graphs | +| Parity reference DB | src/reference_data/subsystems/ | 29 JSON snapshots of TS archive | + +## CODE MAP +| Symbol | Type | Location | Refs | Role | +|--------|------|----------|------|------| +| Session | struct | runtime/src/session.rs:117 | 229 | session persistence/lifecycle | +| ConfigLoader | struct | runtime/src/config.rs:409 | 83 | config schema/load | +| PluginManager | struct | plugins/src/lib.rs | 48 | plugin install/registry | +| PermissionEnforcer | struct | runtime/src/permission_enforcer.rs:27 | 35 | pre-dispatch permission gate | +| ConversationRuntime | struct | runtime/src/conversation.rs:130 | 32 | conversation loop driver | +| McpServerManager | struct | runtime/src/mcp_stdio.rs:488 | 30 | MCP JSON-RPC processes | +| HookRunner | struct | runtime/src/hooks.rs:155 | 25 | shell hook execution | +| CliAction | enum | rusty-claude-cli/src/main.rs:1162 | — | 25 subcommand variants | +| mvp_tool_specs | fn | tools/src/lib.rs:484 | — | static 55-tool table | +| SLASH_COMMAND_SPECS | const | commands/src/lib.rs:60 | — | 120+ slash commands | + +(Refs = rg count across rust/crates; rust-analyzer references timed out during mapping.) + +## CONVENTIONS +- `unsafe_code = "forbid"` workspace-wide; every crate opts in via `[lints] workspace = true`; clippy all=warn, pedantic=allow +- Edition 2021, resolver 2, publish=false; no rust-toolchain pin (CI floats stable); no rustfmt.toml/clippy.toml — stock defaults +- Giant flat files by design (main.rs 19.8k, tools/lib.rs 10.9k, commands/lib.rs 7.2k): organization is positional — types → spec table → dispatch → handlers → tests at EOF +- Dual output paths everywhere: `render_x` + `render_x_json`; JSON errors to **stdout**, text errors to **stderr** +- Tests: inline `#[cfg(test)] mod tests` primary; integration tests spawn `CARGO_BIN_EXE_claw` subprocess against mock-anthropic-service; tempfile everywhere; env-mutating tests serialize via env_lock/test_env_lock +- Comments carry issue numbers (#824, #146); gate tests named by roadmap gate (g004_conformance.rs) +- Python side: stdlib only, `python -m unittest`; src/ mixes camelCase (QueryEngine.py) and snake_case filenames + +## ANTI-PATTERNS (THIS PROJECT) +- NEVER `cargo install claw-code` — crates.io stub is deprecated and installs `claw-code-deprecated.exe`; build from source +- Forbidden doc strings (CI-enforced by .github/scripts/check_doc_source_of_truth.py): old org links `github.com/Yeachan-Heo/claw-code`, `github.com/code-yeongyu/claw-code`, `discord.gg/6ztZB9jvWq`, `assets/clawd-hero.jpeg` +- Deprecated config keys: `permissionMode` → `permissions.defaultMode`; `enabledPlugins` → `plugins.enabled`; env `RUSTY_CLAUDE_PERMISSION_MODE` is dead +- Direct push to main is policy-blocked (`main_push_forbidden` approval scope) +- Automation lanes must not merge/close remote PRs/issues (docs/anti-slop-triage.md) +- `claw init` must not scaffold `dontAsk` permission mode (regression-pinned in output_format_contract.rs) +- File-level `#![allow(dead_code)]` blocks (main.rs, session_control.rs) are tolerated legacy — do not extend the pattern + +## UNIQUE STYLES +- Dogfood build: scripts/dogfood-build.sh injects GIT_SHA; `claw version` provenance must equal HEAD +- Mock parity: rust/mock_parity_scenarios.json drives CLI subprocess vs MockAnthropicService +- Dogfooding uses `CLAW_CONFIG_HOME=$(mktemp -d)` for config isolation +- Env contracts: GIT_SHA (build), CLAW_CONFIG_HOME (config dir), OLLAMA_HOST (provider override), `*_API_KEY`/`*_BASE_URL` per provider + +## COMMANDS +```bash +scripts/fmt.sh --check # fmt check (apply: scripts/fmt.sh) +cd rust && cargo clippy --workspace --all-targets -- -D warnings +cd rust && cargo test --workspace +cd rust && cargo build -p rusty-claude-cli # binary: rust/target/debug/claw +python -m unittest discover -s tests # Python suite +python .github/scripts/check_doc_source_of_truth.py && scripts/roadmap-check-ids.sh # docs/roadmap CI +``` + +## NOTES +- `claw` binary comes from crate `rusty-claude-cli` (package/bin name mismatch) +- rust-ci.yml triggers only on rust/**, docs/**, listed meta file changes (path filters) +- CI clippy job runs without `-D warnings` — weaker than the documented gate; known pre-existing failures recorded in docs/g002/g003 maps +- `claw acp` is a status stub, not a real ACP server +- rust/ has committed harness dotdirs (.clawd-agents/, .omc/, .sandbox-home/) — intentional diff --git a/rust/AGENTS.md b/rust/AGENTS.md new file mode 100644 index 00000000..efb7844d --- /dev/null +++ b/rust/AGENTS.md @@ -0,0 +1,80 @@ +# AGENTS.md — rust/ workspace + +## OVERVIEW + +Virtual Cargo workspace (resolver 2, edition 2021) housing 11 crates that compose the `claw` CLI and supporting services. + +## STRUCTURE + +| Crate | Kind | Purpose | +|---|---|---| +| `rusty-claude-cli` | bin (`claw`) | Main CLI binary. Package name ≠ binary name. | +| `claw-analog` | lib+bin | Alternate entry point; depends on api + runtime only. | +| `claw-rag-service` | bin | RAG service. Only crate with `[features]` (`qdrant-index`). | +| `mock-anthropic-service` | lib+bin | Mock Anthropic Messages API. Prints `MOCK_ANTHROPIC_BASE_URL`. Dev-dep for CLI and analog tests. | +| `runtime` | lib | Core: sessions, permissions, MCP, conversation loop. ~47 modules. | +| `api` | lib | Provider clients: Anthropic, OpenAI-compat (xAI, OpenAI, DashScope, Ollama). | +| `tools` | lib | 55-tool surface area. Depends on `commands` (not vice versa). | +| `commands` | lib | 120+ slash commands. | +| `plugins` | lib | Plugin manifest and lifecycle. | +| `telemetry` | lib | Request identity + analytics sinks. | +| `compat-harness` | lib | Extracts upstream TS claude-code manifest/commands/tools for parity comparison. | + +Dependency direction: `rusty-claude-cli` → tools/commands/runtime/api/plugins. `tools` → `commands`. + +## WHERE TO LOOK + +- **Parity testing**: `mock_parity_scenarios.json` at workspace root, loaded via `CARGO_MANIFEST_DIR/../../mock_parity_scenarios.json`. Scripts in `scripts/` (`run_mock_parity_harness.sh`, `run_mock_parity_diff.py`). +- **CI**: `.github/workflows/rust-ci.yml` (fmt, clippy, test, docs, Windows smoke) and `release.yml` (v* tag builds for linux-x64/macos-arm64/windows-x64). +- **Committed test fixtures**: `.clawd-agents/`, `.omc/`, `.sandbox-home/` are checked-in harness dotdirs. +- **Docs**: `PARITY.md`, `TUI-ENHANCEMENT-PLAN.md`, `README.md` alongside this file. + +## CONVENTIONS + +Workspace lints (all crates opt in via `[lints] workspace = true`): +- `unsafe_code` = **forbid**. No exceptions. +- clippy `all` = warn, `pedantic` = allow. Explicitly allowed: `module_name_repetitions`, `missing_panics_doc`, `missing_errors_doc`. + +No `rustfmt.toml` or `clippy.toml`. Stock defaults only. + +TUI rule: formatting fns take `&mut impl Write`, never stdout directly. Never mix raw ANSI escapes with crossterm. + +Library crates don't carry the `claw-` prefix. Binary crates do (except legacy `rusty-claude-cli`). + +Workspace version is `0.1.3`, `publish = false`, MIT license. + +No rust-toolchain file, no MSRV. CI pins `dtolnay/rust-toolchain@stable`. + +## ANTI-PATTERNS + +- Don't run `cargo fmt --manifest-path rust/Cargo.toml` from the repo root. Use `../scripts/fmt.sh` instead. +- Don't add `unsafe` code. The lint is set to `forbid`, not `deny`. You can't `#[allow]` it. +- Don't create dependencies from `commands` → `tools`. The arrow goes `tools` → `commands`. +- Don't write TUI output directly to stdout or use raw ANSI escape sequences. +- Don't add features to crates other than `claw-rag-service` without good reason; the workspace is feature-lean by design. + +## COMMANDS + +All run from `rust/`: + +```sh +# Format (check only) +../scripts/fmt.sh --check + +# Format (apply) +../scripts/fmt.sh + +# Lint (strict, matches what you should pass before pushing) +cargo clippy --workspace --all-targets -- -D warnings + +# Test +cargo test --workspace + +# Build specific binary +cargo build -p rusty-claude-cli +cargo build -p claw-analog +cargo build -p claw-rag-service +cargo build -p mock-anthropic-service +``` + +Note: CI clippy runs without `-D warnings`, so the local check above is stricter than the gate. diff --git a/rust/crates/api/AGENTS.md b/rust/crates/api/AGENTS.md new file mode 100644 index 00000000..c6214bb9 --- /dev/null +++ b/rust/crates/api/AGENTS.md @@ -0,0 +1,39 @@ +# AGENTS.md — api crate + +## OVERVIEW + +LLM provider client layer: dispatches Anthropic, xAI, OpenAI, DashScope, and Ollama behind two wire protocols (Anthropic Messages native, OpenAI Chat Completions compat). + +## WHERE TO LOOK + +| Module | What lives here | +|---|---| +| `client.rs` | `ProviderClient` enum (facade). `from_model(model)` resolves alias, picks `ProviderKind`, handles OLLAMA_HOST and DashScope qwen-prefix cases. `send_message`/`stream_message`. | +| `providers/mod.rs` | `Provider` trait (generic, dead_code-allowed, not used for dispatch). `ProviderKind`, `resolve_model_alias`, `ProviderMetadata` (auth_env, base_url_env, default_base_url), `max_tokens_for_model[_with_override]`, capability/diagnostic reporting, `preflight_message_request` validation. | +| `providers/anthropic.rs` | `AnthropicClient` (re-exported as `ApiClient` at crate root). Dual auth: API key env vs saved OAuth (`AuthSource`, `OAuthTokenSet`, token expiry checks). Base-url resolution. SSE `MessageStream`. Prompt-cache hooks. | +| `providers/openai_compat.rs` | `OpenAiCompatClient` parameterized by `OpenAiCompatConfig` (presets: `xai()`, `openai()`, `dashscope()`, `OLLAMA_CONFIG`). Heavy translation layer: `build_chat_completion_request`, `translate_message`, `sanitize_tool_message_pairing`, `flatten_tool_result_content`. Model-quirk predicates (`is_reasoning_model`, etc.). Body-size estimation/guards. | +| `types.rs` | Provider-agnostic wire types: `MessageRequest`, `InputMessage`, `ContentBlock`, `StreamEvent`, `Usage`, `ToolDefinition`, `ToolChoice`. | +| `sse.rs` | `SseParser`, `parse_frame`. | +| `http_client.rs` | reqwest builders, `ProxyConfig` from env proxy vars, `TimeoutConfig`. | +| `error.rs` | `ApiError`. | +| `prompt_cache.rs` | `PromptCache` + `Stats` (Anthropic-only). | +| `lib.rs` | Curated `pub use` lists define the public surface. Also re-exports sibling telemetry crate items. | + +## CONVENTIONS + +- Module-private by default. `lib.rs` `pub use` lists are the sole public API surface. +- `#[must_use]` on pure constructors. +- Provider config follows an env-var pair pattern: `*_API_KEY` / `*_BASE_URL`, recorded in `ProviderMetadata`. +- Leaf files carry targeted `#![allow(clippy::cast_possible_truncation)]` where needed. +- Dispatch goes through the `ProviderClient` enum, not trait objects. The `Provider` trait exists but is dead-code-allowed. +- Streams unify into `MessageStream` with `next_event()` yielding `StreamEvent`. + +## TESTS + +- Four integration test files under `tests/`: + - `client_integration` — core client behavior + - `openai_compat_integration` — OpenAI-compat translation paths + - `provider_client_integration` — `ProviderClient` dispatch + - `proxy_integration` — proxy config +- Tests that touch env vars serialize through a shared `env_lock()` mutex. Don't skip this or you'll get flaky parallel failures. +- `benches/request_building.rs` is the workspace's only Criterion bench. Targets hot translation functions. This file bulk-opts out of strict lints. diff --git a/rust/crates/commands/AGENTS.md b/rust/crates/commands/AGENTS.md new file mode 100644 index 00000000..340dab6d --- /dev/null +++ b/rust/crates/commands/AGENTS.md @@ -0,0 +1,37 @@ +# commands crate + +## OVERVIEW + +REPL slash-command surface: parsing, spec registry, help rendering, and a handful of in-crate handlers. Single flat `src/lib.rs` (~7k lines). Deps: `plugins`, `runtime`, `serde_json` only. Note: `tools` depends on `commands`, not the reverse. + +## lib.rs MAP + +| Lines | Landmark | +|-------------|----------| +| 16–58 | Registry types: `CommandManifestEntry`, `CommandSource` (Builtin / InternalOnly / FeatureGated), `CommandRegistry`, `SlashCommandSpec`, `SkillSlashDispatch` | +| 60–1047 | `SLASH_COMMAND_SPECS` static table. 120+ entries (help, status, sandbox, compact, model, permissions, clear, cost, resume, config, mcp, memory, init, diff, version, bughunter, commit, pr, issue, ultraplan, teleport, debug-tool-call, export, session, plugin, agents, skills, doctor, plan, review, tasks, theme, vim, voice, chat, ...) | +| 1048–1303 | `SlashCommand` enum (~65 variants + `Unknown(String)`), `SlashCommandParseError`, `SlashCommand::parse` (L1218) | +| 1515–1899 | Per-command arg parsers: `parse_mcp_command`, `parse_plugin_command`, `parse_session_command`, etc. | +| 1900–2108 | Help/suggestion rendering: `render_slash_command_help*`, `suggest_slash_commands` (Levenshtein), category grouping | +| 2109–2682 | Result types + handlers: `handle_plugins_slash_command`, `handle_agents/mcp/skills_slash_command(_json)`, skill dispatch/resolve | +| 3160–5293 | Reporting layer: paired text and `_json` renderers for plugins/agents/skills/mcp reports, skill install/uninstall/create-agent logic, frontmatter parsing, root discovery | +| 5294 | `handle_slash_command(input, session, compaction)` top dispatch. Only Compact and Help execute here; all other variants return to the REPL caller | +| 5403–7183 | `mod tests` (~1780 lines) | + +## ADDING A SLASH COMMAND + +1. **Spec.** Add a `SlashCommandSpec` entry to `SLASH_COMMAND_SPECS`. Set `resume_supported` honestly. +2. **Enum + parse.** Add a variant to `SlashCommand`. Wire a match arm in `SlashCommand::parse`. If the command takes arguments, add a dedicated `parse_*_command` function in the arg-parser block. +3. **Handler.** Decide where execution lives: + - In-crate (like Compact/Help): handle it inside `handle_slash_command`. + - Returned to caller: just return the parsed variant. The REPL layer executes it. +4. **Help.** Make sure the spec's `summary` and `argument_hint` are set so help rendering and suggestion matching pick it up automatically. +5. **Tests.** Cover parsing (valid input, bad input, edge cases) in the inline `mod tests`. + +## CONVENTIONS + +- **Dual renderers.** Every report surface has a text variant and a `_json` variant: `handle_x` / `handle_x_json`, `render_*` / `render_*_json`. Keep them in sync. +- **Error style.** Handlers return `std::io::Result`. Parse failures use `SlashCommandParseError`. +- **Manifest registries.** Pattern is `entries: Vec<_Entry>` backed by the static spec table. +- **Dependency direction.** This crate knows nothing about `tools`. Don't import it. +- **No execution here.** Almost all commands pass through as parsed data. Only Compact and Help run inside this crate. Respect that boundary. diff --git a/rust/crates/plugins/AGENTS.md b/rust/crates/plugins/AGENTS.md new file mode 100644 index 00000000..87953c49 --- /dev/null +++ b/rust/crates/plugins/AGENTS.md @@ -0,0 +1,39 @@ +# AGENTS.md — plugins crate + +## OVERVIEW + +Plugin subsystem: how third-party, builtin, and bundled tools/commands/hooks enter the runtime. + +## WHERE TO LOOK + +- `src/lib.rs` (~3,863 lines): the bulk of the crate. Manifest parsing (`.claude-plugin/plugin.json`), installed-plugin registry, lifecycle model, permission model, install/update management. +- `src/hooks.rs`: hook event model (`HookEvent`, `HookRunResult`) and `HookRunner` for shell-hook execution. Re-exported from `lib.rs`. **Caution:** the runtime crate has its own `hooks.rs` with a separate `HookRunner` (execution + abort-signal side, around L155). Know which layer you need before editing. +- `src/test_isolation.rs`: test isolation helpers. +- `bundled/`: example plugin fixtures. `example-bundled/` and `sample-hooks/` each contain `.claude-plugin/plugin.json` plus `pre.sh`/`post.sh` shell hooks. Treat these as the reference shape when authoring a new plugin. + +## CONVENTIONS + +**Key public types** (all in `src/lib.rs` unless noted): + +- Kinds/definitions: `PluginKind`, `PluginDefinition`, `BuiltinPlugin`, `BundledPlugin`, `ExternalPlugin`. +- Manifests: `PluginManifest`, `PluginToolManifest`, `PluginToolDefinition`, `PluginToolPermission`, `PluginCommandManifest`. +- Hooks: `PluginHooks`, `HookEvent`, `HookRunResult` (from `hooks.rs`). +- Lifecycle/permissions: `PluginLifecycle`, `PluginPermission`. +- Registry: `InstalledPluginRecord`, `InstalledPluginRegistry`, `RegisteredPlugin`, `PluginRegistry` (+ `Report`, `Summary`, `LoadFailure`). +- Management: `PluginManager` (+ `Config`), `InstallOutcome`, `UpdateOutcome`. +- Trait: `Plugin`. +- Errors: `PluginError`. +- Entry points: `builtin_plugins()`, `load_plugin_from_directory()`. + +**Lifecycle spans two crates.** Manifest parsing and registry live here. Health checks, degraded-mode, and `PluginState` live in `runtime/src/plugin_lifecycle.rs`. Changes to plugin lifecycle logic often touch both. + +**Plugin shape.** A plugin directory contains `.claude-plugin/plugin.json` at minimum. Shell hooks (`pre.sh`, `post.sh`) sit alongside. See `bundled/` for working examples. + +**Consumers.** `PluginManager` has ~48 references across the workspace. CLI wires plugins via `RuntimePluginStateBuildOutput` in `rusty-claude-cli`. The tools crate exposes plugin tools through `GlobalToolRegistry`. + +## NOTES + +- Don't confuse the two `HookRunner` implementations. This crate's version handles the event model. The runtime crate's version handles execution and abort signals. +- `lib.rs` is large. Most searches for plugin behavior start and end there. +- Bundled plugin fixtures under `bundled/` are used in tests. Breaking their structure breaks CI. +- Permission model is enforced at install time and checked at runtime. Both paths matter when modifying `PluginPermission`. diff --git a/rust/crates/runtime/AGENTS.md b/rust/crates/runtime/AGENTS.md new file mode 100644 index 00000000..04c6542f --- /dev/null +++ b/rust/crates/runtime/AGENTS.md @@ -0,0 +1,46 @@ +# AGENTS.md — runtime crate + +## OVERVIEW + +Core crate of `claw`: session persistence, permissions, prompt assembly, MCP plumbing, tool-facing file ops, conversation loop. 47 flat modules in src/, ~330 pub symbols, ~170 re-exported flat from lib.rs. + +## WHERE TO LOOK + +| Group | Files | Entry points | +|---|---|---| +| session/conversation | session.rs, session_control.rs, conversation.rs, compact.rs, summary_compression.rs, usage.rs | `Session` (L117), `SessionStore`, `ConversationRuntime` (L130), `ApiClient`/`ToolExecutor` traits | +| config | config.rs, config_validate.rs, bootstrap.rs | `ConfigLoader` (L409), type-export heaviest file; MCP server config enums live here | +| MCP (6-file split) | mcp.rs, mcp_client.rs, mcp_stdio.rs, mcp_server.rs, mcp_tool_bridge.rs, mcp_lifecycle_hardened.rs | `McpServerManager` (L488 in mcp_stdio.rs), JSON-RPC spawn | +| hooks/plugins | hooks.rs, plugin_lifecycle.rs | `HookRunner` (L155), abort signal, healthcheck, degraded mode | +| permissions/safety | permissions.rs, permission_enforcer.rs, policy_engine.rs, approval_tokens.rs, sandbox.rs, bash_validation.rs, trust_resolver.rs | `PermissionEnforcer` (L27), `GreenLevel`, lane decisions | +| tools/execution | bash.rs, file_ops.rs, lsp_client.rs | `execute_bash`, `*_in_workspace` file op variants | +| lane/worker | lane_events.rs, worker_boot.rs, task_packet.rs, task_registry.rs, team_cron_registry.rs, branch_lock.rs, stale_base.rs, stale_branch.rs | `LaneEvent` dedupe/provenance, `LaneBoard` | +| prompt | prompt.rs | `SystemPromptBuilder`, `ContextFile`, dynamic boundary marker | +| git/remote/auth | git_context.rs, remote.rs, oauth.rs | Upstream proxy, PKCE flow | +| misc | json.rs, sse.rs, g004_conformance.rs, green_contract.rs, recovery_recipes.rs, report_schema.rs, trident.rs | Report v1 + redaction | + +Largest files by line count: config.rs (3894), mcp_stdio.rs (2969), lane_events.rs (2561), worker_boot.rs (2441), session.rs (1961), conversation.rs (1878). + +## CONVENTIONS + +- One file per module, flat layout. No subdirectories. +- Most modules are private `mod x` with selective `pub use`. 21 modules are `pub mod`, so consumers use both the re-export and the qualified path. +- Deps kept minimal: serde, tokio, glob, regex, sha2, walkdir + internal plugins/telemetry. No reqwest, no async-trait. Remote/SSE done by hand. +- Inline `#[cfg(test)]` tests per file. session.rs has two test modules. +- `pub(crate) test_env_lock()` mutex in lib.rs serializes env-mutating tests. Use it when touching env vars. +- trust_resolver.rs is `#[cfg(test)]`-gated yet pub-used: test-only API surface. + +## INVARIANTS (do not break) + +1. **Compaction pairs**: compact.rs must never split assistant(ToolUse)/ToolResult pairs. +2. **No side effects on construction**: SessionStore construction must not create `.claw` directories (session_control.rs:1090). +3. **Workspace containment**: file_ops.rs workspace ops must not escape the workspace root. +4. **Permission ordering**: a leading read-only permission token must not launder a trailing destructive one (permission_enforcer.rs:450). + +## ANTI-PATTERNS + +- Don't extend whole-file `#![allow(...)]` blocks. They exist as legacy tolerance in worker_boot.rs, mcp_tool_bridge.rs, lsp_client.rs, stale_branch.rs, stale_base.rs, recovery_recipes.rs, mcp_lifecycle_hardened.rs, session_control.rs. Adding new ones is not acceptable. +- Don't add reqwest or async-trait as deps. Remote calls go through the manual SSE/proxy layer in remote.rs and sse.rs. +- Don't create subdirectories under src/. The flat module layout is intentional. +- Don't bypass `*_in_workspace` variants for file ops when running inside a workspace context. The unchecked versions exist for bootstrap and out-of-workspace scenarios only. +- Don't add new `pub mod` exports without reason. Prefer private mod + selective `pub use` from lib.rs. diff --git a/rust/crates/rusty-claude-cli/AGENTS.md b/rust/crates/rusty-claude-cli/AGENTS.md new file mode 100644 index 00000000..21737214 --- /dev/null +++ b/rust/crates/rusty-claude-cli/AGENTS.md @@ -0,0 +1,60 @@ +# AGENTS.md — rusty-claude-cli (the `claw` binary) + +## OVERVIEW + +Crate `rusty-claude-cli` produces the `claw` binary (~25 subcommands). Wires together api, runtime, tools, commands, plugins; terminal via crossterm/rustyline/syntect. Hand-rolled arg parser (no clap). + +## main.rs MAP + +src/main.rs is ~19,800 lines. Landmark table: + +| Lines | Section | +|---|---| +| 73–330 | Provenance/model types (`ModelSource`, `ModelProvenance`, `PermissionModeSource`), build constants | +| 330–682 | Error taxonomy (`classify_error_kind`, JSON/text error output) | +| 774–994 | Global flags, `--cwd`/`-C` stripping, stdin plumbing | +| 995–1158 | `run()`: single flat match dispatching `CliAction` variants | +| 1162–1280 | `CliAction` enum, 25 struct variants (each carries `output_format`) | +| 1312–1477 | Output-format machinery: `OnceLock` statics, duplicate-flag tracking | +| 1478–2272 | `parse_args`: ~800-line manual token loop | +| 2542–3389 | Per-subcommand sub-parsers inside `parse_args` | +| 2902–3389 | Model/permission/allowed-tools resolution | +| 3390–4696 | Doctor subsystem (~13 `check_*_health` fns) | +| 4697–6062 | Manifests, bootstrap-plan, system-prompt, version, `resume_session` | +| 5459–7047 | `StatusContext`, `BinaryProvenance`, broad-cwd policy, stale-base preflight | +| 7048–9423 | `run_repl` interactive loop (`LiveCli` struct, streaming, heartbeat, `HookAbortMonitor`) | +| 9424–14264 | Snapshot printers: session-list, status, sandbox, models, help topics, acp, `run_init` (L11027), `run_export` (L11715), `print_help` (L14055) | +| 14266–19831 | In-file `mod tests` + 3 smaller test modules (one embeds a Python MCP fixture) | + +## CONVENTIONS + +- Every subcommand supports `--output-format text|json`, env-overridable. +- `raw_args_request_json_output` pre-scans argv before parsing to suppress stderr config warnings in JSON mode. +- Dual renderers for each output path: human text + structured `*_json`. +- Unknown flags/typos get levenshtein-distance suggestions. +- Comments carry issue numbers (#824, #146, etc.) when tracking known problems. +- `main()` (L330) is only the error envelope. All real work happens in `run()`. +- Error output always includes `status`, `error_kind`, `action`, `hint`, `exit_code` fields. +- `classify_error_kind` maps message prefixes to snake_case kind tokens. +- JSON errors go to stdout, text errors to stderr. +- Sibling modules: `init.rs`, `input.rs` (rustyline), `render.rs` (MarkdownStreamState, Spinner, syntect), `setup_wizard.rs`. +- `build.rs` injects `GIT_SHA`, `RUSTC_VERSION`, `GIT_DIRTY` via `cargo:rustc-env`. + +## ANTI-PATTERNS + +- File opens with crate-wide `#![allow(...)]` suppressing 13 lints including `dead_code` and `unused_imports`. Legacy. Do NOT extend this list. +- 9+ functions carry `#[allow(clippy::too_many_lines)]`. Tolerated, not license for more. +- Package/bin name mismatch: crate is `rusty-claude-cli`, binary is `claw`. Watch for this in paths and test macros. + +## TESTS + +All tests live in `tests/` (6 files), black-box style. They spawn `env!("CARGO_BIN_EXE_claw")` in unique temp dirs (AtomicU64 counter). + +| File | What it covers | +|---|---| +| `output_format_contract.rs` | ~105 tests pinning `kind`/`status`/`action` JSON contract for EVERY subcommand. Must update when adding/changing any command output. 5,986 lines. | +| `resume_slash_commands.rs` | Resume and slash-command behavior | +| `cli_flags_and_config_defaults.rs` | Flag parsing, config file defaults | +| `compact_output.rs` | Compact output mode | +| `compact_repl_panic.rs` | Nested-runtime panic regression | +| `mock_parity_harness.rs` | Scenario-driven tests against mock-anthropic-service, driven by `rust/mock_parity_scenarios.json` | diff --git a/rust/crates/tools/AGENTS.md b/rust/crates/tools/AGENTS.md new file mode 100644 index 00000000..0ab54c58 --- /dev/null +++ b/rust/crates/tools/AGENTS.md @@ -0,0 +1,47 @@ +# AGENTS.md — rust/crates/tools + +## OVERVIEW + +Single-crate tool surface: registry, 55 tool specs, permission-gated dispatch, all implementations. One flat `src/lib.rs` (10,892 lines, ~37% tests). + +## lib.rs MAP + +| Lines | Landmark | +|-------------|----------| +| 1–74 | Imports + six `global_*_registry()` OnceLock singletons (Lsp, McpTool, Team, Cron, Task, Worker) | +| 75–483 | Registry API: `ToolManifestEntry`, `ToolSource`, `ToolRegistry`, `ToolSpec`, `GlobalToolRegistry`, `RuntimeToolDefinition`, `canonical_allowed_tool_name` | +| 484–1348 | `mvp_tool_specs()` static table of 55 tools with inline JSON schemas | +| 1349–1524 | `enforce_permission_check` + `execute_tool()` string-match dispatch, permission classification helpers | +| 1525–2735 | `run_*` wrappers: deserialize input, call into `execute_*` or runtime fns | +| 2736–2763 | `workspace_traversal_guard_tests` mod | +| 2764–3354 | ~45 private serde IO structs | +| 3355–6824 | Real implementations: web fetch/search, todo store, skill resolution, agent/subagent spawning (`ProviderRuntimeClient` L5182, `SubagentToolExecutor` L5361), notebook edit, sleep, config, plan-mode, structured output, REPL, PowerShell | +| 6825–6826 | `pub mod lane_completion; pub mod pdf_extract;` | +| 6829–10892 | `mod tests` (~4000 lines) | + +## ADDING A TOOL + +1. Add a `ToolSpec` entry in `mvp_tool_specs()`. Include `name`, `description`, `input_schema` (inline JSON), and `required_permission: PermissionMode`. +2. Add a dispatch arm in `execute_tool()` matching the tool name string. +3. Write a `run_()` wrapper. Deserialize input from a dedicated serde struct. +4. Implement the actual logic below L3355 (or call into another crate). +5. Add inline tests in `mod tests`. Follow BDD naming: `given_x_when_y_then_z`. +6. Permission gating is automatic: `GlobalToolRegistry` / `SubagentToolExecutor` hold an optional `PermissionEnforcer` checked pre-dispatch. + +## CONVENTIONS + +- **Tool boundary signature**: `Result`. Always. +- **Tool naming**: snake_case for file/shell tools, PascalCase otherwise. `canonical_allowed_tool_name` normalizes aliases. +- **State**: OnceLock registries for global singletons. JSON state files under config dirs for persistence. +- **Input validation**: reject empty strings for todos, descriptions, prompts, messages, code. ~12 validation sites between L3806–6167. Keep that contract. +- **Test naming**: BDD style (`given_x_when_y_then_z`). +- **Env-mutating tests**: acquire `env_lock()` mutex first. +- **Dependencies**: runtime, api, plugins, commands, reqwest(blocking), aspect-*, tokio. + +## ANTI-PATTERNS + +- **Don't add more `#[allow(clippy::...)]` suppressions.** ~50 `needless_pass_by_value` and several `too_many_lines` allows exist as legacy debt. Don't extend. +- **Don't skip input validation.** Empty-string rejection is a contract across all user-facing text fields. +- **Don't scatter implementation across new submodules.** The crate is intentionally flat (one lib.rs + two leaf mods). Only `lane_completion` and `pdf_extract` break out. +- **Don't duplicate tool names.** The canonical name mapping already handles aliases. +- **Don't bypass `enforce_permission_check`.** Every tool dispatch goes through permission gating. No exceptions. diff --git a/src/AGENTS.md b/src/AGENTS.md new file mode 100644 index 00000000..3195acb6 --- /dev/null +++ b/src/AGENTS.md @@ -0,0 +1,69 @@ +# src/ AGENTS.md + +## OVERVIEW + +This is a **porting workspace**, not production code. Nothing here is imported by, +built with, or shipped in the Rust product (`rust/crates/`). The Python tree exists +solely to mirror and track parity against the Claude Code TypeScript source. + +## STRUCTURE + +``` +src/ +├── main.py # argparse CLI entry point (summary, parity-audit, manifest, etc.) +├── ~38 top-level .py # mirror TS root files one-to-one +├── models.py # frozen dataclasses: Subsystem, PortingModule, PermissionDenial, ... +├── parity_audit.py # hard-coded TS→Python filename mapping (main.tsx→main.py, etc.) +├── port_manifest.py # builds a manifest of the src/ tree itself +├── reference_data/ # tracked JSON snapshots extracted from the TS archive +│ ├── archive_surface_snapshot.json +│ ├── tools_snapshot.json, commands_snapshot.json +│ └── subsystems/*.json (29 per-subsystem records) +└── ~30 subdirectories/ # PLACEHOLDER PACKAGES (assistant/, bootstrap/, voice/, vim/, ...) + └── each contains only __init__.py loading subsystems/.json +``` + +Placeholder packages follow an identical template: load +`reference_data/subsystems/.json` via `_archive_helper.load_archive_metadata()`, +re-export `ARCHIVE_NAME`, `MODULE_COUNT`, `SAMPLE_FILES`, `PORTING_NOTE`. There is no +voice, vim, or other real functionality behind them. + +## WHERE TO LOOK + +| Goal | Start here | +|---|---| +| Understand the CLI subcommands | `main.py` | +| See which TS files map to which .py | `parity_audit.py` | +| Find shared data structures | `models.py` | +| Check TS archive metadata | `reference_data/` | +| Real logic (permissions, path scoping) | `permissions.py`, `path_scope.py` | +| Query engine shim | `query_engine.py` | +| Runtime simulation | `runtime.py` | +| Tests | repo-root `tests/` (test_porting_workspace.py, test_security_scope.py) | + +Run tests: `python -m unittest discover -s tests` from repo root. + +## CONVENTIONS + +- snake_case filenames, preserving TS names. camelCase exceptions exist where the + TS original used it: `QueryEngine.py`, `costHook.py`, `replLauncher.py`. +- Every mirrored entry carries a `source_hint` pointing back to its original `.ts`/`.tsx` path. +- `from __future__ import annotations` throughout. Stdlib only, no third-party deps. +- `models.py` dataclasses are frozen. Renderers are `as_markdown()` / `to_markdown()`. +- main.py simulates routing, turn-loops, bootstrap over mirrored inventories. + Read-only shims return handled/message results. It never calls an LLM. +- Thin shim modules (e.g. `ink.py`) exist as backlog metadata, not working code. + +## ANTI-PATTERNS + +**Don't add real agent, tool, voice, or vim functionality here.** That belongs in +`rust/crates/`. This tree is a scaffold, not an implementation target. + +**Don't commit anything from `archive/`.** The local TS snapshot +(`archive/claude_code_ts_snapshot/src`) is gitignored. `reference_data/` holds the +tracked extracts; work from those. + +**Don't let parity_audit.py drift.** When you rename a mirrored module, update the +hard-coded mapping in `parity_audit.py` to match. + +**Don't add third-party dependencies.** Everything runs on stdlib.