Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ Sessions:

Flags (passed after the agent name):
-f, --no-firewall Disable network firewall
--no-tmux Run the agent without the tmux wrapper (better for
Kitty-protocol TUIs like Pi; loses tmux status bar,
workspace switcher, and tmux-based session resume)
-r, --read-only Mount workspace as read-only
-n, --no-env Don't pass host environment variables
--name SESSION Name this session (resumes if it already exists)
Expand Down Expand Up @@ -300,6 +303,7 @@ func runAgent(agentName string, passthrough []string) {
WorkspaceOverride: flags.Workspace,
EnvProfile: flags.EnvProfile,
NoFirewall: flags.NoFirewall,
NoTmux: flags.NoTmux,
ReadOnly: flags.ReadOnly,
NoEnv: flags.NoEnv,
Resume: flags.Resume,
Expand Down Expand Up @@ -395,6 +399,7 @@ func runAgent(agentName string, passthrough []string) {

type parsedFlags struct {
NoFirewall bool
NoTmux bool
ReadOnly bool
NoEnv bool
Resume bool
Expand Down Expand Up @@ -432,6 +437,8 @@ func parseRunFlags(passthrough []string, defaults config.DefaultFlags) parsedFla
switch arg {
case "-f", "--no-firewall":
f.NoFirewall = true
case "--no-tmux":
f.NoTmux = true
case "-r", "--read-only":
f.ReadOnly = true
case "-n", "--no-env":
Expand Down
2 changes: 2 additions & 0 deletions cmd/run_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ func TestParseRunFlags_BooleanFlags(t *testing.T) {
}{
{"short no-firewall", []string{"-f"}, func(f parsedFlags) bool { return f.NoFirewall }},
{"long no-firewall", []string{"--no-firewall"}, func(f parsedFlags) bool { return f.NoFirewall }},
{"no-tmux", []string{"--no-tmux"}, func(f parsedFlags) bool { return f.NoTmux }},
{"no-tmux default off", []string{}, func(f parsedFlags) bool { return !f.NoTmux }},
{"short read-only", []string{"-r"}, func(f parsedFlags) bool { return f.ReadOnly }},
{"long read-only", []string{"--read-only"}, func(f parsedFlags) bool { return f.ReadOnly }},
{"short no-env", []string{"-n"}, func(f parsedFlags) bool { return f.NoEnv }},
Expand Down
6 changes: 6 additions & 0 deletions internal/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Options struct {
WorkspaceOverride string
EnvProfile string
NoFirewall bool
NoTmux bool
ReadOnly bool
NoEnv bool
Resume bool
Expand Down Expand Up @@ -398,6 +399,11 @@ func AgentContainer(rt container.Runtime, opts Options) (int, error) {
if opts.ResumeToken != "" {
args = append(args, "-e", "EXITBOX_RESUME_TOKEN="+opts.ResumeToken)
}
if opts.NoTmux {
// Run the agent directly, without the tmux wrapper, so Kitty-protocol
// TUIs (e.g. Pi) own the terminal and modified keys work natively.
args = append(args, "-e", "EXITBOX_NO_TMUX=1")
}
if opts.EnvProfile != "" {
args = append(args, "-e", "EXITBOX_ENV_PROFILE="+opts.EnvProfile)
}
Expand Down
4 changes: 4 additions & 0 deletions static/build/docker-entrypoint
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,10 @@ should_exec_raw() {

should_start_tmux() {
[[ -n "$AGENT" ]] || return 1
# Opt-out: run the agent directly (no tmux wrapper) so TUIs that speak the
# Kitty keyboard protocol (e.g. Pi) own the terminal and modified keys like
# Shift+Enter work natively, with no tmux key re-encoding in the way.
[[ -z "${EXITBOX_NO_TMUX:-}" ]] || return 1
[[ -z "${TMUX:-}" ]] || return 1
[[ -t 0 && -t 1 ]] || return 1
command -v tmux >/dev/null 2>&1 || return 1
Expand Down
Loading