Skip to content

SDK Dashboard TUI Example App [Spec + Impl] - #27

Merged
rhuss merged 1 commit into
mainfrom
018-sdk-dashboard-tui
Jul 11, 2026
Merged

rhuss merged 1 commit into
mainfrom
018-sdk-dashboard-tui

Conversation

@rhuss

@rhuss rhuss commented Jul 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

Full-screen Bubble Tea dashboard TUI (oshell) showcasing the Go SDK.

Tabs: Sandboxes (live Watch, CRUD), Providers, Services, Health (sparkline), Exec
Auth: Lazy OIDC flow (stub pending oidc package)
Logging: Custom slog tee handler (TUI panel + JSON file)
Demo: --demo mode using SDK fake client with simulated data

Self-contained Go module in examples/oshell/ for future repo extraction.

Artifacts

  • Spec: specs/018-sdk-dashboard-tui/spec.md
  • Plan: specs/018-sdk-dashboard-tui/plan.md
  • Tasks: specs/018-sdk-dashboard-tui/tasks.md
  • Review: specs/018-sdk-dashboard-tui/REVIEW-CODE.md

Test plan

  • cd examples/oshell && go build ./... compiles cleanly
  • go vet ./... passes with no warnings
  • go run . --demo launches the dashboard with simulated data
  • Tab switching (1-5 keys) works across all views
  • Log panel scrolls with Tab key focus cycling
  • Graceful shutdown via 'q' or Ctrl+C

Assisted-By: 🤖 Claude Code


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Added a new full-screen terminal dashboard example (“oshell”) with numbered tabs for Sandboxes, Providers, Services, Health, and Exec, plus keyboard navigation and focus switching.
    • Includes demo mode and gateway-connected mode, with live connection/auth status, lazy browser-based sign-in on unauthenticated responses, reconnection backoff, and an in-app scrolling log panel.
    • Adds sandbox actions (create/delete/details with policy and SSH/TCP indicators), health monitoring with a latency sparkline, and exec command history (stdout/stderr/exit info).
    • Services tab supports copying endpoint URLs to the clipboard.
  • Documentation

    • Added/updated example README with run instructions and shortcuts, plus planning/spec/review notes for the new dashboard experience.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rhuss, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e52796b-0cef-4f79-926c-c201f641b376

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd80fa and c75144b.

