Skip to content
This repository was archived by the owner on Jul 24, 2026. It is now read-only.

Latest commit

 

History

History
50 lines (34 loc) · 4.27 KB

File metadata and controls

50 lines (34 loc) · 4.27 KB

Codex hooks for smalltalk

Reference scripts that wire smalltalk into Codex CLI via its hook system. They make Codex aware of unread smalltalk messages without requiring real-time push (Codex has no channel equivalent — only these polling-style hooks).

What's in here

  • session-start.shSessionStart hook. Reads $ST_ROOT/$ST_AGENT/inbox/ via st message ls --json and emits the unread snapshot as additionalContext so the agent sees pending smalltalk messages the moment it boots.
  • stop.shStop hook. Same shape, run when the agent goes idle. Tracks a state file ($XDG_STATE_HOME/st-codex-hooks/last-checked.txt) so it only reports messages that arrived since the previous Stop — empty delta means silent idle.
  • config.toml.example~/.codex/config.toml fragment registering st mcp as an MCP server and pointing the hook entries at the two scripts above.

Install

  1. Make sure st and jq are on your $PATH.
  2. Copy or symlink the two .sh scripts into ~/.codex/hooks/ (or anywhere Codex can read; the config snippet expects absolute paths).
  3. Merge config.toml.example into your ~/.codex/config.toml. Update the command = "/full/path/to/..." lines to point at wherever you placed the scripts.
  4. Set ST_ROOT and ST_AGENT in the shell that launches codex — the env_vars passthrough in the MCP block hands them to st mcp, and the hooks read them directly.
  5. Restart Codex.

What you get

  • At session start: the agent's first turn sees an additionalContext block listing every file in your inbox with sender + subject. It can then call st_msg_read (via the MCP server registered in the same config) to inspect any of them.
  • On idle: the Stop hook re-checks for arrivals since the previous Stop. Only NEW messages trigger the injection; quiet inboxes idle silently.
  • Verbs: st_msg_send, st_msg_ls, st_msg_read, st_msg_archive, st_msg_thread — the same five tools every other MCP host gets. Use them in chat the way you'd use a built-in capability.

Push mode (st ding)

Codex itself has no channel equivalent, so push semantics come from outside the agent: run Codex inside a pty session, then arm st ding against that session. The daemon watches the inbox + status, and on every new arrival pty-sends a one-line notice into Codex when the agent is available (or offline); busy and dnd buffer the notice until status flips back.

# In one terminal: run Codex inside a named pty session
pty run --name codex-foo -- codex

# In another: arm the ding daemon for that session
ST_ROOT=~/.local/state/smalltalk ST_AGENT=me \
  st ding codex-foo --interval 2000

The daemon is long-running; pair with pty up (or systemd, launchd, etc.) for restart-on-crash. Set st status me --set busy to stop deliveries while a turn is mid-flight; st status me --set available flushes the buffered notices.

Limitations

  • Hooks alone aren't push. The SessionStart and Stop hooks fire at the boundaries of a turn — smalltalk messages that arrive mid-turn don't surface until the next Stop. Combine with st ding (above) for true push, or run Codex alongside a Claude Code session in channel mode (see walkthrough.md).
  • Filename-ts filtering. stop.sh filters by the <unix-ms> prefix of the filename. Sync-delivered files whose prefix is older than the last checkpoint are missed — Stop is a notification cue, not a backfill audit.
  • Single-agent assumption. The state file is global; running Codex with different ST_AGENT values against the same $HOME will cross-pollinate the cursor. If that bites, edit the script to scope the state path under the agent name.

Troubleshooting

  • Nothing happens on session start. Check $ST_AGENT / $ST_ROOT are exported in the shell that launches Codex; if they're empty the hook exits non-zero with a stderr message that Codex usually surfaces in its log.
  • st-codex-hook: jq not on PATH. Install jq (brew install jq, apt install jq, etc.). The hook uses jq to construct the JSON envelope.
  • The same messages keep getting injected on every Stop. The state file isn't being written. Check that $XDG_STATE_HOME/st-codex-hooks/ (or ~/.local/state/st-codex-hooks/) is writable.