@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
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,45 +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
- await ensureUserAuthenticated(client, {
46
- binName: "my-harness",
47
- harness: "my-harness",
48
- allowBlock: true,
49
- });
50
- await ensureAgentIdentity(client, {
51
- projectUrl: process.env.ORY_PROJECT_URL,
52
- });
49
+ await sessionStart(client, { harness: "my-harness" });
53
50
  }
54
51
 
55
52
  // 2. Before each tool call: check Ory Permissions; block on `deny`.
56
- async function onBeforeTool(toolName: string, sessionId: string) {
57
- const result = await client.checkPermission({
58
- namespace: "AgentTools",
59
- object: toolName,
60
- relation: "use",
61
- 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 } : {};
62
57
  });
63
- if (result.allowed === false) {
64
- return { block: true, reason: result.reason };
65
- }
66
58
  }
67
59
 
68
- // 3. After each tool call: record a structured trace span.
69
- async function onAfterTool(toolName: string, durationMs: number) {
70
- 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 });
71
63
  }
72
64
  ```
73
65
 
@@ -84,8 +76,8 @@ The wrapped Ory client. One instance per harness session.
84
76
  | Sessions and tokens | `verifySession`, `introspectToken`, `classifyError` |
85
77
  | Permission checks | `checkPermission`, `batchCheckPermissions`, `checkMcpPermission` |
86
78
  | Principals (who is acting) | `setUserPrincipal`, `setAgentPrincipal` |
87
- | Delegation relations | `createRelationship`, `deleteRelationship` |
88
- | 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) |
89
81
 
90
82
  ### Identity gates
91
83
 
@@ -94,23 +86,18 @@ Resolve the user and agent identities at session start. Non-blocking by default;
94
86
  | Helper | Purpose |
95
87
  |---|---|
96
88
  | `ensureUserAuthenticated` | Interactive PKCE login, token refresh, or env-token short-circuit |
97
- | `ensureAgentIdentity` | OAuth2 dynamic client registration with persisted credentials |
98
- | `ensureSubAgentIdentity` | Per-sub-agent identity for harnesses that fan out |
99
- | `resolveUserSubject`, `subjectLabel` | Subject resolution and printable labels for spans and denial messages |
100
-
101
- ### Tracer
102
-
103
- `Tracer` is exposed as `client.tracer`. Records every decision as a structured span.
104
-
105
- - `record(event, attrs)`: emit a span
106
- - `EventEmitter` `"span"` events for live observers
107
- - NDJSON file output
108
- - 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 |
109
92
 
110
93
  ### Logger
111
94
 
112
- - `DebugLogger`: structured JSON to stderr plus optional log file
113
- - 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
114
101
 
115
102
  ### Skill and command catalog
116
103
 
@@ -125,9 +112,8 @@ Materialize the canonical `SKILL.md` templates into each harness's native skill
125
112
  ### CLI and dev tooling
126
113
 
127
114
  - Shared CLI handlers used by every plugin's CLI: `configure`, `status`, `local`, `setup`
128
- - `runDevLauncher(...)`: the dev-launcher pipeline used by every plugin
129
115
  - Local-stack manager: brings up a local Ory instance in Docker Compose
130
- - Verdaccio registry manager: a local npm registry for dev launchers
116
+ - Verdaccio registry manager: builds and publishes the workspace for local product development
131
117
 
132
118
  ## License
133
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,45 +75,18 @@ 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 when ORY_USER_LOGIN=true, no-op otherwise.
90
- const userDecision = await ensureUserAuthenticated(client, {
91
- binName: "my-agent",
92
- harness: "my-agent",
93
- allowBlock: true, // flip to false if your agent can't refuse to start
94
- });
95
- if (userDecision.proceed === false) {
96
- console.error(`Ory user login: ${userDecision.reason}`);
97
- process.exit(2);
98
- }
99
-
100
- // 2. Agent gate — never blocks; resolves machine credentials (DCR by default).
101
- await ensureAgentIdentity(client, { projectUrl, harness: "my-agent" });
102
-
103
- // 3. (optional) write the user→agent delegation tuple for audit.
104
- if (client.userPrincipal.subject && client.agentPrincipal.subject) {
105
- await client
106
- .createRelationship({
107
- namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools",
108
- object: `agent:${client.agentPrincipal.subject}`,
109
- relation: "delegate",
110
- subjectId: `user:${client.userPrincipal.subject}`,
111
- })
112
- .catch(() => undefined); // audit-only — swallow failures
113
- }
82
+ await sessionStart(client, { harness: "my-agent" });
114
83
  ```
115
84
 
