Hooks and runtime
Marketing Hooks and runtime behavior
Understand the Marketing Kit automation that runs around tool use, how supporting files differ from active Hooks, and what each runtime can project.
Marketing Kit adds background checks and reminders around normal work. A Hook becomes active when the runtime connects an event to an entrypoint. Manifests, libraries, and utilities shipped beside that entrypoint are artifacts, not additional automatic behaviors.
Active outcomes
| Moment | What the active Hook graph does |
|---|---|
| Before tool use | Checks descriptive naming before writes, checks file and shell operations for privacy-sensitive access, catches broad read or shell exploration that should be narrowed, checks how much content a read, search, or shell command can return, and substitutes ${secret:NAME} references in shell commands and fetch URLs. |
| After edits | Tracks supported edit activity and can remind the workflow to simplify and review substantial changes. Claude Code includes MultiEdit; Codex narrows this matcher to `Edit |
| When you submit a prompt | Checks for requests that could expose secrets and surfaces applicable development-rule guidance. |
These behaviors can add guidance or stop an operation for review, depending on the event and runtime. They are workflow guardrails, not a general security boundary or a replacement for the runtime's own permission controls.
The reused context-firewall Hook runs before Bash, Read, Grep, and
Glob calls. It warns about a whole-file read of 256 KB or more, a shell dump
of 128 KB or more, an unbounded content search, and unbounded log, history,
or recursive shell output. It blocks a whole-file read of 2 MB or more, a shell
dump of 512 KB or more, and an unbounded content search with a broad pattern,
and names a bounded alternative. The third intervention on the same operation
in one session becomes a block. The Hook is on by default and fails open; set
hooks.context-firewall to false to turn it off, as described in Managing
Hook preferences.
Secret references in tool calls
The secrets-inject Hook runs before Bash and WebFetch calls. When a shell
command or fetch URL contains a ${secret:NAME} reference, the Hook asks
ak secrets resolve for the stored value and substitutes it in memory, so the
model can compose the call without seeing the credential. Only Bash.command
and WebFetch.url are scanned; file contents and prompts are left untouched.
An ak secrets grant for the calling agent binary decides whether a
value is released, and a grant restricted with --allow-host also checks the
fetch destination.
Every failure blocks the tool call rather than passing the literal reference
through, including a missing grant, an invalid name, or a value with
shell-special characters bound for a Bash command. The Hook writes no copy of
the value, but the substituted input still reaches the tool process and
whatever the runtime records for an executed call, such as its transcript.
Treat a released value as present on the host and rotate it when needed.
Claude Code and Grok register the Hook for Bash|WebFetch, and Codex narrows it
to Bash. Cursor support for this Hook is not established in this release.
Background auto-update liveness
The session-heartbeat.cjs Hook is registered on SessionStart,
UserPromptSubmit, Stop, and SessionEnd. It writes a per-session marker
under the AgentKit home so the opt-in background auto-update
skips a project with a live agent session, and removes that marker at
SessionEnd. On SessionStart, it also prints a one-line notice for an
unacknowledged background-update result, acknowledged with
ak update --status --ack --json. The Hook never blocks a session and exits
0 even on its own failure.
Artifact entries are not behavior counts
The Marketing manifest declares nine Hook file exports:
- The
hooks.jsonmanifest itself. - One Marketing-specific automatic entrypoint provides the post-edit reminder.
- One manual Discord sender is shipped as a utility.
- Six libraries support configuration and bounded runtime state.
The separate hooks.json manifest wires the Marketing entrypoint together with
nine reused core entrypoints, including context-firewall, secrets-inject, and session-heartbeat. Support libraries do not run independently, and
none of these entries is a Marketing command.
notifications/send-discord is not referenced by hooks.json. It runs only
when a caller deliberately invokes it; installing Marketing Kit does not enable
Discord notifications automatically. Its failure paths are non-blocking.
Runtime projection
| Runtime | Projected behavior |
|---|---|
| Claude Code | Activates the configured event graph through native or plugin delivery. The separate Marketing statusline is also available here and can show directory, Git, model, context and usage, changed-work, configuration, and activity signals. |
| Codex | Translates representable groups into .codex/hooks.json. Its tool matcher set is narrower than Claude Code's, so some trigger coverage can be removed even when the rest of a group remains active. The Marketing statusline is not projected. |
| Cursor | Translates supported registrations into .cursor/hooks.json. Source-level projection does not establish identical behavior across every provider setup. The Marketing statusline is not projected. |
Codex behavior in this release
- Marketing projects no fully dropped Codex group and five narrowed matchers. Shared
Read|Write|Edit|BashbecomesWrite|Edit|Bash; sharedBash|ReadbecomesBash; sharedBash|Read|Grep|GlobbecomesBash; sharedBash|WebFetchbecomesBash; Marketing'sEdit|Write|MultiEditbecomesEdit|Write. The original handlers remain active for the supported atoms. - Human output reports narrowing under Hook matchers narrowed (some tool matches unsupported on this target). Machine-readable output uses optional
hookMatchersNarrowedandnarrowedHookSummaries; full-drop fields remain absent for this projection. - On Windows, an eligible
.cjsHook under the Codex home can use a managed.cmdshim when an ordinary path contains spaces. A spaced.cjspath outside that home remains unshimmed. Paths withcmd.exemetacharacters, non-ASCII shim basenames, and unsafe or non-ASCII baked arguments also remain refused, so this is not a blanket compatibility guarantee. - A wrapper-managed Codex home may alias only its final
hooksleaf to canonical~/.codex/hooks, using a POSIX symlink or a Windows directory junction; writes, translated commands, rollback, and ownership use that canonical identity. Linked parents and other targets are refused. - Shared global Hook registration preserves user and foreign structures, supports matching ownership across Kits, and cleans up only exact stale claims. The stronger rollback and cleanup handling does not authorize deleting arbitrary content from
~/.codex/hooks.json.
These changes improve disclosure and ownership handling. They do not make Hook behavior identical across runtimes or turn Marketing Hooks into a security enforcement boundary.
Ownership and lifecycle
AgentKit records the Hook files, managed Windows shims, and registrations it emits. Refresh and uninstall act on matching owned outputs while preserving or reporting modified, foreign, and sibling-Kit content. Project and user installations can coexist, so inspect both scopes if an automation appears twice.
Review the install summary and warnings after every install or refresh. A successful install can still contain a runtime-specific projection limit.
For the wider compatibility model, see Runtime adapters. For lifecycle commands, see Installing kits.