Skip to content

Add Claude Code integration (v0.9.0)#1

Merged
klappy merged 2 commits into
mainfrom
claude/oddkit-claude-code-integration-J8KjW
Feb 2, 2026
Merged

Add Claude Code integration (v0.9.0)#1
klappy merged 2 commits into
mainfrom
claude/oddkit-claude-code-integration-J8KjW

Conversation

@klappy
Copy link
Copy Markdown
Owner

@klappy klappy commented Feb 2, 2026

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


Note

Medium Risk
Medium risk because it expands CLI behavior that writes/merges user and project config files (including ~/.claude.json and .claude/settings.local.json) and changes MCP resource/instruction surfaces that IDEs consume.

Overview
Adds first-class Claude Code support: oddkit init can 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 claudemd to generate/append a CLAUDE.md integration guide (with optional advanced section) and oddkit hooks to write/merge .claude/settings.local.json hook configs (minimal/strict modes).

Enhances MCP integration by updating oddkit://instructions with spawned-agent guidance and adding new MCP resources oddkit://quickstart and oddkit://examples, alongside updated docs (docs/CLAUDE-CODE.md, MCP/quickstart updates) and a version bump to 0.9.0.

Written by Cursor Bugbot for commit 89731eb. This will update automatically on new commits. Configure here.

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
@klappy klappy merged commit 9f93fae into main Feb 2, 2026
1 check passed
@klappy klappy deleted the claude/oddkit-claude-code-integration-J8KjW branch February 2, 2026 01:26
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

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.

Comment thread src/cli.js
console.error(`${r.targetName} error: ${r.error || r.message}`);
hasErrors = true;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Comment thread package-lock.json
{
"name": "oddkit",
"version": "0.7.0",
"version": "0.8.1",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

package-lock.json version doesn't match package.json

Medium Severity

The package-lock.json version is 0.8.1 but package.json version is 0.9.0. These should be synchronized. This can cause issues with npm ci operations and creates confusion about the actual package version.

Fix in Cursor Fix in Web

Comment thread src/cli/hooks.js
// Check if oddkit hooks already exist
const hasOddkit = merged.hooks[hookType].some(
(h) => JSON.stringify(h).includes("oddkit") || JSON.stringify(h).includes("oddkit"),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant duplicate condition in OR clause

Low Severity

The hasOddkit check uses an OR with identical conditions: JSON.stringify(h).includes("oddkit") || JSON.stringify(h).includes("oddkit"). The same expression appears on both sides of the || operator, making the second check redundant.

Fix in Cursor Fix in Web

Comment thread src/cli/init.js
// If --all flag, configure all targets
if (all) {
return runInitAll(options);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

--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)

Fix in Cursor Fix in Web

klappy added a commit that referenced this pull request Apr 20, 2026
….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.
klappy added a commit that referenced this pull request Apr 20, 2026
….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.
klappy added a commit that referenced this pull request Apr 26, 2026
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.
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.

2 participants