@samirosamsam/aim 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,20 @@
1
+ {
2
+ "name": "aim",
3
+ "interface": {
4
+ "displayName": "AIM"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "aim",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Productivity"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "aim",
3
+ "version": "0.1.0",
4
+ "description": "Install deterministic Codex guardrails from natural-language block rules.",
5
+ "author": {
6
+ "name": "AIM"
7
+ },
8
+ "repository": "https://github.com/tototozip/AIM",
9
+ "license": "MIT",
10
+ "keywords": ["agents", "codex", "iam", "mcp", "permissions"],
11
+ "skills": "./skills/",
12
+ "interface": {
13
+ "displayName": "AIM",
14
+ "shortDescription": "Block matching Codex tool calls with local guardrails.",
15
+ "longDescription": "AIM helps Codex turn natural-language block requests into local PreToolUse guardrails for Bash, file edits, and MCP tool calls.",
16
+ "developerName": "AIM",
17
+ "category": "Productivity",
18
+ "capabilities": ["Write"],
19
+ "defaultPrompt": [
20
+ "Block this Codex action.",
21
+ "Install deterministic guardrails for this repo."
22
+ ]
23
+ }
24
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AIM contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # AIM
2
+
3
+ Minimal command-first prototype for **Agent Identity & Access Management**.
4
+
5
+ AIM keeps the first surface small: Codex uses a plugin skill to install a local `PreToolUse` hook, turn natural-language "block this" requirements into policy rows, and deny matching Codex tool calls before they execute. There is no local server and no UI.
6
+
7
+ ## Install
8
+
9
+ Run the public CLI without installing:
10
+
11
+ ```bash
12
+ npx -y @samirosamsam/aim@latest demo
13
+ ```
14
+
15
+ Install the CLI globally:
16
+
17
+ ```bash
18
+ npm install -g @samirosamsam/aim
19
+ aim demo
20
+ ```
21
+
22
+ Install the Codex plugin from this repo:
23
+
24
+ ```bash
25
+ codex plugin marketplace add tototozip/AIM --ref main
26
+ codex plugin add aim@aim
27
+ ```
28
+
29
+ Then start a new Codex thread and invoke `@aim`.
30
+
31
+ ## Codex Guardrail
32
+
33
+ Install or refresh the local Codex hook:
34
+
35
+ ```bash
36
+ npx -y @samirosamsam/aim@latest setup
37
+ ```
38
+
39
+ If Codex says hooks need review, run `/hooks`, inspect the AIM hook, and trust it.
40
+
41
+ Add a deterministic guardrail from natural language:
42
+
43
+ ```bash
44
+ npx -y @samirosamsam/aim@latest rule add 'empêche git push'
45
+ npx -y @samirosamsam/aim@latest rule add 'empêche de modifier package.json'
46
+ npx -y @samirosamsam/aim@latest rule add 'empêche les calls GitHub qui ajoutent des collaborators'
47
+ ```
48
+
49
+ Codex then calls the AIM hook before supported tool calls. A blocked Bash call returns the Codex `PreToolUse` deny shape:
50
+
51
+ ```json
52
+ {
53
+ "hookSpecificOutput": {
54
+ "hookEventName": "PreToolUse",
55
+ "permissionDecision": "deny",
56
+ "permissionDecisionReason": "AIM blocked Bash: Block write on bash/git push*."
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Run
62
+
63
+ ```bash
64
+ npm test
65
+ node ./bin/aim.js demo
66
+ ```
67
+
68
+ ## CLI
69
+
70
+ Draft grants without writing policy:
71
+
72
+ ```bash
73
+ npx -y @samirosamsam/aim@latest compile 'Block Notion read access to "workspace/shared/legal/*"' --json
74
+ ```
75
+
76
+ Capture a concrete MCP call as a resource/action rule:
77
+
78
+ ```bash
79
+ npx -y @samirosamsam/aim@latest capture \
80
+ --provider github \
81
+ --tool list_repository_collaborators \
82
+ --args '{"owner":"tototozip","repo":"AIM"}' \
83
+ --effect deny \
84
+ --agent 'spiffe://local/agent/demo/codex' \
85
+ --connection 'github:prod' \
86
+ --json
87
+ ```
88
+
89
+ Append grants to a policy file:
90
+
91
+ ```bash
92
+ npx -y @samirosamsam/aim@latest add 'Allow Notion read access to "workspace/shared/*"' \
93
+ --policy aim.policy.json \
94
+ --agent 'spiffe://local/agent/demo/codex' \
95
+ --json
96
+ ```
97
+
98
+ Append a captured MCP rule to a policy file:
99
+
100
+ ```bash
101
+ npx -y @samirosamsam/aim@latest capture \
102
+ --provider github \
103
+ --tool list_branches \
104
+ --args '{"owner":"tototozip","repo":"AIM"}' \
105
+ --effect allow \
106
+ --policy aim.policy.json \
107
+ --agent 'spiffe://local/agent/demo/codex' \
108
+ --connection 'github:prod' \
109
+ --json
110
+ ```
111
+
112
+ Check a representative MCP call:
113
+
114
+ ```bash
115
+ npx -y @samirosamsam/aim@latest check \
116
+ --policy aim.policy.json \
117
+ --agent 'spiffe://local/agent/demo/codex' \
118
+ --connection 'notion:prod' \
119
+ --tool 'pages.read' \
120
+ --resource 'workspace/shared/legal/term-sheet' \
121
+ --access read \
122
+ --json
123
+ ```
124
+
125
+ Authorize using raw MCP call args:
126
+
127
+ ```bash
128
+ npx -y @samirosamsam/aim@latest authorize \
129
+ --policy aim.policy.json \
130
+ --agent 'spiffe://local/agent/demo/codex' \
131
+ --connection 'github:prod' \
132
+ --provider github \
133
+ --tool list_branches \
134
+ --args '{"owner":"tototozip","repo":"AIM"}' \
135
+ --json
136
+ ```
137
+
138
+ ## Codex Plugin
139
+
140
+ This repo is shaped as a Codex plugin:
141
+
142
+ - `.codex-plugin/plugin.json` declares the plugin package.
143
+ - `skills/aim/SKILL.md` teaches Codex to install the hook and add rules with the local `aim` command instead of inventing grant JSON manually.
144
+ - `hooks/hooks.json` bundles the `PreToolUse` hook for plugin installs.
145
+ - `bin/aim.js` is the command surface.
146
+
147
+ The current prototype implements prompt-to-guardrail compilation, Codex `PreToolUse` blocking for Bash, `apply_patch`, and MCP tool calls, MCP-call capture, JSON policy writes, deny-overrides precedence, and decision audit rows. It intentionally skips the real MCP proxy, token vault, OAuth, Cedar, and hosted control plane.
package/bin/aim.js ADDED
@@ -0,0 +1,392 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import {
6
+ addGrantDraft,
7
+ compileCodexRulePrompt,
8
+ compileGrantPrompt,
9
+ createPolicy,
10
+ deriveMcpCall,
11
+ draftGrantFromCall,
12
+ evaluateCodexHook,
13
+ evaluatePolicyCall,
14
+ } from "../src/engine.js";
15
+
16
+ const args = parseArgs(process.argv.slice(2));
17
+ const command = args._.shift();
18
+
19
+ try {
20
+ if (!command || command === "help" || args.help) {
21
+ printHelp();
22
+ } else if (command === "compile") {
23
+ compileCommand(args);
24
+ } else if (command === "add") {
25
+ addCommand(args);
26
+ } else if (command === "rule") {
27
+ ruleCommand(args);
28
+ } else if (command === "setup") {
29
+ setupCommand(args);
30
+ } else if (command === "hook") {
31
+ hookCommand(args);
32
+ } else if (command === "capture") {
33
+ captureCommand(args);
34
+ } else if (command === "check") {
35
+ checkCommand(args);
36
+ } else if (command === "authorize") {
37
+ authorizeCommand(args);
38
+ } else if (command === "demo") {
39
+ demoCommand(args);
40
+ } else {
41
+ fail(`Unknown command: ${command}`, 1, args.json);
42
+ }
43
+ } catch (error) {
44
+ fail(error.message, 1, args.json);
45
+ }
46
+
47
+ function ruleCommand(args) {
48
+ const subcommand = args._.shift();
49
+ if (subcommand === "add") {
50
+ ruleAddCommand(args);
51
+ } else if (subcommand === "list") {
52
+ ruleListCommand(args);
53
+ } else {
54
+ fail("Usage: aim rule add <intent> [--json] or aim rule list [--json]", 1, args.json);
55
+ }
56
+ }
57
+
58
+ function ruleAddCommand(args) {
59
+ const prompt = promptFrom(args);
60
+ const policyPath = policyPathFrom(args);
61
+ const policy = readPolicy(policyPath);
62
+ const result = compileCodexRulePrompt(prompt, { agentUid: args.agent ?? "codex" });
63
+
64
+ if (result.questions.length > 0 && !args.force) {
65
+ writeOutput({
66
+ error: "Refusing to write ambiguous Codex guardrail.",
67
+ questions: result.questions,
68
+ drafts: result.drafts,
69
+ }, args, true);
70
+ process.exitCode = 2;
71
+ return;
72
+ }
73
+
74
+ const grants = result.drafts.map((draft) =>
75
+ addGrantDraft(policy, draft, {
76
+ agentUid: args.agent ?? "codex",
77
+ grantedBy: args["granted-by"] ?? "aim",
78
+ connectionId: args.connection,
79
+ }),
80
+ );
81
+ writePolicy(policyPath, policy);
82
+ writeOutput({ policy: resolve(policyPath), grants, questions: result.questions }, args);
83
+ }
84
+
85
+ function ruleListCommand(args) {
86
+ const policyPath = policyPathFrom(args);
87
+ writeOutput({ policy: resolve(policyPath), grants: readPolicy(policyPath).grants }, args);
88
+ }
89
+
90
+ function setupCommand(args) {
91
+ const codexHome = codexHomeFrom(args);
92
+ const policyPath = policyPathFrom(args, codexHome);
93
+ const hooksPath = join(codexHome, "hooks.json");
94
+ const commandPrefix = args.command ?? "npx -y @samirosamsam/aim@latest";
95
+ const hookCommand = `${commandPrefix} hook pre-tool-use --policy ${quote(policyPath)}`;
96
+ const hooksConfig = readJson(hooksPath, { hooks: {} });
97
+ hooksConfig.hooks ??= {};
98
+ hooksConfig.hooks.PreToolUse = (hooksConfig.hooks.PreToolUse ?? [])
99
+ .filter((entry) => !(entry.hooks ?? []).some((hook) => String(hook.command ?? "").includes("aim") && String(hook.command ?? "").includes("pre-tool-use")));
100
+ hooksConfig.hooks.PreToolUse.push({
101
+ matcher: args.matcher ?? ".*",
102
+ hooks: [{
103
+ type: "command",
104
+ command: hookCommand,
105
+ timeout: Number(args.timeout ?? 5),
106
+ statusMessage: "AIM checking tool call",
107
+ }],
108
+ });
109
+
110
+ if (!existsSync(policyPath)) writePolicy(policyPath, createPolicy());
111
+ writeJson(hooksPath, hooksConfig);
112
+ writeOutput({ codexHome, hooks: resolve(hooksPath), policy: resolve(policyPath), command: hookCommand }, args);
113
+ }
114
+
115
+ function hookCommand(args) {
116
+ const subcommand = args._.shift();
117
+ if (subcommand !== "pre-tool-use") fail("Usage: aim hook pre-tool-use [--policy <file>]", 1, args.json);
118
+ const policy = readPolicy(policyPathFrom(args));
119
+ const input = JSON.parse(readFileSync(0, "utf8") || "{}");
120
+ const result = evaluateCodexHook(policy, input, { agentUid: args.agent ?? "codex" });
121
+
122
+ if (result.decision === "deny") {
123
+ console.log(JSON.stringify({
124
+ hookSpecificOutput: {
125
+ hookEventName: "PreToolUse",
126
+ permissionDecision: "deny",
127
+ permissionDecisionReason: `AIM blocked ${input.tool_name ?? "tool"}: ${result.reason}`,
128
+ },
129
+ }, null, 2));
130
+ return;
131
+ }
132
+
133
+ if (args.json) writeOutput(result, args);
134
+ }
135
+
136
+ function compileCommand(args) {
137
+ const prompt = promptFrom(args);
138
+ const result = compileGrantPrompt(prompt, { agentUid: args.agent ?? "" });
139
+ const drafts = applyDraftOverrides(result.drafts, args);
140
+ writeOutput({ intent: prompt, drafts, questions: result.questions }, args);
141
+ }
142
+
143
+ function addCommand(args) {
144
+ const prompt = promptFrom(args);
145
+ const policyPath = requireFlag(args, "policy");
146
+ const agentUid = requireFlag(args, "agent");
147
+ const policy = readPolicy(policyPath);
148
+ const result = compileGrantPrompt(prompt, { agentUid });
149
+ const drafts = applyDraftOverrides(result.drafts, args);
150
+
151
+ if (result.questions.length > 0 && !args.force) {
152
+ writeOutput({
153
+ error: "Refusing to write ambiguous grants. Answer questions or pass --force.",
154
+ questions: result.questions,
155
+ drafts,
156
+ }, args, true);
157
+ process.exitCode = 2;
158
+ return;
159
+ }
160
+
161
+ const grants = drafts.map((draft) =>
162
+ addGrantDraft(policy, draft, {
163
+ agentUid,
164
+ grantedBy: args["granted-by"] ?? "codex",
165
+ connectionId: args.connection,
166
+ }),
167
+ );
168
+ writePolicy(policyPath, policy);
169
+ writeOutput({ policy: resolve(policyPath), grants }, args);
170
+ }
171
+
172
+ function captureCommand(args) {
173
+ const call = callFromArgs(args);
174
+ const draft = draftGrantFromCall(call, {
175
+ effect: args.effect ?? "deny",
176
+ strictTool: Boolean(args["strict-tool"]),
177
+ reason: args.reason,
178
+ });
179
+ const questions = draft.resourcePattern === "*" ? ["Pass --resource or more MCP args before writing this rule."] : [];
180
+
181
+ if (args.policy) {
182
+ if (questions.length > 0 && !args.force) {
183
+ writeOutput({ error: "Refusing to write ambiguous MCP rule.", questions, draft }, args, true);
184
+ process.exitCode = 2;
185
+ return;
186
+ }
187
+ const policy = readPolicy(args.policy);
188
+ const grant = addGrantDraft(policy, draft, {
189
+ agentUid: requireFlag(args, "agent"),
190
+ grantedBy: args["granted-by"] ?? "codex",
191
+ connectionId: args.connection,
192
+ });
193
+ writePolicy(args.policy, policy);
194
+ writeOutput({ policy: resolve(args.policy), call, grants: [grant], questions }, args);
195
+ return;
196
+ }
197
+
198
+ writeOutput({ call, drafts: [draft], questions }, args);
199
+ }
200
+
201
+ function checkCommand(args) {
202
+ const policyPath = requireFlag(args, "policy");
203
+ const decision = evaluatePolicyCall(readPolicy(policyPath), {
204
+ agentUid: requireFlag(args, "agent"),
205
+ connectionId: requireFlag(args, "connection"),
206
+ tool: requireFlag(args, "tool"),
207
+ resource: requireFlag(args, "resource"),
208
+ access: args.access ?? "read",
209
+ params: args.params ? JSON.parse(args.params) : {},
210
+ });
211
+ writeOutput({ policy: resolve(policyPath), decision }, args);
212
+ }
213
+
214
+ function authorizeCommand(args) {
215
+ const policyPath = requireFlag(args, "policy");
216
+ const call = callFromArgs(args);
217
+ const decision = evaluatePolicyCall(readPolicy(policyPath), call);
218
+ writeOutput({ policy: resolve(policyPath), call, decision }, args);
219
+ }
220
+
221
+ function demoCommand(args) {
222
+ const policy = createPolicy();
223
+ const agentUid = "spiffe://local/agent/demo/codex";
224
+ const allow = compileGrantPrompt('Allow Notion read access to "workspace/shared/*"', { agentUid }).drafts[0];
225
+ const deny = compileGrantPrompt('Block Notion read access to "workspace/shared/legal/*"', { agentUid }).drafts[0];
226
+ const allowGrant = addGrantDraft(policy, allow, { agentUid, grantedBy: "demo" });
227
+ const denyGrant = addGrantDraft(policy, deny, { agentUid, grantedBy: "demo" });
228
+ const allowed = evaluatePolicyCall(policy, {
229
+ agentUid,
230
+ connectionId: "notion:prod",
231
+ tool: "pages.read",
232
+ resource: "workspace/shared/roadmap",
233
+ access: "read",
234
+ });
235
+ const denied = evaluatePolicyCall(policy, {
236
+ agentUid,
237
+ connectionId: "notion:prod",
238
+ tool: "pages.read",
239
+ resource: "workspace/shared/legal/term-sheet",
240
+ access: "read",
241
+ });
242
+ writeOutput({ grants: [allowGrant, denyGrant], decisions: [allowed, denied] }, args);
243
+ }
244
+
245
+ function applyDraftOverrides(drafts, args) {
246
+ return drafts.map((draft) => ({
247
+ ...draft,
248
+ agentUid: args.agent ?? draft.agentUid,
249
+ connectionId: args.connection ?? draft.connectionId,
250
+ }));
251
+ }
252
+
253
+ function callFromArgs(args) {
254
+ return deriveMcpCall({
255
+ agentUid: requireFlag(args, "agent"),
256
+ connectionId: requireFlag(args, "connection"),
257
+ provider: args.provider,
258
+ tool: requireFlag(args, "tool"),
259
+ args: args.args ? JSON.parse(args.args) : {},
260
+ access: args.access,
261
+ resource: args.resource,
262
+ });
263
+ }
264
+
265
+ function promptFrom(args) {
266
+ const prompt = args.prompt ?? args._.join(" ");
267
+ if (!prompt.trim()) throw new Error("Missing intent prompt.");
268
+ return prompt;
269
+ }
270
+
271
+ function readPolicy(path) {
272
+ const absolute = resolve(expandHome(path));
273
+ if (!existsSync(absolute)) return createPolicy();
274
+ return createPolicy(JSON.parse(readFileSync(absolute, "utf8")));
275
+ }
276
+
277
+ function writePolicy(path, policy) {
278
+ const absolute = resolve(expandHome(path));
279
+ mkdirSync(dirname(absolute), { recursive: true });
280
+ writeFileSync(absolute, `${JSON.stringify(policy, null, 2)}\n`);
281
+ }
282
+
283
+ function readJson(path, fallback) {
284
+ const absolute = resolve(expandHome(path));
285
+ if (!existsSync(absolute)) return fallback;
286
+ return JSON.parse(readFileSync(absolute, "utf8"));
287
+ }
288
+
289
+ function writeJson(path, value) {
290
+ const absolute = resolve(expandHome(path));
291
+ mkdirSync(dirname(absolute), { recursive: true });
292
+ writeFileSync(absolute, `${JSON.stringify(value, null, 2)}\n`);
293
+ }
294
+
295
+ function writeOutput(payload, args, stderr = false) {
296
+ const text = args.json ? JSON.stringify(payload, null, 2) : humanize(payload);
297
+ (stderr ? console.error : console.log)(text);
298
+ }
299
+
300
+ function humanize(payload) {
301
+ if (payload.error) {
302
+ return `${payload.error}\n${(payload.questions ?? []).map((q) => `- ${q}`).join("\n")}`;
303
+ }
304
+ if (payload.decision) {
305
+ return `${payload.decision.decision}: ${payload.decision.reason}`;
306
+ }
307
+ if (payload.grants) {
308
+ return payload.grants.map(formatGrant).join("\n");
309
+ }
310
+ if (payload.hooks) {
311
+ return `AIM hook installed\npolicy: ${payload.policy}\nhooks: ${payload.hooks}`;
312
+ }
313
+ if (!payload.drafts) return JSON.stringify(payload, null, 2);
314
+ return [
315
+ ...(payload.questions ?? []).map((question) => `QUESTION ${question}`),
316
+ ...payload.drafts.map(formatGrant),
317
+ ].join("\n");
318
+ }
319
+
320
+ function formatGrant(grant) {
321
+ return [
322
+ grant.effect.toUpperCase(),
323
+ grant.access,
324
+ grant.connectionId,
325
+ grant.toolPattern,
326
+ grant.resourcePattern,
327
+ ].join(" ");
328
+ }
329
+
330
+ function requireFlag(args, name) {
331
+ if (!args[name]) throw new Error(`Missing --${name}.`);
332
+ return args[name];
333
+ }
334
+
335
+ function codexHomeFrom(args) {
336
+ return resolve(expandHome(args["codex-home"] ?? process.env.CODEX_HOME ?? join(homedir(), ".codex")));
337
+ }
338
+
339
+ function policyPathFrom(args, codexHome = codexHomeFrom(args)) {
340
+ return resolve(expandHome(args.policy ?? join(codexHome, "aim", "policy.json")));
341
+ }
342
+
343
+ function expandHome(path) {
344
+ const text = String(path);
345
+ return text === "~" || text.startsWith("~/") ? join(homedir(), text.slice(2)) : text;
346
+ }
347
+
348
+ function quote(value) {
349
+ return `'${String(value).replace(/'/g, "'\\''")}'`;
350
+ }
351
+
352
+ function parseArgs(argv) {
353
+ const parsed = { _: [] };
354
+ for (let i = 0; i < argv.length; i += 1) {
355
+ const arg = argv[i];
356
+ if (!arg.startsWith("--")) {
357
+ parsed._.push(arg);
358
+ continue;
359
+ }
360
+ const key = arg.slice(2);
361
+ const next = argv[i + 1];
362
+ if (!next || next.startsWith("--")) {
363
+ parsed[key] = true;
364
+ } else {
365
+ parsed[key] = next;
366
+ i += 1;
367
+ }
368
+ }
369
+ return parsed;
370
+ }
371
+
372
+ function fail(message, code = 1, asJson = false) {
373
+ console.error(asJson ? JSON.stringify({ error: message }, null, 2) : message);
374
+ process.exit(code);
375
+ }
376
+
377
+ function printHelp() {
378
+ console.log(`AIM command
379
+
380
+ Usage:
381
+ aim compile "<intent>" [--agent <uid>] [--connection <id>] [--json]
382
+ aim setup [--codex-home <dir>] [--policy <file>] [--json]
383
+ aim rule add "<intent>" [--codex-home <dir>] [--policy <file>] [--json]
384
+ aim rule list [--codex-home <dir>] [--policy <file>] [--json]
385
+ aim hook pre-tool-use [--policy <file>]
386
+ aim add "<intent>" --policy <file> --agent <uid> [--connection <id>] [--granted-by <id>] [--json]
387
+ aim capture --provider <name> --tool <name> --args <json> --effect allow|deny|approval --agent <uid> --connection <id> [--policy <file>] [--json]
388
+ aim authorize --policy <file> --agent <uid> --connection <id> --provider <name> --tool <name> --args <json> [--json]
389
+ aim check --policy <file> --agent <uid> --connection <id> --tool <name> --resource <path> [--access read|write|delete] [--json]
390
+ aim demo [--json]
391
+ `);
392
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": ".*",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "npx -y @samirosamsam/aim@latest hook pre-tool-use",
10
+ "timeout": 5,
11
+ "statusMessage": "AIM checking tool call"
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@samirosamsam/aim",
3
+ "version": "0.1.0",
4
+ "description": "AIM CLI for installing deterministic Codex tool-call guardrails.",
5
+ "private": false,
6
+ "type": "module",
7
+ "bin": {
8
+ "aim": "bin/aim.js"
9
+ },
10
+ "files": [
11
+ ".agents/plugins/marketplace.json",
12
+ ".codex-plugin/plugin.json",
13
+ "bin/",
14
+ "hooks/",
15
+ "skills/",
16
+ "src/",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "prepublishOnly": "npm test",
22
+ "test": "node test/engine.test.js"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/tototozip/AIM.git"
27
+ },
28
+ "keywords": [
29
+ "agents",
30
+ "codex",
31
+ "iam",
32
+ "mcp",
33
+ "permissions"
34
+ ],
35
+ "author": "AIM",
36
+ "license": "MIT",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }