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
17 changes: 13 additions & 4 deletions bin/agentbox
Original file line number Diff line number Diff line change
Expand Up @@ -3126,16 +3126,25 @@ class Renderer:
supervisor on a live box: `jq: Cannot index array with string ("0")`
in a restart loop, with the seeded session showing up as one named
"0" and never starting. Defaults mirror the module's per-session
options (modules/agent-box.nix.in: skipPermissions/remoteControl
default true, everything else null/[]).
options (modules/agent-box.nix.in): skipPermissions defaults true;
remoteControl defaults true except for codex, which defaults false
since remote control there is a different program, not a TUI flag
(issue #623); everything else null/[].
"""
sessions = {}
for sname in sorted(u.sessions):
s = u.sessions[sname] or {}
agent = s.get("agent") or u.agent
sessions[sname] = {
"agent": s.get("agent") or u.agent,
"agent": agent,
"skipPermissions": bool(s.get("skipPermissions", True)),
"remoteControl": bool(s.get("remoteControl", True)),
# codex's remote control is a different PROGRAM entirely
# (the app-server pairing daemon, not a TUI flag), so a
# seeded codex session left unset now defaults to the
# interactive TUI (issue #623), mirroring
# sessionOpts.remoteControl's default in agent-box.nix.in.
# Every other harness keeps the old default.
"remoteControl": bool(s.get("remoteControl", agent != "codex")),
"extraArgs": list(s.get("extraArgs") or []),
# null → the supervisor derives "<user>-<session>@<host>"
# at start time.
Expand Down
96 changes: 85 additions & 11 deletions modules/agent-box.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 18 additions & 5 deletions modules/agent-box.nix.in
Original file line number Diff line number Diff line change
Expand Up @@ -1145,7 +1145,7 @@ let
# One session = one agent CLI in one tmux session. These options are the
# FIRST-BOOT SEED only (see users.<name>.sessions); at runtime the same
# fields live as JSON in ~/.config/agent-box/sessions.json.
sessionOpts = {
sessionOpts = { config, ... }: {
options = {
agent = lib.mkOption {
type = lib.types.nullOr (lib.types.enum (sessionKinds supportedAgents));
Expand All @@ -1169,7 +1169,14 @@ let
};
remoteControl = lib.mkOption {
type = lib.types.bool;
default = true;
# codex's remote control is a different PROGRAM entirely (the
# app-server pairing daemon, not a TUI flag), so a seeded codex
# session left unset now defaults to the interactive TUI, the same
# default the CLI and web add-session writers use (issue #623).
# Every other harness keeps the old default. "codex" falls back to
# cfg.agent so a null (box-default) agent is judged the same way
# sessionsSeedFile itself resolves it.
default = (if config.agent != null then config.agent else cfg.agent) != "codex";
description = "Make the session drivable from the agent's apps (see users.<name>.remoteControl).";
};
remoteControlName = lib.mkOption {
Expand Down Expand Up @@ -1222,7 +1229,7 @@ let
};
};

userOpts = { name, ... }: {
userOpts = { name, config, ... }: {
options = {
sessions = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule sessionOpts);
Expand Down Expand Up @@ -1302,11 +1309,17 @@ let
};
remoteControl = lib.mkOption {
type = lib.types.bool;
default = true;
# See sessionOpts.remoteControl (issue #623): codex's remote control
# is the app-server pairing daemon, not a TUI flag, so a "main"
# session seeded for codex now defaults to false (the TUI) unless
# this is set explicitly. Every other harness keeps `true`.
default = (if config.agent != null then config.agent else cfg.agent) != "codex";
description = ''
Make the session drivable from the agent's desktop and mobile apps.
Default `true` because "drive it from your phone" is one of the
module's headline features.
module's headline features -- except for codex, which defaults to
`false` (see below) since remote control there means a different
program altogether.

Set false to disable remote-app control for this user — then the
agent is only reachable through the local tmux session (or the
Expand Down
30 changes: 26 additions & 4 deletions modules/src/session-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ usage() {
echo "Stop a session to free a slot. A refused start exits 75; retry is safe."
echo " agent-box-session peers"
echo " agent-box-session add [NAME] [--harness HARNESS] [--profile PROFILE]"
echo " [--cwd DIR]"
echo " [--cwd DIR] [--remote-control true|false]"
echo " [--prompt TEXT] [--resume-prompt TEXT] [--ephemeral]"
echo " [-- EXTRA_ARGS...]"
echo " agent-box-session rm NAME"
Expand Down Expand Up @@ -91,6 +91,11 @@ usage() {
echo "fail to start."
echo "--prompt kicks the session off with a task (first spawn only); a later"
echo "respawn resumes the prior transcript instead of redoing it."
echo "--remote-control defaults to true, except for codex where it defaults to"
echo "false: claude's remote control is a flag on its ordinary TUI, but codex's"
echo "replaces the TUI outright with the app-server pairing daemon, so a plain"
echo "codex session (a profile, or --harness codex with none) now opens the"
echo "TUI unless this is passed explicitly."
echo "--ephemeral marks a ONE-SHOT session: parking it (a clean agent exit, or"
echo "'stop') delists it outright, because nobody is going to resume it. A"
echo "CRASH still parks nothing and leaves the post-mortem shell attachable."
Expand Down Expand Up @@ -456,7 +461,7 @@ case "$cmd" in
*) name="$1"; shift; valid_new_name "$name" || { usage >&2; exit 2; } ;;
esac
harness="$DEFAULT_AGENT"; cwd=""; prompt=""; rprompt=""; has_prompt=0; has_rprompt=0
profile=""; has_harness=0; ephemeral=0
profile=""; has_harness=0; ephemeral=0; remote_control=""
while [ $# -gt 0 ]; do
case "$1" in
--harness) harness="${2:?--harness needs a value}"; has_harness=1; shift 2 ;;
Expand All @@ -472,6 +477,13 @@ case "$cmd" in
;;
--profile) profile="${2:?--profile needs a value}"; shift 2 ;;
--cwd) cwd="${2:?--cwd needs a value}"; shift 2 ;;
--remote-control)
case "${2:?--remote-control needs 'true' or 'false'}" in
(true|false) remote_control="$2" ;;
(*) echo "agent-box-session: --remote-control must be 'true' or 'false'" >&2
exit 2 ;;
esac
shift 2 ;;
--prompt) prompt="${2?--prompt needs a value}"; has_prompt=1; shift 2 ;;
--resume-prompt) rprompt="${2?--resume-prompt needs a value}"; has_rprompt=1; shift 2 ;;
--ephemeral) ephemeral=1; shift ;;
Expand Down Expand Up @@ -561,6 +573,16 @@ case "$cmd" in
pargs+=("$parg")
done < <("$JQ" -j '.args[] + "\u0000"' <<<"$pjson")
fi
# codex's remote control is a different PROGRAM entirely - the app-server
# pairing daemon, not a TUI flag (see supervisor.sh) - so an unqualified
# codex session now opens the TUI by default (issue #623); claude's own
# remote control is just a flag on its ordinary TUI and keeps its old
# default. Resolved AFTER the profile above, since a profile can change
# $harness. An explicit --remote-control always wins.
if [ -z "$remote_control" ]; then
remote_control=true
[ "$harness" = codex ] && remote_control=false
fi
case " $AGENTS " in
(*" $harness "*) ;;
(*) echo "harness '$harness' is not available (available: $AGENTS)" >&2; exit 2 ;;
Expand Down Expand Up @@ -597,8 +619,8 @@ case "$cmd" in
registry_edit --arg n "$name" --arg a "$harness" --arg c "$cwd" \
--arg p "$prompt" --arg pp "$has_prompt" \
--arg rp "$rprompt" --arg rpp "$has_rprompt" --arg bid "$bid" \
--arg prof "$profile" --arg eph "$ephemeral" \
'.sessions[$n] = ({agent: $a, skipPermissions: true, remoteControl: true,
--arg prof "$profile" --arg eph "$ephemeral" --argjson rc "$remote_control" \
'.sessions[$n] = ({agent: $a, skipPermissions: true, remoteControl: $rc,
remoteControlName: null,
workingDirectory: (if $c == "" then null else $c end),
extraArgs: $ARGS.positional,
Expand Down
Loading