From 649312793b3c1f067ab5e22b1a2896047672cece Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Sat, 3 Jan 2026 14:33:47 -0800 Subject: [PATCH 1/3] docs: Add AI Sessions documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive documentation for LimaCharlie AI Sessions: - New AI Sessions section with 5 documentation pages: - index.md: Overview of D&R-driven and User sessions - dr-sessions.md: D&R-driven sessions configuration and examples - user-sessions.md: User sessions lifecycle and use cases - api-reference.md: Full REST API and WebSocket protocol - sdk.md: TypeScript SDK documentation - Updated response-actions.md with 'start ai session' action - Updated mkdocs.yml navigation with new section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../doc/AI_Sessions/api-reference.md | 928 ++++++++++++++++++ .../doc/AI_Sessions/dr-sessions.md | 374 +++++++ docs/limacharlie/doc/AI_Sessions/index.md | 103 ++ docs/limacharlie/doc/AI_Sessions/sdk.md | 536 ++++++++++ .../doc/AI_Sessions/user-sessions.md | 361 +++++++ .../Reference/response-actions.md | 71 ++ mkdocs.yml | 7 + 7 files changed, 2380 insertions(+) create mode 100644 docs/limacharlie/doc/AI_Sessions/api-reference.md create mode 100644 docs/limacharlie/doc/AI_Sessions/dr-sessions.md create mode 100644 docs/limacharlie/doc/AI_Sessions/index.md create mode 100644 docs/limacharlie/doc/AI_Sessions/sdk.md create mode 100644 docs/limacharlie/doc/AI_Sessions/user-sessions.md diff --git a/docs/limacharlie/doc/AI_Sessions/api-reference.md b/docs/limacharlie/doc/AI_Sessions/api-reference.md new file mode 100644 index 00000000..996bf2a6 --- /dev/null +++ b/docs/limacharlie/doc/AI_Sessions/api-reference.md @@ -0,0 +1,928 @@ +# API Reference + +This document provides a complete reference for the AI Sessions REST API and WebSocket protocol. + +## Base URL + +| Environment | URL | +|-------------|-----| +| Production | `https://ai-sessions.limacharlie.io` | +| Staging | `https://ai-sessions-staging.limacharlie.io` | + +## Authentication + +All API requests require a valid LimaCharlie JWT token in the Authorization header: + +``` +Authorization: Bearer +``` + +For WebSocket connections, you can also pass the token as a query parameter: + +``` +wss://ai-sessions.limacharlie.io/v1/sessions/{sessionId}/ws?token= +``` + +## Rate Limits + +| Operation | Limit | +|-----------|-------| +| Registration | 10 requests/minute per user | +| Session creation | 10 requests/minute per user | +| WebSocket messages | 100 messages/second per connection | + +--- + +## REST API Endpoints + +### Registration + +#### Register User + +``` +POST /v1/register +``` + +Register the authenticated user for the AI Sessions platform. + +**Response: 200 OK** +```json +{ + "registered": true, + "registered_at": "2025-01-15T10:30:00Z" +} +``` + +**Error Responses:** +- `401`: Invalid or missing JWT token +- `403`: Email domain not in allowed list +- `409`: User already registered + +#### Deregister User + +``` +DELETE /v1/register +``` + +Deregister the user and delete all associated data. This terminates all active sessions and deletes stored credentials. + +**Response: 200 OK** +```json +{ + "deregistered": true +} +``` + +--- + +### Sessions + +#### List Sessions + +``` +GET /v1/sessions +``` + +**Query Parameters:** + +| Parameter | Type | Description | +|-----------|------|-------------| +| `status` | string | Filter by status: `pending`, `running`, `terminated`, `failed` | +| `limit` | integer | Max results (default 50, max 200) | +| `cursor` | string | Pagination cursor | + +**Response: 200 OK** +```json +{ + "sessions": [ + { + "id": "abc123", + "status": "running", + "region": "us-central1", + "created_at": "2025-01-15T10:30:00Z", + "started_at": "2025-01-15T10:30:05Z", + "lc_auth_type": "jwt", + "allowed_tools": ["Bash", "Read"], + "denied_tools": ["Write"] + } + ], + "next_cursor": "xyz789" +} +``` + +#### Create Session + +``` +POST /v1/sessions +``` + +**Request Body:** +```json +{ + "lc_credentials": { + "type": "org_api_key", + "org_api_key": "xxxxxxxx" + }, + "allowed_tools": ["Bash", "Read", "Write"], + "denied_tools": ["WebFetch"] +} +``` + +**Response: 201 Created** +```json +{ + "session": { + "id": "abc123", + "status": "pending", + "region": "us-central1", + "created_at": "2025-01-15T10:30:00Z" + } +} +``` + +**Error Responses:** +- `400`: Invalid request body +- `403`: Not registered or no Claude credentials +- `409`: Maximum concurrent sessions (10) reached + +#### Get Session + +``` +GET /v1/sessions/{sessionId} +``` + +**Response: 200 OK** +```json +{ + "session": { + "id": "abc123", + "status": "running", + "region": "us-central1", + "created_at": "2025-01-15T10:30:00Z", + "started_at": "2025-01-15T10:30:05Z", + "terminated_at": null, + "termination_reason": null, + "exit_code": null, + "error_message": null, + "allowed_tools": ["Bash", "Read"], + "denied_tools": ["Write"] + } +} +``` + +#### Terminate Session + +``` +DELETE /v1/sessions/{sessionId} +``` + +**Response: 200 OK** +```json +{ + "terminated": true +} +``` + +#### Delete Session Record + +``` +DELETE /v1/sessions/{sessionId}/record +``` + +Delete a terminated session from history. Only terminated or failed sessions can be deleted. + +**Response: 200 OK** +```json +{ + "deleted": true +} +``` + +--- + +### Profiles + +#### List Profiles + +``` +GET /v1/profiles +``` + +**Response: 200 OK** +```json +{ + "profiles": [ + { + "id": "profile123", + "name": "Investigation", + "description": "Profile for security investigations", + "is_default": true, + "allowed_tools": ["Bash", "Read"], + "denied_tools": ["Write"], + "permission_mode": "acceptEdits", + "model": "claude-sonnet-4-20250514", + "max_turns": 100, + "max_budget_usd": 10.0, + "created_at": "2025-01-15T10:30:00Z", + "updated_at": "2025-01-15T10:30:00Z" + } + ] +} +``` + +#### Create Profile + +``` +POST /v1/profiles +``` + +**Request Body:** +```json +{ + "name": "Investigation", + "description": "Profile for security investigations", + "allowed_tools": ["Bash", "Read", "Grep"], + "denied_tools": ["Write", "Edit"], + "permission_mode": "acceptEdits", + "model": "claude-sonnet-4-20250514", + "max_turns": 100, + "max_budget_usd": 10.0, + "mcp_servers": { + "limacharlie": { + "type": "http", + "url": "https://mcp.limacharlie.io", + "headers": { + "Authorization": "Bearer token" + } + } + }, + "is_default": false +} +``` + +**Response: 201 Created** +```json +{ + "profile": { + "id": "profile123", + "name": "Investigation", + ... + } +} +``` + +**Error Responses:** +- `400`: Invalid request body +- `409`: Maximum profiles (10) reached + +#### Get Profile + +``` +GET /v1/profiles/{profileId} +``` + +#### Update Profile + +``` +PUT /v1/profiles/{profileId} +``` + +#### Delete Profile + +``` +DELETE /v1/profiles/{profileId} +``` + +> Note: The default profile cannot be deleted. + +#### Set Default Profile + +``` +POST /v1/profiles/{profileId}/default +``` + +#### Capture Session as Profile + +``` +POST /v1/sessions/{sessionId}/capture-profile +``` + +**Request Body:** +```json +{ + "name": "My Session Config", + "description": "Captured from session abc123" +} +``` + +--- + +### Claude Authentication + +#### Start OAuth Flow + +``` +POST /v1/auth/claude/start +``` + +**Response: 200 OK** +```json +{ + "oauth_session_id": "oauth123", + "expires_in": 300, + "message": "Poll /auth/claude/url for the OAuth URL" +} +``` + +#### Get OAuth URL + +``` +GET /v1/auth/claude/url?session_id={oauth_session_id} +``` + +**Response: 200 OK (URL Ready)** +```json +{ + "status": "url_ready", + "url": "https://console.anthropic.com/oauth/authorize?...", + "message": "Visit the URL to authorize" +} +``` + +**Response: 200 OK (Pending)** +```json +{ + "status": "pending", + "message": "Waiting for OAuth URL to be generated" +} +``` + +#### Submit OAuth Code + +``` +POST /v1/auth/claude/code +``` + +**Request Body:** +```json +{ + "session_id": "oauth123", + "code": "authorization_code_from_anthropic" +} +``` + +**Response: 200 OK** +```json +{ + "success": true, + "status": "completed", + "message": "Claude credentials stored successfully" +} +``` + +#### Store API Key + +``` +POST /v1/auth/claude/apikey +``` + +**Request Body:** +```json +{ + "api_key": "sk-ant-api03-xxxxx" +} +``` + +**Response: 200 OK** +```json +{ + "success": true, + "message": "API key stored successfully" +} +``` + +#### Get Credential Status + +``` +GET /v1/auth/claude/status +``` + +**Response: 200 OK** +```json +{ + "has_credentials": true, + "credential_type": "api_key", + "created_at": "2025-01-15T10:30:00Z" +} +``` + +#### Delete Credentials + +``` +DELETE /v1/auth/claude +``` + +--- + +### File Transfer + +#### Request Upload URL + +``` +POST /v1/io/sessions/{sessionId}/upload +``` + +**Request Body:** +```json +{ + "filename": "data.csv", + "content_type": "text/csv", + "size": 1024 +} +``` + +**Response: 200 OK** +```json +{ + "upload_url": "https://storage.googleapis.com/...", + "upload_id": "upload123", + "target_path": "/workspace/uploads/data.csv", + "expires_at": "2025-01-15T11:30:00Z" +} +``` + +**Error Responses:** +- `413`: File size exceeds limit (100 MB) + +#### Notify Upload Complete + +``` +POST /v1/io/sessions/{sessionId}/upload/complete +``` + +**Request Body:** +```json +{ + "upload_id": "upload123" +} +``` + +**Response: 200 OK** +```json +{ + "success": true, + "path": "/workspace/uploads/data.csv" +} +``` + +#### Request Download URL + +``` +POST /v1/io/sessions/{sessionId}/download +``` + +**Request Body:** +```json +{ + "path": "/workspace/output.txt" +} +``` + +**Response: 200 OK** +```json +{ + "download_url": "https://storage.googleapis.com/...", + "expires_at": "2025-01-15T11:30:00Z" +} +``` + +--- + +## WebSocket Protocol + +### Connection + +**Endpoint:** +``` +wss://ai-sessions.limacharlie.io/v1/sessions/{sessionId}/ws +``` + +**Authentication:** +- Header: `Authorization: Bearer ` +- Query parameter: `?token=` + +### Connection Errors + +| Code | Description | +|------|-------------| +| 4001 | Invalid or missing authentication | +| 4003 | Session belongs to different user | +| 4004 | Session not found | +| 4009 | Session not running | +| 4100 | Session ended | +| 4101 | Connection reset | +| 4500 | Internal error | + +### Message Format + +All messages are JSON objects: + +```json +{ + "type": "message_type", + "timestamp": "2025-01-15T10:30:00Z", + "session_id": "abc123", + "payload": { ... } +} +``` + +--- + +### Client to Server Messages + +#### prompt + +Send a user prompt to Claude. + +```json +{ + "type": "prompt", + "payload": { + "text": "List all files in the current directory" + } +} +``` + +#### interrupt + +Interrupt the current Claude operation. + +```json +{ + "type": "interrupt" +} +``` + +#### heartbeat + +Keep the connection alive (send every 30 seconds). + +```json +{ + "type": "heartbeat" +} +``` + +#### upload_request + +Request a signed URL for file upload. + +```json +{ + "type": "upload_request", + "payload": { + "request_id": "req_123", + "filename": "data.csv", + "content_type": "text/csv", + "size": 1024 + } +} +``` + +#### upload_complete + +Notify that file upload has completed. + +```json +{ + "type": "upload_complete", + "payload": { + "request_id": "req_123", + "filename": "data.csv", + "path": "/workspace/uploads/data.csv" + } +} +``` + +#### download_request + +Request a signed URL for file download. + +```json +{ + "type": "download_request", + "payload": { + "request_id": "req_456", + "path": "/workspace/output.txt" + } +} +``` + +--- + +### Server to Client Messages + +#### assistant + +Claude's response content. + +```json +{ + "type": "assistant", + "timestamp": "2025-01-15T10:30:00Z", + "payload": { + "content": [ + { + "type": "text", + "text": "Here are the files in the current directory:\n\n- file1.txt\n- file2.py" + } + ], + "model": "claude-sonnet-4-20250514" + } +} +``` + +#### tool_use + +Claude is invoking a tool. + +```json +{ + "type": "tool_use", + "timestamp": "2025-01-15T10:30:01Z", + "payload": { + "id": "tool_abc123", + "name": "Bash", + "input": { + "command": "ls -la" + } + } +} +``` + +#### tool_result + +Result of a tool execution. + +```json +{ + "type": "tool_result", + "timestamp": "2025-01-15T10:30:02Z", + "payload": { + "tool_use_id": "tool_abc123", + "content": "total 16\ndrwxr-xr-x 2 user user 4096 Jan 15 10:00 .\n..." + } +} +``` + +#### user + +Echo of user input (for display purposes). + +```json +{ + "type": "user", + "timestamp": "2025-01-15T10:30:00Z", + "payload": { + "text": "List all files in the current directory" + } +} +``` + +#### system + +System messages from Claude. + +```json +{ + "type": "system", + "timestamp": "2025-01-15T10:30:00Z", + "payload": { + "message": "Working directory: /workspace" + } +} +``` + +#### result + +Final result of a Claude operation. + +```json +{ + "type": "result", + "timestamp": "2025-01-15T10:35:00Z", + "payload": { + "success": true, + "summary": "Listed directory contents successfully" + } +} +``` + +#### session_status + +Session status update. + +```json +{ + "type": "session_status", + "timestamp": "2025-01-15T10:30:00Z", + "payload": { + "status": "running" + } +} +``` + +#### session_end + +Session has terminated. + +```json +{ + "type": "session_end", + "timestamp": "2025-01-15T10:35:00Z", + "payload": { + "reason": "completed", + "exit_code": 0 + } +} +``` + +**Termination Reasons:** +- `completed`: Session completed normally +- `user_requested`: User terminated the session +- `timeout`: Session timed out +- `process_crashed`: Claude process crashed +- `cancelled`: Session was cancelled + +#### session_error + +An error occurred in the session. + +```json +{ + "type": "session_error", + "timestamp": "2025-01-15T10:35:00Z", + "payload": { + "error": "Claude process died unexpectedly", + "details": "Exit code: 1" + } +} +``` + +#### error + +General error message. + +```json +{ + "type": "error", + "timestamp": "2025-01-15T10:35:00Z", + "payload": { + "message": "Rate limit exceeded", + "code": "rate_limited" + } +} +``` + +**Error Codes:** +- `session_not_found`: Session no longer exists +- `session_not_running`: Session is not in running state +- `session_crashed`: Session process crashed +- `invalid_message`: Malformed message received +- `rate_limited`: Too many messages sent + +#### upload_url + +Response to upload_request. + +```json +{ + "type": "upload_url", + "timestamp": "2025-01-15T10:30:00Z", + "payload": { + "request_id": "req_123", + "upload_id": "upload_789", + "url": "https://storage.googleapis.com/...", + "target_path": "/workspace/uploads/data.csv", + "expires_at": "2025-01-15T11:30:00Z" + } +} +``` + +#### download_url + +Response to download_request. + +```json +{ + "type": "download_url", + "timestamp": "2025-01-15T10:30:00Z", + "payload": { + "request_id": "req_456", + "url": "https://storage.googleapis.com/...", + "expires_at": "2025-01-15T11:30:00Z" + } +} +``` + +--- + +## Connection Management + +### Heartbeat + +- **Client**: Send `heartbeat` message every 30 seconds +- **Server**: Sends WebSocket ping frames every 30 seconds +- **Timeout**: Connection closed after 60 seconds of inactivity + +### Reconnection + +If the connection is lost: + +1. Reconnect using the same session ID +2. Server sends any buffered messages (up to 60 seconds old) +3. If session has ended, server sends `session_end` message + +### Message Size + +Maximum message size is 1 MB. Use file transfer for larger payloads. + +--- + +## Example: Complete Session Flow + +```javascript +const jwt = 'your-limacharlie-jwt'; +const baseUrl = 'https://ai-sessions.limacharlie.io'; + +// 1. Create session +const createResp = await fetch(`${baseUrl}/v1/sessions`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${jwt}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + allowed_tools: ['Bash', 'Read', 'Write'] + }) +}); +const { session } = await createResp.json(); + +// 2. Wait for session to be running +let status = 'pending'; +while (status === 'pending') { + await new Promise(r => setTimeout(r, 1000)); + const resp = await fetch(`${baseUrl}/v1/sessions/${session.id}`, { + headers: { 'Authorization': `Bearer ${jwt}` } + }); + const data = await resp.json(); + status = data.session.status; +} + +// 3. Connect via WebSocket +const ws = new WebSocket( + `wss://ai-sessions.limacharlie.io/v1/sessions/${session.id}/ws?token=${jwt}` +); + +// 4. Set up heartbeat +const heartbeat = setInterval(() => { + ws.send(JSON.stringify({ type: 'heartbeat' })); +}, 30000); + +// 5. Handle messages +ws.onmessage = (event) => { + const msg = JSON.parse(event.data); + switch (msg.type) { + case 'assistant': + console.log('Claude:', msg.payload.content); + break; + case 'tool_use': + console.log('Using tool:', msg.payload.name); + break; + case 'tool_result': + console.log('Tool result:', msg.payload.content); + break; + case 'session_end': + console.log('Session ended:', msg.payload.reason); + clearInterval(heartbeat); + break; + case 'error': + console.error('Error:', msg.payload.message); + break; + } +}; + +// 6. Send a prompt +ws.send(JSON.stringify({ + type: 'prompt', + payload: { text: 'Hello! List the files in the current directory.' } +})); + +// 7. Later: interrupt if needed +// ws.send(JSON.stringify({ type: 'interrupt' })); + +// 8. Cleanup +ws.onclose = () => { + clearInterval(heartbeat); +}; +``` diff --git a/docs/limacharlie/doc/AI_Sessions/dr-sessions.md b/docs/limacharlie/doc/AI_Sessions/dr-sessions.md new file mode 100644 index 00000000..f655f112 --- /dev/null +++ b/docs/limacharlie/doc/AI_Sessions/dr-sessions.md @@ -0,0 +1,374 @@ +# D&R-Driven AI Sessions + +D&R-Driven AI Sessions allow you to automatically spawn Claude AI sessions in response to detections, events, or any condition matched by a Detection & Response rule. This enables powerful automated investigation, triage, and response workflows. + +## Overview + +When a D&R rule matches, the `start ai session` response action launches a Claude session with: + +- A prompt containing the context you specify +- Access to tools and MCP servers you configure +- Optional event data extracted and included automatically + +The session runs autonomously, performing the investigation or analysis you've defined, and the results can be captured via outputs or stored for later review. + +## The `start ai session` Action + +### Basic Syntax + +```yaml +respond: + - action: start ai session + prompt: "Your instructions to Claude..." + anthropic_secret: hive://secret/my-anthropic-key +``` + +### Required Parameters + +| Parameter | Description | +|-----------|-------------| +| `prompt` | The instructions for Claude. Supports [template strings](../Events/template-strings-and-transforms.md) to include event data. | +| `anthropic_secret` | Your Anthropic API key. Use `hive://secret/` to reference a [Hive Secret](../Platform_Management/Config_Hive/config-hive-secrets.md). | + +### Optional Parameters + +| Parameter | Description | +|-----------|-------------| +| `name` | Session name. Supports template strings. Useful for identifying sessions in logs. | +| `lc_api_key_secret` | LimaCharlie API key for org-level API access. Use `hive://secret/`. | +| `idempotent_key` | Unique key to prevent duplicate sessions. Supports template strings. | +| `data` | Extract event data fields to include in the prompt as JSON. | +| `profile` | Inline session configuration (tools, model, limits, etc.). | +| `profile_name` | Reference a saved profile by name. | + +> Note: You can specify either `profile` (inline) or `profile_name` (reference), but not both. + +## Configuration Options + +### Prompt Templating + +The `prompt` parameter supports LimaCharlie's template syntax. You can include event data directly in your instructions: + +```yaml +- action: start ai session + prompt: | + A suspicious process was detected on {{ .routing.hostname }}. + + Process: {{ .event.FILE_PATH }} + Command Line: {{ .event.COMMAND_LINE }} + User: {{ .event.USER_NAME }} + + Please investigate this activity and determine if it's malicious. + anthropic_secret: hive://secret/anthropic-key +``` + +### Data Extraction + +Use the `data` parameter to extract specific fields and include them as structured JSON: + +```yaml +- action: start ai session + prompt: "Analyze this detection and provide a severity assessment." + anthropic_secret: hive://secret/anthropic-key + data: + hostname: "{{ .routing.hostname }}" + sensor_id: "{{ .routing.sid }}" + process_path: "{{ .event.FILE_PATH }}" + command_line: "{{ .event.COMMAND_LINE }}" + parent_process: "{{ .event.PARENT/FILE_PATH }}" + detection_name: "{{ .detect.cat }}" +``` + +The extracted data is appended to the prompt as a JSON code block. + +### Idempotent Sessions + +Prevent duplicate sessions for the same event using `idempotent_key`: + +```yaml +- action: start ai session + prompt: "Investigate this detection..." + anthropic_secret: hive://secret/anthropic-key + idempotent_key: "{{ .detect.detect_id }}" +``` + +If a session with the same idempotent key was recently created, the action is skipped. + +### Session Profiles + +Profiles let you configure Claude's behavior, available tools, and resource limits. + +#### Inline Profile + +```yaml +- action: start ai session + prompt: "Investigate this activity..." + anthropic_secret: hive://secret/anthropic-key + profile: + # Tool access + allowed_tools: + - Bash + - Read + - Grep + - Glob + - WebFetch + denied_tools: + - Write + - Edit + + # Permission mode + permission_mode: acceptEdits + + # Model configuration + model: claude-sonnet-4-20250514 + max_turns: 50 + max_budget_usd: 5.0 + ttl_seconds: 1800 + + # Environment variables + environment: + LOG_LEVEL: debug + API_KEY: hive://secret/external-api-key + + # MCP servers + mcp_servers: + limacharlie: + type: http + url: https://mcp.limacharlie.io + headers: + Authorization: hive://secret/lc-mcp-token +``` + +#### Profile Options + +| Option | Type | Description | +|--------|------|-------------| +| `allowed_tools` | list | Tools Claude can use. If empty, all tools are allowed. | +| `denied_tools` | list | Tools Claude cannot use. Takes precedence over `allowed_tools`. | +| `permission_mode` | string | `acceptEdits` (default), `plan`, or `bypassPermissions` | +| `model` | string | Claude model to use (e.g., `claude-sonnet-4-20250514`) | +| `max_turns` | integer | Maximum conversation turns before auto-termination | +| `max_budget_usd` | float | Maximum spend limit in USD | +| `ttl_seconds` | integer | Maximum session lifetime in seconds | +| `environment` | map | Environment variables. Values can use `hive://secret/` | +| `mcp_servers` | map | MCP server configurations (see below) | + +### MCP Server Configuration + +MCP (Model Context Protocol) servers extend Claude's capabilities by providing additional data sources and tools. + +#### HTTP MCP Server + +```yaml +mcp_servers: + limacharlie: + type: http + url: https://mcp.limacharlie.io + headers: + Authorization: hive://secret/lc-mcp-token +``` + +#### Stdio MCP Server + +```yaml +mcp_servers: + custom-tool: + type: stdio + command: /usr/bin/my-tool + args: + - --config + - /etc/my-tool.conf + env: + API_KEY: hive://secret/tool-api-key +``` + +## Examples + +### Example 1: Basic Detection Investigation + +Automatically investigate when a suspicious process is detected: + +```yaml +detect: + event: NEW_PROCESS + op: contains + path: event/COMMAND_LINE + value: -encodedcommand + +respond: + - action: report + name: encoded-powershell-command + - action: start ai session + prompt: | + A PowerShell process with an encoded command was detected. + + Decode the command and analyze what it does. + Check for persistence mechanisms, lateral movement, or data exfiltration. + Provide a severity assessment and recommended response actions. + anthropic_secret: hive://secret/anthropic-key + data: + command_line: "{{ .event.COMMAND_LINE }}" + hostname: "{{ .routing.hostname }}" + user: "{{ .event.USER_NAME }}" +``` + +### Example 2: Automated Triage with LimaCharlie MCP + +Use the LimaCharlie MCP server to query additional context: + +```yaml +detect: + target: detection + event: "*" + op: is greater than + path: priority + value: 3 + +respond: + - action: start ai session + prompt: | + A high-priority detection was triggered. Use the LimaCharlie MCP tools to: + + 1. Get information about the sensor where this occurred + 2. Query recent events from the same sensor + 3. Check if the same detection occurred on other sensors + 4. Look up any relevant threat intelligence + + Produce a summary report with: + - What happened + - Scope of impact + - Recommended immediate actions + - Suggested long-term mitigations + anthropic_secret: hive://secret/anthropic-key + lc_api_key_secret: hive://secret/lc-api-key + idempotent_key: "{{ .detect.detect_id }}" + profile: + max_turns: 100 + max_budget_usd: 10.0 + mcp_servers: + limacharlie: + type: http + url: https://mcp.limacharlie.io + headers: + Authorization: hive://secret/lc-mcp-token +``` + +### Example 3: Threat Hunting Automation + +Automatically investigate IoC matches from threat intelligence: + +```yaml +detect: + event: DNS_REQUEST + op: lookup + path: event/DOMAIN_NAME + resource: lookup/threat-domains + +respond: + - action: report + name: threat-intel-domain-match + - action: start ai session + name: "threat-hunt-{{ .routing.sid }}" + prompt: | + A DNS request to a known malicious domain was detected. + + Using the available tools: + 1. Identify the process that made the DNS request + 2. Examine the process's network connections + 3. Check for any files written by the process + 4. Look for persistence mechanisms + 5. Identify if other sensors communicated with this domain + + Document all findings and provide a detailed incident report. + anthropic_secret: hive://secret/anthropic-key + lc_api_key_secret: hive://secret/lc-api-key + profile: + allowed_tools: + - Bash + - Read + - Grep + - Glob + - WebFetch + denied_tools: + - Write + - Edit + max_turns: 150 + ttl_seconds: 3600 +``` + +### Example 4: Custom Enrichment + +Use external tools via MCP for enrichment: + +```yaml +respond: + - action: start ai session + prompt: | + Enrich this alert with external threat intelligence. + + Check the file hash against VirusTotal. + Look up the IP address geolocation and reputation. + Cross-reference with MITRE ATT&CK techniques. + anthropic_secret: hive://secret/anthropic-key + data: + file_hash: "{{ .event.HASH }}" + ip_address: "{{ .event.IP_ADDRESS }}" + profile: + mcp_servers: + virustotal: + type: http + url: https://vt-mcp.example.com + headers: + x-apikey: hive://secret/vt-api-key + mitre: + type: http + url: https://mitre-mcp.example.com +``` + +## Best Practices + +### Prompt Design + +- **Be specific**: Tell Claude exactly what you want it to investigate and how to report findings +- **Provide context**: Include relevant event data in the prompt +- **Define outputs**: Specify the format you want for results (markdown, JSON, etc.) +- **Set boundaries**: Clearly state what actions Claude should NOT take + +### Resource Limits + +- **Set max_turns**: Prevent runaway sessions that consume excessive resources +- **Set max_budget_usd**: Cap costs for each session +- **Use ttl_seconds**: Automatically terminate long-running sessions + +### Security + +- **Store secrets in Hive**: Never hardcode API keys in D&R rules +- **Limit tools**: Only allow tools Claude needs for the task +- **Use denied_tools**: Explicitly block dangerous tools for sensitive operations +- **Restrict MCP access**: Only configure MCP servers that are necessary + +### Deduplication + +- **Use idempotent_key**: Prevent duplicate sessions for the same event +- **Include unique identifiers**: Use `detect_id`, `this` atom, or similar unique values +- **Combine with suppression**: Use D&R suppression to limit how often sessions are spawned + +## Troubleshooting + +### Session Not Starting + +- Verify the Anthropic API key is valid and stored correctly in Hive Secrets +- Check that the D&R rule is enabled and matching events +- Review D&R rule syntax for errors + +### Session Failing + +- Check `max_turns` isn't too low for the task +- Verify MCP server URLs and authentication +- Review session logs for error messages + +### Unexpected Behavior + +- Review the prompt for ambiguity +- Check that `allowed_tools` includes necessary tools +- Verify `denied_tools` isn't blocking required capabilities diff --git a/docs/limacharlie/doc/AI_Sessions/index.md b/docs/limacharlie/doc/AI_Sessions/index.md new file mode 100644 index 00000000..905775c5 --- /dev/null +++ b/docs/limacharlie/doc/AI_Sessions/index.md @@ -0,0 +1,103 @@ +# AI Sessions + +LimaCharlie AI Sessions brings the power of Claude, Anthropic's advanced AI assistant, directly into your security operations. AI Sessions enables you to leverage AI for automated incident investigation, threat hunting, and response actions—all within the context of your LimaCharlie organization. + +## Overview + +AI Sessions provides two complementary ways to use Claude AI: + +### D&R-Driven Sessions + +Automatically spawn AI sessions in response to detections, events, or any condition matched by a Detection & Response rule. Use cases include: + +- **Automated incident triage**: When a detection fires, have Claude investigate the alert, gather context, and produce a summary report +- **Threat hunting**: Automatically investigate suspicious activity patterns +- **Enrichment**: Use Claude to correlate data from multiple sources via MCP servers +- **Response automation**: Generate recommendations or take automated actions + +[Learn more about D&R-Driven Sessions](dr-sessions.md) + +### User Sessions + +Interactive AI sessions accessed through the web interface or API. Use cases include: + +- **Ad-hoc investigation**: Interactively investigate incidents with Claude's help +- **Learning and exploration**: Explore your environment and learn about security concepts +- **Custom analysis**: Perform complex analysis tasks with full Claude Code capabilities + +[Learn more about User Sessions](user-sessions.md) + +## Key Features + +| Feature | D&R-Driven Sessions | User Sessions | +|---------|---------------------|---------------| +| **Trigger** | Automatic (D&R rules) | Manual (UI/API) | +| **Authentication** | Org API key + Anthropic secret | User JWT + stored credentials | +| **Interaction** | Fire-and-forget | Real-time WebSocket | +| **Use case** | Automation | Investigation | +| **Idempotency** | Supported | N/A | + +## How It Works + +AI Sessions runs fully-managed Claude Code instances in isolated cloud environments. Each session: + +1. **Receives a prompt** with context (event data, detection details, or user input) +2. **Executes autonomously** using Claude's tool capabilities (Bash, file operations, web fetch, etc.) +3. **Connects to external data** via MCP servers (LimaCharlie API, threat intel, etc.) +4. **Returns results** either as a final summary or streamed in real-time + +## Getting Started + +### For D&R-Driven Sessions + +1. Store your Anthropic API key in a [Hive Secret](../Platform_Management/Config_Hive/config-hive-secrets.md) +2. Create a D&R rule with the `start ai session` action +3. Configure the prompt and optional profile settings + +```yaml +detect: + event: NEW_PROCESS + op: contains + path: event/COMMAND_LINE + value: mimikatz + +respond: + - action: report + name: suspicious-process-detected + - action: start ai session + prompt: | + Investigate this suspicious process detection. + Analyze the process tree, network connections, and file activity. + Provide a summary of findings and recommended actions. + anthropic_secret: hive://secret/anthropic-key + lc_api_key_secret: hive://secret/lc-api-key +``` + +### For User Sessions + +1. [Register](user-sessions.md#registration) for AI Sessions +2. Store your Anthropic credentials (API key or OAuth) +3. Create a session and start interacting + +## Documentation + +- [D&R-Driven Sessions](dr-sessions.md) - Automated sessions triggered by D&R rules +- [User Sessions](user-sessions.md) - Interactive sessions via web UI or API +- [API Reference](api-reference.md) - REST API and WebSocket protocol +- [TypeScript SDK](sdk.md) - SDK for programmatic access + +## Billing + +AI Sessions usage is billed based on: + +- **Session runtime**: Per-minute charges for active sessions +- **Claude API usage**: Passed through from your Anthropic account (Bring Your Own Key model) + +Since you provide your own Anthropic API key, Claude API costs are billed directly by Anthropic to your account. + +## Privacy & Security + +- **Bring Your Own Key**: You provide your own Anthropic API key; LimaCharlie never has access to your Claude conversations +- **Isolated execution**: Each session runs in an isolated container +- **Encrypted storage**: Credentials are encrypted at rest using AES-256-GCM +- **No training**: Neither LimaCharlie nor Anthropic uses your data for model training diff --git a/docs/limacharlie/doc/AI_Sessions/sdk.md b/docs/limacharlie/doc/AI_Sessions/sdk.md new file mode 100644 index 00000000..fb96e200 --- /dev/null +++ b/docs/limacharlie/doc/AI_Sessions/sdk.md @@ -0,0 +1,536 @@ +# TypeScript SDK + +The `@limacharlie/ai-sessions` package provides a TypeScript SDK for interacting with the AI Sessions Platform. + +## Installation + +```bash +npm install @limacharlie/ai-sessions +# or +yarn add @limacharlie/ai-sessions +# or +pnpm add @limacharlie/ai-sessions +``` + +For Node.js environments, you also need the `ws` package: + +```bash +npm install ws +``` + +## Quick Start + +```typescript +import { createClient, createSessionWebSocket } from '@limacharlie/ai-sessions'; + +// Create REST client +const client = createClient({ + baseUrl: 'https://ai-sessions.limacharlie.io', + token: 'your-limacharlie-jwt-token', +}); + +// Register user (first time only) +await client.register(); + +// Store your Anthropic API key +await client.storeAPIKey('sk-ant-api03-xxxxx'); + +// Create a session +const { session } = await client.createSession({ + allowed_tools: ['Bash', 'Read', 'Write'], +}); +console.log('Session created:', session.id); + +// Connect via WebSocket for real-time communication +const ws = createSessionWebSocket( + client.getWebSocketURL(session.id), + { + onAssistant: (msg) => { + console.log('Claude:', msg.content); + }, + onToolUse: (msg) => { + console.log('Tool:', msg.data.tool_name, msg.data.input); + }, + onError: (err) => { + console.error('Error:', err); + }, + onSessionEnd: (msg) => { + console.log('Session ended:', msg.data.reason); + }, + onConnectionChange: (state) => { + console.log('Connection:', state); + }, + } +); + +await ws.connect(); + +// Send a prompt +ws.sendPrompt('Hello! List the files in the current directory.'); + +// Later, disconnect +ws.disconnect(); +``` + +## Features + +- **REST API Client**: Full coverage of the AI Sessions API +- **WebSocket Client**: Real-time communication with automatic reconnection +- **File Transfer**: Upload and download files to/from sessions +- **TypeScript Support**: Full type definitions included +- **Node.js & Browser**: Works in both environments + +## REST Client + +### Configuration + +```typescript +import { createClient } from '@limacharlie/ai-sessions'; + +const client = createClient({ + baseUrl: 'https://ai-sessions.limacharlie.io', + token: 'your-jwt-token', + timeout: 30000, // optional, default 30s + retry: { + maxRetries: 3, + retryDelay: 1000, + retryOn: [429, 502, 503, 504], + }, +}); +``` + +### Registration + +```typescript +// Register for AI Sessions +await client.register(); + +// Deregister (deletes all data) +await client.deregister(); +``` + +### Sessions + +```typescript +// List all sessions +const { sessions } = await client.listSessions(); + +// List running sessions only +const { sessions } = await client.listSessions({ status: 'running' }); + +// Create a session +const { session } = await client.createSession({ + allowed_tools: ['Bash', 'Read', 'Write'], + denied_tools: ['WebFetch'], +}); + +// Get session details +const { session } = await client.getSession(sessionId); + +// Terminate a session +await client.terminateSession(sessionId); + +// Delete session record (after termination) +await client.deleteSessionRecord(sessionId); +``` + +### Credentials + +```typescript +// Store Anthropic API key +await client.storeAPIKey('sk-ant-api03-xxxxx'); + +// Check credential status +const status = await client.getCredentialStatus(); +console.log(status.has_credentials); // true/false +console.log(status.credential_type); // 'api_key' or 'oauth_token' + +// Delete stored credentials +await client.deleteCredentials(); +``` + +### OAuth Flow + +```typescript +// Start OAuth flow +const { oauth_session_id } = await client.startOAuth(); + +// Poll for OAuth URL +const response = await client.pollOAuthURL(oauth_session_id); +if (response.status === 'url_ready') { + console.log('Visit:', response.url); +} + +// After user authorizes, submit the code +await client.submitOAuthCode(oauth_session_id, authorizationCode); +``` + +### Profiles + +```typescript +// List profiles +const { profiles } = await client.listProfiles(); + +// Create a profile +const { profile } = await client.createProfile({ + name: 'Investigation', + description: 'Profile for security investigations', + allowed_tools: ['Bash', 'Read', 'Grep'], + denied_tools: ['Write', 'Edit'], + max_turns: 100, + max_budget_usd: 10.0, +}); + +// Get profile +const { profile } = await client.getProfile(profileId); + +// Update profile +await client.updateProfile(profileId, { + name: 'Updated Investigation', + max_turns: 150, +}); + +// Delete profile +await client.deleteProfile(profileId); + +// Set as default +await client.setDefaultProfile(profileId); + +// Capture session settings as profile +await client.captureProfile(sessionId, { + name: 'My Session Config', +}); +``` + +### File Transfer (REST) + +```typescript +// Request upload URL +const { upload_url, upload_id, target_path } = await client.requestUploadURL( + sessionId, + { + filename: 'data.csv', + content_type: 'text/csv', + size: 1024, + } +); + +// Upload using the URL (use fetch or your preferred HTTP client) +await fetch(upload_url, { + method: 'PUT', + body: fileContent, + headers: { 'Content-Type': 'text/csv' }, +}); + +// Notify upload complete +await client.notifyUploadComplete(sessionId, upload_id); + +// Request download URL +const { download_url } = await client.requestDownloadURL(sessionId, { + path: '/workspace/output.txt', +}); + +// Download using the URL +const response = await fetch(download_url); +const content = await response.text(); +``` + +## WebSocket Client + +### Configuration + +```typescript +import { createSessionWebSocket } from '@limacharlie/ai-sessions'; + +const ws = createSessionWebSocket( + client.getWebSocketURL(sessionId), + { + // Message handlers + onMessage: (msg) => { /* any message */ }, + onAssistant: (msg) => { /* Claude response */ }, + onToolUse: (msg) => { /* tool being used */ }, + onToolResult: (msg) => { /* tool result */ }, + onUser: (msg) => { /* user message echo */ }, + onSystem: (msg) => { /* system message */ }, + onResult: (msg) => { /* final result */ }, + onError: (err) => { /* error */ }, + onSessionEnd: (msg) => { /* session ended */ }, + onConnectionChange: (state) => { /* connection state changed */ }, + }, + { + // Options + autoReconnect: true, + maxReconnectAttempts: 5, + reconnectDelay: 1000, + heartbeatInterval: 30000, + } +); +``` + +### Connection + +```typescript +// Connect +await ws.connect(); + +// Check connection state +console.log(ws.getState()); // 'connecting', 'connected', 'disconnected' + +// Disconnect +ws.disconnect(); +``` + +### Sending Messages + +```typescript +// Send a prompt +ws.sendPrompt('Write a hello world in Python'); + +// Interrupt current operation +ws.sendInterrupt(); + +// Send heartbeat (usually handled automatically) +ws.sendHeartbeat(); +``` + +### File Transfer (WebSocket) + +```typescript +// Request upload URL +ws.requestUpload({ + request_id: 'req_123', + filename: 'data.csv', + content_type: 'text/csv', + size: 1024, +}); + +// Listen for upload_url response in onMessage handler + +// Notify upload complete +ws.notifyUploadComplete({ + request_id: 'req_123', + filename: 'data.csv', + path: '/workspace/uploads/data.csv', +}); + +// Request download URL +ws.requestDownload({ + request_id: 'req_456', + path: '/workspace/output.txt', +}); +``` + +## File Transfer Helper + +The SDK provides a convenience wrapper for file transfers: + +```typescript +import { createFileTransfer, createWebSocketFileTransfer } from '@limacharlie/ai-sessions'; + +// REST-based file transfer +const fileTransfer = createFileTransfer(client); + +// Upload a file +const path = await fileTransfer.uploadFile( + sessionId, + file, // File or Blob + 'document.pdf', + { + onProgress: (progress) => console.log(`${progress}%`), + } +); + +// Download a file +const blob = await fileTransfer.downloadFromURL(downloadUrl); + +// WebSocket-based file transfer +const wsFileTransfer = createWebSocketFileTransfer(ws); +await wsFileTransfer.uploadFile(file, 'data.csv'); +const blob = await wsFileTransfer.downloadFile('/output/result.txt'); +``` + +## Node.js Usage + +For Node.js, provide WebSocket implementation: + +```typescript +import { createClient, createSessionWebSocket } from '@limacharlie/ai-sessions'; +import WebSocket from 'ws'; + +const client = createClient({ + baseUrl: 'https://ai-sessions.limacharlie.io', + token: 'your-jwt-token', + fetch: globalThis.fetch, // Node 18+ has native fetch +}); + +const ws = createSessionWebSocket( + client.getWebSocketURL(sessionId), + handlers, + options, + WebSocket as unknown as typeof globalThis.WebSocket +); +``` + +## Types + +All types are exported from the main package: + +```typescript +import type { + // Client types + AISessionsClient, + AISessionsConfig, + + // Session types + Session, + SessionStatus, + CreateSessionRequest, + LCCredentials, + + // Profile types + Profile, + CreateProfileRequest, + MCPServerConfig, + + // WebSocket types + WebSocketMessage, + AssistantMessage, + ToolUseMessage, + ToolResultMessage, + WebSocketOptions, + ConnectionState, + + // File transfer types + UploadRequest, + UploadResponse, + DownloadRequest, + DownloadResponse, +} from '@limacharlie/ai-sessions'; +``` + +## Error Handling + +```typescript +import { APIError } from '@limacharlie/ai-sessions'; + +try { + await client.createSession({}); +} catch (error) { + if ('error' in error && 'message' in error) { + const apiError = error as APIError; + console.error(`API Error: ${apiError.error} - ${apiError.message}`); + + // Handle specific errors + switch (apiError.status) { + case 401: + console.error('Authentication failed'); + break; + case 403: + console.error('Not registered or no credentials'); + break; + case 409: + console.error('Max sessions reached'); + break; + case 429: + console.error('Rate limited'); + break; + } + } +} +``` + +## Complete Example + +Here's a complete example showing a typical workflow: + +```typescript +import { createClient, createSessionWebSocket } from '@limacharlie/ai-sessions'; +import WebSocket from 'ws'; + +async function main() { + // Create client + const client = createClient({ + baseUrl: 'https://ai-sessions.limacharlie.io', + token: process.env.LC_JWT!, + }); + + // Check if registered, register if not + try { + await client.getCredentialStatus(); + } catch (e) { + console.log('Registering...'); + await client.register(); + await client.storeAPIKey(process.env.ANTHROPIC_KEY!); + } + + // Create session + console.log('Creating session...'); + const { session } = await client.createSession({ + allowed_tools: ['Bash', 'Read', 'Grep', 'Glob'], + denied_tools: ['Write', 'Edit'], + }); + console.log('Session ID:', session.id); + + // Wait for session to be running + let status = session.status; + while (status === 'pending') { + await new Promise(r => setTimeout(r, 1000)); + const resp = await client.getSession(session.id); + status = resp.session.status; + } + + if (status !== 'running') { + throw new Error(`Session failed to start: ${status}`); + } + + // Connect via WebSocket + console.log('Connecting...'); + const ws = createSessionWebSocket( + client.getWebSocketURL(session.id), + { + onAssistant: (msg) => { + for (const content of msg.payload.content) { + if (content.type === 'text') { + process.stdout.write(content.text); + } + } + }, + onToolUse: (msg) => { + console.log(`\n[Using ${msg.payload.name}]`); + }, + onToolResult: (msg) => { + console.log(`[Result: ${msg.payload.content.substring(0, 100)}...]`); + }, + onSessionEnd: (msg) => { + console.log(`\nSession ended: ${msg.payload.reason}`); + process.exit(0); + }, + onError: (err) => { + console.error('Error:', err); + }, + }, + { autoReconnect: true }, + WebSocket as unknown as typeof globalThis.WebSocket + ); + + await ws.connect(); + console.log('Connected!'); + + // Send prompt + ws.sendPrompt('Find all Python files in /workspace and show their first 10 lines'); + + // Keep alive + process.on('SIGINT', async () => { + console.log('\nTerminating session...'); + ws.disconnect(); + await client.terminateSession(session.id); + process.exit(0); + }); +} + +main().catch(console.error); +``` + +## License + +MIT diff --git a/docs/limacharlie/doc/AI_Sessions/user-sessions.md b/docs/limacharlie/doc/AI_Sessions/user-sessions.md new file mode 100644 index 00000000..439e618c --- /dev/null +++ b/docs/limacharlie/doc/AI_Sessions/user-sessions.md @@ -0,0 +1,361 @@ +# User AI Sessions + +User AI Sessions provide interactive access to Claude AI through the LimaCharlie web interface or API. Unlike D&R-driven sessions that run automatically, user sessions are manually initiated and allow real-time, bidirectional communication with Claude. + +## Overview + +User sessions give you: + +- **Interactive Claude Code**: Full Claude Code capabilities in a cloud-hosted environment +- **Real-time communication**: WebSocket-based streaming of responses and tool usage +- **Session management**: Create, list, and manage multiple sessions +- **File transfer**: Upload and download files to/from session workspaces +- **Profiles**: Save and reuse session configurations + +## Getting Started + +### Step 1: Registration + +Before using AI Sessions, you must register. Registration is available to LimaCharlie users with approved email domains. + +**Via Web UI:** +Navigate to the AI Sessions section in the LimaCharlie web console and click "Register". + +**Via API:** +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/register \ + -H "Authorization: Bearer $LC_JWT" +``` + +### Step 2: Store Claude Credentials + +AI Sessions uses a Bring Your Own Key (BYOK) model. You provide your Anthropic credentials—either an API key or via Claude Max OAuth. + +#### Option A: API Key + +Store your Anthropic API key directly: + +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/auth/claude/apikey \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{"api_key": "sk-ant-api03-xxxxx"}' +``` + +> Note: API keys must start with `sk-ant-`. + +#### Option B: Claude Max OAuth + +If you have a Claude Max subscription, you can authenticate via OAuth: + +1. Start the OAuth flow: +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/auth/claude/start \ + -H "Authorization: Bearer $LC_JWT" +``` + +2. Poll for the authorization URL: +```bash +curl https://ai-sessions.limacharlie.io/v1/auth/claude/url?session_id= \ + -H "Authorization: Bearer $LC_JWT" +``` + +3. Visit the URL in your browser and authorize +4. Submit the authorization code: +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/auth/claude/code \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{"session_id": "", "code": ""}' +``` + +### Step 3: Create a Session + +Create a new session to start working with Claude: + +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/sessions \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{ + "allowed_tools": ["Bash", "Read", "Write", "Grep", "Glob"], + "denied_tools": ["WebFetch"] + }' +``` + +### Step 4: Connect via WebSocket + +For real-time interaction, connect to the session via WebSocket: + +```javascript +const ws = new WebSocket( + 'wss://ai-sessions.limacharlie.io/v1/sessions/{sessionId}/ws?token={jwt}' +); + +ws.onmessage = (event) => { + const msg = JSON.parse(event.data); + console.log(msg.type, msg.payload); +}; + +// Send a prompt +ws.send(JSON.stringify({ + type: 'prompt', + payload: { text: 'List all files in the current directory' } +})); +``` + +## Session Profiles + +Profiles let you save and reuse session configurations. You can have up to 10 profiles, with one designated as the default. + +### Creating a Profile + +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/profiles \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Investigation", + "description": "Profile for security investigations", + "allowed_tools": ["Bash", "Read", "Grep", "Glob", "WebFetch"], + "denied_tools": ["Write", "Edit"], + "permission_mode": "acceptEdits", + "max_turns": 100, + "max_budget_usd": 10.0 + }' +``` + +### Profile Options + +| Option | Type | Description | +|--------|------|-------------| +| `name` | string | Profile name (max 100 characters) | +| `description` | string | Profile description (max 500 characters) | +| `allowed_tools` | list | Tools Claude can use | +| `denied_tools` | list | Tools Claude cannot use | +| `permission_mode` | string | `acceptEdits`, `plan`, or `bypassPermissions` | +| `model` | string | Claude model to use | +| `max_turns` | integer | Maximum conversation turns | +| `max_budget_usd` | float | Maximum spend limit in USD | +| `mcp_servers` | map | MCP server configurations | + +### Setting a Default Profile + +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/profiles/{profileId}/default \ + -H "Authorization: Bearer $LC_JWT" +``` + +### Capturing Settings from a Session + +You can create a new profile from an existing session's settings: + +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/sessions/{sessionId}/capture-profile \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{"name": "My Session Config"}' +``` + +## Session Lifecycle + +### Session States + +| State | Description | +|-------|-------------| +| `pending` | Session is being created and provisioned | +| `running` | Session is active and accepting prompts | +| `terminated` | Session ended normally or was terminated by user | +| `failed` | Session encountered an error | + +### Termination Reasons + +| Reason | Description | +|--------|-------------| +| `user_requested` | User terminated the session | +| `completed` | Session completed its task | +| `process_crashed` | Claude process crashed unexpectedly | +| `timeout` | Session exceeded time limit | +| `cancelled` | Session was cancelled by the system | + +### Terminating a Session + +```bash +curl -X DELETE https://ai-sessions.limacharlie.io/v1/sessions/{sessionId} \ + -H "Authorization: Bearer $LC_JWT" +``` + +### Deleting Session Records + +After a session is terminated, you can delete its record: + +```bash +curl -X DELETE https://ai-sessions.limacharlie.io/v1/sessions/{sessionId}/record \ + -H "Authorization: Bearer $LC_JWT" +``` + +## File Transfer + +### Uploading Files + +1. Request an upload URL: +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/io/sessions/{sessionId}/upload \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{ + "filename": "data.csv", + "content_type": "text/csv", + "size": 1024 + }' +``` + +2. Upload the file to the signed URL: +```bash +curl -X PUT "{upload_url}" \ + -H "Content-Type: text/csv" \ + --data-binary @data.csv +``` + +3. Notify that upload is complete: +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/io/sessions/{sessionId}/upload/complete \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{"upload_id": "{upload_id}"}' +``` + +The file will be available in the session at the `target_path` returned in step 1. + +### Downloading Files + +1. Request a download URL: +```bash +curl -X POST https://ai-sessions.limacharlie.io/v1/io/sessions/{sessionId}/download \ + -H "Authorization: Bearer $LC_JWT" \ + -H "Content-Type: application/json" \ + -d '{"path": "/workspace/output.txt"}' +``` + +2. Download the file from the signed URL: +```bash +curl -o output.txt "{download_url}" +``` + +### File Size Limits + +- Maximum file size: 100 MB +- Maximum message size (WebSocket): 1 MB + +## Use Cases + +### Interactive Threat Investigation + +Use Claude to investigate a security incident step by step: + +``` +You: I need to investigate suspicious activity on sensor abc123. + The user reported strange popup windows. + +Claude: I'll investigate this sensor. Let me start by gathering some + context about the sensor and recent events. + + [Uses LimaCharlie MCP to query sensor info and events] + + I found several suspicious indicators: + 1. A new process "update.exe" started from a temp directory + 2. Multiple outbound connections to an unknown IP + 3. Registry modifications for persistence + + Would you like me to investigate any of these in more detail? +``` + +### Ad-hoc Analysis + +Perform quick analysis tasks: + +``` +You: Analyze this list of IP addresses and tell me which ones + appear in threat intelligence feeds. + +Claude: I'll analyze each IP address against available threat + intelligence sources. + + [Checks each IP against VirusTotal, AbuseIPDB, etc.] + + Results: + - 192.168.1.1: Clean (internal) + - 45.33.32.156: Malicious - Known C2 server + - 8.8.8.8: Clean (Google DNS) +``` + +### Learning and Exploration + +Explore your LimaCharlie environment: + +``` +You: Show me how to create a D&R rule that detects PowerShell + downloading files from the internet. + +Claude: Here's how to create a D&R rule for detecting PowerShell + web downloads: + + [Provides detailed explanation with examples] +``` + +## Best Practices + +### Session Management + +- **Terminate idle sessions**: Sessions consume resources; terminate when done +- **Use profiles**: Save common configurations for quick session creation +- **Set resource limits**: Use `max_turns` and `max_budget_usd` to control costs + +### Security + +- **Limit tool access**: Only enable tools needed for your task +- **Review tool usage**: Monitor what actions Claude is taking +- **Be careful with Write/Edit**: These tools can modify files + +### Performance + +- **Keep prompts focused**: Specific, clear prompts get better results +- **Upload files for large data**: Use file transfer instead of pasting into prompts +- **Use heartbeats**: Keep WebSocket connections alive with regular heartbeats + +## Rate Limits + +| Operation | Limit | +|-----------|-------| +| Registration requests | 10/minute per user | +| Session creation | 10/minute per user | +| Maximum concurrent sessions | 10 per user | +| WebSocket messages | 100/second per connection | +| Prompts | 60/minute per session | +| File uploads | 10/minute per session | + +## Troubleshooting + +### Cannot Register + +- Verify your email domain is in the allowed list +- Check that your JWT token is valid +- Contact support if the issue persists + +### Cannot Create Session + +- Ensure you have Claude credentials stored +- Check you haven't exceeded the maximum session limit (10) +- Verify your profile configuration is valid + +### WebSocket Connection Issues + +- Use the query parameter for JWT if header doesn't work +- Send heartbeats every 30 seconds to keep connection alive +- Check session status—connection only works for `running` sessions + +### Session Crashes + +- Check `max_turns` isn't being exceeded +- Review the error message in session details +- Ensure MCP server configurations are correct diff --git a/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md b/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md index 38b43f54..648052e7 100644 --- a/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md +++ b/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md @@ -343,3 +343,74 @@ Removes a tag from a Hive record. record name: my-rule tag: high-hit ``` + +### start ai session + +Spawns a Claude AI session to perform automated investigation, analysis, or response actions. See [AI Sessions](../../AI_Sessions/index.md) for full documentation. + +```yaml +- action: start ai session + prompt: "Investigate this detection and provide a summary..." + anthropic_secret: hive://secret/my-anthropic-key +``` + +This action launches a fully-managed Claude Code session that can investigate events, query data via MCP servers, and generate reports. + +#### Required Parameters + +| Parameter | Description | +|-----------|-------------| +| `prompt` | Instructions for Claude. Supports [template strings](../../Events/template-strings-and-transforms.md). | +| `anthropic_secret` | Your Anthropic API key. Use `hive://secret/` to reference a [Hive Secret](../../Platform_Management/Config_Hive/config-hive-secrets.md). | + +#### Optional Parameters + +| Parameter | Description | +|-----------|-------------| +| `name` | Session name. Supports template strings. | +| `lc_api_key_secret` | LimaCharlie API key for org-level API access. Use `hive://secret/`. | +| `idempotent_key` | Unique key to prevent duplicate sessions. Supports template strings. | +| `data` | Extract event fields to include in the prompt as JSON. | +| `profile` | Inline session configuration (tools, model, limits, MCP servers). | +| `profile_name` | Reference a saved profile by name. | + +#### Example: Automated Detection Investigation + +```yaml +detect: + event: NEW_PROCESS + op: contains + path: event/COMMAND_LINE + value: mimikatz + +respond: + - action: report + name: mimikatz-detected + - action: start ai session + prompt: | + A Mimikatz-related process was detected. + Investigate the process tree, check for credential dumping activity, + and provide a detailed incident report. + anthropic_secret: hive://secret/anthropic-key + lc_api_key_secret: hive://secret/lc-api-key + idempotent_key: "{{ .detect.detect_id }}" + data: + hostname: "{{ .routing.hostname }}" + process: "{{ .event.FILE_PATH }}" + command_line: "{{ .event.COMMAND_LINE }}" + profile: + allowed_tools: + - Bash + - Read + - Grep + max_turns: 50 + max_budget_usd: 5.0 + mcp_servers: + limacharlie: + type: http + url: https://mcp.limacharlie.io + headers: + Authorization: hive://secret/lc-mcp-token +``` + +For detailed configuration options, see [D&R-Driven AI Sessions](../../AI_Sessions/dr-sessions.md). diff --git a/mkdocs.yml b/mkdocs.yml index 2dce0a94..63a67791 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -164,6 +164,13 @@ nav: - Examples: limacharlie/doc/Detection_and_Response/detection-and-response-examples.md - Alternate Targets: limacharlie/doc/Detection_and_Response/detection-on-alternate-targets.md + - AI Sessions: + - limacharlie/doc/AI_Sessions/index.md + - D&R-Driven Sessions: limacharlie/doc/AI_Sessions/dr-sessions.md + - User Sessions: limacharlie/doc/AI_Sessions/user-sessions.md + - API Reference: limacharlie/doc/AI_Sessions/api-reference.md + - TypeScript SDK: limacharlie/doc/AI_Sessions/sdk.md + - Events & Telemetry: - limacharlie/doc/Events/index.md - Telemetry: limacharlie/doc/Telemetry/index.md From dbed3fc2d9befaf92cf3d93b265aa1047a31d3a5 Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Sun, 4 Jan 2026 10:26:28 -0800 Subject: [PATCH 2/3] fix idempotent key --- .../doc/Detection_and_Response/Reference/response-actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md b/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md index 648052e7..83fbaf3c 100644 --- a/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md +++ b/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md @@ -393,7 +393,7 @@ respond: and provide a detailed incident report. anthropic_secret: hive://secret/anthropic-key lc_api_key_secret: hive://secret/lc-api-key - idempotent_key: "{{ .detect.detect_id }}" + idempotent_key: "{{ .routing.event_id }}" data: hostname: "{{ .routing.hostname }}" process: "{{ .event.FILE_PATH }}" From 858f0581ab478db54511da247c357c8e6d43c45f Mon Sep 17 00:00:00 2001 From: Maxime Date: Mon, 5 Jan 2026 11:21:10 -0800 Subject: [PATCH 3/3] docs: Add one_shot parameter for D&R AI sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the new one_shot profile option for D&R-triggered AI sessions: - Add to profile options table in dr-sessions.md - Add to optional parameters in response-actions.md - Update examples to show one_shot usage One-shot mode causes sessions to complete all work for the initial prompt (including tools, skills, and subagents) before automatically terminating. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- docs/limacharlie/doc/AI_Sessions/dr-sessions.md | 2 ++ .../doc/Detection_and_Response/Reference/response-actions.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/limacharlie/doc/AI_Sessions/dr-sessions.md b/docs/limacharlie/doc/AI_Sessions/dr-sessions.md index f655f112..be2c1375 100644 --- a/docs/limacharlie/doc/AI_Sessions/dr-sessions.md +++ b/docs/limacharlie/doc/AI_Sessions/dr-sessions.md @@ -123,6 +123,7 @@ Profiles let you configure Claude's behavior, available tools, and resource limi model: claude-sonnet-4-20250514 max_turns: 50 max_budget_usd: 5.0 + one_shot: true # Complete initial task then terminate ttl_seconds: 1800 # Environment variables @@ -149,6 +150,7 @@ Profiles let you configure Claude's behavior, available tools, and resource limi | `model` | string | Claude model to use (e.g., `claude-sonnet-4-20250514`) | | `max_turns` | integer | Maximum conversation turns before auto-termination | | `max_budget_usd` | float | Maximum spend limit in USD | +| `one_shot` | boolean | When `true`, session completes all work for the initial prompt (including tools, skills, and subagents) then terminates automatically. Recommended for D&R-triggered sessions. Default: `false` | | `ttl_seconds` | integer | Maximum session lifetime in seconds | | `environment` | map | Environment variables. Values can use `hive://secret/` | | `mcp_servers` | map | MCP server configurations (see below) | diff --git a/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md b/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md index 83fbaf3c..65ce2f6f 100644 --- a/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md +++ b/docs/limacharlie/doc/Detection_and_Response/Reference/response-actions.md @@ -373,6 +373,7 @@ This action launches a fully-managed Claude Code session that can investigate ev | `data` | Extract event fields to include in the prompt as JSON. | | `profile` | Inline session configuration (tools, model, limits, MCP servers). | | `profile_name` | Reference a saved profile by name. | +| `profile.one_shot` | When `true`, session completes initial prompt work then terminates. Recommended for automated sessions. | #### Example: Automated Detection Investigation @@ -405,6 +406,7 @@ respond: - Grep max_turns: 50 max_budget_usd: 5.0 + one_shot: true mcp_servers: limacharlie: type: http