Skip to content

Commit 0c46501

Browse files
committed
fix(serena): harden codex dashboard startup
1 parent 4048c3d commit 0c46501

5 files changed

Lines changed: 125 additions & 18 deletions

File tree

codex/os/linux/runtime/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ It was exported from the source Linux machine and is the active reference payloa
1515
## Truth Boundaries
1616

1717
- `config/config.template.toml` defines the current portable config baseline.
18+
- The Linux Serena MCP entry in `config/config.template.toml` includes a small environment recovery wrapper so Codex-launched Serena sessions can still auto-open the web dashboard when GUI session variables are missing.
1819
- `rules/default.rules.source.snapshot` preserves the exported source-machine rules.
1920
- `rules/default.rules` and `rules/default.rules.template` are derived outputs, not hand-maintained policy files.
2021
- `meta/toolchain.lock` is the runtime version contract used by verification scripts.

codex/os/linux/runtime/config/config.template.toml

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,34 @@ command = "npx"
2828
args = ["-y", "chrome-devtools-mcp@latest"]
2929

3030
[mcp_servers.serena]
31-
command = "uvx"
32-
args = ["--from", "git+https://github.com/oraios/serena", "serena", "start-mcp-server", "--context", "codex", "--enable-web-dashboard", "--open-web-dashboard"]
31+
startup_timeout_sec = 60
32+
command = "/usr/bin/bash"
33+
args = [
34+
"-lc",
35+
'''
36+
uid="$(id -u)"
37+
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/${uid}}"
38+
if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -S "${XDG_RUNTIME_DIR}/bus" ]]; then
39+
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
40+
fi
41+
if [[ -z "${WAYLAND_DISPLAY:-}" ]]; then
42+
for wayland_socket in "${XDG_RUNTIME_DIR}"/wayland-*; do
43+
if [[ -S "$wayland_socket" ]]; then
44+
export WAYLAND_DISPLAY="${wayland_socket##*/}"
45+
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:-wayland}"
46+
break
47+
fi
48+
done
49+
fi
50+
if [[ -z "${DISPLAY:-}" ]]; then
51+
for x_socket in /tmp/.X11-unix/X*; do
52+
if [[ -S "$x_socket" ]]; then
53+
export DISPLAY=":${x_socket##*/X}"
54+
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:-x11}"
55+
break
56+
fi
57+
done
58+
fi
59+
exec uvx --from git+https://github.com/oraios/serena serena start-mcp-server --context codex --enable-web-dashboard true --open-web-dashboard true
60+
'''
61+
]

docs/setup/PORTABLE_SETUP.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ scripts/self-test.sh
115115
- If `codex mcp list` is unavailable, install or upgrade Codex CLI first.
116116
- If the curated install step fails, rerun with `--skip-curated`.
117117
- If toolchain mismatch is reported, run `scripts/sync-codex-version.sh --apply`.
118+
- On Linux, the portable Serena MCP entry restores missing GUI session variables before launch so the web dashboard can auto-open under Codex. If the browser still does not open after install, restart Codex and use the dashboard URL shown in Serena logs as a fallback.
118119

119120
## Related Documents
120121

scripts/codex-activate.sh

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ if ! command -v codex >/dev/null 2>&1; then
1818
echo "[ERROR] codex CLI is not installed or not in PATH"
1919
exit 1
2020
fi
21+
if ! command -v python3 >/dev/null 2>&1; then
22+
echo "[ERROR] python3 is not installed or not in PATH"
23+
exit 1
24+
fi
2125

2226
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
2327
CONFIG_FILE="$CODEX_HOME_DIR/config.toml"
@@ -75,9 +79,24 @@ warn() { echo "[WARN] $*"; warn_count=$((warn_count + 1)); }
7579
err() { echo "[ERROR] $*"; err_count=$((err_count + 1)); }
7680

