Skip to content

feat: mark remote sessions as experimental#17

Merged
gavin-jeong merged 62 commits intomasterfrom
feat/remote-experimental
Apr 2, 2026
Merged

feat: mark remote sessions as experimental#17
gavin-jeong merged 62 commits intomasterfrom
feat/remote-experimental

Conversation

@gavin-jeong
Copy link
Copy Markdown
Collaborator

Summary

  • Add [R·exp] badge for remote sessions (was [R])
  • Show (experimental) label in remote session progress view
  • Update filter hint to "Remote sessions (exp)"
  • Add remote badge to help modal

Test plan

  • Verify [R·exp] badge renders on remote sessions in session list
  • Check help modal includes the new badge description
  • Confirm is:remote filter hint shows "(exp)" suffix
  • Verify remote progress view shows "(experimental)" after title

…ons, badge toggle

- Unified config file (~/.config/ccx/config.yaml) with keybindings, preferences, and shortcuts
- Number key shortcuts (1-9) scoped by view + focus side with sensible defaults
- View state persistence: group/preview/view mode, detail level, split ratio auto-saved on quit
- Memory import from worktree (M action) and memory removal (X action)
- Badge toggle via :badge:toggle command, persisted in preferences
- Worktree detection fallback for cleaned-up worktrees
- Conversation detail:text/tool/hook commands
- Live preview restore fix (async pane lookup from Update path)
- Help modal alignment fix (wider modal, shortcuts section)
- Diff rendering for Edit/Write tool blocks
…ments, fork action

Phase 1 - Smart chain-mode filter:
- In chain/tree/fork/repo group modes, filter preserves parent-child relationships
- Parent match keeps all children visible; child match keeps parent visible

Phase 2 - Base-project group mode (group:repo):
- Groups sessions by base repository using git worktree info
- ResolveBaseRepo reads .git file to find main repo (not just path matching)
- Works for external worktrees outside the repo directory
- Uses configurable worktreeDir from preferences

Search/filter improvements:
- proj:<name> filter for sessions
- Conversation filter now includes tool names (tool:Read, tool:Bash)
- Selection preserved when clearing filter (Esc)
- Filter term persisted across restarts

Other:
- Fork session action (F in actions menu)
- Editor input mode persistence (ctrl+e toggles, saved in preferences)
- Memory import hint shows for all worktree sessions
- Config explorer shows KEYMAPS and SHORTCUTS categories
- Badge toggle, config:edit, detail commands, fillKeymapDefaults on save
…rrow, design docs

Phase 3 - Worktree alignment:
- :worktree:align (:wt:align) detects worktrees not under configured dir
- Lists misaligned worktrees via git worktree list --porcelain
- Moves selected worktrees via git worktree move
- Updates in-memory session paths after move

Phase 4 - Session/worktree creation:
- :new (:n) opens new Claude session in project dir (tmux window or exec)
- :worktree:new (:wt:new) <branch> creates git worktree + new session
- NewWindowClaudeNew tmux helper for fresh sessions

Smart left arrow:
- In live pane preview, left arrow at cursor column 0 escapes to list
- Uses tmux display-message #{cursor_x} to detect cursor position
- Normal left arrow forwarded when cursor can move

Design documents:
- docs/design-image-rendering.md - Kitty graphics protocol modal
- docs/design-remote-execution.md - K8s pod execution architecture
- docs/design-multi-session-orchestration.md - Multi-session DAG orchestration
…flow

- Press x → n on any session to create a new session in the same project
- Prompted for branch name: enter name = create worktree + new session,
  empty = new session in main project dir
- Separate from w (worktree) which moves existing session
- Also supports :new <path> command for arbitrary directories
- Help line shows context-sensitive hint for the input prompt
- Auto-refresh session list 2s after spawning new session/worktree
- delayedRefreshMsg triggers doRefresh() to pick up new sessions
- Non-git projects skip branch prompt, create session directly
- Git repos show branch prompt (worktree-first workflow)
When task directory files are cleaned up after completion, the task
preview now falls back to parsing TaskCreate/TaskUpdate tool_use
entries from the JSONL conversation data. Shows "(from conversation)"
label to distinguish from active/ongoing tasks.
New package internal/remote/ for executing Claude Code on K8s pods:
- config.go: RemoteConfig with defaults and validation
- pod.go: Pod spec generation, create/delete/wait via CLI
- sync.go: Config tarball (CLAUDE.md, settings, memory) upload
- stream.go: JSONL streaming from pod via logs -f
- session.go: Full lifecycle orchestrator (auth, pod, config, stream)

TUI integration:
- :remote:start <context> <repo> [branch] [prompt] - create pod and stream
- :remote:stop - stop session and delete pod
- Stream content displayed in session preview pane
- Auth via macOS Keychain OAuth token injection

Also: moved keymaps under keymaps section in config.yaml
…sync

Remote execution improvements:
- Sync local workdir to pod via tar (respects .gitignore via git ls-files)
- Falls back to git clone when no local dir specified
- Configurable env vars (env_vars map) and local env mirroring (mirror_env list)
- Full Claude config sync: settings, memory, skills, agents, commands,
  contexts, rules, hooks, and project-specific config
