@ory/argus 0.13.9 → 1.0.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.
Files changed (133) hide show
  1. package/README.md +31 -45
  2. package/assets/commands/temporal-up.md +1 -1
  3. package/assets/skills/auth-setup/SKILL.md +1 -1
  4. package/assets/skills/local-dev/SKILL.md +17 -7
  5. package/assets/skills/ory-build-agent/SKILL.md +43 -97
  6. package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -18
  7. package/assets/skills/ory-temporal-worker/SKILL.md +38 -42
  8. package/assets/skills/permissions-onboarding/SKILL.md +131 -104
  9. package/dist/adapters.d.ts +93 -30
  10. package/dist/adapters.js +464 -136
  11. package/dist/agent-auth.d.ts +258 -68
  12. package/dist/agent-auth.js +998 -202
  13. package/dist/auth-store.d.ts +37 -2
  14. package/dist/auth-store.js +37 -3
  15. package/dist/auth.d.ts +40 -4
  16. package/dist/auth.js +247 -19
  17. package/dist/bash-parser.d.ts +98 -0
  18. package/dist/bash-parser.js +396 -0
  19. package/dist/branding.d.ts +128 -0
  20. package/dist/branding.js +151 -0
  21. package/dist/build-info.json +4 -4
  22. package/dist/cli-invocation.d.ts +1 -1
  23. package/dist/cli-invocation.js +2 -1
  24. package/dist/cli.d.ts +20 -29
  25. package/dist/cli.js +271 -278
  26. package/dist/client.d.ts +175 -138
  27. package/dist/client.js +672 -391
  28. package/dist/config.d.ts +249 -57
  29. package/dist/config.js +486 -62
  30. package/dist/context.d.ts +10 -0
  31. package/dist/context.js +21 -0
  32. package/dist/contract-suite.d.ts +8 -8
  33. package/dist/contract-suite.js +88 -69
  34. package/dist/denial.d.ts +36 -3
  35. package/dist/denial.js +79 -10
  36. package/dist/event-reporter.d.ts +77 -0
  37. package/dist/event-reporter.js +776 -0
  38. package/dist/external-registrations-main.d.ts +10 -0
  39. package/dist/external-registrations-main.js +38 -0
  40. package/dist/external-registrations.d.ts +79 -0
  41. package/dist/external-registrations.js +188 -0
  42. package/dist/help-cli.d.ts +39 -0
  43. package/dist/help-cli.js +55 -0
  44. package/dist/hook-timeout.d.ts +64 -0
  45. package/dist/hook-timeout.js +88 -0
  46. package/dist/index.d.ts +31 -19
  47. package/dist/index.js +182 -31
  48. package/dist/lifecycle.d.ts +3 -3
  49. package/dist/lifecycle.js +38 -6
  50. package/dist/local/cli.js +11 -6
  51. package/dist/local/configs.d.ts +74 -18
  52. package/dist/local/configs.js +291 -84
  53. package/dist/local/health.d.ts +14 -0
  54. package/dist/local/health.js +50 -4
  55. package/dist/local/index.d.ts +2 -2
  56. package/dist/local/index.js +24 -10
  57. package/dist/local/manager.d.ts +20 -1
  58. package/dist/local/manager.js +160 -39
  59. package/dist/local/ports.d.ts +158 -0
  60. package/dist/local/ports.js +443 -0
  61. package/dist/local/seed.d.ts +22 -25
  62. package/dist/local/seed.js +88 -56
  63. package/dist/logger.d.ts +54 -25
  64. package/dist/logger.js +329 -63
  65. package/dist/mcp.d.ts +2 -2
  66. package/dist/mcp.js +10 -5
  67. package/dist/mirror-bootstrap.d.ts +48 -0
  68. package/dist/mirror-bootstrap.js +254 -0
  69. package/dist/opl.d.ts +289 -0
  70. package/dist/opl.js +446 -0
  71. package/dist/permission-mode.d.ts +87 -0
  72. package/dist/permission-mode.js +307 -0
  73. package/dist/permissions-cli.d.ts +13 -49
  74. package/dist/permissions-cli.js +154 -348
  75. package/dist/permissions.d.ts +148 -38
  76. package/dist/permissions.js +591 -45
  77. package/dist/post-install.d.ts +33 -0
  78. package/dist/post-install.js +127 -0
  79. package/dist/read-credential.d.ts +65 -0
  80. package/dist/read-credential.js +86 -0
  81. package/dist/registry/cli.js +5 -2
  82. package/dist/registry/config.d.ts +0 -17
  83. package/dist/registry/config.js +0 -23
  84. package/dist/registry/index.d.ts +1 -1
  85. package/dist/registry/index.js +2 -2
  86. package/dist/registry/manager.d.ts +4 -21
  87. package/dist/registry/manager.js +83 -55
  88. package/dist/runtime-credential.d.ts +140 -0
  89. package/dist/runtime-credential.js +572 -0
  90. package/dist/runtime.d.ts +408 -0
  91. package/dist/runtime.js +748 -0
  92. package/dist/setup.d.ts +23 -28
  93. package/dist/setup.js +57 -84
  94. package/dist/status-cli.d.ts +29 -13
  95. package/dist/status-cli.js +124 -144
  96. package/dist/status-data.d.ts +195 -0
  97. package/dist/status-data.js +333 -0
  98. package/dist/status-system.d.ts +24 -0
  99. package/dist/status-system.js +56 -0
  100. package/dist/subject.d.ts +126 -20
  101. package/dist/subject.js +215 -30
  102. package/dist/testing.d.ts +74 -38
  103. package/dist/testing.js +185 -68
  104. package/dist/tool-catalog.d.ts +53 -11
  105. package/dist/tool-catalog.js +164 -13
  106. package/dist/tool-metadata.d.ts +7 -6
  107. package/dist/tool-metadata.js +6 -5
  108. package/dist/types.d.ts +11 -1
  109. package/dist/uninstall.d.ts +74 -19
  110. package/dist/uninstall.js +224 -49
  111. package/dist/user-login.d.ts +22 -16
  112. package/dist/user-login.js +67 -96
  113. package/dist/watch-cli.d.ts +6 -0
  114. package/dist/watch-cli.js +217 -0
  115. package/package.json +3 -11
  116. package/dist/dev.d.ts +0 -103
  117. package/dist/dev.js +0 -584
  118. package/dist/interactive-setup.d.ts +0 -165
  119. package/dist/interactive-setup.js +0 -1546
  120. package/dist/local/jaeger-main.d.ts +0 -13
  121. package/dist/local/jaeger-main.js +0 -85
  122. package/dist/local/jaeger.d.ts +0 -50
  123. package/dist/local/jaeger.js +0 -162
  124. package/dist/otel/exporter.d.ts +0 -17
  125. package/dist/otel/exporter.js +0 -12
  126. package/dist/otel/index.d.ts +0 -2
  127. package/dist/otel/index.js +0 -8
  128. package/dist/otel/otlp.d.ts +0 -103
  129. package/dist/otel/otlp.js +0 -385
  130. package/dist/tracer.d.ts +0 -190
  131. package/dist/tracer.js +0 -481
  132. package/dist/watch-sandbox.d.ts +0 -9
  133. package/dist/watch-sandbox.js +0 -81
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ory-temporal-worker
3
- description: Scaffold a [Temporal](https://temporal.io) TypeScript worker where every Activity execution is gated by Ory — the user is authenticated, the worker's agent identity is resolved via DCR, each Activity invocation runs an Ory Permission check, and the full lifecycle emits trace spans. Use when the user asks to "add Ory to my Temporal worker", "wire Ory permissions into Temporal activities", "create a Temporal worker with Ory auth", "build a Temporal TypeScript project with the Ory agent client", or any close variant. The skill scaffolds the project in the user's repo following <https://docs.temporal.io/develop/typescript/set-up-your-local-typescript> — it does not run the worker.
3
+ description: Scaffold a [Temporal](https://temporal.io) TypeScript worker where every Activity execution is gated by Ory — the user is authenticated, the worker's agent identity is resolved via DCR, each Activity invocation runs an Ory Permission check, and the full lifecycle emits structured activity events. Use when the user asks to "add Ory to my Temporal worker", "wire Ory permissions into Temporal activities", "create a Temporal worker with Ory auth", "build a Temporal TypeScript project with the Ory agent client", or any close variant. The skill scaffolds the project in the user's repo following <https://docs.temporal.io/develop/typescript/set-up-your-local-typescript> — it does not run the worker.
4
4
  ---
5
5
 
6
6
  # Ory-authed Temporal TypeScript worker
@@ -9,7 +9,7 @@ You are helping the user scaffold a [Temporal](https://temporal.io) TypeScript
9
9
  worker where every Activity execution is gated by Ory: the user is
10
10
  authenticated, the worker's agent identity is resolved via OAuth2 Dynamic Client
11
11
  Registration, each Activity invocation runs an Ory Permission check, and the
12
- full lifecycle emits trace spans. **Workflows stay deterministic** — only
12
+ full lifecycle emits structured activity events. **Workflows stay deterministic** — only
13
13
  Activities call out to Ory.
14
14
 
15
15
  This skill carries the workflow. You generate the files in the user's repo; the
@@ -70,7 +70,7 @@ import {
70
70
  } from "@ory/argus";
71
71
 
72
72
  // One client per worker process. `harness` is a label that shows up on
73
- // every trace span so worker-originated audit lives in its own namespace
73
+ // every activity event so worker-originated audit lives in its own namespace
74
74
  // alongside the CLI plugins.
75
75
  const ory = OryAgentClient.fromEnv("temporal");
76
76
 
@@ -83,12 +83,10 @@ function bootstrap(): Promise<void> {
83
83
  await ensureUserAuthenticated(ory, {
84
84
  binName: "temporal-worker",
85
85
  harness: "temporal",
86
- // Temporal's Activity entry point has no channel to carry a
87
- // session-start block, so the user gate runs in advisory mode:
88
- // it still refreshes tokens and emits the audit span, but the
89
- // worker proceeds even if the user is unauthenticated. Hard
90
- // enforcement happens at the per-Activity permission check.
91
- allowBlock: false,
86
+ // The user gate runs every invocation and never blocks: it refreshes
87
+ // tokens and emits the audit event, but the worker proceeds even if the
88
+ // user is unauthenticated. Enforcement happens at the per-Activity
89
+ // permission check (permissionMode).
92
90
  });
93
91
  await ensureAgentIdentity(ory, {
94
92
  projectUrl: process.env.ORY_PROJECT_URL,
@@ -104,13 +102,13 @@ async function gate(toolName: string, userSubject: string): Promise<void> {
104
102
  const decision = await checkAndDecide(
105
103
  ory,
106
104
  {
107
- namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools",
105
+ namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTool",
108
106
  object: toolName,
109
107
  relation: "use",
110
108
  ...subject,
111
109
  },
112
110
  {
113
- spanAttributes: {
111
+ activityAttributes: {
114
112
  toolName,
115
113
  workflowId: Context.current().info.workflowExecution.workflowId,
116
114
  activityId: Context.current().info.activityId,
@@ -145,13 +143,13 @@ Key choices:
145
143
 
146
144
  - **Activities call Ory, Workflows don't.** Anything that needs a live decision
147
145
  goes in an Activity. Workflows only orchestrate.
148
- - **`allowBlock: false`.** The Activity boundary can't carry a session-start
149
- block, so the user gate runs in advisory mode. Enforcement is at the
150
- permission check, which throws on deny — Temporal will mark the Activity as
151
- failed and surface the error via the Workflow result or retry policy.
152
- - **`harness: "temporal"`.** Distinguishes worker-originated spans in the trace
153
- file from CLI plugin spans.
154
- - **Span attributes carry the Workflow + Activity IDs.** This is how operators
146
+ - **The user gate never blocks.** It runs every invocation to refresh the user
147
+ identity, but always proceeds. Enforcement is at the permission check, which
148
+ throws on deny — Temporal will mark the Activity as failed and surface the
149
+ error via the Workflow result or retry policy.
150
+ - **`harness: "temporal"`.** Distinguishes worker-originated events in the
151
+ unified activity log.
152
+ - **Activity attributes carry the Workflow + Activity IDs.** This is how operators
155
153
  correlate Ory denials back to Temporal executions in the Web UI.
156
154
 
157
155
  ## Step 4 — Pass the user subject through the Workflow
@@ -217,7 +215,7 @@ cd temporal-worker
217
215
  export ORY_PROJECT_URL=http://localhost:4000
218
216
  export ORY_AUTH_GATE=1
219
217
  export ORY_AGENT_DEBUG=true
220
- export ORY_AGENT_TRACE_FILE=$PWD/ory-trace.ndjson
218
+ export ORY_AGENT_LOG_FILE=$PWD/ory-agent-debug.log
221
219
  npm run start # boots the worker, polls task queue
222
220
  ```
223
221
 
@@ -228,49 +226,47 @@ cd temporal-worker
228
226
  npm run workflow
229
227
  ```
230
228
 
231
- Tail the trace file to confirm the gates fired:
229
+ Tail the activity log to confirm the gates fired:
232
230
 
233
231
  ```bash
234
- tail -f ory-trace.ndjson | jq .
232
+ tail -f ory-agent-debug.log | jq .
235
233
  ```
236
234
 
237
235
  You should see:
238
236
 
239
- - exactly one `user.auth` span (the worker's first Activity triggered
237
+ - exactly one `user.auth` activity event (the worker's first Activity triggered
240
238
  `bootstrap()`),
241
- - exactly one `agent.auth` span,
242
- - one `tool.invoke` (allow) or `tool.block` (deny) span **per Activity
239
+ - exactly one `agent.auth` activity event,
240
+ - one `tool.invoke` (allow) or `tool.block` (deny) event **per Activity
243
241
  execution**.
244
242
 
245
- The Workflow itself produces no Ory spans — only its Activities do.
243
+ The Workflow itself produces no Ory activity — only its Activities do.
246
244
 
247
245
  ## Step 6 — Promotion from observe to enforce
248
246
 
249
247
  The worker starts in `observe` mode by default: denies pass through but each is
250
- recorded as a `permission.observe_deny` audit span. Once the user has confirmed
251
- the deny set is what they expect, promote to enforcement:
248
+ recorded as a `permission.observe_deny` activity event. Once the user has confirmed
249
+ the deny set is what they expect, an admin promotes the posture to `enforce` in
250
+ the Ory Console (Agent Security). It is a permission on the project, read on
251
+ every session, so the worker picks it up on its next run with no redeploy.
252
252
 
253
- ```bash
254
- export ORY_PERMISSION_MODE=enforce
255
- ```
256
-
257
- On a fresh Ory project, run the permissions bootstrap once before flipping the
258
- switch so the `use` tuples for each Activity name (`send_email`, …) exist —
259
- see {{REF_PERMISSIONS_ONBOARDING}}.
253
+ On a hosted Ory project, grant `use` on each Activity name (`send_email`, …) in
254
+ the Ory Console (Agent Security) before promoting the posture there — otherwise
255
+ enforcement blocks every Activity. See {{REF_PERMISSIONS_ONBOARDING}}.
260
256
 
261
- To exercise the deny path locally, write a tuple that explicitly removes `use`
262
- for the test user against one Activity object, kick the Workflow, and watch the
263
- Activity fail with the `Ory denied use of …` error in the Temporal Web UI.
257
+ To exercise the deny path locally, kick the Workflow with an Activity name the
258
+ local stack never granted, and watch it fail with the `Ory denied use of …`
259
+ error in the Temporal Web UI.
264
260
 
265
261
  ## Step 7 — Beyond the dev server
266
262
 
267
263
  This skill stops at the local dev server. For production:
268
264
 
269
- - Pin a static agent identity with `ORY_AGENT_API_KEY` (single key) or
270
- `ORY_AGENT_CLIENT_ID + ORY_AGENT_CLIENT_SECRET` (client_credentials) so the
271
- worker doesn't re-register on every cold start.
272
- - Persist the worker's `ory-trace.ndjson` somewhere durable, or replace the
273
- file tracer with an OpenTelemetry exporter wired up around `ory.tracer`.
265
+ - Pin a static agent identity with `ORY_AGENT_CLIENT_ID +
266
+ ORY_AGENT_CLIENT_SECRET` (client_credentials) so the worker doesn't
267
+ re-register on every cold start.
268
+ - Set retention and access controls for the worker's unified activity log.
269
+ Ory Agent Security owns service telemetry; the worker does not export traces.
274
270
  - Use Temporal Cloud or a self-hosted Temporal cluster instead of
275
271
  `temporal server start-dev`; the worker code does not change.
276
272
 
@@ -1,32 +1,57 @@
1
1
  ---
2
2
  name: ory-permissions-onboarding
3
- description: Onboard a fresh install onto Ory Permissions for AI agent tool calls. Use when the user has just installed the Ory plugin and wants to enforce per-tool authorization without first getting blocked by missing tuples. Walks through observe-mode observation, idempotent tuple bootstrap, and promotion to enforce mode.
3
+ description: Onboard a fresh install onto Ory Permissions for AI agent tool calls. Use when the user has just installed the Ory plugin and wants per-tool authorization enforced without first getting blocked by missing permissions. Covers connecting the plugin, reading coverage in observe mode, and what has to happen in the Ory Console (grants, blocks, enforce posture).
4
4
  ---
5
5
 
6
6
  # Onboard onto Ory Permissions for Agent Tool Calls
7
7
 
8
8
  You are helping a user move a freshly-installed Ory agent plugin from
9
- "permissions are running but never block" (the default after install)
10
- to "permissions are enforcing" (the production posture), without the
11
- common first-run failure mode of getting every tool call blocked
12
- because no tuples exist yet.
9
+ "disconnected" to "permissions are enforcing", without the common
10
+ first-run failure mode of getting every tool call blocked because the
11
+ project has no grants yet.
12
+
13
+ **The plugin only reads permissions. It never writes them.** Everything
14
+ that provisions the project — the permission model, per-tool grants,
15
+ explicit blocks, and the observe/enforce posture — is done in the **Ory
16
+ Console** (Agent Security) by someone with access to the project. That
17
+ split is deliberate: it means installing and connecting a plugin needs
18
+ nothing but project connection details and a public OAuth2 client id, with no
19
+ workspace privilege and no project API key.
20
+
21
+ Two things govern behavior:
22
+
23
+ - **Whether Agent Security is connected** — it runs when a project URL,
24
+ canonical Agent Security origin, and public OAuth2 client id resolve. Existing
25
+ configurations fall back to the project URL when the canonical origin is
26
+ unset. Not connected means no login and no permission checks, with
27
+ tool calls recorded locally. Skills, commands, the local dev stack, and
28
+ the MCP server work either way — they don't need a project at all.
29
+ - **`permissionMode`** — `observe` or `enforce`, **read from the Ory
30
+ project** on every session, and only meaningful once connected.
31
+ `observe` (the default) runs every check, records denials, and lets the
32
+ tool proceed. `enforce` blocks on deny. There is no local override — an
33
+ admin sets it in the Console.
34
+
35
+ The journey: **install → connect → observe → grant in the Console →
36
+ enforce in the Console.**
37
+
38
+ ## Step 1: Connect the plugin to the project
39
+
40
+ A fresh install has the developer-experience half working and Agent
41
+ Security not connected. Copy the connection details shown in the Ory Console
42
+ under **Agent Security**:
13
43
 
14
- The plugin ships with two orthogonal switches:
15
-
16
- - **`auditOnly`** — a kill switch. When set, Ory is *off entirely* (no
17
- auth, no permission checks). This is for users who want only audit
18
- logging of tool invocations. Not what onboarding is about.
19
- - **`permissionMode`** — the dial this skill is about. `observe` (the
20
- default) runs every permission check, logs denials, but allows the
21
- tool to proceed. `enforce` blocks on deny. Mode is read from
22
- `ORY_PERMISSION_MODE` first, then the shared config file, then
23
- defaults to `observe`.
24
-
25
- The journey: **install → observe → bootstrap → enforce.**
44
+ ```sh
45
+ {{NPX}} configure --project-url <URL> --agent-security-url <URL>
46
+ ```
26
47
 
27
- ## Step 1: Confirm the plugin is installed and configured
48
+ - **project URL** the project's SDK URL (`https://<slug>.projects.oryapis.com`).
49
+ - **Agent Security URL** — the canonical broker origin (`https://agents.console.ory.com` in production).
50
+ - **OAuth2 client id** — the project's public login client, provisioned
51
+ in the Console. The per-session user login needs it to complete its
52
+ PKCE browser flow.
28
53
 
29
- Verify the plugin is wired up and pointing at the right Ory project:
54
+ Then confirm what the plugin resolved:
30
55
 
31
56
  ```sh
32
57
  {{NPX}} status
@@ -35,133 +60,135 @@ Verify the plugin is wired up and pointing at the right Ory project:
35
60
  What you want to see:
36
61
 
37
62
  - **Project URL**: a real Ory URL or your local dev gateway (not "NOT SET").
38
- - **API Key**: set (Ory Network) or unset (local Keto OSS — that's fine).
39
- - **Mode**: not "audit-only" that would mean Ory is disabled.
40
-
41
- If any of those are wrong, fix them before continuing:
63
+ - **OAuth2 Client**: the project's public login client (not "NOT SET").
64
+ - **Agent Security**: connected. If it says "not connected", it names the
65
+ unresolved connection value.
42
66
 
43
- ```sh
44
- {{NPX}} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]
45
- ```
46
-
47
- `--oauth2-client-id` is the public OAuth2 client registered in your Ory project (required when `ORY_USER_LOGIN=true`; see the *Register the user OAuth2 client* section of the plugin README).
67
+ If the user doesn't have those values, they need them from whoever
68
+ administers the project. Don't try to create the client from here — the
69
+ plugin has no privilege to, by design.
48
70
 
49
71
  ## Step 2: Look at the current permission posture
50
72
 
51
73
  ```sh
52
- {{NPX}} permissions status
74
+ {{NPX}} permissions
53
75
  ```
54
76
 
55
77
  This prints:
56
78
 
57
- - The current **permission mode** (`observe` or `enforce`) and where it
58
- was resolved from (env / config / default).
59
- - The **subject** (the user identity tuples are checked against).
79
+ - The live **permission mode** (`observe` or `enforce`) and whether it
80
+ came from the project, a cached value, or the default.
81
+ - The **subject** the user identity permissions are checked against.
60
82
  - For each tool in this harness's built-in catalog, **allowed / denied /
61
- errored** based on a real `checkPermission` call against your Ory
62
- project right now.
83
+ blocked / errored**, from a real check against the project right now.
84
+ - A one-line coverage summary for decomposed shell command words.
63
85
 
64
- On a fresh install you will almost always see every tool reported as
65
- **denied** — because no tuples exist yet for the current user. That's
66
- expected, and in observe mode it is *not blocking anyone*. The tool
67
- calls are running through; you are simply seeing what *would* be
68
- blocked once enforce mode is turned on.
86
+ On a freshly-connected project you will usually see every tool reported
87
+ as **denied** — no grants exist for this user yet. In observe mode that
88
+ blocks nobody: tool calls run through, and you are seeing what *would*
89
+ be blocked under enforce.
69
90
 
70
- If the status command prints `Mode: enforce` but tuples are missing,
71
- stop here: tool calls *are* being blocked right now. Either bootstrap
72
- (next step) or run `{{NPX}} permissions observe` first to flip back to
73
- non-blocking.
91
+ If status prints `Mode: enforce` while tools are denied, tool calls
92
+ **are** being blocked right now. The fix is in the Console (grant the
93
+ tools, or move the project back to observe) not from the CLI.
74
94
 
75
- ## Step 3: Bootstrap tuples for the harness's built-in tools
95
+ ## Step 3: Run a real session in observe mode
76
96
 
77
- Grant the current user `use` on every tool the harness ships with:
97
+ Observe mode is the discovery phase. Use the harness normally, then look
98
+ at what was recorded:
78
99
 
79
100
  ```sh
80
- {{NPX}} permissions bootstrap
101
+ {{NPX}} status # summary + recent activity
102
+ {{NPX}} watch # live event, decision, and error view
81
103
  ```
82
104
 
83
- This is **idempotent** Keto returns 409 on a tuple that already
84
- exists, and the command treats that as success. Safe to re-run any time
85
- (e.g. after the harness adds a new tool to its catalog).
86
-
87
- The command writes `<namespace>:<tool>#use@<userSubject>` for each tool
88
- in the harness's known catalog. MCP server tools are *not* covered —
89
- they are discovered dynamically per session, so they need tuples added
90
- out-of-band as they come into scope.
91
-
92
- ### When bootstrap can't write tuples
105
+ Launch the harness with `ORY_AGENT_DEBUG=true` to include verbose diagnostics in
106
+ the watched log and stderr. Denials appear as `permission.observe_deny` activity events (and
107
+ `permission.block_observed` for an explicit block), with the tool name
108
+ and the subject. That list is exactly what has to be granted before
109
+ enforce is safe.
93
110
 
94
- Two common failure modes:
111
+ ## Step 4: Grant the tools in the Ory Console
95
112
 
96
- 1. **No user identity cached.** Bootstrap needs to know which subject
97
- to grant tuples to. If user login has never run (no PKCE login,
98
- no `ORY_USER_SUBJECT_ID`), the command refuses. Run the harness once
99
- with `ORY_USER_LOGIN=true` to cache a user token, or set
100
- `ORY_USER_SUBJECT_ID=<id>` to target a known subject.
101
- 2. **Credentials lack write scope on the permission namespace.** The
102
- command prints the full tuple list so you can apply them manually
103
- via `keto relation-tuples create`, the Ory Console's *Add
104
- relationship* dialog, or `curl` against Keto's write API. Hand the
105
- list to whoever holds write credentials.
106
-
107
- ### Add tuples for non-default tools
108
-
109
- If the harness has tools beyond the built-in catalog (MCP servers,
110
- custom commands), grant them by writing tuples directly. Use the same
111
- shape:
113
+ In the Ory Console **Agent Security**, grant the subject `use` on the
114
+ tools it needs. The grant shape the runtime checks is:
112
115
 
113
116
  ```
114
- namespace: AgentTools (or whatever ORY_PERMISSION_NAMESPACE is set to)
115
- object: <tool name>
117
+ namespace: AgentTool (or whatever ORY_PERMISSION_NAMESPACE is set to)
118
+ object: <tool name> (e.g. Read, Bash, WebFetch)
116
119
  relation: use
117
- subject: <user subject id>
120
+ subject: User:<id> (a SubjectSet — namespace `User`, object the user id)
118
121
  ```
119
122
 
120
- Re-run `{{NPX}} permissions status` afterwards to confirm coverage.
123
+ Notes worth passing on to the user:
121
124
 
122
- ## Step 4: Promote to enforce mode
125
+ - The subject is a **SubjectSet** (`User:<id>`), which is what the
126
+ Console's *Add relationship* dialog emits and exactly what the runtime
127
+ check uses. A bare subject id will not match.
128
+ - Granting a **group** and putting users in it scales better than
129
+ per-user grants; the check follows subject-set expansion.
130
+ - **Shell command words** are authorized separately in the `ShellTool`
131
+ namespace (`ShellTool:curl#use`, …) because a denied surface is
132
+ otherwise reachable through `bash -c "curl …"`.
133
+ - **MCP server tools** are discovered dynamically per session, so they
134
+ are not in the built-in catalog and need granting as they come into
135
+ scope.
123
136
 
124
- Once `permissions status` shows the tools you actually use are
125
- `allowed`, flip the dial:
137
+ Re-run `{{NPX}} permissions` afterwards to confirm coverage.
126
138
 
127
- ```sh
128
- {{NPX}} permissions enforce
129
- ```
139
+ ## Step 5: Promote to enforce in the Console
140
+
141
+ Once the tools the user actually needs report `allowed`, an admin flips
142
+ the posture in the Console (Agent Security). The mode is a permission on
143
+ the project, so it can be set **project-wide** — covering principals
144
+ that don't exist yet — or **per principal** as an exception.
130
145
 
131
- This persists `permissionMode = "enforce"` in the shared config file.
132
- Subsequent sessions will block any tool call that returns deny. Mode
133
- can always be flipped back:
146
+ Every session reads the live mode, so the change takes effect without
147
+ reinstalling or reconfiguring anything. Confirm it landed:
134
148
 
135
149
  ```sh
136
- {{NPX}} permissions observe
150
+ {{NPX}} permissions
137
151
  ```
138
152
 
139
- `ORY_PERMISSION_MODE`, when set, overrides the config useful for CI
140
- runs that want enforce regardless of what's persisted, or for one-off
141
- debugging sessions where you want observe without rewriting config.
142
-
143
- ## Step 5: Verify a real session
153
+ ## Step 6: Verify a real session under enforce
144
154
 
145
155
  Start a normal agent session and confirm:
146
156
 
147
157
  - **Allowed tools** invoke without complaint.
148
- - **Denied tools** (if any) are blocked with a clear "Ory: permission
149
- denied" message.
150
- - The trace file shows `permission.check` spans for each tool call and
151
- `tool.block` spans for any denial.
158
+ - **Denied tools** are blocked with a clear "Ory: permission denied"
159
+ message naming the tool (or the shell command word).
160
+ - The activity log shows `permission.check` events per tool call and
161
+ `tool.block` events for denials.
162
+
163
+ If a tool is unexpectedly blocked, run `{{NPX}} permissions` to
164
+ see whether it is `denied` (no grant) or `blocked` (an explicit
165
+ deny-override), then fix it in the Console and re-test.
166
+
167
+ ## Explicit blocks (deny-override)
168
+
169
+ Granting is additive. To express the opposite — a subject is **blocked**
170
+ from a tool, beating any grant, including one inherited through a group —
171
+ an admin writes a `blockedSubjects` relation in the Console. Ory evaluates it
172
+ natively (the `use` permit is "granted AND not blocked"), so it holds
173
+ no matter how the grant was reached.
152
174
 
153
- If a tool is unexpectedly blocked, run `{{NPX}} permissions status` to
154
- confirm whether the tuple exists, then add or fix tuples and re-test.
175
+ A block behaves like any other deny: under **observe** it is recorded (a
176
+ `permission.block_observed` activity event) but the tool still runs; under
177
+ **enforce** it blocks. `permissions` marks blocked tools so they
178
+ are distinguishable from a plain missing grant at a glance.
155
179
 
156
- ## Reference: what each command does
180
+ ## Reference
157
181
 
158
182
  | Command | Effect |
159
183
  |---|---|
160
- | `{{NPX}} permissions status` | Print mode + per-tool allow/deny breakdown for the current user. Read-only. |
161
- | `{{NPX}} permissions bootstrap` | Write `use` tuples for the harness's built-in tools. Idempotent. |
162
- | `{{NPX}} permissions bootstrap --dry-run` | Print what would be written without making any changes. |
163
- | `{{NPX}} permissions observe` | Persist `permissionMode = "observe"` (denies log, allow through). |
164
- | `{{NPX}} permissions enforce` | Persist `permissionMode = "enforce"` (denies block). |
184
+ | `{{NPX}} configure --project-url <URL> --agent-security-url <URL>` | Connect the plugin to the canonical Agent Security broker. |
185
+ | `{{NPX}} configure --disconnect` | Turn sign-in and permission checks back off. Skills, commands, the local stack, and activity logging are unaffected. |
186
+ | `{{NPX}} permissions` | Print the live mode + per-tool allowed/denied/blocked breakdown. Read-only. |
187
+ | `{{NPX}} status` | Configuration, identities, permission coverage, recent activity. |
188
+
189
+ Done in the **Ory Console** (Agent Security), not from the CLI: applying
190
+ the permission model, granting `use` on tools, writing explicit blocks,
191
+ and setting the observe/enforce posture.
165
192
 
166
193
  For deeper background on the authentication side of the flow (which
167
194
  identity is the subject, how the user gate resolves it), see