# Ory Argus: Agent and Developer Experience

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.

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.

## Use

```typescript
import { OryAgentClient, resolveUserSubject } from "@ory/argus";

const client = OryAgentClient.fromEnv("my-harness");

const session = await client.verifySession(sessionToken);

// Every principal is addressed as a SubjectSet (`User:<id>` by default,
// `Session:<id>` for the fallback). resolveUserSubject builds the right shape.
const result = await client.checkPermission({
  namespace: "AgentTool",
  object: "Bash",
  relation: "use",
  ...resolveUserSubject(client, `session:${sessionId}`),
});

if (!result.allowed) {
  // block the tool call (or fail-open on result.error)
}
```

`fromEnv()` returns a working client even when `ORY_PROJECT_URL` is unset; calls fail with `network_error` and the fail-open path handles them.

## Build a new plugin, extension, or custom integration

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:

```typescript
import {
  complete,
  gate,
  OryAgentClient,
  sessionStart,
  withHookContext,
} from "@ory/argus";

const client = OryAgentClient.fromEnv("my-harness");

// 1. Session start: authenticate the human and the agent process.
async function onSessionStart() {
  await sessionStart(client, { harness: "my-harness" });
}

// 2. Before each tool call: check Ory Permissions; block on `deny`.
async function onBeforeTool(toolName: string, args: unknown, sessionId: string) {
  return withHookContext(client, { sessionId }, async () => {
    const result = await gate(client, { harness: "my-harness", toolName, toolArgs: args });
    return result.blocked ? { block: true, reason: result.denialMessage } : {};
  });
}

// 3. After each tool call: record structured completion activity.
async function onAfterTool(toolName: string, output: unknown) {
  complete(client, { toolName, output });
}
```

Map the host SDK's or harness's hook names onto those three calls and you get the same identity, policy, and audit story as every published plugin in this repo. Subprocess hosts can additionally block via exit codes; in-process hosts can return decision objects directly.

## Surface

### `OryAgentClient`

The wrapped Ory client. One instance per harness session.

| Group | Members |
|---|---|
| Sessions and tokens | `verifySession`, `introspectToken`, `classifyError` |
| Permission checks | `checkPermission`, `batchCheckPermissions`, `checkMcpPermission` |
| Principals (who is acting) | `setUserPrincipal`, `setAgentPrincipal` |
| Delegation | `recordDelegation` (via the Ory Agent Security broker — the only write path; Keto is read-only here) |
| Activity and debug | `logger` (see Logger below) |

### Identity gates

Resolve the user and agent identities at session start. Non-blocking by default; opt in to hard blocking on the user gate where the host can carry an exit-style decision.

| Helper | Purpose |
|---|---|
| `ensureUserAuthenticated` | Interactive PKCE login, token refresh, or env-token short-circuit |
| `ensureAgentIdentity` | Injected/Talos runtime authentication with OS-store persistence and session-start enrollment |
| `ensureSubAgentIdentity` | Spawn-scoped child Talos identity issued through the authenticated parent |
| `resolveUserSubject`, `subjectLabel` | Subject resolution and printable labels for activity and denial messages |

### Logger

- `DebugLogger`: recursively redacted structured activity plus verbose diagnostics in one NDJSON stream
- Privacy-safe activity always persists to `<dataDir>/<harness>/ory-agent-debug.log` by default
- `ORY_AGENT_LOG_FILE` overrides the path; an empty value disables persistence
- `ORY_AGENT_DEBUG=true` adds the complete live JSON stream to stderr and verbose local diagnostics, including raw shell commands
- `runWatchCommand` follows the unified log with human-readable event, decision, and error context or raw NDJSON
- Ory Agent Security owns service telemetry; Argus has no OTel exporter or trace-context surface

### Skill and command catalog

Materialize the canonical `SKILL.md` templates into each harness's native skill or command format.

| Helper | Purpose |
|---|---|
| `renderOrySkills`, `renderOryCommands` | Substitute template tokens (binary name, package name, reference style) |
| `commandToSkill`, `commandToToml`, `commandToFrontmatterMarkdown`, `commandToPlainMarkdown` | Format per harness |
| `writeSkillTree`, `removeSkillDirs` | Materialize on install, clean up on uninstall |

### CLI and dev tooling

- Shared CLI handlers used by every plugin's CLI: `configure`, `status`, `local`, `setup`
- Local-stack manager: brings up a local Ory instance in Docker Compose
- Verdaccio registry manager: builds and publishes the workspace for local product development

## License

Apache-2.0
