GoogleCloudPlatform / GoogleCloudPlatform/scion
feat: support tmux -f ~/.tmux.conf when launching agent sessions
- Dominant language
- Go
- Stars
- 1.7k
- Forks
- 263
- Avg merge
- 7h 6m
- Merged PRs (30d)
- 447
Description
# Support tmux configuration files in agent containers
## Description
### Problem
User tmux configurations (prefix key, mode-keys, custom bindings) are ignored when Scion launches agent containers, even when the config file exists at `~/.tmux.conf` inside the container. This affects user experience when interacting with agents via `scion attach`.
### Current Behavior
Scion hardcodes the tmux invocation in `pkg/runtime/common.go:413-415`:
```go
tmuxCmd := fmt.Sprintf(
"tmux new-session -d -s scion -n agent %s \\; set-option -g window-size latest \\; new-window -t scion -n shell \\; select-window -t scion:agent \\; attach-session -t scion",
cmdLine,
)
```
This starts tmux **without the `-f` flag**, so tmux uses its built-in defaults:
- `prefix C-b` (not user's preferred `C-a`)
- `mode-keys emacs` (not user's preferred `vi`)
- No custom keybindings or settings
### Expected Behavior
When a user has a tmux config file at `~/.tmux.conf` (either baked into their custom image or synced via harness configs), tmux should load and use it.
### Reproduction Steps
1. **Create custom Dockerfile** with user's tmux config:
```dockerfile
FROM _________2187.dkr.ecr.us-east-1.amazonaws.com/scion/scion-base:latest
# ... existing scion-pi setup ...
USER scion
COPY --chown=scion:scion tmux.conf /home/scion/.tmux.conf
USER root
```
2. **Build and push image** to ECR
3. **Start agent** using custom image:
```bash
scion start test-agent "Simple task"
```
4. **Attach to agent**:
```bash
scion attach test-agent
```
5. **Check tmux settings**:
```bash
tmux show-options -g prefix # Shows "C-b" (default)
tmux show-options -g mode-keys # Shows "emacs" (default)
```
6. **Verify config exists**:
```bash
cat ~/.tmux.conf | grep "prefix C-a" # Config is present
```
**Result**: Config file exists but is not loaded by tmux.
---
## Investigation & Root Cause
### 1. Primary Issue: Missing `-f` Flag
The tmux command in `pkg/runtime/common.go` and `pkg/runtime/k8s_runtime.go` does not include `-f ~/.tmux.conf`:
**Current**:
```bash
tmux new-session -d -s scion -n agent ...
```
**Should be**:
```bash
tmux -f ~/.tmux.conf new-session -d -s scion -n agent ...
```
### 2. Attempted Workarounds
#### Workaround A: Manual Reload (Doesn't Persist)
```bash
tmux source-file ~/.tmux.conf
```
- ✅ Works temporarily
- ❌ Must be run manually after attaching
- ❌ Doesn't apply to new windows/panes created before reload
#### Workaround B: Post-Start Hook (Timing Issues)
Added hook at `/etc/scion/hooks/post-start.d/10-reload-tmux-config`:
```bash
#!/bin/bash
if command -v tmux >/dev/null 2>&1 && [ -f "$HOME/.tmux.conf" ]; then
tmux source-file "$HOME/.tmux.conf" 2>/dev/null || true
fi
```
**Result**:
- ✅ Hook executes (confirmed in logs: `Running post-start hooks...`)
- ❌ Config not successfully reloaded
- **Root cause**: Hook runs too early (before tmux fully initializes) or in wrong environment (can't access tmux socket)
#### Workaround C: Harness Config Home Files (Doesn't Work in Hub Mode)
Placing config in `~/.scion/harness-configs/pi-sonnet/home/.tmux.conf`:
- ✅ Works in `--no-hub` local mode
- ❌ **Not synced in Hub mode** (related to issue #101)
### 3. Related Issues
This issue is related to:
- **#101** [CLOSED] "Hub-dispatched agents do not apply harness config or template volumes" - harness home files aren't synced in Hub mode
- **#257** [CLOSED] "sciontool's chownRecursive aborts on read-only bind mounts" - permission issues with home directory files
- **#87** [OPEN] "Harness home directories should exist before sync into non-root homes" - precondition for home file sync
- **#212** [OPEN] "default_harness_config is not respected after grove is init" - broader harness config issues
---
## Proposed Solutions
### Solution 1: Add `-f ~/.tmux.conf` Flag (Preferred)
**Modify** `pkg/runtime/common.go` line 413:
```diff
tmuxCmd := fmt.Sprintf(
- "tmux new-session -d -s scion -n agent %s \\; ...",
+ "tmux -f ~/.tmux.conf new-session -d -s scion -n agent %s \\; ...",
cmdLine,
)
```
**Also update** `pkg/runtime/k8s_runtime.go` with same change.
**Benefits**:
- ✅ Simple one-line change
- ✅ Respects user preferences
- ✅ Standard tmux behavior
- ✅ No breaking changes (if file missing, tmux falls back to defaults)
**Fallback safety**: If `~/.tmux.conf` doesn't exist, tmux silently uses defaults.
### Solution 2: Make Hook Timing Reliable (Alternative)
Document how to make post-start hooks work reliably with tmux:
- Add `$HOME` environment to hook execution
- Ensure hook runs after tmux socket is available
- Add retry logic in hook system
**Benefits**:
- ✅ More flexible (works for other config files)
- ❌ More complex
- ❌ Timing still tricky
### Solution 3: Configuration Option (Most Flexible)
Add harness config option:
```yaml
# ~/.scion/harness-configs/pi-sonnet/config.yaml
tmux:
config_file: ~/.tmux.conf # or null to use defaults
options:
- "set-option -g prefix C-a"
- "setw -g mode-keys vi"
```
**Benefits**:
- ✅ Most flexible
- ✅ Doesn't require baking config into image
- ❌ Most complex to implement
- ❌ Yet another config layer
---
## Impact & Use Cases
### Who This Affects
**Current workaround** for affected users: Use `--no-hub` mode, which loses Hub features (secrets management, web UI, broker coordination).
**Affected users**:
1. **Power users** with muscle memory for custom tmux keybindings
2. **Teams** standardizing on specific tmux configs across agents
3. **Users with accessibility needs** requiring specific keybindings
4. **Vim users** who expect vi-mode in copy/paste operations
### Real-World Scenario
User has Ctrl-a prefix and vi-mode in their local tmux. When they `scion attach` to debug an agent, they:
- Press `Ctrl-a d` to detach → nothing happens (prefix is still Ctrl-b)
- Enter copy mode → emacs keys, not vi keys
- Repeatedly hit wrong keybindings, slowing down debugging
---
## Testing
### Test Case 1: Config File Present
```bash
# In Dockerfile
COPY tmux.conf /home/scion/.tmux.conf
# After agent starts
$ tmux show-options -g prefix
prefix C-a # ✅ Should show user's custom prefix
$ tmux show-options -g mode-keys
mode-keys vi # ✅ Should show user's custom mode
```
### Test Case 2: No Config File
```bash
# Don't add tmux.conf to image
# After agent starts
$ tmux show-options -g prefix
prefix C-b # ✅ Should fall back to defaults
$ tmux show-options -g mode-keys
mode-keys emacs # ✅ Should fall back to defaults
```
### Test Case 3: Invalid Config
```bash
# Add broken tmux.conf
COPY broken-tmux.conf /home/scion/.tmux.conf
# tmux should fail gracefully with error message
# Container should still start (don't fail hard on bad config)
```
---
## Implementation Notes
### Files to Modify
1. **`pkg/runtime/common.go`** (line ~413):
```go
tmuxCmd := fmt.Sprintf(
"tmux -f ~/.tmux.conf new-session -d -s scion -n agent %s \\; ...",
cmdLine,
)
```
2. **`pkg/runtime/k8s_runtime.go`** (similar location):
Same change for Kubernetes runtime
3. **Tests to update**:
- `pkg/runtime/common_test.go` - update expected tmux commands
- `pkg/runtime/k8s_runtime_tmux_test.go` - same
### Backward Compatibility
✅ **No breaking changes**: If `~/.tmux.conf` doesn't exist, tmux silently uses built-in defaults (standard tmux behavior).
### Documentation to Update
- Harness configuration docs: mention users can bake tmux.conf into images
- Container build docs: example of adding custom tmux config
- Troubleshooting: note about `-f` flag for debugging tmux issues
---
## Environment
- **Scion version**: `main` branch (commit d20a238+)
- **Runtime**: Apple container CLI
- **Harness**: pi
- **OS**: macOS (Apple container)
- **Image**: Custom `scion-pi:latest` with tmux.conf baked in
---
## Additional Context
### Example Custom Config
User's `~/.tmux.conf` that should be loaded:
```bash
# Prefix
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# Vi mode
setw -g mode-keys vi
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi y send-keys -X copy-selection
# Splits
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
```
### Logs Showing Hook Execution
From `scion logs test-agent`:
```
2026-06-01 18:43:37 [sciontool] [INFO] Running post-start hooks...
```
Hook was called but config not loaded (timing/environment issue).
---
## Questions for Maintainers
1. **Is Solution 1** (adding `-f ~/.tmux.conf`) acceptable? Any concerns about the change?
2. **Should we also** support a `TMUX_CONF` env var override?
```bash
TMUX_CONF=/custom/path/tmux.conf scion start ...
```
3. **Post-start hooks**: What's the intended use case? Our hook executes but can't reliably interact with tmux. Is this expected?
4. **Hub mode vs local mode**: Related to #101 - is there a roadmap for making harness home files work in Hub mode, or should users bake configs into images?
---
## Workaround (Until Fixed)
For users who need custom tmux configs NOW:
### Option A: Use --no-hub Mode
```bash
scion start --no-hub agent-name "task"
```
- ✅ Harness configs work
- ❌ Lose Hub features (secrets, web UI, coordination)
### Option B: Manually Reload After Attach
```bash
scion attach agent-name
# Then inside container:
tmux source-file ~/.tmux.conf
```
- ✅ Works immediately
- ❌ Must do every time
- ❌ Doesn't affect windows created before reload
### Option C: Alias in Shell RC
Add to image's `~/.zshrc` or `~/.bashrc`:
```bash
alias ta='tmux source-file ~/.tmux.conf && echo "Tmux config reloaded"'
```
Then run `ta` after attaching.
---
## References
- tmux documentation: `man tmux`, specifically `-f file` flag
- Scion hook system: `pkg/sciontool/hooks/lifecycle.go`
- Tmux invocation: `pkg/runtime/common.go:413-415`
- Related PR #76 (mentioned in #87): Precreate harness home directories
---
**Would appreciate any guidance on the preferred solution!** Happy to submit a PR for Solution 1 if that direction makes sense.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.