⛔ Files ignored due to path filters (1)
  • examples/oshell/go.sum is excluded by !**/*.sum
📒 Files selected for processing (30)
  • CLAUDE.md
  • brainstorm/00-overview.md
  • brainstorm/021-sdk-dashboard-tui.md
  • brainstorm/idea-inbox.md
  • examples/oshell/.gitignore
  • examples/oshell/README.md
  • examples/oshell/connection.go
  • examples/oshell/demo.go
  • examples/oshell/go.mod
  • examples/oshell/keys.go
  • examples/oshell/logpanel.go
  • examples/oshell/main.go
  • examples/oshell/model.go
  • examples/oshell/statusbar.go
  • examples/oshell/styles.go
  • examples/oshell/tab_gateway.go
  • examples/oshell/tab_provider.go
  • examples/oshell/tab_sandbox.go
  • examples/oshell/tab_service.go
  • openshell/v1/gateway/config.go
  • openshell/v1/gateway/config_test.go
  • openshell/v1/gateway/gateway_test.go
  • openshell/v1/internal/grpc/conn.go
  • specs/018-sdk-dashboard-tui/REVIEW-CODE.md
  • specs/018-sdk-dashboard-tui/checklists/requirements.md
  • specs/018-sdk-dashboard-tui/data-model.md
  • specs/018-sdk-dashboard-tui/plan.md
  • specs/018-sdk-dashboard-tui/research.md
  • specs/018-sdk-dashboard-tui/spec.md
  • specs/018-sdk-dashboard-tui/tasks.md
📝 Walkthrough

Walkthrough

This PR adds a standalone examples/oshell Go module implementing a Bubble Tea dashboard for the OpenShell SDK, with tabs for sandboxes, providers, services, health, and exec, plus connection/auth handling, structured logging, demo mode, and supporting design/spec documentation.

Changes

SDK Dashboard TUI implementation

Layer / File(s) Summary
Module scaffold and shared UI
examples/oshell/go.mod, .gitignore, styles.go, keys.go
Adds the module definition, ignore rule, shared Lip Gloss styles, and dashboard key bindings.
Connection, status, and logging
examples/oshell/connection.go, statusbar.go, logpanel.go
Adds connection state transitions, lazy OIDC login, status rendering, and the log ring buffer / tee handler / scrollable log panel.
Dashboard root and entrypoint
examples/oshell/model.go, main.go
Adds the root dashboard model, tab routing, auth overlay, shutdown cleanup, and CLI wiring for demo/gateway mode.
Sandbox, provider, service, and exec tabs
examples/oshell/tab_sandbox.go, tab_provider.go, tab_service.go, tab_exec.go
Adds the tab implementations for sandbox management, provider and service tables, and sandbox command execution.
Health tab and demo client
examples/oshell/tab_health.go, demo.go
Adds health polling/sparkline rendering and the fake demo client with sandbox phase simulation.
Brainstorm and spec documentation
CLAUDE.md, brainstorm/*, examples/oshell/README.md, specs/018-sdk-dashboard-tui/*
Adds the example README, brainstorm notes, and the 018-sdk-dashboard-tui planning/spec/review documents.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: a new SDK Dashboard TUI example app with spec and implementation work.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 018-sdk-dashboard-tui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.63%. Comparing base (0f8e5e8) to head (c75144b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #27   +/-   ##
=======================================
  Coverage   88.63%   88.63%           
=======================================
  Files          70       70           
  Lines        4161     4163    +2     
=======================================
+ Hits         3688     3690    +2     
  Misses        325      325           
  Partials      148      148           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

devin-ai-integration[bot]

This comment was marked as resolved.

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 3, 2026
Applied fixes from bot review comments:
- Comment #3517851914: add reconnectTickMsg handler (Devin, bug)
- Comment #3517851980: fix watcher data race via message pattern (Devin+Copilot)
- Comment #3517852068: wire gateway name to status bar (Devin)
- Comment #3517855498: route keys to log panel when focused (Copilot)
- Comment #3517855534: remove URL from log output (Copilot, secrets)
- Comment #3517855551,#3517855567: clamp service table height (Copilot)
- Comment #3517855582,#3517855597: clamp provider table height (Copilot)

Assisted-By: 🤖 Claude Code
devin-ai-integration[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 3, 2026
Applied fixes from bot review comments:
- Comment #3517851914: add reconnectTickMsg handler (Devin, bug)
- Comment #3517851980: fix watcher data race via message pattern (Devin+Copilot)
- Comment #3517852068: wire gateway name to status bar (Devin)
- Comment #3517855498: route keys to log panel when focused (Copilot)
- Comment #3517855534: remove URL from log output (Copilot, secrets)
- Comment #3517855551,#3517855567: clamp service table height (Copilot)
- Comment #3517855582,#3517855597: clamp provider table height (Copilot)

Assisted-By: 🤖 Claude Code
@rhuss
rhuss force-pushed the 018-sdk-dashboard-tui branch from e2f8466 to 15ada4a Compare July 3, 2026 06:38
devin-ai-integration[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 3, 2026
Applied fixes from 5 Devin review comments:
- Comment #3517936965: route scroll keys to log panel when focused
- Comment #3517937018: propagate program field to child loggers
- Comment #3517937097: Enabled() always returns true for ring buffer
- Comment #3517937192: document demo mode watch limitation (deferred)
- Comment #3517972417: ANSI-aware log line truncation

Assisted-By: 🤖 Claude Code
devin-ai-integration[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 3, 2026
OIDCLogin now takes a context tied to the dashboard's lifetime,
with a 2-minute timeout. Prevents orphaned goroutines and lingering
callback listeners if the dashboard shuts down mid-login flow.

Assisted-By: 🤖 Claude Code
rhuss added a commit that referenced this pull request Jul 3, 2026
Applied fixes from 3 Devin review comments:
- Comment #3518019252: gate global shortcuts when tab captures input
- Comment #3518019326: adjust detail pane index on sandbox deletion
- Comment #3518019413: route sandbox list errors to connection manager

Assisted-By: 🤖 Claude Code
devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 3, 2026
Applied fixes from review comments:
- main.go: cleanup runs unconditionally after p.Run() (CR, critical)
- model.go: forward non-key messages to ALL tabs (Devin, health ticker)
- tab_sandbox.go: stop existing watcher before starting new on Refresh (CR)
- tab_sandbox.go: add 5s backoff on watch reconnection (CR)
- tab_exec.go: add Sandbox field to ExecEntry (CR)
- tab_health.go: sort settings keys for deterministic display (CR)

Assisted-By: 🤖 Claude Code
devin-ai-integration[bot]

This comment was marked as resolved.

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 9, 2026
Applied fix from bot review comment:
- Comment #3518574788: add missing d.keys.Retry handler in handleKeyPress

Assisted-By: 🤖 Claude Code
rhuss added a commit that referenced this pull request Jul 9, 2026
Applied fix from bot review comment:
- Comment #3518574836: remove unreachable v==0 branch in sparkline rendering

Assisted-By: 🤖 Claude Code
devin-ai-integration[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 11, 2026
…27)

Tests used the old 'endpoint' JSON field name but config.go was renamed
to 'gateway_endpoint' in commit 9b43455. Update all test fixtures.

Assisted-By: 🤖 Claude Code

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +1051 to +1053
func (st *SandboxTab) execScrollUp(n int) {
st.execScrollOffset -= n
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Scrolling up in the command history panel accumulates unbounded offset, requiring excessive scrolling down to return

The scroll-up handler decrements the offset without any lower bound (execScrollUp at examples/oshell/tab_sandbox.go:1052), so the offset can grow arbitrarily negative even though the rendering clamps the visible start position to zero.

Impact: After scrolling up many times past the top of the command history, the user must scroll down the same excessive number of times before the view starts moving again.

Unbounded negative offset in execScrollUp

execScrollOffset is always <= 0 (clamped in execScrollDown at line 1057). execScrollUp subtracts n without checking a lower bound. The rendering code at examples/oshell/tab_sandbox.go:1167-1173 computes start = total - viewportHeight + st.execScrollOffset and clamps start >= 0, so the display is correct. However, the offset itself keeps accumulating. For example, if the user scrolls up 100 times with 3 lines of history, execScrollOffset becomes -300. They then need to scroll down 300/n times before the offset reaches 0 and auto-scroll resumes. The fix is to clamp execScrollOffset so it never goes below -(total - viewportHeight) (or 0 if total <= viewportHeight).

Prompt for agents
In examples/oshell/tab_sandbox.go, the execScrollUp method at line 1051-1053 decrements execScrollOffset without a lower bound. The offset should be clamped so it never goes below the negative of (totalHistoryLines - viewportHeight). However, execScrollUp doesn't have access to the total line count or viewport height. Consider either: (1) passing the current history line count and viewport height into execScrollUp so it can clamp, (2) clamping the offset in renderExecPopup after computing total and viewportHeight (around line 1167), or (3) storing the last-known total/viewport and clamping in execScrollUp against those cached values.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Implement a full-screen Bubble Tea TUI that demonstrates the OpenShell
SDK for Go. Four tabbed views (Sandboxes, Providers, Services, Gateway)
exercise 10+ SDK sub-client methods including Watch, Exec, and Health.

Key features:
- Live sandbox table with Watch API, create/delete dialogs, and
  integrated exec popup for running commands in sandboxes
- OIDC lazy authentication with browser-based login flow
- Gateway health tab with latency sparkline (30 measurements)
- Structured logging via custom slog.Handler (ring buffer + file)
- Demo mode using the SDK's fake client for zero-dependency demos
- Connection management with exponential backoff and manual retry

Assisted-By: 🤖 Claude Code
@rhuss
rhuss force-pushed the 018-sdk-dashboard-tui branch from dad4d2f to c75144b Compare July 11, 2026 05:50
@rhuss
rhuss merged commit 580d763 into main Jul 11, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants