@ory/codex 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "ory-codex",
3
+ "version": "0.1.0",
4
+ "description": "Ory authentication and authorization for Codex CLI — session auth, tool permissions, and audit logging",
5
+ "author": {
6
+ "name": "Ory",
7
+ "url": "https://ory.com"
8
+ },
9
+ "homepage": "https://ory.com"
10
+ }
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # Ory Agent Plugin: Codex
2
+
3
+ [Ory](https://ory.com) bundled into [Codex](https://github.com/openai/codex): skills that scaffold Ory authentication into your codebase, a local Ory stack you can spin up in one command, and (when pointed at an Ory project) authentication, authorization, and audit for every tool Codex runs.
4
+
5
+ ## Install
6
+
7
+ Codex loads hooks from its config. Install and register in one step, with no prior `npm install` required:
8
+
9
+ ```bash
10
+ npx @ory/codex install # current project
11
+ npx @ory/codex install --global # all Codex projects
12
+ npx @ory/codex uninstall
13
+ ```
14
+
15
+ `install` wires the Ory hooks into your Codex config non-destructively (existing hooks are preserved), registers the Ory MCP server, and drops the Ory skill catalog into `.codex/skills/`. If the installer can't locate your Codex config, `npx ory-codex-setup` writes it directly.
16
+
17
+ ## Developer experience
18
+
19
+ This plugin is a productivity layer for Ory itself. You don't need a real Ory project, an account, or any prior Ory experience to start using it.
20
+
21
+ ### Skills for scaffolding Ory into your application
22
+
23
+ Codex surfaces the skill catalog in `/skills` and auto-invokes by description. Ask Codex to add Ory auth to your codebase, or invoke a skill directly:
24
+
25
+ - **`ory-auth-setup`**: full project setup. Install the Ory CLI, create an Ory Network project, add Ory Elements, configure the SDK, build the auth pages, wire session middleware.
26
+ - **`ory-login-flow`**: login, registration, recovery, verification, and settings pages with Ory Elements. Next.js App Router and React SPA variants.
27
+ - **`ory-social-login`**: Google, GitHub, Apple, Microsoft, Discord, and other OIDC providers with Jsonnet data mappers.
28
+ - **`ory-local-dev`**: drive the local Ory stack (below) from within Codex to prototype and test against without a remote project.
29
+
30
+ Skills are versioned with the plugin so guidance stays in sync as Ory APIs evolve.
31
+
32
+ ### Ory MCP server
33
+
34
+ Bundled and registered automatically. It exposes the Ory CLI and the Ory Network REST API as MCP tools so Codex can manage identities, OAuth2 clients, projects, permission tuples, and configuration without ever leaving the chat. Useful for seeding test data, verifying a scaffolded integration, or running one-off admin tasks.
35
+
36
+ ### Local Ory stack in one command
37
+
38
+ From Codex's `/skills` picker:
39
+
40
+ ```
41
+ ory-local-up # start a local Ory instance in Docker
42
+ ory-local-down # tear it all down
43
+ ```
44
+
45
+ Or via the CLI: `npx ory-codex local up | down`.
46
+
47
+ `local up` runs a local Ory instance in Docker, covering everything the plugin and your scaffolded application need. It also brings up a login UI on `:3000` and Jaeger on `:16686`, all reachable through `http://localhost:4000`. A test user identity is seeded and the credentials are printed for you. Use it to:
48
+
49
+ - **Learn Ory hands-on** without signing up for a hosted project.
50
+ - **Prototype** flows (login, social, MFA, recovery, permission tuples) against a real Ory backend in your local dev loop.
51
+ - **Test** an auth integration end-to-end before pushing anything to a real environment.
52
+ - **Develop** your application against the same identity, OAuth2, and permission surfaces you'll ship with.
53
+
54
+ Point `ORY_PROJECT_URL` at `http://localhost:4000` (or run `npx ory-codex configure`) and the security features below run against the local stack.
55
+
56
+ ## Configure
57
+
58
+ ```bash
59
+ npx ory-codex configure --project-url https://<id>.projects.oryapis.com --api-key ory_pat_...
60
+ ```
61
+
62
+ Config is saved to `~/.config/ory-agent-plugins/config.json` and shared across every Ory agent plugin on the machine. Without it the plugin still loads cleanly and runs in **pass-through mode**: skills work, but nothing is blocked.
63
+
64
+ ## Agent security (Argus)
65
+
66
+ Once the plugin is pointed at an Ory project (local or hosted), Codex's session and every tool call are governed by Ory.
67
+
68
+ - **Authentication.** Two identities. The human at the keyboard (the **user**) authenticates interactively via Ory Identities when `ORY_AUTH_GATE=1`. The Codex process (the **agent**) gets its own OAuth2 identity, self-registered via Dynamic Client Registration on first run.
69
+ - **Authorization.** Before any tool runs, the plugin checks Ory Permissions against the user's subject and blocks the call on `deny`. MCP tool calls additionally get a server-level check.
70
+ - **Audit.** Every decision (allow, deny, fallback) is recorded as a structured trace span: NDJSON file output and/or OTLP/HTTP export to Jaeger, Honeycomb, Grafana, and similar collectors. The user-to-agent delegation is written to Ory as a Zanzibar tuple so "agent X acting on behalf of user Y" stays queryable after tokens expire.
71
+
72
+ The plugin is **fail-open** on its own infrastructure failures (network errors, rate limits, missing config), so enforcement is only as strong as your tuples; grant explicit `invoke` relations for the tools each user should be able to run.
73
+
74
+ ## CLI
75
+
76
+ ```
77
+ npx ory-codex install | uninstall [--global]
78
+ npx ory-codex configure [--project-url <url>] [--api-key <key>] [--audit-only]
79
+ npx ory-codex agent <status|unregister> Manage the agent's OAuth2 identity
80
+ npx ory-codex local <up|down|status|seed|logs|env|configure|reset>
81
+ npx ory-codex status
82
+ ```
83
+
84
+ ## Links
85
+
86
+ - [ory.com](https://ory.com)
87
+
88
+ ## License
89
+
90
+ Apache-2.0
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Main CLI for @ory/codex.
4
+ *
5
+ * Usage:
6
+ * npx ory-codex install [--global] Install hooks into Codex config
7
+ * npx ory-codex uninstall Remove hooks from Codex config
8
+ * npx ory-codex configure Set or view Ory project URL and API key
9
+ * npx ory-codex setup [--global] Write hooks to config directly (fallback)
10
+ * npx ory-codex status Show plugin status
11
+ */
12
+ export {};
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Main CLI for @ory/codex.
5
+ *
6
+ * Usage:
7
+ * npx ory-codex install [--global] Install hooks into Codex config
8
+ * npx ory-codex uninstall Remove hooks from Codex config
9
+ * npx ory-codex configure Set or view Ory project URL and API key
10
+ * npx ory-codex setup [--global] Write hooks to config directly (fallback)
11
+ * npx ory-codex status Show plugin status
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ const path = __importStar(require("node:path"));
48
+ const fs = __importStar(require("node:fs"));
49
+ const argus_1 = require("@ory/argus");
50
+ const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
51
+ function main() {
52
+ const [command, ...args] = process.argv.slice(2);
53
+ switch (command) {
54
+ case "install":
55
+ install(args);
56
+ break;
57
+ case "uninstall":
58
+ uninstall(args);
59
+ break;
60
+ case "configure":
61
+ (0, argus_1.runConfigureCommand)("ory-codex", args);
62
+ break;
63
+ case "agent":
64
+ (0, argus_1.runAgentCommand)("ory-codex", args).then((code) => process.exit(code), (err) => {
65
+ console.error(err.message ?? err);
66
+ process.exit(1);
67
+ });
68
+ break;
69
+ case "setup":
70
+ require("./setup.js");
71
+ break;
72
+ case "status":
73
+ status();
74
+ break;
75
+ case "local":
76
+ (0, argus_1.runLocalCommand)("ory-codex", args).catch((err) => {
77
+ console.error(err.message ?? err);
78
+ process.exit(1);
79
+ });
80
+ break;
81
+ case "help":
82
+ case "--help":
83
+ case "-h":
84
+ case undefined:
85
+ help();
86
+ break;
87
+ default:
88
+ console.error(`Unknown command: ${command}`);
89
+ help();
90
+ process.exit(1);
91
+ }
92
+ }
93
+ function install(args) {
94
+ const isGlobal = args.includes("--global");
95
+ console.log(`Installing Ory hooks for Codex (scope: ${isGlobal ? "global" : "project"})...`);
96
+ manualSetup(isGlobal);
97
+ }
98
+ function uninstall(args) {
99
+ const setupArgs = ["--uninstall", ...args];
100
+ process.argv = ["node", "setup.js", ...setupArgs];
101
+ require("./setup.js");
102
+ }
103
+ function manualSetup(isGlobal) {
104
+ const setupArgs = isGlobal ? ["--global"] : [];
105
+ process.argv = ["node", "setup.js", ...setupArgs];
106
+ require("./setup.js");
107
+ }
108
+ function status() {
109
+ console.log("Ory Agent Plugin Status (Codex)");
110
+ console.log("================================");
111
+ console.log("");
112
+ (0, argus_1.printOryConfig)();
113
+ (0, argus_1.printEnvironment)();
114
+ // Plugin-specific status
115
+ console.log("");
116
+ console.log("Plugin:");
117
+ console.log(` Directory: ${PACKAGE_ROOT}`);
118
+ console.log(` Hook script: ${fs.existsSync(path.join(PACKAGE_ROOT, "dist", "hook.js")) ? "built" : "NOT BUILT (run pnpm build)"}`);
119
+ (0, argus_1.printLogTail)();
120
+ }
121
+ function help() {
122
+ console.log(`
123
+ ory-codex — Ory plugin for Codex
124
+
125
+ Usage:
126
+ npx ory-codex <command> [options]
127
+
128
+ Commands:
129
+ install [--global] Install the Ory hooks into Codex configuration
130
+ uninstall Remove the Ory hooks from Codex configuration
131
+ configure Set or view Ory project URL and API key
132
+ setup [--global] Write hooks directly to config (fallback)
133
+ status Show plugin status and configuration
134
+ local <cmd> Manage local Ory dev environment (up, down, status, seed, ...)
135
+
136
+ Examples:
137
+ npx ory-codex install # Install for current project
138
+ npx ory-codex install --global # Install globally
139
+ npx ory-codex configure --project-url https://your-project.projects.oryapis.com --api-key ory_pat_...
140
+ npx ory-codex status # Check configuration
141
+ npx ory-codex uninstall # Remove hooks
142
+ `);
143
+ }
144
+ main();
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Setup CLI for the Ory Codex plugin.
4
+ *
5
+ * Writes hooks to `.codex/hooks.json` and enables the codex_hooks feature
6
+ * flag in `.codex/config.toml`. Codex does not read `.codex/config.json`
7
+ * for hooks; that path is intentionally not used.
8
+ *
9
+ * Usage:
10
+ * npx ory-codex-setup # Auto-detect and configure
11
+ * npx ory-codex-setup --project-dir /path/to/repo
12
+ * npx ory-codex-setup --global # Install to ~/.codex/
13
+ * npx ory-codex-setup --print # Print config to stdout without writing
14
+ * npx ory-codex-setup --uninstall # Remove Ory hooks from config
15
+ */
16
+ export {};
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Setup CLI for the Ory Codex plugin.
5
+ *
6
+ * Writes hooks to `.codex/hooks.json` and enables the codex_hooks feature
7
+ * flag in `.codex/config.toml`. Codex does not read `.codex/config.json`
8
+ * for hooks; that path is intentionally not used.
9
+ *
10
+ * Usage:
11
+ * npx ory-codex-setup # Auto-detect and configure
12
+ * npx ory-codex-setup --project-dir /path/to/repo
13
+ * npx ory-codex-setup --global # Install to ~/.codex/
14
+ * npx ory-codex-setup --print # Print config to stdout without writing
15
+ * npx ory-codex-setup --uninstall # Remove Ory hooks from config
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ const fs = __importStar(require("node:fs"));
52
+ const path = __importStar(require("node:path"));
53
+ const argus_1 = require("@ory/argus");
54
+ const BIN_NAME = "ory-codex-hook";
55
+ const PACKAGE_NAME = "@ory/codex";
56
+ const RENDER_OPTS = {
57
+ binName: "ory-codex",
58
+ packageName: "@ory/codex",
59
+ };
60
+ function getCodexDir(args) {
61
+ if (args.global) {
62
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
63
+ return path.join(home, ".codex");
64
+ }
65
+ return path.join(args.projectDir, ".codex");
66
+ }
67
+ function generateHooksConfig() {
68
+ const cmd = (0, argus_1.resolveHookCommand)(PACKAGE_NAME, BIN_NAME);
69
+ return {
70
+ SessionStart: (0, argus_1.flatHookEntry)(cmd),
71
+ PreToolUse: (0, argus_1.flatHookEntry)(cmd),
72
+ PostToolUse: (0, argus_1.flatHookEntry)(cmd),
73
+ PermissionRequest: (0, argus_1.flatHookEntry)(cmd),
74
+ UserPromptSubmit: (0, argus_1.flatHookEntry)(cmd),
75
+ Stop: (0, argus_1.flatHookEntry)(cmd),
76
+ };
77
+ }
78
+ /**
79
+ * Ensure `[features] codex_hooks = true` is present in config.toml.
80
+ * Hand-rolled TOML editing — we only manage one line; full TOML parsing
81
+ * is not warranted. Idempotent.
82
+ */
83
+ function ensureCodexHooksFeature(configTomlPath) {
84
+ let contents = "";
85
+ if (fs.existsSync(configTomlPath)) {
86
+ contents = fs.readFileSync(configTomlPath, "utf-8");
87
+ }
88
+ if (/^codex_hooks\s*=\s*true\b/m.test(contents)) {
89
+ return;
90
+ }
91
+ if (/^\[features\]\s*$/m.test(contents)) {
92
+ contents = contents.replace(/^\[features\]\s*$/m, (m) => `${m}\ncodex_hooks = true`);
93
+ }
94
+ else {
95
+ const sep = contents.endsWith("\n") || contents.length === 0 ? "" : "\n";
96
+ contents += `${sep}\n[features]\ncodex_hooks = true\n`;
97
+ }
98
+ fs.mkdirSync(path.dirname(configTomlPath), { recursive: true });
99
+ fs.writeFileSync(configTomlPath, contents);
100
+ }
101
+ /**
102
+ * Materialize the Ory skill catalog (4 guide skills + 2 user-invocable
103
+ * command-skills for local-up/local-down) into Codex's skills tree. Codex
104
+ * surfaces them in the `/skills` picker and the model auto-invokes them
105
+ * based on the SKILL.md descriptions.
106
+ *
107
+ * Codex's documented skill location is `~/.codex/skills/`; the `--global`
108
+ * flag routes the install there. Project-scope installs land in
109
+ * `<projectDir>/.codex/skills/` for parity with the hooks layout.
110
+ */
111
+ function installOrySkills(codexDir) {
112
+ const skillsDir = path.join(codexDir, "skills");
113
+ const guideSkills = (0, argus_1.renderOrySkills)("codex", RENDER_OPTS);
114
+ const commandSkills = (0, argus_1.renderOryCommands)("codex", RENDER_OPTS).map(argus_1.commandToSkill);
115
+ (0, argus_1.writeSkillTree)(skillsDir, [...guideSkills, ...commandSkills]);
116
+ }
117
+ /** Remove every skill this plugin installed; tidy the dir if it ends up empty. */
118
+ function uninstallOrySkills(codexDir) {
119
+ const skillsDir = path.join(codexDir, "skills");
120
+ if (!fs.existsSync(skillsDir))
121
+ return;
122
+ (0, argus_1.removeSkillDirs)(skillsDir, [...argus_1.ORY_SKILL_NAMES, ...argus_1.ORY_COMMAND_SKILL_NAMES]);
123
+ try {
124
+ if (fs.readdirSync(skillsDir).length === 0) {
125
+ fs.rmdirSync(skillsDir);
126
+ }
127
+ }
128
+ catch {
129
+ /* ignore — directory still in use is fine. */
130
+ }
131
+ }
132
+ /** Remove `codex_hooks = true` from `[features]`. Leaves other entries alone. */
133
+ function removeCodexHooksFeature(configTomlPath) {
134
+ if (!fs.existsSync(configTomlPath))
135
+ return;
136
+ const original = fs.readFileSync(configTomlPath, "utf-8");
137
+ const updated = original.replace(/^codex_hooks\s*=\s*true\s*\n?/m, "");
138
+ if (updated !== original) {
139
+ fs.writeFileSync(configTomlPath, updated);
140
+ }
141
+ }
142
+ function main() {
143
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
144
+ (0, argus_1.printSetupHelp)("ory-codex-setup", "Codex", {
145
+ supportsGlobal: true,
146
+ globalPath: "~/.codex/hooks.json",
147
+ });
148
+ process.exit(0);
149
+ }
150
+ const args = (0, argus_1.parseSetupArgs)({ supportsGlobal: true });
151
+ const hooksConfig = generateHooksConfig();
152
+ if (args.print) {
153
+ console.log(JSON.stringify({ hooks: hooksConfig }, null, 2));
154
+ return;
155
+ }
156
+ const codexDir = getCodexDir(args);
157
+ const hooksPath = path.join(codexDir, "hooks.json");
158
+ const configTomlPath = path.join(codexDir, "config.toml");
159
+ const existing = (0, argus_1.readJsonFile)(hooksPath);
160
+ if (args.uninstall) {
161
+ if (!fs.existsSync(codexDir)) {
162
+ console.log("No Codex config directory found. Nothing to uninstall.");
163
+ return;
164
+ }
165
+ let updated = (0, argus_1.removeFlatHooks)(existing, BIN_NAME);
166
+ updated = (0, argus_1.removeMcpServer)(updated);
167
+ (0, argus_1.writeJsonFile)(hooksPath, updated);
168
+ removeCodexHooksFeature(configTomlPath);
169
+ uninstallOrySkills(codexDir);
170
+ console.log(`Removed Ory hooks and MCP server from ${hooksPath}`);
171
+ console.log(`Removed codex_hooks feature flag from ${configTomlPath}`);
172
+ console.log(`Removed Ory skills from ${path.join(codexDir, "skills")}`);
173
+ return;
174
+ }
175
+ let merged = (0, argus_1.mergeFlatHooks)(existing, hooksConfig, BIN_NAME);
176
+ merged = (0, argus_1.mergeMcpServer)(merged);
177
+ (0, argus_1.writeJsonFile)(hooksPath, merged);
178
+ ensureCodexHooksFeature(configTomlPath);
179
+ installOrySkills(codexDir);
180
+ console.log(`Ory hooks and MCP server installed to ${hooksPath}`);
181
+ console.log(`Enabled [features] codex_hooks = true in ${configTomlPath}`);
182
+ console.log(`Ory skills installed to ${path.join(codexDir, "skills")}`);
183
+ if (!args.global) {
184
+ console.log(" Tip: re-run with --global if Codex only discovers skills from ~/.codex/skills.");
185
+ }
186
+ (0, argus_1.printNextSteps)("Codex", "npx ory-codex-setup --uninstall");
187
+ }
188
+ main();
@@ -0,0 +1,16 @@
1
+ import { OryAgentClient, ensureUserAuthenticated, ensureAgentIdentity } from "@ory/argus";
2
+ import type { CodexHookInput, CodexHookOutput } from "./types.js";
3
+ export interface HandleHookEventDeps {
4
+ /** Test injection point for the user auth gate. */
5
+ authGate?: typeof ensureUserAuthenticated;
6
+ /** Test injection point for the agent identity gate. */
7
+ agentGate?: typeof ensureAgentIdentity;
8
+ }
9
+ /**
10
+ * Route a Codex hook event to the appropriate Ory integration.
11
+ *
12
+ * Codex events: SessionStart, PreToolUse, PostToolUse, PermissionRequest,
13
+ * UserPromptSubmit, Stop. Hooks must be enabled via
14
+ * `[features] codex_hooks = true` in `~/.codex/config.toml`.
15
+ */
16
+ export declare function handleHookEvent(input: CodexHookInput, client: OryAgentClient, deps?: HandleHookEventDeps): Promise<CodexHookOutput>;
@@ -0,0 +1,370 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleHookEvent = handleHookEvent;
4
+ const argus_1 = require("@ory/argus");
5
+ /**
6
+ * Route a Codex hook event to the appropriate Ory integration.
7
+ *
8
+ * Codex events: SessionStart, PreToolUse, PostToolUse, PermissionRequest,
9
+ * UserPromptSubmit, Stop. Hooks must be enabled via
10
+ * `[features] codex_hooks = true` in `~/.codex/config.toml`.
11
+ */
12
+ async function handleHookEvent(input, client, deps = {}) {
13
+ const event = input.hook_event_name;
14
+ client.logger.debug("hook.received", {
15
+ event,
16
+ sessionId: input.session_id,
17
+ toolName: input.tool_name,
18
+ turnId: input.turn_id,
19
+ });
20
+ // Set trace context so all spans within this hook invocation correlate
21
+ client.tracer.setContext({
22
+ traceId: (0, argus_1.deriveTraceId)(input.session_id),
23
+ sessionId: input.session_id,
24
+ });
25
+ try {
26
+ switch (event) {
27
+ case "SessionStart":
28
+ return await handleSessionStart(input, client, deps);
29
+ case "PreToolUse":
30
+ return await handlePreToolUse(input, client);
31
+ case "PostToolUse":
32
+ return await handlePostToolUse(input, client);
33
+ case "PermissionRequest":
34
+ return await handlePermissionRequest(input, client);
35
+ case "UserPromptSubmit":
36
+ return await handleUserPromptSubmit(input, client);
37
+ case "Stop":
38
+ return await handleStop(input, client);
39
+ default:
40
+ client.logger.debug("hook.passthrough", { event });
41
+ client.tracer.record("hook.passthrough", "skipped", {
42
+ attributes: { event },
43
+ });
44
+ return {};
45
+ }
46
+ }
47
+ finally {
48
+ client.tracer.clearContext();
49
+ }
50
+ }
51
+ // ─── SessionStart ───────────────────────────────────────────────────
52
+ async function handleSessionStart(input, client, deps) {
53
+ client.logger.info("lifecycle.session_start", {
54
+ sessionId: input.session_id,
55
+ model: input.model,
56
+ cwd: input.cwd,
57
+ });
58
+ client.tracer.record("session.start", "ok", {
59
+ attributes: { model: input.model },
60
+ });
61
+ const userGate = deps.authGate ?? argus_1.ensureUserAuthenticated;
62
+ const decision = await userGate(client, {
63
+ binName: "ory-codex",
64
+ harness: "codex",
65
+ allowBlock: true,
66
+ });
67
+ // Resolve the agent identity (machine credentials). Never blocks;
68
+ // attaches the agent's bearer token to outgoing Ory API calls.
69
+ const agentGate = deps.agentGate ?? argus_1.ensureAgentIdentity;
70
+ await agentGate(client, { projectUrl: (0, argus_1.resolveConfig)().projectUrl, harness: "codex" });
71
+ if (!decision.proceed) {
72
+ return { decision: "block", reason: decision.reason };
73
+ }
74
+ if (decision.mode !== "disabled") {
75
+ return {};
76
+ }
77
+ const resolved = (0, argus_1.resolveConfig)();
78
+ if (resolved.auditOnly) {
79
+ client.logger.info("config.audit_only", {
80
+ message: "Audit-only mode enabled. Auth and permission checks are disabled.",
81
+ });
82
+ return {};
83
+ }
84
+ if (!resolved.projectUrl) {
85
+ client.logger.warn("config.not_configured", {
86
+ message: "Ory plugin is not configured. Auth and permission checks are disabled. " +
87
+ "Run 'npx ory-codex configure' to connect to an Ory project.",
88
+ });
89
+ return {};
90
+ }
91
+ // Try session token first, then OAuth2 token
92
+ const sessionToken = process.env.ORY_SESSION_TOKEN;
93
+ const oauth2Token = process.env.ORY_OAUTH2_TOKEN;
94
+ if (sessionToken) {
95
+ await verifySessionToken(sessionToken, client);
96
+ return {};
97
+ }
98
+ if (oauth2Token) {
99
+ await verifyOAuth2Token(oauth2Token, client);
100
+ return {};
101
+ }
102
+ client.logger.warn("session.no_credentials", {
103
+ message: "Neither ORY_SESSION_TOKEN nor ORY_OAUTH2_TOKEN is set. " +
104
+ "Skipping authentication.",
105
+ });
106
+ return {};
107
+ }
108
+ async function verifySessionToken(token, client) {
109
+ try {
110
+ const session = await client.verifySession(token);
111
+ if (!session.active) {
112
+ client.logger.warn("session.inactive", {
113
+ message: "Ory session is not active. Re-authenticate to enable auth checks.",
114
+ });
115
+ }
116
+ }
117
+ catch (err) {
118
+ const oryErr = err;
119
+ client.logger.warn("session.verify_failed", {
120
+ code: oryErr.code,
121
+ message: oryErr.message,
122
+ });
123
+ }
124
+ }
125
+ async function verifyOAuth2Token(token, client) {
126
+ try {
127
+ const tokenInfo = await client.introspectToken(token);
128
+ if (!tokenInfo.active) {
129
+ client.logger.warn("oauth2.token_inactive", {
130
+ message: "Ory OAuth2 token is not active. Obtain a new token to enable auth checks.",
131
+ });
132
+ return;
133
+ }
134
+ client.logger.info("oauth2.session_authenticated", {
135
+ clientId: tokenInfo.clientId,
136
+ subject: tokenInfo.subject,
137
+ scope: tokenInfo.scope,
138
+ });
139
+ }
140
+ catch (err) {
141
+ const oryErr = err;
142
+ client.logger.warn("oauth2.introspect_failed", {
143
+ code: oryErr.code,
144
+ message: oryErr.message,
145
+ });
146
+ }
147
+ }
148
+ // ─── PreToolUse ─────────────────────────────────────────────────────
149
+ async function handlePreToolUse(input, client) {
150
+ // No default. Codex always sets `tool_name` to the canonical value
151
+ // (`Bash`, `apply_patch`, or `mcp__<server>__<tool>`). Defaulting to
152
+ // `"Bash"` here would silently mislabel apply_patch and MCP calls.
153
+ const toolName = input.tool_name;
154
+ if (!toolName) {
155
+ client.logger.warn("pre_tool_use.missing_tool_name", {
156
+ sessionId: input.session_id,
157
+ message: "PreToolUse event missing tool_name; allowing through.",
158
+ });
159
+ return {};
160
+ }
161
+ client.logger.info("lifecycle.pre_tool_use", {
162
+ sessionId: input.session_id,
163
+ toolName,
164
+ toolInput: input.tool_input,
165
+ });
166
+ const inputSummary = (0, argus_1.summarizeToolInput)(toolName, input.tool_input);
167
+ // In audit-only mode, log the invocation but skip permission checks
168
+ if ((0, argus_1.resolveConfig)().auditOnly) {
169
+ client.tracer.record("tool.invoke", "ok", {
170
+ attributes: { toolName, ...inputSummary },
171
+ });
172
+ return {};
173
+ }
174
+ const subject = (0, argus_1.resolveUserSubject)(client, `session:${input.session_id}`);
175
+ const subjectId = (0, argus_1.subjectLabel)(subject);
176
+ const mcpTool = (0, argus_1.parseMcpToolGeneric)(toolName);
177
+ try {
178
+ if (mcpTool) {
179
+ const mcpResult = await (0, argus_1.checkMcpPermission)(client, mcpTool, {
180
+ subject,
181
+ spanAttributes: { toolName },
182
+ });
183
+ if (!mcpResult.allowed) {
184
+ client.tracer.record("tool.block", "denied", {
185
+ attributes: { toolName, mcpServer: mcpTool.serverName, mcpTool: mcpTool.toolName, ...inputSummary, ...(0, argus_1.alertAttributes)(true) },
186
+ });
187
+ return {
188
+ decision: "block",
189
+ reason: (0, argus_1.formatDenialMessage)({ tool: toolName, subjectId, mcp: mcpTool }),
190
+ };
191
+ }
192
+ client.tracer.record("tool.invoke", "ok", {
193
+ attributes: { toolName, mcpServer: mcpTool.serverName, mcpTool: mcpTool.toolName, ...inputSummary },
194
+ });
195
+ return {};
196
+ }
197
+ const namespace = resolveNamespace();
198
+ const result = await client.checkPermission({
199
+ namespace,
200
+ object: toolName,
201
+ relation: "use",
202
+ ...subject,
203
+ }, { spanAttributes: { toolName } });
204
+ if (!result.allowed) {
205
+ client.tracer.record("tool.block", "denied", {
206
+ attributes: { toolName, ...inputSummary, allowed: result.allowed, ...(0, argus_1.alertAttributes)(true) },
207
+ });
208
+ return {
209
+ decision: "block",
210
+ reason: (0, argus_1.formatDenialMessage)({ tool: toolName, subjectId, namespace }),
211
+ };
212
+ }
213
+ client.tracer.record("tool.invoke", "ok", {
214
+ attributes: { toolName, ...inputSummary, allowed: result.allowed },
215
+ });
216
+ return {};
217
+ }
218
+ catch (err) {
219
+ return handlePermissionError(err, toolName, client);
220
+ }
221
+ }
222
+ // ─── PostToolUse ────────────────────────────────────────────────────
223
+ async function handlePostToolUse(input, client) {
224
+ const toolName = input.tool_name;
225
+ if (!toolName) {
226
+ client.logger.warn("post_tool_use.missing_tool_name", {
227
+ sessionId: input.session_id,
228
+ });
229
+ return {};
230
+ }
231
+ client.logger.info("lifecycle.post_tool_use", {
232
+ sessionId: input.session_id,
233
+ toolName,
234
+ turnId: input.turn_id,
235
+ toolUseId: input.tool_use_id,
236
+ });
237
+ client.tracer.record("tool.complete", "ok", {
238
+ attributes: {
239
+ toolName,
240
+ turnId: input.turn_id,
241
+ toolUseId: input.tool_use_id,
242
+ ...(0, argus_1.summarizeToolInput)(toolName, input.tool_input),
243
+ ...(0, argus_1.summarizeToolOutput)(toolName, input.tool_response),
244
+ },
245
+ });
246
+ return {};
247
+ }
248
+ // ─── PermissionRequest ──────────────────────────────────────────────
249
+ async function handlePermissionRequest(input, client) {
250
+ const toolName = input.tool_name;
251
+ if (!toolName) {
252
+ client.logger.warn("permission_request.missing_tool_name", {
253
+ sessionId: input.session_id,
254
+ });
255
+ return {};
256
+ }
257
+ client.logger.info("lifecycle.permission_request", {
258
+ sessionId: input.session_id,
259
+ toolName,
260
+ turnId: input.turn_id,
261
+ });
262
+ if ((0, argus_1.resolveConfig)().auditOnly) {
263
+ return permissionRequestFallback("Audit-only mode — deferring to user");
264
+ }
265
+ const subject = (0, argus_1.resolveUserSubject)(client, `session:${input.session_id}`);
266
+ const subjectId = (0, argus_1.subjectLabel)(subject);
267
+ const mcpTool = (0, argus_1.parseMcpToolGeneric)(toolName);
268
+ try {
269
+ if (mcpTool) {
270
+ const mcpResult = await (0, argus_1.checkMcpPermission)(client, mcpTool, {
271
+ subject,
272
+ spanAttributes: { toolName },
273
+ });
274
+ return permissionRequestDecision(mcpResult.allowed ? "allow" : "deny", mcpResult.allowed
275
+ ? "Ory MCP server permission granted"
276
+ : (0, argus_1.formatDenialMessage)({ tool: toolName, subjectId, mcp: mcpTool }));
277
+ }
278
+ const namespace = resolveNamespace();
279
+ const result = await client.checkPermission({
280
+ namespace,
281
+ object: toolName,
282
+ relation: "use",
283
+ ...subject,
284
+ }, { spanAttributes: { toolName } });
285
+ return permissionRequestDecision(result.allowed ? "allow" : "deny", result.allowed
286
+ ? "Ory permission granted"
287
+ : (0, argus_1.formatDenialMessage)({ tool: toolName, subjectId, namespace }));
288
+ }
289
+ catch (err) {
290
+ const oryErr = err;
291
+ const reason = oryErr.code === "network_error" || oryErr.code === "rate_limited"
292
+ ? `Ory unavailable (${oryErr.code}), falling back to user prompt`
293
+ : `Ory permission check failed: ${oryErr.message}`;
294
+ return permissionRequestFallback(reason);
295
+ }
296
+ }
297
+ function permissionRequestDecision(behavior, message) {
298
+ return {
299
+ hookSpecificOutput: {
300
+ hookEventName: "PermissionRequest",
301
+ decision: { behavior, message },
302
+ },
303
+ };
304
+ }
305
+ function permissionRequestFallback(message) {
306
+ return {
307
+ hookSpecificOutput: {
308
+ hookEventName: "PermissionRequest",
309
+ message,
310
+ },
311
+ };
312
+ }
313
+ // ─── UserPromptSubmit ───────────────────────────────────────────────
314
+ async function handleUserPromptSubmit(input, client) {
315
+ client.logger.info("lifecycle.user_prompt_submit", {
316
+ sessionId: input.session_id,
317
+ turnId: input.turn_id,
318
+ promptLen: input.prompt?.length,
319
+ });
320
+ client.tracer.record("user.prompt", "ok", {
321
+ attributes: {
322
+ turnId: input.turn_id,
323
+ promptLen: input.prompt?.length,
324
+ },
325
+ });
326
+ return {};
327
+ }
328
+ // ─── Stop ───────────────────────────────────────────────────────────
329
+ async function handleStop(input, client) {
330
+ client.logger.info("lifecycle.stop", {
331
+ sessionId: input.session_id,
332
+ turnId: input.turn_id,
333
+ stopHookActive: input.stop_hook_active,
334
+ });
335
+ client.tracer.record("turn.stop", "ok", {
336
+ attributes: {
337
+ turnId: input.turn_id,
338
+ stopHookActive: input.stop_hook_active,
339
+ messageLen: input.last_assistant_message?.length,
340
+ },
341
+ });
342
+ return {};
343
+ }
344
+ // ─── Helpers ────────────────────────────────────────────────────────
345
+ function resolveNamespace() {
346
+ return process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools";
347
+ }
348
+ function handlePermissionError(oryErr, toolName, client) {
349
+ if (oryErr.code === "network_error") {
350
+ client.logger.warn("permission.network_error", {
351
+ toolName,
352
+ message: "Ory unreachable, failing open",
353
+ });
354
+ return {};
355
+ }
356
+ if (oryErr.code === "rate_limited") {
357
+ client.logger.warn("permission.rate_limited", {
358
+ toolName,
359
+ message: "Ory rate limited, failing open",
360
+ });
361
+ return {};
362
+ }
363
+ // For other errors, also fail open but log prominently
364
+ client.logger.error("permission.check.error", {
365
+ toolName,
366
+ code: oryErr.code,
367
+ message: oryErr.message,
368
+ });
369
+ return {};
370
+ }
package/dist/hook.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Codex hook entry point.
4
+ * This script is invoked by Codex for each hook event.
5
+ * Input: JSON on stdin
6
+ * Output: JSON on stdout
7
+ * Exit code 2 = block the action (reason written to stderr)
8
+ */
9
+ export {};
package/dist/hook.js ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Codex hook entry point.
5
+ * This script is invoked by Codex for each hook event.
6
+ * Input: JSON on stdin
7
+ * Output: JSON on stdout
8
+ * Exit code 2 = block the action (reason written to stderr)
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ const argus_1 = require("@ory/argus");
12
+ const handlers_js_1 = require("./handlers.js");
13
+ /**
14
+ * Read all of stdin as a string.
15
+ *
16
+ * Uses event listeners instead of `for await` so that we don't depend on the
17
+ * parent process closing stdin (sending EOF). If no EOF arrives, we resolve
18
+ * after a short idle gap once data has been received.
19
+ */
20
+ function readStdin() {
21
+ return new Promise((resolve, reject) => {
22
+ const chunks = [];
23
+ let resolved = false;
24
+ function done() {
25
+ if (!resolved) {
26
+ resolved = true;
27
+ resolve(Buffer.concat(chunks).toString("utf-8"));
28
+ }
29
+ }
30
+ process.stdin.on("data", (chunk) => {
31
+ chunks.push(chunk);
32
+ clearTimeout(idleTimer);
33
+ idleTimer = setTimeout(done, 100);
34
+ });
35
+ process.stdin.on("end", done);
36
+ process.stdin.on("error", (err) => {
37
+ if (!resolved) {
38
+ resolved = true;
39
+ reject(err);
40
+ }
41
+ });
42
+ let idleTimer;
43
+ });
44
+ }
45
+ async function main() {
46
+ const client = argus_1.OryAgentClient.fromEnv("codex");
47
+ const raw = await readStdin();
48
+ let input;
49
+ try {
50
+ input = JSON.parse(raw);
51
+ }
52
+ catch {
53
+ client.logger.error("hook.stdin.parse_failed", { raw: raw.slice(0, 200) });
54
+ await client.tracer.shutdown();
55
+ process.exit(0); // Don't block on parse errors
56
+ }
57
+ const output = await (0, handlers_js_1.handleHookEvent)(input, client);
58
+ if (output.decision === "block") {
59
+ // Codex reads the block reason from stderr
60
+ process.stderr.write(output.reason ?? "Blocked by Ory agent plugin");
61
+ process.stdout.write(JSON.stringify(output));
62
+ await client.tracer.shutdown();
63
+ process.exit(2);
64
+ }
65
+ if (output.oryConfigRequired || output.message) {
66
+ process.stdout.write(JSON.stringify(output));
67
+ }
68
+ await client.tracer.shutdown();
69
+ process.exit(0);
70
+ }
71
+ main().catch((err) => {
72
+ process.stderr.write(`[ory-agent] fatal: ${err}\n`);
73
+ process.exit(0); // Fail open
74
+ });
@@ -0,0 +1,2 @@
1
+ export { handleHookEvent } from "./handlers.js";
2
+ export { generateSettings } from "./settings.js";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateSettings = exports.handleHookEvent = void 0;
4
+ var handlers_js_1 = require("./handlers.js");
5
+ Object.defineProperty(exports, "handleHookEvent", { enumerable: true, get: function () { return handlers_js_1.handleHookEvent; } });
6
+ var settings_js_1 = require("./settings.js");
7
+ Object.defineProperty(exports, "generateSettings", { enumerable: true, get: function () { return settings_js_1.generateSettings; } });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generate the hooks config that configures Ory hooks for Codex.
3
+ *
4
+ * Codex supports two hook events:
5
+ * - SessionStart: fired when the agent session begins
6
+ * - PreToolUse: fired before each tool call (Bash only)
7
+ */
8
+ export declare function generateSettings(hookScriptPath: string): object;
9
+ /**
10
+ * Generate settings assuming the plugin is installed via npm/pnpm.
11
+ */
12
+ export declare function generateInstalledSettings(): object;
13
+ /**
14
+ * Generate settings pointing to a local dev build.
15
+ */
16
+ export declare function generateDevSettings(packageDir: string): object;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateSettings = generateSettings;
37
+ exports.generateInstalledSettings = generateInstalledSettings;
38
+ exports.generateDevSettings = generateDevSettings;
39
+ const path = __importStar(require("node:path"));
40
+ const argus_1 = require("@ory/argus");
41
+ /**
42
+ * Generate the hooks config that configures Ory hooks for Codex.
43
+ *
44
+ * Codex supports two hook events:
45
+ * - SessionStart: fired when the agent session begins
46
+ * - PreToolUse: fired before each tool call (Bash only)
47
+ */
48
+ function generateSettings(hookScriptPath) {
49
+ const cmd = `node ${hookScriptPath}`;
50
+ return {
51
+ hooks: {
52
+ SessionStart: (0, argus_1.flatHookEntry)(cmd),
53
+ PreToolUse: (0, argus_1.flatHookEntry)(cmd),
54
+ },
55
+ };
56
+ }
57
+ /**
58
+ * Generate settings assuming the plugin is installed via npm/pnpm.
59
+ */
60
+ function generateInstalledSettings() {
61
+ return generateSettings("ory-codex-hook");
62
+ }
63
+ /**
64
+ * Generate settings pointing to a local dev build.
65
+ */
66
+ function generateDevSettings(packageDir) {
67
+ const hookPath = path.resolve(packageDir, "dist", "hook.js");
68
+ return generateSettings(hookPath);
69
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Codex hook event payload delivered on stdin.
3
+ *
4
+ * Codex uses a subprocess hook model (JSON stdin/stdout). Hooks are
5
+ * feature-gated behind `[features] codex_hooks = true` in config.toml.
6
+ *
7
+ * Canonical `tool_name` values:
8
+ * - `"Bash"`
9
+ * - `"apply_patch"` — canonical name for file edits. `Write`/`Edit` are
10
+ * matcher aliases only; the serialized name is always `apply_patch`.
11
+ * - `"mcp__<server>__<tool>"` for MCP tools.
12
+ *
13
+ * Supported events: SessionStart, PreToolUse, PostToolUse, PermissionRequest,
14
+ * UserPromptSubmit, Stop.
15
+ */
16
+ export interface CodexHookInput {
17
+ hook_event_name: string;
18
+ session_id: string;
19
+ cwd: string;
20
+ transcript_path?: string;
21
+ turn_id?: string;
22
+ tool_name?: string;
23
+ tool_input?: Record<string, unknown>;
24
+ tool_use_id?: string;
25
+ tool_response?: Record<string, unknown>;
26
+ source?: "startup" | "resume" | "clear";
27
+ model?: string;
28
+ permission_mode?: "default" | "acceptEdits" | "plan" | "dontAsk" | "bypassPermissions";
29
+ prompt?: string;
30
+ last_assistant_message?: string;
31
+ stop_hook_active?: boolean;
32
+ }
33
+ /**
34
+ * Codex hook output written to stdout.
35
+ *
36
+ * Allow is implicit (omit `decision`); only `"block"` is valid at the top
37
+ * level. PermissionRequest uses the structured `hookSpecificOutput.decision`
38
+ * shape — its top-level `decision` field is ignored.
39
+ *
40
+ * `additionalContext` is supported on SessionStart and UserPromptSubmit.
41
+ */
42
+ export interface CodexHookOutput {
43
+ continue?: boolean;
44
+ decision?: "block";
45
+ reason?: string;
46
+ systemMessage?: string;
47
+ suppressOutput?: boolean;
48
+ stopReason?: string;
49
+ hookSpecificOutput?: CodexHookSpecificOutput;
50
+ /** Set when the plugin needs the agent to prompt the user for config. */
51
+ oryConfigRequired?: boolean;
52
+ message?: string;
53
+ }
54
+ export interface CodexHookSpecificOutput {
55
+ hookEventName?: string;
56
+ permissionDecision?: "allow" | "deny" | "ask";
57
+ permissionDecisionReason?: string;
58
+ decision?: {
59
+ behavior: "allow" | "deny";
60
+ message?: string;
61
+ };
62
+ additionalContext?: string;
63
+ [key: string]: unknown;
64
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@ory/codex",
3
+ "version": "0.1.0",
4
+ "description": "Ory plugin for Codex: scaffolding skills, a local Ory instance, and authentication, authorization, and audit for every tool call",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://ory.com",
7
+ "keywords": [
8
+ "ory",
9
+ "codex",
10
+ "openai",
11
+ "hooks",
12
+ "plugin",
13
+ "identity",
14
+ "identity-management",
15
+ "iam",
16
+ "authentication",
17
+ "authorization",
18
+ "access-control",
19
+ "permissions",
20
+ "rbac",
21
+ "zanzibar",
22
+ "oauth",
23
+ "oauth2",
24
+ "openid-connect",
25
+ "oidc",
26
+ "session",
27
+ "mfa",
28
+ "sso",
29
+ "audit",
30
+ "audit-log",
31
+ "compliance",
32
+ "agent",
33
+ "ai-agent",
34
+ "agent-security",
35
+ "guardrails",
36
+ "llm",
37
+ "tracing",
38
+ "distributed-tracing",
39
+ "observability",
40
+ "kratos",
41
+ "keto",
42
+ "hydra"
43
+ ],
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "main": "dist/index.js",
48
+ "types": "dist/index.d.ts",
49
+ "exports": {
50
+ ".": {
51
+ "types": "./dist/index.d.ts",
52
+ "default": "./dist/index.js"
53
+ }
54
+ },
55
+ "bin": {
56
+ "codex": "dist/cli/main.js",
57
+ "ory-codex": "dist/cli/main.js",
58
+ "ory-codex-hook": "dist/hook.js",
59
+ "ory-codex-setup": "dist/cli/setup.js"
60
+ },
61
+ "files": [
62
+ "dist",
63
+ "!dist/dev",
64
+ "!dist/**/*.tsbuildinfo",
65
+ ".codex-plugin"
66
+ ],
67
+ "dependencies": {
68
+ "@ory/argus": "0.1.0"
69
+ },
70
+ "engines": {
71
+ "node": ">=24"
72
+ },
73
+ "scripts": {
74
+ "build": "tsc",
75
+ "clean": "rm -rf dist *.tsbuildinfo",
76
+ "test": "vitest run",
77
+ "test:watch": "vitest",
78
+ "typecheck": "tsc --noEmit",
79
+ "dev": "node dist/dev/launcher.js"
80
+ }
81
+ }