Repository navigation
feat: model-free tool CLI and MCP server for external coding agents
#1609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
18e72ea
feat: experiment: model-free `tool` CLI and MCP server on one adapter
hkaltai fc33c2e
feat: experiment: workspace tools on by default for linked projects
hkaltai 06223f4
feat: experiment: mirror workspace skills into Claude Code project sk…
hkaltai 2f45bc4
Merge remote-tracking branch 'origin/main' into tool-cli-daemon
hkaltai 7d5d12c
fix: harden tool daemon startup, lock release, MCP write gate and ski…
hkaltai 8822f29
test: restore shared dispatcher handlers and MCP SDK modules after mo…
hkaltai bd1f98e
fix: share the Claude Code plugin's skill-copy safeguards in the work…
hkaltai 7f1230a
Merge remote-tracking branch 'origin/main' into tool-cli-daemon
hkaltai 4e523b0
fix: reload daemon connections on edit, release locks in mcp serve, g…
hkaltai 615f88b
fix: keep the workspace skill mirror in step with the plugin's sync u…
hkaltai 39525e4
Merge remote-tracking branch 'origin/main' into tool-cli-daemon
hkaltai c8a46b9
fix: publish skill copies only for an unchanged, still-owned snapshot…
hkaltai f87d128
fix: keep workspace skill copies when a SKILL.md disappears between i…
hkaltai b139685
test: a SKILL.md that disappears between its check and its read keeps…
hkaltai 853bfa0
fix: address review findings in the tool CLI, MCP server and workspac…
hkaltai 7109869
fix: never send a doubled quote to BigQuery or Databricks in batch re…
hkaltai 4652bed
fix: keep data_diff and the tool daemon within read-only and release …
hkaltai fcc3c44
Merge remote-tracking branch 'origin/main' into tool-cli-daemon
hkaltai fdeddbf
fix: dialect-aware hard blocks, failed data_diff reported as an error…
hkaltai d500243
fix: hard blocks classify with each warehouse's dialect; daemon liste…
hkaltai 6b54087
fix: data_diff checks an omitted source in the default warehouse's di…
hkaltai 20fb04e
fix: data_diff treats an empty warehouse name as the default, as the …
hkaltai 88f03f4
fix: read sql_execute SQL in every dialect an omitted warehouse can r…
hkaltai 1311bf7
fix: uncertain SQL is hard-blocked on the words alone; dbt adapter ty…
hkaltai c9a9cf9
fix: Oracle, Trino and Fabric keep their reads; TRUNCATE /* c */ ( is…
hkaltai dac4caa
fix: classify SQL as each warehouse reads it, and keep the hard block…
hkaltai fa31614
Merge remote-tracking branch 'origin/main' into tool-cli-daemon
hkaltai ee6add5
test: dbt-adapter-type resets the shared adapter route before each test
hkaltai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| --- | ||
| title: "Tool CLI (Headless) — Altimate Code" | ||
| description: "Call Altimate Code data tools from any shell, agent or CI job without an LLM. Optional warm daemon keeps connections and the schema cache ready." | ||
| --- | ||
|
|
||
| # Tool CLI (Headless) | ||
|
|
||
| Expose the data tools -- warehouse, SQL, schema, lineage, impact, PII, data-diff, FinOps and dbt -- as plain commands. The local data tools use no model or API key, so Claude Code, Codex and CI jobs can call them directly. Linked workspace tools authenticate to Altimate and `workspace_execute` may use backend models. | ||
|
|
||
| ## List tools | ||
|
|
||
| ```bash | ||
| altimate-code tool list # id and description | ||
| altimate-code tool list --json # id, description and JSON input schema | ||
| ``` | ||
|
|
||
| `tool` and `mcp serve` share one implementation, so compact schemas, `sql_execute` with `tables`, `query_from` chaining, spilled result files, read-only enforcement and `answer_commit` (with its `request` argument) are consistent in both. Their permission policies differ: the CLI requires `--allow-write` for local configuration writes such as `warehouse_add`, while `mcp serve` allows `warehouse_add` by default. `tool` exposes the full tool list. In a project linked to a workspace it also exposes `workspace_context`, `workspace_skill` and `workspace_execute`; the link is read from the project's saved state, with no network request. Pass `--workspace-tools` to add them to an unlinked project, or `--no-workspace-tools` to leave them out of a linked one. | ||
|
|
||
| ## Startup context | ||
|
|
||
| ```bash | ||
| altimate-code tool context [--connections <file>] [--json] | ||
| ``` | ||
|
|
||
| Prints the analyst method and the connections known at startup (the same base instructions `mcp serve` sends, plus the linked workspace's name, skills and tools when workspace tools are enabled), so a shell agent gets it in one call. | ||
|
|
||
| ## Run a tool | ||
|
|
||
| ```bash | ||
| altimate-code tool run sql_format --args '{"sql":"select a,b from t","dialect":"postgres"}' | ||
| altimate-code tool run warehouse_list | ||
| altimate-code tool run schema_inspect --args-file inspect.json --json | ||
| echo '{"query":"select 1"}' | altimate-code tool run sql_execute --args - | ||
| ``` | ||
|
|
||
| | Option | Description | | ||
| |---|---| | ||
| | `--args '<json>'` | Tool arguments as a JSON object. `-` reads them from stdin. | | ||
| | `--args-file <path>` | Read the arguments from a file. | | ||
| | `--allow-write` | Allow writes. Without it, only reads run. | | ||
| | `--no-daemon` | Run in this process instead of using the daemon. | | ||
| | `--connections <file>` | Use only this connections JSON file instead of the project and global connection configs. Defaults to `$ALTIMATE_TOOL_CONNECTIONS`. | | ||
| | `--workspace-tools` / `--no-workspace-tools` | Force the linked workspace tools on or off. Unset, they are on when the project is linked. | | ||
| | `--json` | Print `{"status","title","output","metadata"}`. Otherwise only `output` is printed. | | ||
|
|
||
| Arguments are validated against the tool's schema. An unknown tool, invalid arguments or a failing tool exits non-zero. | ||
|
|
||
| Only the data tools are exposed. Coding tools (`bash`, `read`, `edit`, ...), `dbt_pr_review` (use `altimate-code review`), memory and training tools are not available here. | ||
|
|
||
| ## Permissions | ||
|
|
||
| Runs are read-only by default. Reads such as `sql_execute` on a SELECT and `schema_inspect` are allowed; anything else is refused with `Permission denied: <kind>. Re-run with --allow-write to enable writes.` Tools that change local configuration (`warehouse_add`, `warehouse_remove`, `warehouse_install_driver`) also need `--allow-write`. | ||
|
|
||
| `DROP DATABASE`, `DROP SCHEMA` and `TRUNCATE` stay blocked even with `--allow-write`. | ||
|
|
||
| ## Daemon | ||
|
|
||
| `tool run` starts a background process per project directory and CLI version on first use, and reuses it afterwards so warehouse connections and the schema cache stay warm. If it cannot be reached within about 3 seconds, the call runs in-process. `scratch` tables created by `sql_materialize` live as long as the daemon does, with one exception: with `--connections`, an edit to that file is reloaded by replacing the registry entirely, which also closes and empties `scratch`, so a `--connections` daemon's `scratch` tables only live between connection file edits. Every caller in that directory shares the daemon, so concurrent agents share its `scratch` tables and its `answer_commit` history; use `--no-daemon` to keep a caller separate. | ||
|
|
||
| The daemon reloads its connections when the global or project `connections.json` (or the `--connections` file) changed since its last reload. The check runs on a call that has no other call in flight, so an edit made while calls overlap is picked up by the next call that runs alone; calls that arrive during a reload wait for it. | ||
|
|
||
| ```bash | ||
| altimate-code tool daemon status | ||
| altimate-code tool daemon stop | ||
| ``` | ||
|
|
||
| `status` and `stop` locate the running daemon the same way `run` does: by project directory, CLI version, the `--connections` file (if any), whether workspace tools are on, and the caller's `ALTIMATE_CODE_CONN_*`, `ALTIMATE_DISABLE_SCHEMA_VALUES`, `ALTIMATE_INTEGRATIONS` and `ALTIMATE_DISABLE_WORKSPACE` environment variables. Run them with the same flags and variables as the call that started the daemon, or they will report no daemon running for this project even though one is. | ||
|
|
||
| | Setting | Description | | ||
| |---|---| | ||
| | `ALTIMATE_TOOL_DAEMON=0` | Always run in-process. | | ||
| | `ALTIMATE_TOOL_DAEMON_IDLE_MS` | Idle time before the daemon exits (default `600000`). | | ||
|
|
||
| The daemon listens on a local socket (a named pipe on Windows) under the Altimate Code state directory and removes it on exit. | ||
|
|
||
| ## Claude Code routing | ||
|
|
||
| For clients that cannot use the `altimate-code` MCP server, the Claude Code plugin adds CLI routing guidance at session start: `altimate-code tool context` followed by `altimate-code tool run` for data questions, and `altimate-code run` for long multi-step jobs. To persist the same guidance in the repository, run `altimate-code link --claude-md`; it writes a managed block to the project's `CLAUDE.md` and never changes content outside the `<!-- altimate-code:routing start -->` / `<!-- altimate-code:routing end -->` markers. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Workspaces for external coding clients (experimental) | ||
|
|
||
| `altimate-code mcp serve --workspace-tools` adds workspace context, named skills and known read operations from the linked workspace's existing `datamate` engine. The default MCP server remains unchanged. This draft builds on the experimental MCP server; no rollout or merge is implied. | ||
|
|
||
| The client must run in the intended project directory. Sign-in and linking may complete after connecting: `workspace_context` returns structured setup status and the catalog remains stable. `workspace_context` returns the current workspace, bounded project memory, a summary of skills/knowledge/integrations, and skill names. `workspace_skill` reads a named skill from the validated snapshot; refresh missing skills with `altimate-code workspace refresh`. It rejects traversal, symlinks, oversized skills and a changed snapshot/account. | ||
|
|
||
| The engine is pinned with its existing `--datamate` option. Only knowledge, supported metadata reads and SQL reads are exposed; arbitrary tools, writes and engine memory mutations are excluded. SQL uses the existing classifier. Unsupported SQL argument schemas are withheld. The engine authenticates through its normal local configuration. Use read-only warehouse credentials: classification is not database isolation. Local SQL remains available if workspace authentication, linking or engine startup fails. An account/binding change invalidates stale receipts. Read fresh context and use the new receipt; reconnecting MCP is not required. | ||
|
|
||
| For non-model clients: | ||
|
|
||
| ``` | ||
| altimate-code workspace-client list | ||
| altimate-code workspace-client context --directory /absolute/project | ||
| printf '%s' 'Use booked ARR for recurring revenue.' | altimate-code workspace-client remember --directory /absolute/project --token=<context-workspace-token> --id=metrics/arr | ||
| ``` | ||
|
|
||
| These commands output JSON. A context receipt binds account, workspace and project. `remember` requires that receipt, a valid memory id and 1–2,048 characters on stdin; it saves exactly one project block. It suppresses the ordinary fire-and-forget mirror, then uses the existing sync path with the explicitly selected binding. Requests pin credentials across async API/index operations. A backend failure after local persistence reports `savedLocally: true, cloudConfirmed: false`; retrying is a user decision. Confirmed cloud publication is reported only when the sync reports one successful write. No model-callable memory-write tool or bulk-sync operation is added. | ||
|
|
||
| Workspace context adds bounded data to a client's prompt; skills load on demand. Explicit knowledge calls can use backend models, memory publication can invoke the existing backend extractor, and warehouse calls retain warehouse costs. There is no new reasoning agent or per-row model loop. A CLI link can normally backfill existing memory; clients that expose linking without a backfill confirmation must disable memory for that subprocess, as the Claude plugin does. Do not pass `--yes` unless replacing a link was explicitly requested. | ||
|
|
||
| Verification covers unit contracts, a real stdio protocol fixture and existing SQLite MCP behavior. Production read-only testing listed visible workspaces and loaded matching context through a temporary local project. Production bindings and memory were not written. A non-empty cloud memory round trip and real workspace-engine SQL/knowledge calls remain rollout checks. | ||
|
|
||
| ## Automatic-client setup and stable gateway | ||
|
|
||
| The opt-in workspace catalog is always `workspace_context`, `workspace_skill` and `workspace_execute`, including when initially unlinked. `workspace_context` reports `needs_auth`, `needs_workspace`, `disabled` or `unavailable` without returning raw credential errors. A ready context includes the workspace receipt. Context loads coalesce and cache for 30 seconds; identity is verified on every use. `refresh: true` bypasses that cache. | ||
|
|
||
| Pass `include_tools: true` to request lazy engine discovery. The response includes `engineStatus` (`ready`, `needs_engine` or `unavailable`) and an operation catalog with the engine's actual input schemas. After explicit engine installation, request both `refresh: true` and `include_tools: true`. `workspace_execute` takes `workspace_token`, `operation` and an `arguments` object matching the returned schema. Unknown operations, invalid schemas, stale receipts and source-write SQL are refused. `workspace_skill` also requires `workspace_token`. | ||
|
|
||
| This gateway intentionally changes the host permission surface: allowing `workspace_execute` permits its entire closed read-operation allowlist, including knowledge requests that can invoke backend models. It does not inherit per-operation approvals from the old dynamically discovered tool names. No workspace memory write is exposed as an MCP tool. | ||
|
|
||
| `workspace-client context` returns the same structured setup status. `workspace-client engine-install` invokes the existing native installer; a UI must require an explicit user action before invoking it. The Claude pilot runs native sign-in and link actions from its first-use panel. Linking disables memory backfill for that subprocess. Authentication output stays outside model context. Default MCP startup without `--workspace-tools` is unchanged. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MINOR (docs): this line still says the block holds unconditionally.
At fa31614 it reads "
DROP DATABASE,DROP SCHEMAandTRUNCATEstay blocked even with--allow-write." The PR description says this page documents the block as best effort, but that wording is not pushed yet. Dynamic SQL gets past the block with--allow-write(see thesql-classify.tscomment).Suggested fix: push the best-effort wording from the description, e.g. "are refused even with
--allow-write, by reading the SQL text; SQL the warehouse assembles at run time (dynamic SQL, stored routines) can get past it — use a role without these privileges for a guarantee."Blocker: no. The gap predates this PR on
main, and the wording is already written in the description.