116
- Set `allowBlock: false` when the agent runs in-process inside a parent
117
- application and can't refuse to start. The gate still runs in advisory mode
118
- it refreshes tokens, prompts on TTY, emits the `user.auth` span but
119
- always returns `proceed: true`.
85
+ The user gate runs on every session and is always non-blocking: it refreshes
86
+ tokens, prompts on TTY, and emits the `user.auth` activity event, but always returns
87
+ `proceed: true`. A missing or declined login never stops the agentthe
88
+ consequence surfaces at the tool gate, where `permissionMode: enforce` denies
89
+ and `observe` audits.
120
90
 
121
91
  ## Step 4 — The shared gate body
122
92
 
@@ -125,48 +95,25 @@ Put it next to where you construct the client.
125
95
 
126
96
  ```ts
127
97
  import {
128
- checkAndDecide,
129
- resolveUserSubject,
130
- subjectLabel,
98
+ complete,
99
+ gate,
131
100
  } from "@ory/argus";
132
101
 
133
- async function gateTool(toolName: string, sessionId: string) {
134
- const subject = resolveUserSubject(client, `session:${sessionId}`);
135
- const decision = await checkAndDecide(
136
- client,
137
- {
138
- namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools",
139
- object: toolName,
140
- relation: "use",
141
- ...subject,
142
- },
143
- { spanAttributes: { toolName } }
144
- );
145
-
146
- switch (decision.kind) {
147
- case "allow":
148
- case "observe":
149
- case "fail_open":
150
- return { allow: true as const };
151
- case "deny":
152
- return {
153
- allow: false as const,
154
- message: `Ory denied ${toolName} for ${subjectLabel(subject)}.`,
155
- };
156
- }
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 };
157
107
  }
158
108
  ```
159
109
 
160
- After the tool finishes (whichever SDK), record a completion span:
110
+ After the tool finishes (whichever SDK), record completion activity:
161
111
 
162
112
  ```ts
163
- client.tracer.record("tool.complete", "ok", {
164
- attributes: { toolName, durationMs },
165
- });
113
+ complete(client, { toolName, output });
166
114
  ```
167
115
 
168
- `checkAndDecide` already records `permission.check`, `permission.observe_deny`
169
- (on observe), and `tool.block` (on deny). You only own `tool.complete`.
116
+ `gate` records permission and execution activity; `complete` records the terminal event.
170
117
 
171
118
  ## Step 5 — SDK-specific wiring
172
119
 
@@ -242,7 +189,7 @@ Agentforce is a declarative agent inside the Salesforce platform — you
242
189
  operations. The gate runs inside your Node service on every call; denies
243
190
  come back as tool errors the agent surfaces to the user.
244
191
 
245
- Pre-supply `ORY_USER_SESSION_TOKEN` (or `ORY_USER_OAUTH2_TOKEN`) to the
192
+ Pre-supply `ORY_USER_OAUTH2_TOKEN` to the
246
193
  side-car from a session the user established out-of-band — for example, a
247
194
  PKCE flow at sign-on into the Experience Cloud site that fronts the agent.
248
195
  A headless side-car cannot run PKCE on its own.
@@ -340,13 +287,11 @@ Pure-Python agents don't link `@ory/argus` directly. The two supported
340
287
  patterns:
341
288
 
342
289
  - **Side-car HTTP service.** Run a small Node process that exposes
343
- `POST /gate` (calls `gateTool`) and `POST /trace` (calls
344
- `client.tracer.record(...)`). Your Python agent calls these from inside
290
+ `POST /gate` (calls `gateTool`). Your Python agent calls it from inside
345
291
  each `@agent.tool`.
346
- - **Direct Ory APIs.** Use the official `ory-client` Python SDK to call
347
- `PermissionApi.check_permission()` and post audit spans to your own
348
- collector. You lose the fail-open / observe-mode helpers; re-implement
349
- 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.
350
295
 
351
296
  Side-car pattern:
352
297
 
@@ -404,21 +349,22 @@ The `gateTool` body does not change.
404
349
  ## Step 6 — Test against the local Ory stack
405
350
 
406
351
  Before pointing at production, run the gate against the local stack so the
407
- PKCE flow, permission tuples, and trace spans are all visible:
352
+ PKCE flow, permission tuples, and activity events are all visible:
408
353
 
409
354
  1. {{REF_LOCAL_UP}} — brings up Kratos / Keto / Hydra on `localhost:4000`
410
355
  and seeds a demo user. The banner prints the email + password.
411
356
  2. Export the env vars the launcher writes (`ORY_PROJECT_URL`,
412
- `ORY_USER_LOGIN=true`, `ORY_OAUTH2_CLIENT_ID`, optional
413
- `ORY_AGENT_TRACE_FILE` for an NDJSON span log).
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.
414
359
  3. Start your agent. Confirm the browser opens for PKCE login.
415
- 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
416
362
  should see `user.auth` → `agent.auth` → `permission.check` →
417
363
  `tool.complete` for every call.
