Add Claude Code integration (v0.9.0)#1
Conversation
New features for Claude Code users: - `oddkit init --claude` for ~/.claude.json config - `oddkit init --all` for both Cursor and Claude Code - `oddkit claudemd` to generate CLAUDE.md with integration docs - `oddkit hooks` for Claude Code hooks (.claude/settings.local.json) - Enhanced MCP resources: oddkit://quickstart, oddkit://examples - Updated instructions with spawned agent guidance https://claude.ai/code/session_013bqxMuddFD1CkyEDRzo2bp
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| console.error(`${r.targetName} error: ${r.error || r.message}`); | ||
| hasErrors = true; | ||
| } | ||
| } |
There was a problem hiding this comment.
Error tracking bypassed when quiet mode enabled
High Severity
In the --all mode handler, the hasErrors = true statements on lines 290 and 293 are inside the if (!quiet) block. When --quiet is used, the code skips the entire block including error tracking, causing hasErrors to remain false even when conflicts or errors occur. The exit code will always be success (0) in quiet mode, even if configuration failed.
| { | ||
| "name": "oddkit", | ||
| "version": "0.7.0", | ||
| "version": "0.8.1", |
There was a problem hiding this comment.
| // Check if oddkit hooks already exist | ||
| const hasOddkit = merged.hooks[hookType].some( | ||
| (h) => JSON.stringify(h).includes("oddkit") || JSON.stringify(h).includes("oddkit"), | ||
| ); |
There was a problem hiding this comment.
| // If --all flag, configure all targets | ||
| if (all) { | ||
| return runInitAll(options); | ||
| } |
There was a problem hiding this comment.
--all --print combination writes files and outputs undefined
Medium Severity
When --all and --print flags are used together, the --print flag is ignored. runInit immediately delegates to runInitAll before checking print, and runInitAll doesn't destructure or handle the print option. This causes files to be written when the user expected a dry-run. Additionally, cli.js then accesses result.snippet which doesn't exist in the "all" mode response, resulting in undefined being printed.
Additional Locations (2)
….21.1) Two fixes from Cursor Bugbot findings on PR #120 / #121 that should have blocked the 0.21.0 ship and didn't because the orchestrator treated Bugbot's in_progress state as non-blocking. The findings are real and the medium-severity one is a prod regression vs pre-refactor behavior. Bug #1 (medium) — Stop-word filtering silently drops canon vocab keywords: - parseCheckColumn called tokenize(m[1]) with default STOP_WORDS filter. Canon vocab includes 'from' (in source-named) and 'to' (inside 'according to'); STOP_WORDS includes both. Result: 'from' is dropped from stemmedTokens; the runtime call site applied the same filter to inputStems so 'from' is dropped there too. - Pre-refactor regex evaluator matched 'from' literally as new RegExp('\\bfrom\\b', 'i') against raw input. Inputs like 'I learned this from my colleague' passed source-named pre-refactor and fail post-refactor — the strictly-additive invariant the 0.21.0 CHANGELOG and PR description claimed is broken. - Latent landmine: any prereq whose canon vocab is entirely stop-words would have stemmedTokens.size === 0 and trigger the conservative length>=20 fallback inappropriately (false positive). Not currently exploited by canon but the structural risk is there. - Fix: pass new Set() (empty stop-words) to both tokenize() calls so canon keywords survive on both sides and shape matches. Bug #2 (low) — DRY violation in BasePrerequisite: - 0.21.0 introduced PrereqMatchVocab interface to share shape between BasePrerequisite and ChallengeTypeDef.prerequisiteOverlays[]. The inline type on prerequisiteOverlays uses '& PrereqMatchVocab' intersection; BasePrerequisite re-listed all five fields manually. Future PrereqMatchVocab additions would not propagate to BasePrerequisite — defeats the DRY purpose. - Fix: split into BasePrerequisiteCore (3 core fields) and type BasePrerequisite = BasePrerequisiteCore & PrereqMatchVocab. Verification: - Typecheck clean - governance-parser.test.mjs 105/105 pass - 2 new regression assertions in canon-tool-envelope.smoke.mjs: (10) source-named via 'from'-only canon keyword (11) source-named via 'according to' multi-word phrase - Bugbot Autofix preview diff for PR #121 used as the basis for the Bug #1 fix (cherry-picked the change locally rather than applying via Autofix UI to keep the audit trail in this branch). Process post-mortem to follow in P1.3.3 closeout ledger.
….21.1) (#122) Two fixes from Cursor Bugbot findings on PR #120 / #121 that should have blocked the 0.21.0 ship and didn't because the orchestrator treated Bugbot's in_progress state as non-blocking. The findings are real and the medium-severity one is a prod regression vs pre-refactor behavior. Bug #1 (medium) — Stop-word filtering silently drops canon vocab keywords: - parseCheckColumn called tokenize(m[1]) with default STOP_WORDS filter. Canon vocab includes 'from' (in source-named) and 'to' (inside 'according to'); STOP_WORDS includes both. Result: 'from' is dropped from stemmedTokens; the runtime call site applied the same filter to inputStems so 'from' is dropped there too. - Pre-refactor regex evaluator matched 'from' literally as new RegExp('\\bfrom\\b', 'i') against raw input. Inputs like 'I learned this from my colleague' passed source-named pre-refactor and fail post-refactor — the strictly-additive invariant the 0.21.0 CHANGELOG and PR description claimed is broken. - Latent landmine: any prereq whose canon vocab is entirely stop-words would have stemmedTokens.size === 0 and trigger the conservative length>=20 fallback inappropriately (false positive). Not currently exploited by canon but the structural risk is there. - Fix: pass new Set() (empty stop-words) to both tokenize() calls so canon keywords survive on both sides and shape matches. Bug #2 (low) — DRY violation in BasePrerequisite: - 0.21.0 introduced PrereqMatchVocab interface to share shape between BasePrerequisite and ChallengeTypeDef.prerequisiteOverlays[]. The inline type on prerequisiteOverlays uses '& PrereqMatchVocab' intersection; BasePrerequisite re-listed all five fields manually. Future PrereqMatchVocab additions would not propagate to BasePrerequisite — defeats the DRY purpose. - Fix: split into BasePrerequisiteCore (3 core fields) and type BasePrerequisite = BasePrerequisiteCore & PrereqMatchVocab. Verification: - Typecheck clean - governance-parser.test.mjs 105/105 pass - 2 new regression assertions in canon-tool-envelope.smoke.mjs: (10) source-named via 'from'-only canon keyword (11) source-named via 'according to' multi-word phrase - Bugbot Autofix preview diff for PR #121 used as the basis for the Bug #1 fix (cherry-picked the change locally rather than applying via Autofix UI to keep the audit trail in this branch). Process post-mortem to follow in P1.3.3 closeout ledger.
The three Cursor Agent fix commits on this PR addressed all three Bugbot findings correctly, but only the count() collision (Bug #1) got dedicated test coverage. Bugs #2 and #3 — both about literal handling — landed without regression tests, so a future refactor that reverts the literal-skip logic would not be caught by CI. This commit closes the gap. Test 1: rewriteSqlToRaw — semantic names inside single-quoted literals - 'klappy://sources/scientific-method' must not have method → blob2 - SQL doubled-quote escape '' must keep word inside literal preserved - Mixed case: column ref outside literal still rewrites; same word inside a literal stays untouched Test 2: detectRawSlotNames — raw slot names inside literals do not trigger rejection - 'https://example.com/blob1/readme' must not be falsely rejected - 'klappy://reports/double5-summary' likewise - Sanity guard: bare blob1 outside any literal STILL gets rejected - Mixed case: raw slot outside a literal is rejected even when another raw slot appears inside a literal in the same query All 17 tests pass locally: 17 passed, 0 failed (was 15 — added 2) This addresses the test-coverage gap I noted in the PR review, not a code defect — the fixes themselves are correct and these tests verify they hold.


New features for Claude Code users:
oddkit init --claudefor ~/.claude.json configoddkit init --allfor both Cursor and Claude Codeoddkit claudemdto generate CLAUDE.md with integration docsoddkit hooksfor Claude Code hooks (.claude/settings.local.json)https://claude.ai/code/session_013bqxMuddFD1CkyEDRzo2bp
Note
Medium Risk
Medium risk because it expands CLI behavior that writes/merges user and project config files (including
~/.claude.jsonand.claude/settings.local.json) and changes MCP resource/instruction surfaces that IDEs consume.Overview
Adds first-class Claude Code support:
oddkit initcan now target Cursor or Claude Code (--cursor,--claude) or configure both (--all), including auto-detecting Claude Code sessions and supporting project-local config paths.Introduces new CLI commands for Claude workflows:
oddkit claudemdto generate/append aCLAUDE.mdintegration guide (with optional advanced section) andoddkit hooksto write/merge.claude/settings.local.jsonhook configs (minimal/strict modes).Enhances MCP integration by updating
oddkit://instructionswith spawned-agent guidance and adding new MCP resourcesoddkit://quickstartandoddkit://examples, alongside updated docs (docs/CLAUDE-CODE.md, MCP/quickstart updates) and a version bump to0.9.0.Written by Cursor Bugbot for commit 89731eb. This will update automatically on new commits. Configure here.