@ory/argus 0.14.0 → 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 (150) hide show
  1. package/README.md +31 -46
  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 +39 -91
  6. package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -17
  7. package/assets/skills/ory-temporal-worker/SKILL.md +31 -33
  8. package/assets/skills/permissions-onboarding/SKILL.md +131 -104
  9. package/dist/adapters.d.ts +88 -32
  10. package/dist/adapters.js +443 -164
  11. package/dist/agent-auth.d.ts +226 -67
  12. package/dist/agent-auth.js +951 -205
  13. package/dist/auth-store.d.ts +37 -2
  14. package/dist/auth-store.js +37 -3
  15. package/dist/auth.d.ts +33 -4
  16. package/dist/auth.js +163 -20
  17. package/dist/bash-parser.d.ts +98 -0
  18. package/dist/bash-parser.js +396 -0
  19. package/dist/branding.d.ts +77 -16
  20. package/dist/branding.js +93 -23
  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 -239
  26. package/dist/client.d.ts +175 -138
  27. package/dist/client.js +672 -391
  28. package/dist/config.d.ts +217 -54
  29. package/dist/config.js +461 -42
  30. package/dist/context.d.ts +10 -0
  31. package/dist/context.js +21 -0
  32. package/dist/contract-suite.d.ts +3 -5
  33. package/dist/contract-suite.js +75 -47
  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 +28 -23
  47. package/dist/index.js +173 -58
  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.js +7 -7
  54. package/dist/local/index.d.ts +2 -2
  55. package/dist/local/index.js +24 -10
  56. package/dist/local/manager.d.ts +20 -1
  57. package/dist/local/manager.js +159 -36
  58. package/dist/local/ports.d.ts +158 -0
  59. package/dist/local/ports.js +443 -0
  60. package/dist/local/seed.d.ts +13 -5
  61. package/dist/local/seed.js +62 -38
  62. package/dist/logger.d.ts +54 -25
  63. package/dist/logger.js +329 -63
  64. package/dist/mcp.d.ts +2 -2
  65. package/dist/mcp.js +10 -5
  66. package/dist/mirror-bootstrap.d.ts +48 -0
  67. package/dist/mirror-bootstrap.js +254 -0
  68. package/dist/opl.d.ts +289 -0
  69. package/dist/opl.js +446 -0
  70. package/dist/permission-mode.d.ts +87 -0
  71. package/dist/permission-mode.js +307 -0
  72. package/dist/permissions-cli.d.ts +13 -49
  73. package/dist/permissions-cli.js +154 -348
  74. package/dist/permissions.d.ts +148 -38
  75. package/dist/permissions.js +591 -45
  76. package/dist/post-install.d.ts +33 -0
  77. package/dist/post-install.js +127 -0
  78. package/dist/read-credential.d.ts +65 -0
  79. package/dist/read-credential.js +86 -0
  80. package/dist/registry/cli.js +5 -2
  81. package/dist/registry/config.d.ts +0 -17
  82. package/dist/registry/config.js +0 -23
  83. package/dist/registry/index.d.ts +1 -1
  84. package/dist/registry/index.js +2 -2
  85. package/dist/registry/manager.d.ts +4 -21
  86. package/dist/registry/manager.js +21 -37
  87. package/dist/runtime-credential.d.ts +140 -0
  88. package/dist/runtime-credential.js +572 -0
  89. package/dist/runtime.d.ts +408 -0
  90. package/dist/runtime.js +748 -0
  91. package/dist/setup.d.ts +23 -47
  92. package/dist/setup.js +59 -116
  93. package/dist/skills.js +0 -7
  94. package/dist/status-cli.d.ts +27 -11
  95. package/dist/status-cli.js +121 -115
  96. package/dist/status-data.d.ts +116 -17
  97. package/dist/status-data.js +121 -38
  98. package/dist/subject.d.ts +126 -20
  99. package/dist/subject.js +215 -30
  100. package/dist/testing.d.ts +74 -38
  101. package/dist/testing.js +185 -68
  102. package/dist/tool-catalog.d.ts +53 -11
  103. package/dist/tool-catalog.js +164 -13
  104. package/dist/tool-metadata.d.ts +7 -6
  105. package/dist/tool-metadata.js +6 -5
  106. package/dist/types.d.ts +11 -1
  107. package/dist/uninstall.d.ts +71 -34
  108. package/dist/uninstall.js +217 -85
  109. package/dist/user-login.d.ts +9 -10
  110. package/dist/user-login.js +56 -75
  111. package/dist/watch-cli.d.ts +6 -0
  112. package/dist/watch-cli.js +217 -0
  113. package/package.json +4 -27
  114. package/assets/commands/dashboard.md +0 -34
  115. package/dist/dashboard-cli.d.ts +0 -8
  116. package/dist/dashboard-cli.js +0 -70
  117. package/dist/dev.d.ts +0 -103
  118. package/dist/dev.js +0 -583
  119. package/dist/interactive-setup.d.ts +0 -286
  120. package/dist/interactive-setup.js +0 -1734
  121. package/dist/local/jaeger-main.d.ts +0 -13
  122. package/dist/local/jaeger-main.js +0 -85
  123. package/dist/local/jaeger.d.ts +0 -50
  124. package/dist/local/jaeger.js +0 -162
  125. package/dist/otel/exporter.d.ts +0 -17
  126. package/dist/otel/exporter.js +0 -12
  127. package/dist/otel/index.d.ts +0 -2
  128. package/dist/otel/index.js +0 -8
  129. package/dist/otel/otlp.d.ts +0 -103
  130. package/dist/otel/otlp.js +0 -385
  131. package/dist/project-api-key.d.ts +0 -69
  132. package/dist/project-api-key.js +0 -147
  133. package/dist/setup-actions.d.ts +0 -232
  134. package/dist/setup-actions.js +0 -507
  135. package/dist/tracer.d.ts +0 -190
  136. package/dist/tracer.js +0 -481
  137. package/dist/watch-sandbox.d.ts +0 -9
  138. package/dist/watch-sandbox.js +0 -81
  139. package/dist/web/api.d.ts +0 -33
  140. package/dist/web/api.js +0 -294
  141. package/dist/web/launch.d.ts +0 -11
  142. package/dist/web/launch.js +0 -96
  143. package/dist/web/server.d.ts +0 -20
  144. package/dist/web/server.js +0 -233
  145. package/dist/web/types.d.ts +0 -65
  146. package/dist/web/types.js +0 -2
  147. package/dist/webapp/assets/index-Wucl4SZs.css +0 -1
  148. package/dist/webapp/assets/index-m-GtEdq0.js +0 -49
  149. package/dist/webapp/favicon.ico +0 -0
  150. package/dist/webapp/index.html +0 -15
package/README.md CHANGED
@@ -1,23 +1,25 @@
1
1
  # Ory Argus: Agent and Developer Experience
2
2
 
3
- The core API behind every Ory Agent Plugin and Extension. Argus wraps [Ory Identities](https://www.ory.com/ory-ecosystem), [Ory Permissions](https://ory.com/permissions), MCP authorization, and distributed tracing into a single client. Each harness package (`@ory/claude-code`, `@ory/codex`, `@ory/gemini-cli`, and the rest — see the [root README](../../README.md) for the full list) is a thin adapter that maps one harness's hook contract onto Argus.
3
+ The core API behind every Ory Agent Plugin and Extension. Argus wraps [Ory Identities](https://www.ory.com/ory-ecosystem), [Ory Permissions](https://ory.com/permissions), MCP authorization, and privacy-safe activity auditing into a single client. Each harness package (`@ory/claude-code`, `@ory/codex`, `@ory/gemini-cli`, and the rest) is a thin adapter that maps one harness's hook contract onto Argus.
4
4
 
5
5
  Argus is also published on its own so you can build new harness plugins or extensions, embed Ory into a custom agent runtime, or instrument any SDK that exposes event lifecycle hooks for session start, tool execution, and tool completion.
6
6
 
7
7
  ## Use
8
8
 
9
9
  ```typescript
10
- import { OryAgentClient } from "@ory/argus";
10
+ import { OryAgentClient, resolveUserSubject } from "@ory/argus";
11
11
 
12
12
  const client = OryAgentClient.fromEnv("my-harness");
13
13
 
14
14
  const session = await client.verifySession(sessionToken);
15
15
 
16
+ // Every principal is addressed as a SubjectSet (`User:<id>` by default,
17
+ // `Session:<id>` for the fallback). resolveUserSubject builds the right shape.
16
18
  const result = await client.checkPermission({
17
- namespace: "AgentTools",
19
+ namespace: "AgentTool",
18
20
  object: "Bash",
19
21
  relation: "use",
20
- subjectId: `session:${sessionId}`,
22
+ ...resolveUserSubject(client, `session:${sessionId}`),
21
23
  });
22
24
 
23
25
  if (!result.allowed) {
@@ -29,46 +31,35 @@ if (!result.allowed) {
29
31
 
30
32
  ## Build a new plugin, extension, or custom integration
31
33
 
32
- Any agent runtime, framework, or SDK that exposes lifecycle hooks for **session start**, **tool execution**, and **tool completion** can use Argus as its authentication, authorization, and audit layer. The integration contract is the same three calls every plugin in this repo makes:
34
+ Any agent runtime, framework, or SDK that exposes lifecycle hooks for **session start**, **tool execution**, and **tool completion** can use Argus as its authentication, authorization, and audit layer. Core adapters own the shared behavior; integrations only translate host fields and block outputs:
33
35
 
34
36
  ```typescript
35
37
  import {
38
+ complete,
39
+ gate,
36
40
  OryAgentClient,
37
- ensureUserAuthenticated,
38
- ensureAgentIdentity,
41
+ sessionStart,
42
+ withHookContext,
39
43
  } from "@ory/argus";
40
44
 
41
45
  const client = OryAgentClient.fromEnv("my-harness");
42
46
 
43
47
  // 1. Session start: authenticate the human and the agent process.
44
48
  async function onSessionStart() {
45
- // Runs every session and never blocks — it establishes the user identity
46
- // for attribution; enforcement happens at the tool gate via permissionMode.
47
- await ensureUserAuthenticated(client, {
48
- binName: "my-harness",
49
- harness: "my-harness",
50
- });
51
- await ensureAgentIdentity(client, {
52
- projectUrl: process.env.ORY_PROJECT_URL,
53
- });
49
+ await sessionStart(client, { harness: "my-harness" });
54
50
  }
55
51
 
56
52
  // 2. Before each tool call: check Ory Permissions; block on `deny`.
57
- async function onBeforeTool(toolName: string, sessionId: string) {
58
- const result = await client.checkPermission({
59
- namespace: "AgentTools",
60
- object: toolName,
61
- relation: "use",
62
- subjectId: `session:${sessionId}`,
53
+ async function onBeforeTool(toolName: string, args: unknown, sessionId: string) {
54
+ return withHookContext(client, { sessionId }, async () => {
55
+ const result = await gate(client, { harness: "my-harness", toolName, toolArgs: args });
56
+ return result.blocked ? { block: true, reason: result.denialMessage } : {};
63
57
  });
64
- if (result.allowed === false) {
65
- return { block: true, reason: result.reason };
66
- }
67
58
  }
68
59
 
69
- // 3. After each tool call: record a structured trace span.
70
- async function onAfterTool(toolName: string, durationMs: number) {
71
- client.tracer.record("tool.complete", { toolName, durationMs });
60
+ // 3. After each tool call: record structured completion activity.
61
+ async function onAfterTool(toolName: string, output: unknown) {
62
+ complete(client, { toolName, output });
72
63
  }
73
64
  ```
74
65
 
@@ -85,8 +76,8 @@ The wrapped Ory client. One instance per harness session.
85
76
  | Sessions and tokens | `verifySession`, `introspectToken`, `classifyError` |
86
77
  | Permission checks | `checkPermission`, `batchCheckPermissions`, `checkMcpPermission` |
87
78
  | Principals (who is acting) | `setUserPrincipal`, `setAgentPrincipal` |
88
- | Delegation relations | `createRelationship`, `deleteRelationship` |
89
- | Tracing | `tracer` (see Tracer below) |
79
+ | Delegation | `recordDelegation` (via the Ory Agent Security broker — the only write path; Keto is read-only here) |
80
+ | Activity and debug | `logger` (see Logger below) |
90
81
 
91
82
  ### Identity gates
92
83
 
@@ -95,23 +86,18 @@ Resolve the user and agent identities at session start. Non-blocking by default;
95
86
  | Helper | Purpose |
96
87
  |---|---|
97
88
  | `ensureUserAuthenticated` | Interactive PKCE login, token refresh, or env-token short-circuit |
98
- | `ensureAgentIdentity` | OAuth2 dynamic client registration with persisted credentials |
99
- | `ensureSubAgentIdentity` | Per-sub-agent identity for harnesses that fan out |
100
- | `resolveUserSubject`, `subjectLabel` | Subject resolution and printable labels for spans and denial messages |
101
-
102
- ### Tracer
103
-
104
- `Tracer` is exposed as `client.tracer`. Records every decision as a structured span.
105
-
106
- - `record(event, attrs)`: emit a span
107
- - `EventEmitter` `"span"` events for live observers
108
- - NDJSON file output
109
- - OTLP / HTTP export
89
+ | `ensureAgentIdentity` | Injected/Talos runtime authentication with OS-store persistence and session-start enrollment |
90
+ | `ensureSubAgentIdentity` | Spawn-scoped child Talos identity issued through the authenticated parent |
91
+ | `resolveUserSubject`, `subjectLabel` | Subject resolution and printable labels for activity and denial messages |
110
92
 
111
93
  ### Logger
112
94
 
113
- - `DebugLogger`: structured JSON to stderr plus optional log file
114
- - Gated by `ORY_AGENT_DEBUG`
95
+ - `DebugLogger`: recursively redacted structured activity plus verbose diagnostics in one NDJSON stream
96
+ - Privacy-safe activity always persists to `<dataDir>/<harness>/ory-agent-debug.log` by default
97
+ - `ORY_AGENT_LOG_FILE` overrides the path; an empty value disables persistence
98
+ - `ORY_AGENT_DEBUG=true` adds the complete live JSON stream to stderr and verbose local diagnostics, including raw shell commands
99
+ - `runWatchCommand` follows the unified log with human-readable event, decision, and error context or raw NDJSON
100
+ - Ory Agent Security owns service telemetry; Argus has no OTel exporter or trace-context surface
115
101
 
116
102
  ### Skill and command catalog
117
103
 
@@ -126,9 +112,8 @@ Materialize the canonical `SKILL.md` templates into each harness's native skill
126
112
  ### CLI and dev tooling
127
113
 
128
114
  - Shared CLI handlers used by every plugin's CLI: `configure`, `status`, `local`, `setup`
129
- - `runDevLauncher(...)`: the dev-launcher pipeline used by every plugin
130
115
  - Local-stack manager: brings up a local Ory instance in Docker Compose
131
- - Verdaccio registry manager: a local npm registry for dev launchers
116
+ - Verdaccio registry manager: builds and publishes the workspace for local product development
132
117
 
133
118
  ## License
134
119
 
@@ -26,7 +26,7 @@ The process runs in the foreground. Stop it with `Ctrl+C`; data is preserved.
26
26
  For a clean reset, delete `~/.config/temporalio/` and start again.
27
27
 
28
28
  For the matching Ory side of the stack (Identities, Permissions, OAuth2, login
29
- UI, Jaeger), use {{REF_LOCAL_UP}}. The two stacks are independent — Temporal
29
+ UI), use {{REF_LOCAL_UP}}. The two stacks are independent — Temporal
30
30
  runs on `:7233/:8233`, Ory runs on `:4000` and friends — so they can run side
31
31
  by side without port conflicts.
32
32
 
@@ -399,7 +399,7 @@ right place:
399
399
  route, or in the browser Network tab, is an **app/config** issue — work the
400
400
  four contract items and the checks above.
401
401
  - **The agent plugin** governs *this coding session* — it authenticates the
402
- agent, checks Ory Permissions before each tool call, and writes trace spans. It
402
+ agent, checks Ory Permissions before each tool call, and writes activity events. It
403
403
  never serves your app's HTTP routes. Diagnose it with
404
404
  `{{NPX}} status` and the debug log (`ORY_AGENT_DEBUG=true`), **not** by looking
405
405
  at your app's auth pages.
@@ -38,6 +38,7 @@ After {{REF_LOCAL_UP}} completes:
38
38
  | Service | URL | Purpose |
39
39
  |---------------|----------------------------------|--------------------------------------|
40
40
  | Gateway | `http://localhost:4000` | Unified API (mirrors Ory Network) |
41
+ | Agent Security| `https://agents.console.ory:8080`| Canonical permission/delegation broker |
41
42
  | Kratos public | `http://localhost:4433` | Self-service flows (login, etc.) |
42
43
  | Kratos admin | `http://localhost:4434` | Identity & session admin |
43
44
  | Keto read | `http://localhost:4466` | Permission checks |
@@ -49,7 +50,7 @@ The seed step also produces:
49
50
 
50
51
  - Test identity: `agent@ory-local.dev`
51
52
  - A live session token (printed at the end of {{REF_LOCAL_UP}})
52
- - Permission tuples in the `AgentTools` namespace for common tool names
53
+ - Permission tuples in the `AgentTool` namespace for common tool names
53
54
  - An OAuth2 client (`ory-agent-plugins-local`, `client_credentials` grant)
54
55
 
55
56
  ## Step 1: Verify Docker is running
@@ -73,10 +74,13 @@ Tell the user to run {{REF_LOCAL_UP}}, or the equivalent shell command:
73
74
  ```
74
75
 
75
76
  Wait for the command to print "All services are running!" and the seed
76
- output. Capture two values from the output:
77
+ output. Configure these connection values:
77
78
 
78
79
  - `ORY_PROJECT_URL` (always `http://localhost:4000`)
79
- - `ORY_SESSION_TOKEN` (the seeded session token)
80
+ - `ORY_AGENT_SECURITY_URL` (`https://agents.console.ory:8080`; run the Agent Security service separately)
81
+ - `ORY_OAUTH2_CLIENT_ID` (the seeded PKCE login client)
82
+ - the seeded user's email + password, which you type into the login UI
83
+ when the browser opens
80
84
 
81
85
  If the user wants to skip seeding (to bring their own data), use
82
86
  `{{NPX}} local up --no-seed` instead.
@@ -134,14 +138,20 @@ Two ways to exercise the flows:
134
138
  with password `ory-agent-local-dev-password!` to test session-bearing
135
139
  pages without going through registration.
136
140
 
137
- For automated tests against the running stack, use the seeded session
138
- token directly:
141
+ For automated tests against the running stack, log in through Kratos to
142
+ get a session token and call the session API with it:
139
143
 
140
144
  ```bash
141
- curl -H "X-Session-Token: $ORY_SESSION_TOKEN" \
145
+ KRATOS_SESSION_TOKEN=$(...) # from a Kratos login flow
146
+ curl -H "X-Session-Token: $KRATOS_SESSION_TOKEN" \
142
147
  http://localhost:4000/sessions/whoami
143
148
  ```
144
149
 
150
+ That token is a **Kratos session token** — it authenticates the Kratos
151
+ session API only. It is not what the plugin uses: the plugin's env
152
+ credential (`ORY_USER_OAUTH2_TOKEN`) must be an OAuth2 access token,
153
+ because it authenticates delegation and can bootstrap the agent's OAuth2 client.
154
+
145
155
  ## Step 6: Iterate
146
156
 
147
157
  Common day-to-day commands:
@@ -191,7 +201,7 @@ plugin updates the bundled service configs.
191
201
  config change is needed. For non-localhost dev URLs, switch back to
192
202
  the Ory Tunnel + a Network project.
193
203
  - **Permission checks always deny** — the seeded tuples live in the
194
- `AgentTools` namespace. If your app uses a different namespace, set
204
+ `AgentTool` namespace. If your app uses a different namespace, set
195
205
  `ORY_PERMISSION_NAMESPACE` before `local seed`, or write the tuples
196
206
  manually via the Keto write API on `:4467`.
197
207
 
@@ -1,25 +1,22 @@
1
1
  ---
2
2
  name: ory-build-agent
3
- description: Build your own AI agent that authenticates the user, authorizes every tool call against Ory Permissions, and emits trace spans — by dropping `@ory/argus` directly into the Claude Agent SDK, OpenAI Agents SDK, Mastra, Vercel AI SDK, PydanticAI / LangGraph, or as an external service called by Salesforce Agentforce. Use when the user wants to wire Ory into a custom agent they own — phrases like "add Ory to my own agent", "build a custom agent with Ory auth", "wrap my Claude Agent SDK tools with Ory permissions", "OpenAI Agents SDK with Ory", "Mastra agent with Ory permissions", "Agentforce action with Ory", "use `@ory/argus` directly". For wiring Ory into an existing agent harness (Claude Code, Codex, Gemini CLI, OpenClaw, OpenCode) use the corresponding `@ory/<harness>` plugin instead.
3
+ description: Build your own AI agent that authenticates the user, authorizes every tool call against Ory Permissions, and records structured activity — by dropping `@ory/argus` directly into the Claude Agent SDK, OpenAI Agents SDK, Mastra, Vercel AI SDK, PydanticAI / LangGraph, or as an external service called by Salesforce Agentforce. Use when the user wants to wire Ory into a custom agent they own — phrases like "add Ory to my own agent", "build a custom agent with Ory auth", "wrap my Claude Agent SDK tools with Ory permissions", "OpenAI Agents SDK with Ory", "Mastra agent with Ory permissions", "Agentforce action with Ory", "use `@ory/argus` directly". For wiring Ory into an existing agent harness (Claude Code, Codex, Gemini CLI, OpenClaw, OpenCode) use the corresponding `@ory/<harness>` plugin instead.
4
4
  ---
5
5
 
6
6
  # Build your own agent with `@ory/argus`
7
7
 
8
- You are helping the user wire Ory Identities, Permissions, and tracing into
8
+ You are helping the user wire Ory Identities, Permissions, and activity auditing into
9
9
  **an agent they are building themselves**. They are not extending Claude Code,
10
10
  Codex, or one of the other harness plugins — they own the agent loop and
11
11
  choose where to intercept tool calls.
12
12
 
13
13
  The integration is the same three moves regardless of SDK:
14
14
 
15
- 1. **User gate at start.** `ensureUserAuthenticated(client, …)` the human at
16
- the keyboard becomes the subject of every permission check.
17
- 2. **Agent gate at start.** `ensureAgentIdentity(client, …)` the process
18
- making outbound Ory API calls gets its own credential (OAuth2 Dynamic
19
- Client Registration by default, persisted across sessions).
20
- 3. **Permission check on every tool call.** Wrap the SDK's tool dispatch with
21
- `checkAndDecide(client, …)` and branch on `decision.kind`. Record a
22
- `tool.complete` span after the tool returns.
15
+ 1. **Session start.** `sessionStart(client, …)` runs user and agent identity,
16
+ delegation, permission-mode warming, and fail-open handling.
17
+ 2. **Permission check on every tool call.** Wrap the SDK's tool dispatch with
18
+ `gate(client, …)` and translate `result.blocked` into the SDK's veto signal.
19
+ 3. **Completion.** Call `complete(client, …)` after the tool returns.
23
20
 
24
21
  `@ory/argus` ships every helper and handles fail-open semantics (network
25
22
  errors, rate limits, unconfigured project → allow). The SDKs differ only in
@@ -52,7 +49,7 @@ Also establish:
52
49
 
53
50
  - **Interactive vs headless.** Desktop / terminal agents can run PKCE login.
54
51
  Headless services (CI, daemons, Salesforce side-cars) must pre-supply
55
- `ORY_USER_SESSION_TOKEN` or `ORY_USER_OAUTH2_TOKEN`.
52
+ `ORY_USER_OAUTH2_TOKEN`.
56
53
  - **Which tools to gate.** Usually all of them. Some SDKs have built-in
57
54
  "safe" steps (an LLM-only reasoning step, a model-provided memory tool)
58
55
  that don't need a permission check.
@@ -70,7 +67,7 @@ That's the only Ory dependency you need. The Ory SDK clients
70
67
  (`@ory/client`) and the OAuth2/PKCE plumbing are re-exported and ready to
71
68
  use.
72
69
 
73
- ## Step 3 — Construct the client and run both gates
70
+ ## Step 3 — Construct the client and start the session
74
71
 
75
72
  Put this at the top of the agent's bootstrap, before the agent loop starts
76
73
  processing the first message:
@@ -78,40 +75,15 @@ processing the first message:
78
75
  ```ts
79
76
  import {
80
77
  OryAgentClient,
81
- ensureUserAuthenticated,
82
- ensureAgentIdentity,
83
- resolveConfig,
78
+ sessionStart,
84
79
  } from "@ory/argus";
85
80
 
86
81
  const client = OryAgentClient.fromEnv("my-agent");
87
- const { projectUrl } = resolveConfig();
88
-
89
- // 1. User gate — interactive PKCE; runs every session and never blocks.
90
- // Establishes the user identity for attribution; a declined/skipped login
91
- // is audited and the flow proceeds (enforcement is at the tool gate).
92
- await ensureUserAuthenticated(client, {
93
- binName: "my-agent",
94
- harness: "my-agent",
95
- });
96
-
97
- // 2. Agent gate — never blocks; resolves machine credentials (DCR by default).
98
- await ensureAgentIdentity(client, { projectUrl, harness: "my-agent" });
99
-
100
- // 3. (optional) write the user→agent delegation tuple for audit.
101
- if (client.userPrincipal.subject && client.agentPrincipal.subject) {
102
- await client
103
- .createRelationship({
104
- namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools",
105
- object: `agent:${client.agentPrincipal.subject}`,
106
- relation: "delegate",
107
- subjectId: `user:${client.userPrincipal.subject}`,
108
- })
109
- .catch(() => undefined); // audit-only — swallow failures
110
- }
82
+ await sessionStart(client, { harness: "my-agent" });
111
83
  ```
112
84
 
113
85
  The user gate runs on every session and is always non-blocking: it refreshes
114
- tokens, prompts on TTY, and emits the `user.auth` span, but always returns
86
+ tokens, prompts on TTY, and emits the `user.auth` activity event, but always returns
115
87
  `proceed: true`. A missing or declined login never stops the agent — the
116
88
  consequence surfaces at the tool gate, where `permissionMode: enforce` denies
117
89
  and `observe` audits.
@@ -123,48 +95,25 @@ Put it next to where you construct the client.
123
95
 
124
96
  ```ts
125
97
  import {
126
- checkAndDecide,
127
- resolveUserSubject,
128
- subjectLabel,
98
+ complete,
99
+ gate,
129
100
  } from "@ory/argus";
130
101
 
131
- async function gateTool(toolName: string, sessionId: string) {
132
- const subject = resolveUserSubject(client, `session:${sessionId}`);
133
- const decision = await checkAndDecide(
134
- client,
135
- {
136
- namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools",
137
- object: toolName,
138
- relation: "use",
139
- ...subject,
140
- },
141
- { spanAttributes: { toolName } }
142
- );
143
-
144
- switch (decision.kind) {
145
- case "allow":
146
- case "observe":
147
- case "fail_open":
148
- return { allow: true as const };
149
- case "deny":
150
- return {
151
- allow: false as const,
152
- message: `Ory denied ${toolName} for ${subjectLabel(subject)}.`,
153
- };
154
- }
102
+ async function gateTool(toolName: string, toolArgs?: unknown) {
103
+ const result = await gate(client, { harness: "my-agent", toolName, toolArgs });
104
+ return result.blocked
105
+ ? { allow: false as const, message: result.denialMessage }
106
+ : { allow: true as const };
155
107
  }
156
108
  ```
157
109
 
158
- After the tool finishes (whichever SDK), record a completion span:
110
+ After the tool finishes (whichever SDK), record completion activity:
159
111
 
160
112
  ```ts
161
- client.tracer.record("tool.complete", "ok", {
162
- attributes: { toolName, durationMs },
163
- });
113
+ complete(client, { toolName, output });
164
114
  ```
165
115
 
166
- `checkAndDecide` already records `permission.check`, `permission.observe_deny`
167
- (on observe), and `tool.block` (on deny). You only own `tool.complete`.
116
+ `gate` records permission and execution activity; `complete` records the terminal event.
168
117
 
169
118
  ## Step 5 — SDK-specific wiring
170
119
 
@@ -240,7 +189,7 @@ Agentforce is a declarative agent inside the Salesforce platform — you
240
189
  operations. The gate runs inside your Node service on every call; denies
241
190
  come back as tool errors the agent surfaces to the user.
242
191
 
243
- Pre-supply `ORY_USER_SESSION_TOKEN` (or `ORY_USER_OAUTH2_TOKEN`) to the
192
+ Pre-supply `ORY_USER_OAUTH2_TOKEN` to the
244
193
  side-car from a session the user established out-of-band — for example, a
245
194
  PKCE flow at sign-on into the Experience Cloud site that fronts the agent.
246
195
  A headless side-car cannot run PKCE on its own.
@@ -338,13 +287,11 @@ Pure-Python agents don't link `@ory/argus` directly. The two supported
338
287
  patterns:
339
288
 
340
289
  - **Side-car HTTP service.** Run a small Node process that exposes
341
- `POST /gate` (calls `gateTool`) and `POST /trace` (calls
342
- `client.tracer.record(...)`). Your Python agent calls these from inside
290
+ `POST /gate` (calls `gateTool`). Your Python agent calls it from inside
343
291
  each `@agent.tool`.
344
- - **Direct Ory APIs.** Use the official `ory-client` Python SDK to call
345
- `PermissionApi.check_permission()` and post audit spans to your own
346
- collector. You lose the fail-open / observe-mode helpers; re-implement
347
- them in Python.
292
+ - **Native Python integration.** Use `ory-argus`, which routes checks through
293
+ the canonical Agent Security broker and preserves the same fail-open,
294
+ observe/enforce, identity, and activity behavior as the TypeScript core.
348
295
 
349
296
  Side-car pattern:
350
297
 
@@ -402,21 +349,22 @@ The `gateTool` body does not change.
402
349
  ## Step 6 — Test against the local Ory stack
403
350
 
404
351
  Before pointing at production, run the gate against the local stack so the
405
- PKCE flow, permission tuples, and trace spans are all visible:
352
+ PKCE flow, permission tuples, and activity events are all visible:
406
353
 
407
354
  1. {{REF_LOCAL_UP}} — brings up Kratos / Keto / Hydra on `localhost:4000`
408
355
  and seeds a demo user. The banner prints the email + password.
409
356
  2. Export the env vars the launcher writes (`ORY_PROJECT_URL`,
410
- `ORY_OAUTH2_CLIENT_ID`, optional `ORY_AGENT_TRACE_FILE` for an NDJSON
411
- span log). The user login runs every session.
357
+ `ORY_OAUTH2_CLIENT_ID`, and optionally `ORY_AGENT_LOG_FILE` to override the
358
+ default unified NDJSON log). The user login runs every session.
412
359
  3. Start your agent. Confirm the browser opens for PKCE login.
413
- 4. Invoke a gated tool and `tail -f $ORY_AGENT_TRACE_FILE | jq .` — you
360
+ 4. Invoke a gated tool and tail `<dataDir>/<harness>/ory-agent-debug.log` with
361
+ `jq` — you
414
362
  should see `user.auth` → `agent.auth` → `permission.check` →
415
363
  `tool.complete` for every call.
416
- 5. Promote to enforce once the `use` tuples are seeded: either
417
- `ORY_PERMISSION_MODE=enforce` for one launch, or use one of the harness
418
- CLIs to flip it persistently (e.g. `npx -y -p @ory/claude-code ory-claude
419
- permissions enforce` same shared config file).
364
+ 5. Promote to enforce once the tools are granted. The posture is a
365
+ permission on the Ory project, read on every session an admin sets it
366
+ in the Ory Console (Agent Security); see the resolved value with
367
+ `... permissions` via any harness CLI (same shared config file).
420
368
  6. {{REF_LOCAL_DOWN}} when done. Volumes persist, so the seeded user
421
369
  survives across runs.
422
370
 
@@ -428,9 +376,9 @@ For full env-var coverage (including the user/agent split,
428
376
  - It does not generate the agent. The user owns the agent loop, tool
429
377
  catalog, and deployment shape. This skill only drops `@ory/argus` into
430
378
  whatever they already have.
431
- - It does not write the permission tuples. Seed them with
432
- `... permissions bootstrap` (run via any of the harness CLIs — same shared
433
- config file) or by calling `client.createRelationship` directly.
379
+ - It does not grant permissions. Those are provisioned in the Ory Console
380
+ (Agent Security); `@ory/argus` only reads them. Locally, the dev stack's
381
+ seed step grants the catalog for you.
434
382
  - It does not adapt one of the existing harness plugins (`@ory/claude-code`,
435
383
  `@ory/codex`, `@ory/gemini-cli`, `@ory/openclaw`, `@ory/opencode`). Those
436
384
  are for users running those harnesses — not building a custom agent.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ory-e2b-sandbox
3
- description: Scaffold an E2B (e2b.dev) sandbox template that boots with {{PKG}} preinstalled, so every Claude/Codex/Gemini/OpenClaw/OpenCode session running inside the sandbox is gated by Ory auth, permissions, and tracing without any per-sandbox setup. Use when the user asks to "create an E2B sandbox with Ory agent security", "build an E2B template with the Ory plugin", "make an E2B image that includes Ory auth", or any close variant. The skill generates the template files in the user's project — it does not deploy them.
3
+ description: Scaffold an E2B (e2b.dev) sandbox template that boots with {{PKG}} preinstalled, so every Claude/Codex/Gemini/OpenClaw/OpenCode session running inside the sandbox is gated by Ory auth and permissions and records structured activity without any per-sandbox setup. Use when the user asks to "create an E2B sandbox with Ory agent security", "build an E2B template with the Ory plugin", "make an E2B image that includes Ory auth", or any close variant. The skill generates the template files in the user's project — it does not deploy them.
4
4
  ---
5
5
 
6
6
  # E2B sandbox with Ory agent security
@@ -9,8 +9,8 @@ You are helping the user scaffold an [E2B](https://e2b.dev) sandbox template
9
9
  that preinstalls and registers the {{PKG}} plugin. The resulting template
10
10
  publishes a named image; every `Sandbox.create("<tag>")` call from their SDK
11
11
  gets a runtime where the agent's tool calls are already authenticated against
12
- Ory Identities, authorized against Ory Permissions, and emitted as trace
13
- spans — with **no** install step at sandbox boot.
12
+ Ory Identities, authorized against Ory Permissions, and recorded as structured
13
+ activity events — with **no** install step at sandbox boot.
14
14
 
15
15
  This skill carries the full workflow and the file contents. You generate the
16
16
  files in the user's repo; the user runs the build.
@@ -66,8 +66,7 @@ export const template = Template()
66
66
  // Sandbox runtime defaults. Per-tenant secrets (project URL, tokens, client
67
67
  // IDs) MUST be passed at Sandbox.create() time, never baked into the image.
68
68
  .setEnvs({
69
- ORY_PERMISSION_MODE: "observe",
70
- ORY_PERMISSION_NAMESPACE: "AgentTools",
69
+ ORY_PERMISSION_NAMESPACE: "AgentTool",
71
70
  ORY_AGENT_DEBUG: "true",
72
71
  ORY_AGENT_LOG_FILE: "/root/ory-agent-debug.log",
73
72
  })
@@ -114,9 +113,10 @@ E2B_API_KEY=e2b_***
114
113
  # the template. Listed here so operators know what to plumb through.
115
114
  ORY_PROJECT_URL=https://<slug>.projects.oryapis.com
116
115
  ORY_OAUTH2_CLIENT_ID=
117
- ORY_USER_SESSION_TOKEN=
116
+ ORY_USER_OAUTH2_TOKEN=
118
117
  # Optional: pin a static agent identity instead of DCR.
119
- # ORY_AGENT_API_KEY=
118
+ # ORY_AGENT_CLIENT_ID=
119
+ # ORY_AGENT_CLIENT_SECRET=
120
120
  ```
121
121
 
122
122
  ### `integrations/e2b/package.json`
@@ -152,8 +152,8 @@ Generate a README that captures:
152
152
  `npm run build:prod`.
153
153
  - A `Sandbox.create("agent-ory", { envs: { ... } })` example showing which env
154
154
  vars to inject at runtime (`ORY_PROJECT_URL`, `ORY_OAUTH2_CLIENT_ID`,
155
- `ORY_USER_SESSION_TOKEN` or `ORY_USER_OAUTH2_TOKEN`, optional
156
- `ORY_AGENT_API_KEY`).
155
+ `ORY_USER_OAUTH2_TOKEN`, optional
156
+ `ORY_AGENT_CLIENT_ID` + `ORY_AGENT_CLIENT_SECRET`).
157
157
  - A pointer to {{REF_AUTH_SETUP}} for full env-var coverage and to
158
158
  {{REF_LOCAL_DEV}} for testing the same plugin locally before publishing the
159
159
  template.
@@ -189,7 +189,7 @@ const sbx = await Sandbox.create("agent-ory", {
189
189
  ORY_PROJECT_URL: process.env.ORY_PROJECT_URL!,
190
190
  ORY_OAUTH2_CLIENT_ID: process.env.ORY_OAUTH2_CLIENT_ID!,
191
191
  // Pre-supply a user token so the headless sandbox skips PKCE.
192
- ORY_USER_SESSION_TOKEN: process.env.ORY_USER_SESSION_TOKEN!,
192
+ ORY_USER_OAUTH2_TOKEN: process.env.ORY_USER_OAUTH2_TOKEN!,
193
193
  },
194
194
  });
195
195
 
@@ -197,18 +197,19 @@ await sbx.commands.run("{{BIN}} --version"); // sanity check
197
197
  ```
198
198
 
199
199
  Sandboxes are headless, so the user **must** pre-supply
200
- `ORY_USER_SESSION_TOKEN` or `ORY_USER_OAUTH2_TOKEN` — otherwise user login's
200
+ `ORY_USER_OAUTH2_TOKEN` — otherwise user login's
201
201
  PKCE browser flow has no target and hangs. See {{REF_AUTH_SETUP}} for the full
202
202
  env-var matrix.
203
203
 
204
204
  ## Step 5 — Promotion path
205
205
 
206
- The template ships with `ORY_PERMISSION_MODE=observe` baked in so first-run
207
- sandboxes never block. To promote a sandbox to hard enforcement without
208
- rebuilding the template, either pass `ORY_PERMISSION_MODE=enforce` at
209
- `Sandbox.create()` time, or run `{{NPX}} permissions enforce` inside a running
210
- sandbox. Run `{{NPX}} permissions bootstrap` first on a fresh Ory project so
211
- the `use` tuples exist before enforcement turns on.
206
+ A sandbox starts in observe mode, so first-run sandboxes never block. The
207
+ deny posture is a property of the **Ory project**, read on every session: an
208
+ admin promotes it to `enforce` in the Ory Console (Agent Security), project-wide
209
+ or for a single principal, and running sandboxes pick that up without a rebuild.
210
+ Grant `use` on the tools first, also in the Console otherwise flipping to
211
+ enforce blocks everything. Check what a sandbox resolves with
212
+ `{{NPX}} permissions`.
212
213
 
213
214
  ## What this skill does NOT do
214
215