Skip to content

feat: model-free tool CLI and MCP server for external coding agents - #1609

Draft
hkaltai wants to merge 12 commits into
mainfrom
tool-cli-daemon
Draft

hkaltai wants to merge 12 commits into
mainfrom
tool-cli-daemon

Conversation

@hkaltai

@hkaltai hkaltai commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

No linked issue (new feature).

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Lets external coding agents such as Claude Code call altimate-code's data tools directly, over MCP or from the shell, instead of delegating each task to a second altimate-code agent with its own model. It builds on #1543 (mcp serve) and #1576 (workspace tools), which are included here.

  • One adapter, two entry points. altimate-code mcp serve and a new model-free altimate-code tool CLI (list, schema, run, context, daemon) execute tools through the same adapter: one allow-list, one permission layer, the same compact schemas, result spill files and answer_commit. Organisations that disallow MCP servers keep the same tools through tool run.
  • Default MCP tools. The five feat(mcp): altimate-code mcp serve exposes data tools to MCP clients without an LLM #1543 tools plus impact_analysis, dbt_lineage, altimate_core_column_lineage, schema_detect_pii, data_diff, altimate_core_equivalence and sql_translate; --all-tools exposes the full allow-list.
  • Warm per-project process. tool calls go through a per-project daemon (auto-start, exits after 10 idle minutes, socket scoped to version and connections) that keeps connections and the schema cache warm and releases DuckDB/SQLite file locks between calls.
  • Workspace tools. workspace_context, workspace_skill and workspace_execute are on by default for tool commands in linked projects (--no-workspace-tools turns them off); mcp serve exposes them with --workspace-tools. tool context prints the analyst method, connections, the linked workspace and its skills.
  • Workspace skills for Claude Code. Every workspace skill sync also writes sanitised copies (frontmatter reduced to name and description, no command blocks, no hook or plugin component files) into <project>/.claude/skills/, so linking or refreshing a project makes them available when a Claude Code session starts. User-written skills of the same name are never touched, unlink removes the copies, projects without .claude/ are left alone, ALTIMATE_CLAUDE_SKILL_SYNC=0 disables it, and a mirror failure never changes the sync result.
  • Safety. MCP requests are read-only unless --allow-write; DROP DATABASE, DROP SCHEMA and TRUNCATE stay blocked even then.
  • link --claude-md (opt-in) writes CLI routing guidance into CLAUDE.md for clients that cannot use MCP.

Behaviour changes in shared tools:

  • schema_inspect without a table lists schemas, or up to 500 tables with catalog row estimates (no scans); MongoDB catalog discovery is bounded.
  • answer_commit accepts asked and readings; its rejection checks moved to their own module with per-turn limits.
  • The analyst requests high reasoning effort on adaptive-thinking models unless the user or agent config sets one.

The CI change from #1543 is intentionally not included. Companion Claude Code plugin: AltimateAI/altimate-claude-plugin#11.

How did you verify your code works?

  • bun run typecheck clean after merging current main.
  • bun test test/altimate/mcp-server test/altimate/tool-cli test/altimate/workspace test/altimate/analyst-effort.test.ts test/agent/analyst-data-explorer.test.ts: 1994 tests, 0 failures (includes the new .claude/skills mirror tests).
  • End to end: tool context, tool run through the daemon and in-process, mcp serve over stdio (initialize, tools/list, tools/call) against DuckDB, and workspace refresh against a linked workspace writing the Claude Code skill copies.
  • Benchmarks with Claude Code (Sonnet 4.5):
    • 100 dbt and warehouse tasks: routing to altimate-code rose from 55/75 to 74/75 over MCP and 75/75 through tool run, with no false positives on the 25 tasks that should not use it and unchanged accuracy (94–95/100).
    • Questions that need workspace skills: setups using this PR had the skills available at the start of every session (100/100 vs 0/100 without), and accuracy matched the existing MCP flow (58% vs 55% on 100 questions) at 12% lower cost per run.

Cost side effects

No new model calls: the tool CLI and MCP server run tools without an LLM. The analyst agent now requests high reasoning effort on adaptive-thinking models when neither the agent nor the model config sets one, so analyst runs use more reasoning tokens; ALTIMATE_ANALYST_EFFORT (e.g. medium or off), the agent's options or the model's options override it. Warehouse queries run only when an agent calls a tool, with results capped by the existing output limits and spill files. schema_inspect listings are capped at 500 tables and use catalog estimates rather than scans. The per-project daemon exits after 10 idle minutes.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR
  • I checked for cost side effects (model calls, queries or cloud resources that grow with user data) and described them, or wrote "none"

Do not merge: experiment for evaluating direct altimate-code tools in Claude Code.

- Bring in `altimate-code mcp serve` and the workspace tools from the MCP draft branches
- `tool list|schema|run|context|daemon`: run the same adapter as `mcp serve` without a model
- `mcp serve` default set adds impact, lineage, PII, data-diff, equivalence and translation tools; `--all-tools` exposes the full allow-list
- Long-running per-project process keeps connections warm and releases DuckDB/SQLite file locks between calls
- `--connections` / `ALTIMATE_TOOL_CONNECTIONS`, `--args -` from stdin, `tool schema` for one tool
- DROP DATABASE, DROP SCHEMA and TRUNCATE stay blocked even with `--allow-write`
- `link --claude-md` writes CLI routing guidance for clients without MCP

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

