Burn gate
Uses the published Burn gateway for subagent spawning and sustained-burn observations. It keeps the existing Burn policy, reservations, ledger and receipts under AGENTGUARD_HOME or ~/.agentguard.
Plugin 0.2.2 ยท Operator reference
Signed tool decisions, matter budgets and session tool policies. Start in free shadow mode, then activate an existing license when you want enforcement.
codex plugin marketplace add MerchantGuard/agentguard-codex-plugin
codex plugin add agentguard@agentguard
npm ci
Run the first two commands in your terminal. Change into the installed plugin root reported by Codex before running npm ci. Then start a session and review all five commands in /hooks.
Requires Node.js 22. The public marketplace selects the Codex 0.154 compatibility installation. Installing a plugin does not trust its hooks.
This page follows the public plugin source. It describes the runtime's current behavior, including what happens when a hook cannot answer.
AgentGuard applies policies to every local tool call that Codex or ChatGPT Work sends through its hook path, including plugin MCP tools. Two PreToolUse gates and one PostToolUse recorder match .*. A separate SessionStart hook starts license resolution.
Uses the published Burn gateway for subagent spawning and sustained-burn observations. It keeps the existing Burn policy, reservations, ledger and receipts under AGENTGUARD_HOME or ~/.agentguard.
Applies tool patterns, capability tiers and configured unit costs to other tool calls. Supported hook paths include Bash, apply_patch, Edit, Write, update_plan, spawn_agent and MCP tools.
Web ChatGPT and hosted tools such as WebSearch are outside this hook path. An already-approved shell session can receive write_stdin without another pre-tool decision, and specialized tool paths can opt out. This is not universal interception. See the host's tool coverage documentation.
An internal error allows the call, exits successfully, emits a one-line warning and records a fail-open event when local storage is writable. A dead process, full disk, inaccessible directory or disabled hook can prevent that record. If the signed writer is unavailable but storage works, the client queues content-free recovery metadata. Those pending rows are unsigned until recovery. An absent receipt does not prove that a tool was never used.
The warm response budget defaults to 250 ms. hookBudgetMs can change it up to 1900 ms, leaving 100 ms before the host's two second timeout. Cold startup keeps its 1500 ms budget. Process startup, scheduling and operating-system delays can add wall time. Burn's combined synchronous decision, reservation, receipt and ledger operation remains inside the same response budget.
Keep authorization at the tool or service boundary when a failed hook must never permit access. MDM delivery does not turn fail-open hooks into fail-closed authorization.
@agentguard-run/spend ^0.20.0 and @agentguard-run/burn ^0.2.3, with no sibling links. Marketplace installation does not install them automatically./hooks, inspect the startup command, both tool gates and the receipt command, then trust the reviewed definitions.agentguard-status to check the effective mode. A configured enforce policy remains shadow until a usable license is available.Provisioning may access npm. Hooks communicate through a private filesystem mailbox and never open a socket. In a Codex cache installation, postinstall also provisions the locked dependencies in the persistent plugin data directory, because Codex 0.154 can replace its install cache at session start. Run npm ci again after a lockfile change. For a managed installation, set PLUGIN_DATA to the intended private runtime directory during provisioning.
Trust is pinned to each normalized hook definition. Changed definitions need review again. User hooks can take precedence over conflicting plugin decisions, and other matching hooks can run alongside these hooks. Read the host's review and trust guide.
The marketplace points at compat/codex-0.154/agentguard. This generated installation has .codex-plugin/plugin.json and .mcp.json, with the same hook code, policies, skills and assets. Codex 0.154 skips portable hook sources, so installing the portable root directly can expose MCP tools without running the hooks.
Compatibility hooks return an empty success response for unchanged allowed input, as required by that release's parser. Denials and signed decisions retain their values. The MCP launcher derives the same data directory as the hooks from the validated installation cache path, or accepts an explicit PLUGIN_DATA. Future host versions and ChatGPT Work need their own installation validation.
Maintainers regenerate compatibility files with npm run build:compat and check them with npm run check:compat. See the source-linked compatibility reference.
A firm can distribute its reviewed copy through .agents/plugins/marketplace.json, pointing the plugin entry at the compatibility installation. Register that marketplace and install from it. A marketplace named firm uses the selector agentguard@firm. In a supported desktop surface, select the marketplace in the Plugins Directory and install in a new chat. Node, scripts and dependencies must exist wherever Work executes them.
A public repository is not a universal directory submission. Workspace-wide publication is a separate administrator action. See the host's marketplace and packaging guide.
| License | Plugin behavior | Seats |
|---|---|---|
| Free | Signed decisions in shadow mode. No tool call is blocked. Burn why and pace remain free. Chain verification is free. | No paid seat allocation |
| Solo, including Solo Pro | Enforce mode, team policy files, receipt export and seat metering. A policy can still choose shadow. | 1 |
| Startup, including Startup Pro | The same paid plugin features. | 5 |
| Growth, including Growth Pro | The same paid plugin features. | 50 |
Use an existing license or see pricing. Ask the agentguard-policy skill to activate license <KEY>. Its helper accepts the key on standard input, writes licenseKey into ${PLUGIN_DATA}/policy.json, preserves unrelated settings and resolves the current session again. Do not put the key in shell command arguments or an audit entry. AGENTGUARD_LICENSE_KEY takes precedence over a saved key.
At session start, a detached process makes one license refresh attempt through the Spend SDK. The two second deadline covers validation and seat registration. Hook processes only read the local result. Without a usable cached license, they stay in shadow while resolution finishes.
A previously valid cache can remain usable offline for seven days after expiresAt. An explicit server rejection does not receive that grace. After the grace period, the engine selects shadow with license_required. An exceeded seat limit selects shadow with seat_limit. Licensing never denies a tool call.
The shared KV store counts all sessions on a license across machines. A seat stays active for fifteen minutes after its last heartbeat, and its license record expires after twenty four hours. Each live session renews every five minutes from the worker, never from a hook. Heartbeat failures and later over-limit responses do not change the current session mode. Status shows seats used, the limit, seatStorage and seatsVerified. Memory fallback is explicitly unverified. A failed heartbeat marks any retained count as an older, unverified observation. Renewal stops at SessionEnd or host exit; an unidentified host uses a fifteen minute lease renewed by tool activity.
The runtime reads ${PLUGIN_DATA}/policy.json. If it is absent, the packaged default requests enforce mode, permits capability tiers through payment_execute, and sets no unit prices, caps, explicit denies or session mappings. Licensing still controls the effective mode. A corrupt file causes a recorded fail-open.
A paid operator can set teamPolicyFile or the AGENTGUARD_PLUGIN_POLICY environment variable. Relative paths resolve from PLUGIN_DATA; the environment variable takes precedence. Shared top-level fields replace matching local fields, rather than merging nested rules. A local license key is preserved. Free sessions use the personal rules. Burn keeps its separate existing policy.
Use identifiers and regular expressions, not document content, prompts or provider credentials. licenseKey is the sole credential exception and never enters the ledger. Protect policy files from agent modification when they serve as organizational controls.
| Field | Value and behavior |
|---|---|
version | Required integer 1. Other values are invalid. |
tenantId | Tenant identifier used in actor scope and cap keys. Default: local. |
mode | enforce or shadow; omitted means enforce is requested. A usable paid license is required for enforcement. |
hookBudgetMs | Positive safe integer for the warm response budget. Default: 250. Values above 1900 are capped; invalid values use the default. Cold startup stays at 1500. |
licenseKey | License key saved locally by the activation helper. AGENTGUARD_LICENSE_KEY overrides it. Never copy it into a shared policy or receipt. |
teamPolicyFile | Paid shared policy path. A relative path starts at PLUGIN_DATA. AGENTGUARD_PLUGIN_POLICY overrides this selection. |
defaultMatterId | Default identifier for actor.taskId. A session's matterId overrides it. |
maxCapability | Highest permitted capability tier. Omission adds no ceiling; the packaged default is payment_execute. |
allowedTools | Array of tool-name regular expressions. Omission allows tools past this check; an empty array matches nothing. Global and session allowlists both apply. |
deniedTools | Array of explicit tool-name deny patterns. Default: empty. Independent of costs and allowlists. |
ethicalWall | Array of tool-name deny patterns recorded as ethical_wall. Default: empty. This does not inspect document content or infer conflicts. |
paymentPattern | Case-insensitive expression tested against the provider and tool/model name. Default: payment|pay_|charge|transfer|checkout|purchase. A match claims at least payment_initiate. |
toolRules | Ordered array of matching tool rules below. Later matching rules replace values they explicitly supply. |
caps | Array of spend caps below. Matching global and session caps apply together, with the most restrictive exceeded action winning. |
sessions | Object keyed by actual host session ID. Each value accepts the session fields below. Unknown session IDs use the root rules. |
Tool patterns use case-insensitive JavaScript regular expressions. Anchor an exact tool name with ^ and $. Tool rule patterns and list patterns have a 512-character limit. A matching deny or wall remains a restriction even when a monetary cap would allow the call. In shadow mode these checks record what would happen without denying the tool.
| Field | Value and behavior |
|---|---|
pattern | Required tool-name regular expression, up to 512 characters. Applies to the full name, such as mcp__documents__save_document. |
capability | Capability classification for matching calls. Rules cannot lower the built-in classification of a file write or payment-like call. |
requiredCapability | Minimum capability claim required by the Spend policy evaluator for matching calls. |
unitCostCents | Non-negative safe integer charged once per allowed or shadow call for cap accounting. Default: 0. These are operator-configured units, not observed provider charges. |
Unpriced tools cost zero in this ledger. The accounting uses a synthetic input-token unit in the Spend pricing path; those token counts are not measured model usage. A configured cap cannot limit unknown third-party charges.
| Field | Value and behavior |
|---|---|
window | Required: per_call, per_minute, per_hour, per_day or per_month. The plugin's in-memory store uses fixed windows; its month is a 30-day interval, not a calendar month. |
amountCents | Required non-negative safe integer. The cap is exceeded when projected configured spend is greater than this amount. |
action | block, shadow or allow. Default: block. The plugin does not accept the SDK's downgrade action. |
selector | Optional object of exact actor-field matches. Every supplied field must match. Omission shares the cap across the policy's tenant scope. |
reason | Optional short identifier forwarded as cap metadata to Spend. The plugin's displayed reason is a stable policy reason code. Do not put content or credentials here. |
| Field | Source and limits |
|---|---|
tenantId | The root tenant identifier, defaulting to local. |
agentId | Host agent_id, then the session's configured agent ID, then its session ID. No separate subagent accounting is possible without a distinct identity. |
taskId | The session's matterId or root defaultMatterId. |
sessionId | Actual host session ID. Every session-level cap is automatically scoped to its session, overriding a supplied session selector. |
provider | The MCP server segment of mcp__server__tool, or codex for a local tool. The tool segment becomes the model name. |
userId | Accepted by cap validation, but current plugin calls do not populate this actor field. A selector requiring it does not match. |
teamId | Accepted by cap validation, but current plugin calls do not populate this actor field. A selector requiring it does not match. |
Selector values must be strings. workflowId is not an accepted plugin cap selector. Identical selector and window combinations share spend; adding another cap on that combination does not charge the call twice.
| Field | Value and behavior |
|---|---|
matterId | Sets actor.taskId for this session, overriding defaultMatterId. |
agentId | Operator mapping used when the host does not supply agent_id. |
allowedTools | Additional allowlist. When present, a tool must match this list and any root allowlist. |
deniedTools | Additional explicit tool denies. Root denies still apply. |
ethicalWall | Additional tool-name wall for this session. Root wall patterns still apply. |
maxCapability | Additional tier ceiling. It cannot loosen a more restrictive root ceiling. |
caps | Additional caps with the same fields as root caps. The runtime adds the actual session ID to each selector. |
Sessions do not override the root mode, license, tool rules or payment pattern. Unknown fields are not a way to add a supported feature; use the fields documented here.
| Tier | Classification |
|---|---|
read_only | Default classification for other tools, unless a matching payment pattern or tool rule raises it. A tool's name does not prove its real effects. |
data_write | Built-in minimum for Bash, apply_patch, Edit and Write. Assign this tier to document-writing MCP tools with a rule. |
payment_initiate | Built-in minimum when the configurable payment expression matches the provider and tool/model name. |
payment_execute | Explicit higher classification available to an operator's tool rule. Classification grants no payment credentials. |
capability describes the call's claim, requiredCapability sets the policy's minimum claim, and maxCapability places a ceiling on a session. Tool allowlists and ethical walls remain independent checks.
This example uses synthetic identifiers and illustrative configured amounts. Replace the session key with a real host session ID. The document save costs two configured cents, the matter cap is 500 cents per day, and the session cap is 50 cents per day. In free mode, the same rules produce signed shadow decisions without blocking.
{
"version": 1,
"tenantId": "example-firm",
"mode": "enforce",
"hookBudgetMs": 250,
"defaultMatterId": "matter-example",
"maxCapability": "data_write",
"allowedTools": ["^mcp__documents__(search_documents|read_document|save_document)$", "^mcp__agentguard__(get_status|list_decisions|verify_chain|export_receipts)$", "^update_plan$"],
"deniedTools": ["^Bash$"],
"ethicalWall": ["^mcp__restricted_matter__.*$"],
"toolRules": [{"pattern": "^mcp__documents__save_document$", "capability": "data_write", "unitCostCents": 2}],
"caps": [{"selector": {"taskId": "matter-example"}, "window": "per_day", "amountCents": 500, "action": "block"}],
"sessions": {
"session-example": {
"matterId": "matter-example",
"agentId": "reviewer-example",
"ethicalWall": ["^mcp__other_matter__.*$"],
"caps": [{"window": "per_day", "amountCents": 50, "action": "block"}]
}
}
}
For a read-only review, set that session's maxCapability to read_only and limit its allowedTools to document reads, planning and the desired AgentGuard read-only tools. Do not silently exempt plugin tools from an allowlist.
An ethical wall is a list of tool-name patterns, not a content classifier or a conflicts database. Pair it with service-side permissions. A request blocked by a policy does not authorize the agent to loosen that policy.
The signed chain is ${PLUGIN_DATA}/ledger/decisions.ndjson. Decisions record tool names, input SHA-256, byte counts, actor identifiers, configured cost and the policy result. They never retain tool input content or output text. Tool names and identifiers can still be sensitive metadata, so protect the policy, private signing key and records.
Outcome receipts link to the preceding decision ID. Host timing is preferred; otherwise duration is elapsed pre/post time, including scheduling. Explicit errors and structured exit codes determine success. Codex 0.154 unified Bash provides raw output without an exit code, so those receipts use status: "unknown" and success: null. The plugin does not parse output text to guess success.
Before replying, the worker signs and writes each complete plugin ledger row to the operating system; a later asynchronous sync confirms a durable chain head, so a crash or power loss can lose an unconfirmed tail. On restart it verifies surviving rows against that head, discards only an incomplete final row beyond it, and appends a signed integrity event when surviving evidence shows an unconfirmed tail or sync failure; complete invalid rows are never silently repaired.
An older ledger without a durability checkpoint receives one conservative integrity event at first startup. Existing signed rows remain intact. Status counts integrity events separately from tool decisions and configured spend.
Use the agentguard-status skill for an operator summary or the optional local MCP tools below. These tools are read-only: they do not change policy, execute business tools or write an export file.
| Tool | Result |
|---|---|
get_status | Tier, seats used, limit, storage verification, expiry, effective mode and reason; UTC-day decisions, configured spend, blocks, outcomes, integrity events and fail-open health. Supply the known sessionId when available. |
list_decisions | A bounded page of content-free decision summaries, using fromSequence and limit. |
verify_chain | Verifies hashes and signatures against the local public verification key. Available on every tier. |
export_receipts | Returns a bounded page of signed receipts and the public key when a usable paid license is present. The caller saves the bundle. |
Fail-open health reports count, total and rate over the last hour and since worker start. Each pre-tool gate invocation counts once, including a pass-through allow from the gate that does not govern that tool. Post-tool observations are separate. A timeout and late worker response share one request ID. Either rate above five percent produces a one-line warning with a known cause.
Health counters are unsigned operational observations and may lag the signed chain. A partial or truncated denominator is labeled. Signed UTC-day failure counts remain separate from pending recovery rows, which can span dates and contain batch duplicates. Never add pending counts to the verified total.
For a custodian bundle, use agentguard-verify or this paid local export helper with an operator-approved destination:
node "${PLUGIN_ROOT}/runtime/verify.cjs" export RECEIPTS_FILE
Preserve the verification public key through a trusted channel separate from the bundle. A bundled key proves consistency with that key, not who controlled it. Export never includes the signing private key.
To disable only the optional MCP server for the public marketplace installation:
[plugins."agentguard@agentguard".mcp_servers.agentguard]
enabled = false
For a firm using Astra for Law in Codex or ChatGPT Work, policy can assign matter budgets, tool allowlists for a review session and ethical-wall denies. The firm retains the signed content-free record locally. These controls describe tool authorization and recorded activity, not legal analysis or model accuracy.
IT reviews one installation through /hooks, then uses scripts/print-trust-state.cjs to print exact hooks.state keys and trusted_hash values for its marketplace. Distribute the reviewed TOML through managed configuration.
Distribute the reviewed package, Node 22 and dependencies. Configure requirements.toml with allow_managed_hooks_only = true, hooks.managed_dir and all four hook commands. MCP and skills remain installed through the private marketplace.
A changed normalized hook definition changes its hash and prompts review. Referenced script bytes and imported modules are not part of that hash, so IT must protect the reviewed executable files separately. Managed commands need explicit PLUGIN_ROOT and per-user PLUGIN_DATA paths.
On macOS, Codex managed preferences use application identifier com.openai.codex and the keys config_toml_base64 or requirements_toml_base64. The enterprise guide includes complete TOML, packaging commands and source citations pinned to rust-v0.154.0. Its trust script matched the four keys and hashes from a real normal hook review; managed-device delivery and Windows execution have not been verified.
MDM delivery does not turn fail-open hooks into fail-closed authorization. Enforce a fail-closed requirement at the tool or service boundary.
The public repository contains the plugin, generated compatibility installation, tests and changelog. The portable manifest uses OpenAI extension settings, the MCP transport is local stdio, and the empty app mapping claims no registered external server. Distribution does not publish to npm or submit a directory entry.
The package uses the same license terms as Spend. Return to the plugin overview or the SDK documentation.