Skip to content

Fix/skill mcp - #68

Merged
bernoussama merged 3 commits into
masterfrom
fix/skill-mcp
Jun 24, 2026
Merged

Fix/skill mcp#68
bernoussama merged 3 commits into
masterfrom
fix/skill-mcp

Conversation

@bernoussama

@bernoussama bernoussama commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added ambient failure-detection hooks that nudge agents to search when tool/session failures are detected (with cooldown to reduce repeat prompts)
    • Introduced a clanker hook command to generate and optionally install ambient hooks, plus a session-start reminder
  • Bug Fixes
    • Improved advanced search query parsing and NEAR() normalization/validation; malformed queries now return clearer “invalid syntax” errors
    • Updated exact keyword search to better handle leading hyphens
  • Documentation
    • Refreshed skill guidance for “search-first” behavior and stricter logging/trigger rules
    • Updated search-syntax documentation and added a new blog draft on tool usage best practices
  • Tests
    • Added/expanded local search and hook-related test coverage

The operator-aware ftsQuery parser (AND/OR/NOT, column filters, prefix
terms, NEAR, syntax validation) was only exercised by unit tests; the
runtime keyword path used the simpler localFtsQuery, so documented
advanced syntax was silently ignored and syntax errors never surfaced.

- local-backend: route searchLocalKeywordExact through ftsQuery so
  advanced operators, column filters, and syntax validation work as
  documented; delete the now-dead localFtsQuery
- local-backend: fix NEAR passthrough — tokenizeFtsQuery now captures
  NEAR(...) as a unit and normalizes the forgiving comma form
  (NEAR(a, b, 5)) to FTS5's space-separated form (NEAR(a b, 5))
- local-backend: treat a leading hyphen as punctuation in simple mode
  (e.g. "sqlite -wal" searches for both terms) instead of rejecting it
- local-backend: correct the FTS5 syntax hint (NEAR uses space-separated
  terms, not commas)
- server: surface FtsQuerySyntaxError as text content instead of
  re-throwing, so MCP clients can read the hint and retry
- index: special-case FtsQuerySyntaxError in the CLI catch blocks with a
  clearer "Invalid search syntax" header
- search-solutions.md: show the canonical NEAR(token nft, 5) form
…gers

Phase 1 — Rewrite skill descriptions to fix undertriggering:
- Lead with 'BEFORE implementing' instead of 9 failure nouns
- Name the real competitor: 'The search cost is near-zero;
  the cost of rediscovering a known gotcha is high'
- Invert log default from 'only if novel' to 'if it took effort, log it'
- Add 'specific technical fingerprint' test to skip guidance
- Collapse three exclusion lists into one tight bar
- Behavioral eval: recall 0% -> 100%, precision 60% -> 67%

Phase 2 — Ambient hooks that fire on failure signals:
- post-tool-use.mjs: detects error codes, stack traces, build failures;
  extracts fingerprint and nudges agent to search; silent on success;
  debounced to avoid noise during iterative debugging
- session-start.mjs: primes agent at session start
- hooks.json: rewritten from flat type:prompt (inert) to native
  type:command object schema (Claude/Codex/ZCode compatible)
- clanker hook CLI: generates/installs config per harness with
  idempotent merge that preserves existing user hooks
- setup.ts: wired to install hooks alongside MCP + skills for
  Claude, Codex, and Cursor

Blog draft documenting methodology and results.

CLI bumped 1.3.1 -> 1.4.0
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 287eaf51-a4d7-4f24-b42b-9e63cc05ba6c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds ambient hook scripts and install wiring, updates FTS5 query parsing and syntax handling, rewrites ClankerOverflow skill guidance, bumps CLI/plugin versions to 1.4.0, and adds a blog draft about the rollout.

Changes

Ambient hooks, FTS query updates, and release content

