feat(coda): three-mode framework + coda_interactive, agent/setup fixes, and skill-bundle refresh (Databricks + Flutter/Dart/shadcn) - #67
Conversation
…117) Recompiled requirements.txt from pyproject.toml via uv pip compile. Both packages pass the 7-day exclude-newer supply-chain gate. - charset-normalizer 3.4.6 → 3.4.7 (released 2026-04-02) - claude-agent-sdk 0.1.50 → 0.1.54 (released 2026-04-02) Dependabot PRs #110 (pydantic-core), #111 (cryptography), #113 (claude-agent-sdk 0.1.58) propose versions blocked by the 7-day rule. PR #109 (importlib-metadata 9.0.0) also blocked by UV exclude-newer.
….17.0) Closes #118, #120, #121, #122 - Session creation prompt: ask users to reuse existing sessions before creating new - MAX_CONCURRENT_SESSIONS backend cap (env var, default 5) with TOCTOU-safe check - Session count label in tab bar with updates on all create/close/exit paths - xterm.js ClipboardAddon for OSC 52 (copy-paste inside Claude Code) - Write batching with requestAnimationFrame to prevent escape sequence fragmentation - Alternate screen exit detection (auto-clear after Claude Code no-flicker/vim) - SIGWINCH-based reattach (force redraw by toggling terminal size) - 429 error message with hint to increase MAX_CONCURRENT_SESSIONS - Replaced mlflow-tracing with mlflow-skinny 3.10.1 - PTY read chunk 4096→65536 bytes - Fixed repo name in deployment docs - Version bump to 0.17.0
Cherry-pick of #114 by David O'Keeffe (@dgokeeffe), rebased onto v0.17.0. 1. Normalize all emails to lowercase at ingestion points so SSO header casing differences don't cause authorization failures. 2. Probe auto-discovered AI Gateway URLs for reachability (2s timeout). Workspaces without AI Gateway gracefully fall back to serving-endpoints. Result cached in _GATEWAY_RESOLVED env var so subprocesses skip re-probing. 3. Version bump to 0.17.1. Co-authored-by: David O'Keeffe <david.okeeffe@databricks.com>
…0.0.26 Databricks pypi proxy currently tops out at 0.0.24; fix version 0.0.26 isn't installable for clients, so we waive the audit alongside the existing cryptography 46.0.7 waiver until the proxy catches up. Co-authored-by: Isaac
Bumps [mlflow-skinny](https://github.com/mlflow/mlflow) from 3.10.1 to 3.11.1. - [Release notes](https://github.com/mlflow/mlflow/releases) - [Changelog](https://github.com/mlflow/mlflow/blob/master/CHANGELOG.md) - [Commits](mlflow/mlflow@v3.10.1...v3.11.1) --- updated-dependencies: - dependency-name: mlflow-skinny dependency-version: 3.11.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
…skinny-3.11.1 chore(deps): bump mlflow-skinny from 3.10.1 to 3.11.1
Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.1.7 to 3.1.8. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](pallets/werkzeug@3.1.7...3.1.8) --- updated-dependencies: - dependency-name: werkzeug dependency-version: 3.1.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…g-3.1.8 chore(deps): bump werkzeug from 3.1.7 to 3.1.8
Prevents dependabot from opening PRs for versions younger than 7 days, aligning with the supply-chain safety gate in pyproject.toml and avoiding CI failures where freshly released versions can't resolve under uv's exclude-newer filter. Co-authored-by: Isaac
Bumps [uvicorn](https://github.com/Kludex/uvicorn) from 0.42.0 to 0.44.0. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](Kludex/uvicorn@0.42.0...0.44.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.44.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
… (#133) * fix: enforce owner auth on /api/sessions and /api/session/attach (#132) These endpoints were incorrectly exempted from the before_request authorization check, allowing any Databricks user to list sessions and read buffered terminal output. Also adds 17 new tests covering endpoint-level auth enforcement and case-insensitive email matching. Fixes #132 * chore: bump version to 0.17.2
…-0.44.0 chore(deps): bump uvicorn from 0.42.0 to 0.44.0
…137) - cryptography 46.0.6 → 46.0.7 (fixes GHSA-p423-j2cm-9vmq) - python-multipart 0.0.22 → 0.0.26 (fixes GHSA-mj87-hwqh-73pj) - claude-agent-sdk 0.1.54 → 0.1.58 - softprops/action-gh-release v2 → v3 SHA pin - Remove --ignore-vuln flags from CI audit (both CVEs now patched) - Regenerate requirements.lock with hashes
…d-steps) Adds four Claude Code skills for behaviour-driven development on Databricks: - bdd-scaffold: scaffold a Behave project wired to Databricks SDK (generates behave.ini, features/, steps/, environment.py, pyproject.toml with UV) - bdd-features: write Gherkin feature files following Databricks-specific patterns (Unity Catalog operations, pipeline runs, SQL assertions) - bdd-steps: generate Python step definitions from feature files using the Databricks SDK step library - bdd-run: execute Behave suites with tag filtering, parallel mode, and CI-friendly reporting Includes reference test suite for UC catalog and SQL operations. Pure addition — no production code changes. Co-authored-by: Isaac
* feat: integrate Hermes Agent as 5th coding CLI Adds Hermes Agent (github.com/NousResearch/hermes-agent) alongside Claude Code, Codex, OpenCode, and Gemini CLI. Hermes is a Python-based multi- provider AI CLI with tool-calling, persistent memory, and a rich skill system — installed via its official installer into ~/.local/bin/hermes. Integration points: - setup_hermes.py: installs Hermes, writes ~/.hermes/config.yaml pointing at Databricks AI Gateway (/mlflow/v1) or /serving-endpoints fallback. Configures custom provider, fallback_providers chain (opus-4-7 -> opus-4-6 on 429/529/503), external skills dir shared with Claude Code, and MCP servers (deepwiki + exa + optional team-memory). - app.py: adds hermes to setup_state steps, parallel_steps, and the _configure_all_cli_auth re-run loop. - cli_auth.py: _update_hermes() rewrites api_key lines in ~/.hermes/config.yaml on PAT rotation (every 10m). - app.yaml.template: HERMES_MODEL env var (default opus-4-7). - CLAUDE.md / README.md / docs/deployment.md: documentation. Usage after deploy: hermes chat # interactive chat hermes --tui chat # rich TUI hermes model # select default model hermes mcp list # list configured MCP servers * fix: replace 135MB git clone with uv tool install for hermes setup The original setup_hermes.py cloned the full NousResearch/hermes-agent repo (135MB) with a 180s timeout, which silently failed on Databricks Apps. Switched to `uv tool install` from git URL — handles venv and binary setup automatically. Also dropped the `matrix` extra (requires native libolm). * fix: post-setup token sync to prevent stale PAT in CLI configs When PAT rotation happens while a setup script is still installing (e.g., Hermes takes minutes to install from git), the rotation's update_cli_tokens() silently skips missing config files. The setup script then writes config with the initial (now-revoked) token. Fix: after all parallel setup completes, re-apply the current token to all CLI configs. This ensures every config has the latest token regardless of installation timing vs rotation timing. Closes the race window that caused HTTP 403 on first Hermes launch. * fix: Gemini CLI auth — remove quoted .env value + strip stale env var Two bugs preventing Gemini CLI from authenticating: 1. setup_gemini.py wrote GEMINI_API_KEY_AUTH_MECHANISM="bearer" (with literal quotes). Node.js dotenv parses this as '"bearer"' — Gemini CLI expects 'bearer' without quotes, fails auth check, falls back to interactive prompt asking for credentials. 2. Terminal sessions inherited GEMINI_API_KEY from the parent process env, which goes stale after PAT rotation. Now stripped from shell env (like DATABRICKS_TOKEN) so Gemini CLI reads from ~/.gemini/.env which is kept current by cli_auth.py. * chore: update default Gemini model to databricks-gemini-2-5-pro Updated in setup_gemini.py, setup_opencode.py, setup_hermes.py, app.yaml, app.yaml.template, README.md, and deployment docs. * fix: pre-trust workspace so Gemini CLI loads .env credentials Gemini CLI has a workspace trust system that silently skips loading .env files in untrusted directories (gemini-cli#20005). Terminal sessions on Databricks Apps start in ~/projects/ which was never trusted, so GEMINI_API_KEY from ~/.gemini/.env was never loaded. Fix: write ~/.gemini/trustedFolders.json during setup to pre-trust both ~/projects/ and ~/ so .env loading works from any directory. * fix: use TRUST_FOLDER enum value in trustedFolders.json Gemini CLI expects string enum values (TRUST_FOLDER, TRUST_PARENT, DO_NOT_TRUST), not booleans. Using true caused: Invalid trust level "true" for path "..." * fix: include mcp package in Hermes install for MCP server support Hermes is installed via uv tool install into an isolated venv. The mcp Python package (HTTP transport) wasn't included, so MCP servers (DeepWiki, Exa) failed with "mcp.client.streamable_http not available." Fix: add --with 'mcp>=1.2.0' to the uv tool install command. --------- Co-authored-by: Hermes Agent <hermes@databricks.app>
feat: add BDD testing skills (bdd-scaffold, bdd-features, bdd-steps, bdd-run)
Adds SDK User-Agent based event tracking so CoDA usage appears on the
shared Labs usage dashboard. Events fire in background daemon threads
and never block Flask request handling or terminal I/O.
Active events tracked:
- app_startup (initialize_app)
- agent session creation with agent type (create_session)
- file_upload (upload_file)
- pat_rotation (_rotate_once)
- workspace_sync (sync_project)
Passive: all existing WorkspaceClient instances now carry product_info
('coda', version) so regular SDK calls also identify CoDA.
Reference: https://github.com/databrickslabs/dqx/blob/main/src/databricks/labs/dqx/telemetry.py
The original PR only updated setup_*.py, but the deployed app.yaml CODEX_MODEL env var still pinned databricks-gpt-5-3-codex (overriding the new default), and app.py had a parallel settings block still on opus-4-6. Also fixed the README and deployment docs. Co-authored-by: Isaac
…toml Adds a model_catalog_json catalog so users can pick from gpt-5-5/5-4/5-4-mini/ 5-3-codex/5-2 in the codex /model picker (instead of just the active default). - Bundle .codex/databricks-models.json in the repo - setup_codex.py copies it into ~/.codex/ at startup and adds `model_catalog_json = "databricks-models.json"` (relative path; codex's AbsolutePathBuf resolves relatives against CODEX_HOME) - .gitignore now tracks only the bundled catalog under .codex/, so per-user generated config.toml stays untracked Co-authored-by: Isaac
Codex looks for skills in \$HOME/.agents/skills and .agents/skills walking up from cwd. We mirror the gemini setup pattern: copy .claude/skills (the canonical bundled-skills source) into ~/.agents/skills at startup so codex sees the same 30+ Databricks/superpowers skills the other agents do. Also gitignore .agents/ since it's generated, like .gemini/skills. Co-authored-by: Isaac
feat: add control plane event tracking
Notable updates: - claude-agent-sdk 0.1.58 → 0.1.65 - databricks-sdk 0.102.0 → 0.103.0 - mcp 1.26.0 → 1.27.0 - certifi 2026.2.25 → 2026.4.22 - opentelemetry-sdk 1.40.0 → 1.41.0 - pydantic 2.12.5 → 2.13.3 - uvicorn 0.44.0 → 0.45.0 protobuf stays at 6.x (7.x is a major version bump, skipped)
fix(deps): install requests from PyPI instead of a git+https GitHub pin
Co-authored-by: Isaac
Remove promo video file and README fallback link
…6.5.20 chore(deps): bump certifi from 2026.4.22 to 2026.5.20
…astral-sh/setup-uv-8.1.0 chore(deps): bump astral-sh/setup-uv from 7.6.0 to 8.1.0
…ry-proto-1.42.1 chore(deps): bump opentelemetry-proto from 1.41.1 to 1.42.1
…36.3 chore(deps): bump fastapi from 0.136.1 to 0.136.3
chore(deps): bump zipp from 3.23.1 to 4.1.0
…13.4 chore(deps): bump pydantic from 2.13.3 to 2.13.4
…-comment chore: drop the giant gitignore comment from #25 (post-merge nit)
Hot fix for dependabot update conflict
…ack) PR #67 review flagged these for removal: docs/superpowers/{plans,specs}/* and docs/plans/2026-05-01-coda-mcp-server.md are working artifacts of the spec->plan->implement workflow, not user-facing docs.
…t 400, Hermes model catalog
- Gemini CLI broke on tool-call turns: newer gemini-cli attaches `id` to
functionCall/functionResponse history parts; the Databricks /gemini route
rejects unknown proto fields with 400 'Unknown name "id"'. Gemini CLI now
routes through the local content-filter proxy, which strips those ids,
forwards /gemini/* to the matching gateway route, detects Gemini streaming
from the URL (:streamGenerateContent), and re-injects a fresh PAT after
rotation (bonus: gemini sessions now survive PAT rotation).
- OpenCode 400'd after a model switch: it sends reasoning_effort, which
Databricks chat-completions rejects ('Extra inputs are not permitted').
The proxy now strips reasoning_effort/reasoning/verbosity from
OpenAI-format request bodies.
- Hermes known_models catalog listed databricks-gemini-2-5-pro twice and
omitted the default model databricks-claude-opus-4-7.
Tests: 21 new (proxy sanitizers, /gemini routing, stream detection, setup
wiring pins, hermes catalog hygiene). Full suite: 634 passed, 5 skipped.
|
Review feedback addressed ( 1. Gemini CLI regression → fixed ( 2. OpenCode model switch → 3. Hermes → partially fixed ( 4. Cludgy terminal UI — agreed; deferring to its own issue/PR. It's xterm.js rendering/reflow work, orthogonal to this PR. 5. MCPs from Genie Code working — 🎉 6. Spec/plan artifacts → removed ( 21 new regression tests (proxy sanitizers, |
The comment claimed OPENAI_API_KEY is written to a shell profile; the code (correctly) writes only ~/.codex/.env, which cli_auth._update_codex() rewrites on every PAT rotation. Spell out the rotation contract and warn against profile/app.yaml exports — a frozen env copy would shadow the rotating .env and pin Codex to a revoked token.
…lay through content-filter proxy Codex reads OPENAI_API_KEY once at process start (config.toml env_key → ~/.codex/.env). cli_auth rewrites that file every rotation, so NEW sessions always get the current token — but a RUNNING session froze its token and 401'd once the 10-min rotation revoked it. Codex now points at the local content-filter proxy, which injects the freshest PAT per request. The /openai/* prefix is relayed TRANSPARENTLY so zero Responses-API capability is lost: byte-identical bodies both directions (no sanitizers, no JSON re-serialization), all HTTP methods (GET/POST/DELETE), Accept- Encoding identity, and connect-timeout-only so long silent reasoning stretches never 504. Critic-review hardening (verdict SHIP-WITH-FIXES, both blockers fixed): - upstream response always closed; client disconnect mid-stream stops the relay (_write_chunk_strict propagates BrokenPipeError) instead of silently draining the upstream - proxy now speaks HTTP/1.1 — chunked framing is invalid on 1.0 and strict hyper-based clients (Codex) can misparse it; pinned by resp.raw.version - 204/304 forwarded bodyless (no chunked framing) - elif prefix routing in resolve_upstream_url - also: corrected a stale comment claiming OPENAI_API_KEY is written to a shell profile, and added an ast.parse syntax gate over setup/*.py (a text-pin test suite cannot catch syntax breaks — one occurred mid-dev) Tests: +12 incl. live-socket relay fixture (fake upstream + real proxy): byte-identical pass-through with reasoning fields intact, fresh-token injection over a stale client header, GET/DELETE forwarding, verbatim SSE (2^53+1 big-int canary), and a sanitized-path regression guard. Full suite: 646 passed, 5 skipped.
|
Follow-up ( Proxy topology now: OpenCode + Gemini + Codex via |
|
Review — sole maintainer doing a backlog pass. Short version: the MCP feature is worth landing, but not in this shape. Three things need resolving first, one of them a security regression. Detail below so this is actionable rather than just blocked. Note #64 and #66 are strict ancestors of this branch, so I've closed them in favour of this one — 1.
|
| Part | Size |
|---|---|
coda_mcp/ |
7 files, ~1,875 lines |
| tests | 9 MCP-related files |
| docs | 3 files |
The rest is a repo-wide relocation (setup_*.py → setup/, install scripts → scripts/) plus a 176-file .claude/ skills refresh. That churn is what makes this unreviewable, and it maximises conflict surface against everything else in flight — it's also why the diff reads as +34k/-8k.
Suggested split:
coda_mcp/+ its tests + docs + the minimalapp.pywiring, with the auth fix from §1.- The
setup/+scripts/relocation as its own mechanical PR, if it's wanted at all. - The
.claude/refresh via the existingrefresh-databricks-skillsskill, separately.
Happy to do the split myself if you'd rather — say the word. But §1 needs an answer from you either way, since it's a deliberate design choice in the current code rather than an oversight, and I'd rather not guess at the intent.






Summary
Two changes that together establish the three-mode framework for the CoDA MCP server:
coda_runto replay-only URLs — its returnedviewer_urlnow always serves a static transcript from disk, never a live PTY attach. Drops the 5-minute grace machinery introduced in feat: CoDA MCP live session URL — watch hermes execute live + replay #66 (which was actually never wired in production — see commit193c9a3for the dead-code analysis).coda_interactiveMCP tool — for human handoff from upstream MCP clients (Genie Code, Claude Desktop, Cursor). Caller passes a Databricks Workspace Git Folder path, optional branch, and a kickoff prompt. Coda exports the file tree, launches the chosen agent (claude default; also hermes/codex/gemini/opencode), auto-types the prompt, and returns aviewer_urlfor the human to attach to.The three-mode framework now:
coda_interactive(new)coda_run(narrowed)Why Workspace Git Folders (not GitHub clone)
coda_interactivematerializes project files via the Databricks Workspace API — uses Coda's existingDATABRICKS_TOKEN, no new credentials needed. Trade-off: git history is unavailable inside the session (files-only export). If history matters for a session, the MCP caller can include agit logsummary in the prompt string.Pre-existing security fix bundled
mcp_create_pty_sessionwas stripping only 5 env vars; the HTTPcreate_sessionpath was strippingNPM_TOKEN,UV_*, andnpm_config_//*patterns too. Refactored to share_build_terminal_shell_env(commitef15ef7). Closes a latent registry-credential leak into MCP-created PTYs.Subsumes PR #66
PR #66 introduced live-attach + 5-min grace on
coda_run. This PR keeps the viewer URL feature but narrows it to replay-only (since live attach moves tocoda_interactive). Close #66 if this lands.Spec + Plan artifacts (in the diff)
docs/superpowers/specs/2026-05-28-coda-run-replay-only-design.md+plans/2026-05-28-coda-run-replay-only.mddocs/superpowers/specs/2026-05-28-coda-interactive-mcp-tool-design.md+plans/2026-05-28-coda-interactive-mcp-tool.mdTest plan
551 passed, 21 skipped— confirmed (pytest tests/ --ignore=tests/e2e)coda_runfrom Genie Code; confirm viewer URL is replay-onlycoda_interactivewith a Workspace Git Folder; confirm agent launches in exported project dir with prompt typedcoda_inboxdoes NOT show interactive sessions;coda_get_resultreturns nothing for them_build_terminal_shell_envstrip on deployed PTY —env | grep -E 'NPM_TOKEN|UV_'should be emptyFollow-up: broadened source contract (commits
326e19a..a555602)coda_interactiveno longer requires theworkspace_pathto be a Databricks Workspace Git Folder. Any Workspace directory (Git Folder or plain Workspace folder) is accepted. Thebranchparameter has been removed — callers manage Git Folder branch state themselves before calling.API change (no shipped consumers — safe):
coda_interactive(prompt, workspace_path, branch=..., agent=..., email=...)→coda_interactive(prompt, workspace_path, agent=..., email=...)"branch"key dropped.Validation: replaced
repos.list+ exact-match filter + optionalrepos.updatewith a singleworkspace.get_statuscall + directory-type check (_is_directoryfromworkspace_export.py). Clean errors for "path not found" and "path is not a directory" — both return before any PTY allocation.Server-level instructions string rewritten to:
workspace.importfirst if files aren't in the Workspace yet) so an upstream LLM knows the tool doesn't accept inline file payloads.Quality fix bundled: hoisted the
_app_send_input is Noneguard above PTY creation so an unwired send-hook can no longer orphan a PTY + project dir.Test delta: −3 / +4. All 13 tests in
tests/test_coda_interactive.pypass.Artifacts:
docs/superpowers/specs/2026-05-28-coda-interactive-broaden-source-design.mddocs/superpowers/plans/2026-05-28-coda-interactive-broaden-source.mdAmended by:for traceability.Follow-up #2: Workflow protocol + Databricks orientation (commits
6ff6a9b..77321dc)coda_runnow injects two new sections intoprompt.txt:~/.claude/skills/, and the DeepWiki / Exa / CoDA MCP servers.New terminal
result.jsonstatus"info_needed"with a requiredfeedbackfield gives the calling client a structured iteration loop when the agent is blocked. The existing"needs_approval"status is preserved with explicit disambiguation in the protocol:info_needed= "caller must add context";needs_approval= "caller must approve a destructive action".Three upstream-facing surfaces updated so calling LLMs know about the new statuses:
coda_inboxcounts dict gainsinfo_neededandneeds_approvalkeys.coda_get_resultdocstring lists all four valid statuses + the newfeedbackfield.feedbackand resubmit withprevious_session_id.Flag:
coda_run(..., workflow_protocol=True)is the default. Set False to skip both new sections for non-Databricks tasks.Artifacts:
docs/superpowers/specs/2026-05-28-coda-run-workflow-protocol-design.mddocs/superpowers/plans/2026-05-28-coda-run-workflow-protocol.mdDiscipline gates run:
_write_jsonstub, expanded regression coverage)section_noisedead code, JSON union-syntax placeholder)Follow-up #3:
coda_interactivepulls files in the terminal (fixes empty-session bug)Bug: Calling
coda_interactivelaunched the agent over an empty directory — the agent had no idea about the user's Workspace files.Root cause: The MCP server's
WorkspaceClient()resolves to the app's service principal (app-167dcd …), which canget_statusthe user's/Users/<user>/…folder (so the tool reported"launched") but cannotlist/exportits contents.workspace_export.pyswallowed those errors → empty dir + misleading success. Verified: the CoDA terminal's CLI runs as the user (databricks current-user me→ the user), anddatabricks workspace list/exportof the folder works as the user via REST.Fix: Stop exporting server-side.
coda_interactivenow typescd <project_dir> && databricks workspace export-dir <source> ./<name> && cd <name>into the PTY (authenticated as the user), waits for the pull to settle, then does a server-side filesystem post-check (identity-independent — it stats the local disk the terminal wrote). If files landed it launches the agent and seeds the prompt with a context line naming the source; if nothing landed it returns a realstatus=errorand never launches.Design highlights:
databricks workspace export-dirnatively handles notebook extensions, replacing the hand-rolledworkspace_export.py(deleted, with its tests)._wait_for_agent_readyis now a thin wrapper over a generalized_wait_for_output_stable(pty, max_wait, stability);coda_runis unchanged._safe_dirname(sanitized basename, rejects./..) and_normalize_workspace_path(drops the/WorkspaceFUSE prefix).instructionswording updated; no more "server-side snapshot".Tests:
test_coda_interactive.pyrewritten to the pull contract (pull-first, FS-check failure → no launch, prompt context line, agent matrix);_safe_dirname/_normalize_workspace_path+ the wait-wrapper covered intest_mcp_server.py. Suite: 117 passed (only the documented PTY-fd flake fails in multi-file runs; passes in isolation).Artifacts:
docs/superpowers/specs/2026-05-28-coda-interactive-terminal-pull-design.mddocs/superpowers/plans/2026-05-28-coda-interactive-terminal-pull.mdDiscipline gates: brainstorm → design critic (SOUND-WITH-FIXES, folded in) → spec → plan → plan critic (SOUND-WITH-FIXES, folded in) → TDD implementation → final critic (SHIP-WITH-FOLLOWUPS; the one Important finding —
..path-traversal in_safe_dirname— fixed before push).This branch also merges the latest
main(Dependabot deps bump #68: urllib3 2.7.0 / gitpython 3.1.50 / idna 3.16).Follow-up #4: OpenCode + Codex + Claude-subagent fixes (the
fec2152file-move regression class)The CoDA-MCP commit (
fec2152) relocated every setup script intosetup/(and the install scripts intoscripts/), but several scripts kept resolving sibling resources viaPath(__file__).parent— which then pointed atsetup/instead of the repo root. Three resources were silently broken; all fixed and pinned with regression tests.444e133):setup_proxy.pylaunched a nonexistentsetup/content_filter_proxy.py, so the content-filter proxy never started and OpenCode — the only agent routed through127.0.0.1:4000— failed withCannot connect to API. Other agents talk to the gateway directly and were unaffected. Now resolves from the repo root viaresolve_proxy_script_path()(script body guarded undermain()so the path logic is importable/testable). Also registereddatabricks-claude-opus-4-7in the OpenCode model map and dropped a duplicategemini-2-5-prokey.7bdc3f3):setup_claude.pylooked insetup/agents/, silently hitting the "No agents directory found" branch — the TDD subagents (build-feature,prd-writer,test-generator,implementer) were never installed into~/.claude/agents. Fixed viaresolve_agents_src()→ repo root.7bdc3f3):setup_codex.pylooked insetup/.codex/databricks-models.json; the catalog was never copied into~/.codexwhileconfig.tomlstill referenced it. Fixed viaresolve_codex_catalog_src()→ repo root.Regression tests pin each resolved resource path to a real file so a future move can't silently regress it again:
tests/test_setup_proxy.py,tests/test_setup_resource_paths.py.Follow-up #5: flaky PTY test-suite hardening (
32624c7)The full unit suite failed intermittently (a different set each run); two independent causes:
terminate_sessiondouble-closedmaster_fd(production bug): both the explicit close path (mcp_close_pty_session) and the read-thread exit path (read_pty_output) call it for the same session, but the kill/os.closeblock ran unconditionally — so the secondos.close()could land on a since-reused fd (e.g. an asyncio event loop's self-pipe from a later test), surfacing as intermittentOSError: [Errno 9] Bad file descriptor. Now atomically claims the session (sessions.pop) and closes exactly once. Covered bytests/test_terminate_session_idempotent.py.tests/test_mcp_server.py::_reset_hookssetmcp_server's process-wide PTY hooks toNonein teardown, leaking into later files socoda_runcreated no PTY (pty_id is None) — but only in full-suite runs. Fixed with atests/conftest.pyautouse fixture that re-establishes app's real hooks after each test, making hook state order-independent.TestNpmVersionLivenow skips when the npm registry is unreachable (theskipifprobe was raisingTimeoutExpiredas a collection error; the body asserted on aNoneresult) instead of erroring/failing offline.Full unit suite now green across 3 consecutive runs: 613 passed, 2 skipped.
Follow-up #6: skill-bundle refresh + Flutter / Dart / shadcn (
f2ca8c7,37df2f8)databricks-solutions/ai-dev-kit(local was ~3 months stale: 2026-02-22 → upstream76c774f, 2026-05-28). 24 → 26 skills: newdatabricks-ai-functions,databricks-execution-compute,databricks-iceberg; renamedapp-python→apps-python,asset-bundles→bundles,synthetic-data-generation→synthetic-data-gen; droppeddatabricks-app-apx(no longer shipped upstream); content refreshed across the rest. The curated 16-skill list (coda_mcp/databricks_preamble.py) and the CLAUDE.md Databricks Skills table are kept in lockstep bytest_databricks_preamble.py.flutter-*(flutter/skills), 9dart-*(dart-lang/skills), andshadcn-ui-flutter(nank1ro/flutter-shadcn-ui). Documented in CLAUDE.md (skill count 30 → 50).All of the above is verified live on the deployed test app
mcp-test-coda-labs-feat(refreshed Databricks skills + the 20 new Flutter/Dart/shadcn skills confirmed in the deployed.claude/skills/).