Offer T3 Code as the preferred agent, opening a thread in the Panama project, and install it with the desktop

This commit is contained in:
Gabriel Brown committed 2026-10-30 14:58:46 -04:00
1 parent 5af5d7a96b
commit e21a4c24f0
8 files changed
+108 -15

No files matched your search

+40 -5
View File
@@ -10,9 +10,16 @@
# start time, so choosing an agent in Settings takes effect on the next crash
# without restarting anything:
#
# preferredAgent none | claude | codex ("none" is the default: silence)
# preferredAgent none | claude | codex | t3 ("none" is the default: silence)
# agentAutoApprove true -> the agent starts in its own "don't stop to ask"
# mode; false -> its normal prompting mode, untouched.
# T3 Code ignores it: a T3 thread runs in the mode its
# project is set to, which is a choice made inside T3.
#
# claude and codex open in a kitty window. t3 starts a thread in the Panama
# project on the running T3 Code server and brings it up in the desktop app,
# so the investigation lives beside every other thread instead of in a
# terminal of its own.
#
# "none" exits 0 without a word. It is not an error to have no agent; it is the
# shipped state, and a rung that shouted about it would be a rung that gets
@@ -95,8 +102,9 @@ usage() {
cat <<'EOF'
Usage: panama-agent [--prompt "text"]
Opens the agent named by preferredAgent in a terminal, in the Panama checkout.
With no agent chosen, exits silently: choose one on Settings > System > Agents.
Opens the agent named by preferredAgent in the Panama checkout: a terminal for
claude and codex, a thread in the T3 Code app for t3. With no agent chosen,
exits silently: choose one on Settings > System > Agents.
EOF
}
@@ -139,7 +147,7 @@ agent="$(read_setting preferredAgent none)"
auto_approve="$(read_setting agentAutoApprove true)"
case "$agent" in
claude | codex) ;;
claude | codex | t3) ;;
*)
printf 'panama-agent: unsupported preferredAgent: %s\n' "$agent" >&2
printf 'Choose one on Settings > System > Agents.\n' >&2
@@ -148,7 +156,8 @@ case "$agent" in
esac
# Resolved to a path before argv is built, so kitty is never asked to repeat a
# PATH lookup this script has already done more carefully than kitty could.
# PATH lookup this script has already done more carefully than kitty could. T3
# Code's CLI is `t3`, which the desktop app writes into ~/.local/bin.
if ! agent_bin="$(resolve_agent "$agent")"; then
printf 'panama-agent: %s is not installed.\n' "$agent" >&2
printf 'Looked on PATH and in %s.\n' "$HOME/.local/bin" >&2
@@ -156,6 +165,32 @@ if ! agent_bin="$(resolve_agent "$agent")"; then
exit 1
fi
# T3 Code: no terminal. The thread starts on the running server in the
# project whose root is the checkout, with the project's default model, and
# the t3code:// link opens it in the app. `project add` refuses a root that is
# already a project, which is the common case, so its failure is not one. The
# prompt goes over stdin ("-"), so a prompt that begins with a dash is never
# read as a flag. With no prompt there is nothing to start, so the app just
# opens on the project.
if [[ "$agent" == "t3" ]]; then
repair_path
"$agent_bin" project add "$PANAMA_PATH" >/dev/null 2>&1 || true
if [[ -z "$prompt" ]]; then
exec setsid "$agent_bin" app "$PANAMA_PATH"
fi
if ! thread="$(printf '%s' "$prompt" | "$agent_bin" thread start "$PANAMA_PATH" -)"; then
printf 'panama-agent: T3 Code could not start a thread.\n' >&2
printf 'Is the T3 Code server running? Check: systemctl --user status t3code\n' >&2
exit 1
fi
environment_file="${T3CODE_HOME:-$HOME/.t3}/userdata/environment-id"
environment="$(cat "$environment_file" 2>/dev/null || true)"
if [[ -n "$environment" ]]; then
exec setsid xdg-open "t3code://threads/$environment/$thread"
fi
exec setsid "$agent_bin" app "$PANAMA_PATH"
fi
# The per-agent launch table. VERIFIED against the installed binaries' --help on
# 2026-08-25 (claude 2.1.245, codex-cli 0.149.1) -- these flags are not the same
# from release to release, so re-run --help before changing them.
@@ -184,7 +184,8 @@ Singleton {
options: [
{ value: "none", label: "None" },
{ value: "claude", label: "Claude Code" },
{ value: "codex", label: "Codex" }
{ value: "codex", label: "Codex" },
{ value: "t3", label: "T3 Code" }
]
},
{
@@ -205,7 +206,7 @@ Singleton {
{
key: "agentAutoApprove", type: "bool", def: true, group: "agents",
label: "Launched agents approve their own tools",
detail: "Investigations run without permission prompts. The diagnose skill still holds agents to reading rather than fixing, and root still goes through panama-sudo, reason and all"
detail: "Investigations run without permission prompts. T3 Code threads use the mode set on the Panama project in T3 instead. The diagnose skill still holds agents to reading rather than fixing, and root still goes through panama-sudo, reason and all"
},
{
key: "agentUsageClaude", type: "bool", def: true, group: "agents",
@@ -37,8 +37,8 @@ SettingsPage {
// them not to believe the page.
//
// Probed through a LOGIN shell rather than this one. Quickshell is started
// by systemd, whose PATH does not include ~/.local/bin -- where both of
// these usually land -- and a login shell is the environment the launcher
// by systemd, whose PATH does not include ~/.local/bin -- where all three of
// these usually land (T3 Code's CLI is `t3`) -- and a login shell is the environment the launcher
// hands the agent when it spawns a terminal. Asking with the shell's own
// PATH would report "not installed" for an agent that starts perfectly.
property var installed: ({})
@@ -60,7 +60,7 @@ SettingsPage {
running: true
command: ["bash", "-lc",
"for agent in claude codex; do command -v \"$agent\" >/dev/null 2>&1 && printf '%s\\n' \"$agent\"; done"]
"for agent in claude codex t3; do command -v \"$agent\" >/dev/null 2>&1 && printf '%s\\n' \"$agent\"; done"]
stdout: StdioCollector {
onStreamFinished: root.absorbProbe(this.text)
}
@@ -70,6 +70,7 @@ SettingsPage {
switch (value) {
case "claude": return "starred-symbolic";
case "codex": return "utilities-terminal-symbolic";
case "t3": return "view-dual-symbolic";
default: return "notifications-disabled-symbolic";
}
}
@@ -356,6 +356,7 @@ Singleton {
{ label: "AI assistant", detail: "Choose the agent this desktop hands crashes, failed reloads and red health checks to", page: "agents" },
{ label: "Claude Code", detail: "Use Claude Code as the agent the desktop escalates to, and watch its usage", page: "agents" },
{ label: "Codex", detail: "Use Codex as the agent the desktop escalates to, and watch its usage", page: "agents" },
{ label: "T3 Code", detail: "Open a T3 Code thread in the Panama project when the desktop escalates something", page: "agents" },
{ label: "Diagnose crashes", detail: "When a program dumps core, the notification carries a click that opens your AI assistant with the crash details", page: "agents" },
{ label: "Ask the agent", detail: "A red System Health check with no repair left hands its snapshot to your AI assistant", page: "agents" },
{ label: "Agent usage panel", detail: "Limits, resets and tokens for each agent, opened from the bar", page: "agents" },
@@ -5,6 +5,6 @@
# @vicinae.mode silent
# @vicinae.icon ../../icons/hicolor/scalable/apps/panama-settings.svg
# @vicinae.description Open Agents in Settings.
# @vicinae.keywords ["settings", "preferred agent", "offer to diagnose crashes", "offer help when the shell fails to reload", "system health hands off unrepairable checks", "launched agents approve their own tools", "collect claude code usage", "collect codex usage", "refresh interval", "ai assistant", "claude code", "codex", "diagnose crashes"]
# @vicinae.keywords ["settings", "preferred agent", "offer to diagnose crashes", "offer help when the shell fails to reload", "system health hands off unrepairable checks", "launched agents approve their own tools", "collect claude code usage", "collect codex usage", "refresh interval", "ai assistant", "claude code", "codex", "t3 code"]
exec "$HOME/.config/quickshell/scripts/panama-action" settings-page agents
+2 -2
View File
@@ -28,11 +28,11 @@ Found on **System › Agents**.
| Setting | Default | What it does |
|---|---|---|
| **Preferred agent**<br>`preferredAgent` | none | Who answers when the desktop offers to investigate something Choices: None, Claude Code, Codex. |
| **Preferred agent**<br>`preferredAgent` | none | Who answers when the desktop offers to investigate something Choices: None, Claude Code, Codex, T3 Code. |
| **Offer to diagnose crashes**<br>`crashDiagnoseOffer` | true | When a program dumps core, the notification carries a click that opens the preferred agent mid-investigation with the crash details in hand |
| **Offer help when the shell fails to reload**<br>`reloadFailureOffer` | true | A broken change to the shell's own configuration offers the failing log to the agent |
| **System Health hands off unrepairable checks**<br>`healthAgentHandoff` | true | A red check with no repair, or whose repair failed, grows an Ask-the-agent button carrying the check's snapshot |
| **Launched agents approve their own tools**<br>`agentAutoApprove` | true | Investigations run without permission prompts. The diagnose skill still holds agents to reading rather than fixing, and root still goes through panama-sudo, reason and all |
| **Launched agents approve their own tools**<br>`agentAutoApprove` | true | Investigations run without permission prompts. T3 Code threads use the mode set on the Panama project in T3 instead. The diagnose skill still holds agents to reading rather than fixing, and root still goes through panama-sudo, reason and all |
| **Collect Claude Code usage**<br>`agentUsageClaude` | true | Limits from Anthropic's usage endpoint, tokens from the local transcripts |
| **Collect Codex usage**<br>`agentUsageCodex` | true | Limits over the Codex app-server, sessions from its local files |
| **Refresh interval**<br>`agentUsageRefreshMinutes` | 15 min | How often the usage collectors ask for fresh numbers, in minutes. Range 5–60. |
+4
View File
@@ -86,6 +86,10 @@ rbw
# The Snapshots page is snapper end to end; see scripts/panama-snapshots.
snapper
sushi
# T3 Code, from Terra: the desktop app, its background server and the `t3` CLI.
# panama-agent opens a T3 thread when preferredAgent is t3, and the ticket
# skill renders its plans and mocks into T3 threads.
t3code
# Fonts the desktop names by family and would otherwise render as tofu.
# VictorMono is required: it draws every glyph in the shell.
victormono-nerd-fonts
+53 -2
View File
@@ -27,8 +27,11 @@
# 6. panama-agent-crash carries all four coredump facts and the absolute path
# to the skill. The path is what makes the ladder work for an agent whose
# harness has no skill mechanism.
# 7. T3 Code opens no terminal. It starts a thread in the checkout's project
# with the prompt intact on stdin, and opens that thread's t3code:// link.
#
# Hermetic on purpose: kitty, claude, codex, setsid and coredumpctl are all
# Hermetic on purpose: kitty, claude, codex, t3, xdg-open, setsid and
# coredumpctl are all
# stubbed onto PATH and the settings file is fabricated, so no agent is ever
# launched and no window is ever opened. This is NOT in tests/desktop-hijacking
# for exactly that reason -- it must stay runnable mid-session.
@@ -79,6 +82,23 @@ for agent in claude codex; do
STUB
done
# T3 Code's CLI. It records each call and its stdin, and answers `thread start`
# with a thread id the way the real one does.
cat >"$stub/t3" <<STUB
#!/usr/bin/env bash
printf '%s\0' "\$@" >>"$work/t3-calls"
printf '\n' >>"$work/t3-calls"
if [[ "\$1 \$2" == "thread start" ]]; then
cat >"$work/t3-stdin"
printf 'thread-123\n'
fi
STUB
cat >"$stub/xdg-open" <<STUB
#!/usr/bin/env bash
printf '%s' "\$1" >"$work/opened"
STUB
# A hand-run PID has no core here; the real one would be a slow lookup against
# this machine's journal.
cat >"$stub/coredumpctl" <<'STUB'
@@ -104,7 +124,9 @@ chmod +x "$stub"/*
# from the previous run are cleared first, so "was not launched" is a missing
# file rather than a stale one.
launch() {
rm -f "$work/argv" "$work/cwd" "$work/setsid-used" "$work/agent-actually-ran"
rm -f "$work/argv" "$work/cwd" "$work/setsid-used" "$work/agent-actually-ran" \
"$work/t3-calls" "$work/t3-stdin" "$work/opened"
T3CODE_HOME="$work/t3home" \
PATH="$stub:/usr/bin:/bin" \
PANAMA_PATH="$repo_dir" \
PANAMA_AGENT_SETTINGS="$settings" \
@@ -252,6 +274,35 @@ else
note 'launching codex with auto-approve off opened no terminal'
fi
# ── 7. T3 Code ──────────────────────────────────────────────────────────────
# The recorded t3 calls, one per line, arguments joined by \x1f.
t3_calls() { tr '\0' '\037' <"$work/t3-calls" 2>/dev/null; }
mkdir -p "$work/t3home/userdata"
printf 'env-456' >"$work/t3home/userdata/environment-id"
printf '{"preferredAgent":"t3","agentAutoApprove":true}\n' >"$settings"
dash_prompt=$'--looks-like-a-flag\nsecond line'
launch "$launcher" --prompt "$dash_prompt"
status=$?
(( status == 0 )) || note "panama-agent exited $status launching T3 Code: $(head -1 "$work/stderr")"
[[ -e "$work/argv" ]] && note 'T3 Code was launched in a terminal; it should open a thread in the app'
t3_calls | grep -qxF "thread"$'\x1f'"start"$'\x1f'"$repo_dir"$'\x1f'"-"$'\x1f' \
|| note 'T3 Code was not asked to start a thread in the checkout with the prompt on stdin'
[[ "$(cat "$work/t3-stdin" 2>/dev/null)" == "$dash_prompt" ]] \
|| note 'the T3 thread did not receive the prompt intact on stdin'
[[ "$(cat "$work/opened" 2>/dev/null)" == "t3code://threads/env-456/thread-123" ]] \
|| note "T3 Code opened '$(cat "$work/opened" 2>/dev/null)' rather than the new thread's link"
# No prompt means nothing to start: the app opens on the project.
launch "$launcher"
t3_calls | grep -qF "thread"$'\x1f'"start" \
&& note 'with no prompt T3 Code still started a thread'
t3_calls | grep -qxF "app"$'\x1f'"$repo_dir"$'\x1f' \
|| note 'with no prompt T3 Code was not opened on the checkout'
# ── An agent installed where only the user's own PATH looks ─────────────────
#
# Both agents install themselves into ~/.local/bin. The rungs are clicked from