Copy link
Copy Markdown

Hey! Your PR title [DO NOT MERGE] Experiment: model-free tool CLI and MCP server on one adapter doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Do not merge: experiment.

- `tool list|schema|run|context|daemon` enable workspace tools automatically when the project is linked; `--no-workspace-tools` disables them
- `tool context` lists the linked workspace, its skills and how to use the workspace tools
- Daemon identity and spawn arguments follow the effective workspace-tools value

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

…ills

Do not merge: experiment.

- Every workspace skill sync also writes the skills into `<project>/.claude/skills/`, so linking or refreshing a project puts them on disk before a Claude Code session starts
- Copies follow the Claude Code plugin's rules: frontmatter reduced to `name` and `description`, command blocks neutralised, hook and plugin component paths skipped, user-written skills never touched, each copy marked and git-ignored
- Unlink and the feature-off path remove the copies; projects without `.claude` are left alone; `ALTIMATE_CLAUDE_SKILL_SYNC=0` disables it
- A mirror failure never changes the sync result
- Tests: `claude-skill-mirror.test.ts`, mirror wiring in `skill-sync.test.ts`

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

# Conflicts:
#	packages/opencode/src/altimate/api/client.ts
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@hkaltai hkaltai changed the title [DO NOT MERGE] Experiment: model-free tool CLI and MCP server on one adapter feat: model-free tool CLI and MCP server for external coding agents Oct 29, 2026
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions

Copy link
Copy Markdown

Thanks for updating your PR! It now meets our contributing guidelines. 👍

…ll mirror

- daemon: release file locks when the last request finishes; serialize bind and
  stale-socket recovery with a lock; clients never unlink sockets; refuse a
  symlinked or foreign-owned socket directory
- mcp: warehouse_remove and driver installs need --allow-write over MCP too
- analyst effort: a per-model effort or thinking option wins over the default
- adapter: bound the answer_commit history kept across turns
- tool CLI: keep spilled results under the state directory, not /tmp
- skill mirror: skip a symlinked .claude or .claude/skills; swap copies without
  deleting the old one first
- docs: callers in one directory share the daemon

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hkaltai and others added 5 commits October 30, 2026 09:25
…cking files

Files that reset the native dispatcher or mock the MCP SDK client modules now
restore them, so tests that run later in the same process see the real ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…space skill mirror

Copies carry a marker naming the skill, so a renamed copy is the user's; nested
CLAUDE.md files are not copied; staging uses an .altimate-staging- infix, gets
its .gitignore first and is swept when abandoned; an unreadable snapshot, or one
missing while it is swapped, leaves the copies alone; and the mirror and the
plugin's sync take turns under one mkdir lock in .claude/skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/opencode/src/altimate/api/client.ts
#	packages/opencode/src/memory/store.ts
…uard read-only warehouse_add

- daemon: reload connections when a connections file changes, only when no other
  call is in flight, with calls arriving during a reload waiting for it; key the
  socket on the caller's ALTIMATE_CODE_CONN_* environment; resolve --connections
  once
- registry: validate a connections file before closing anything; never release
  in-memory DuckDB/SQLite connections
- mcp serve: release file database locks when no call is in flight
- warehouse_add: a read-only session cannot replace a connection named in the
  active registry, the global or project file, or the credential store
- adapter: bound the answer_commit history on every call, not only on commit
- skill mirror: keep copies when the snapshot or a skill cannot be read; let
  withdrawal run with ALTIMATE_CLAUDE_SKILL_SYNC=0
- tool CLI: decide the workspace tools default from the saved link, without a
  network call
- workspace-client: telemetry name and disabled-workspace stub
- docs and help text for the daemon, workspace tools and --all-tools

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nder concurrent and partial reads

The mkdir lock shared with the plugin is renewed by its holder, taken over from
a dead one by rename, released only by the holder (an empty token directory),
and never waited on past its deadline; a holder that lost it stops before the
next swap. The manifest is read without following symlinks and re-read before
the removal pass; a listed skill directory that is gone, or credentials that
exist but cannot be read, change nothing. One skill's failed swap no longer
stops the others; tree comparison streams one file pair at a time; frontmatter
whitespace matches Python's; readManifest rejects a skills array.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

hkaltai and others added 2 commits October 30, 2026 17:22
…, and withdraw them on sign-out

Each copy is swapped in only while the lock is held and the snapshot is the one
read and still the signed-in account's, so a mid-copy swap, takeover or sign-out
publishes nothing. Swap detection uses the staging directory's mtime, which a
rename updates on every platform. A SKILL.md that is not a regular file skips
that skill instead of freezing every sync; markers decode strictly with their BOM
kept, as the plugin's Python reads them. The sync waits at most 2 s for the lock.
Signing out withdraws the project's copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant