feat: session prompt, clipboard fix, output batching, and dep cleanup#119
Merged
datasciencemonkey merged 21 commits intomainfrom Apr 14, 2026
Merged
feat: session prompt, clipboard fix, output batching, and dep cleanup#119datasciencemonkey merged 21 commits intomainfrom
datasciencemonkey merged 21 commits intomainfrom
Conversation
#118) Prevent OOM crashes on 6GB Databricks Apps containers by reducing unnecessary session accumulation. Users now see their active sessions and can reuse one instead of blindly spawning a new one each time. - Add session-aware prompt on page load, new tab, and split pane - Add MAX_CONCURRENT_SESSIONS backend cap (env var, default 5) - Add session count badge on the toolbar sessions button - Add 8 tests covering the session limit enforcement
Claude Code uses OSC 52 escape sequences for clipboard operations. Without the ClipboardAddon, xterm.js silently ignores these sequences, making copy-paste inside Claude Code sessions non-functional. - Add addon-clipboard.js to static/lib/ - Load and initialize ClipboardAddon in createPane() - Add 8 tests verifying addon presence and integration
Align with the lockfile pin to prevent accidental upgrades that could pull in incompatible transitive dependencies.
No Python code imports mlflow. Removing unused deps cuts the package count from 65 to 50, reducing container image size and attack surface.
Keep only mlflow-skinny (lightweight client) — mlflow-tracing and the full mlflow package are not needed. Pins to 3.10.1.
…ation Claude Code's no-flicker mode uses dense cursor-positioning sequences that get split when the PTY reader sends fixed-size chunks. This causes garbled rendering (text fragments at wrong positions). - Add requestAnimationFrame write batching (~16ms) for PTY output - Increase PTY read chunk size from 4096 to 65536 bytes - Only PTY stream is batched; direct UI writes (splash, picker) unaffected
After replaying the output buffer on reattach, send ESC[?1049l to ensure the terminal is on the main screen buffer. Prevents garbled display when reattaching after exiting Claude Code no-flicker mode or other alternate-screen apps (vim, htop).
When Claude Code no-flicker mode (or vim/htop) exits the alternate screen, the restored main buffer has stale content overlapping with exit output. Detect ESC[?1049l in the output stream and clear the screen after 150ms to let exit output finish, then show a clean prompt.
The output buffer contains raw escape sequences captured at different terminal dimensions or from alternate-screen apps. Replaying them produces garbled output. Clear the screen after replay to guarantee a clean terminal, then resize triggers the shell to redraw its prompt.
…122) Buffer replay produces garbled output from stale escape sequences and conflicts with alternate-screen apps (Claude Code no-flicker mode). Replace with term.reset() + resize — the resize sends SIGWINCH so the running app (bash, Claude Code, vim) redraws its own UI correctly.
The kernel only sends SIGWINCH when the PTY size actually changes. On reattach, if the terminal dimensions are unchanged, no SIGWINCH fires and the app (Claude Code in no-flicker mode) never redraws. Fix by sending a 1-column shrink then restoring the real size, guaranteeing SIGWINCH regardless of current dimensions.
- Add q/Esc/Q cancel handler to promptExistingSessions so the Promise can't hang forever if user presses an unrecognized key - Add cancel() method to write batcher to clear pending data and timers - Call batchWrite.cancel() from cleanupPane to prevent writes to disposed terminals when altExitTimer fires after pane teardown
Backend: - Fix TOCTOU race in session cap: authoritative len(sessions) check inside the same sessions_lock as dict insertion. Early approximate check still rejects before forking a PTY. - Use len(sessions) instead of exited flag filter (exited is dead code — sessions are popped, never marked) Tests: - Fix env var test to patch the actual module constant - Fix bare open() calls in clipboard tests (use context managers) - Use re.search for more specific OSC 52 handler assertion - Replace exited-flag tests with removal-based tests matching real behavior
When the backend returns 429 (max sessions), display a clear error in the terminal with the message and a hint to increase MAX_CONCURRENT_SESSIONS in app.yaml or close sessions via Ctrl+Shift+S.
coding-agents-in-databricks → coding-agents-databricks-apps
Add overflow:visible to sessions button and reposition badge to top-right corner (-4px offset) so it sits above the button edge instead of being clipped by the flex container.
The red badge on the hamburger button was clipped and invisible. Replace with a plain text label on the right side of the tab bar showing "1 active session" / "2 active sessions" / etc.
Add updateSessionBadge() to cleanupPane (covers all exit paths) and after individual session kills in the session picker. Count now decrements when sessions are closed, exited, or killed.
Traced all session create/close/exit/switch paths and found 2 gaps:
- Cancelled session picker (Esc/q) early-returns before badge update
- Kill-all ("x") in picker didn't update badge before creating new session
Both now call updateSessionBadge() at the right point.
When a session exits (user types "exit"), cleanupPane fetches the session count immediately — but the backend hasn't finished removing the session yet (3s SIGKILL wait). Add a 4s delayed retry so the count reflects the removal after backend cleanup completes.
Owner
Author
|
All tests pass. |
Session management, clipboard, rendering, and dependency improvements.
Owner
Author
v0.17.0 Ship SummaryWhat shipped
Test results
Issues closed
|
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #118, closes #120, closes #121, closes #122
Addresses multiple issues discovered during investigation of a user-reported crash on the coda Databricks App:
1. OOM crash prevention (#118)
The app crashed suddenly with clean logs on a Medium instance (6GB RAM / 2 vCPUs) — pointing to an OOM kill. Users unknowingly accumulated terminal sessions (each with PTY + bash + AI agent subprocesses) until the container exceeded its memory limit.
2. Copy-paste broken inside Claude Code (#120)
Claude Code uses OSC 52 escape sequences for clipboard operations. The xterm.js ClipboardAddon was never loaded, so OSC 52 sequences were silently ignored.
3. Garbled rendering in Claude Code no-flicker mode (#121)
Claude Code's fullscreen/no-flicker mode (
CLAUDE_CODE_NO_FLICKER=1) uses dense cursor-positioning sequences that get split when the PTY reader sends fixed 4096-byte chunks. Split escape sequences cause text fragments to render at wrong positions.4. Garbled screen on reattach after alternate-screen apps (#122)
After exiting Claude Code (or vim/htop), reattaching to the session showed a screen full of repeated bash prompts. The output buffer contained raw alternate-screen escape sequences that produced garbage on replay.
5. Dependency cleanup
Replaced
mlflow-tracingwithmlflow-skinny==3.10.1— the app only needs the lightweight MLflow client, not the tracing package.6. Docs fix
Corrected repo name in deployment docs (
coding-agents-in-databricks→coding-agents-databricks-apps).Changes
app.pyMAX_CONCURRENT_SESSIONSbackend cap (env var, default 5) with TOCTOU-safe double-check; PTY read chunk 4096→65536 bytesapp.yamlMAX_CONCURRENT_SESSIONSenv varstatic/index.htmlcreateWriteBatcher()for output batching; ClipboardAddon; session count label in tab bar; alternate screen exit detection; SIGWINCH-based reattach; 429 error message; escape key handlingstatic/lib/addon-clipboard.jspyproject.tomlmlflow-tracingwithmlflow-skinny==3.10.1requirements.txtdocs/deployment.mdREADME.mdtests/test_session_limit.pytests/test_clipboard_addon.pyTest plan
Automated (all pass locally)
uv run python -m pytest tests/ -q— 163/163 pass (excluding 2 pre-existing flaky network tests intest_gateway_discovery.pyandtest_npm_version_pinning.py)Manual testing on Databricks Apps
Session prompt (#118):
n— creates new sessionqorEsc— creates new session (cancel = default to new)Session cap (#118):
MAX_CONCURRENT_SESSIONSor use Ctrl+Shift+SSession count label (tab bar):
exit)Clipboard / OSC 52 (#120):
Output rendering / no-flicker mode (#121):
CLAUDE_CODE_NO_FLICKER=1 claudeinside a sessioncatlarge file) renders smoothlyReattach after alternate-screen apps (#122):
Dependencies:
pip list | grep mlflowshows onlymlflow-skinny==3.10.1Docs:
coding-agents-databricks-apps)