feat: claw parity batch — memory/compact/rules/pricing/hooks/perms#3019
feat: claw parity batch — memory/compact/rules/pricing/hooks/perms#3019MoSaleh-AKB wants to merge 1 commit into
Conversation
9 of 17 plan tasks completed in a single session. 14 new tests added; full
workspace runs 527 of 528 (the 1 failure is pre-existing on upstream main:
hooks::tests::malformed_nonempty_hook_output_reports_explicit_diagnostic_with_previews).
T1.2 /compact + post-compact CLAUDE.md re-attachment (main.rs:5302)
T1.3 Auto-memory discovery — reads ~/.claude/projects/<encoded-cwd>/memory/
so memory written by Claude Code flows into claw's system prompt
(prompt.rs: discover_instruction_files + memory_dir_for_cwd)
T1.4 Pricing tables for Llama, Qwen, Grok, GPT, local Ollama (zero-cost
heuristic via colon-tag detection); avoids the silent $75/M sonnet
fallback for non-Anthropic models (usage.rs: pricing_for_model)
T1.5 Compound bash pipeline splitting + 9 tests. Closes the
`cmd1 && rm -rf /` bypass; quoted strings/backslash-escapes respected
(bash_validation.rs: split_bash_pipeline, validate_command rewrite)
T2.1 Hook events expanded 3 → 10. Stop, StopFailure, UserPromptSubmit,
SessionStart, SessionEnd, PostToolBatch, PermissionRequest,
InstructionsLoaded now configurable in settings.json. Firing for new
events deferred to a follow-up. Backward-compatible: 3-arg
RuntimeHookConfig::new() preserved (hooks.rs, config.rs).
T2.2 SKILL.md discovery confirmed already-implemented (no-op).
T2.3 AGENT.md discovery confirmed already-implemented; subagent context
isolation deferred (no-op).
T2.4 Path-scoped rules: .claude/rules/*.md and .claw/rules/*.md discovered
and injected. Frontmatter `paths:` glob filtering deferred
(prompt.rs: discover_instruction_files extension).
T2.5 Permission rule wildcard suffix: Bash(npm run *), Bash(git *),
WebFetch(https://example.com/*) now match correctly via
PermissionRuleMatcher::Prefix. Existing colon-star and Any forms
preserved (permissions.rs: parse_rule_matcher).
Plus an earlier session patch routing `xai/<model>` prefix through the XAI
provider lane (api/providers/mod.rs: metadata_for_model).
Plan reference: ~/.claude/plans/model-later-be-able-snug-blanket.md
Deferred: T1.1 (bash branch merge), T3.x (worktrees, /batch, Monitor,
scheduler), T4.x (ACP daemon, VS Code, JetBrains extensions).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dc9b132 to
cad236e
Compare
|
Closing — keeping these changes on my fork (MoSaleh-AKB/claw-code) as a personal branch. Not upstreaming for now. |
|
Reopening to keep this open as a tracking PR — keeping the work parked here for later upstream discussion, not actively pushing for merge. |
yuanri007
left a comment
There was a problem hiding this comment.
Code Review
Diff: +530 / −16 across 7 files
Overview
A 9-change parity batch: post-/compact prompt rediscovery, auto-memory ingestion, expanded pricing tables, top-level bash-pipeline splitting in the validator, 7 new hook events at config layer, .claude/rules & .claw/rules ingestion, trailing-* permission glob, xai/ provider prefix, and a CLAW_NO_TOOLS env switch. Mostly additive; one intentional semantic tightening (compound-command validation).
Strengths
- Backward-compat care.
RuntimeHookConfig::new()kept at 3 args via..Default::default(); permission:*form preserved alongside the new general*; pre-T1.5validate_commandbody lifted intact intovalidate_command_segment. - Security win. The
ls && rm -rf /bypass is a real hole; the fix is targeted and the deferred-Warn / first-Block precedence is the right policy. - Test coverage for the new splitter is reasonable (single quotes, double quotes, escape,
&&/||/;/|), plus a regression test against the original bypass. - Pricing test asserts no-silent-default —
pricing_unknown_returns_noneis exactly the right guard.
Issues — by severity
Bugs
-
memory_dir_for_cwdis broken on Windows.prompt.rsreadsHOME(not set by default on Windows) and replaces only/(Windows paths use\). Result: auto-memory silently no-ops on Windows, and even ifHOMEis set, the encoded path won't match what Claude Code wrote. Usedirs::home_dir()(orhome::home_dir()) and normalize the path separator — or canonicalize to/first. The whole point of T1.3 is CC↔claw memory sharing, so this needs to work cross-platform. -
Backtick /
$()command substitutions evade the splitter.bash_validation.rstracksin_backtickso separators inside backticks aren't split — good — but the contents of`…`and$(…)are never validated as standalone segments.echo $(rm -rf /tmp/x)produces one segment and only the outerechois path-checked. The author's test comment acknowledgescheck_destructivemay still catchrm -rf /via substring, but anything not in that paranoid list (e.g.curl …|sh,dd of=/dev/sda) gets through. At minimum, document this; ideally recurse into$(…)content. -
Speculative GPT-5 / O-series pricing.
usage.rscommits $10/$30 forgpt-5and $15/$60 foro1/o3/o4. These are best-effort guesses dressed as fact in a constant table. If the published tariff is lower, users see inflated cost estimates and lose trust; if higher, they under-budget. Either source these numbers (link in a comment), gate them behind a "best-effort" flag, or returnNoneand surface "pricing unknown" upstream.
Style / minor
-
canonical.contains(':')is too loose for Ollama detection. Any future cloud model with a:in the identifier (some providers already usemodel:version) silently goes to zero-cost. Tighten with a regex like^[^/]+:[^/]+$after stripping a routing prefix, or require it not to match a known cloud family. -
Rules loading walks every ancestor on every prompt build.
read_dirruns per ancestor, twice (.claude/rulesand.claw/rules). For deep trees in monorepos this is noisy. Worth a quick benchmark or at least a cache by cwd. -
Trailing-
*matcher overlap with bare*.strip_suffix('*')on input"*"would yield prefix"". The earlierunescaped == "*"branch catches it first, so we're fine, but the precedence is load-bearing — worth a comment, or test the empty-prefix case explicitly. -
PR description claims "Avoids silent Sonnet-tier default", but the pre-change
pricing_for_modelonly matched the three Anthropic families and returnedNoneotherwise. If a Sonnet default exists, it's in a caller (UsageCostEstimate::default()perhaps). The change is good either way, but the description is misleading. -
Batch size. Description openly offers to split. Worth doing — the bash-validator fix is security-relevant and deserves to land on its own diff for cherry-pick / revert clarity; pricing + provider routing + memory discovery are all independent.
Risks
split_bash_pipelinepolicy change in ReadOnly mode could break existing user scripts that chain a safe inspection with a write step (git status && git commit …). The author flags this as intentional; just make sure release notes call it out, because the failure mode is "command silently blocked" not "loud error."CLAW_NO_TOOLSis a quiet new env switch. Worth documenting inclaw doctor/--help.
Recommendation
Request changes. Fix the Windows memory-path bug (#1) before merge — it negates one of the PR's headline parity features. Either land or remove the speculative GPT-5/O-series pricing (#3). Everything else can ship as-is or as follow-ups, but consider splitting (#8) so the bash-validator security fix has its own revertable commit.
Summary
9 distinct parity improvements committed together as a single batch. 14 new tests added; full workspace runs 527 of 528 (the 1 failure —
hooks::tests::malformed_nonempty_hook_output_reports_explicit_diagnostic_with_previews— is pre-existing onmain)./compactrusty-claude-cli/src/main.rs~/.claude/projects/<encoded-cwd>/memory/so memory files written by Claude Code or other tools auto-attach —runtime/src/prompt.rsruntime/src/usage.rscmd1 && rm -rf /no longer bypasses; quoted strings + backslash escapes respected; newsplit_bash_pipeline()—runtime/src/bash_validation.rsRuntimeHookConfig::new()preserved for backward compat —runtime/src/hooks.rs,runtime/src/config.rs.claude/rules/*.mdand.claw/rules/*.mddiscovered and injected into system prompt —runtime/src/prompt.rs*glob now matches:Bash(npm run *),Bash(git *),WebFetch(https://example.com/*). Existing:*andAnyforms preserved —runtime/src/permissions.rsxai/<model>prefix routes to XAI lane (letsOPENAI_BASE_URL+XAI_BASE_URLcoexist in one process) —api/src/providers/mod.rsTest plan
Notes for reviewers
Happy to split this into smaller PRs if preferred — kept as one batch to ship the parity sweep coherently.
🤖 Generated with Claude Code