Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,9 @@ $agmsg — or /skills → agmsg

Codex supports `mode monitor` as a **beta** app-server bridge, plus `mode turn` and `mode off`.

> ⚠️ **The monitor beta changes how Codex starts — opt in only if you understand it.** Codex has no Monitor tool, so `mode monitor` installs a shim at `~/.agents/bin/codex` and asks you to put `~/.agents/bin` **first on your PATH**, so `codex` then resolves to the shim instead of the real binary. In monitor-mode projects the shim routes interactive launches through a bridge that turns incoming agmsg messages into turns on the current Codex thread; `codex exec` and non-monitor projects pass straight through to the real Codex. It depends on experimental Codex app-server behavior and has known rough edges (orphans on TUI close — #149; one identity per project — #150).
> ⚠️ **The monitor beta changes how Codex starts — opt in only if you understand it.** Codex has no Monitor tool, so `mode monitor` prints a shell function that makes `codex` route through agmsg's monitor shim in your interactive shell. In monitor-mode projects the shim routes interactive launches through a bridge that turns incoming agmsg messages into turns on the current Codex thread; `codex exec` and non-monitor projects pass straight through to the real Codex. It depends on experimental Codex app-server behavior and has known rough edges (orphans on TUI close — #149; one identity per project — #150).

If the shim can't be installed, launch with `~/.agents/skills/<cmd>/scripts/drivers/types/codex/codex-monitor.sh`. Codex sandboxing must allow writes to the skill's `db/`, `teams/`, and `run/` dirs — `install.sh` configures those `writable_roots` when `~/.codex/config.toml` exists. Setup, PATH notes, and internals: [docs/codex-monitor-beta.md](docs/codex-monitor-beta.md).
If you prefer a global PATH shim, run `~/.agents/skills/<cmd>/scripts/drivers/types/codex/codex-shim-install.sh install` and put `~/.agents/bin` before the real Codex binary on PATH. You can also launch with `~/.agents/skills/<cmd>/scripts/drivers/types/codex/codex-monitor.sh`. Codex sandboxing must allow writes to the skill's `db/`, `teams/`, and `run/` dirs — `install.sh` configures those `writable_roots` when `~/.codex/config.toml` exists. Setup notes and internals: [docs/codex-monitor-beta.md](docs/codex-monitor-beta.md).

### GitHub Copilot CLI

Expand Down
48 changes: 30 additions & 18 deletions docs/codex-monitor-beta.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ Codex does not expose Claude Code's Monitor tool. agmsg's Codex monitor beta
approximates the same experience by launching Codex through an app-server bridge.

> ⚠️ **Experimental beta — read before enabling.** This changes how Codex starts.
> Enabling monitor mode installs a shim at `~/.agents/bin/codex` and asks you to
> put `~/.agents/bin` **first on your PATH**, so `codex` then resolves to the shim
> instead of the real binary. In monitor-mode projects the shim re-routes
> interactive launches through an app-server bridge; everywhere else it passes
> straight through. **Only enable this if you understand PATH precedence and are
> comfortable with the `codex` command being intercepted.** It also depends on
> Codex app-server behavior and may break as Codex changes. Known rough edges:
> Enabling monitor mode prints a shell function that makes `codex` route through
> agmsg's monitor shim in your interactive shell. In monitor-mode projects the
> shim re-routes interactive launches through an app-server bridge; everywhere
> else it passes straight through. **Only enable this if you are comfortable with
> the `codex` command being intercepted in that shell.** It also depends on Codex
> app-server behavior and may break as Codex changes. Known rough edges:
> enabling monitor takes effect only after you **restart Codex and send your
> first message** — the SessionStart hook fires on the first turn, not the
> moment Codex opens, so the bridge is absent until you interact once; an
Expand All @@ -30,9 +29,8 @@ Enable monitor mode in a project:
The command:

1. Enables agmsg's Codex SessionStart/SessionEnd hooks for the project.
2. Installs a Codex shim at `~/.agents/bin/codex` when it is safe to do so.
3. Prints PATH instructions if `~/.agents/bin` is not before the real Codex
binary.
2. Prints a shell function that routes interactive `codex` launches through the
monitor shim.

The Codex sandbox must allow writes to the installed skill's runtime state:

Expand All @@ -45,11 +43,12 @@ The Codex sandbox must allow writes to the installed skill's runtime state:
`install.sh` and `install.sh --update` add these writable roots to
`~/.codex/config.toml` when that file exists.

If the command says `~/.agents/bin` is not on PATH, add this to your shell
profile:
Add the printed function to your shell profile. It looks like:

```bash
export PATH="$HOME/.agents/bin:$PATH"
codex() {
~/.agents/skills/agmsg/scripts/drivers/types/codex/codex-shim.sh "$@"
}
```

Restart the shell, then launch Codex normally:
Expand All @@ -58,13 +57,25 @@ Restart the shell, then launch Codex normally:
codex
```

In monitor-mode projects, the shim routes interactive Codex launches through
In monitor-mode projects, the function routes interactive Codex launches through
the bridge. Outside monitor-mode projects, it passes through to the real Codex.

## Fallback
## Optional PATH Shim

If you prefer the previous global PATH shim setup, install it explicitly:

```bash
~/.agents/skills/agmsg/scripts/drivers/types/codex/codex-shim-install.sh install
```

Then put `~/.agents/bin` before the real Codex binary on PATH:

```bash
export PATH="$HOME/.agents/bin:$PATH"
```

If `~/.agents/bin/codex` already exists and is not the agmsg shim, agmsg leaves
it untouched. You can either move that command aside and run `mode monitor`
it untouched. You can either move that command aside and run the install command
again, or launch monitor sessions explicitly:

```bash
Expand All @@ -79,7 +90,8 @@ For custom command names, replace `agmsg` with the installed skill name:

## What The Shim Does

The shim only wraps interactive Codex TUI launches:
The shell function and optional PATH shim only wrap interactive Codex TUI
launches:

```bash
codex
Expand Down Expand Up @@ -139,7 +151,7 @@ and the bridge stops instead of looping.

```mermaid
flowchart TD
user["User runs codex"] --> shim["~/.agents/bin/codex shim"]
user["User runs codex"] --> shim["codex shell function or ~/.agents/bin/codex shim"]
shim --> mode{"Project delivery mode?"}
mode -- "not monitor / codex exec / --version" --> real["real codex"]
mode -- "monitor (interactive)" --> monitor["codex-monitor.sh"]
Expand Down
34 changes: 13 additions & 21 deletions scripts/drivers/types/codex/_delivery.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,21 @@
# codex delivery plug.
#
# codex keeps the default JSON event-hooks apply (agmsg_delivery_apply); it only
# adds enable/disable side effects: install the monitor shim on enable, stop the
# bridge on disable. Sourced into delivery.sh's context, so SKILL_DIR,
# adds enable/disable side effects: print the monitor shim setup on enable, stop
# the bridge on disable. Sourced into delivery.sh's context, so SKILL_DIR,
# agmsg_resolve_node, CODEX_MONITOR_DOC_URL and stop_codex_bridge are in scope.
# Args (both hooks): on_enable <mode> <type> <project>; on_disable <type> <project>.

agmsg_delivery_on_enable() {
if AGMSG_CODEX_SHIM_INSTALL_QUIET=1 "$SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh" install; then
echo "Codex monitor shim installed at ~/.agents/bin/codex."
case ":$PATH:" in
*":$HOME/.agents/bin:"*)
echo "Future Codex sessions: launch with codex. In monitor-mode projects, the agmsg shim routes interactive Codex sessions through the bridge."
;;
*)
# Loud, unambiguous: this is the #1 reason monitor silently does nothing.
echo "WARNING: ~/.agents/bin is NOT on your PATH, so 'codex' still launches the real"
echo " binary and the monitor bridge will NOT engage. Add this line, restart your shell,"
echo " then launch with codex:"
echo " export PATH=\"\$HOME/.agents/bin:\$PATH\""
;;
esac
echo "Codex monitor beta is enabled."
echo "Add this shell function to your interactive shell profile, then restart the shell:"
if "$SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh" function; then
echo "Future Codex sessions: launch with codex. In monitor-mode projects, the agmsg function routes interactive Codex sessions through the bridge."
echo "Optional global PATH shim is still available with:"
echo " $SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh install"
else
echo "Codex monitor mode is enabled, but the codex shim was not installed."
echo "Future Codex sessions: launch with $SKILL_DIR/scripts/drivers/types/codex/codex-monitor.sh, or resolve the shim install issue above."
echo "Codex monitor mode is enabled, but the codex shell function could not be printed."
echo "Future Codex sessions: launch with $SKILL_DIR/scripts/drivers/types/codex/codex-monitor.sh, or resolve the setup issue above."
fi
# Node preflight: the bridge (codex-bridge.js) is a Node program, so without
# Node it silently never starts — flag it at enable time. Resolve via the same
Expand All @@ -48,8 +40,8 @@ agmsg_delivery_on_disable() {
if [ "${stopped:-0}" -gt 0 ]; then
echo "Stopped $stopped Codex bridge process(es) for this project and cleaned their run files."
fi
echo "Note: the codex shim (~/.agents/bin/codex) is shared across projects, so it was left in place."
echo " If no other project uses monitor mode, remove it and restore your PATH:"
echo "Note: shell profile functions are not changed automatically."
echo " If you installed the optional global shim and no other project uses monitor mode, remove it:"
echo " $SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh remove"
echo " # then drop ~/.agents/bin from PATH if you added it for monitor"
echo " # then drop any agmsg Codex function or ~/.agents/bin PATH entry you added for monitor"
}
24 changes: 17 additions & 7 deletions scripts/drivers/types/codex/codex-shim-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ TARGET="$AGENTS_BIN/codex"

usage() {
cat <<EOF
Usage: codex-shim-install.sh [install|remove|status]
Usage: codex-shim-install.sh [function|install|remove|status]

Installs an optional agmsg Codex shim at:
Prints the recommended shell function for agmsg Codex monitor mode.
With no subcommand, prints the function.

The optional global PATH shim can still be installed at:
$TARGET

Put ~/.agents/bin before the real Codex binary on PATH. The shim only routes
interactive Codex launches through agmsg's monitor bridge when the current
project is in Codex monitor mode.
The function and PATH shim both route only interactive Codex launches through
agmsg's monitor bridge when the current project is in Codex monitor mode.
EOF
}

Expand All @@ -26,11 +28,19 @@ shell_quote() {
printf '%q' "$1"
}

cmd="${1:-install}"
cmd="${1:-function}"
case "$cmd" in
-h|--help)
usage
;;
function|print-function|shell-function)
cat <<EOF
# agmsg Codex monitor beta: put this in your interactive shell profile.
codex() {
$(shell_quote "$SCRIPT_DIR/codex-shim.sh") "\$@"
}
EOF
;;
install)
mkdir -p "$AGENTS_BIN"
if [ -e "$TARGET" ] && ! is_agmsg_shim; then
Expand All @@ -56,7 +66,7 @@ case "$cmd" in
case ":$PATH:" in
*":$AGENTS_BIN:"*) ;;
*)
echo "note: add $AGENTS_BIN before the real Codex binary on PATH"
echo "note: this optional global shim needs $AGENTS_BIN before the real Codex binary on PATH"
;;
esac
fi
Expand Down
8 changes: 7 additions & 1 deletion scripts/drivers/types/codex/codex-shim.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ else
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
fi

is_agmsg_wrapper() {
[ -f "$1" ] && grep -q "Optional Codex entrypoint shim for agmsg monitor mode" "$1" 2>/dev/null
}

resolve_real_codex() {
if [ -n "${AGMSG_REAL_CODEX:-}" ]; then
printf '%s\n' "$AGMSG_REAL_CODEX"
Expand All @@ -35,7 +39,9 @@ resolve_real_codex() {
candidate_dir="$(cd "$(dirname "$candidate")" 2>/dev/null && pwd || true)"
[ -n "$candidate_dir" ] || continue
candidate_path="$candidate_dir/$(basename "$candidate")"
if [ "$candidate_path" != "$self_path" ] && [ "$candidate_path" != "$shim_target" ]; then
if [ "$candidate_path" != "$self_path" ] \
&& [ "$candidate_path" != "$shim_target" ] \
&& ! is_agmsg_wrapper "$candidate_path"; then
printf '%s\n' "$candidate_path"
return 0
fi
Expand Down
10 changes: 5 additions & 5 deletions scripts/drivers/types/codex/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ Four possible outputs:
Manual $__SKILL_NAME__ only.

3) monitor — Real-time push (BETA, advanced)
Installs a `codex` shim on PATH and routes launches through an
app-server bridge. Opt in ONLY if you understand PATH precedence
and accept experimental behavior. See docs/codex-monitor-beta.md.
Prints a `codex` shell function that routes launches through an
app-server bridge. Opt in ONLY if you accept experimental behavior.
See docs/codex-monitor-beta.md.

[1]:
```

- **Wait for the user's answer before proceeding.** Empty input means `1` (turn).
- Map the chosen number to a mode (`1`→`turn`, `2`→`off`, `3`→`monitor`) and run:
`~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set <mode> codex "$(pwd)"`
- If monitor is chosen, tell the user: "Codex monitor is a BETA that changes how `codex` starts — it installs a `codex` shim and needs `~/.agents/bin` first on PATH. If the output says `~/.agents/bin` is not on PATH, add `export PATH=\"$HOME/.agents/bin:$PATH\"` to your shell profile, restart the shell, then launch future sessions with normal `codex`. If shim installation was refused because `~/.agents/bin/codex` already exists, use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` or resolve that command conflict. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md"
- If monitor is chosen, tell the user: "Codex monitor is a BETA that changes how `codex` starts — it prints a shell function to add to your shell profile. Add the printed function, restart the shell, then launch future sessions with normal `codex`. If you prefer a global PATH shim, run `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-shim-install.sh install` and put `~/.agents/bin` first on PATH. You can also use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` for explicit monitor launches. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md"

6. Then check inbox for the newly joined team.

Expand Down Expand Up @@ -143,7 +143,7 @@ If argument is "mode" (no further args):
If argument starts with "mode" followed by a mode name (e.g. "mode monitor"):
1. Parse the mode. Codex supports `monitor` (beta bridge), `turn`, and `off` — reject `both` with: "Codex bridge beta supports `monitor`, `turn`, or `off`; `both` is not supported yet."
2. Run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set <mode> codex "$(pwd)"`
3. If mode is `monitor`, tell the user: "Codex monitor beta is enabled. agmsg installs an optional `codex` shim automatically. If the output says `~/.agents/bin` is not on PATH, add `export PATH=\"$HOME/.agents/bin:$PATH\"` to your shell profile, restart the shell, then launch future sessions with normal `codex`. If shim installation was refused because `~/.agents/bin/codex` already exists, use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` or resolve that command conflict. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md"
3. If mode is `monitor`, tell the user: "Codex monitor beta is enabled. Add the printed shell function to your shell profile, restart the shell, then launch future sessions with normal `codex`. If you prefer a global PATH shim, run `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-shim-install.sh install` and put `~/.agents/bin` first on PATH. You can also use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` for explicit monitor launches. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md"

If argument is "hook on" (legacy alias):
1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set turn codex "$(pwd)"`
Expand Down
47 changes: 47 additions & 0 deletions tests/test_codex_shim.bats
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,57 @@ teardown() {
grep -q "monitor real=$FAKE_CODEX <--project> <$TEST_PROJECT> <--codex-command> <resume> <--> <--cd> <$TEST_PROJECT>" "$CALL_LOG"
}

@test "codex shim install: default prints shell function without installing bin wrapper" {
export HOME="$TEST_PROJECT/home"
mkdir -p "$HOME"

run bash "$TYPES/codex/codex-shim-install.sh"

[ "$status" -eq 0 ]
[[ "$output" == *"codex() {"* ]]
[[ "$output" == *"codex-shim.sh"* ]]
[ ! -e "$HOME/.agents/bin/codex" ]
}

@test "codex shim function: existing agmsg PATH wrapper is skipped when resolving real codex" {
export HOME="$TEST_PROJECT/home"
mkdir -p "$HOME"
bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null
bash "$TYPES/codex/codex-shim-install.sh" install >/dev/null
[ -x "$HOME/.agents/bin/codex" ]

local real_bin="$TEST_PROJECT/real-bin"
mkdir -p "$real_bin"
cp "$FAKE_CODEX" "$real_bin/codex"
chmod +x "$real_bin/codex"

PATH="$HOME/.agents/bin:$real_bin:$PATH" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" \
run bash -c 'eval "$("$TYPES/codex/codex-shim-install.sh" function)"; cd "$TEST_PROJECT"; codex resume --last'

[ "$status" -eq 0 ]
grep -Fq "monitor real=$real_bin/codex <--project> <$TEST_PROJECT> <--codex-command> <resume> <--> <--last>" "$CALL_LOG"
! grep -Fq "monitor real=$HOME/.agents/bin/codex" "$CALL_LOG"
}

@test "codex shim function: non-agmsg PATH codex remains eligible as real codex" {
export HOME="$TEST_PROJECT/home"
mkdir -p "$HOME/.agents/bin"
bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null
cp "$FAKE_CODEX" "$HOME/.agents/bin/codex"
chmod +x "$HOME/.agents/bin/codex"

PATH="$HOME/.agents/bin:$PATH" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" \
run bash -c 'eval "$("$TYPES/codex/codex-shim-install.sh" function)"; cd "$TEST_PROJECT"; codex resume --last'

[ "$status" -eq 0 ]
grep -Fq "monitor real=$HOME/.agents/bin/codex <--project> <$TEST_PROJECT> <--codex-command> <resume> <--> <--last>" "$CALL_LOG"
}

@test "codex shim install: installed bin wrapper still finds skill scripts" {
export HOME="$TEST_PROJECT/home"
mkdir -p "$HOME"
bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null
bash "$TYPES/codex/codex-shim-install.sh" install >/dev/null
[ -x "$HOME/.agents/bin/codex" ]

PATH="$HOME/.agents/bin:$PATH" run bash -c 'cd "$TEST_PROJECT" && AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" codex resume'
Expand Down
Loading