7781
say "Collecting MCP status..."
78-
MCP_LIST="$(codex mcp list || true)"
79-
if [[ -z "$MCP_LIST" ]]; then
80-
err "Unable to read MCP status via 'codex mcp list'"
82+
MCP_LIST_JSON="$(codex mcp list --json || true)"
83+
if [[ -z "$MCP_LIST_JSON" ]]; then
84+
err "Unable to read MCP status via 'codex mcp list --json'"
85+
fi
86+
87+
if [[ -f "$CONFIG_FILE" ]]; then
88+
if grep -Eq -- '--enable-web-dashboard' "$CONFIG_FILE" && grep -Eq -- '--open-web-dashboard' "$CONFIG_FILE"; then
89+
say "Serena dashboard flags found in Codex config"
90+
else
91+
warn "Serena MCP config is missing dashboard startup flags"
92+
fi
93+
if grep -Eq 'DBUS_SESSION_BUS_ADDRESS|WAYLAND_DISPLAY|/tmp/\.X11-unix/X' "$CONFIG_FILE"; then
94+
say "Serena display environment recovery found in Codex config"
95+
else
96+
warn "Serena MCP config is missing display environment recovery for browser auto-open"
97+
fi
98+
else
99+
warn "Codex config not found at $CONFIG_FILE"
81100
fi
82101

83102
enable_mcp() {
@@ -93,11 +112,21 @@ enable_mcp() {
93112
}
94113

95114
for mcp in "${REQUIRED_MCPS[@]}"; do
96-
if ! grep -Eq "^${mcp}[[:space:]]+" <<<"$MCP_LIST"; then
115+
state="$(printf '%s' "$MCP_LIST_JSON" | python3 -c '
116+
import json
117+
import sys
118+
119+
name = sys.argv[1]
120+
for entry in json.load(sys.stdin):
121+
if entry.get("name") == name:
122+
print("enabled" if entry.get("enabled") else "disabled")
123+
raise SystemExit(0)
124+
raise SystemExit(1)
125+
' "$mcp")" || {
97126
err "Missing MCP config: $mcp"
98127
continue
99-
fi
100-
if grep -Eq "^${mcp}[[:space:]]+.*[[:space:]]enabled[[:space:]]" <<<"$MCP_LIST"; then
128+
}
129+
if [[ "$state" == "enabled" ]]; then
101130
say "MCP present/enabled: $mcp"
102131
else
103132
warn "MCP configured but disabled: $mcp"
@@ -106,16 +135,35 @@ for mcp in "${REQUIRED_MCPS[@]}"; do
106135

107136
done
108137

109-
MCP_LIST_AFTER="$(codex mcp list || true)"
110-
MCP_LIST_AFTER_CLEAN="$(printf '%s\n' "$MCP_LIST_AFTER" | tr -d '\r' | sed -E 's/\x1B\\[[0-9;]*[[:alpha:]]//g')"
111-
if grep -Eiq "context7.*not logged in" <<<"$MCP_LIST_AFTER_CLEAN"; then
138+
MCP_LIST_AFTER_JSON="$(codex mcp list --json || true)"
139+
context7_auth="$(printf '%s' "$MCP_LIST_AFTER_JSON" | python3 -c '
140+
import json
141+
import sys
142+
143+
for entry in json.load(sys.stdin):
144+
if entry.get("name") == "context7":
145+
print(entry.get("auth_status") or "")
146+
raise SystemExit(0)
147+
raise SystemExit(1)
148+
')"
149+
if [[ "$context7_auth" == "not_logged_in" ]]; then
112150
if [[ -f "$CONFIG_FILE" ]] && grep -Eq '^CONTEXT7_API_KEY = "[^"]+"' "$CONFIG_FILE" && ! grep -q '__CONTEXT7_API_KEY__' "$CONFIG_FILE"; then
113151
say "context7 reports not logged in, but token header is configured in config.toml (can be expected with token-based auth)."
114152
else
115153
warn "context7 MCP is enabled but not logged in (check CONTEXT7_API_KEY)"
116154
fi
117155
fi
118-
if grep -Eiq "github.*not logged in" <<<"$MCP_LIST_AFTER_CLEAN"; then
156+
github_auth="$(printf '%s' "$MCP_LIST_AFTER_JSON" | python3 -c '
157+
import json
158+
import sys
159+
160+
for entry in json.load(sys.stdin):
161+
if entry.get("name") == "github":
162+
print(entry.get("auth_status") or "")
163+
raise SystemExit(0)
164+
raise SystemExit(1)
165+
')"
166+
if [[ "$github_auth" == "not_logged_in" ]]; then
119167
if [[ -f "$CONFIG_FILE" ]] && grep -Eq '^Authorization = "Bearer [^"]+"' "$CONFIG_FILE" && ! grep -q '__GITHUB_MCP_TOKEN__' "$CONFIG_FILE"; then
120168
say "github reports not logged in, but bearer header is configured in config.toml (can be expected with token-based auth)."
121169
else

