# codex-quality-plugin **Repository Path**: oliver_hjf/codex-quality-plugin ## Basic Information - **Project Name**: codex-quality-plugin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-20 - **Last Updated**: 2026-10-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Codex quality plugin Makes the code an agent writes compliant **at the moment it is written**. The plugin carries the general layer only. It is not tied to a repository, it works in every project, and it is installed once per machine. ## Layout ``` .agents/plugins/marketplace.json marketplace manifest plugins/codex-quality/ ├── .codex-plugin/plugin.json plugin manifest ├── hooks/hooks.json the two trigger points ├── scripts/codex_quality.py the implementation └── commands/quality-check.md /quality-check, a manual full pass templates/AGENTS.md contract template for ~/.codex/AGENTS.md install.sh install / uninstall / status ``` The hook file of a plugin lives in `hooks/hooks.json` **inside** the plugin directory. A `hooks.json` in the plugin root and a `hooks` object in `plugin.json` are both ignored by Codex 0.163.0 - the plugin ships with no hooks at all. The command of a hook runs with the plugin root as the working directory, and `$CLAUDE_PLUGIN_ROOT` points at it. ## Install ```sh ./install.sh install ``` It registers the local marketplace, installs the plugin, and prints the two steps that are left: restart Codex, and trust the hooks once in `/hooks`. Uninstall with `./install.sh uninstall`. ## The two halves of the contract | | where | how it loads | | --- | --- | --- | | rules a lint cannot judge | `~/.codex/AGENTS.md` | Codex loads it automatically, every session | | rules a machine can judge | this plugin | hook, on every tool call | The plugin does not carry the contract. `AGENTS.md` is a file in the user's home or in the repository, because that is where a team can read it, diff it, and commit it. A template is in `templates/AGENTS.md`. ## What the hook does `PreToolUse` - gate. A write that breaks a hard rule is refused and the reason tells the agent exactly what to change: ``` {"hookSpecificOutput":{"hookEventName":"PreToolUse", "permissionDecision":"deny", "permissionDecisionReason":"..."}} ``` `PostToolUse` - lint. The file that was just written is cleaned on disk, and what is left that needs a decision is reported back into the same turn: ``` [quality] I already cleaned this up, the code on disk is compliant: - demo.py: removed 2 commented-out code line(s); removed unused import(s): sys ``` Cleaned without asking the agent: commented-out code blocks, unused imports. Reported for a decision: linter findings on the lines the change touched, dead functions, stale TODO comments. ## The file on disk is the truth The hook does not trust the command to say which file changed. An agent that writes through `python3 -c open(...)`, `tee` or an editor leaves no redirect to parse, and a model that notices a rewrite will try to route around it. The hook therefore scans the source files that changed in the last few minutes and works on those, whatever wrote them. ## Verified on Codex 0.163.0 - event names are **PascalCase** (`PreToolUse`); camelCase is silently ignored - a command hook must be trusted before it runs (`/hooks`, or `--dangerously-bypass-hook-trust`) - three block mechanisms work: `permissionDecision: "deny"`, `{"decision": "block", ...}`, and exit code 2 with a reason on stderr - `permissionDecision: "ask"` is not supported - `updatedInput` rewrites the tool input and works, but only together with `permissionDecision: "allow"`; without it the hook fails - `prompt` and `agent` handler types are declared but **not implemented yet**; inject text with a command hook that returns `additionalContext` - `mcp_tool` handlers are supported - a plugin hook is only registered when the file is `hooks/hooks.json` under the plugin root; the plugin still needs one trust review per hook ## Known limits - `additionalContext` is advice, not a command: if it contradicts an explicit instruction, the agent may keep its own version. Use `PreToolUse` to make a rule absolute. - The lint dispatch only runs tools that are installed; missing tools are skipped silently. Install `shellcheck` and `ruff` for full coverage. - The cleanup only touches languages whose import list is static (Python, Go, JavaScript), because a hook cannot know whether an import was needed by dynamic loading.