### Full ACP Plugin Configuration Example Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md An example of a complete ACP plugin configuration object. All values shown match the defaults and serve as a documentation reference. ```json { "enabledAgents": "claude,codex", "defaultAgent": "claude", "defaultMode": "persistent", "defaultCwd": "/workspace", "sessionIdleTimeoutMs": 1800000, "sessionMaxAgeMs": 28800000, "maxSessionsPerThread": 5, "reaperIntervalMs": 60000, "sessionRowTtlDays": 30, "peakHourEnabled": true, "peakHourStart": 14, "peakHourEnd": 20, "peakHourTimezone": "Europe/Amsterdam", "peakHourWeekdaysOnly": true, "peakSessionsMax": 2, "peakPriorityThreshold": "high", "maxBudgetUsd": 5.0, "sharedPoolSize": 18, "rateLimitCooldownMs": 300000 } ``` -------------------------------- ### Development Commands Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/README.md Standard commands for installing dependencies, type checking, testing, and building the project. ```bash pnpm install pnpm typecheck pnpm test pnpm build ``` -------------------------------- ### Example Output Event: Text Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/11-cross-plugin-events.md An example of an 'output' event payload representing standard text output from an agent. ```typescript { sessionId: "acp-1718100223456-a3f8c2", type: "text", text: "Starting analysis...", platform: "slack", threadId: "C123456" } ``` -------------------------------- ### Example Output Event: Tool Call Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/11-cross-plugin-events.md An example of an 'output' event payload indicating an agent is making a tool call. ```typescript { sessionId: "acp-1718100223456-a3f8c2", type: "tool_call", toolName: "read_file", toolInput: "{\"path\": \"src/main.ts\"}", platform: "slack", threadId: "C123456" } ``` -------------------------------- ### Example Output Event: Done Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/11-cross-plugin-events.md An example of an 'output' event payload signifying the agent has completed its task. ```typescript { sessionId: "acp-1718100223456-a3f8c2", type: "done", text: "Agent exited with code 0", platform: "slack", threadId: "C123456" } ``` -------------------------------- ### Priority Ranking Comparison Example Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/12-constants-and-metrics.md Illustrates how to compare event priorities against a threshold using the PRIORITY_RANK mapping. This example assumes peak hours are active and a threshold of 'high' is set. ```typescript // During peak hours with threshold="high" PRIORITY_RANK["high"] // 1 PRIORITY_RANK["medium"] // 2 // high (1) <= high (1) → allowed // medium (2) <= high (1) → false, rejected ``` -------------------------------- ### Example: Spawn and Get ACP Session Result Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Demonstrates spawning an ACP session in oneshot mode and then retrieving its result after a delay. Ensure the session ID is correctly passed to acp_result. ```typescript // Spawn in oneshot mode const spawn = await tools.call("acp_spawn", { agent: "claude", mode: "oneshot", prompt: "Summarize the README" }); const sessionId = spawn.data.sessionId; // Wait and fetch result await sleep(5000); const result = await tools.call("acp_result", { sessionId }); // Returns: // { // sessionId: "acp-1718100223456-abc123", // state: "closed", // mode: "oneshot", // exitCode: 0, // output: "The README contains..." // } ``` -------------------------------- ### Spawn Guard Example Usage Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Demonstrates how to use the `checkSpawnGuards` function and handle its result. If `allowed` is false, it logs the reason for the rejection. ```typescript const result = await checkSpawnGuards(ctx, config, { issueId: "issue-abc123", companyId: "company-xyz789", priority: "medium", ... }); if (!result.allowed) { console.log(result.reason); // Output: "Peak hours active — only high+ priority allowed (issue is medium)" } ``` -------------------------------- ### Install paperclip-plugin-acp via npm Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/README.md Install the ACP plugin using npm. This is the standard method for adding the plugin to your project. ```bash npm install paperclip-plugin-acp ``` -------------------------------- ### Registering and Spawning Custom Agents Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Illustrates how to support custom agents by ensuring their executables are installed and in the PATH. The plugin attempts to spawn custom agents using their provided ID. ```typescript // 1. Install the agent's executable (e.g., /usr/local/bin/my-agent) // 2. Use in a spawn request const session = await createSession(ctx, { agentId: "my-agent", // Custom agent mode: "persistent", cwd: "/workspace" }); // 3. The plugin will attempt: spawn("my-agent", args, ...) // 4. If the executable is not found, spawn fails with ENOENT ``` -------------------------------- ### isAgentInstalled Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Checks if an agent's executable is installed and available in the system's PATH. This is a synchronous function and useful for pre-flight checks. ```APIDOC ## isAgentInstalled ### Description Checks whether the agent's executable is installed by running `which {command}`. Useful for pre-flight checks or availability UI. This is a synchronous function that blocks. ### Signature ```typescript function isAgentInstalled(agent: AcpAgentConfig): boolean; ``` ### Parameters #### Path Parameters - **agent** (AcpAgentConfig) - Required - Agent configuration ### Returns - **boolean** - true if the agent's command is in PATH, false otherwise. ### Example ```typescript const agent = getAgent("claude"); if (isAgentInstalled(agent)) { console.log("Claude Code is installed"); } else { console.log("Claude Code not found in PATH"); } ``` ``` -------------------------------- ### Example Event Name Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/11-cross-plugin-events.md Illustrates the naming convention for events emitted by chat platforms, including the platform plugin ID and a suffix. ```plaintext plugin.paperclip-plugin-slack.acp-spawn ``` -------------------------------- ### Example SessionCompleteEvent Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md An example event object for the onSessionComplete hook, detailing the information provided upon session completion, including exit code, duration, and success status. ```typescript { sessionId: "acp-1718100223456-a3f8c2", issueId: "issue-abc123", companyId: "company-xyz789", agentId: "claude", exitCode: 0, durationMs: 45000, promptCount: 3, toolCallCount: 12, success: true, targetStatus: "in_review", summary: "Implemented OAuth2 login with JWT tokens", completedAt: 1718100268456 } ``` -------------------------------- ### 03-tools.md - Agent Tools Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md This section documents the 8 tools that agents can call, including their full signatures and examples. It details the parameters, return types, descriptions, and potential errors for each tool. ```APIDOC ## Agent Tools This document details all 8 tools that agents can call, providing their full signatures, parameter descriptions, return types, and usage examples. ### Tool Signature [Full function/type definition from source] ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Returns - **type**: Description of what the return value represents. ### Description [What the tool does and when to use it] ### Errors/Exceptions [Conditions that trigger errors] ### Code Example [Realistic usage pattern for the tool] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Peak Hour Detection Example Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Demonstrates the usage of `isPeakHour` with a sample configuration. Shows how it returns true for a weekday afternoon but false for a weekend afternoon under the same configuration. ```typescript const config = { peakHourEnabled: true, peakHourStart: 14, peakHourEnd: 20, peakHourTimezone: "Europe/Amsterdam", peakHourWeekdaysOnly: true }; // 3pm Amsterdam time on Tuesday isPeakHour(config); // true // 3pm Amsterdam time on Saturday isPeakHour(config); // false ``` -------------------------------- ### Example ApprovalRequiredEvent Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md An example event object for the onApprovalRequired hook, showcasing the data structure for an approval request, including issue details and the reason for the request. ```typescript { issueId: "issue-abc123", companyId: "company-xyz789", title: "Implement user authentication", description: "Add OAuth2 login flow", deliberationSummary: "Agent completed implementation but wants confirmation before merge", requestedBy: "claude-code", priority: "high", requestedAt: 1718100268456 } ``` -------------------------------- ### acp_spawn Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Starts a new ACP coding agent session with specified parameters like agent type, mode, working directory, and an initial prompt. ```APIDOC ## acp_spawn ### Description Start a new ACP coding agent session. ### Method `acp_spawn` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **agent** (string) - Optional - default: config.defaultAgent - Agent to spawn: claude, codex, gemini, opencode - **mode** (string) - Optional - default: config.defaultMode - persistent or oneshot - **cwd** (string) - Optional - default: config.defaultCwd - Working directory for agent - **prompt** (string) - Optional - initial prompt (optional) ### Response #### Success Response - **success** (boolean) - **sessionId** (string) - **agent** (string) - display name - **mode** (string) - **cwd** (string) ### Errors - `Unknown agent: {agentId}` — Agent name not recognized - `Agent {agentId} is not enabled` — Agent not in enabledAgents config ### Request Example ```typescript const result = await tools.call("acp_spawn", { agent: "claude", mode: "persistent", cwd: "/workspace/project", prompt: "Analyze this codebase" }); // Returns: { success: true, sessionId: "acp-1718100223456-abc123", ... } ``` ``` -------------------------------- ### Example IssueStatusChangeEvent Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md An example event object for the onIssueStatusChange hook, illustrating the data payload when an issue's status changes. ```typescript { issueId: "issue-abc123", companyId: "company-xyz789", previousStatus: "backlog", newStatus: "todo", title: "Implement user authentication", description: "Add OAuth2 login flow", priority: "high", labels: ["feature", "backend"], cwd: "/workspace/auth-service", changedAt: 1718100223456 } ``` -------------------------------- ### Example: Attach a PDF Report to an Issue Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Shows how to read a local file, base64-encode its content, and then attach it to an issue using acp_attach. Ensure the file exists and the issue ID is valid. ```typescript // Read file and base64-encode const fs = require("fs"); const content = fs.readFileSync("report.pdf").toString("base64"); const result = await tools.call("acp_attach", { issueId: "issue-123", filename: "report.pdf", content: content, mimeType: "application/pdf" }); // Returns: // { // success: true, // attachment: { // attachmentId: "att-1718100223456-abc123", // issueId: "issue-123", // filename: "report.pdf", // mimeType: "application/pdf", // sizeBytes: 125432, // url: "/issues/issue-123/attachments/att-1718100223456-abc123", // createdAt: 1718100223456 // } // } ``` -------------------------------- ### Example: List Attachments for a Specific Issue Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Demonstrates how to call the acp_attachments tool with an issue ID to retrieve a list of its attachments. The output includes the count and details of each attachment. ```typescript const result = await tools.call("acp_attachments", { issueId: "issue-123" }); // Returns: // { // issueId: "issue-123", // count: 2, // attachments: [ // { // attachmentId: "att-1718100223456-abc123", // issueId: "issue-123", // filename: "report.pdf", // mimeType: "application/pdf", // sizeBytes: 125432, // url: "/issues/issue-123/attachments/att-1718100223456-abc123", // createdAt: 1718100223456 // }, // { ... } // ] // } ``` -------------------------------- ### Configure Peak Hour Start and End Times Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md Adjust `peakHourStart` and `peakHourEnd` to define the daily window for peak scheduling. These values are based on the configured timezone. ```json { "peakHourStart": 9, "peakHourEnd": 17 } ``` -------------------------------- ### Check if Agent is Installed Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Verifies if an agent's executable command is present in the system's PATH. Useful for pre-flight checks before attempting to use an agent. This is a synchronous operation. ```typescript function isAgentInstalled(agent: AcpAgentConfig): boolean; ``` ```typescript const agent = getAgent("claude"); if (isAgentInstalled(agent)) { console.log("Claude Code is installed"); } else { console.log("Claude Code not found in PATH"); } ``` -------------------------------- ### Reaper Loop Worker Setup Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/10-reaper.md Sets up the interval timer for the reaper loop in the worker process. This loop periodically checks active sessions for reaping conditions. ```typescript const reaperHandle = setInterval(async () => { const now = Date.now(); const activeIds = getActiveSessionIds(); for (const id of activeIds) { if (reapingInFlight.has(id)) continue; // Skip if already reaping reapingInFlight.add(id); try { const sess = await getSession(ctx, id); if (!sess) continue; const reason = computeReapReason(now, sess, idleTimeoutMs, maxAgeMs); if (!reason) continue; ctx.logger.info("Reaping ACP session", { sessionId: id, reason, idleMs: now - (sess.lastActivityAt ?? sess.createdAt ?? 0), ageMs: now - (sess.createdAt ?? 0) }); await reapSessionIfDue(ctx, id, { killSession, now, idleTimeoutMs, maxAgeMs }); } catch (err) { ctx.logger.error("Reaper iteration failed", { sessionId: id, error: String(err) }); } finally { reapingInFlight.delete(id); } } }, reaperIntervalMs); reaperHandle.unref?.(); // Don't keep event loop alive ``` -------------------------------- ### Create New Session Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/05-session-manager.md Creates a new session record and persists it to plugin state. The session starts in a 'spawning' state with the current timestamp. It can optionally be bound to a chat thread. ```typescript const session = await createSession(ctx, { agentId: "claude", mode: "persistent", cwd: "/workspace", binding: { platform: "slack", threadId: "C123456", boundAt: Date.now() } }); // Returns: { sessionId: "acp-1718100223456-a3f8c2", agentId: "claude", ... } ``` -------------------------------- ### Spawn ACP Agent Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Starts a new ACP coding agent session. Use this to initiate an agent with specific configurations like agent type, mode, working directory, and an initial prompt. ```typescript function acp_spawn(params: { agent?: string; // default: config.defaultAgent mode?: string; // default: config.defaultMode cwd?: string; // default: config.defaultCwd prompt?: string; // initial prompt (optional) }): Promise; ``` ```typescript const result = await tools.call("acp_spawn", { agent: "claude", mode: "persistent", cwd: "/workspace/project", prompt: "Analyze this codebase" }); // Returns: { success: true, sessionId: "acp-1718100223456-abc123", ... } ``` -------------------------------- ### 04-configuration.md - Configuration Options Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md This section details all configuration options, environment variables, and their default values for deploying and configuring the plugin. ```APIDOC ## Configuration Options This document outlines all configuration options, environment variables, and their default values for the ACP plugin. ### Option Name - **Type**: [Type of the configuration option] - **Required**: Yes/No - **Default**: [Default value] - **Environment Variable**: [Name of the environment variable, if applicable] ### Description [Description of the configuration option and its purpose] ### Validation [Details on how the option is validated] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### New Session Binding Format (1:N) Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/INDEX.md Details the current format for binding sessions, allowing multiple agents per thread up to a configurable cap. ```text acp_sessions_{chatId}_{threadId} → [sessionEntry, sessionEntry, ...] ``` -------------------------------- ### Merge Configuration with Defaults Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md At startup, the plugin merges provided configuration with orchestration defaults. Explicitly set values override any defaults. ```typescript const config = { ...ORCHESTRATION_DEFAULTS, ...(rawConfig as unknown as Partial), } as AcpConfig; ``` -------------------------------- ### Get In Progress Issue Count Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Queries the Paperclip API to get the count of issues currently in progress for a given company. Returns 0 if the API call fails, allowing spawns to proceed. ```typescript async function getInProgressCount(companyId?: string): Promise; ``` -------------------------------- ### 06-agent-spawn.md - Agent Spawning Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Documentation for subprocess management, including lifecycle, I/O protocol, and related functions. ```APIDOC ## Agent Spawning Functions This document details the functions related to agent subprocess management, including lifecycle and I/O protocol. ### Function Signature [Full function/type definition from source] ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Returns - **type**: Description of what the return value represents. ### Description [What the function does and when to use it] ### Errors/Exceptions [Conditions that trigger errors] ### Code Example [Realistic usage pattern for the function] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Get Rate Limit Cooldown State Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Retrieves a snapshot of the current rate limit cooldown state. ```typescript function getRateLimitCooldown(): RateLimitCooldownState; ``` -------------------------------- ### RateLimitCooldownState Type Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/02-types-reference.md Manages the state of a global rate-limit cooldown, indicating if it's active and its start and expiration times. ```typescript type RateLimitCooldownState = { active: boolean; startedAt: number | null; // epoch ms expiresAt: number | null; // epoch ms triggeredByIssueId: string | null; }; ``` -------------------------------- ### getCircuitBreaker Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Gets or initializes the circuit breaker state for a specific company. This is useful for monitoring and managing the reliability of webhook processing. ```APIDOC ## getCircuitBreaker ### Description Gets or initializes circuit breaker state for a company. ### Method `getCircuitBreaker` ### Parameters #### Path Parameters - **companyId** (string) - Required - The ID of the company. ### Response #### Success Response (WebhookCircuitBreakerState) - **isOpen** (boolean) - Indicates if the circuit breaker is currently open. - **failureCount** (number) - The number of consecutive failures. - **cooldownEnd** (Date | null) - The timestamp when the cooldown period ends, if applicable. ``` -------------------------------- ### 11-cross-plugin-events.md - Cross-Plugin Events Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Documentation for cross-plugin event handling, focusing on chat platform integration, event routing, and multi-tenancy. ```APIDOC ## Cross-Plugin Events This document details cross-plugin event handling, focusing on chat platform integration, event routing, and multi-tenancy. ### Event Name - **Description**: Description of the event and its purpose. - **Routing**: How the event is routed within the system. - **Multi-tenancy**: How multi-tenancy is handled for this event. ### Event Payload - **field1** (type) - Description of the event payload field. ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Get All Circuit Breaker States Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Returns a snapshot of the current state for all active circuit breakers, useful for health endpoints. ```typescript function getCircuitBreakerStates(): Record; ``` -------------------------------- ### ACP Plugin Architecture Overview Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md This diagram illustrates the high-level architecture of the ACP plugin, showing its interaction with the Paperclip Event Bus, Agents, Plugin State, PostgreSQL, and the Filesystem. ```text Chat Platform → Paperclip Event Bus → ACP Plugin ↔ Agents (subprocesses) ↓ Plugin State (sessions) PostgreSQL (metrics) Filesystem (attachments) ``` -------------------------------- ### Old Session Binding Format (1:1) Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/INDEX.md Illustrates the previous format for binding sessions to chat threads, where each thread had a single session. ```text acp_{chatId}_{threadId} → sessionId ``` -------------------------------- ### Get or Initialize Circuit Breaker State Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Retrieves the current circuit breaker state for a given company or initializes it if it doesn't exist. ```typescript function getCircuitBreaker(companyId: string): WebhookCircuitBreakerState; ``` -------------------------------- ### Get Active Session IDs Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/06-agent-spawn.md Returns an array of session IDs for all currently active agent processes. Used for monitoring and reaper loops. ```typescript const activeIds = getActiveSessionIds(); console.log(`${activeIds.length} sessions active`); ``` -------------------------------- ### Get Thread Sessions Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/05-session-manager.md Retrieves all session entries for a given thread. Handles migration from legacy session formats to the new 1:N format. ```typescript async function getThreadSessions( ctx: PluginContext, chatId: string, threadId: string ): Promise; const sessions = await getThreadSessions(ctx, "telegram", "12345"); // Returns: [ // { // sessionId: "acp-1718100223456-a3f8c2", // agentName: "claude", // agentDisplayName: "Claude Code", // spawnedAt: 1718100223456, // status: "active" // } // ] ``` -------------------------------- ### 09-webhook-hooks.md - Webhook Hooks Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Documentation for webhook hooks, including event-driven spawning, orchestration guards, and circuit breaker patterns. ```APIDOC ## Webhook Hooks This document details webhook hooks, including event-driven spawning, orchestration guards, and circuit breaker patterns. ### Hook Definition [Description of the webhook hook and its purpose] ### Event Triggers - **Event Name**: Description of the event that triggers the hook. ### Actions - **Action Type**: Description of the action performed by the hook. ### Configuration [Configuration options specific to the webhook hook] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Get ACP Session Status Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Retrieves a list of all active ACP sessions and their current states. Useful for monitoring and managing ongoing agent processes. ```typescript function acp_status(): Promise; ``` ```typescript const result = await tools.call("acp_status"); // Returns: // { // activeSessions: 2, // sessions: [ // { // sessionId: "acp-1718100223456-abc123", // agent: "claude", // mode: "persistent", // state: "active", // cwd: "/workspace", // uptime: 245, // idleFor: 12, // binding: "slack:C123456" // }, // { ... } // ] // } ``` -------------------------------- ### Get Attachment Metadata Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/08-attachment-manager.md Retrieves attachment metadata from plugin state using its ID. Does not read the file content. Returns null if the attachment is not found. ```typescript async function getAttachment( ctx: PluginContext, attachmentId: string ): Promise; const attachment = await getAttachment(ctx, "att-1718100223456-a3f8c2"); if (attachment) { console.log(attachment.filename, attachment.mimeType, attachment.sizeBytes); // Output: hello.txt text/plain 13 } ``` -------------------------------- ### createSession Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/05-session-manager.md Creates a new session record, persists it, and initializes it in the 'spawning' state. It can optionally bind the session to a chat thread. ```APIDOC ## createSession ### Description Creates a new session record and persists it to plugin state under the key `acp-session:{sessionId}`. The session starts in the "spawning" state with the current timestamp. ### Signature ```typescript async function createSession( ctx: PluginContext, params: { agentId: AcpAgentId; mode: AcpSessionMode; cwd: string; binding?: AcpBinding; } ): Promise; ``` ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A #### Parameters - **ctx** (PluginContext) - Required - Paperclip plugin context - **params** ({ agentId: AcpAgentId, mode: AcpSessionMode, cwd: string, binding?: AcpBinding }) - Required - Parameters for session creation - **agentId** (AcpAgentId) - Required - Agent to run - **mode** (AcpSessionMode) - Required - persistent or oneshot - **cwd** (string) - Required - Working directory - **binding** (AcpBinding) - Optional - Chat thread binding ### Returns The newly created `AcpSession` object. ### Example ```typescript const session = await createSession(ctx, { agentId: "claude", mode: "persistent", cwd: "/workspace", binding: { platform: "slack", threadId: "C123456", boundAt: Date.now() } }); // Returns: { sessionId: "acp-1718100223456-a3f8c2", agentId: "claude", ... } ``` ``` -------------------------------- ### Get a Specific Agent Configuration Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Retrieves the configuration for a specific agent by its ID. Returns undefined if the agent ID is not found among the built-in agents. ```typescript const agent = getAgent("claude"); if (agent) { console.log(`Agent: ${agent.displayName}`); // Output: Agent: Claude Code } const unknown = getAgent("unknown-agent"); // Returns: undefined ``` -------------------------------- ### Attachment Configuration Defaults and Prefixes Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/12-constants-and-metrics.md Constants for default attachment storage, size limits, and state/index key prefixes. Limits are enforced during attachment creation. ```typescript export const ATTACHMENT_DEFAULTS = { storageDir: "/tmp/paperclip-attachments", maxFileSizeBytes: 25 * 1024 * 1024, // 25 MB maxAttachmentsPerIssue: 50 } as const; export const ATTACHMENT_STATE_PREFIX = "acp-attachment:"; export const ATTACHMENT_INDEX_PREFIX = "acp-attachments-index:"; export const ATTACHMENT_METRIC_NAMES = { attachmentsCreated: "acp.attachments.created", attachmentsListed: "acp.attachments.listed", attachmentErrors: "acp.attachments.errors" } as const; ``` -------------------------------- ### List All Available Built-In Agents Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Retrieves an array containing the configurations of all built-in agents. This is useful for populating UI elements like dropdowns or for checking agent availability. ```typescript const agents = listAgents(); agents.forEach((agent) => { console.log(`- ${agent.displayName}: ${agent.description}`); }); // Output: // - Claude Code: Anthropic's Claude Code CLI - full coding agent... // - Codex CLI: OpenAI's Codex CLI - coding agent with sandbox execution. // - Gemini CLI: Google's Gemini CLI - coding agent with Gemini models. // - OpenCode: Open-source terminal coding agent. ``` -------------------------------- ### Default Configuration Constants Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/12-constants-and-metrics.md Provides fallback values for plugin configuration. These can be overridden by instance-specific configurations. ```typescript export const DEFAULT_CONFIG = { enabledAgents: "claude,codex,gemini,opencode", defaultAgent: "claude", defaultMode: "persistent" as const, defaultCwd: "/workspace", sessionIdleTimeoutMs: 30 * 60 * 1000, // 30 minutes sessionMaxAgeMs: 8 * 60 * 60 * 1000, // 8 hours maxSessionsPerThread: 5, reaperIntervalMs: 60 * 1000, // 1 minute sessionRowTtlDays: 30 }; ``` -------------------------------- ### ACP Spawn Event Flow Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Illustrates the sequence of events when a user initiates an agent spawn command via the chat plugin. ```text User: /acp spawn claude ↓ Chat Plugin: emit acp-spawn ↓ ACP Plugin: handleSpawn() → create session → spawnAgent() ↓ Agent Subprocess: emit NDJSON ↓ ACP Plugin: parseOutput() → emit output event ↓ Chat Plugin: route to thread ↓ User: sees agent output ``` -------------------------------- ### 10-reaper.md - Reaper Functions Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Documentation for the Reaper, covering idle timeout and cleanup functions. ```APIDOC ## Reaper Functions This document details the functions related to idle timeout and cleanup managed by the Reaper. ### Function Signature [Full function/type definition from source] ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Returns - **type**: Description of what the return value represents. ### Description [What the function does and when to use it] ### Errors/Exceptions [Conditions that trigger errors] ### Code Example [Realistic usage pattern for the function] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Plugin to Agent stdin Prompts Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/06-agent-spawn.md Shows the text-based prompt format used for communication from the ACP plugin to the agent via stdin in persistent mode. Each prompt is sent on a new line. ```text Analyze the structure of this project Now implement the missing function ``` -------------------------------- ### getInProgressCount Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Queries the Paperclip API to get the count of issues with the status 'in_progress' for a given company. If the API call fails, it returns 0 to allow the spawn process to proceed. ```APIDOC ## getInProgressCount ### Description Queries Paperclip API for count of issues with status "in_progress". Returns total count. ### Endpoint `{PAPERCLIP_API_BASE}/issues?status=in_progress&company_id={companyId}` ### Fails Open If API call fails, returns 0. ``` -------------------------------- ### sendPrompt Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/06-agent-spawn.md Writes a prompt to the stdin of an active persistent-mode agent session. It updates the session's last activity timestamp and logs a metric. Returns false if the session is not active or its stdin is not writable. ```APIDOC ## sendPrompt ### Description Writes a prompt to the subprocess stdin. Updates `lastActivityAt` timestamp and logs metric. Returns false if the session is not in the active process map or stdin is not writable. This function only works with persistent-mode sessions. ### Signature ```typescript async function sendPrompt( ctx: PluginContext, sessionId: string, text: string ): Promise; ``` ### Parameters #### Path Parameters - **ctx** (PluginContext) - Required - Paperclip plugin context - **sessionId** (string) - Required - Session to send to - **text** (string) - Required - Prompt text ### Returns true if prompt was sent, false if session not active. ### Constraints Only works with persistent-mode sessions. For oneshot sessions, the initial prompt must be passed to `spawnAgent()`. ### Example ```typescript const sent = await sendPrompt(ctx, sessionId, "Now implement the feature"); if (!sent) { console.log("Session not active or closed"); } ``` ``` -------------------------------- ### Event Listener for acp-spawn Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/11-cross-plugin-events.md Sets up an event listener for the 'acp-spawn' event across all configured chat platform plugins. ```typescript for (const platformPlugin of CHAT_PLATFORM_PLUGINS) { ctx.events.on( `plugin.${platformPlugin}.acp-spawn`, async (rawEvent) => { const event = rawEvent.payload as AcpSpawnEvent; await handleSpawn(ctx, config, enabledAgents, event, platformPlugin); } ); } ``` -------------------------------- ### Set Maximum Subscription Budget Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md The `maxBudgetUsd` setting is a placeholder for maximum USD budget tracking for subscription usage. Currently, it is not enforced by consumers. ```json { "maxBudgetUsd": 10.0 } ``` -------------------------------- ### Set PostgreSQL Connection String Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md Set the NEXUS_METRICS_DB environment variable to specify the PostgreSQL connection string for performance records. The plugin requires write access to this database. ```bash export NEXUS_METRICS_DB=postgresql://user:pass@db.example.com:5432/nexus_metrics ``` -------------------------------- ### Get ACP Session Result Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/03-tools.md Fetches the final stdout and exit code for a completed one-shot ACP session. Use this to retrieve results without needing to poll the session status. ```typescript function acp_result(params: { sessionId: string; }): Promise; ``` -------------------------------- ### Get Attachment Index for Issue Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/08-attachment-manager.md Retrieves a list of attachment IDs associated with a specific issue from plugin state. Used for enforcing per-issue limits and enumerating attachments. Returns an empty array if no attachments are found. ```typescript async function getAttachmentIndex( ctx: PluginContext, issueId: string ): Promise; const ids = await getAttachmentIndex(ctx, "issue-123"); console.log(`Issue has ${ids.length} attachments`); // Output: Issue has 2 attachments ``` -------------------------------- ### Configure Rate Limit Cooldown Duration Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md Set `rateLimitCooldownMs` to define the duration, in milliseconds, for which spawns are halted after a rate-limit error is detected. The default is 5 minutes. ```json { "rateLimitCooldownMs": 600000 } ``` -------------------------------- ### listAgents Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Retrieves a list of all available built-in agent configurations. This is useful for populating UI elements like dropdowns or for checking agent availability. ```APIDOC ## listAgents ### Description Returns all available agents. Useful for UI dropdowns or availability checks. ### Signature ```typescript function listAgents(): AcpAgentConfig[]; ``` ### Returns Array of all built-in agent configurations. ### Example ```typescript const agents = listAgents(); agents.forEach((agent) => { console.log(`- ${agent.displayName}: ${agent.description}`); }); ``` ``` -------------------------------- ### Ensure Issue Directory Exists Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/08-attachment-manager.md Creates the storage directory for a specific issue if it does not already exist. Returns the resolved path to the directory. ```typescript const dir = await ensureIssueDir("/tmp/attachments", "issue-123"); // /tmp/attachments/issue-123 created if missing ``` -------------------------------- ### 05-session-manager.md - Session Management Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Documentation for the Session Manager, covering Session CRUD operations, 1:N thread binding, and lazy migration. ```APIDOC ## Session Management Functions This document details the functions for managing sessions, including CRUD operations, 1:N thread binding, and lazy migration. ### Function Signature [Full function/type definition from source] ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Returns - **type**: Description of what the return value represents. ### Description [What the function does and when to use it] ### Errors/Exceptions [Conditions that trigger errors] ### Code Example [Realistic usage pattern for the function] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Set Minimum Priority for Peak Hour Spawning Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md Use `peakPriorityThreshold` to define the minimum priority level for spawning issues during peak hours. Only issues with this priority or higher will be spawned. ```json { "peakPriorityThreshold": "critical" } ``` -------------------------------- ### detectRateLimitInText Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Searches provided text for common rate-limit indicators using a set of predefined regular expressions. Returns true if any pattern matches. ```APIDOC ## detectRateLimitInText ### Description Searches text for regex patterns indicating a rate limit. ### Method `detectRateLimitInText` ### Parameters #### Path Parameters - **text** (string) - Required - The text to search within. ``` -------------------------------- ### 12-constants-and-metrics.md - Constants and Metrics Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md This section lists constants and metric names used for monitoring and internal operations within the plugin. ```APIDOC ## Constants and Metrics This document lists constants and metric names used for monitoring and internal operations. ### Constant Name - **Value**: [The value of the constant] - **Description**: [Description of the constant's purpose] ### Metric Name - **Description**: [Description of the metric and what it measures] - **Unit**: [Unit of measurement, if applicable] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### Listen for Output Events Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/INDEX.md This snippet shows how to listen for 'output' events and filter them by company ID to route messages within a chat. ```typescript ctx.events.on("output", (event) => { if (event.companyId !== myCompanyId) return; // Route to thread in chat }); ``` -------------------------------- ### AcpSpawnRequest Type Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/02-types-reference.md Parameters for creating a new session. Optional fields like mode and cwd will fall back to configuration defaults. Includes agent ID, mode, working directory, binding, and initial prompt. ```typescript type AcpSpawnRequest = { agentId: AcpAgentId; mode?: AcpSessionMode; // default: config.defaultMode cwd?: string; // default: config.defaultCwd binding?: AcpBinding; initialPrompt?: string; }; ``` -------------------------------- ### Export Plugin Manifest Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/01-api-overview.md This code snippet shows how the plugin manifest is exported from the main entry point of the package. It's used by Paperclip during plugin initialization. ```typescript // src/index.ts export { default as manifest } from "./manifest.js"; ``` -------------------------------- ### Parse Enabled Agents from Configuration String Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/07-agents.md Parses a comma-separated string of agent IDs to retrieve their configurations. Unknown agent IDs are silently ignored. If the input string is null or empty, it defaults to listing all built-in agents. ```typescript const enabled = parseEnabledAgents("claude,gemini"); console.log(enabled.length); // 2 console.log(enabled[0].displayName); // "Claude Code" const withUnknown = parseEnabledAgents("claude,unknown,codex"); console.log(withUnknown.length); // 2 (unknown filtered out) const defaulted = parseEnabledAgents(null); console.log(defaulted.length); // 4 (all four agents) ``` -------------------------------- ### 02-types-reference.md - Type Definitions Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md This document provides a reference for all type definitions used within the plugin, categorized by domain. It includes request and response types for agent interactions. ```APIDOC ## Type Definitions This document lists all type definitions used in the plugin, including request and response types for agent interactions. Types are grouped by domain for clarity. ### Type Name - **Type Definition**: [Exact type definition from source] ### Description [Description of the type and its purpose] ### Fields - **field1** (type) - Required/Optional - Description ### Source Reference [File path and line number(s)] ``` -------------------------------- ### checkSpawnGuards Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Executes a series of orchestration checks to determine if a spawn should be allowed. It includes rate-limit cooldown, session cap checks, and peak-hour priority filtering. ```APIDOC ## checkSpawnGuards ### Description Runs all orchestration checks in order: Rate-limit cooldown, Session cap, and Peak-hour priority filter. Rejects the spawn if any guard condition is met. ### Method `checkSpawnGuards(ctx: PluginContext, config: WebhookHookConfig, event: IssueStatusChangeEvent): Promise` ### Parameters - **ctx** (PluginContext) - Context for the plugin. - **config** (WebhookHookConfig) - Configuration for the webhook hook. - **event** (IssueStatusChangeEvent) - The event data, including issue details. ### Returns - **allowed** (boolean) - Indicates if the spawn is allowed. - **reason** (string) - Optional reason for rejection. - **routineRunStatus** ("skipped" | "failed") - Status of routine checks. - **reasonCode** ("session_cap_exhausted" | "company_cap_exhausted" | "peak_hour_deferred" | "rate_limit_cooldown" | "rate_limited") - Code indicating the reason for rejection. ### Example ```typescript const result = await checkSpawnGuards(ctx, config, { issueId: "issue-abc123", companyId: "company-xyz789", priority: "medium", ... }); if (!result.allowed) { console.log(result.reason); // Output: "Peak hours active — only high+ priority allowed (issue is medium)" } ``` ``` -------------------------------- ### 07-agents.md - Agent Catalog Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/00-README.md Documentation for the agent catalog, including functions for managing and interacting with built-in agents. ```APIDOC ## Agent Catalog Functions This document details the functions for managing the agent catalog and interacting with built-in agents. ### Function Signature [Full function/type definition from source] ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Returns - **type**: Description of what the return value represents. ### Description [What the function does and when to use it] ### Errors/Exceptions [Conditions that trigger errors] ### Code Example [Realistic usage pattern for the function] ### Source Reference [File path and line number(s)] ``` -------------------------------- ### List Attachments for an Issue Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/08-attachment-manager.md Lists all attachments for a given issue. It fetches the index and then retrieves metadata for each attachment. Skips attachments that do not exist in the state. ```typescript const attachments = await listAttachments(ctx, "issue-123"); attachments.forEach((att) => { console.log(`${att.filename} (${att.sizeBytes} bytes)`); }); ``` -------------------------------- ### onApprovalRequired Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/09-webhook-hooks.md Triggered when an approval decision is needed. Emits the event to Cockpit for presentation to humans. It logs the approval request, emits a cockpit event, and records a metric. ```APIDOC ## onApprovalRequired ### Description Triggered when an approval decision is needed. Emits the event to Cockpit for presentation to humans. ### Method async function ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **ctx** (PluginContext) - Required - Paperclip plugin context * **event** (ApprovalRequiredEvent) - Required - Approval request event ### Request Example ```json { "issueId": "issue-abc123", "companyId": "company-xyz789", "title": "Implement user authentication", "description": "Add OAuth2 login flow", "deliberationSummary": "Agent completed implementation but wants confirmation before merge", "requestedBy": "claude-code", "priority": "high", "requestedAt": 1718100268456 } ``` ### Response #### Success Response (void) void (async) #### Response Example None (void return type) ``` -------------------------------- ### Set Global Session Pool Size Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/04-configuration.md Configure `sharedPoolSize` to establish the global cap on concurrent in-progress sessions across all companies. Spawn guards enforce this limit. ```json { "sharedPoolSize": 10 } ``` -------------------------------- ### Webhook Configuration Constants Source: https://github.com/mvanhorn/paperclip-plugin-acp/blob/main/_autodocs/12-constants-and-metrics.md Defines statuses that trigger agent spawns and parameters for a webhook circuit breaker. ```typescript export const SPAWN_TRIGGER_STATUSES = ["todo", "in_progress"] as const; export const WEBHOOK_CIRCUIT_BREAKER_THRESHOLD = 3; export const WEBHOOK_CIRCUIT_BREAKER_COOLDOWN_MS = 10 * 60 * 1000; // 10 minutes ```