@@ -81,6 +81,7 @@ REPORT_DATE="${REPORT_DATE:-$(TZ="$REPORT_TZ" date +%F)}"
8181RUN_ID=" ${RUN_ID:- $(date -u +% Y% m% dT% H% M% SZ)} "
8282REPORT_TITLE=" ${REPORT_TITLE:- Launch Readiness Benchmark $RUN_ID } "
8383OUT_DIR=" ${OUT_DIR:- $REPO_DIR / experiment/ runs/ $RUN_ID } "
84+ RUN_ROOT_OUT_DIR=" $OUT_DIR "
8485CODEX_MODEL=" ${CODEX_MODEL:- gpt-5.6-luna} "
8586CODEX_REASONING_EFFORT=" ${CODEX_REASONING_EFFORT:- low} "
8687CODEX_EXEC_TIMEOUT_SECONDS=" ${CODEX_EXEC_TIMEOUT_SECONDS:- 900} "
@@ -93,8 +94,15 @@ LOCALITY_EXPERIMENT_TRACE_FORCE_DIRECT="${LOCALITY_EXPERIMENT_TRACE_FORCE_DIRECT
9394PROMPT_ROOT=" ${PROMPT_ROOT:- $SCRIPT_DIR / prompts} "
9495LOCALITY_PROMPT_DIR=" ${LOCALITY_PROMPT_DIR:- $PROMPT_ROOT / Locality} "
9596MCP_PROMPT_DIR=" ${MCP_PROMPT_DIR:- $PROMPT_ROOT / MCP} "
96- MCP_SECRET_DIR=" ${MCP_SECRET_DIR:- $HOME / .config/ locality-launch-readiness/ mcp} "
97- MCP_BIN_DIR=" ${MCP_BIN_DIR:- $HOME / .local/ bin} "
97+ BASE_CODEX_HOME=" ${CODEX_HOME:- $HOME / .codex} "
98+ CODEX_STRATEGY_ROOT=" ${CODEX_STRATEGY_ROOT:- $RUN_ROOT_OUT_DIR / codex} "
99+ LOCALITY_CODEX_HOME=" $CODEX_STRATEGY_ROOT /locality"
100+ MCP_CODEX_HOME=" $CODEX_STRATEGY_ROOT /notion-mcp"
101+ MCP_SECRET_DIR=" ${MCP_SECRET_DIR:- $RUN_ROOT_OUT_DIR / mcp/ secrets} "
102+ MCP_BIN_DIR=" ${MCP_BIN_DIR:- $RUN_ROOT_OUT_DIR / mcp/ bin} "
103+ MCP_AUTH_SETUP_OUT=" $RUN_ROOT_OUT_DIR /mcp-auth-setup.out"
104+ MCP_AUTH_SETUP_ERR=" $RUN_ROOT_OUT_DIR /mcp-auth-setup.err"
105+ MCP_AUTH_CONFIGURED=0
98106METRICS_TSV=" $OUT_DIR /metrics.tsv"
99107SUMMARY_JSON=" $OUT_DIR /summary.json"
100108CONTEXT_PATHS_FILE=" $OUT_DIR /locality-context-paths.txt"
@@ -167,11 +175,52 @@ render_locality_traces() {
167175 done
168176}
169177
170- configure_codex_mcp_auth () {
171- MCP_AUTH_DETAIL=" linear=skipped; notion=skipped; slack=skipped"
178+ strip_codex_mcp_tables () {
179+ local source=" $1 "
180+ local destination=" $2 "
181+ python3 - " $source " " $destination " << 'PY '
182+ import re
183+ import sys
184+ from pathlib import Path
172185
173- command -v codex > /dev/null || return
186+ source = Path(sys.argv[1])
187+ destination = Path(sys.argv[2])
188+ text = source.read_text(encoding="utf-8") if source.exists() else ""
189+
190+ skip = False
191+ lines = []
192+ for line in text.splitlines(keepends=True):
193+ stripped = line.strip()
194+ header = stripped.split("#", 1)[0].strip()
195+ if header.startswith("[") and header.endswith("]"):
196+ table = header.strip("[]").strip()
197+ skip = table == "mcp_servers" or table.startswith("mcp_servers.")
198+ if skip:
199+ continue
200+ if re.match(r"^mcp_servers\s*=", stripped):
201+ continue
202+ lines.append(line)
203+
204+ destination.parent.mkdir(parents=True, exist_ok=True)
205+ body = "".join(lines).rstrip()
206+ destination.write_text((body + "\n") if body else "", encoding="utf-8")
207+ PY
208+ }
174209
210+ prepare_codex_home_without_mcp () {
211+ local codex_home=" $1 "
212+ mkdir -p " $codex_home "
213+ chmod 700 " $codex_home "
214+
215+ if [ -d " $BASE_CODEX_HOME " ] && [ " $BASE_CODEX_HOME " != " $codex_home " ]; then
216+ find " $BASE_CODEX_HOME " -maxdepth 1 -type f ! -name config.toml -exec cp -p {} " $codex_home /" \; 2> /dev/null || true
217+ fi
218+
219+ strip_codex_mcp_tables " $BASE_CODEX_HOME /config.toml" " $codex_home /config.toml"
220+ chmod 600 " $codex_home /config.toml"
221+ }
222+
223+ validate_codex_mcp_auth_inputs () {
175224 if [ -z " $LINEAR_API_KEY " ]; then
176225 echo " LINEAR_API_KEY is required when --compare-mcp is enabled" >&2
177226 return 2
@@ -185,9 +234,32 @@ configure_codex_mcp_auth() {
185234 echo " SLACK_BOT_TOKEN and SLACK_TEAM_ID are both required to configure Slack MCP" >&2
186235 return 2
187236 fi
237+ }
238+
239+ prepare_codex_strategy_homes () {
240+ prepare_codex_home_without_mcp " $LOCALITY_CODEX_HOME "
241+ if [ " $COMPARE_MCP " -eq 1 ]; then
242+ validate_codex_mcp_auth_inputs || return
243+ prepare_codex_home_without_mcp " $MCP_CODEX_HOME "
244+ fi
245+ }
188246
189- mkdir -p " $MCP_SECRET_DIR " " $MCP_BIN_DIR " " $HOME /.codex" || return
190- chmod 700 " $MCP_SECRET_DIR " " $HOME /.codex" || return
247+ codex_home_for_strategy () {
248+ case " $1 " in
249+ locality) printf ' %s\n' " $LOCALITY_CODEX_HOME " ;;
250+ notion-mcp) printf ' %s\n' " $MCP_CODEX_HOME " ;;
251+ * ) printf ' %s\n' " $BASE_CODEX_HOME " ;;
252+ esac
253+ }
254+
255+ configure_codex_mcp_auth () {
256+ MCP_AUTH_DETAIL=" linear=skipped; notion=skipped; slack=skipped"
257+
258+ command -v codex > /dev/null || return
259+ validate_codex_mcp_auth_inputs || return
260+
261+ mkdir -p " $MCP_SECRET_DIR " " $MCP_BIN_DIR " " $MCP_CODEX_HOME " || return
262+ chmod 700 " $MCP_SECRET_DIR " " $MCP_BIN_DIR " " $MCP_CODEX_HOME " || return
191263
192264 local notion_helper=" $MCP_BIN_DIR /locality-launch-notion-mcp"
193265 (
216288 ) || return
217289
218290 export LINEAR_API_KEY
219- codex mcp remove linear-server > /dev/null 2>&1 || true
220- codex mcp remove notion > /dev/null 2>&1 || true
221- codex mcp remove slack > /dev/null 2>&1 || true
222- codex mcp remove slack-server > /dev/null 2>&1 || true
223- codex mcp add linear-server --url https://mcp.linear.app/mcp --bearer-token-env-var LINEAR_API_KEY || return
224- codex mcp add notion -- " $notion_helper " || return
291+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp remove linear-server > /dev/null 2>&1 || true
292+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp remove notion > /dev/null 2>&1 || true
293+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp remove slack > /dev/null 2>&1 || true
294+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp remove slack-server > /dev/null 2>&1 || true
295+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp add linear-server --url https://mcp.linear.app/mcp --bearer-token-env-var LINEAR_API_KEY || return
296+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp add notion -- " $notion_helper " || return
225297
226298 local slack_status=" skipped"
227299 if [ -n " $SLACK_BOT_TOKEN " ]; then
@@ -250,13 +322,14 @@ exec npx -y @modelcontextprotocol/server-slack
250322SH
251323 chmod 700 " $slack_helper "
252324 ) || return
253- codex mcp add slack -- " $slack_helper " || return
325+ CODEX_HOME= " $MCP_CODEX_HOME " codex mcp add slack -- " $slack_helper " || return
254326 slack_status=" configured"
255327 else
256328 rm -f " $MCP_SECRET_DIR /slack-bot-token" " $MCP_SECRET_DIR /slack-team-id" " $MCP_SECRET_DIR /slack-channel-ids"
257329 fi
258330
259- MCP_AUTH_DETAIL=" linear=configured; notion=configured; slack=$slack_status "
331+ MCP_AUTH_DETAIL=" linear=configured; notion=configured; slack=$slack_status ; codex_home=$MCP_CODEX_HOME "
332+ MCP_AUTH_CONFIGURED=1
260333 echo " Configured Codex MCP auth: $MCP_AUTH_DETAIL "
261334}
262335
@@ -277,6 +350,8 @@ run_codex_agent() {
277350 local agent_loc_trace=" $OUT_DIR /$strategy -agent-locality-trace.jsonl"
278351 local prompt
279352 local run_cmd
353+ local codex_home
354+ codex_home=" $( codex_home_for_strategy " $strategy " ) "
280355 prompt=" $( cat " $prompt_file " ) "
281356 cp " $prompt_file " " $prompt_snapshot "
282357
@@ -304,6 +379,7 @@ run_codex_agent() {
304379 fi
305380 {
306381 printf ' timeout_seconds=%s\n' " $CODEX_EXEC_TIMEOUT_SECONDS "
382+ printf ' codex_home=%s\n' " $codex_home "
307383 printf ' codex_command='
308384 printf ' %q ' " ${cmd[@]} "
309385 printf ' \nwrapped_command='
@@ -313,7 +389,7 @@ run_codex_agent() {
313389
314390 set +e
315391 set -o pipefail
316- LOCALITY_TRACE_FILE=" $agent_loc_trace " LOCALITY_TRACE_RUN_ID=" $RUN_ID " \
392+ CODEX_HOME= " $codex_home " LOCALITY_TRACE_FILE=" $agent_loc_trace " LOCALITY_TRACE_RUN_ID=" $RUN_ID " \
317393 " ${run_cmd[@]} " < /dev/null 2> " $err_file " | python3 " $SCRIPT_DIR /scripts/timestamp-jsonl.py" > " $events_file "
318394 local pipe_status=(" ${PIPESTATUS[@]} " )
319395 local rc=" ${pipe_status[0]} "
@@ -493,21 +569,21 @@ git -C "$REPO_DIR" rev-parse --git-dir >/dev/null
493569phase_end " locality" " validate_environment" " ok" " repo=$REPO_DIR ; model=$CODEX_MODEL ; effort=$CODEX_REASONING_EFFORT ; scenarios=${# SCENARIO_FILES[@]} ; prompts=$LOCALITY_PROMPT_DIR ; write_mounted_page=$WRITE_MOUNTED_PAGE "
494570
495571phase_start
496- if [ " $COMPARE_MCP " -eq 1 ] ; then
497- set +e
498- configure_codex_mcp_auth > " $OUT_DIR /mcp-auth-setup.out " 2> " $OUT_DIR /mcp-auth-setup.err "
499- MCP_AUTH_RC= $?
500- set -e
501- if [ " $MCP_AUTH_RC " -eq 0 ]; then
502- phase_end " notion_mcp " " mcp_auth_setup " " ok" " $MCP_AUTH_DETAIL ; out= $OUT_DIR /mcp-auth-setup.out "
572+ set +e
573+ prepare_codex_strategy_homes > " $OUT_DIR /codex-strategy-setup.out " 2> " $OUT_DIR /codex-strategy-setup.err "
574+ CODEX_STRATEGY_SETUP_RC= $?
575+ set -e
576+ if [ " $CODEX_STRATEGY_SETUP_RC " -eq 0 ] ; then
577+ if [ " $COMPARE_MCP " -eq 1 ]; then
578+ phase_end " locality " " codex_strategy_config " " ok" " locality_home= $LOCALITY_CODEX_HOME ; mcp_home= $MCP_CODEX_HOME ; mcp_auth=validated "
503579 else
504- phase_end " notion_mcp" " mcp_auth_setup" " failed" " exit=$MCP_AUTH_RC ; out=$OUT_DIR /mcp-auth-setup.out; err=$OUT_DIR /mcp-auth-setup.err"
505- cat " $OUT_DIR /mcp-auth-setup.out" >&2 || true
506- cat " $OUT_DIR /mcp-auth-setup.err" >&2 || true
507- exit " $MCP_AUTH_RC "
580+ phase_end " locality" " codex_strategy_config" " ok" " locality_home=$LOCALITY_CODEX_HOME ; mcp_auth=not requested"
508581 fi
509582else
510- phase_end " notion_mcp" " mcp_auth_setup" " skipped" " pass --compare-mcp to configure Codex MCP auth"
583+ phase_end " locality" " codex_strategy_config" " failed" " exit=$CODEX_STRATEGY_SETUP_RC ; out=$OUT_DIR /codex-strategy-setup.out; err=$OUT_DIR /codex-strategy-setup.err"
584+ cat " $OUT_DIR /codex-strategy-setup.out" >&2 || true
585+ cat " $OUT_DIR /codex-strategy-setup.err" >&2 || true
586+ exit " $CODEX_STRATEGY_SETUP_RC "
511587fi
512588
513589phase_start
709785 fi
710786
711787 if [ " $COMPARE_MCP " -eq 1 ]; then
788+ phase_start
789+ if [ " $MCP_AUTH_CONFIGURED " -eq 0 ]; then
790+ set +e
791+ configure_codex_mcp_auth > " $MCP_AUTH_SETUP_OUT " 2> " $MCP_AUTH_SETUP_ERR "
792+ MCP_AUTH_RC=$?
793+ set -e
794+ if [ " $MCP_AUTH_RC " -eq 0 ]; then
795+ phase_end " notion_mcp" " mcp_auth_setup" " ok" " $MCP_AUTH_DETAIL ; out=$MCP_AUTH_SETUP_OUT "
796+ else
797+ phase_end " notion_mcp" " mcp_auth_setup" " failed" " exit=$MCP_AUTH_RC ; out=$MCP_AUTH_SETUP_OUT ; err=$MCP_AUTH_SETUP_ERR "
798+ cat " $MCP_AUTH_SETUP_OUT " >&2 || true
799+ cat " $MCP_AUTH_SETUP_ERR " >&2 || true
800+ OUT_DIR=" $RUN_OUT_DIR "
801+ CONTEXT_PATHS_FILE=" $RUN_CONTEXT_PATHS_FILE "
802+ CONTEXT_INVENTORY=" $RUN_CONTEXT_INVENTORY "
803+ CONTEXT_SEARCH_RESULTS=" $RUN_CONTEXT_SEARCH_RESULTS "
804+ export OUT_DIR CONTEXT_PATHS_FILE CONTEXT_INVENTORY CONTEXT_SEARCH_RESULTS
805+ exit " $MCP_AUTH_RC "
806+ fi
807+ else
808+ phase_end " notion_mcp" " mcp_auth_setup" " skipped" " already configured; codex_home=$MCP_CODEX_HOME "
809+ fi
810+
712811 phase_start
713812 set +e
714813 run_codex_agent " notion-mcp" " $MCP_PROMPT_FILE " " $OUT_DIR /notion-mcp-report-body.md" " $OUT_DIR /notion-mcp-agent-final.md"
0 commit comments