npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ascenda-one/codex-hooks

v0.1.35

Published

OpenAI Codex hooks adapter for Ascenda AI workload telemetry

Readme

Ascenda Codex Hooks

OpenAI Codex hooks adapter for Ascenda AI workload telemetry.

Part of ai-engineer-tools. Event mapping: docs/CODEX_MAPPING.md. Codex hooks reference: developers.openai.com/codex/hooks.

What it sends

Metadata only. It doesn't send prompts, responses, code, file names, repository names, branch names or terminal output. Privacy defaults has the detail.

It records the same signals as the Claude Code hooks, from Codex sessions:

| Signal | What the hook records | | --- | --- | | Agent interaction | That a prompt, correction loop or compaction happened, and for each tool call the tool's name (shell, apply_patch) | | Long agent runs | Session starts, and that a turn ran long (agent_loop_long, measured locally) | | Friction | Tool failures and context pressure | | Verification | A test, lint or build command ran (editor_verification_activity / compile_error) |

Identity: Codex rides the canonical cli_agent toolType/source (the backend registry has no codex value yet); events carry metadata.host: "codex" for later disaggregation.

Hook safety contract

Codex awaits command hooks and treats exit code 2 as blocking the user's action. This adapter therefore always exits 0 and caps every HTTP call at 3 s (ASCENDA_HTTP_TIMEOUT_MS to change): telemetry failures surface as a one-line systemMessage or stderr note and never stall or block the engineer.

Install

Prerequisites

  • Codex CLI with hooks support (v0.117+)
  • Node.js 20+

1. Set up

One command pairs Codex, installs the hook binary, and registers the hooks:

npx -y @ascenda-one/codex-hooks setup

It prints a 6-digit code — confirm it in the Ascenda app under Connections → Ingest telemetry — then writes:

  • the write token to ~/.ascenda/tokens/
  • the pairing to tools.codex in ~/.ascenda/credentials.json
  • the hook entries to ~/.codex/hooks.json

There is no shell profile line to add. Codex reads its identity from the credentials file, which is per agent — so pairing Codex cannot disturb a Claude Code or Cursor pairing on the same machine, and a Codex hook launched from the Dock with an empty environment still names itself correctly.

Hooks register machine-wide by default. --scope project puts them in <cwd>/.codex/hooks.json instead, for that project only. Each hook runs through a small launcher at ~/.ascenda/bin/ascenda-codex-hook that finds Node 20 or newer itself, so hooks keep working when Codex starts without your shell's PATH. --no-pair installs without pairing: the screen saver and live view work, and nothing is sent.

2. Check it

npx @ascenda-one/codex-hooks status
~/.ascenda/bin/ascenda-codex-hook doctor

status names the pairing, the Node the hooks will run, the last hook Codex ran and how many events are registered. It exits non-zero when something is missing, so it can gate a CI step. doctor also checks the live signal, and pings the Waterline screen saver when it is running.

To undo everything it wrote:

npx @ascenda-one/codex-hooks uninstall

3. Restart Codex and review hooks

Open /hooks in the Codex CLI and review and trust the Ascenda commands. Codex skips untrusted hooks; registration and workspace trust alone do not authorize them. Changes to a hook definition require review again. See the Codex hook trust reference.

The setup command registers hooks but does not write Codex trust hashes or bypass review. A successful status checks installation, not runtime trust or accepted delivery.

On a Dev backend with no phone

setup --local points at the dev server, which auto-confirms the pairing:

node ../ascenda-dev-server/dist/cli.js      # in another terminal
npx @ascenda-one/codex-hooks setup --local --scope user

--api-base-url takes any other host; the default is https://api.ascenda.one.

Registering hooks by hand

setup is the supported path. examples/hooks.json is the same content for anyone who would rather merge it themselves, or who needs the inline config.toml form:

[[hooks.UserPromptSubmit]]
[[hooks.UserPromptSubmit.hooks]]
type = "command"
command = "npx -y @ascenda-one/codex-hooks UserPromptSubmit"
timeout = 10

A hand-merged file still needs a pairing — run setup for that, or export ASCENDA_TOOL_INSTALLATION_ID yourself. A matching cli_agent: id or an unqualified id overrides the credentials file. An id qualified for another tool type, such as claude_code:, is ignored so a shell-wide setting cannot redirect Codex events to that pairing. Multiple agents using cli_agent should use per-host credentials instead of a shared environment override.

Verify

Run a Codex session, then read the send journal at ~/.ascenda/state/<installationId>.json. Look for lastOutcome: "accepted" and a fresh attempt timestamp. The journal records delivery attempts under the resolved installation id, not hook process starts. An absent expected journal can also mean a different identity was selected, input processing failed before delivery, or the hook mapped to no event. Check the local event log for metadata.host: "codex" and confirm its toolInstallationId matches tools.codex in the credentials file. The hook always exits 0, so its exit code alone cannot prove delivery.

An unpaired install logs every payload to ~/.ascenda/events.jsonl. On a paired one, setup --event-log or ASCENDA_EVENT_LOG_FILE turns the same log on, and off turns it off.

Build from source

Not needed to use this — npm ships it prebuilt. It is here so you can verify what runs.

# from the repo root (workspace install + shared packages first)
npm install
npm run build:shared

cd ascenda-codex-hooks
npm run build
npm link                # exposes `ascenda-codex-hook`
which ascenda-codex-hook

npm run test            # unit tests for the mapping
npm run test:sample     # pipes a sample PostToolUse payload through the CLI

A local build exposes the binary as ascenda-codex-hook — substitute it for npx -y @ascenda-one/codex-hooks in the hook config above. If it is not on Codex's PATH, use the absolute path to the binary.

Supported Codex hook events

SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PreCompact, PostCompact, Stop, PermissionRequest. (SubagentStart and SubagentStop have no catalog counterpart and are skipped.)

PermissionRequest records that the agent stopped at an approval gate, and nothing about what it was asking to do — one field, interruptionKind: "permission_request". The command, its arguments and the paths involved are never read.

Turn duration

Codex's Stop payload has no duration, so the adapter records a turn-start timestamp per session under ~/.ascenda/state/ at UserPromptSubmit and consumes it at Stop; turns of 30+ minutes emit agent_loop_long, and every turn emits ai_turn_completed. State failures degrade silently to "no duration".

Privacy defaults

Metadata-only. Does not send prompts, responses, code, file names, repository names, branch names, or terminal output. Correction detection runs locally on prompt text; only the classification is transmitted. consentScope: ide_telemetry, provenance: ai_work_telemetry on every event.

Repository and branch identity travel only as machine-salted digests, never as text: workspaceHash/projectHash from folder names, and metadata.branchHash from the branch the checkout is on. A branch name is low-entropy, so that digest is not a security boundary — the machine salt is what makes the input space unguessable. On a detached HEAD, outside a checkout, or with no readable salt the key is omitted rather than sent blank.