# Agent: MITM Rules

**Page:** api/agent/mitm

[Download Raw Markdown](./api/agent/mitm.md)

---

{/* AUTO-GENERATED — Do not edit manually. Regenerate with: npm run docs:api:generate */}



The Agent MITM API lets you inspect and manage the request/response interception rules that apply to your own workspace. Use these endpoints to read the effective state, manage overlay rules and tags, observe firings via logs and a live SSE event stream, run rule-match diagnostics, and verify webhook targets before saving a rule.


All endpoints are scoped to the caller's own workspace. The overlay is a per-workspace layer on top of the base config (typically `hoody.json`); changes to the overlay do not modify the base config on disk.


## Snapshot

### `GET /api/v1/workspaces/{workspaceID}/mitm/snapshot`

Returns the composed effective state — base config + overlay + transient enables — that the firing path uses. Includes the version triple (`configEpoch`, `overlayRevision`, `transientEpoch`), the rule list with `effectiveEnabled`, `source`, and `overlayState`, and the effective tag catalog.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```json
{
  "scope": "ws_abc123",
  "rules": [
    {
      "id": "block-dangerous-rm",
      "name": "Block dangerous rm -rf",
      "enabled": true,
      "description": "Prevents accidental recursive deletion",
      "severity": "critical",
      "trigger": {
        "event": "tool.execute.before",
        "tags": ["destructive"],
        "toolName": "Bash"
      },
      "action": {
        "type": "message",
        "content": "Refusing to run rm -rf on this project."
      },
      "cooldownMs": 0,
      "maxDepth": 1,
      "blocking": true,
      "effectiveEnabled": true,
      "source": "base",
      "overlayState": "active"
    }
  ],
  "tags": [
    {
      "id": "destructive",
      "label": "Destructive",
      "description": "Operations that mutate or delete user data",
      "color": "red"
    }
  ],
  "version": {
    "configEpoch": 12,
    "overlayRevision": 3,
    "transientEpoch": 0
  },
  "builtAt": 1730000000000,
  "processEpoch": 7
}
```



**SDK**

```ts
const snapshot = await client.agent.workspaceMitmSnapshot.getWorkspaceMitmSnapshot({
  workspaceID: "ws_abc123",
});
```

## Rules

### `GET /api/v1/workspaces/{workspaceID}/mitm/rules`

Returns the list of effective rules, including overlay provenance (`source`) and the `effectiveEnabled` flag (which reflects any overlay `enabledOverride` and any transient override).

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```json
[
  {
    "id": "block-dangerous-rm",
    "name": "Block dangerous rm -rf",
    "enabled": true,
    "severity": "critical",
    "trigger": {
      "event": "tool.execute.before",
      "tags": ["destructive"],
      "toolName": "Bash"
    },
    "action": {
      "type": "message",
      "content": "Refusing to run rm -rf on this project."
    },
    "cooldownMs": 0,
    "maxDepth": 1,
    "blocking": true,
    "effectiveEnabled": true,
    "source": "base",
    "overlayState": "active"
  },
  {
    "id": "inject-safety-prompt",
    "name": "Inject safety prompt",
    "enabled": true,
    "severity": "info",
    "trigger": {
      "event": "chat.system.transform"
    },
    "action": {
      "type": "prompt-inject",
      "content": "Always confirm before running shell commands.",
      "position": "prepend",
      "target": "system"
    },
    "cooldownMs": 60000,
    "maxDepth": 1,
    "blocking": false,
    "effectiveEnabled": false,
    "source": "overlay",
    "overlayState": "active"
  }
]
```



**SDK**

```ts
const rules = await client.agent.workspaceMitmRules.listWorkspaceMitmRules({
  workspaceID: "ws_abc123",
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/rules`

Adds a new rule to the overlay. The base config (e.g. `hoody.json`) is not modified. The new overlay revision is returned in the `ETag` header.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | Unique rule identifier |
| `name` | string | Yes | Human-readable rule name |
| `enabled` | boolean | No | Whether the rule is enabled (Default: `true`) |
| `description` | string | No | Free-form description |
| `severity` | string | No | One of `info`, `warn`, `error`, `critical` |
| `trigger` | object | Yes | Trigger configuration; `event` is required |
| `action` | object | Yes | One of: `shell`, `message`, `prompt-inject`, `webhook`, `notification` |
| `cooldownMs` | number | No | Per-(rule,session) cooldown (Default: `0`) |
| `maxDepth` | number | No | Max recursion depth (Default: `1`) |
| `blocking` | boolean | No | Block the underlying call when matched (Default: `false`) |



```json
{
  "id": "notify-on-write",
  "name": "Notify on file write",
  "description": "Logs every file write to the workspace channel",
  "severity": "info",
  "trigger": {
    "event": "tool.execute.before",
    "toolName": "Write"
  },
  "action": {
    "type": "notification",
    "title": "File write",
    "body": "Tool Write is about to run."
  },
  "cooldownMs": 0,
  "maxDepth": 1,
  "blocking": false
}
```


```json
{
  "id": "notify-on-write",
  "name": "Notify on file write",
  "enabled": true,
  "description": "Logs every file write to the workspace channel",
  "severity": "info",
  "trigger": {
    "event": "tool.execute.before",
    "tags": [],
    "toolName": "Write"
  },
  "action": {
    "type": "notification",
    "title": "File write",
    "body": "Tool Write is about to run."
  },
  "cooldownMs": 0,
  "maxDepth": 1,
  "blocking": false
}
```


```json
{
  "error": "Rule with this id already exists in overlay",
  "code": "rule_already_exists"
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "Validation failed: trigger.event is required"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.workspaceMitmRule.createWorkspaceMitmRule({
  workspaceID: "ws_abc123",
  data: {
    id: "notify-on-write",
    name: "Notify on file write",
    severity: "info",
    trigger: { event: "tool.execute.before", toolName: "Write" },
    action: {
      type: "notification",
      title: "File write",
      body: "Tool Write is about to run.",
    },
  },
});
```

### `PUT /api/v1/workspaces/{workspaceID}/mitm/rules/{id}`

Replaces the rule at `:id` in the overlay with the request body. If `:id` refers to a base-config rule, the overlay records a full overlay patch (with `baseContentHash` for stale detection on subsequent rebase).

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Rule identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | Must equal the path `:id` |
| `name` | string | Yes | Human-readable rule name |
| `enabled` | boolean | No | Whether the rule is enabled (Default: `true`) |
| `description` | string | No | Free-form description |
| `severity` | string | No | One of `info`, `warn`, `error`, `critical` |
| `trigger` | object | Yes | Trigger configuration; `event` is required |
| `action` | object | Yes | One of: `shell`, `message`, `prompt-inject`, `webhook`, `notification` |
| `cooldownMs` | number | No | Per-(rule,session) cooldown (Default: `0`) |
| `maxDepth` | number | No | Max recursion depth (Default: `1`) |
| `blocking` | boolean | No | Block the underlying call when matched (Default: `false`) |



```json
{
  "id": "notify-on-write",
  "name": "Notify on file write (updated)",
  "description": "Logs file writes and shell commands",
  "severity": "warn",
  "trigger": {
    "event": "tool.execute.before",
    "toolName": "Write"
  },
  "action": {
    "type": "notification",
    "title": "File write",
    "body": "Tool Write is about to run."
  },
  "cooldownMs": 0,
  "maxDepth": 1,
  "blocking": false
}
```