- Usage: :remote:start <context> [prompt] (uses selected session's project)

Config example in config.yaml:
  remote:
    env_vars:
      AWS_PROFILE: mesg-prod
      KUBECONFIG: /path/to/kubeconfig
    mirror_env: [AWS_PROFILE, AWS_REGION, GITHUB_TOKEN]
Redesigned remote execution:
- Single container pod (sleep infinity) — exec into it for setup and Claude
- Progress reporting during each step (auth, pod create, install, sync)
- Interactive Claude via tea.ExecProcess (takes over terminal like $EDITOR)
- :remote:start [prompt] — uses current context, selected session for resume
- :remote:attach — reattach to running remote Claude
- :remote:stop — delete pod
- Auto-detects current context (no arg needed)
- Session JSONL synced for --resume support
- Full config sync: skills, agents, hooks, memory, commands, contexts, rules
Remote sessions now appear as first-class items in the session list:
1. :remote:start creates pod and inserts virtual [LIVE] session at top
2. Preview pane tracks setup progress (auth, pod, install, sync)
3. Once Claude starts, JSONL output streams to live preview
4. :remote:attach opens interactive Claude (takes over terminal)
5. :remote:stop deletes pod and removes virtual session

Setup steps channel tracked separately from stream channel.
Virtual sessions have IsRemote=true, RemotePodName, RemoteStatus fields.
- Remote sessions saved to ~/.config/ccx/remote-sessions.yaml
- Restored as virtual items on ccx startup
- Status updates persisted (starting, running, stopped, failed)
- Removed from disk on :remote:stop
- Filterable with / search: is:remote, pod name, status
- :remote:stop on saved/restored sessions (no active in-memory session)
  now reads saved config to delete the pod from the cluster
- Works on selected remote session even after ccx restart
- Added is:remote to search filter hints in help modal
- R key in actions menu starts remote execution for selected session
- Shows R:remote hint in actions hint box
- Auto-cleanup on startup: checks pod phase via cluster API
  - Running/Pending pods kept
  - Succeeded/Failed/Unknown pods removed from saved sessions
  - Cluster unreachable: session kept (no blind deletion)
- Added PodPhase() to remote/pod.go
…re start

1. Default image changed from node:22-slim to ubuntu:24.04
   - Installs Node.js + git + Claude Code in the pod setup step
2. Remote sessions no longer show [LIVE] badge — show [R] (purple) instead
3. Before starting remote, shows confirmation with context/namespace
   - "Remote → context/namespace? (y/n)" — press y to proceed, any other key cancels
…m, correct selection

Issues fixed:
1. Confirmation now shows "Start remote on <context>/<namespace>? (y/n)"
   with the actual cluster context prominently displayed
2. Session info (project path, session ID) captured at confirm time,
   not re-read after y press (prevents wrong session pickup)
3. Guard prevents creating multiple remote sessions — must :remote:stop first
4. Progress steps accumulate correctly (previous shown as ✓, current as ◉)
5. Preview updates use helper to check selected session matches
6. Cleaned up duplicate code paths in the full rewrite
Preview flickering fix:
- Remote preview only calls SetContent when cacheKey changes
- Render path skips re-setting content for remote sessions entirely
- CacheKey set to "remote:<id>" prevents conversation loader from overriding

Delete persistence fix:
- Deleting remote session via 'd' action now also:
  - Stops active remote session (if matching)
  - Deletes pod from cluster (for saved sessions)
  - Removes from remote-sessions.yaml
- Works for both active and persisted remote sessions
Remote sessions now have their own preview type (sessPreviewRemote):
- Automatically activated when a remote session is selected
- Never overridden by conversation/stats/memory preview loading
- Resize only updates viewport dimensions, doesn't reload content
- Skipped in tab cycling (like sessPreviewLive)
- Content managed exclusively by remote progress/stream handlers
- Enter on a remote session opens interactive Claude (takes over terminal)
- L (Live) on a remote session also attaches interactively
- Works for both active sessions and saved/restored ones
- Saved sessions use stored context/namespace/pod to build exec command
- Returns to ccx when Claude exits (pod stays running)
Remote sessions now support conversation, stats, memory, and tasks
preview modes — same as local sessions:

- Streamed JSONL output written to temp file as it arrives
- Virtual session's FilePath set to temp file path
- During setup: shows progress view (sessPreviewRemote)
- Once streaming: normal preview modes work (tab to cycle)
- Conversation preview auto-refreshes on new data
- Temp file cleaned up on :remote:stop
- L key on remote sessions opens/refreshes preview (not attach)
- Enter key still attaches interactively
- claude_args config: extra CLI args for remote Claude
  (e.g. --model, --allowedTools, --permission-mode)
- buildClaudeCmd helper used by both streaming and attach
- Config example: claude_args: ["--permission-mode", "bypassPermissions"]
Folded summaries:
- Bash: $ command (yellow, with description prefix)
- Read: ~/path L10-30 (with line range)
- Grep: /pattern/ path glob
- Glob: pattern path
- Agent: subagent_type  description

Expanded view:
- Bash: # description + $ command lines (multi-line support)

Updated tests and golden files for new tool formatting.
- text → compact (text only)
- tool → standard (text + tools)
- hook → verbose (text + tools + hooks)

Commands: :detail:compact, :detail:standard, :detail:verbose
Old names still work as aliases (detail:text, detail:tool, detail:hook)
Status bar shows COMPACT/STANDARD/VERBOSE
Shortcuts updated: 1=compact, 2=standard, 3=verbose
conv_detail_level persisted across restarts (already was)
…changes

- Number key shortcuts (1:conv 2:stats etc.) shown in the session help line
- Changing group mode (Tab/G) preserves the active search filter
- Filter is saved before rebuild and reapplied to the new list
Add [R·exp] badge, (experimental) label in progress view, and (exp)
suffix in filter hints to signal remote session support is experimental.
@gavin-jeong gavin-jeong merged commit 35bf9c7 into master Apr 2, 2026
3 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