scripts/verify.sh

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ if ! command -v codex >/dev/null 2>&1; then
5050
err "codex CLI not found"
5151
exit 1
5252
fi
53+
if ! command -v python3 >/dev/null 2>&1; then
54+
err "python3 not found"
55+
exit 1
56+
fi
5357

5458
if [[ "$REQUESTED_PROFILE" != "$PROFILE_OS" ]]; then
5559
warn "Profile '$REQUESTED_PROFILE' has no payload, using '$PROFILE_OS'"
@@ -90,18 +94,28 @@ if [[ -d "$SKILLS_DIR/custom" && ! -d "$SKILLS_DIR/agent-development" ]]; then
9094
SKILLS_ROOT="$SKILLS_DIR/custom"
9195
fi
9296

93-
status="$(codex mcp list || true)"
94-
if [[ -z "$status" ]]; then
95-
err "Failed to read MCP table"
97+
status_json="$(codex mcp list --json || true)"
98+
if [[ -z "$status_json" ]]; then
99+
err "Failed to read MCP table as JSON"
96100
exit 1
97101
fi
98102

99103
for mcp in "${REQUIRED_MCPS[@]}"; do
100-
if ! grep -Eq "^${mcp}[[:space:]]+" <<<"$status"; then
104+
state="$(printf '%s' "$status_json" | python3 -c '
105+
import json
106+
import sys
107+
108+
name = sys.argv[1]
109+
for entry in json.load(sys.stdin):
110+
if entry.get("name") == name:
111+
print("enabled" if entry.get("enabled") else "disabled")
112+
raise SystemExit(0)
113+
raise SystemExit(1)
114+
' "$mcp")" || {
101115
err "Missing MCP: $mcp"
102116
exit 1
103-
fi
104-
if ! grep -E "^${mcp}[[:space:]].*[[:space:]]enabled([[:space:]]|$)" <<<"$status" >/dev/null; then
117+
}
118+
if [[ "$state" != "enabled" ]]; then
105119
err "MCP configured but not enabled: $mcp"
106120
exit 1
107121
fi
@@ -119,6 +133,20 @@ else
119133
warn "Config still contains GitHub MCP placeholder"
120134
fi
121135

136+
if grep -Eq -- '--enable-web-dashboard' "$CONFIG_FILE" && grep -Eq -- '--open-web-dashboard' "$CONFIG_FILE"; then
137+
say "Serena dashboard auto-open flags found"
138+
else
139+
err "Serena MCP missing dashboard startup flags"
140+
exit 1
141+
fi
142+
143+
if grep -Eq 'DBUS_SESSION_BUS_ADDRESS|WAYLAND_DISPLAY|/tmp/\.X11-unix/X' "$CONFIG_FILE"; then
144+
say "Serena display environment recovery wrapper found"
145+
else
146+
err "Serena MCP missing display environment recovery wrapper"
147+
exit 1
148+
fi
149+
122150
if ! grep -Eiq 'think step by step' "$GLOBAL_AGENTS_FILE"; then
123151
err "Global AGENTS does not include expected baseline phrase: 'think step by step'"
124152
exit 1

0 commit comments

Comments
 (0)