```json
{
  "id": "notify-on-write",
  "name": "Notify on file write (updated)",
  "enabled": true,
  "description": "Logs file writes and shell commands",
  "severity": "warn",
  "trigger": {
    "event": "tool.execute.before",
    "tags": [],
    "toolName": "Write"
  },
  "action": {
    "type": "notification",
    "title": "File write",
    "body": "Tool Write is about to run."
  },
  "cooldownMs": 0,
  "maxDepth": 1,
  "blocking": false
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "Validation failed: trigger.event is required"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.rules.replaceWorkspaceMitmRule({
  workspaceID: "ws_abc123",
  id: "notify-on-write",
  data: {
    id: "notify-on-write",
    name: "Notify on file write (updated)",
    severity: "warn",
    trigger: { event: "tool.execute.before", toolName: "Write" },
    action: {
      type: "notification",
      title: "File write",
      body: "Tool Write is about to run.",
    },
  },
});
```

### `PATCH /api/v1/workspaces/{workspaceID}/mitm/rules/{id}`

Applies a shallow-merge patch to the overlay rule at `:id`. Pass `null` explicitly to delete a field on merge (the schema accepts `nullable().optional()` on every property).

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Rule identifier |

### Request Body

This endpoint accepts a partial rule object. Any field listed in the rule schema may be supplied. Set a field to `null` to remove it from the merged result.



```json
{
  "name": "Notify on file write (v2)",
  "severity": "warn",
  "description": null
}
```


```json
{
  "id": "notify-on-write",
  "name": "Notify on file write (v2)",
  "enabled": true,
  "severity": "warn",
  "trigger": {
    "event": "tool.execute.before",
    "tags": [],
    "toolName": "Write"
  },
  "action": {
    "type": "notification",
    "title": "File write",
    "body": "Tool Write is about to run."
  },
  "cooldownMs": 0,
  "maxDepth": 1,
  "blocking": false
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "Validation failed: severity must be one of info, warn, error, critical"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.workspaceMitmRule.patchWorkspaceMitmRule({
  workspaceID: "ws_abc123",
  id: "notify-on-write",
  data: {
    name: "Notify on file write (v2)",
    severity: "warn",
    description: null,
  },
});
```

### `DELETE /api/v1/workspaces/{workspaceID}/mitm/rules/{id}`

Removes the rule at `:id` from the overlay. If `:id` refers to a base-config rule, the overlay records a deletion tombstone so the rule is omitted from the effective state.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Rule identifier |

This endpoint accepts no body.



```json
{
  "description": "Deleted"
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.workspaceMitmRule.deleteWorkspaceMitmRule({
  workspaceID: "ws_abc123",
  id: "notify-on-write",
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/rules/{id}/enable`

Records an `enabledOverride` on the overlay so the rule's effective enabled state flips, without rewriting any other fields. Persists across restart.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Rule identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `enabled` | boolean | Yes | The new effective enabled state |



```json
{
  "enabled": false
}
```


```json
{
  "description": "Override recorded"
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.enable.setWorkspaceMitmRuleEnabled({
  workspaceID: "ws_abc123",
  id: "notify-on-write",
  data: { enabled: false },
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/rules/{id}/transient-enable`

Volatile per-process enable/disable. Does NOT persist across restart. Bumps `transientEpoch` and triggers a snapshot rebuild. Useful for short-lived A/B testing or temporary disables.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Rule identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `enabled` | boolean | Yes | The new effective enabled state |
| `ttlMs` | integer | No | Time-to-live in milliseconds (Default: `300000`, minimum `1000`, maximum `86400000`) |



```json
{
  "enabled": false,
  "ttlMs": 60000
}
```


```json
{
  "description": "Transient override recorded"
}
```



**SDK**

```ts
await client.agent.transientEnable.setWorkspaceMitmRuleTransientEnabled({
  workspaceID: "ws_abc123",
  id: "notify-on-write",
  data: { enabled: false, ttlMs: 60000 },
});
```

## Tags

### `GET /api/v1/workspaces/{workspaceID}/mitm/tags`

Returns the effective tag catalog for the workspace's MITM scope.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```json
[
  {
    "id": "destructive",
    "label": "Destructive",
    "description": "Operations that mutate or delete user data",
    "color": "red"
  },
  {
    "id": "review",
    "label": "Review",
    "description": "",
    "color": "gray"
  }
]
```



**SDK**

```ts
const tags = await client.agent.workspaceMitmTags.listWorkspaceMitmTags({
  workspaceID: "ws_abc123",
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/tags`

Adds a new tag to the overlay.

### Parameters



| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | workspaceID path parameter |


### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | Unique tag identifier |
| `label` | string | Yes | Human-readable tag label |
| `description` | string | No | Free-form description (Default: `""`) |
| `color` | string | No | One of `green`, `blue`, `yellow`, `purple`, `red`, `orange`, `gray` (Default: `"gray"`) |



```json
{
  "id": "review",
  "label": "Review",
  "description": "Sessions under human review",
  "color": "blue"
}
```


```json
{
  "id": "review",
  "label": "Review",
  "description": "Sessions under human review",
  "color": "blue"
}
```


```json
{
  "error": "Tag with this id already exists in overlay",
  "code": "tag_already_exists"
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.workspaceMitmTag.createWorkspaceMitmTag({
  workspaceID: "ws_abc123",
  data: {
    id: "review",
    label: "Review",
    description: "Sessions under human review",
    color: "blue",
  },
});
```

### `DELETE /api/v1/workspaces/{workspaceID}/mitm/tags/{id}`

Removes the tag at `:id` from the overlay. If `:id` refers to a base-config tag, the overlay records a deletion tombstone so the tag is omitted from the effective state.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Tag identifier |

This endpoint accepts no body.



```json
{
  "description": "Deleted"
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.workspaceMitmTag.deleteWorkspaceMitmTag({
  workspaceID: "ws_abc123",
  id: "review",
});
```

### `PATCH /api/v1/workspaces/{workspaceID}/mitm/sessions/{sessionID}/tags`

Replaces the `mitm_tags` on a session. The handler canonicalises the incoming list (sorted + deduped) and short-circuits to a no-op when canonical equality is detected.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `sessionID` | path | string | Yes | Session identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `tags` | array | Yes | The full replacement list of tag ids |



```json
{
  "tags": ["review", "destructive"]
}
```


```json
{
  "description": "Tags updated (or no-op)"
}
```


```json
{
  "description": "Session not found"
}
```



**SDK**

```ts
await client.agent.sessionMitmTags.patchSessionMitmTags({
  workspaceID: "ws_abc123",
  sessionID: "sess_xyz",
  data: { tags: ["review", "destructive"] },
});
```

## Cooldowns & Logs

### `GET /api/v1/workspaces/{workspaceID}/mitm/cooldowns`

Returns the list of active per-(rule, session) cooldowns currently in effect for this scope.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```json
[
  {
    "ruleId": "notify-on-write",
    "sessionID": "sess_xyz",
    "lastFiredAt": 1730000040000
  },
  {
    "ruleId": "inject-safety-prompt",
    "sessionID": "sess_abc",
    "lastFiredAt": 1730000055000
  }
]
```



**SDK**

```ts
const cooldowns = await client.agent.workspaceMitmCooldowns.listWorkspaceMitmCooldowns({
  workspaceID: "ws_abc123",
});
```

### `GET /api/v1/workspaces/{workspaceID}/mitm/logs`

Returns a paginated, redacted projection of the MITM log scoped to this workspace. Pass `sessionID` to filter by session.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `page` | query | integer | No | Page number (Default: `1`) |
| `limit` | query | integer | No | Items per page (Default: `50`) |
| `sessionID` | query | string | No | Filter entries by session id |



```json
{
  "items": [
    {
      "id": "log_01HXYZ",
      "ruleId": "notify-on-write",
      "ruleName": "Notify on file write",
      "event": "tool.execute.before",
      "sessionID": "sess_xyz",
      "messageID": "msg_001",
      "timestamp": 1730000040000,
      "status": "success",
      "durationMs": 12,
      "actionType": "notification",
      "rule": {
        "id": "notify-on-write",
        "name": "Notify on file write",
        "enabled": true,
        "severity": "info",
        "trigger": {
          "event": "tool.execute.before",
          "tags": [],
          "toolName": "Write"
        },
        "action": {
          "type": "notification",
          "title": "File write",
          "body": "Tool Write is about to run."
        },
        "cooldownMs": 0,
        "maxDepth": 1,
        "blocking": false
      },
      "context": {
        "sessionTitle": "Refactor auth",
        "tags": ["review"],
        "directory": "/home/user/project",
        "projectID": "proj_1",
        "depth": 0,
        "toolName": "Write",
        "messageRole": "assistant"
      },
      "scope": "ws_abc123",
      "seq": 142,
      "processEpoch": 7,
      "severity": "info"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 50,
    "total": 1,
    "pages": 1
  }
}
```



**SDK**

```ts
const logs = await client.agent.workspaceMitmLogsPaginated.listWorkspaceMitmLogsPaginated({
  workspaceID: "ws_abc123",
  page: 1,
  limit: 50,
  sessionID: "sess_xyz",
});
```

### `GET /api/v1/workspaces/{workspaceID}/mitm/logs/{id}`

Returns the redacted projection of a single MITM log entry. Set the request header `Hoody-MITM-Include-Secrets: 1` to receive the unredacted entry.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |
| `id` | path | string | Yes | Log entry identifier |



```json
{
  "id": "log_01HXYZ",
  "ruleId": "notify-on-write",
  "ruleName": "Notify on file write",
  "event": "tool.execute.before",
  "sessionID": "sess_xyz",
  "messageID": "msg_001",
  "timestamp": 1730000040000,
  "status": "success",
  "durationMs": 12,
  "actionType": "notification",
  "rule": {
    "id": "notify-on-write",
    "name": "Notify on file write",
    "enabled": true,
    "severity": "info",
    "trigger": {
      "event": "tool.execute.before",
      "tags": [],
      "toolName": "Write"
    },
    "action": {
      "type": "notification",
      "title": "File write",
      "body": "Tool Write is about to run."
    },
    "cooldownMs": 0,
    "maxDepth": 1,
    "blocking": false
  },
  "context": {
    "sessionTitle": "Refactor auth",
    "tags": ["review"],
    "directory": "/home/user/project",
    "projectID": "proj_1",
    "depth": 0,
    "toolName": "Write",
    "messageRole": "assistant"
  },
  "scope": "ws_abc123",
  "seq": 142,
  "processEpoch": 7,
  "severity": "info"
}
```


```json
{
  "description": "Entry not found"
}
```



**SDK**

```ts
const entry = await client.agent.workspaceMitmLogEntry.getWorkspaceMitmLogEntry({
  workspaceID: "ws_abc123",
  id: "log_01HXYZ",
});
```

## Validation & Plugins

### `GET /api/v1/workspaces/{workspaceID}/mitm/validation-rules`

Returns the discriminated-union list of validation rules the server applies to MITM rules on top of the Zod structural schema. SDK consumers can use this metadata to implement matching client-side validation.


This endpoint is pure metadata — no auth, no scope binding.


### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```json
[
  {
    "type": "regex",
    "field": "id",
    "pattern": "^[a-z0-9][a-z0-9-]{2,62}$",
    "flags": "i",
    "message": "Rule id must be 3-63 chars, lowercase letters, digits, or hyphens"
  },
  {
    "type": "range",
    "field": "cooldownMs",
    "min": 0,
    "max": 86400000,
    "message": "cooldownMs must be between 0 and 24h"
  },
  {
    "type": "enum",
    "field": "severity",
    "values": ["info", "warn", "error", "critical"],
    "message": "severity must be one of info, warn, error, critical"
  },
  {
    "type": "depends-on",
    "field": "trigger.toolName",
    "requires": "trigger.event",
    "when": "tool.execute.before",
    "message": "toolName requires trigger.event to be a tool event"
  },
  {
    "type": "max-length",
    "field": "name",
    "max": 80,
    "message": "Rule name must be at most 80 characters"
  }
]
```



**SDK**

```ts
const validators = await client.agent.workspaceMitmValidationRules.listWorkspaceMitmValidationRules({
  workspaceID: "ws_abc123",
});
```

### `GET /api/v1/workspaces/{workspaceID}/mitm/plugin-descriptors`

Returns plugin metadata in registration order, including `id`, `source`, declared `hooks`, declared `tools`, and the `auth` provider name.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```json
[
  {
    "id": "hoody-builtin-notifier",
    "source": "internal",
    "exportName": "default",
    "packageName": "@hoody/plugin-notifier",
    "packageVersion": "1.4.2",
    "hooks": ["onRuleFire", "onSessionIdle"],
    "tools": ["sendDesktopNotification"],
    "auth": "none"
  },
  {
    "id": "user-slack-relay",
    "source": "npm",
    "exportName": "SlackRelay",
    "packageName": "@acme/hoody-slack-relay",
    "packageVersion": "0.9.0",
    "hooks": ["onRuleFire"],
    "tools": ["postToSlack"],
    "auth": "oauth2"
  }
]
```



**SDK**

```ts
const plugins = await client.agent.workspaceMitmPluginDescriptors.listWorkspaceMitmPluginDescriptors({
  workspaceID: "ws_abc123",
});
```

## Overlay & Webhooks

### `POST /api/v1/workspaces/{workspaceID}/mitm/overlay/reset`

Drops the entire overlay for this scope — every overlay entry, including tags, rules, deletions, and `enabledOverride` values. Effective state reverts to base config only.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |

This endpoint accepts no body.



```json
{
  "description": "Overlay cleared"
}
```


```json
{
  "error": "If-Match did not match current overlay revision"
}
```


```json
{
  "error": "If-Match header is required for overlay writes"
}
```



**SDK**

```ts
await client.agent.reset.resetWorkspaceMitmOverlay({
  workspaceID: "ws_abc123",
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/overlay/rebase`

For every overlay rule whose `baseContentHash` has drifted, recompute the merged rule against the new base. On success, all `baseContentHash` values are refreshed. If a merged rule fails validation (e.g. the base rule's type changed under you), the server returns `409` with the failed rule and a diff.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |

This endpoint accepts no body.



```json
{
  "description": "Rebase completed"
}
```


```json
{
  "description": "Conflict — merged rule fails validation"
}
```


```json
{
  "description": "Optimistic-concurrency conflict"
}
```


```json
{
  "description": "Missing If-Match header"
}
```



**SDK**

```ts
await client.agent.rebase.rebaseWorkspaceMitmOverlay({
  workspaceID: "ws_abc123",
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/webhooks/verify`

Dispatches a one-shot webhook via `safeFetch` and returns the response status plus a redacted summary. Use this to confirm that a URL and its auth headers work before saving a rule that targets that URL.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `url` | string | Yes | The webhook URL to test |
| `method` | string | No | One of `POST`, `GET` (Default: `"POST"`) |
| `headers` | object | No | Additional request headers (string-to-string map) |
| `bodyJson` | object | No | JSON body to send |



```json
{
  "url": "https://example.com/hooks/hoody",
  "method": "POST",
  "headers": {
    "Authorization": "Bearer test-token"
  },
  "bodyJson": {"ping": true}
}
```


```json
{
  "description": "Diagnostic result"
}
```



**SDK**

```ts
await client.agent.verify.verifyWorkspaceMitmWebhook({
  workspaceID: "ws_abc123",
  data: {
    url: "https://example.com/hooks/hoody",
    method: "POST",
    headers: { Authorization: "Bearer test-token" },
    bodyJson: { ping: true },
  },
});
```

## Events & Diagnostics

### `GET /api/v1/workspaces/{workspaceID}/mitm/events`

Server-Sent Events stream of `MitmLog.Event.RuleFired` filtered to this scope.


Each event carries an `id` formatted as `&lt;processEpoch&gt;:&lt;seq&gt;`. Reconnect with `Last-Event-ID`; if the epoch on the resume event does not match the running process, treat it as a restart. Fresh subscribers receive only future events — there is no replay. The stream emits a synthetic `connected` event on connect and closes with `error: scope_changed` if `Instance.directory` drift is detected. Rebinds are not supported within a single connection.


### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |



```http
HTTP/1.1 200 OK
Content-Type: text/event-stream

event: connected
id: 7:0
data: {"scope":"ws_abc123","processEpoch":7}

event: rule_fired
id: 7:142
data: {"ruleId":"notify-on-write","sessionID":"sess_xyz","event":"tool.execute.before","timestamp":1730000040000}

event: rule_fired
id: 7:143
data: {"ruleId":"notify-on-write","sessionID":"sess_xyz","event":"tool.execute.before","timestamp":1730000041000}
```



**SDK**

```ts
await client.agent.events.streamWorkspaceMitmEvents({
  workspaceID: "ws_abc123",
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/diagnostics/dry-run`

Simulates rule firing against the current snapshot for a synthetic event. Returns the matched rules and each rule's cooldown status. Pure read-only — no actions are executed.

### Parameters



| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | workspaceID path parameter |


### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `event` | string | Yes | One of `session.created`, `session.idle`, `session.error`, `chat.message`, `tool.execute.before`, `tool.execute.after`, `chat.system.transform` |
| `sessionTags` | array | No | Tags on the synthetic session (Default: `[]`) |
| `depth` | integer | No | Recursion depth for the synthetic event (Default: `0`) |
| `toolName` | string | No | Tool name for `tool.execute.*` events |
| `role` | string | No | One of `user`, `assistant` |
| `messageContent` | string | No | Message content for `chat.message` |



```json
{
  "event": "tool.execute.before",
  "sessionTags": ["review"],
  "depth": 0,
  "toolName": "Bash"
}
```


```json
{
  "description": "Match diagnostic"
}
```



**SDK**

```ts
const result = await client.agent.dryRun.diagnoseWorkspaceMitmDryRun({
  workspaceID: "ws_abc123",
  data: {
    event: "tool.execute.before",
    sessionTags: ["review"],
    depth: 0,
    toolName: "Bash",
  },
});
```

### `POST /api/v1/workspaces/{workspaceID}/mitm/diagnostics/match-trace`

Same shape as the dry-run endpoint, but reports WHY each rule did or did not match — at every filter stage (`event`, `depth`, `tags`, `toolName`, `role`, `contentMatch`, `overlayState`). Pure read-only on the snapshot.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `workspaceID` | path | string | Yes | Workspace identifier |

### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `event` | string | Yes | One of `session.created`, `session.idle`, `session.error`, `chat.message`, `tool.execute.before`, `tool.execute.after`, `chat.system.transform` |
| `sessionTags` | array | No | Tags on the synthetic session (Default: `[]`) |
| `depth` | integer | No | Recursion depth for the synthetic event (Default: `0`) |
| `toolName` | string | No | Tool name for `tool.execute.*` events |
| `role` | string | No | One of `user`, `assistant` |
| `messageContent` | string | No | Message content for `chat.message` |



```json
{
  "event": "chat.message",
  "sessionTags": ["review"],
  "depth": 0,
  "role": "user",
  "messageContent": "Please delete the staging database."
}
```


```json
{
  "description": "Per-rule trace"
}
```



**SDK**

```ts
const trace = await client.agent.matchTrace.diagnoseWorkspaceMitmMatchTrace({
  workspaceID: "ws_abc123",
  data: {
    event: "chat.message",
    sessionTags: ["review"],
    depth: 0,
    role: "user",
    messageContent: "Please delete the staging database.",
  },
});
```