← Files Astral OrchestratorARCHIVED FILE
scripts/inspect-agent-runtime.sh
7.47 KB · Oct 2, 2026 · 00:29 UTC
#!/bin/sh
# Emit only allowlisted routing metadata from one exact native subagent rollout.
set -eu
usage() {
printf '%s\n' \
'Usage: sh inspect-agent-runtime.sh [--sessions-dir PATH] THREAD_ID' \
' sh inspect-agent-runtime.sh [--sessions-dir PATH] [--since-epoch N] --agent-path PATH' \
'' \
'Return a small JSON object containing only identity, model, effort, sandbox,' \
'permission, and working-directory evidence for one subagent task.'
}
fail() {
printf '%s\n' "ERROR: $*" >&2
exit 1
}
sessions_dir=''
since_epoch=0
selector_kind=''
selector_value=''
while [ "$#" -gt 0 ]; do
case "$1" in
--sessions-dir)
[ "$#" -ge 2 ] || fail "--sessions-dir requires a path."
[ -n "$2" ] || fail "--sessions-dir requires a non-empty path."
sessions_dir=$2
shift 2
;;
--since-epoch)
[ "$#" -ge 2 ] || fail "--since-epoch requires whole seconds."
since_epoch=$2
shift 2
;;
--thread-id)
[ "$#" -ge 2 ] || fail "--thread-id requires a lowercase UUID."
[ -z "$selector_kind" ] || fail "choose only one task selector."
selector_kind=thread_id
selector_value=$2
shift 2
;;
--agent-path)
[ "$#" -ge 2 ] || fail "--agent-path requires the canonical spawned task path."
[ -z "$selector_kind" ] || fail "choose only one task selector."
selector_kind=agent_path
selector_value=$2
shift 2
;;
--help|-h)
usage
exit 0
;;
--*) fail "unknown option: $1" ;;
*)
[ -z "$selector_kind" ] || fail "choose only one task selector."
selector_kind=thread_id
selector_value=$1
shift
;;
esac
done
[ -n "$selector_kind" ] || fail "a THREAD_ID or --agent-path selector is required."
if ! printf '%s\n' "$since_epoch" | LC_ALL=C grep -Eq '^[0-9]+$'; then
fail "--since-epoch must be zero or positive whole seconds."
fi
if [ -z "$sessions_dir" ]; then
if [ -n "${CODEX_HOME-}" ]; then
sessions_dir=$CODEX_HOME/sessions
else
[ -n "${HOME-}" ] || fail "HOME is unavailable; pass --sessions-dir explicitly."
sessions_dir=$HOME/.codex/sessions
fi
fi
[ -d "$sessions_dir" ] || fail "sessions directory is unavailable: $sessions_dir"
command -v python3 >/dev/null 2>&1 || fail "Python 3.11 or newer is required for route inspection."
python3 -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)' >/dev/null 2>&1 || fail "Python 3.11 or newer is required for route inspection."
python3 - "$sessions_dir" "$selector_kind" "$selector_value" "$since_epoch" <<'PY'
import json
import re
import sys
from pathlib import Path
def fail(message):
print(f"ERROR: {message}", file=sys.stderr)
raise SystemExit(1)
sessions_dir = Path(sys.argv[1])
selector_kind = sys.argv[2]
selector_value = sys.argv[3]
since_epoch = int(sys.argv[4])
uuid_pattern = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
if selector_kind == "thread_id":
if not re.fullmatch(uuid_pattern, selector_value):
fail("THREAD_ID must be a lowercase UUID.")
thread_id = selector_value
elif selector_kind == "agent_path":
if not re.fullmatch(r"/[A-Za-z0-9_./-]+", selector_value):
fail("--agent-path must be a canonical task path.")
matching_ids = set()
for candidate in sessions_dir.rglob("rollout-*.jsonl"):
try:
if not candidate.is_file() or candidate.stat().st_mtime < since_epoch:
continue
with candidate.open(encoding="utf-8") as handle:
for line in handle:
if not line.strip():
continue
item = json.loads(line)
payload = item.get("payload")
if (
item.get("type") == "session_meta"
and isinstance(payload, dict)
and payload.get("agent_path") == selector_value
and isinstance(payload.get("id"), str)
and re.fullmatch(uuid_pattern, payload["id"])
):
matching_ids.add(payload["id"])
except (OSError, UnicodeError, json.JSONDecodeError):
continue
if len(matching_ids) != 1:
fail(
"expected one task id for the returned agent path since the supplied time; "
f"found {len(matching_ids)}."
)
thread_id = next(iter(matching_ids))
else:
fail("unsupported task selector.")
matches = [
path
for path in sessions_dir.rglob(f"rollout-*-{thread_id}.jsonl")
if path.is_file()
]
if len(matches) != 1:
fail(f"expected one rollout filename for the task; found {len(matches)}.")
records = []
try:
with matches[0].open(encoding="utf-8") as handle:
for line in handle:
if line.strip():
records.append(json.loads(line))
except (OSError, UnicodeError, json.JSONDecodeError):
fail("the matched rollout is unreadable or contains invalid JSON.")
sessions = [
item.get("payload")
for item in records
if item.get("type") == "session_meta"
and isinstance(item.get("payload"), dict)
and item["payload"].get("id") == thread_id
]
turns = [
item.get("payload")
for item in records
if item.get("type") == "turn_context" and isinstance(item.get("payload"), dict)
]
if not sessions:
fail("metadata for the requested task is missing or ambiguous.")
session_identity_fields = (
"id",
"parent_thread_id",
"forked_from_id",
"agent_nickname",
"agent_path",
"model_provider",
)
session_identity = {
field: sessions[0].get(field) for field in session_identity_fields
}
if any(
{field: candidate.get(field) for field in session_identity_fields}
!= session_identity
for candidate in sessions[1:]
):
fail("metadata for the requested task is missing or ambiguous.")
if not turns:
fail("turn context is missing.")
session = sessions[0]
# Forked rollout snapshots can contain inherited parent contexts with different routes.
# The final turn_context is the effective context last observed for this task.
turn = turns[-1]
def required_string(label, value):
if not isinstance(value, str) or not value:
fail(f"{label} is missing.")
return value
def optional_string(label, value):
if value is None:
return None
if not isinstance(value, str):
fail(f"{label} is invalid.")
return value
sandbox = turn.get("sandbox_policy")
permission = turn.get("permission_profile")
if not isinstance(sandbox, dict):
fail("sandbox policy is missing.")
if not isinstance(permission, dict):
fail("permission profile is missing.")
evidence = {
"thread_id": thread_id,
"parent_thread_id": optional_string("parent task id", session.get("parent_thread_id")),
"forked_from_id": optional_string("fork source id", session.get("forked_from_id")),
"agent_nickname": optional_string("agent nickname", session.get("agent_nickname")),
"agent_path": optional_string("agent path", session.get("agent_path")),
"model_provider": optional_string("model provider", session.get("model_provider")),
"model": required_string("model", turn.get("model")),
"effort": required_string("effort", turn.get("effort")),
"sandbox_policy_type": required_string("sandbox policy type", sandbox.get("type")),
"permission_profile_type": required_string("permission profile type", permission.get("type")),
"cwd": required_string("working directory", turn.get("cwd")),
}
print(json.dumps(evidence, separators=(",", ":"), sort_keys=True))
PY
SHA-256: 642ec5e783717cc980777b42b901abe5f6198811b4d81c4ba1241464e3343098