418
- 5. Promote to enforce once the `use` tuples are seeded: either
419
- `ORY_PERMISSION_MODE=enforce` for one launch, or use one of the harness
420
- CLIs to flip it persistently (e.g. `npx -y -p @ory/claude-code ory-claude
421
- 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).
422
368
  6. {{REF_LOCAL_DOWN}} when done. Volumes persist, so the seeded user
423
369
  survives across runs.
424
370
 
@@ -430,9 +376,9 @@ For full env-var coverage (including the user/agent split,
430
376
  - It does not generate the agent. The user owns the agent loop, tool
431
377
  catalog, and deployment shape. This skill only drops `@ory/argus` into
432
378
  whatever they already have.
433
- - It does not write the permission tuples. Seed them with
434
- `... permissions bootstrap` (run via any of the harness CLIs — same shared
435
- 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.
436
382
  - It does not adapt one of the existing harness plugins (`@ory/claude-code`,
437
383
  `@ory/codex`, `@ory/gemini-cli`, `@ory/openclaw`, `@ory/opencode`). Those
438
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,9 +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_USER_LOGIN: "true",
70
- ORY_PERMISSION_MODE: "observe",
71
- ORY_PERMISSION_NAMESPACE: "AgentTools",
69
+ ORY_PERMISSION_NAMESPACE: "AgentTool",
72
70
  ORY_AGENT_DEBUG: "true",
73
71
  ORY_AGENT_LOG_FILE: "/root/ory-agent-debug.log",
74
72
  })
@@ -115,9 +113,10 @@ E2B_API_KEY=e2b_***
115
113
  # the template. Listed here so operators know what to plumb through.
116
114
  ORY_PROJECT_URL=https://<slug>.projects.oryapis.com
117
115
  ORY_OAUTH2_CLIENT_ID=
118
- ORY_USER_SESSION_TOKEN=
116
+ ORY_USER_OAUTH2_TOKEN=
119
117
  # Optional: pin a static agent identity instead of DCR.
120
- # ORY_AGENT_API_KEY=
118
+ # ORY_AGENT_CLIENT_ID=
119
+ # ORY_AGENT_CLIENT_SECRET=
121
120
  ```
122
121
 
123
122
  ### `integrations/e2b/package.json`
@@ -153,8 +152,8 @@ Generate a README that captures:
153
152
  `npm run build:prod`.
154
153
  - A `Sandbox.create("agent-ory", { envs: { ... } })` example showing which env
155
154
  vars to inject at runtime (`ORY_PROJECT_URL`, `ORY_OAUTH2_CLIENT_ID`,
156
- `ORY_USER_SESSION_TOKEN` or `ORY_USER_OAUTH2_TOKEN`, optional
157
- `ORY_AGENT_API_KEY`).
155
+ `ORY_USER_OAUTH2_TOKEN`, optional
156
+ `ORY_AGENT_CLIENT_ID` + `ORY_AGENT_CLIENT_SECRET`).
158
157
  - A pointer to {{REF_AUTH_SETUP}} for full env-var coverage and to
159
158
  {{REF_LOCAL_DEV}} for testing the same plugin locally before publishing the
160
159
  template.
@@ -190,7 +189,7 @@ const sbx = await Sandbox.create("agent-ory", {
190
189
  ORY_PROJECT_URL: process.env.ORY_PROJECT_URL!,
191
190
  ORY_OAUTH2_CLIENT_ID: process.env.ORY_OAUTH2_CLIENT_ID!,
192
191
  // Pre-supply a user token so the headless sandbox skips PKCE.
193
- ORY_USER_SESSION_TOKEN: process.env.ORY_USER_SESSION_TOKEN!,
192
+ ORY_USER_OAUTH2_TOKEN: process.env.ORY_USER_OAUTH2_TOKEN!,
194
193
  },
195
194
  });
196
195
 
@@ -198,18 +197,19 @@ await sbx.commands.run("{{BIN}} --version"); // sanity check
198
197
  ```
199
198
 
200
199
  Sandboxes are headless, so the user **must** pre-supply
201
- `ORY_USER_SESSION_TOKEN` or `ORY_USER_OAUTH2_TOKEN` — otherwise user login's
200
+ `ORY_USER_OAUTH2_TOKEN` — otherwise user login's
202
201
  PKCE browser flow has no target and hangs. See {{REF_AUTH_SETUP}} for the full
203
202
  env-var matrix.
204
203
 
205
204
  ## Step 5 — Promotion path
206
205
 
207
- The template ships with `ORY_PERMISSION_MODE=observe` baked in so first-run
208
- sandboxes never block. To promote a sandbox to hard enforcement without
209
- rebuilding the template, either pass `ORY_PERMISSION_MODE=enforce` at
210
- `Sandbox.create()` time, or run `{{NPX}} permissions enforce` inside a running
211
- sandbox. Run `{{NPX}} permissions bootstrap` first on a fresh Ory project so
212
- 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`.
213
213
 
214
214
  ## What this skill does NOT do
215
215