Layer / File(s) Summary
Hook scripts and install logic
packages/cli/hooks/post-tool-use.mjs, packages/cli/hooks/session-start.mjs, packages/cli/src/hooks/install.ts, packages/cli/src/setup.ts, packages/cli/src/index.ts
Adds a stdin-based failure hook with fingerprint-based debouncing, a session-start reminder, per-harness hook config generation and install/merge behavior, setup wiring for hook installation, and a new clanker hook subcommand.
FTS parsing and error handling
packages/cli/src/mcp/local-backend.ts, packages/cli/src/mcp/local-backend.test.ts, packages/cli/src/mcp/server.ts, packages/cli/src/mcp/server.test.ts, packages/cli/src/index.ts, packages/cli/commands/search-solutions.md
Routes exact searches through the shared FTS query pipeline, normalizes NEAR(...), changes simple-mode hyphen handling, updates related tests, and adds dedicated FtsQuerySyntaxError handling in MCP and CLI search paths.
Skill guidance rewrites
skills/clanker-overflow/SKILL.md, packages/cli/skills/clankeroverflow-cli/SKILL.md, packages/cli/skills/clankeroverflow-mcp/SKILL.md
Rewrites the skill descriptions, trigger conditions, workflow text, and logging rules across the three skill files.
Blog draft and version bumps
packages/cli/package.json, packages/cli/openclaw.plugin.json, packages/cli/.claude-plugin/plugin.json, packages/cli/.codex-plugin/plugin.json, blog/drafts/making-agents-actually-use-your-tools.md
Bumps manifest/package versions to 1.4.0 and adds a blog draft covering the hook rollout, evaluation phases, and lessons learned.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐇 I hopped through hooks at morning light,
Sniffed out the errors, nudged search right.
With NEAR made neat and guidance clear,
I left a trail for agents here.
A carrot, a cache, a cheerful cheer—
ClankerOverflow’s alive this year!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too vague and generic to convey the main change; it only hints at skill/MCP work. Rename it to describe the primary change, such as adding ClankerOverflow MCP hook installation and search-syntax fixes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/skill-mcp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
blog/drafts/making-agents-actually-use-your-tools.md (2)

43-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider an alternative for "exactly" to add variety.

