feat: forward agent style via native CLI config and terminal title
lint / lint (push) Successful in 1m33s
test / unit (pull_request) Successful in 34s
test / integration (pull_request) Successful in 21s

Replace prompt-injection for display identity with native UI wiring:
- Claude: writes a statusline shell script + custom theme JSON, wired up
  via settings.json so label/color show in the status bar and theme
- Codex: writes [tui] block into codex-config.toml (status_line,
  terminal_title, dark-ansi theme)
- Both backends set the terminal title via ANSI OSC 0 escape before
  exec-ing the agent when a label is present

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 00:00:19 -04:00
parent 0a564bb41e
commit 20cfafcc4d
9 changed files with 204 additions and 65 deletions
+11 -3
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import subprocess
import shlex
from typing import Callable
from typing import cast
@@ -22,12 +23,14 @@ class DockerBottle(Bottle):
*,
agent_command: str = "claude",
agent_prompt_mode: PromptMode = "append_file",
terminal_title: str = "",
):
self.name = container
self._teardown = teardown
self.prompt_path = prompt_path_in_container
self._agent_prompt_mode = agent_prompt_mode
self.agent_command = agent_command
self.terminal_title = terminal_title
self.agent_provider_template = (
"codex" if agent_command == "codex" else "claude"
)
@@ -47,9 +50,14 @@ class DockerBottle(Bottle):
return cmd
def exec_agent(self, argv: list[str], *, tty: bool = True) -> int:
return subprocess.run(
self.agent_argv(argv, tty=tty), check=False,
).returncode
agent_argv = self.agent_argv(argv, tty=tty)
if self.terminal_title and tty:
shell_script = (
f"printf '\\033]0;%s\\007' {shlex.quote(self.terminal_title)}; "
f"exec {shlex.join(agent_argv)}"
)
return subprocess.run(["sh", "-lc", shell_script], check=False).returncode
return subprocess.run(agent_argv, check=False).returncode
def exec(self, script: str, *, user: str = "node") -> ExecResult:
# Pipe via stdin to `sh -s` so the caller never has to worry
+1
View File
@@ -175,6 +175,7 @@ def launch(
None,
agent_command=plan.agent_command,
agent_prompt_mode=plan.agent_prompt_mode,
terminal_title=plan.spec.label or plan.spec.agent_name,
)
bottle.prompt_path = provision(plan, bottle)
+11 -3
View File
@@ -20,6 +20,7 @@ from __future__ import annotations
import subprocess
import sys
import time
import shlex
from typing import Mapping, cast
from ...agent_provider import PromptMode, prompt_args
@@ -68,6 +69,7 @@ class SmolmachinesBottle(Bottle):
guest_env: Mapping[str, str] | None = None,
agent_command: str = "claude",
agent_prompt_mode: PromptMode = "append_file",
terminal_title: str = "",
) -> None:
self.name = machine_name
# In-VM path to the agent's prompt file. None when the
@@ -81,6 +83,7 @@ class SmolmachinesBottle(Bottle):
self._guest_env = dict(guest_env or {})
self._agent_prompt_mode = agent_prompt_mode
self.agent_command = agent_command
self.terminal_title = terminal_title
self.agent_provider_template = (
"codex" if agent_command == "codex" else "claude"
)
@@ -128,9 +131,14 @@ class SmolmachinesBottle(Bottle):
UID switches via `runuser -u node --` (not `-l`) so we
avoid login-shell wiring. HOME / USER come from `smolvm
-e` instead, which sets them on the process env."""
return subprocess.run(
self.agent_argv(argv, tty=tty), check=False,
).returncode
agent_argv = self.agent_argv(argv, tty=tty)
if self.terminal_title and tty:
shell_script = (
f"printf '\\033]0;%s\\007' {shlex.quote(self.terminal_title)}; "
f"exec {shlex.join(agent_argv)}"
)
return subprocess.run(["sh", "-lc", shell_script], check=False).returncode
return subprocess.run(agent_argv, check=False).returncode
# smolvm/libkrun can SIGKILL an otherwise-normal exec during
# early-VM provisioning. Retry once after a short settle so
@@ -103,6 +103,7 @@ def launch(
guest_env=plan.guest_env,
agent_command=plan.agent_command,
agent_prompt_mode=plan.agent_prompt_mode,
terminal_title=plan.spec.label or plan.spec.agent_name,
)
bottle.prompt_path = provision(plan, bottle)