From ce6751d5687e81fcee2fdd3069098ce21d1ad50a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 08:42:36 +0000 Subject: [PATCH 1/5] feat(plugin): add /kbagent:setup one-command first-run setup Collapse the documented five-step onboarding (install CLI -> project add with a hand-pasted Storage API token -> doctor -> two /plugin commands) into one slash command that runs after the plugin is installed. plugins/kbagent/commands/setup.md orchestrates existing verbs only -- `--json version` (respecting `install_channel` on standalone builds), `--json project list` (skip if already connected, never overwrite an alias), `--json auth login --register-projects` (browser PKCE, so no token to paste; relays `session_unsupported_features` from the result rather than hand-listing it) with a `project add` hidden-prompt / KBC_TOKEN fallback for headless hosts, then `--json doctor` interpreted for the user including the claude_plugin check. Every step is conditional on a check, so the command is idempotent. No new CLI surface, no change to `doctor` (its --fix removal in 0.85.0 stands), no token ever printed or passed on a command line. Doc sync for the new surface (none of these are CI-checked): plugin .claude-plugin/CLAUDE.md surfaces list and "For Claude Code users"; skills/kbagent/SKILL.md prose "First-time setup" (auto-generated table untouched); README.md and docs/TUTORIAL.md so the documented flow is install plugin -> /kbagent:setup; install.sh "Next steps"; AGENT_CONTEXT in commands/context.py. Also corrects the already-stale plugin surface inventory in CLAUDE.md and widens the CONTRIBUTING.md sync-map row from commands/keboola.md to commands/*.md with the follow-through list for adding a new slash-command file. --- CLAUDE.md | 5 +- CONTRIBUTING.md | 4 +- README.md | 3 + docs/TUTORIAL.md | 11 ++ install.sh | 4 + plugins/kbagent/.claude-plugin/CLAUDE.md | 19 +++- plugins/kbagent/commands/setup.md | 124 ++++++++++++++++++++++ plugins/kbagent/skills/kbagent/SKILL.md | 14 ++- src/keboola_agent_cli/commands/context.py | 6 ++ 9 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 plugins/kbagent/commands/setup.md diff --git a/CLAUDE.md b/CLAUDE.md index b44207ee..5a998fbf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -253,7 +253,7 @@ Full author checklist: see `CONTRIBUTING.md` > "Releasing a beta (pre-release) v ## Claude Code Plugin (Marketplace) -This repo doubles as a Claude Code plugin marketplace. The plugin lives in `plugins/kbagent/` and exposes four AI surfaces: a CLI (`kbagent`), a skill (`kbagent`), a slash command (`/keboola`), and a specialist subagent (`keboola-expert`). All are namespaced under `kbagent:`. +This repo doubles as a Claude Code plugin marketplace. The plugin lives in `plugins/kbagent/` and exposes: a CLI (`kbagent`), skills (`kbagent` + siblings), three slash commands (`/kbagent:setup`, `/keboola`, `/kbagent:review`), and two specialist subagents (`keboola-expert`, `kbagent-pr-reviewer`). All are namespaced under `kbagent:`. `/kbagent:setup` is the documented one-command first-run path (install CLI -> connect project -> `doctor`); it runs in the main context and spawns no subagent. **Update rules** -- see `CONTRIBUTING.md` > "Documentation changes (mandatory!)", "Plugin synchronization map", and "Releasing a new version" for the binding checklists. Coding convention #17 above is the short version. Do **not** maintain a parallel update list here -- it always drifts. @@ -266,8 +266,11 @@ plugins/kbagent/ CLAUDE.md # Operational guidance for Claude Code main agents agents/ keboola-expert.md # Specialist subagent system prompt (HIGHEST silent-drift risk) + kbagent-pr-reviewer.md # Read-only PR-review subagent system prompt commands/ + setup.md # /kbagent:setup slash command (one-command first-run setup) keboola.md # /keboola slash command + review.md # /kbagent:review slash command skills/kbagent/ SKILL.md # Trigger rules + auto-generated decision table references/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21256511..f1cbb531 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -385,7 +385,7 @@ before the PR is mergeable. - [ ] **`plugins/kbagent/skills/kbagent/references/gotchas.md`** -- if the command's behavior is non-obvious, add an entry tagged with `(since vX.Y.Z)`. The version tag is **non-optional**; gotchas without versions are how AI agents end up recommending behavior that does not exist on older kbagent installs. - [ ] **`plugins/kbagent/skills/kbagent/references/-workflow.md`** -- create a new file if the command introduces a new workflow or topic area (existing examples: `workspace-workflow.md`, `branch-workflow.md`, `sync-workflow.md`, `storage-files-workflow.md`, `storage-types-workflow.md`). Single-command additions go into an existing workflow file. - [ ] **`plugins/kbagent/.claude-plugin/CLAUDE.md`** -- only update when the high-level delegation strategy changes (e.g. new "when NOT to delegate" cases). Most command additions do not touch this. -- [ ] **`plugins/kbagent/commands/keboola.md`** -- only update if the `/keboola` slash-command UX changes. Most command additions do not touch this. +- [ ] **`plugins/kbagent/commands/*.md`** -- only update if a slash-command UX changes (`/keboola`, `/kbagent:setup`, `/kbagent:review`). Most command additions do not touch these. Adding a *new* slash-command file has its own follow-through list -- see the [Plugin synchronization map](#plugin-synchronization-map) row. ### Tests (mandatory!) @@ -462,7 +462,7 @@ release checklist below. | `plugins/kbagent/.claude-plugin/plugin.json` | Every release (auto-synced) | YES (`make version-check`; pre-commit auto-stages) | | `plugins/kbagent/.claude-plugin/CLAUDE.md` | Changing delegation strategy / when-to-delegate rules | NO | | `plugins/kbagent/agents/keboola-expert.md` | New write/destructive command **group** (one matrix row per group, not per command -- file has a hard 60 KB prompt budget); new minimum-version requirement (Rule 6 VERSION GATE); behavior change (gotchas) | NO -- **highest silent-drift risk** | -| `plugins/kbagent/commands/keboola.md` | `/keboola` slash-command UX change (rare) | NO | +| `plugins/kbagent/commands/*.md` (`setup.md`, `keboola.md`, `review.md`) | Slash-command UX change (rare). **Adding a new slash-command file** also needs: the surfaces list + "For Claude Code users" block in `plugins/kbagent/.claude-plugin/CLAUDE.md`, `skills/kbagent/SKILL.md` prose if it changes the documented setup/usage path, and the user-facing flow in `README.md`, `docs/TUTORIAL.md`, `commands/context.py` `AGENT_CONTEXT` and `install.sh`'s "Next steps" | NO -- no CI gate or test reads `commands/*.md` at all | | `plugins/kbagent/skills/kbagent/SKILL.md` -- table | Auto-generated by `make skill-gen` | YES (`make skill-check`; pre-commit auto-stages) | | `plugins/kbagent/skills/kbagent/SKILL.md` -- description / rules / workflow links | New topic area in `description` triggers; new workflow file added to bottom table | NO | | `plugins/kbagent/skills/kbagent/references/commands-reference.md` | Adding/removing/renaming commands; flag changes | NO | diff --git a/README.md b/README.md index 60e144fb..935031db 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,11 @@ This CLI is built AI-first. Every command outputs structured JSON (`--json`), er ``` /plugin marketplace add keboola/cli /plugin install kbagent@keboola-agent-cli +/kbagent:setup ``` +`/kbagent:setup` is the whole rest of the setup in one command: it installs the `kbagent` CLI if you don't have it, connects a Keboola project (browser login, no token to paste; static-token fallback for headless hosts), and verifies the result with `kbagent doctor`. Every step is conditional, so re-running it after a partial setup just fills the gaps. + Then either let the `kbagent` skill auto-trigger from natural prompts, or delegate explicitly with `/keboola ` -- the slash command spawns a `kbagent:keboola-expert` subagent with fresh context, hard rules (fresh fetch, dry-run first, prefer CLI over raw REST, version gate), and a JSON verification payload. See [docs/TUTORIAL.md §6](docs/TUTORIAL.md#6-using-the-agent-and-slash-commands). **Any other agent** -- just tell it to run `kbagent context` and it gets the full command reference. diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index 7c44bec6..fc791c09 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -309,11 +309,21 @@ In Claude Code, run: ``` /plugin marketplace add keboola/cli /plugin install kbagent@keboola-agent-cli +/kbagent:setup ``` Claude Code clones the marketplace and drops the plugin into `~/.claude/plugins/cache/keboola-agent-cli/kbagent//`. +`/kbagent:setup` then does everything else in one command: installs the +`kbagent` CLI if it is missing (handling the installer's PATH caveat), +connects a project via `kbagent auth login --register-projects` (browser +login -- nothing to paste; a `kbagent project add` static-token path +covers headless hosts and the surfaces a browser session does not serve), +and finishes with `kbagent doctor`, interpreting the result for you. Each +step runs only if its check fails, so it is safe to re-run at any point +-- including if you already followed §1-§4 by hand. + ### Verify Outside Claude Code: @@ -337,6 +347,7 @@ you to run `/plugin update kbagent` in Claude Code. | Component | What it does | |---|---| | `kbagent` skill | Loaded into the main agent when it recognises Keboola-related prompts. 10 rules + a decision table mapping goals to commands. | +| `/kbagent:setup` slash command | One-command first-run setup: install the CLI, connect a project, verify with `doctor`. Idempotent. | | `/keboola ` slash command | Explicitly delegates a Keboola task to the specialist subagent (see §6). | | `kbagent:keboola-expert` subagent | Fresh-context specialist with non-negotiable rules, tool matrix, inline gotchas, and a JSON verification payload output contract. | | Plugin-level `CLAUDE.md` | Instructs the main agent *when* to delegate vs. handle inline. | diff --git a/install.sh b/install.sh index 6c392d0a..4a31b7bf 100755 --- a/install.sh +++ b/install.sh @@ -258,6 +258,10 @@ printf ' %s%s%s %s%s%s %s %s\n' "$GREEN" "$CHECK" "$RESET" "$BOLD" "$ver_str" printf ' %sno sudo required%s\n' "$DIM" "$RESET" >&2 info "" printf ' %sNext steps%s\n' "$BOLD" "$RESET" >&2 +printf ' %sIn Claude Code:%s %s/kbagent:setup%s %s# connect + verify in one command%s\n' "$DIM" "$RESET" "$BOLD" "$RESET" "$DIM" "$RESET" >&2 +printf ' %s(needs the plugin: /plugin marketplace add keboola/cli, /plugin install kbagent@keboola-agent-cli)%s\n' "$DIM" "$RESET" >&2 +info "" +printf ' %sOr do it by hand%s\n' "$BOLD" "$RESET" >&2 printf ' %skbagent project add%s --project myproject \\\n' "$BOLD" "$RESET" >&2 printf ' --url https://connection.keboola.com --token YOUR_TOKEN %s# connect a project%s\n' "$DIM" "$RESET" >&2 printf ' %skbagent --help%s %s# see everything you can do%s\n' "$BOLD" "$RESET" "$DIM" "$RESET" >&2 diff --git a/plugins/kbagent/.claude-plugin/CLAUDE.md b/plugins/kbagent/.claude-plugin/CLAUDE.md index 6d47053f..c48eb4ae 100644 --- a/plugins/kbagent/.claude-plugin/CLAUDE.md +++ b/plugins/kbagent/.claude-plugin/CLAUDE.md @@ -1,9 +1,14 @@ # kbagent plugin — operational guidance -This plugin exposes a CLI (`kbagent`), a skill (`kbagent`), two slash -commands (`/keboola`, `/kbagent:review`), and two specialist subagents -(`keboola-expert`, `kbagent-pr-reviewer`). All are namespaced under -`kbagent:`. The two subagents serve disjoint domains: +This plugin exposes a CLI (`kbagent`), a skill (`kbagent`), three slash +commands (`/kbagent:setup`, `/keboola`, `/kbagent:review`), and two +specialist subagents (`keboola-expert`, `kbagent-pr-reviewer`). All are +namespaced under `kbagent:`. + +`/kbagent:setup` is the first-run entry point: it installs the CLI if +missing, connects a project, and verifies with `kbagent doctor` -- every +step conditional, so it is safe to re-run. It runs in the main context and +spawns no subagent. The two subagents serve disjoint domains: | Subagent | Use for | Slash command | Trigger phrases | |---|---|---|---| @@ -124,7 +129,11 @@ When the subagent returns: ## For Claude Code users -- Install the kbagent CLI: `uv tool install git+https://github.com/keboola/cli` +- **Start here: run `/kbagent:setup`.** One command -- it installs the + kbagent CLI if it is missing, connects a Keboola project (browser + login, with a static-token fallback), and verifies the result with + `kbagent doctor`. Idempotent, so re-running it after a partial setup + only fills the gaps. - Initialize a project workspace: `kbagent init --from-global` (writes `.kbagent/config.json` whose first field is a `_warning` steering any LLM that reads the file away from direct REST calls) diff --git a/plugins/kbagent/commands/setup.md b/plugins/kbagent/commands/setup.md new file mode 100644 index 00000000..57f2ddeb --- /dev/null +++ b/plugins/kbagent/commands/setup.md @@ -0,0 +1,124 @@ +--- +description: One-command kbagent setup -- install the CLI if missing, connect a Keboola project via browser login (token fallback), then verify with `kbagent doctor`. Idempotent; safe to re-run. +allowed-tools: Bash +argument-hint: [optional stack URL or project name, e.g. "https://connection.north-europe.azure.keboola.com"] +--- + +# /kbagent:setup -- get from zero to a verified connection + +Run the whole first-time setup in one invocation: CLI present, project +connected, setup verified. Every step is **conditional on a check**, so +re-running this after a partial setup only fills the gaps. + +## Non-negotiable rules + +- **Never print, echo, log, or persist a token.** No token in a command + line -- not `--token `, not `echo`, not a heredoc. The CLI has a + hidden prompt and reads `KBC_TOKEN` from the environment; use those. +- **Use `--json`** for every check you have to parse. Parse the JSON; + do not scrape human-mode Rich output. +- **Do not re-run a step that already passes.** Never re-register or + overwrite an existing project or alias. +- **When a step needs a human, say so and stop guessing.** Browser login + is a human action; announce it, then wait for the outcome. + +## Behavior + +1. **Is the CLI installed?** + ```bash + kbagent --json version 2>&1 + ``` + - **Runs** -> continue to step 2. If `kbagent.install_channel` is + present, this is a standalone/packaged build (Homebrew, Chocolatey, + winget, an unpacked archive, ...). **Respect it** -- do not run the + installer over it; the JSON's `upgrade_command` / `upgrade_hint` is + the only sanctioned way that install gets updated. + - **Not found** -> install it: + ```bash + curl -LsSf https://raw.githubusercontent.com/keboola/cli/main/install.sh | sh + ``` + The installer puts `kbagent` on `PATH` for **its own process only**. + If `kbagent --json version` still fails right after, run + `source $HOME/.local/bin/env` (or tell the user to open a new shell) + and retry once. If it fails a second time, stop and report the + installer output -- do not attempt a third install. + +2. **Is a project already connected?** + ```bash + kbagent --json project list + ``` + If the list is non-empty, say which aliases are already connected and + **skip straight to step 4**. Do not touch existing entries. + +3. **Connect a project (no token pasting).** + ```bash + kbagent --json auth login --register-projects + ``` + Browser login (PKCE loopback, with an automatic device-code fallback), + registering every project the session can reach under a local alias. + Tell the user a browser window / verification code is coming and that + this step is theirs to complete -- then wait for it. + + The result carries `session_unsupported_features`: the command surfaces + a browser session does not serve, whose canonical list is + `SESSION_UNSUPPORTED_FEATURES` in + `src/keboola_agent_cli/services/_auth_registration.py`. Read the key off + the result and relay it verbatim; never hand-list it from memory. + + **Static-token fallback** -- use it when *either* the user needs one of + the surfaces named in `session_unsupported_features`, or there is no + browser at all (headless host, container, CI, SSH without forwarding): + ```bash + kbagent --json project add --project '' --url + ``` + Never pass `--token` on the command line. Two safe routes: + - `KBC_TOKEN` is already exported in the environment -> run it as-is. + - Otherwise hand the command to the **user** to run in their own + terminal: `project add` prompts for the token with hidden input, and + that prompt needs a real TTY, which a tool-run shell does not have. + + Ask the user for the alias and stack URL if `$ARGUMENTS` did not + supply them. + +4. **Verify.** + ```bash + kbagent --json doctor + ``` + Read the check list off the JSON and interpret it for the user rather + than dumping it. Call out: + - config file + permissions and per-project connectivity -- any `fail` + here means step 2/3 did not really land; fix that before declaring + success. + - the **`claude_plugin` check** -- `pass` means the plugin is cached + (a version-drift note asks for `/plugin update kbagent`); `warn` + means Claude Code is present but the plugin is not cached, so print + the two `/plugin` lines doctor gives you; `skip` means Claude Code + was not detected on this host. `doctor` deliberately does not + install the plugin -- `/plugin` is an in-session user command. + +5. **Close it out.** One short line: what is connected, and two or three + things to try next -- e.g. `/keboola list all configs in `, + `kbagent project list`, `kbagent context`. + +## Examples + +``` +/kbagent:setup +/kbagent:setup https://connection.north-europe.azure.keboola.com +/kbagent:setup my-prod-project +``` + +## Why this is a slash command and not a CLI subcommand + +- The last mile of setup lives *inside* Claude Code: `/plugin marketplace + add` and `/plugin install` are in-session commands a background CLI + cannot invoke (`services/doctor_service.py` says so explicitly). A + command that already runs in the session can at least read the plugin + state and speak plainly about it. +- Every step it runs is an existing, tested verb (`version`, `project + list`, `auth login`, `project add`, `doctor`). This file is the + *ordering and the conditionals*, not new behavior -- so it cannot drift + away from the CLI's semantics. +- Idempotence is a checking discipline, and checks are cheap here: the + agent reads `--json`, compares, and skips. A shell script would have to + reimplement that. diff --git a/plugins/kbagent/skills/kbagent/SKILL.md b/plugins/kbagent/skills/kbagent/SKILL.md index a80256c1..30de500a 100644 --- a/plugins/kbagent/skills/kbagent/SKILL.md +++ b/plugins/kbagent/skills/kbagent/SKILL.md @@ -421,10 +421,22 @@ For detailed response parsing rules and common pitfalls, see [gotchas](reference ## First-time setup +**In Claude Code with this plugin installed, run `/kbagent:setup`.** It is +the one-command path: it installs the CLI if missing, connects a project +(browser login via `auth login --register-projects`, static-token fallback), +and verifies with `kbagent doctor`. Every step is conditional, so it is safe +to re-run on a half-finished setup. See +`plugins/kbagent/commands/setup.md`. + +Everything below is the manual equivalent -- for a plain shell, or another +agent, or when you want to drive the steps yourself. + If kbagent is not yet installed: ```bash -uv tool install git+https://github.com/keboola/cli +curl -LsSf https://raw.githubusercontent.com/keboola/cli/main/install.sh | sh +# the installer puts kbagent on PATH for its own process only -- +# 'source $HOME/.local/bin/env' or open a new shell kbagent doctor ``` diff --git a/src/keboola_agent_cli/commands/context.py b/src/keboola_agent_cli/commands/context.py index 0e969da3..45302396 100644 --- a/src/keboola_agent_cli/commands/context.py +++ b/src/keboola_agent_cli/commands/context.py @@ -1913,6 +1913,12 @@ /plugin marketplace add keboola/cli /plugin install kbagent@keboola-agent-cli + /kbagent:setup + +`/kbagent:setup` is the one-command first-run path: it installs this CLI if +it is missing, connects a project (`auth login --register-projects`, with a +`project add` static-token fallback), and verifies with `kbagent doctor`. +Every step is conditional, so it is safe to re-run. The plugin provides a skill with detailed workflow references including: - SQL transformation migration (input mapping removal, Snowflake paths) From 702860ddf17168381a40dafdf9e4a3ce6e5fec4e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 16:41:09 +0000 Subject: [PATCH 2/5] fix(install): defer plugin hint to `kbagent doctor` The next-steps hint hardcoded the Claude Code marketplace and plugin names (`keboola/cli` / `kbagent@keboola-agent-cli`). #627 moves the marketplace listing to keboola/ai-kit and does not touch install.sh, so the hardcoded pair would merge silently and then advertise deprecated names. Point at `kbagent doctor` instead, which already prints the current `/plugin` commands and is updated by #627 -- correct under either merge order. --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 4a31b7bf..74113c5a 100755 --- a/install.sh +++ b/install.sh @@ -259,7 +259,7 @@ printf ' %sno sudo required%s\n' "$DIM" "$RESET" >&2 info "" printf ' %sNext steps%s\n' "$BOLD" "$RESET" >&2 printf ' %sIn Claude Code:%s %s/kbagent:setup%s %s# connect + verify in one command%s\n' "$DIM" "$RESET" "$BOLD" "$RESET" "$DIM" "$RESET" >&2 -printf ' %s(needs the plugin: /plugin marketplace add keboola/cli, /plugin install kbagent@keboola-agent-cli)%s\n' "$DIM" "$RESET" >&2 +printf ' %s(needs the plugin:%s %skbagent doctor%s %sprints the exact /plugin commands)%s\n' "$DIM" "$RESET" "$BOLD" "$RESET" "$DIM" "$RESET" >&2 info "" printf ' %sOr do it by hand%s\n' "$BOLD" "$RESET" >&2 printf ' %skbagent project add%s --project myproject \\\n' "$BOLD" "$RESET" >&2 From b1353e56a3b81819dc24b42eec6b8c649256d6a1 Mon Sep 17 00:00:00 2001 From: jordanrburger Date: Tue, 25 Aug 2026 09:04:03 -0400 Subject: [PATCH 3/5] fix(plugin): setup ladder -- login-password rung, and pass --stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses @soustruh's review on #625. **Review item 1 — try `auth login-password` before a static token.** Step 3 was a two-rung fallback (browser login -> `project add --token`), skipping the middle step the repo has documented since 0.84.0. It is now an explicit three-rung ladder, 3a/3b/3c, with the reviewer's two guards stated in the text: `login-password` does not exist before 0.84.0 (compare `kbagent.version` from step 1, else skip to the static token), and `AUTH_MFA_INVALID` means a WebAuthn/passkey-only account, which drops to the static token rather than retrying or looping back to the browser rung. 3b runs only when KBC_LOGIN_EMAIL + KBC_LOGIN_PASSWORD are already exported (+ KBC_LOGIN_TOTP_SECRET for TOTP MFA); the command reads all three off the environment, so nothing lands on a command line. The "never persist a token" rule is widened to any credential, and made explicit that the command must never *solicit* a password or TOTP seed -- absent env vars close that route, they are not a prompt. **Review item 2 — the two doc surfaces.** No change, per the review: the `keboola-expert.md` static-token line sits inside the version-gate rule and is correct for pre-0.84.0, and `.claude-plugin/CLAUDE.md` describes current versions. Each is right in its own scope. **Separately: step 3 could not have worked as written.** `auth login` without `--stack` resolves the stack from the default project, and step 2 has just established there is no project registered -- so on the fresh-install path this command exists to serve, it failed with CONFIG_ERROR ("login is not stack discovery"). Verified against an empty config dir. Every login invocation now passes `--stack `, taken from $ARGUMENTS or asked for up front; the argument-hint says so. Doc surfaces re-synced (CONTRIBUTING.md "Plugin synchronization map", none CI-checked): README.md, docs/TUTORIAL.md, plugins/kbagent/.claude-plugin/ CLAUDE.md, skills/kbagent/SKILL.md prose, commands/context.py AGENT_CONTEXT. No version bump, no changelog entry, no CLI surface change. Verified: `--stack` and `--register-projects` exist on both login commands; env-var resolution satisfies the required `--email` and reaches the server with no secret on the argv; `auth login --stack` gets past stack resolution on an empty config where the flagless form errors. lint, format-check, typecheck (0 errors, 66 pre-existing warnings), version-check, version-gate-check, command-sync-check, endpoints-check, check-error-codes, check-sentinel-guards, loc-check green. Tests: 6154 passed, 181 skipped, 0 failed. skill-check flags SKILL.md only because the hand edit is uncommitted -- `make skill-gen` regenerates it byte-identical. Co-Authored-By: Claude Opus 5 --- README.md | 2 +- docs/TUTORIAL.md | 6 +- plugins/kbagent/.claude-plugin/CLAUDE.md | 3 +- plugins/kbagent/commands/setup.md | 75 ++++++++++++++++++----- plugins/kbagent/skills/kbagent/SKILL.md | 3 +- src/keboola_agent_cli/commands/context.py | 5 +- 6 files changed, 70 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index dcf35d35..4b8fb40e 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ This CLI is built AI-first. Every command outputs structured JSON (`--json`), er /kbagent:setup ``` -`/kbagent:setup` is the whole rest of the setup in one command: it installs the `kbagent` CLI if you don't have it, connects a Keboola project (browser login, no token to paste; static-token fallback for headless hosts), and verifies the result with `kbagent doctor`. Every step is conditional, so re-running it after a partial setup just fills the gaps. +`/kbagent:setup` is the whole rest of the setup in one command: it installs the `kbagent` CLI if you don't have it, connects a Keboola project (browser login, so there is no token to paste; on a headless host it falls back to an account login from the environment, then to a static token), and verifies the result with `kbagent doctor`. Every step is conditional, so re-running it after a partial setup just fills the gaps. Then either let the `kbagent` skill auto-trigger from natural prompts, or delegate explicitly with `/keboola ` -- the slash command spawns a `kbagent:keboola-expert` subagent with fresh context, hard rules (fresh fetch, dry-run first, prefer CLI over raw REST, version gate), and a JSON verification payload. See [docs/TUTORIAL.md §6](docs/TUTORIAL.md#6-using-the-agent-and-slash-commands). diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index baa6839d..9cc8d686 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -318,8 +318,10 @@ Claude Code clones the marketplace and drops the plugin into `/kbagent:setup` then does everything else in one command: installs the `kbagent` CLI if it is missing (handling the installer's PATH caveat), connects a project via `kbagent auth login --register-projects` (browser -login -- nothing to paste; a `kbagent project add` static-token path -covers headless hosts and the surfaces a browser session does not serve), +login -- nothing to paste; for a headless host, or a surface a browser +session does not serve, it drops to `kbagent auth login-password` when +`KBC_LOGIN_EMAIL`/`KBC_LOGIN_PASSWORD` are already in the environment and +only then to a `kbagent project add` static token), and finishes with `kbagent doctor`, interpreting the result for you. Each step runs only if its check fails, so it is safe to re-run at any point -- including if you already followed §1-§4 by hand. diff --git a/plugins/kbagent/.claude-plugin/CLAUDE.md b/plugins/kbagent/.claude-plugin/CLAUDE.md index e63a42d5..f3ef09aa 100644 --- a/plugins/kbagent/.claude-plugin/CLAUDE.md +++ b/plugins/kbagent/.claude-plugin/CLAUDE.md @@ -131,7 +131,8 @@ When the subagent returns: - **Start here: run `/kbagent:setup`.** One command -- it installs the kbagent CLI if it is missing, connects a Keboola project (browser - login, with a static-token fallback), and verifies the result with + login, falling back to `auth login-password` from the environment and + then a static token, per the order above), and verifies the result with `kbagent doctor`. Idempotent, so re-running it after a partial setup only fills the gaps. - Initialize a project workspace: `kbagent init --from-global` diff --git a/plugins/kbagent/commands/setup.md b/plugins/kbagent/commands/setup.md index 57eb1e97..cc2c9f88 100644 --- a/plugins/kbagent/commands/setup.md +++ b/plugins/kbagent/commands/setup.md @@ -1,7 +1,7 @@ --- -description: One-command kbagent setup -- install the CLI if missing, connect a Keboola project via browser login (token fallback), then verify with `kbagent doctor`. Idempotent; safe to re-run. +description: One-command kbagent setup -- install the CLI if missing, connect a Keboola project (browser login, then an account login from the environment, then a static token), then verify with `kbagent doctor`. Idempotent; safe to re-run. allowed-tools: Bash -argument-hint: [optional stack URL or project name, e.g. "https://connection.north-europe.azure.keboola.com"] +argument-hint: [stack URL and/or a project alias, e.g. "https://connection.north-europe.azure.keboola.com" -- whatever is missing is asked for] --- # /kbagent:setup -- get from zero to a verified connection @@ -12,9 +12,12 @@ re-running this after a partial setup only fills the gaps. ## Non-negotiable rules -- **Never print, echo, log, or persist a token.** No token in a command - line -- not `--token `, not `echo`, not a heredoc. The CLI has a - hidden prompt and reads `KBC_TOKEN` from the environment; use those. +- **Never print, echo, log, or persist a credential.** No secret in a + command line -- not `--token `, not `--password`, not + `--totp-secret`, not `echo`, not a heredoc. The CLI has hidden prompts + and reads `KBC_TOKEN` / `KBC_LOGIN_*` from the environment; use those. + Never *solicit* a password or TOTP seed either -- if those are not + already in the environment, that route is simply closed. - **Use `--json`** for every check you have to parse. Parse the JSON; do not scrape human-mode Rich output. - **Do not re-run a step that already passes.** Never re-register or @@ -50,14 +53,28 @@ re-running this after a partial setup only fills the gaps. If the list is non-empty, say which aliases are already connected and **skip straight to step 4**. Do not touch existing entries. -3. **Connect a project (no token pasting).** +3. **Connect a project.** This step needs the **stack URL**, and it needs it + first: login is not stack discovery, and step 2 just established there is + no registered project to infer one from -- so `auth login` without + `--stack` fails with `CONFIG_ERROR` ("No stack to log into"). Take the URL + from `$ARGUMENTS` when it looks like one; otherwise ask the user for it + before running anything (it is the host they see in the Keboola UI, e.g. + `https://connection.north-europe.azure.keboola.com`). + + Then work down this ladder and **stop at the first rung that lands**. It + is the order this repo has documented since 0.84.0 + (`plugins/kbagent/.claude-plugin/CLAUDE.md`, + `skills/kbagent/references/auth-workflow.md`): browser login -> account + login from the environment -> static token. + + **3a. Browser login -- the default, and nothing to paste.** ```bash - kbagent --json auth login --register-projects + kbagent --json auth login --stack --register-projects ``` - Browser login (PKCE loopback, with an automatic device-code fallback), - registering every project the session can reach under a local alias. - Tell the user a browser window / verification code is coming and that - this step is theirs to complete -- then wait for it. + PKCE loopback with an automatic device-code fallback, registering every + project the session can reach under a local alias. Tell the user a browser + window / verification code is coming and that this step is theirs to + complete -- then wait for it. The result carries `session_unsupported_features`: the command surfaces a browser session does not serve, whose canonical list is @@ -65,9 +82,33 @@ re-running this after a partial setup only fills the gaps. `src/keboola_agent_cli/services/_auth_registration.py`. Read the key off the result and relay it verbatim; never hand-list it from memory. - **Static-token fallback** -- use it when *either* the user needs one of - the surfaces named in `session_unsupported_features`, or there is no - browser at all (headless host, container, CI, SSH without forwarding): + Drop to 3b when *either* the user needs one of the surfaces named in + `session_unsupported_features`, or there is no browser at all (headless + host, container, CI, SSH without port forwarding). + + **3b. Account login from the environment** (kbagent 0.84.0+) -- try this + *before* reaching for a static token, whenever `KBC_LOGIN_EMAIL` and + `KBC_LOGIN_PASSWORD` are both already exported (plus + `KBC_LOGIN_TOTP_SECRET` if the account has TOTP-based MFA): + ```bash + kbagent --json auth login-password --stack --register-projects + ``` + The command reads all three values straight off the environment + (`commands/auth.py`, `envvar=` on `--email` / `--password` / + `--totp-secret`), so no secret enters the conversation and none lands on a + command line. Never pass them as flags. Two guards: + - **Version gate.** `login-password` does not exist before 0.84.0. + Compare `kbagent.version` from step 1; if it is older, skip to 3c. + - **`AUTH_MFA_INVALID`.** The account's MFA is WebAuthn/passkey-only, + which this grant cannot resolve without a browser -- and both routes + into 3b are routes where browser login is unavailable or insufficient. + Go to 3c; do not retry `login-password` and do not loop back to 3a. + + If those variables are absent, skip 3b silently. Never ask the user to + export a password or a TOTP seed to satisfy this step -- a static token is + the smaller blast radius, which is exactly why it is the next rung. + + **3c. Static token -- the last resort.** ```bash kbagent --json project add --project '' --url ``` @@ -77,8 +118,7 @@ re-running this after a partial setup only fills the gaps. terminal: `project add` prompts for the token with hidden input, and that prompt needs a real TTY, which a tool-run shell does not have. - Ask the user for the alias and stack URL if `$ARGUMENTS` did not - supply them. + Ask the user for the alias if `$ARGUMENTS` did not supply one. 4. **Verify.** ```bash @@ -121,7 +161,8 @@ re-running this after a partial setup only fills the gaps. command that already runs in the session can at least read the plugin state and speak plainly about it. - Every step it runs is an existing, tested verb (`version`, `project - list`, `auth login`, `project add`, `doctor`). This file is the + list`, `auth login`, `auth login-password`, `project add`, `doctor`). + This file is the *ordering and the conditionals*, not new behavior -- so it cannot drift away from the CLI's semantics. - Idempotence is a checking discipline, and checks are cheap here: the diff --git a/plugins/kbagent/skills/kbagent/SKILL.md b/plugins/kbagent/skills/kbagent/SKILL.md index ac08d3cd..b95b838c 100644 --- a/plugins/kbagent/skills/kbagent/SKILL.md +++ b/plugins/kbagent/skills/kbagent/SKILL.md @@ -427,7 +427,8 @@ For detailed response parsing rules and common pitfalls, see [gotchas](reference **In Claude Code with this plugin installed, run `/kbagent:setup`.** It is the one-command path: it installs the CLI if missing, connects a project -(browser login via `auth login --register-projects`, static-token fallback), +(browser login via `auth login --register-projects`, then +`auth login-password` from the environment, then a static token), and verifies with `kbagent doctor`. Every step is conditional, so it is safe to re-run on a half-finished setup. See `plugins/kbagent/commands/setup.md`. diff --git a/src/keboola_agent_cli/commands/context.py b/src/keboola_agent_cli/commands/context.py index e2458fcb..e700d2e1 100644 --- a/src/keboola_agent_cli/commands/context.py +++ b/src/keboola_agent_cli/commands/context.py @@ -2055,8 +2055,9 @@ /kbagent:setup `/kbagent:setup` is the one-command first-run path: it installs this CLI if -it is missing, connects a project (`auth login --register-projects`, with a -`project add` static-token fallback), and verifies with `kbagent doctor`. +it is missing, connects a project (`auth login --register-projects`, falling +back to `auth login-password` from the environment and then a `project add` +static token), and verifies with `kbagent doctor`. Every step is conditional, so it is safe to re-run. The plugin provides a skill with detailed workflow references including: From 3a50684bb4238982e5e61e6eb99dfabb30afa1f8 Mon Sep 17 00:00:00 2001 From: jordanrburger Date: Tue, 25 Aug 2026 09:33:17 -0400 Subject: [PATCH 4/5] fix(plugin): setup -- session-insufficient case skips 3b, goes straight to 3c Addresses @soustruh's second review on #625. The routing error is real. The "drop to 3b when *either* ..." sentence funnelled two different reasons for leaving 3a into the same rung. Only one belongs there. `login_password()` returns through the SAME `_finalize_login` as `login()` -- the only difference is `method="password"` -- and `session_unsupported_features` is a `default_factory=default_unsupported_features` field on the shared `LoginResult`, i.e. a copy of the one `SESSION_UNSUPPORTED_FEATURES` constant, independent of method. So for a user who needs a surface on that list, 3b succeeds, the ladder stops at the first rung that "landed", and they are left holding a session with the identical restriction they were trying to escape. Step 3 now routes on *why* 3a was not the answer: - No browser at all (headless, container, CI, SSH without forwarding) -> try 3b, then 3c. This is now the ONLY route into 3b. - Needs a surface named in `session_unsupported_features` -> straight to 3c, skipping 3b, because only a static token serves those surfaces. Two knock-on corrections that would otherwise have contradicted the fix: - The `AUTH_MFA_INVALID` guard justified "do not loop back to 3a" with "both routes into 3b" -- there is one route now, so it cites that instead. - `docs/TUTORIAL.md` explicitly sent "a surface a browser session does not serve" to `login-password`. Rewritten; it was the only downstream surface that asserted the wrong routing (README scopes 3b to headless already, and the plugin CLAUDE.md / SKILL.md / context.py summaries name the order without claiming which reason routes where). Verified in `auth_service.py` rather than from the prose: `login_password` -> `_finalize_login` (line 340), `LoginResult.session_unsupported_features` default factory (line 130), `default_unsupported_features()` returning `list(SESSION_UNSUPPORTED_FEATURES)`. lint, format-check, typecheck, skill-check, version-check, command-sync-check, endpoints-check, check-error-codes, check-sentinel-guards, loc-check all green. Tests: 6154 passed, 181 skipped, 0 failed. No Python changed this round -- two doc files only. Co-Authored-By: Claude Opus 5 --- docs/TUTORIAL.md | 9 +++++---- plugins/kbagent/commands/setup.md | 27 ++++++++++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index 9cc8d686..d3f1dfd9 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -318,10 +318,11 @@ Claude Code clones the marketplace and drops the plugin into `/kbagent:setup` then does everything else in one command: installs the `kbagent` CLI if it is missing (handling the installer's PATH caveat), connects a project via `kbagent auth login --register-projects` (browser -login -- nothing to paste; for a headless host, or a surface a browser -session does not serve, it drops to `kbagent auth login-password` when -`KBC_LOGIN_EMAIL`/`KBC_LOGIN_PASSWORD` are already in the environment and -only then to a `kbagent project add` static token), +login -- nothing to paste; on a headless host it drops to `kbagent auth +login-password` when `KBC_LOGIN_EMAIL`/`KBC_LOGIN_PASSWORD` are already in +the environment, and only then to a `kbagent project add` static token -- +which is also the direct answer for a surface no browser session can serve, +since a password login yields the same restricted session), and finishes with `kbagent doctor`, interpreting the result for you. Each step runs only if its check fails, so it is safe to re-run at any point -- including if you already followed §1-§4 by hand. diff --git a/plugins/kbagent/commands/setup.md b/plugins/kbagent/commands/setup.md index cc2c9f88..bfa20bc5 100644 --- a/plugins/kbagent/commands/setup.md +++ b/plugins/kbagent/commands/setup.md @@ -82,12 +82,21 @@ re-running this after a partial setup only fills the gaps. `src/keboola_agent_cli/services/_auth_registration.py`. Read the key off the result and relay it verbatim; never hand-list it from memory. - Drop to 3b when *either* the user needs one of the surfaces named in - `session_unsupported_features`, or there is no browser at all (headless - host, container, CI, SSH without port forwarding). - - **3b. Account login from the environment** (kbagent 0.84.0+) -- try this - *before* reaching for a static token, whenever `KBC_LOGIN_EMAIL` and + **If 3a is not the answer, route on *why*** -- the two reasons are not + interchangeable, and treating them as one strands the user: + - **No browser at all** (headless host, container, CI, SSH without port + forwarding) -> try **3b**, then 3c. + - **The user needs one of the surfaces named in + `session_unsupported_features`** -> go **straight to 3c, skipping 3b**. + `login-password` mints the *same kind of session* as 3a -- both return + through `_finalize_login`, so both carry the identical + `SESSION_UNSUPPORTED_FEATURES` list -- so 3b would report success and + stop the ladder while leaving the user exactly as unable to do the + thing they came for. Only a static token serves those surfaces. + + **3b. Account login from the environment** (kbagent 0.84.0+) -- the + no-browser rung, and the only route into it. Try this *before* reaching + for a static token, whenever `KBC_LOGIN_EMAIL` and `KBC_LOGIN_PASSWORD` are both already exported (plus `KBC_LOGIN_TOTP_SECRET` if the account has TOTP-based MFA): ```bash @@ -100,9 +109,9 @@ re-running this after a partial setup only fills the gaps. - **Version gate.** `login-password` does not exist before 0.84.0. Compare `kbagent.version` from step 1; if it is older, skip to 3c. - **`AUTH_MFA_INVALID`.** The account's MFA is WebAuthn/passkey-only, - which this grant cannot resolve without a browser -- and both routes - into 3b are routes where browser login is unavailable or insufficient. - Go to 3c; do not retry `login-password` and do not loop back to 3a. + which this grant cannot resolve without a browser -- and the only way + to reach 3b is that no browser is available. Go to 3c; do not retry + `login-password`, and do not loop back to 3a. If those variables are absent, skip 3b silently. Never ask the user to export a password or a TOTP seed to satisfy this step -- a static token is From f01ca672c0c7d223ce5a8486df72cb1f596ab099 Mon Sep 17 00:00:00 2001 From: jordanrburger Date: Tue, 25 Aug 2026 09:44:50 -0400 Subject: [PATCH 5/5] fix(plugin): setup -- hand browser login to the user, add a Windows path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses @padak's second review pass on #625 (runtime behaviour of the instructions, an axis no CI gate covers -- nothing reads commands/*.md). **3a no longer tells the agent to run `auth login` itself.** Two independent reasons, both verified in source: - `commands/auth.py` docstring: "Requires a human at a browser -- an AI agent must not attempt this headlessly." `.claude-plugin/CLAUDE.md:97-99` is blunter still: hand the exact command back to the user and wait. 3a was handing the agent the command to execute. - It cannot finish inside a tool-run shell anyway. PKCE blocks on `AUTH_CALLBACK_TIMEOUT = 115.0` (constants.py:860) and the device fallback polls until the server's `expires_in` (auth/device.py:75). Against a ~120 s Bash timeout the call is killed mid-flow, and a kill is indistinguishable from a failure -- so the agent retries and produces the `orphaned_session_id` case commands/auth.py:178-182 warns about. 3a now hands over the command and waits, mirroring what 3c already does for `project add`'s hidden prompt, and the agent confirms afterwards with `auth status`. A standing rule was added: if a login call you did run gets interrupted, check `auth status` before re-running anything. **stderr.** The snippet drops `--json` deliberately -- a human wants the panel, and `commands/auth.py:304` routes it to `err_console` in json mode, so the device URL and code never appear in the JSON an agent would parse. Made a standing rule too, with `2>&1` for anyone who runs a login anyway. Consequence worth stating: `auth status` does NOT carry `session_unsupported_features` (only `login` / `register-projects` do -- `_auth_registration.py:119`, and context.py:189 says so explicitly). So 3a now names `auth register-projects --all` as the way to read that list programmatically, which is a no-op (`exists`) on anything already registered. **Windows.** Step 1's only route was `curl … install.sh | sh`, and its retry advice `source $HOME/.local/bin/env` is POSIX-only -- so first-run setup, the exact audience, died at step 1 on a Windows box without Git Bash. Step 1 now branches and points at README's Install section for the winget + `uv tool install` PowerShell block, including the "open a new shell after update-shell" caveat, and quotes rather than paraphrases it. Nits, all three: - Root `CLAUDE.md` prose said "three skills" while the structure tree directly below listed only `skills/kbagent/`. Tree now lists all three. - `.claude-plugin/CLAUDE.md:3` still said "a skill (`kbagent`)", singular. - `SKILL.md` pointed readers at the repo path `plugins/kbagent/commands/setup.md`, which does not exist when the skill is loaded from `~/.claude/plugins/cache/…`. Replaced with the command itself. Not changed, per both reviewers agreeing it is out of scope here: the `keboola-expert.md:77-78` version-gate wording (NB-1) and CONTRIBUTING's sync-map row split (NIT-1) are follow-ups. lint, format-check, typecheck, version-check, command-sync-check, endpoints-check, check-error-codes, check-sentinel-guards, loc-check green. Tests: 6154 passed, 181 skipped, 0 failed. Docs only -- no Python changed. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 15 +++-- plugins/kbagent/.claude-plugin/CLAUDE.md | 3 +- plugins/kbagent/commands/setup.md | 78 ++++++++++++++++++------ plugins/kbagent/skills/kbagent/SKILL.md | 4 +- 4 files changed, 74 insertions(+), 26 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 27e79dfd..b7359bc6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -326,12 +326,15 @@ plugins/kbagent/ setup.md # /kbagent:setup slash command (one-command first-run setup) keboola.md # /keboola slash command review.md # /kbagent:review slash command - skills/kbagent/ - SKILL.md # Trigger rules + auto-generated decision table - references/ - commands-reference.md # Per-command notes (hand-maintained) - gotchas.md # Response parsing + (since vX.Y.Z) behavior log - -workflow.md # One file per workflow (workspace, branch, sync, ...) + skills/ + kbagent/ + SKILL.md # Trigger rules + auto-generated decision table + references/ + commands-reference.md # Per-command notes (hand-maintained) + gotchas.md # Response parsing + (since vX.Y.Z) behavior log + -workflow.md # One file per workflow (workspace, branch, sync, ...) + kbagent-cicd-migration/ # CI/CD migration skill + kbagent-promotion-pipeline/ # Promotion-pipeline skill ``` `SKILL.md` instructs Claude to run `kbagent context` as its first step, which dynamically loads the full CLI documentation. That keeps command *signatures* in sync automatically -- but it does **not** save the agent's tool-selection matrix, the gotchas log, or the version-gate examples in `keboola-expert.md`. Those are static and must be updated by hand whenever the CLI changes. diff --git a/plugins/kbagent/.claude-plugin/CLAUDE.md b/plugins/kbagent/.claude-plugin/CLAUDE.md index f3ef09aa..10d6c89a 100644 --- a/plugins/kbagent/.claude-plugin/CLAUDE.md +++ b/plugins/kbagent/.claude-plugin/CLAUDE.md @@ -1,6 +1,7 @@ # kbagent plugin — operational guidance -This plugin exposes a CLI (`kbagent`), a skill (`kbagent`), three slash +This plugin exposes a CLI (`kbagent`), three skills (`kbagent`, +`kbagent-cicd-migration`, `kbagent-promotion-pipeline`), three slash commands (`/kbagent:setup`, `/keboola`, `/kbagent:review`), and two specialist subagents (`keboola-expert`, `kbagent-pr-reviewer`). All are namespaced under `kbagent:`. diff --git a/plugins/kbagent/commands/setup.md b/plugins/kbagent/commands/setup.md index bfa20bc5..3603b0f0 100644 --- a/plugins/kbagent/commands/setup.md +++ b/plugins/kbagent/commands/setup.md @@ -19,11 +19,18 @@ re-running this after a partial setup only fills the gaps. Never *solicit* a password or TOTP seed either -- if those are not already in the environment, that route is simply closed. - **Use `--json`** for every check you have to parse. Parse the JSON; - do not scrape human-mode Rich output. + do not scrape human-mode Rich output. One exception to know about: in + `--json` mode the auth commands print their human panel -- including a + device-login URL and code -- to **stderr**, and it is not in the JSON. If + you ever run one of those yourself, capture `2>&1`. - **Do not re-run a step that already passes.** Never re-register or overwrite an existing project or alias. - **When a step needs a human, say so and stop guessing.** Browser login - is a human action; announce it, then wait for the outcome. + (3a) and the hidden token prompt (3c) are human actions you hand over + rather than attempt: announce the command, then wait for the outcome. If + any login call you did run gets interrupted, check `kbagent --json auth + status` before re-running anything -- a blind retry is what orphans a + session. ## Behavior @@ -36,15 +43,32 @@ re-running this after a partial setup only fills the gaps. winget, an unpacked archive, ...). **Respect it** -- do not run the installer over it; the JSON's `upgrade_command` / `upgrade_hint` is the only sanctioned way that install gets updated. - - **Not found** -> install it: + - **Not found** -> install it, but **check the platform first**: the + one-liner and its PATH fix-up are both POSIX-only. + + *macOS / Linux / WSL / Git Bash:* ```bash curl -LsSf https://raw.githubusercontent.com/keboola/cli/main/install.sh | sh ``` The installer puts `kbagent` on `PATH` for **its own process only**. If `kbagent --json version` still fails right after, run `source $HOME/.local/bin/env` (or tell the user to open a new shell) - and retry once. If it fails a second time, stop and report the - installer output -- do not attempt a third install. + and retry once. + + *Windows with no POSIX shell:* there is no `install.sh` route here and + `$HOME/.local/bin/env` does not exist. Quote the user the PowerShell + block from README's Install section + () -- `winget install --id + astral-sh.uv -e`, then `uv tool install` of the release wheel, then + `uv tool update-shell` -- and tell them `update-shell` edits the + *persisted* PATH, so they must open a **new** shell before `kbagent` + resolves. If Git for Windows is installed, README's documented + alternative is to run the POSIX one-liner through its bash instead. + Quote README rather than paraphrasing it; that block is versioned and + this file is not. + + Either way, if it fails a second time, stop and report the installer + output -- do not attempt a third install. 2. **Is a project already connected?** ```bash @@ -67,20 +91,40 @@ re-running this after a partial setup only fills the gaps. `skills/kbagent/references/auth-workflow.md`): browser login -> account login from the environment -> static token. - **3a. Browser login -- the default, and nothing to paste.** + **3a. Browser login -- the default, and nothing to paste. Hand this one + to the user; do not run it yourself.** + ```bash + kbagent auth login --stack --register-projects + ``` + This is the single step in this file that is **not** yours to execute. + `auth login`'s own docstring says an AI agent must not attempt it + headlessly, and the mechanics agree: PKCE waits `AUTH_CALLBACK_TIMEOUT` + (115 s) on the loopback callback, and the device-code fallback polls until + the server's `expires_in` -- minutes. A tool-run shell on a ~120 s + timeout gets **killed mid-flow**, and the kill tells you nothing: the + login may well have landed a second later. Re-running it blind is exactly + how you produce the `orphaned_session_id` warning, leaving a session + `kbagent auth logout` then has to chase. + + So print the command, say that it opens a browser (or prints a device + code) and that finishing it is theirs, and wait to be told it is done. + Note it is deliberately **without `--json`**: a human reading their own + terminal wants the panel, and in `--json` mode the verification URL and + code are written to **stderr**, not into the JSON payload. + + Then confirm it landed -- this part *is* yours: ```bash - kbagent --json auth login --stack --register-projects + kbagent --json auth status ``` - PKCE loopback with an automatic device-code fallback, registering every - project the session can reach under a local alias. Tell the user a browser - window / verification code is coming and that this step is theirs to - complete -- then wait for it. - - The result carries `session_unsupported_features`: the command surfaces - a browser session does not serve, whose canonical list is - `SESSION_UNSUPPORTED_FEATURES` in - `src/keboola_agent_cli/services/_auth_registration.py`. Read the key off - the result and relay it verbatim; never hand-list it from memory. + + `auth status` deliberately does **not** carry + `session_unsupported_features` (the surfaces a browser session cannot + serve). The login command prints them in the user's own terminal; to read + the list yourself, `kbagent --json auth register-projects --all` ships it + and is a no-op on anything already registered (status `exists`). Either + way relay it verbatim and never hand-list it from memory -- the canonical + copy is `SESSION_UNSUPPORTED_FEATURES` in + `src/keboola_agent_cli/services/_auth_registration.py`. **If 3a is not the answer, route on *why*** -- the two reasons are not interchangeable, and treating them as one strands the user: diff --git a/plugins/kbagent/skills/kbagent/SKILL.md b/plugins/kbagent/skills/kbagent/SKILL.md index b95b838c..74063c62 100644 --- a/plugins/kbagent/skills/kbagent/SKILL.md +++ b/plugins/kbagent/skills/kbagent/SKILL.md @@ -430,8 +430,8 @@ the one-command path: it installs the CLI if missing, connects a project (browser login via `auth login --register-projects`, then `auth login-password` from the environment, then a static token), and verifies with `kbagent doctor`. Every step is conditional, so it is safe -to re-run on a half-finished setup. See -`plugins/kbagent/commands/setup.md`. +to re-run on a half-finished setup. Run `/kbagent:setup` to see the steps it +takes -- it announces each one. Everything below is the manual equivalent -- for a plain shell, or another agent, or when you want to drive the steps yourself.