Line 43 uses "exactly" in "are exactly what ClankerOverflow remembers." This is stylistically fine, but the word is flagged as overused in the broader text. Consider "are precisely what," "capture," or "represent" for wordsmithing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@blog/drafts/making-agents-actually-use-your-tools.md` at line 43, Replace the
word "exactly" in the phrase "are exactly what ClankerOverflow remembers" with a
less frequently used alternative to reduce word repetition and improve
readability. Choose from alternatives such as "precisely," "capture," or
"represent" based on which best maintains the intended meaning and flow of the
sentence while adding stylistic variety to the paragraph.

Source: Linters/SAST tools


88-88: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add language specifier to fenced code block.

The markdown code block is missing a language identifier. Since it appears to be a prompt/message example (not executable code), use text as the language specifier for proper rendering.

💬 Proposed fix
-```
+```text
 ClankerOverflow: A failure signal was detected.
 
 Before re-debugging, search for prior fixes with: search_solutions(e.g. "EADDRINUSE")
 A reusable verified fix may already exist. The search cost is ~2 seconds;
 rediscovering a known gotcha costs far more.
-```
+```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@blog/drafts/making-agents-actually-use-your-tools.md` at line 88, The fenced
code block containing the ClankerOverflow failure signal message is missing a
language specifier on the opening fence. Locate the code block that starts with
the message "ClankerOverflow: A failure signal was detected..." and add the
language identifier `text` immediately after the opening three backticks on the
first line to properly specify that this is a text block rather than executable
code.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/hooks/post-tool-use.mjs`:
- Around line 50-53: Replace the overly broad string literal "at " in the
FAILURE_INDICATORS array with a more specific regex pattern that matches actual
JavaScript stack frame formats (such as patterns like "at function_name" with
proper word boundaries or stack trace line patterns). Apply this same change in
both locations where the issue appears: in the primary FAILURE_INDICATORS
definition and again in the duplicate check around lines 166-171, ensuring the
regex pattern is strict enough to avoid matching normal conversational text
while still catching legitimate error stack traces.

In `@packages/cli/src/hooks/install.ts`:
- Around line 237-239: The condition checking both "command" and "type"
properties in the if statement is too restrictive and prevents Cursor command
entries (which only have "command") from being marked as owned with the
_clankeroverflow flag. This causes removeOwn() to fail to prune prior entries on
reinstalls, breaking idempotency. Modify the condition to mark entries as owned
when they have the "command" property regardless of whether "type" exists,
ensuring both regular and Cursor entries are properly tracked and deduplicated
across repeated installations.

In `@packages/cli/src/index.ts`:
- Around line 727-749: The hook installation results are being printed but the
code always exits successfully regardless of whether any installations failed.
After the results loop that checks result.status for "configured", "skipped",
and "failed" values, add a check to see if any result has status equal to
"failed". If any failures are detected, exit the process with a non-zero exit
code (such as 1) using process.exit before the return statement, otherwise allow
the normal return to proceed. This ensures that failed hook installations are
properly signaled to the CLI caller for CI/scripting failure detection.

In `@packages/cli/src/mcp/local-backend.ts`:
- Around line 137-150: The normalizeNear function currently splits on commas
without accounting for quoted strings, which causes valid NEAR queries
containing commas or other delimiters inside quoted terms to be incorrectly
parsed or prematurely terminated. Modify the parsing logic in normalizeNear to
be quote-aware by tracking whether the parser is currently inside a quoted
string when iterating through the inner content, and only treat commas and
parentheses as structural delimiters when they appear outside of quotes. Apply
this same quote-aware parsing logic to all delimiter handling in the function,
including the sections referenced around lines 160-172.

---

Nitpick comments:
In `@blog/drafts/making-agents-actually-use-your-tools.md`:
- Line 43: Replace the word "exactly" in the phrase "are exactly what
ClankerOverflow remembers" with a less frequently used alternative to reduce
word repetition and improve readability. Choose from alternatives such as
"precisely," "capture," or "represent" based on which best maintains the
intended meaning and flow of the sentence while adding stylistic variety to the
paragraph.
- Line 88: The fenced code block containing the ClankerOverflow failure signal
message is missing a language specifier on the opening fence. Locate the code
block that starts with the message "ClankerOverflow: A failure signal was
detected..." and add the language identifier `text` immediately after the
opening three backticks on the first line to properly specify that this is a
text block rather than executable code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 99a611b6-9c26-4dbd-8282-304ccffd3fae

📥 Commits

Reviewing files that changed from the base of the PR and between b758081 and e939aed.

📒 Files selected for processing (18)
  • blog/drafts/making-agents-actually-use-your-tools.md
  • packages/cli/.claude-plugin/plugin.json
  • packages/cli/.codex-plugin/plugin.json
  • packages/cli/commands/search-solutions.md
  • packages/cli/hooks/post-tool-use.mjs
  • packages/cli/hooks/session-start.mjs
  • packages/cli/openclaw.plugin.json
  • packages/cli/package.json
  • packages/cli/skills/clankeroverflow-cli/SKILL.md
  • packages/cli/skills/clankeroverflow-mcp/SKILL.md
  • packages/cli/src/hooks/install.ts
  • packages/cli/src/index.ts
  • packages/cli/src/mcp/local-backend.test.ts
  • packages/cli/src/mcp/local-backend.ts
  • packages/cli/src/mcp/server.test.ts
  • packages/cli/src/mcp/server.ts
  • packages/cli/src/setup.ts
  • skills/clanker-overflow/SKILL.md

Comment thread packages/cli/hooks/post-tool-use.mjs
Comment thread packages/cli/src/hooks/install.ts Outdated
Comment thread packages/cli/src/index.ts
Comment on lines +137 to +150
function normalizeNear(raw: string): string {
const match = raw.match(/^NEAR\s*\((.*)\)$/is);
if (!match) ftsSyntaxError("malformed NEAR(...) expression.");
const inner = match[1]!.trim();
if (!inner) ftsSyntaxError("NEAR(...) needs at least one term.");
// Split on commas, drop empties, so "a, b, 5" -> ["a","b","5"] and "a b, 5" -> ["a b","5"].
const parts = inner
.split(",")
.map((part) => part.trim())
.filter(Boolean);
// A trailing bare integer is the NEAR distance; keep it after a comma.
const last = parts[parts.length - 1];
const distance = parts.length >= 2 && /^\d+$/.test(last!) ? `, ${last}` : "";
const terms = (distance ? parts.slice(0, -1) : parts).join(" ").trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make NEAR(...) parsing quote-aware before comma/paren handling.

Current parsing treats , and ) inside quoted NEAR terms as structural delimiters, so valid queries can be transformed incorrectly or prematurely terminated.

Proposed fix
 function normalizeNear(raw: string): string {
   const match = raw.match(/^NEAR\s*\((.*)\)$/is);
   if (!match) ftsSyntaxError("malformed NEAR(...) expression.");
   const inner = match[1]!.trim();
   if (!inner) ftsSyntaxError("NEAR(...) needs at least one term.");
-  const parts = inner
-    .split(",")
-    .map((part) => part.trim())
-    .filter(Boolean);
+  const parts = splitNearParts(inner)
+    .map((part) => part.trim())
+    .filter(Boolean);
   const last = parts[parts.length - 1];
   const distance = parts.length >= 2 && /^\d+$/.test(last!) ? `, ${last}` : "";
   const terms = (distance ? parts.slice(0, -1) : parts).join(" ").trim();
   if (!terms) ftsSyntaxError("NEAR(...) needs at least one term.");
   return `NEAR(${terms}${distance})`;
 }
 
+function splitNearParts(inner: string): string[] {
+  const parts: string[] = [];
+  let current = "";
+  let inQuotes = false;
+  for (let i = 0; i < inner.length; i += 1) {
+    const ch = inner[i]!;
+    if (ch === '"' && inner[i - 1] !== "\\") inQuotes = !inQuotes;
+    if (ch === "," && !inQuotes) {
+      parts.push(current);
+      current = "";
+      continue;
+    }
+    current += ch;
+  }
+  if (inQuotes) ftsSyntaxError('unterminated double-quoted phrase in NEAR(...).');
+  parts.push(current);
+  return parts;
+}
+
 function captureNear(query: string, parenIndex: number): { value: string; endIndex: number } {
   let depth = 0;
+  let inQuotes = false;
   let j = parenIndex;
   for (; j < query.length; j += 1) {
     const char = query[j]!;
+    if (char === '"' && query[j - 1] !== "\\") {
+      inQuotes = !inQuotes;
+      continue;
+    }
+    if (inQuotes) continue;
     if (char === "(") depth += 1;
     else if (char === ")") {
       depth -= 1;
       if (depth === 0) break;
     }
   }
+  if (inQuotes) ftsSyntaxError('unterminated double-quoted phrase in NEAR(...).');
   if (depth !== 0) ftsSyntaxError('unmatched "(" in NEAR(...) expression.');
   return { value: query.slice(parenIndex - 4, j + 1), endIndex: j };
 }

Also applies to: 160-172

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/mcp/local-backend.ts` around lines 137 - 150, The
normalizeNear function currently splits on commas without accounting for quoted
strings, which causes valid NEAR queries containing commas or other delimiters
inside quoted terms to be incorrectly parsed or prematurely terminated. Modify
the parsing logic in normalizeNear to be quote-aware by tracking whether the
parser is currently inside a quoted string when iterating through the inner
content, and only treat commas and parentheses as structural delimiters when
they appear outside of quotes. Apply this same quote-aware parsing logic to all
delimiter handling in the function, including the sections referenced around
lines 160-172.

- post-tool-use: replace over-broad "at " substring (matched prose like
  "look at this") with structure-anchored stack-frame regexes so failure
  detection no longer false-positives on user prompts.
- install: markOwn required a "type" field, which Cursor hook entries
  ({command, matcher}) lack, so re-installs produced duplicates. Gate on
  "command" only, matching removeOwn. Export markOwn/removeOwn/
  mergeCursorHooks and add a regression test that fails against the old
  behavior.
- index: exit non-zero (1) when any installHooks result has a failed
  status, so CI/scripts can detect failed installs.
@bernoussama

bernoussama commented Jun 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

@bernoussama Sure! I'll kick off a review of this PR now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bernoussama
bernoussama merged commit eeb29ff into master Jun 24, 2026
2 checks passed
@bernoussama
bernoussama deleted the fix/skill-mcp branch June 24, 2026 21:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant