Skip to content

feat: add Codex-style lifecycle hooks#10

Merged
morganlinton merged 6 commits into
GetSmallAI:mainfrom
dedene:feature/hooks
Jul 2, 2026
Merged

feat: add Codex-style lifecycle hooks#10
morganlinton merged 6 commits into
GetSmallAI:mainfrom
dedene:feature/hooks

Conversation

@dedene

@dedene dedene commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds Codex-style lifecycle hooks to Small Harness.

Hooks let local commands observe or influence harness events: session start/end, prompt submission, tool use, permission requests, compaction, plan updates, subagent start/stop, and stop events.

Demo

The first concrete integration is Zentty agent status, shown in the demo below.

Zentty.2026-06-16.21-26-07.mp4

Codex-style hook model

The hook model follows Codex closely:

  • hooks are grouped by event and optional matcher
  • command hooks receive JSON on stdin
  • command hooks can return JSON decisions on stdout
  • supported decisions are allow, deny, block, and stop
  • hooks can also return updatedInput, additionalContext, and feedback
  • exit code 2 maps to a blocking decision
  • default timeout is 600 seconds for Codex parity
  • /hooks lists configured hooks and manages trust

Project hooks do not run just because a repo config declares them. They must be reviewed and trusted by current definition hash first. If the hook definition changes, it is treated as modified and skipped until trusted again. Project-controlled hook state is ignored.

This also adds process-local managed launch hooks through SMALL_HARNESS_MANAGED_HOOKS_JSON and SMALL_HARNESS_MANAGED_HOOKS_FILE. These are for launchers that already own the Small Harness process, like Zentty. They are modeled after Codex managed hooks, but they are not Codex enterprise/MDM managed hooks or cryptographic signatures.

Environment forwarding

Hook subprocesses still start from a cleared environment by default. That keeps provider credentials out of hooks unless a hook explicitly asks for them.

For launcher integrations, hooks can now use:

  • env for literal values
  • envVars to forward selected parent process variables

That lets a Zentty hook receive only the socket, worklane, pane, and pane token values it needs to report status back to the sidebar.

Hook hardening

This also includes a few safety details around hook execution:

  • invalid matcher regexes are visible in /hooks but skipped
  • PreToolUse and PermissionRequest runner failures fail closed
  • hook subprocesses are cleaned up by process group on timeout
  • hook stdout/stderr previews are bounded and redacted in traces
  • hook-provided model context is bounded and redacted before injection
  • hook env changes are included in the trust hash

Small fixes included

Two small fixes came out while testing this branch:

  • close the turn event channel after the agent future completes, so plain streaming turns can finish, save transcripts, run stop hooks, and return to input mode
  • keep hidden reasoning deltas from closing and reopening the visible response block when reasoning display is disabled

Test plan

  • cargo fmt --check
  • cargo test hooks::tests
  • cargo test

dedene added 6 commits June 20, 2026 20:28
Allow hook configs to forward named parent environment variables and define literal hook environment values while preserving the cleared-env default for credentials.
Drop the outer tool runtime context before waiting for the event-drain future so the mpsc channel closes once the agent future returns. This lets turns finish, save transcripts, run stop hooks, and return to raw input mode.
Ignore reasoning deltas for response layout when the reasoning panel is disabled. This prevents models that stream thinking fields from repeatedly closing and reopening the visible response block.
@morganlinton morganlinton merged commit 07dd623 into GetSmallAI:main Jul 2, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants