> ## Documentation Index
> Fetch the complete documentation index at: https://docs.toolshed.philo.ventures/llms.txt
> Use this file to discover all available pages before exploring further.

# Elicitation

> Human-in-the-loop approval for destructive tool calls.

Elicitation is Toolshed's mechanism for ensuring a human approves destructive operations before they execute. When a sandbox script calls a tool marked `destructive: true`, execution pauses until a human approves or denies the action.

## The elicitation lifecycle

```
1. Script calls tools.github.issues.create(args)
       │
2. Invoke callback calls engine.gate(toolDef, args)
       │
3. Tool is destructive and not session-approved
       │  → creates PendingElicitation with promise
       │  → fires onPause callback
       │
4. Runtime detects pause, returns ExecutionResult with:
       │  { paused: { executionId, toolPath, message, args } }
       │
5. MCP client shows pending action to user
       │
6. User approves → agent calls resume({ execution_id, approved: true })
       │
7. ElicitationEngine.resolve() fulfills the pending promise
       │
8. Execution continues, tool call proceeds
```

## ElicitationEngine

The `ElicitationEngine` class manages the full lifecycle:

```typescript theme={null}
import { ElicitationEngine } from "@toolshed/kernel";

const engine = new ElicitationEngine({
  onPause: (elicitation) => {
    // Notify the user about the pending action
    console.log(`Approval needed: ${elicitation.message}`);
  },
});
```

### Key methods

| Method                                  | Description                                                       |
| --------------------------------------- | ----------------------------------------------------------------- |
| `gate(tool, args)`                      | Gates destructive tool calls. Returns immediately for safe tools. |
| `resolve(executionId, approved, data?)` | Resolves a pending elicitation. Returns `true` if found.          |
| `getPending(executionId)`               | Get a specific pending elicitation                                |
| `getAllPending()`                       | Get all pending elicitations                                      |
| `hasPending()`                          | Check if any elicitations are pending                             |
| `addSessionApproval(toolPath)`          | Auto-approve future calls to this tool path                       |
| `isSessionApproved(toolPath)`           | Check if a tool path is session-approved                          |
| `clearSessionApprovals()`               | Reset all session approvals                                       |

### Session approvals

Once a user approves a tool, the engine can remember the approval for the session. Subsequent calls to the same tool path auto-approve without pausing:

```typescript theme={null}
engine.addSessionApproval("github.issues.create");
// Future calls to github.issues.create will not pause
```

## Using elicit() in plugin handlers

Inside a tool handler, call `ctx.elicit()` to request approval:

```typescript theme={null}
async handler(ctx, input) {
  const approval = await ctx.elicit({
    toolPath: "github.issues.create",
    message: `Create issue "${input.title}" in ${input.owner}/${input.repo}?`,
    args: input,
    type: "approval",
  });

  if (!approval.approved) {
    throw new Error("Issue creation denied by user");
  }

  // proceed...
}
```

The `elicit()` function takes a single object parameter:

| Field      | Type     | Required | Default      | Description                                           |
| ---------- | -------- | -------- | ------------ | ----------------------------------------------------- |
| `toolPath` | `string` | Yes      | --           | Tool requesting approval                              |
| `message`  | `string` | Yes      | --           | Human-readable description                            |
| `args`     | `object` | No       | --           | Arguments being approved                              |
| `type`     | `string` | No       | `"approval"` | `"approval"` for yes/no, `"form"` for data collection |

Returns an `ElicitationResponse`:

| Field         | Type      | Description                       |
| ------------- | --------- | --------------------------------- |
| `executionId` | `string`  | Unique elicitation ID             |
| `approved`    | `boolean` | Whether the user approved         |
| `data`        | `object`  | Additional data (for `form` type) |

## Elicitation types

* **`approval`** -- simple yes/no confirmation. The most common type.
* **`form`** -- collect additional data from the user. The response includes a `data` object with the user's input.
