From 14cc5754cf38a022ab7de3965edd15266738b047 Mon Sep 17 00:00:00 2001 From: Harish Kumar Date: Thu, 15 Oct 2026 19:09:56 +0530 Subject: [PATCH 1/6] fix: resolve CLI as altimate-code or altimate Standalone installs (curl, Homebrew, PowerShell) expose only the `altimate` binary; npm exposes both names. The skills and commands hard-required `altimate-code` and reported the CLI as missing on standalone installs. Resolve either name in every invocation and list both install methods. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 2 +- plugins/altimate-code/.claude-plugin/plugin.json | 2 +- plugins/altimate-code/CHANGELOG.md | 6 ++++++ plugins/altimate-code/README.md | 11 +++++++---- plugins/altimate-code/commands/altimate.md | 12 +++++++----- plugins/altimate-code/commands/review.md | 11 +++++++++-- .../altimate-code/skills/altimate-code/SKILL.md | 14 +++++++++----- plugins/altimate-code/skills/review/SKILL.md | 11 +++++++++-- 8 files changed, 49 insertions(+), 20 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 36550af..4aa7962 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ }, "metadata": { "description": "Altimate's Claude Code plugin — delegates dbt and warehouse work to the altimate-code CLI agent.", - "version": "1.0.0" + "version": "1.0.1" }, "plugins": [ { diff --git a/plugins/altimate-code/.claude-plugin/plugin.json b/plugins/altimate-code/.claude-plugin/plugin.json index ba2b6d7..a173505 100644 --- a/plugins/altimate-code/.claude-plugin/plugin.json +++ b/plugins/altimate-code/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "altimate-code", "displayName": "Altimate Code", - "version": "1.0.0", + "version": "1.0.1", "description": "Delegates dbt and warehouse work to altimate-code, a specialized CLI agent with 100+ purpose-built data tools (SQL analysis, column-level lineage, dbt build/test/run, warehouse profiling, FinOps, connectivity to Snowflake, BigQuery, Redshift, Databricks, Postgres, MySQL, DuckDB).", "author": { "name": "AltimateAI", diff --git a/plugins/altimate-code/CHANGELOG.md b/plugins/altimate-code/CHANGELOG.md index 51abc76..652dff0 100644 --- a/plugins/altimate-code/CHANGELOG.md +++ b/plugins/altimate-code/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this plugin will be documented in this file. +## [1.0.1] — 2026-10-15 + +### Fixed +- The skills and slash commands now resolve the CLI as `altimate-code` and fall back to `altimate`. Standalone installs (curl, Homebrew, PowerShell) expose only `altimate`, so the plugin previously reported "not installed" on machines where the CLI was present. +- Install guidance now lists both the npm and the standalone installer. + ## [1.0.0] — 2026-07-09 ### Added diff --git a/plugins/altimate-code/README.md b/plugins/altimate-code/README.md index 35ee013..f9d7f79 100644 --- a/plugins/altimate-code/README.md +++ b/plugins/altimate-code/README.md @@ -13,13 +13,16 @@ Routes dbt + warehouse tasks from Claude Code to [altimate-code](https://github. ## Prerequisites -The altimate-code CLI must be installed and configured on your PATH: +The altimate-code CLI must be installed and configured on your PATH. Either install method works: ```bash -npm install -g altimate-code # requires Node 20+ -altimate-code # launch the TUI, then run /connect to configure your LLM provider +npm install -g altimate-code # requires Node 20+; exposes `altimate-code` and `altimate` +curl -fsSL https://www.altimate.sh/install | bash # standalone binary; exposes only `altimate` +altimate # launch the TUI, then run /connect to configure your LLM provider ``` +The plugin invokes `altimate-code` when it is on PATH and falls back to `altimate` otherwise, so standalone installs work without an `altimate-code` alias. + Or configure a provider via environment variable (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and 20+ others — see the [altimate-code docs](https://docs.altimate.sh)). If altimate-code is not on PATH or not configured, the plugin surfaces the failure with fix instructions rather than silently falling back to Claude's native tools. @@ -50,7 +53,7 @@ Full details: **[PRIVACY.md](../../PRIVACY.md)** · Security policy and disclosu | Symptom | Fix | |---|---| -| `command not found: altimate-code` | `npm install -g altimate-code` (Node 20+), then run `altimate-code` once to configure your provider. | +| Neither `altimate-code` nor `altimate` on PATH | `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider. | | `Unauthorized` / `No provider configured` | Run `altimate-code` to open the TUI and reconfigure your provider via `/connect`, or set the provider API key env var. | | Task hangs for several minutes | Open `altimate-code` to check for a pending prompt in the TUI, or re-run specifying a known-good model. | | Empty result | The task may be too ambiguous — restate with the target table, expected columns, or time window. | diff --git a/plugins/altimate-code/commands/altimate.md b/plugins/altimate-code/commands/altimate.md index ee80180..8f8c460 100644 --- a/plugins/altimate-code/commands/altimate.md +++ b/plugins/altimate-code/commands/altimate.md @@ -9,10 +9,10 @@ Workflow (follow in order, no skipping): 1. **Verify altimate-code is installed:** ```bash - command -v altimate-code + command -v altimate-code || command -v altimate ``` - If it returns nothing, stop and tell the user: - > altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+), then run `altimate-code` once to configure your provider/warehouse auth, then re-run `/altimate `. + The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Either one is fine. If neither resolves, stop and tell the user: + > altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install | bash`, then run `altimate` once to configure your provider/warehouse auth, then re-run `/altimate `. 2. **Pick the agent persona** based on the user's task shape. Start cheap and escalate on failure — fast-edit handles most dbt/SQL work at 10–20× lower cost than builder. @@ -37,7 +37,8 @@ Workflow (follow in order, no skipping): )" umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" - altimate-code run "$TASK" \ + ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" + "$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo \ --output "$OUTPUT_FILE" \ @@ -53,7 +54,8 @@ Workflow (follow in order, no skipping): )" umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" - altimate-code run "$TASK" \ + ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" + "$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo --output "$OUTPUT_FILE" --dir "$(pwd)" \ --continue diff --git a/plugins/altimate-code/commands/review.md b/plugins/altimate-code/commands/review.md index c74f8ec..1b22493 100644 --- a/plugins/altimate-code/commands/review.md +++ b/plugins/altimate-code/commands/review.md @@ -17,7 +17,14 @@ Run the `altimate-code review` CLI on the current dbt project and present the si ## Workflow -1. **Verify altimate-code is on PATH.** Run `command -v altimate-code`. If nothing is returned, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+), then run 'altimate-code' once to configure your provider and warehouse auth."` — then STOP. +1. **Verify altimate-code is on PATH.** Run `command -v altimate-code || command -v altimate`. If nothing is returned, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+) or 'curl -fsSL https://www.altimate.sh/install | bash', then run 'altimate' once to configure your provider and warehouse auth."` — then STOP. + + The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every `altimate-code review ...` command below must be run through the resolved binary, in the same Bash call as the resolver (shell state does not persist between calls): + + ```bash + ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" + "$ALTIMATE_BIN" review # plus any scope/flags from below + ``` 2. **Confirm you are in a dbt project root** (`dbt_project.yml` present). If not, tell the user to `cd` there and STOP. @@ -54,7 +61,7 @@ Anything else (`--manifest`, `--cwd`) only if the user explicitly requested it o | Symptom | Message to user | |---|---| -| `command not found: altimate-code` | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+), then run `altimate-code` once to configure auth." | +| Neither `altimate-code` nor `altimate` on PATH | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth." | | `Unauthorized: Incorrect auth token` | "altimate-code's LLM provider auth is misconfigured. Run `altimate-code` to reconfigure, or re-run with `--no-ai`." | | `fatal: not a git repository` | "This directory isn't a git repo. `altimate-code review` needs git to compute the diff." | | No `dbt_project.yml` | "No dbt project detected at this path. Run from the directory with `dbt_project.yml`." | diff --git a/plugins/altimate-code/skills/altimate-code/SKILL.md b/plugins/altimate-code/skills/altimate-code/SKILL.md index 9fa80ec..57cc3d4 100644 --- a/plugins/altimate-code/skills/altimate-code/SKILL.md +++ b/plugins/altimate-code/skills/altimate-code/SKILL.md @@ -21,7 +21,7 @@ altimate-code is a CLI AI agent with 100+ purpose-built data engineering tools. ## You MUST follow this workflow -1. **Verify altimate-code is on PATH** with `command -v altimate-code`. If it returns nothing, jump to "Not installed" below and stop. +1. **Verify altimate-code is on PATH** with `command -v altimate-code || command -v altimate`. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Either name is the same CLI. If neither resolves, jump to "Failure modes" below and stop. 2. **Run altimate-code with the user's task** using the invocation below. Pass the user's request through verbatim — do not paraphrase or split it. 3. **Read the output file** and present it to the user as-is. @@ -57,7 +57,8 @@ ALTIMATE_TASK )" umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" -altimate-code run "$TASK" \ +ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" +"$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo \ --output "$OUTPUT_FILE" \ @@ -75,6 +76,8 @@ Then `Read "$OUTPUT_FILE"` and emit its contents to the user without re-summaris | `--output "$OUTPUT_FILE"` | Captures the final response. Use the private `mktemp` file from above — do NOT use a fixed path like `/tmp/altimate-result.md`; concurrent sessions clobber each other and a world-readable fixed path leaks data. | | `--dir "$(pwd)"` | Runs altimate-code in the current project so it picks up dbt project config, profiles.yml, etc. | +Each Bash call starts a fresh shell, so keep the `ALTIMATE_BIN=...` resolver line inside the same command as the `run` — do not resolve it in an earlier call and reuse the variable. + ### Follow-up tasks in the same project When the user makes a follow-up data task in the same project after a successful altimate-code delegation, prefer `--continue` to resume the warm session instead of starting a fresh one. Same here-doc + `mktemp` pattern: @@ -86,7 +89,8 @@ ALTIMATE_TASK )" umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" -altimate-code run "$TASK" \ +ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" +"$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo \ --output "$OUTPUT_FILE" \ @@ -104,7 +108,7 @@ When altimate-code returns an error, **report the error to the user and STOP**. | Symptom | What to tell the user — verbatim | |---|---| -| `command not found: altimate-code` | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) and run `altimate-code` once to configure auth. Then re-run your request." | +| Neither `altimate-code` nor `altimate` on PATH (`ALTIMATE_BIN` is empty) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth. Then re-run your request." | | `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate-code` in your terminal to open the TUI and reconfigure your provider, then re-run your request." | | Process hangs >5 min | "altimate-code is unresponsive. Try `altimate-code` to inspect the TUI for an open prompt, or re-run with `--model anthropic/claude-sonnet-4-6` to force a known-good model." | | Output file empty | "altimate-code returned without producing output. The task may be too ambiguous — please restate with more detail (target table, expected columns, time window)." | @@ -115,5 +119,5 @@ In every row, the instruction to the user is the action — you do not retry the ## Notes - altimate-code runs its own LLM, separate from Claude Code's. Costs and rate limits accrue to altimate-code's configured provider. -- Sessions persist in altimate-code's local store — `altimate-code session list` shows prior runs; `--continue` resumes the latest, `--session ` resumes a specific one. +- Sessions persist in altimate-code's local store — `altimate-code session list` (or `altimate session list`) shows prior runs; `--continue` resumes the latest, `--session ` resumes a specific one. - For very long tasks, the `--output` file is the source of truth — stdout buffering can drop content. diff --git a/plugins/altimate-code/skills/review/SKILL.md b/plugins/altimate-code/skills/review/SKILL.md index 5ba6adf..4405a2c 100644 --- a/plugins/altimate-code/skills/review/SKILL.md +++ b/plugins/altimate-code/skills/review/SKILL.md @@ -27,7 +27,14 @@ description: >- ## You MUST follow this workflow -1. **Verify altimate-code is on PATH** with `command -v altimate-code`. If it returns nothing, jump to "Failure modes" below and stop. +1. **Verify altimate-code is on PATH** with `command -v altimate-code || command -v altimate`. If neither resolves, jump to "Failure modes" below and stop. + + The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every `altimate-code review ...` command below must be run through the resolved binary, in the same Bash call as the resolver (shell state does not persist between calls): + + ```bash + ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" + "$ALTIMATE_BIN" review # plus any scope/flags from below + ``` 2. **Determine review scope from the user's ask** using the table below. @@ -68,7 +75,7 @@ description: >- | Symptom | Message to the user | |---|---| -| `command not found: altimate-code` | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+), then run `altimate-code` once to configure your provider and warehouse auth. Then re-run the review." | +| Neither `altimate-code` nor `altimate` on PATH | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider and warehouse auth. Then re-run the review." | | `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate-code` to reconfigure — or re-run with `--no-ai` to skip the LLM lane entirely and get a deterministic-only review." | | `fatal: not a git repository` | "This directory isn't a git repo. `altimate-code review` computes the diff via git — run from a dbt project inside a git worktree." | | No `dbt_project.yml` found | "No dbt project detected at this path. The review needs a dbt project to compile models against. Run from the directory containing `dbt_project.yml`." | From 457f3c264ec50506479814d5a1acae6b50821863 Mon Sep 17 00:00:00 2001 From: Harish Kumar Date: Mon, 19 Oct 2026 10:20:04 +0530 Subject: [PATCH 2/6] fix: ignore aliases and functions when resolving the CLI `command -v` reports alias text or a function name before the PATH binary, so a user alias such as `alias altimate-code=altimate` was captured as the binary path and every run failed. The resolver now drops the candidate's alias/function in a subshell before looking it up, which also accepts relative PATH entries, and exits 127 with a clear message when neither name is installed. It runs before mktemp so a missing CLI leaves no temp file behind. Review scope tables now use the resolved binary, and recovery messages name `altimate`, which both install methods provide. Adds tests/resolve-cli.sh, which checks every resolver copy is identical and resolves correctly in bash and zsh. Co-Authored-By: Claude Opus 5.5 (1M context) --- CONTRIBUTING.md | 2 + plugins/altimate-code/CHANGELOG.md | 2 +- plugins/altimate-code/README.md | 6 +- plugins/altimate-code/commands/altimate.md | 10 ++- plugins/altimate-code/commands/review.md | 19 ++--- .../skills/altimate-code/SKILL.md | 20 ++++-- plugins/altimate-code/skills/review/SKILL.md | 19 ++--- tests/resolve-cli.sh | 69 +++++++++++++++++++ 8 files changed, 118 insertions(+), 29 deletions(-) create mode 100755 tests/resolve-cli.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c264273..63d8e9b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,8 @@ Thanks for taking the time to contribute. This plugin lives in one repo (`Altima claude plugin validate --strict ./plugins/altimate-code ``` Both must exit clean. **Validating the repo root alone is not sufficient** — the marketplace-level validator does not descend into skills, so skill-frontmatter parse errors go undetected unless you also validate the plugin path. + + If you touch the CLI resolver block in a skill or command, run `./tests/resolve-cli.sh` — it checks every copy is identical and resolves correctly in bash and zsh. 4. Open a PR against `AltimateAI/altimate-claude-plugin:main`. ## Repo layout diff --git a/plugins/altimate-code/CHANGELOG.md b/plugins/altimate-code/CHANGELOG.md index 652dff0..0fad15e 100644 --- a/plugins/altimate-code/CHANGELOG.md +++ b/plugins/altimate-code/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this plugin will be documented in this file. ### Fixed - The skills and slash commands now resolve the CLI as `altimate-code` and fall back to `altimate`. Standalone installs (curl, Homebrew, PowerShell) expose only `altimate`, so the plugin previously reported "not installed" on machines where the CLI was present. -- Install guidance now lists both the npm and the standalone installer. +- Install guidance and recovery messages now name `altimate`, which both install methods provide. ## [1.0.0] — 2026-07-09 diff --git a/plugins/altimate-code/README.md b/plugins/altimate-code/README.md index f9d7f79..48d30a6 100644 --- a/plugins/altimate-code/README.md +++ b/plugins/altimate-code/README.md @@ -54,10 +54,10 @@ Full details: **[PRIVACY.md](../../PRIVACY.md)** · Security policy and disclosu | Symptom | Fix | |---|---| | Neither `altimate-code` nor `altimate` on PATH | `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider. | -| `Unauthorized` / `No provider configured` | Run `altimate-code` to open the TUI and reconfigure your provider via `/connect`, or set the provider API key env var. | -| Task hangs for several minutes | Open `altimate-code` to check for a pending prompt in the TUI, or re-run specifying a known-good model. | +| `Unauthorized` / `No provider configured` | Run `altimate` to open the TUI and reconfigure your provider via `/connect`, or set the provider API key env var. | +| Task hangs for several minutes | Open `altimate` to check for a pending prompt in the TUI, or re-run specifying a known-good model. | | Empty result | The task may be too ambiguous — restate with the target table, expected columns, or time window. | -| `UNKNOWN_USER` / `Database does not exist` mid-run | The CLI connects but your warehouse credentials don't match this project — reconfigure warehouse auth in the `altimate-code` TUI or `profiles.yml`. | +| `UNKNOWN_USER` / `Database does not exist` mid-run | The CLI connects but your warehouse credentials don't match this project — reconfigure warehouse auth in the `altimate` TUI or `profiles.yml`. | | Plugin installed but never delegates | Confirm it's enabled: `claude plugin enable altimate-code@altimate-claude-plugin`. | Still stuck? See [Support](#support). diff --git a/plugins/altimate-code/commands/altimate.md b/plugins/altimate-code/commands/altimate.md index 8f8c460..2c34297 100644 --- a/plugins/altimate-code/commands/altimate.md +++ b/plugins/altimate-code/commands/altimate.md @@ -35,9 +35,12 @@ Workflow (follow in order, no skipping): $ARGUMENTS ALTIMATE_TASK )" + for ALTIMATE_NAME in altimate-code altimate; do + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + done + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" - ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" "$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo \ @@ -52,9 +55,12 @@ Workflow (follow in order, no skipping): $ARGUMENTS ALTIMATE_TASK )" + for ALTIMATE_NAME in altimate-code altimate; do + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + done + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" - ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" "$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo --output "$OUTPUT_FILE" --dir "$(pwd)" \ diff --git a/plugins/altimate-code/commands/review.md b/plugins/altimate-code/commands/review.md index 1b22493..54bc387 100644 --- a/plugins/altimate-code/commands/review.md +++ b/plugins/altimate-code/commands/review.md @@ -19,20 +19,23 @@ Run the `altimate-code review` CLI on the current dbt project and present the si 1. **Verify altimate-code is on PATH.** Run `command -v altimate-code || command -v altimate`. If nothing is returned, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+) or 'curl -fsSL https://www.altimate.sh/install | bash', then run 'altimate' once to configure your provider and warehouse auth."` — then STOP. - The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every `altimate-code review ...` command below must be run through the resolved binary, in the same Bash call as the resolver (shell state does not persist between calls): + The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: ```bash - ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" + for ALTIMATE_NAME in altimate-code altimate; do + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + done + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } "$ALTIMATE_BIN" review # plus any scope/flags from below ``` 2. **Confirm you are in a dbt project root** (`dbt_project.yml` present). If not, tell the user to `cd` there and STOP. 3. **Determine scope from `$ARGUMENTS`:** - - Empty → `altimate-code review` - - Commit SHA (matches `[0-9a-f]{7,40}`) → `altimate-code review --base $ARGUMENTS~1 --head $ARGUMENTS` - - Branch name (matches local branch via `git rev-parse`) → `altimate-code review --base $ARGUMENTS` - - PR URL or number → first `gh pr checkout `, then `altimate-code review` + - Empty → `"$ALTIMATE_BIN" review` + - Commit SHA (matches `[0-9a-f]{7,40}`) → `"$ALTIMATE_BIN" review --base $ARGUMENTS~1 --head $ARGUMENTS` + - Branch name (matches local branch via `git rev-parse`) → `"$ALTIMATE_BIN" review --base $ARGUMENTS` + - PR URL or number → first `gh pr checkout `, then `"$ALTIMATE_BIN" review` 4. **Run the review command as chosen above.** Capture its stdout. @@ -61,8 +64,8 @@ Anything else (`--manifest`, `--cwd`) only if the user explicitly requested it o | Symptom | Message to user | |---|---| -| Neither `altimate-code` nor `altimate` on PATH | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth." | -| `Unauthorized: Incorrect auth token` | "altimate-code's LLM provider auth is misconfigured. Run `altimate-code` to reconfigure, or re-run with `--no-ai`." | +| `altimate-code CLI not found` (neither `altimate-code` nor `altimate` on PATH) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth." | +| `Unauthorized: Incorrect auth token` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` to reconfigure, or re-run with `--no-ai`." | | `fatal: not a git repository` | "This directory isn't a git repo. `altimate-code review` needs git to compute the diff." | | No `dbt_project.yml` | "No dbt project detected at this path. Run from the directory with `dbt_project.yml`." | | Output mentions `DEGRADED — lint-only` | Present verbatim; do NOT silently upgrade a degraded run to a full verdict. | diff --git a/plugins/altimate-code/skills/altimate-code/SKILL.md b/plugins/altimate-code/skills/altimate-code/SKILL.md index 57cc3d4..dc0ace7 100644 --- a/plugins/altimate-code/skills/altimate-code/SKILL.md +++ b/plugins/altimate-code/skills/altimate-code/SKILL.md @@ -55,9 +55,12 @@ TASK="$(cat <<'ALTIMATE_TASK' ALTIMATE_TASK )" +for ALTIMATE_NAME in altimate-code altimate; do + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break +done +[ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" -ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" "$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo \ @@ -76,7 +79,7 @@ Then `Read "$OUTPUT_FILE"` and emit its contents to the user without re-summaris | `--output "$OUTPUT_FILE"` | Captures the final response. Use the private `mktemp` file from above — do NOT use a fixed path like `/tmp/altimate-result.md`; concurrent sessions clobber each other and a world-readable fixed path leaks data. | | `--dir "$(pwd)"` | Runs altimate-code in the current project so it picks up dbt project config, profiles.yml, etc. | -Each Bash call starts a fresh shell, so keep the `ALTIMATE_BIN=...` resolver line inside the same command as the `run` — do not resolve it in an earlier call and reuse the variable. +Each Bash call starts a fresh shell, so keep the `ALTIMATE_BIN` resolver loop inside the same command as the `run` — do not resolve it in an earlier call and reuse the variable. ### Follow-up tasks in the same project @@ -87,9 +90,12 @@ TASK="$(cat <<'ALTIMATE_TASK' ALTIMATE_TASK )" +for ALTIMATE_NAME in altimate-code altimate; do + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break +done +[ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" -ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" "$ALTIMATE_BIN" run "$TASK" \ --agent \ --yolo \ @@ -108,11 +114,11 @@ When altimate-code returns an error, **report the error to the user and STOP**. | Symptom | What to tell the user — verbatim | |---|---| -| Neither `altimate-code` nor `altimate` on PATH (`ALTIMATE_BIN` is empty) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth. Then re-run your request." | -| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate-code` in your terminal to open the TUI and reconfigure your provider, then re-run your request." | -| Process hangs >5 min | "altimate-code is unresponsive. Try `altimate-code` to inspect the TUI for an open prompt, or re-run with `--model anthropic/claude-sonnet-4-6` to force a known-good model." | +| `altimate-code CLI not found` (neither `altimate-code` nor `altimate` on PATH) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth. Then re-run your request." | +| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` in your terminal to open the TUI and reconfigure your provider, then re-run your request." | +| Process hangs >5 min | "altimate-code is unresponsive. Try `altimate` to inspect the TUI for an open prompt, or re-run with `--model anthropic/claude-sonnet-4-6` to force a known-good model." | | Output file empty | "altimate-code returned without producing output. The task may be too ambiguous — please restate with more detail (target table, expected columns, time window)." | -| Warehouse error mid-run (`UNKNOWN_USER`, `Database does not exist`) | "altimate-code can connect but the warehouse credentials it has are wrong for this project. Configure provider/warehouse auth via `altimate-code` TUI." | +| Warehouse error mid-run (`UNKNOWN_USER`, `Database does not exist`) | "altimate-code can connect but the warehouse credentials it has are wrong for this project. Configure provider/warehouse auth via the `altimate` TUI." | In every row, the instruction to the user is the action — you do not retry the task with native tools. If the user fixes the underlying issue and asks again, you delegate again. diff --git a/plugins/altimate-code/skills/review/SKILL.md b/plugins/altimate-code/skills/review/SKILL.md index 4405a2c..bd48382 100644 --- a/plugins/altimate-code/skills/review/SKILL.md +++ b/plugins/altimate-code/skills/review/SKILL.md @@ -29,10 +29,13 @@ description: >- 1. **Verify altimate-code is on PATH** with `command -v altimate-code || command -v altimate`. If neither resolves, jump to "Failure modes" below and stop. - The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every `altimate-code review ...` command below must be run through the resolved binary, in the same Bash call as the resolver (shell state does not persist between calls): + The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: ```bash - ALTIMATE_BIN="$(command -v altimate-code || command -v altimate)" + for ALTIMATE_NAME in altimate-code altimate; do + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + done + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } "$ALTIMATE_BIN" review # plus any scope/flags from below ``` @@ -48,10 +51,10 @@ description: >- | User says | Command to run | |---|---| -| "review my changes" / "review this branch" / "audit my dbt work" / no scope specified | `altimate-code review` (default: working tree vs merge-base with `origin/main`) | -| "review PR #123" or gives a GitHub PR URL | First `gh pr checkout 123`, then `altimate-code review` | -| "review commit `abc123`" | `altimate-code review --base abc123~1 --head abc123` | -| "compare staging to prod" / "review the diff between two branches" | `altimate-code review --base prod --head staging` | +| "review my changes" / "review this branch" / "audit my dbt work" / no scope specified | `"$ALTIMATE_BIN" review` (default: working tree vs merge-base with `origin/main`) | +| "review PR #123" or gives a GitHub PR URL | First `gh pr checkout 123`, then `"$ALTIMATE_BIN" review` | +| "review commit `abc123`" | `"$ALTIMATE_BIN" review --base abc123~1 --head abc123` | +| "compare staging to prod" / "review the diff between two branches" | `"$ALTIMATE_BIN" review --base prod --head staging` | ## Do NOT do these @@ -75,8 +78,8 @@ description: >- | Symptom | Message to the user | |---|---| -| Neither `altimate-code` nor `altimate` on PATH | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider and warehouse auth. Then re-run the review." | -| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate-code` to reconfigure — or re-run with `--no-ai` to skip the LLM lane entirely and get a deterministic-only review." | +| `altimate-code CLI not found` (neither `altimate-code` nor `altimate` on PATH) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider and warehouse auth. Then re-run the review." | +| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` to reconfigure — or re-run with `--no-ai` to skip the LLM lane entirely and get a deterministic-only review." | | `fatal: not a git repository` | "This directory isn't a git repo. `altimate-code review` computes the diff via git — run from a dbt project inside a git worktree." | | No `dbt_project.yml` found | "No dbt project detected at this path. The review needs a dbt project to compile models against. Run from the directory containing `dbt_project.yml`." | | Output says `DEGRADED — lint-only` | Present that note verbatim. Do not silently upgrade a degraded run to a full verdict. | diff --git a/tests/resolve-cli.sh b/tests/resolve-cli.sh new file mode 100755 index 0000000..9deedce --- /dev/null +++ b/tests/resolve-cli.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Checks the CLI resolver block embedded in the skills and slash commands: +# every copy must be identical, and it must pick the right binary in bash and zsh. +set -u +cd "$(dirname "$0")/.." + +# file:expected number of resolver blocks +FILES=( + plugins/altimate-code/commands/altimate.md:2 + plugins/altimate-code/commands/review.md:1 + plugins/altimate-code/skills/altimate-code/SKILL.md:2 + plugins/altimate-code/skills/review/SKILL.md:1 +) +FAILURES=0 +fail() { echo "FAIL: $*"; FAILURES=$((FAILURES + 1)); } + +# Print each resolver block (loop start through the not-found guard) on one line, dedented. +extract_blocks() { + awk '/for ALTIMATE_NAME in/ {grab=1; block=""} + grab {sub(/^ */, ""); block = block $0 "\\n"} + grab && /CLI not found/ {grab=0; print block}' "$1" +} + +ALL_BLOCKS="" +for entry in "${FILES[@]}"; do + file="${entry%:*}" + blocks="$(extract_blocks "$file")" + count="$(printf '%s' "$blocks" | grep -c .)" + [ "$count" -eq "${entry##*:}" ] || fail "$file has $count resolver blocks, expected ${entry##*:}" + ALL_BLOCKS="$ALL_BLOCKS$blocks"$'\n' +done +[ "$(printf '%s' "$ALL_BLOCKS" | grep . | sort -u | grep -c .)" -eq 1 ] || fail "resolver blocks differ between files" +RESOLVER="$(printf '%b' "$(printf '%s' "$ALL_BLOCKS" | head -n1)")" + +STUBS="$(mktemp -d)" +trap 'rm -rf "$STUBS"' EXIT +for stub in only-altimate/altimate only-altimate-code/altimate-code both/altimate both/altimate-code "relative dir/altimate"; do + mkdir -p "$STUBS/$(dirname "$stub")" + printf '#!/bin/sh\necho "ran %s"\n' "$(basename "$stub")" > "$STUBS/$stub" + chmod +x "$STUBS/$stub" +done +mkdir -p "$STUBS/neither" + +# expect +# Runs from $STUBS without startup files, so relative PATH entries resolve and user config can't interfere. +expect() { + local shell_cmd + case "$1" in zsh) shell_cmd=(zsh -f) ;; *) shell_cmd=(bash --noprofile --norc) ;; esac + out="$(cd "$STUBS" && env -u BASH_ENV -u ENV PATH="$2:/usr/bin:/bin" "${shell_cmd[@]}" -c "$3 +$RESOLVER +\"\$ALTIMATE_BIN\"" 2>&1)" + status=$? + [ "$status" -eq "$4" ] && [ "$out" = "$5" ] \ + || fail "$1 / PATH=$2 / '${3:-no setup}': expected exit $4 '$5', got exit $status '$out'" +} + +ALIAS_SETUP='shopt -s expand_aliases 2>/dev/null; alias altimate-code=altimate' +for sh in bash zsh; do + command -v "$sh" >/dev/null || { echo "skip: $sh not installed"; continue; } + expect "$sh" "$STUBS/only-altimate" '' 0 'ran altimate' + expect "$sh" "$STUBS/only-altimate-code" '' 0 'ran altimate-code' + expect "$sh" "$STUBS/both" '' 0 'ran altimate-code' + expect "$sh" "$STUBS/neither" '' 127 'altimate-code CLI not found (tried altimate-code, altimate)' + expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP" 0 'ran altimate' + expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP; altimate() { echo function; }" 0 'ran altimate' + expect "$sh" "relative dir" '' 0 'ran altimate' +done + +[ "$FAILURES" -eq 0 ] && echo "ok" || { echo "$FAILURES failure(s)"; exit 1; } From 648354e5f5117f501414de5e597cd93d92567494 Mon Sep 17 00:00:00 2001 From: Harish Kumar Date: Mon, 19 Oct 2026 13:08:08 +0530 Subject: [PATCH 3/6] chore: bump plugin version to 1.1.0 Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 2 +- plugins/altimate-code/.claude-plugin/plugin.json | 2 +- plugins/altimate-code/CHANGELOG.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4aa7962..b2fc68a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ }, "metadata": { "description": "Altimate's Claude Code plugin — delegates dbt and warehouse work to the altimate-code CLI agent.", - "version": "1.0.1" + "version": "1.1.0" }, "plugins": [ { diff --git a/plugins/altimate-code/.claude-plugin/plugin.json b/plugins/altimate-code/.claude-plugin/plugin.json index a173505..e5c14a8 100644 --- a/plugins/altimate-code/.claude-plugin/plugin.json +++ b/plugins/altimate-code/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "altimate-code", "displayName": "Altimate Code", - "version": "1.0.1", + "version": "1.1.0", "description": "Delegates dbt and warehouse work to altimate-code, a specialized CLI agent with 100+ purpose-built data tools (SQL analysis, column-level lineage, dbt build/test/run, warehouse profiling, FinOps, connectivity to Snowflake, BigQuery, Redshift, Databricks, Postgres, MySQL, DuckDB).", "author": { "name": "AltimateAI", diff --git a/plugins/altimate-code/CHANGELOG.md b/plugins/altimate-code/CHANGELOG.md index 0fad15e..8de9f62 100644 --- a/plugins/altimate-code/CHANGELOG.md +++ b/plugins/altimate-code/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this plugin will be documented in this file. -## [1.0.1] — 2026-10-15 +## [1.1.0] — 2026-10-19 ### Fixed - The skills and slash commands now resolve the CLI as `altimate-code` and fall back to `altimate`. Standalone installs (curl, Homebrew, PowerShell) expose only `altimate`, so the plugin previously reported "not installed" on machines where the CLI was present. From 032fa431b0013f32d52a57e20b28d8ef715bc70a Mon Sep 17 00:00:00 2001 From: Harish Kumar Date: Mon, 19 Oct 2026 13:16:15 +0530 Subject: [PATCH 4/6] fix: use the resolver as the only CLI install check The separate `command -v` step could be satisfied by an alias or shell function that the resolver deliberately ignores, and cost an extra shell call. The skills and slash commands now rely on the resolver's `altimate-code CLI not found` exit instead. Adds a resolver test where `altimate-code` is a shell function. Co-Authored-By: Claude Opus 5.5 --- plugins/altimate-code/commands/altimate.md | 6 +----- plugins/altimate-code/commands/review.md | 2 +- plugins/altimate-code/skills/altimate-code/SKILL.md | 2 +- plugins/altimate-code/skills/review/SKILL.md | 2 +- tests/resolve-cli.sh | 1 + 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/altimate-code/commands/altimate.md b/plugins/altimate-code/commands/altimate.md index 2c34297..461774a 100644 --- a/plugins/altimate-code/commands/altimate.md +++ b/plugins/altimate-code/commands/altimate.md @@ -7,11 +7,7 @@ The user explicitly invoked `/altimate` to delegate this task to altimate-code. Workflow (follow in order, no skipping): -1. **Verify altimate-code is installed:** - ```bash - command -v altimate-code || command -v altimate - ``` - The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Either one is fine. If neither resolves, stop and tell the user: +1. **Verify altimate-code is installed.** There is no separate check: the run command in step 3 resolves the CLI first, ignoring aliases and shell functions, and exits 127 with `altimate-code CLI not found` before doing anything else. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Either one is fine. If the run exits with `altimate-code CLI not found`, stop and tell the user: > altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install | bash`, then run `altimate` once to configure your provider/warehouse auth, then re-run `/altimate `. 2. **Pick the agent persona** based on the user's task shape. Start cheap and escalate on failure — fast-edit handles most dbt/SQL work at 10–20× lower cost than builder. diff --git a/plugins/altimate-code/commands/review.md b/plugins/altimate-code/commands/review.md index 54bc387..f4d1c51 100644 --- a/plugins/altimate-code/commands/review.md +++ b/plugins/altimate-code/commands/review.md @@ -17,7 +17,7 @@ Run the `altimate-code review` CLI on the current dbt project and present the si ## Workflow -1. **Verify altimate-code is on PATH.** Run `command -v altimate-code || command -v altimate`. If nothing is returned, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+) or 'curl -fsSL https://www.altimate.sh/install | bash', then run 'altimate' once to configure your provider and warehouse auth."` — then STOP. +1. **Verify altimate-code is on PATH.** There is no separate check: the resolver below runs first in the same Bash call as the review. If it exits 127 with `altimate-code CLI not found`, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+) or 'curl -fsSL https://www.altimate.sh/install | bash', then run 'altimate' once to configure your provider and warehouse auth."` — then STOP. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: diff --git a/plugins/altimate-code/skills/altimate-code/SKILL.md b/plugins/altimate-code/skills/altimate-code/SKILL.md index dc0ace7..7871a75 100644 --- a/plugins/altimate-code/skills/altimate-code/SKILL.md +++ b/plugins/altimate-code/skills/altimate-code/SKILL.md @@ -21,7 +21,7 @@ altimate-code is a CLI AI agent with 100+ purpose-built data engineering tools. ## You MUST follow this workflow -1. **Verify altimate-code is on PATH** with `command -v altimate-code || command -v altimate`. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Either name is the same CLI. If neither resolves, jump to "Failure modes" below and stop. +1. **Verify altimate-code is on PATH.** There is no separate check: the invocation below resolves the CLI first, ignoring aliases and shell functions, and exits 127 with `altimate-code CLI not found` before doing anything else. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Either name is the same CLI. If the invocation exits with `altimate-code CLI not found`, jump to "Failure modes" below and stop. 2. **Run altimate-code with the user's task** using the invocation below. Pass the user's request through verbatim — do not paraphrase or split it. 3. **Read the output file** and present it to the user as-is. diff --git a/plugins/altimate-code/skills/review/SKILL.md b/plugins/altimate-code/skills/review/SKILL.md index bd48382..ad00239 100644 --- a/plugins/altimate-code/skills/review/SKILL.md +++ b/plugins/altimate-code/skills/review/SKILL.md @@ -27,7 +27,7 @@ description: >- ## You MUST follow this workflow -1. **Verify altimate-code is on PATH** with `command -v altimate-code || command -v altimate`. If neither resolves, jump to "Failure modes" below and stop. +1. **Verify altimate-code is on PATH.** There is no separate check: the resolver below runs first in the same Bash call as the review. If it exits 127 with `altimate-code CLI not found`, jump to "Failure modes" below and stop. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: diff --git a/tests/resolve-cli.sh b/tests/resolve-cli.sh index 9deedce..542fcd7 100755 --- a/tests/resolve-cli.sh +++ b/tests/resolve-cli.sh @@ -63,6 +63,7 @@ for sh in bash zsh; do expect "$sh" "$STUBS/neither" '' 127 'altimate-code CLI not found (tried altimate-code, altimate)' expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP" 0 'ran altimate' expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP; altimate() { echo function; }" 0 'ran altimate' + expect "$sh" "$STUBS/only-altimate" 'altimate-code() { echo function; }' 0 'ran altimate' expect "$sh" "relative dir" '' 0 'ran altimate' done From 2c0f11f0e52989072e4e5ced4871170d57edf086 Mon Sep 17 00:00:00 2001 From: Harish Kumar Date: Mon, 19 Oct 2026 13:31:48 +0530 Subject: [PATCH 5/6] fix: prefer the canonical altimate binary `altimate` is the CLI's canonical name since v0.7.1 and every install method provides it, so the resolver now tries it first and falls back to `altimate-code` only for npm installs that predate it. With both names on PATH from installs of different versions, the canonical name wins instead of a possibly stale `altimate-code` copy. Co-Authored-By: Claude Opus 5.5 --- plugins/altimate-code/CHANGELOG.md | 2 +- plugins/altimate-code/README.md | 2 +- plugins/altimate-code/commands/altimate.md | 8 ++++---- plugins/altimate-code/commands/review.md | 4 ++-- plugins/altimate-code/skills/altimate-code/SKILL.md | 8 ++++---- plugins/altimate-code/skills/review/SKILL.md | 4 ++-- tests/resolve-cli.sh | 5 +++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/plugins/altimate-code/CHANGELOG.md b/plugins/altimate-code/CHANGELOG.md index 8de9f62..a47658b 100644 --- a/plugins/altimate-code/CHANGELOG.md +++ b/plugins/altimate-code/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this plugin will be documented in this file. ## [1.1.0] — 2026-10-19 ### Fixed -- The skills and slash commands now resolve the CLI as `altimate-code` and fall back to `altimate`. Standalone installs (curl, Homebrew, PowerShell) expose only `altimate`, so the plugin previously reported "not installed" on machines where the CLI was present. +- The skills and slash commands now resolve the CLI as `altimate`, its canonical name since v0.7.1, and fall back to `altimate-code` for older npm installs. Standalone installs (curl, Homebrew, PowerShell) expose only `altimate`, so the plugin previously reported "not installed" on machines where the CLI was present. - Install guidance and recovery messages now name `altimate`, which both install methods provide. ## [1.0.0] — 2026-07-09 diff --git a/plugins/altimate-code/README.md b/plugins/altimate-code/README.md index 48d30a6..b8d3779 100644 --- a/plugins/altimate-code/README.md +++ b/plugins/altimate-code/README.md @@ -21,7 +21,7 @@ curl -fsSL https://www.altimate.sh/install | bash # standalone binary; exposes altimate # launch the TUI, then run /connect to configure your LLM provider ``` -The plugin invokes `altimate-code` when it is on PATH and falls back to `altimate` otherwise, so standalone installs work without an `altimate-code` alias. +The plugin invokes `altimate`, the CLI's canonical name, and falls back to `altimate-code` for npm installs older than v0.7.1, so standalone installs work without an `altimate-code` alias. Or configure a provider via environment variable (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and 20+ others — see the [altimate-code docs](https://docs.altimate.sh)). diff --git a/plugins/altimate-code/commands/altimate.md b/plugins/altimate-code/commands/altimate.md index 461774a..033b4c9 100644 --- a/plugins/altimate-code/commands/altimate.md +++ b/plugins/altimate-code/commands/altimate.md @@ -31,10 +31,10 @@ Workflow (follow in order, no skipping): $ARGUMENTS ALTIMATE_TASK )" - for ALTIMATE_NAME in altimate-code altimate; do + for ALTIMATE_NAME in altimate altimate-code; do ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break done - [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" "$ALTIMATE_BIN" run "$TASK" \ @@ -51,10 +51,10 @@ Workflow (follow in order, no skipping): $ARGUMENTS ALTIMATE_TASK )" - for ALTIMATE_NAME in altimate-code altimate; do + for ALTIMATE_NAME in altimate altimate-code; do ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break done - [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" "$ALTIMATE_BIN" run "$TASK" \ diff --git a/plugins/altimate-code/commands/review.md b/plugins/altimate-code/commands/review.md index f4d1c51..bbb8691 100644 --- a/plugins/altimate-code/commands/review.md +++ b/plugins/altimate-code/commands/review.md @@ -22,10 +22,10 @@ Run the `altimate-code review` CLI on the current dbt project and present the si The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: ```bash - for ALTIMATE_NAME in altimate-code altimate; do + for ALTIMATE_NAME in altimate altimate-code; do ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break done - [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } "$ALTIMATE_BIN" review # plus any scope/flags from below ``` diff --git a/plugins/altimate-code/skills/altimate-code/SKILL.md b/plugins/altimate-code/skills/altimate-code/SKILL.md index 7871a75..37d8088 100644 --- a/plugins/altimate-code/skills/altimate-code/SKILL.md +++ b/plugins/altimate-code/skills/altimate-code/SKILL.md @@ -55,10 +55,10 @@ TASK="$(cat <<'ALTIMATE_TASK' ALTIMATE_TASK )" -for ALTIMATE_NAME in altimate-code altimate; do +for ALTIMATE_NAME in altimate altimate-code; do ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break done -[ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } +[ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" "$ALTIMATE_BIN" run "$TASK" \ @@ -90,10 +90,10 @@ TASK="$(cat <<'ALTIMATE_TASK' ALTIMATE_TASK )" -for ALTIMATE_NAME in altimate-code altimate; do +for ALTIMATE_NAME in altimate altimate-code; do ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break done -[ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } +[ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 OUTPUT_FILE="$(mktemp -t altimate-result.XXXXXX.md)" "$ALTIMATE_BIN" run "$TASK" \ diff --git a/plugins/altimate-code/skills/review/SKILL.md b/plugins/altimate-code/skills/review/SKILL.md index ad00239..4924795 100644 --- a/plugins/altimate-code/skills/review/SKILL.md +++ b/plugins/altimate-code/skills/review/SKILL.md @@ -32,10 +32,10 @@ description: >- The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: ```bash - for ALTIMATE_NAME in altimate-code altimate; do + for ALTIMATE_NAME in altimate altimate-code; do ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break done - [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate-code, altimate)" >&2; exit 127; } + [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } "$ALTIMATE_BIN" review # plus any scope/flags from below ``` diff --git a/tests/resolve-cli.sh b/tests/resolve-cli.sh index 542fcd7..70a9411 100755 --- a/tests/resolve-cli.sh +++ b/tests/resolve-cli.sh @@ -59,11 +59,12 @@ for sh in bash zsh; do command -v "$sh" >/dev/null || { echo "skip: $sh not installed"; continue; } expect "$sh" "$STUBS/only-altimate" '' 0 'ran altimate' expect "$sh" "$STUBS/only-altimate-code" '' 0 'ran altimate-code' - expect "$sh" "$STUBS/both" '' 0 'ran altimate-code' - expect "$sh" "$STUBS/neither" '' 127 'altimate-code CLI not found (tried altimate-code, altimate)' + expect "$sh" "$STUBS/both" '' 0 'ran altimate' + expect "$sh" "$STUBS/neither" '' 127 'altimate-code CLI not found (tried altimate, altimate-code)' expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP" 0 'ran altimate' expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP; altimate() { echo function; }" 0 'ran altimate' expect "$sh" "$STUBS/only-altimate" 'altimate-code() { echo function; }' 0 'ran altimate' + expect "$sh" "$STUBS/only-altimate-code" 'shopt -s expand_aliases 2>/dev/null; alias altimate=altimate-code' 0 'ran altimate-code' expect "$sh" "relative dir" '' 0 'ran altimate' done From a295d4c48c84177e5b8a3ead6f8683064536cd68 Mon Sep 17 00:00:00 2001 From: Harish Kumar Date: Mon, 19 Oct 2026 13:50:15 +0530 Subject: [PATCH 6/6] fix: check the CLI before gh pr checkout and require an executable The review flow ran `gh pr checkout` before resolving the CLI, so a machine without it had its branch switched before "not found" was reported. The PR-scope command now runs after the resolver in the same Bash call. bash's `command -v` returns a non-executable file when no executable match exists, so a broken `altimate` on PATH beat a working `altimate-code`. The resolver now only accepts an executable path. Recovery messages name `altimate-code` for npm installs older than v0.7.1, which the resolver still supports. The resolver test checks its temp dir, runs with only the stub dirs on PATH, and covers legacy-only installs with an alias or function, aliases and functions with nothing installed, and a non-executable `altimate`. Co-Authored-By: Claude Opus 5.5 (1M context) --- plugins/altimate-code/README.md | 6 +++--- plugins/altimate-code/commands/altimate.md | 6 ++++-- plugins/altimate-code/commands/review.md | 9 +++++---- .../altimate-code/skills/altimate-code/SKILL.md | 12 +++++++----- plugins/altimate-code/skills/review/SKILL.md | 9 +++++---- tests/resolve-cli.sh | 16 +++++++++++----- 6 files changed, 35 insertions(+), 23 deletions(-) diff --git a/plugins/altimate-code/README.md b/plugins/altimate-code/README.md index b8d3779..2164c42 100644 --- a/plugins/altimate-code/README.md +++ b/plugins/altimate-code/README.md @@ -54,10 +54,10 @@ Full details: **[PRIVACY.md](../../PRIVACY.md)** · Security policy and disclosu | Symptom | Fix | |---|---| | Neither `altimate-code` nor `altimate` on PATH | `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider. | -| `Unauthorized` / `No provider configured` | Run `altimate` to open the TUI and reconfigure your provider via `/connect`, or set the provider API key env var. | -| Task hangs for several minutes | Open `altimate` to check for a pending prompt in the TUI, or re-run specifying a known-good model. | +| `Unauthorized` / `No provider configured` | Run `altimate` (`altimate-code` on npm installs older than v0.7.1) to open the TUI and reconfigure your provider via `/connect`, or set the provider API key env var. | +| Task hangs for several minutes | Open `altimate` (`altimate-code` on npm installs older than v0.7.1) to check for a pending prompt in the TUI, or re-run specifying a known-good model. | | Empty result | The task may be too ambiguous — restate with the target table, expected columns, or time window. | -| `UNKNOWN_USER` / `Database does not exist` mid-run | The CLI connects but your warehouse credentials don't match this project — reconfigure warehouse auth in the `altimate` TUI or `profiles.yml`. | +| `UNKNOWN_USER` / `Database does not exist` mid-run | The CLI connects but your warehouse credentials don't match this project — reconfigure warehouse auth in the `altimate` TUI (`altimate-code` on npm installs older than v0.7.1) or `profiles.yml`. | | Plugin installed but never delegates | Confirm it's enabled: `claude plugin enable altimate-code@altimate-claude-plugin`. | Still stuck? See [Support](#support). diff --git a/plugins/altimate-code/commands/altimate.md b/plugins/altimate-code/commands/altimate.md index 033b4c9..e7024d9 100644 --- a/plugins/altimate-code/commands/altimate.md +++ b/plugins/altimate-code/commands/altimate.md @@ -32,7 +32,8 @@ Workflow (follow in order, no skipping): ALTIMATE_TASK )" for ALTIMATE_NAME in altimate altimate-code; do - ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" + [ -x "$ALTIMATE_BIN" ] && break || ALTIMATE_BIN= done [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 @@ -52,7 +53,8 @@ Workflow (follow in order, no skipping): ALTIMATE_TASK )" for ALTIMATE_NAME in altimate altimate-code; do - ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" + [ -x "$ALTIMATE_BIN" ] && break || ALTIMATE_BIN= done [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 diff --git a/plugins/altimate-code/commands/review.md b/plugins/altimate-code/commands/review.md index bbb8691..4456754 100644 --- a/plugins/altimate-code/commands/review.md +++ b/plugins/altimate-code/commands/review.md @@ -17,13 +17,14 @@ Run the `altimate-code review` CLI on the current dbt project and present the si ## Workflow -1. **Verify altimate-code is on PATH.** There is no separate check: the resolver below runs first in the same Bash call as the review. If it exits 127 with `altimate-code CLI not found`, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+) or 'curl -fsSL https://www.altimate.sh/install | bash', then run 'altimate' once to configure your provider and warehouse auth."` — then STOP. +1. **Verify altimate-code is on PATH.** There is no separate check: the resolver below runs first in the same Bash call as the review, before any `gh pr checkout`. If it exits 127 with `altimate-code CLI not found`, tell the user: `"altimate-code is not installed. Install with 'npm install -g altimate-code' (Node 20+) or 'curl -fsSL https://www.altimate.sh/install | bash', then run 'altimate' once to configure your provider and warehouse auth."` — then STOP. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: ```bash for ALTIMATE_NAME in altimate altimate-code; do - ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" + [ -x "$ALTIMATE_BIN" ] && break || ALTIMATE_BIN= done [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } "$ALTIMATE_BIN" review # plus any scope/flags from below @@ -35,7 +36,7 @@ Run the `altimate-code review` CLI on the current dbt project and present the si - Empty → `"$ALTIMATE_BIN" review` - Commit SHA (matches `[0-9a-f]{7,40}`) → `"$ALTIMATE_BIN" review --base $ARGUMENTS~1 --head $ARGUMENTS` - Branch name (matches local branch via `git rev-parse`) → `"$ALTIMATE_BIN" review --base $ARGUMENTS` - - PR URL or number → first `gh pr checkout `, then `"$ALTIMATE_BIN" review` + - PR URL or number → `gh pr checkout && "$ALTIMATE_BIN" review`, in the same Bash call after the resolver so a missing CLI stops before the checkout 4. **Run the review command as chosen above.** Capture its stdout. @@ -65,7 +66,7 @@ Anything else (`--manifest`, `--cwd`) only if the user explicitly requested it o | Symptom | Message to user | |---|---| | `altimate-code CLI not found` (neither `altimate-code` nor `altimate` on PATH) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth." | -| `Unauthorized: Incorrect auth token` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` to reconfigure, or re-run with `--no-ai`." | +| `Unauthorized: Incorrect auth token` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` (`altimate-code` on npm installs older than v0.7.1) to reconfigure, or re-run with `--no-ai`." | | `fatal: not a git repository` | "This directory isn't a git repo. `altimate-code review` needs git to compute the diff." | | No `dbt_project.yml` | "No dbt project detected at this path. Run from the directory with `dbt_project.yml`." | | Output mentions `DEGRADED — lint-only` | Present verbatim; do NOT silently upgrade a degraded run to a full verdict. | diff --git a/plugins/altimate-code/skills/altimate-code/SKILL.md b/plugins/altimate-code/skills/altimate-code/SKILL.md index 37d8088..d2b91f5 100644 --- a/plugins/altimate-code/skills/altimate-code/SKILL.md +++ b/plugins/altimate-code/skills/altimate-code/SKILL.md @@ -56,7 +56,8 @@ TASK="$(cat <<'ALTIMATE_TASK' ALTIMATE_TASK )" for ALTIMATE_NAME in altimate altimate-code; do - ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" + [ -x "$ALTIMATE_BIN" ] && break || ALTIMATE_BIN= done [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 @@ -91,7 +92,8 @@ TASK="$(cat <<'ALTIMATE_TASK' ALTIMATE_TASK )" for ALTIMATE_NAME in altimate altimate-code; do - ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" + [ -x "$ALTIMATE_BIN" ] && break || ALTIMATE_BIN= done [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } umask 077 @@ -115,10 +117,10 @@ When altimate-code returns an error, **report the error to the user and STOP**. | Symptom | What to tell the user — verbatim | |---|---| | `altimate-code CLI not found` (neither `altimate-code` nor `altimate` on PATH) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure auth. Then re-run your request." | -| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` in your terminal to open the TUI and reconfigure your provider, then re-run your request." | -| Process hangs >5 min | "altimate-code is unresponsive. Try `altimate` to inspect the TUI for an open prompt, or re-run with `--model anthropic/claude-sonnet-4-6` to force a known-good model." | +| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` (`altimate-code` on npm installs older than v0.7.1) in your terminal to open the TUI and reconfigure your provider, then re-run your request." | +| Process hangs >5 min | "altimate-code is unresponsive. Try `altimate` (`altimate-code` on npm installs older than v0.7.1) to inspect the TUI for an open prompt, or re-run with `--model anthropic/claude-sonnet-4-6` to force a known-good model." | | Output file empty | "altimate-code returned without producing output. The task may be too ambiguous — please restate with more detail (target table, expected columns, time window)." | -| Warehouse error mid-run (`UNKNOWN_USER`, `Database does not exist`) | "altimate-code can connect but the warehouse credentials it has are wrong for this project. Configure provider/warehouse auth via the `altimate` TUI." | +| Warehouse error mid-run (`UNKNOWN_USER`, `Database does not exist`) | "altimate-code can connect but the warehouse credentials it has are wrong for this project. Configure provider/warehouse auth via the `altimate` TUI (`altimate-code` on npm installs older than v0.7.1)." | In every row, the instruction to the user is the action — you do not retry the task with native tools. If the user fixes the underlying issue and asks again, you delegate again. diff --git a/plugins/altimate-code/skills/review/SKILL.md b/plugins/altimate-code/skills/review/SKILL.md index 4924795..4818596 100644 --- a/plugins/altimate-code/skills/review/SKILL.md +++ b/plugins/altimate-code/skills/review/SKILL.md @@ -27,13 +27,14 @@ description: >- ## You MUST follow this workflow -1. **Verify altimate-code is on PATH.** There is no separate check: the resolver below runs first in the same Bash call as the review. If it exits 127 with `altimate-code CLI not found`, jump to "Failure modes" below and stop. +1. **Verify altimate-code is on PATH.** There is no separate check: the resolver below runs first in the same Bash call as the review, before any `gh pr checkout`. If it exits 127 with `altimate-code CLI not found`, jump to "Failure modes" below and stop. The CLI ships under two names: the npm package exposes both `altimate-code` and `altimate`, while the standalone curl/Homebrew/PowerShell installers expose only `altimate`. Every review command below runs through `"$ALTIMATE_BIN"`, in the same Bash call as this resolver (shell state does not persist between calls). The lookup ignores aliases and shell functions, so a user alias such as `alias altimate-code=altimate` cannot be captured as the binary path: ```bash for ALTIMATE_NAME in altimate altimate-code; do - ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" && break + ALTIMATE_BIN="$(unalias "$ALTIMATE_NAME" 2>/dev/null; unset -f "$ALTIMATE_NAME" 2>/dev/null; command -v "$ALTIMATE_NAME")" + [ -x "$ALTIMATE_BIN" ] && break || ALTIMATE_BIN= done [ -n "$ALTIMATE_BIN" ] || { echo "altimate-code CLI not found (tried altimate, altimate-code)" >&2; exit 127; } "$ALTIMATE_BIN" review # plus any scope/flags from below @@ -52,7 +53,7 @@ description: >- | User says | Command to run | |---|---| | "review my changes" / "review this branch" / "audit my dbt work" / no scope specified | `"$ALTIMATE_BIN" review` (default: working tree vs merge-base with `origin/main`) | -| "review PR #123" or gives a GitHub PR URL | First `gh pr checkout 123`, then `"$ALTIMATE_BIN" review` | +| "review PR #123" or gives a GitHub PR URL | `gh pr checkout 123 && "$ALTIMATE_BIN" review`, in the same Bash call after the resolver so a missing CLI stops before the checkout | | "review commit `abc123`" | `"$ALTIMATE_BIN" review --base abc123~1 --head abc123` | | "compare staging to prod" / "review the diff between two branches" | `"$ALTIMATE_BIN" review --base prod --head staging` | @@ -79,7 +80,7 @@ description: >- | Symptom | Message to the user | |---|---| | `altimate-code CLI not found` (neither `altimate-code` nor `altimate` on PATH) | "altimate-code is not installed. Install with `npm install -g altimate-code` (Node 20+) or `curl -fsSL https://www.altimate.sh/install \| bash`, then run `altimate` once to configure your provider and warehouse auth. Then re-run the review." | -| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` to reconfigure — or re-run with `--no-ai` to skip the LLM lane entirely and get a deterministic-only review." | +| `Unauthorized: Incorrect auth token` / `No provider configured` | "altimate-code's LLM provider auth is misconfigured. Run `altimate` (`altimate-code` on npm installs older than v0.7.1) to reconfigure — or re-run with `--no-ai` to skip the LLM lane entirely and get a deterministic-only review." | | `fatal: not a git repository` | "This directory isn't a git repo. `altimate-code review` computes the diff via git — run from a dbt project inside a git worktree." | | No `dbt_project.yml` found | "No dbt project detected at this path. The review needs a dbt project to compile models against. Run from the directory containing `dbt_project.yml`." | | Output says `DEGRADED — lint-only` | Present that note verbatim. Do not silently upgrade a degraded run to a full verdict. | diff --git a/tests/resolve-cli.sh b/tests/resolve-cli.sh index 70a9411..deb0a75 100755 --- a/tests/resolve-cli.sh +++ b/tests/resolve-cli.sh @@ -32,21 +32,23 @@ done [ "$(printf '%s' "$ALL_BLOCKS" | grep . | sort -u | grep -c .)" -eq 1 ] || fail "resolver blocks differ between files" RESOLVER="$(printf '%b' "$(printf '%s' "$ALL_BLOCKS" | head -n1)")" -STUBS="$(mktemp -d)" +STUBS="$(mktemp -d)" && [ -d "$STUBS" ] || { echo "FAIL: could not create a temp dir"; exit 1; } trap 'rm -rf "$STUBS"' EXIT for stub in only-altimate/altimate only-altimate-code/altimate-code both/altimate both/altimate-code "relative dir/altimate"; do mkdir -p "$STUBS/$(dirname "$stub")" printf '#!/bin/sh\necho "ran %s"\n' "$(basename "$stub")" > "$STUBS/$stub" chmod +x "$STUBS/$stub" done -mkdir -p "$STUBS/neither" +mkdir -p "$STUBS/neither" "$STUBS/broken-altimate" +printf 'not a program\n' > "$STUBS/broken-altimate/altimate" # expect -# Runs from $STUBS without startup files, so relative PATH entries resolve and user config can't interfere. +# Runs from $STUBS without startup files and with only the stub dirs on PATH, so relative PATH +# entries resolve and neither user config nor system-installed binaries can interfere. expect() { local shell_cmd - case "$1" in zsh) shell_cmd=(zsh -f) ;; *) shell_cmd=(bash --noprofile --norc) ;; esac - out="$(cd "$STUBS" && env -u BASH_ENV -u ENV PATH="$2:/usr/bin:/bin" "${shell_cmd[@]}" -c "$3 + case "$1" in zsh) shell_cmd=("$(command -v zsh)" -f) ;; *) shell_cmd=("$(command -v bash)" --noprofile --norc) ;; esac + out="$(cd "$STUBS" && env -u BASH_ENV -u ENV PATH="$2" "${shell_cmd[@]}" -c "$3 $RESOLVER \"\$ALTIMATE_BIN\"" 2>&1)" status=$? @@ -65,6 +67,10 @@ for sh in bash zsh; do expect "$sh" "$STUBS/only-altimate" "$ALIAS_SETUP; altimate() { echo function; }" 0 'ran altimate' expect "$sh" "$STUBS/only-altimate" 'altimate-code() { echo function; }' 0 'ran altimate' expect "$sh" "$STUBS/only-altimate-code" 'shopt -s expand_aliases 2>/dev/null; alias altimate=altimate-code' 0 'ran altimate-code' + expect "$sh" "$STUBS/only-altimate-code" 'altimate-code() { echo function; }' 0 'ran altimate-code' + expect "$sh" "$STUBS/only-altimate-code" 'shopt -s expand_aliases 2>/dev/null; alias altimate-code="echo alias"' 0 'ran altimate-code' + expect "$sh" "$STUBS/neither" "$ALIAS_SETUP; altimate() { echo function; }" 127 'altimate-code CLI not found (tried altimate, altimate-code)' + expect "$sh" "$STUBS/broken-altimate:$STUBS/only-altimate-code" '' 0 'ran altimate-code' expect "$sh" "relative dir" '' 0 'ran altimate' done