Environment
- OS: WSL Ubuntu (Windows 11)
- kbagent version: 0.46.1 → 0.47.1
Root cause
The startup auto-update hook uses a hardcoded 120s timeout for the uv tool install --upgrade git+... subprocess (auto_update.py, _perform_update). On WSL Ubuntu with a cold uv package cache, preparing all 46 packages takes ~2m 27s. The subprocess is killed at 120s → TimeoutExpired → returns False → "Auto-update failed" is printed. On the next invocation with a warm cache, the update succeeds instantly — confirming the problem is purely the timeout, not a genuine install failure.
Bug 1 — False failure on cold cache
Reproduction:
# Seed a cold cache at v0.46.1
uv tool install git+https://github.com/keboola/cli@v0.46.1 --reinstall
kbagent doctor
# → "Updating kbagent v0.46.1 -> v0.47.1..."
# → "Auto-update failed; continuing with current version."
# Run again (warm cache) — now it succeeds
kbagent doctor
# → "Updating kbagent v0.46.1 -> v0.47.1..."
# → "Updated to v0.47.1. Re-launching..."
Key evidence from the cold-cache uv reinstall:
Prepared 46 packages in 2m 27s ← exceeds hardcoded 120s
Bug 2 — kbagent update reports "already up to date" when it isn't
During the same session, after auto-update failed, running kbagent update returned:
kbagent v0.46.1 (already up to date)
…while kbagent --version confirmed it was still on v0.46.1 and v0.47.1 was available. The explicit update command silently reported wrong state instead of retrying.
Bug 3 — kbagent --json update startup hook and subcommand disagree
When running kbagent --json update, the startup hook fires (because argv[1] is --json, not update) and prints "Auto-update failed". But the explicit update subcommand runs afterward and returns JSON with "updated": true:
{
"kbagent": {
"updated": true,
"current_version": "0.46.1",
"latest_version": "0.47.1",
"message": "Updated kbagent from v0.46.1 to v0.47.1. Restart your shell to use the new version."
}
}
Same process, same invocation: human output says failure, machine output says success. Any script parsing the JSON exit would believe the update succeeded; any human reading the terminal would believe it failed.
This also exposes the argv[1] check issue: kbagent --json update triggers the startup hook, but kbagent update does not.
Suggested fixes
Short-term: Raise the timeout in _perform_update from 120s to at least 300s, or extract it as a named constant UPDATE_TIMEOUT_SECONDS.
Medium-term: Run the install in a background process and print "Update downloading in background — restart your shell when done." CLI is never blocked regardless of network/cache state.
For Bug 2 & 3: The "already up to date" check and the argv[1] check for skipping the startup hook both need reviewing — they interact badly when the previous auto-update silently failed.
Full terminal sessions
Session 1 — cold cache, false failures, JSON discrepancy
vojta@NB-5BC34F3:~$ kbagent doctor
Updating kbagent v0.46.1 -> v0.47.1...
Auto-update failed; continuing with current version.
Updating keboola-mcp-server v1.61.3 -> v1.63.1 (via uv_tool)...
Updated keboola-mcp-server to v1.63.1.
╭─────────────────────────────────────────────────── kbagent doctor ───────────────────────────────────────────────────╮
│ PASS Config source: Using global config at /home/vojta/.config/keboola-agent-cli/config.json │
│ PASS Config file: Config file exists at /home/vojta/.config/keboola-agent-cli/config.json with correct │
│ permissions. │
│ PASS Config parseable: Config file is valid JSON with 14 project(s). │
│ PASS Project 'kosik-core': Connected to https://connection.eu-central-1.keboola.com (project: Kosik CORE, id: │
│ 250) in 99ms │ │
│ PASS CLI version: kbagent v0.46.1 │
│ PASS MCP server: MCP server available via: keboola_mcp_server (transport=stdio) │
│ WARN Conversation ID: KBAGENT_CONVERSATION_ID not set. API requests will not include X-Conversation-ID header. │
│ PASS Claude Code plugin: kbagent plugin v0.46.1 installed at │
│ /home/vojta/.claude/plugins/cache/keboola-agent-cli/kbagent/0.46.1 │
│ │
│ Summary: 21 checks, 20 passed, 1 warnings │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
vojta@NB-5BC34F3:~$ kbagent doctor
Updating kbagent v0.46.1 -> v0.47.1...
Auto-update failed; continuing with current version.
╭─────────────────────────────────────────────────── kbagent doctor ───────────────────────────────────────────────────╮
│ PASS Config source: Using global config at /home/vojta/.config/keboola-agent-cli/config.json │
│ PASS Config file: Config file exists at /home/vojta/.config/keboola-agent-cli/config.json with correct │
│ permissions. │
│ PASS Config parseable: Config file is valid JSON with 14 project(s). │
│ PASS Project 'kosik-core': Connected to https://connection.eu-central-1.keboola.com (project: Kosik CORE, id: │
│ 250) in 123ms │ │
│ PASS CLI version: kbagent v0.46.1 │
│ PASS MCP server: MCP server available via: keboola_mcp_server (transport=stdio) │
│ WARN Conversation ID: KBAGENT_CONVERSATION_ID not set. API requests will not include X-Conversation-ID header. │
│ PASS Claude Code plugin: kbagent plugin v0.46.1 installed at │
│ /home/vojta/.claude/plugins/cache/keboola-agent-cli/kbagent/0.46.1 │
│ │
│ Summary: 21 checks, 20 passed, 1 warnings │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
vojta@NB-5BC34F3:~$ kbagent update
kbagent v0.46.1 (already up to date) | keboola-mcp-server v1.63.1 (already up to date)
vojta@NB-5BC34F3:~$ kbagent --version
kbagent v0.46.1
vojta@NB-5BC34F3:~$ kbagent --json update
Updating kbagent v0.46.1 -> v0.47.1...
Auto-update failed; continuing with current version.
{
"status": "ok",
"data": {
"kbagent": {
"updated": true,
"current_version": "0.46.1",
"latest_version": "0.47.1",
"message": "Updated kbagent from v0.46.1 to v0.47.1. Restart your shell to use the new version.",
"output": ""
},
"mcp": {
"updated": false,
"current_version": "1.63.1",
"latest_version": "1.63.1",
"install_method": "uv_tool",
"message": "keboola-mcp-server v1.63.1 is already up to date."
},
"updated": true,
"message": "kbagent v0.46.1 -> v0.47.1 | keboola-mcp-server v1.63.1 (already up to date)"
}
}
Session 2 — reinstall to cold cache, warm-cache success proof
vojta@NB-5BC34F3:~$ kbagent --version
kbagent v0.47.1
vojta@NB-5BC34F3:~$ kbagent doctor
╭─────────────────────────────────────────────── kbagent doctor ───────────────────────────────────────────────╮
│ PASS Config source: Using global config at /home/vojta/.config/keboola-agent-cli/config.json │
│ PASS Config file: Config file exists at /home/vojta/.config/keboola-agent-cli/config.json with correct │
│ permissions. │
│ PASS Config parseable: Config file is valid JSON with 14 project(s). │
│ PASS Project 'kosik-core': Connected to https://connection.eu-central-1.keboola.com (project: Kosik CORE, │
│ id: 250) in 110ms │ │
│ PASS CLI version: kbagent v0.47.1 │
│ PASS MCP server: MCP server available via: keboola_mcp_server (transport=stdio) │
│ WARN Conversation ID: KBAGENT_CONVERSATION_ID not set. API requests will not include X-Conversation-ID │
│ header. │
│ PASS Claude Code plugin: kbagent plugin v0.46.1 installed at │
│ /home/vojta/.claude/plugins/cache/keboola-agent-cli/kbagent/0.46.1 (CLI is v0.47.1 -- run `/plugin update │
│ kbagent` in Claude Code to sync) │
│ │
│ Summary: 21 checks, 20 passed, 1 warnings │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
vojta@NB-5BC34F3:~$ uv tool install git+https://github.com/keboola/cli@v0.46.1 --reinstall
Resolved 46 packages in 453ms
Built keboola-agent-cli @ git+https://github.com/keboola/cli@a16fe57d12d373627621b7d49506c0b22e231669
Prepared 46 packages in 2m 27s
Uninstalled 46 packages in 196ms
Installed 46 packages in 75ms
~ annotated-doc==0.0.4
~ annotated-types==0.7.0
~ anyio==4.13.0
~ attrs==26.1.0
~ certifi==2026.5.20
~ cffi==2.0.0
~ click==8.4.1
~ croniter==6.2.2
~ cryptography==48.0.0
~ h11==0.16.0
~ httpcore==1.0.9
~ httpx==0.28.1
~ httpx-sse==0.4.3
~ idna==3.16
~ jsonschema==4.26.0
~ jsonschema-specifications==2025.9.1
~ kai-client==0.12.0
- keboola-agent-cli==0.47.1 (from git+https://github.com/keboola/cli@2f80aaa7c4f0827fcae48e8bd472925e99e54b2c)
+ keboola-agent-cli==0.46.1 (from git+https://github.com/keboola/cli@a16fe57d12d373627621b7d49506c0b22e231669)
~ markdown-it-py==4.2.0
~ mcp==1.27.1
~ mdurl==0.1.2
~ packaging==26.2
~ platformdirs==4.9.6
~ prompt-toolkit==3.0.52
~ pycparser==3.0
~ pydantic==2.13.4
~ pydantic-core==2.46.4
~ pydantic-settings==2.14.1
~ pygments==2.20.0
~ pyjwt==2.13.0
~ python-dateutil==2.9.0.post0
~ python-dotenv==1.2.2
~ python-multipart==0.0.29
~ pyyaml==6.0.3
~ referencing==0.37.0
~ rich==15.0.0
~ rpds-py==0.30.0
~ shellingham==1.5.4
~ six==1.17.0
~ sse-starlette==3.4.4
~ starlette==1.1.0
~ typer==0.26.2
~ typing-extensions==4.15.0
~ typing-inspection==0.4.2
~ uvicorn==0.48.0
~ wcwidth==0.7.0
warning: The package `typer==0.26.2` does not have an extra named `all`
Installed 1 executable: kbagent
vojta@NB-5BC34F3:~$ kbagent doctor
Updating kbagent v0.46.1 -> v0.47.1...
Updated to v0.47.1. Re-launching...
What's new in v0.47.1:
- Fix (`storage create-table --if-not-exists`, keboola/cli#349): the `action: "skipped"` envelope now reports the EXISTING table's actual schema instead of re-echoing the caller's request. Pre-0.47.1, `columns` / `primary_key` / `name` on a skip mirrored the args the caller passed in, so a caller probing the skipped envelope to discover the real shape of a pre-existing table got the wrong values whenever the existing table differed from the request. The `get_table_detail(target_id)` lookup that already runs to confirm the table exists is now also the source of the returned schema. The caller's requested values are preserved under two new fields, `requested_columns` and `requested_primary_key`, and a new `schema_drift: bool` flags when the existing table diverges from the request (set comparison on columns and primary key). Human-mode output prints the actual schema on a skip and emits a `Warning:` line when `schema_drift` is true. `action: "created"` envelope is unchanged. No new flag, no signature change. Tests: `tests/test_storage_write.py` (skipped returns actual schema, drift flag set on divergence, no drift on match, human-mode warning render); `tests/test_e2e.py::TestE2E_0_47_0_NewSurfaces` extended to assert the skipped envelope reports actual columns + `requested_*` mirror.
╭─────────────────────────────────────────────── kbagent doctor ───────────────────────────────────────────────╮
│ PASS Config source: Using global config at /home/vojta/.config/keboola-agent-cli/config.json │
│ PASS Config file: Config file exists at /home/vojta/.config/keboola-agent-cli/config.json with correct │
│ permissions. │
│ PASS Config parseable: Config file is valid JSON with 14 project(s). │
│ PASS Project 'kosik-core': Connected to https://connection.eu-central-1.keboola.com (project: Kosik CORE, │
│ id: 250) in 96ms │ │
│ PASS CLI version: kbagent v0.47.1 │
│ PASS MCP server: MCP server available via: keboola_mcp_server (transport=stdio) │
│ WARN Conversation ID: KBAGENT_CONVERSATION_ID not set. API requests will not include X-Conversation-ID │
│ header. │
│ PASS Claude Code plugin: kbagent plugin v0.46.1 installed at │
│ /home/vojta/.claude/plugins/cache/keboola-agent-cli/kbagent/0.46.1 (CLI is v0.47.1 -- run `/plugin update │
│ kbagent` in Claude Code to sync) │
│ │
│ Summary: 21 checks, 20 passed, 1 warnings │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Note: In Session 2, after manually reinstalling to v0.46.1 with --reinstall (which cached all 46 packages as a side effect), the very next kbagent doctor succeeded immediately. This confirms the failure in Session 1 was purely the cold-cache prepare time (~2m 27s) exceeding the 120s timeout — not a genuine install problem.
Environment
Root cause
The startup auto-update hook uses a hardcoded 120s timeout for the
uv tool install --upgrade git+...subprocess (auto_update.py,_perform_update). On WSL Ubuntu with a cold uv package cache, preparing all 46 packages takes ~2m 27s. The subprocess is killed at 120s →TimeoutExpired→ returnsFalse→ "Auto-update failed" is printed. On the next invocation with a warm cache, the update succeeds instantly — confirming the problem is purely the timeout, not a genuine install failure.Bug 1 — False failure on cold cache
Reproduction:
Key evidence from the cold-cache
uvreinstall:Bug 2 —
kbagent updatereports "already up to date" when it isn'tDuring the same session, after auto-update failed, running
kbagent updatereturned:…while
kbagent --versionconfirmed it was still on v0.46.1 and v0.47.1 was available. The explicit update command silently reported wrong state instead of retrying.Bug 3 —
kbagent --json updatestartup hook and subcommand disagreeWhen running
kbagent --json update, the startup hook fires (becauseargv[1]is--json, notupdate) and prints "Auto-update failed". But the explicitupdatesubcommand runs afterward and returns JSON with"updated": true:{ "kbagent": { "updated": true, "current_version": "0.46.1", "latest_version": "0.47.1", "message": "Updated kbagent from v0.46.1 to v0.47.1. Restart your shell to use the new version." } }Same process, same invocation: human output says failure, machine output says success. Any script parsing the JSON exit would believe the update succeeded; any human reading the terminal would believe it failed.
This also exposes the
argv[1]check issue:kbagent --json updatetriggers the startup hook, butkbagent updatedoes not.Suggested fixes
Short-term: Raise the timeout in
_perform_updatefrom 120s to at least 300s, or extract it as a named constantUPDATE_TIMEOUT_SECONDS.Medium-term: Run the install in a background process and print "Update downloading in background — restart your shell when done." CLI is never blocked regardless of network/cache state.
For Bug 2 & 3: The "already up to date" check and the
argv[1]check for skipping the startup hook both need reviewing — they interact badly when the previous auto-update silently failed.Full terminal sessions
Session 1 — cold cache, false failures, JSON discrepancy
Session 2 — reinstall to cold cache, warm-cache success proof