kartman-dev 1.0.0-dev.0 → 1.0.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. package/dist/claude-config/_mcp.json +5 -2
  2. package/dist/index.js +21 -3
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -1
  5. package/dist/claude-config/worktrees/polymorphic-cooking-goose/.claude/.claude-plugin/plugin.json +0 -11
  6. package/dist/claude-config/worktrees/polymorphic-cooking-goose/.claude/.mcp.json +0 -23
  7. package/dist/claude-config/worktrees/polymorphic-cooking-goose/.claude/settings.json +0 -13
  8. package/dist/claude-config/worktrees/polymorphic-cooking-goose/.claude/skills/doc-drift-check/SKILL.md +0 -140
  9. package/dist/claude-config/worktrees/polymorphic-cooking-goose/.claude/skills/doc-drift-check/references/severity-guide.md +0 -174
  10. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/.claude-plugin/plugin.json +0 -11
  11. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/.mcp.json +0 -23
  12. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/commands/linear-issue.md +0 -59
  13. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/commands/linear-project.md +0 -70
  14. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/settings.json +0 -13
  15. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/skills/doc-drift-check/SKILL.md +0 -140
  16. package/dist/claude-config/worktrees/valiant-sparking-hare/.claude/skills/doc-drift-check/references/severity-guide.md +0 -174
  17. package/dist/claude-config/worktrees/valiant-sparking-hare/.github/workflows/claude-code-review.yml +0 -32
  18. package/dist/claude-config/worktrees/valiant-sparking-hare/.github/workflows/claude.yml +0 -37
  19. package/dist/claude-config/worktrees/valiant-sparking-hare/.nvmrc +0 -1
  20. package/dist/claude-config/worktrees/valiant-sparking-hare/.prettierignore +0 -11
@@ -15,9 +15,12 @@
15
15
  "Notion-Version": "2025-09-03"
16
16
  }
17
17
  },
18
- "context7": {
18
+ "laminar": {
19
19
  "command": "npx",
20
- "args": ["-y", "@upstash/context7-mcp", "--api-key", "${CONTEXT7_API_KEY}"]
20
+ "args": ["-y", "@lmnr-ai/lmnr-mcp-server"],
21
+ "env": {
22
+ "LMNR_PROJECT_API_KEY": "${LMNR_PROJECT_API_KEY}"
23
+ }
21
24
  },
22
25
  "nia": {
23
26
  "type": "http",
package/dist/index.js CHANGED
@@ -13,8 +13,9 @@ import { LinearClient } from "@linear/sdk";
13
13
  import * as fs from "fs";
14
14
  import * as path from "path";
15
15
  import {
16
- query
16
+ query as origQuery
17
17
  } from "@anthropic-ai/claude-agent-sdk";
18
+ import { Laminar } from "@lmnr-ai/lmnr";
18
19
 
19
20
  // src/config.ts
20
21
  import { appendFileSync, cpSync, existsSync, mkdirSync, readFileSync, renameSync } from "fs";
@@ -62,6 +63,12 @@ ${PLUGIN_DIRNAME}/
62
63
  }
63
64
 
64
65
  // src/agent.ts
66
+ if (process.env.LMNR_PROJECT_API_KEY) {
67
+ Laminar.initialize({
68
+ projectApiKey: process.env.LMNR_PROJECT_API_KEY
69
+ });
70
+ }
71
+ var query = process.env.LMNR_PROJECT_API_KEY ? Laminar.wrapClaudeAgentQuery(origQuery) : origQuery;
65
72
  var Agent = class {
66
73
  currentSessionId;
67
74
  isRunning = false;
@@ -446,6 +453,7 @@ function createAgent(platform, sessionId) {
446
453
  }
447
454
 
448
455
  // src/callback.ts
456
+ import { Laminar as Laminar2 } from "@lmnr-ai/lmnr";
449
457
  async function sendSessionUpdate(callbackUrl, callbackSecret, update) {
450
458
  try {
451
459
  const response = await fetch(callbackUrl, {
@@ -476,17 +484,27 @@ async function reportResult(callbackUrl, externalSessionId, result) {
476
484
  state: "running" /* Running */
477
485
  });
478
486
  }
487
+ let traceId;
488
+ if (process.env.LMNR_PROJECT_API_KEY) {
489
+ try {
490
+ traceId = Laminar2.getCurrentTraceId() ?? void 0;
491
+ } catch (error) {
492
+ console.error("[callback] Failed to get Laminar trace ID:", error);
493
+ }
494
+ }
479
495
  if (result.error) {
480
496
  await sendSessionUpdate(callbackUrl, callbackSecret, {
481
497
  externalSessionId,
482
498
  state: "error" /* Error */,
483
- error: result.error
499
+ error: result.error,
500
+ traceId
484
501
  });
485
502
  } else if (!result.interrupted) {
486
503
  await sendSessionUpdate(callbackUrl, callbackSecret, {
487
504
  externalSessionId,
488
505
  claudeSessionId: result.sessionId,
489
- state: "completed" /* Completed */
506
+ state: "completed" /* Completed */,
507
+ traceId
490
508
  });
491
509
  }
492
510
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/start.ts","../src/linear/agent.ts","../src/agent.ts","../src/config.ts","../src/factory.ts","../src/callback.ts","../src/commands/stop.ts","../src/commands/resume.ts","../src/commands/init.ts","../src/commands/update.ts"],"sourcesContent":["import { Command } from 'commander';\nimport startCommand from './commands/start';\nimport { stopCommand } from './commands/stop';\nimport { resumeCommand } from './commands/resume';\nimport { initCommand } from './commands/init';\nimport { updateCommand } from './commands/update';\n\nconst program = new Command();\n\nprogram\n .name('kartman')\n .description('CLI for running Claude agents in Vercel sandboxes')\n .version('0.1.0');\n\nprogram.addCommand(initCommand);\nprogram.addCommand(startCommand);\nprogram.addCommand(stopCommand);\nprogram.addCommand(resumeCommand);\nprogram.addCommand(updateCommand);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport { createAgent, type Platform } from '@/factory';\nimport { reportResult } from '@/callback';\nimport type { AgentRunResult } from '@/agent';\n\nconst startCommand = new Command('start')\n .description('Start a new agent session')\n .requiredOption('--platform <platform>', 'Platform type (linear)')\n .requiredOption('--session-id <id>', 'External session ID (e.g., Linear session ID)')\n .requiredOption('--prompt <prompt>', 'Initial prompt for the agent')\n .option('--callback-url <url>', 'Server callback URL for session updates')\n .option('--working-dir <dir>', 'Working directory', process.cwd())\n .action(async (options) => {\n const { platform, sessionId, prompt, callbackUrl, workingDir } = options;\n\n try {\n console.log(`[CLI.start] sessionId=${sessionId} | cwd=${workingDir}`);\n console.log(`[CLI.start] prompt=${prompt.substring(0, 300)}...`);\n\n const agent = createAgent(platform as Platform, sessionId);\n\n const result = await agent.run({\n prompt,\n cwd: workingDir,\n });\n\n await reportResult(callbackUrl, sessionId, result);\n\n console.log(JSON.stringify({\n status: result.error ? 'error' : (result.interrupted ? 'interrupted' : 'completed'),\n claudeSessionId: result.sessionId,\n result: result.result,\n error: result.error,\n }));\n\n process.exit(result.error ? 1 : 0);\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n await reportResult(callbackUrl, sessionId, { sessionId: '', error: errorMessage } as AgentRunResult);\n console.error(JSON.stringify({ status: 'error', error: errorMessage }));\n process.exit(1);\n }\n });\n\nexport default startCommand;\n","import { LinearClient } from '@linear/sdk';\nimport type { SDKResultMessage } from '@anthropic-ai/claude-agent-sdk';\nimport {\n Agent,\n type PlanStep,\n type TextBlock,\n type ToolUseBlock,\n} from '@/agent';\n\nexport interface LinearAgentConfig {\n linearAccessToken: string;\n linearSessionId: string;\n}\n\nenum LinearActivityType {\n\tThought = 'thought',\n\tAction = 'action',\n\tResponse = 'response',\n\tError = 'error',\n\tElicitation = 'elicitation',\n}\n\nexport class LinearAgent extends Agent {\n private linearClient: LinearClient;\n private linearSessionId: string;\n private lastThoughtTime = 0;\n private thoughtDebounceMs = 1000;\n private isCompleted = false;\n\n constructor(config: LinearAgentConfig) {\n super(config.linearSessionId);\n this.linearClient = new LinearClient({ accessToken: config.linearAccessToken });\n this.linearSessionId = config.linearSessionId;\n }\n\n protected async onStart(): Promise<void> {\n await this.sendActivity(LinearActivityType.Thought, 'Starting work...', true);\n }\n\n protected async onThinking(block: TextBlock, isSubagent: boolean): Promise<void> {\n if (this.isCompleted) return;\n\n const now = Date.now();\n if (now - this.lastThoughtTime < this.thoughtDebounceMs) return;\n this.lastThoughtTime = now;\n\n const content = block.text;\n if (content.length < 20) return;\n\n await this.sendActivity(LinearActivityType.Thought, content, false);\n }\n\n /** Tools that should show immediately on use (not wait for result) */\n private static SHOW_ON_USE = new Set(['Task', 'Read', 'Grep', 'Glob', 'WebSearch', 'WebFetch']);\n\n protected async onToolUse(block: ToolUseBlock, isSubagent: boolean): Promise<void> {\n if (this.isCompleted) return;\n if (!LinearAgent.SHOW_ON_USE.has(block.name)) return;\n\n if (block.name === 'Task') {\n const subagentType = String((block.input as Record<string, unknown>).subagent_type ?? 'subagent');\n await this.sendActionActivity('Delegating', subagentType, undefined, false);\n return;\n }\n\n const { action, parameter } = this.formatToolAction(block);\n await this.sendActionActivity(action, parameter, undefined, isSubagent);\n }\n\n protected async onToolResult(block: ToolUseBlock, result: string, isSubagent: boolean): Promise<void> {\n if (this.isCompleted) return;\n // Skip tools already shown in onToolUse\n if (LinearAgent.SHOW_ON_USE.has(block.name)) return;\n\n const { action, parameter } = this.formatToolAction(block);\n const truncatedResult = result.length > 1000 ? result.substring(0, 1000) + '...' : result;\n await this.sendActionActivity(action, parameter, truncatedResult || undefined, isSubagent);\n }\n\n protected async onPlanUpdate(steps: PlanStep[], isSubagent: boolean): Promise<void> {\n if (steps.length === 0) return;\n\n const linearSteps = steps.map(step => ({\n content: step.content,\n status: this.mapStatusToLinear(step.status),\n }));\n\n try {\n await this.linearClient.updateAgentSession(this.linearSessionId, {\n plan: linearSteps,\n });\n } catch (error) {\n console.error('Failed to update Linear plan:', error);\n }\n }\n\n protected async onComplete(message: SDKResultMessage): Promise<void> {\n this.isCompleted = true;\n\n const text = message.subtype === 'success' && message.result\n ? message.result\n : 'Task completed successfully.';\n await this.sendActivity(LinearActivityType.Response, text, false);\n }\n\n protected async onError(error: Error): Promise<void> {\n this.isCompleted = true;\n await this.sendActivity(LinearActivityType.Error, `Error: ${error.message}`, false);\n }\n\n\tprotected async onStop(): Promise<void> {\n\t\tthis.isCompleted = true;\n\t\tawait this.sendActivity(LinearActivityType.Response, 'Session stopped', false);\n\t}\n\n // ============================================\n // Helper methods\n // ============================================\n\n private async sendActivity(\n type: LinearActivityType,\n body: string,\n ephemeral: boolean\n ): Promise<void> {\n try {\n await this.linearClient.createAgentActivity({\n agentSessionId: this.linearSessionId,\n content: { type, body },\n ephemeral,\n });\n } catch (error) {\n console.error('Failed to send Linear activity:', error);\n }\n }\n\n private async sendActionActivity(\n action: string,\n parameter: string,\n result: string | undefined,\n ephemeral: boolean\n ): Promise<void> {\n try {\n const content: Record<string, string> = {\n type: LinearActivityType.Action,\n action,\n parameter,\n };\n if (result) content.result = result;\n\n await this.linearClient.createAgentActivity({\n agentSessionId: this.linearSessionId,\n content,\n ephemeral,\n });\n } catch (error) {\n console.error('Failed to send Linear activity:', error);\n }\n }\n\n private formatToolAction(block: ToolUseBlock): { action: string; parameter: string } {\n const { name, input } = block;\n const params = input as Record<string, unknown>;\n\n switch (name) {\n case 'Write':\n return { action: 'Creating file', parameter: String(params.file_path ?? '') };\n\n case 'Edit':\n return { action: 'Editing file', parameter: String(params.file_path ?? '') };\n\n case 'Read':\n return { action: 'Reading file', parameter: String(params.file_path ?? '') };\n\n case 'Bash': {\n const cmd = String(params.command ?? '');\n return { action: 'Running command', parameter: cmd.length > 80 ? cmd.substring(0, 80) + '...' : cmd };\n }\n\n case 'Grep':\n return { action: 'Searching', parameter: String(params.pattern ?? '') };\n\n case 'Glob':\n return { action: 'Finding files', parameter: String(params.pattern ?? '') };\n\n case 'Task':\n return { action: 'Delegating', parameter: String(params.subagent_type ?? 'subagent') };\n\n case 'Skill':\n return { action: 'Using skill', parameter: String(params.skill ?? '') };\n\n default:\n return { action: name, parameter: JSON.stringify(params).substring(0, 100) };\n }\n }\n\n private mapStatusToLinear(\n status: PlanStep['status']\n ): 'pending' | 'inProgress' | 'completed' | 'canceled' {\n switch (status) {\n case 'in_progress': return 'inProgress';\n case 'completed': return 'completed';\n case 'canceled': return 'canceled';\n case 'pending':\n default: return 'pending';\n }\n }\n}\n\n\nexport const createLinearAgent = (sessionId: string) => {\n\tconst linearAccessToken = process.env.LINEAR_ACCESS_TOKEN;\n\tif (!linearAccessToken) {\n\t\tthrow new Error('Linear access token is missing');\n\t}\n\n\treturn new LinearAgent({ linearAccessToken, linearSessionId: sessionId })\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n query,\n type Query,\n type Options,\n type SDKAssistantMessage,\n type SDKUserMessage,\n type SDKResultMessage,\n type SDKSystemMessage,\n} from '@anthropic-ai/claude-agent-sdk';\nimport type { TextBlock, ToolUseBlock, ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages';\nimport { getPluginPath } from './config.js';\n\n/**\n * Plan step for tracking progress\n */\nexport interface PlanStep {\n content: string;\n status: 'pending' | 'in_progress' | 'completed' | 'canceled';\n}\n\n/**\n * Agent run options\n */\nexport interface AgentRunOptions {\n prompt: string;\n sessionId?: string; // SDK session ID for resumption\n resumeSession?: boolean; // Whether to resume existing session\n forkSession?: boolean; // Whether to fork when resuming\n cwd?: string; // Working directory\n options?: Partial<Options>; // Additional SDK options\n}\n\n/**\n * Agent run result\n */\nexport interface AgentRunResult {\n sessionId: string;\n result?: string;\n error?: string;\n interrupted?: boolean;\n}\n\n/**\n * Base Agent class\n *\n * Runs Claude Agent SDK and calls event methods for each message type.\n * Extend this class and override the event methods you need to integrate\n * with different platforms (Linear, Slack, etc.)\n */\nexport abstract class Agent {\n protected currentSessionId?: string;\n protected isRunning = false;\n protected externalSessionId: string;\n private activeQuery?: Query;\n private pendingToolUses = new Map<string, { block: ToolUseBlock; isSubagent: boolean }>();\n\n constructor(externalSessionId: string) {\n this.externalSessionId = externalSessionId;\n }\n\n // ============================================\n // Interrupt mechanism (private)\n // ============================================\n\n private get interruptPath(): string {\n return path.join('/tmp', `agent-${this.externalSessionId}.interrupt`);\n }\n\n private get isInterrupted(): boolean {\n try {\n if (fs.existsSync(this.interruptPath)) {\n return fs.readFileSync(this.interruptPath, 'utf-8').trim() === 'true';\n }\n return false;\n } catch {\n return false;\n }\n }\n\n private requestInterrupt(): void {\n fs.writeFileSync(this.interruptPath, 'true', 'utf-8');\n }\n\n private clearInterrupt(): void {\n try {\n if (fs.existsSync(this.interruptPath)) {\n fs.unlinkSync(this.interruptPath);\n }\n } catch {\n // Ignore errors\n }\n }\n\n // ============================================\n // Event methods - Override in subclasses\n // ============================================\n\n /**\n * Called when agent starts processing\n */\n protected async onStart(): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent emits a thinking/reasoning text\n */\n protected async onThinking(block: TextBlock, isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent starts using a tool (before result is available)\n */\n protected async onToolUse(block: ToolUseBlock, isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when a tool completes with its result\n */\n protected async onToolResult(block: ToolUseBlock, result: string, isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent updates its plan (via TodoWrite)\n */\n protected async onPlanUpdate(todos: PlanStep[], isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent completes successfully\n */\n protected async onComplete(message: SDKResultMessage): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent encounters an error\n */\n protected async onError(error: Error): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent is stopped via stop command\n */\n protected async onStop(): Promise<void> {\n // Override in subclasses\n }\n\n // ============================================\n // Main execution logic\n // ============================================\n\n /**\n * Run the agent with the given prompt\n */\n public async run(runOptions: AgentRunOptions): Promise<AgentRunResult> {\n const {\n prompt,\n sessionId,\n resumeSession = false,\n forkSession = false,\n cwd = process.cwd(),\n options: additionalOptions = {},\n } = runOptions;\n\n this.isRunning = true;\n let resultSessionId = sessionId ?? '';\n let finalResult: string | undefined;\n let wasInterrupted = false;\n\n // Clear any existing interrupt flag before starting\n this.clearInterrupt();\n\n try {\n await this.onStart();\n\n // Set env vars before spawning (SDK env option replaces process env)\n process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';\n\n // Build SDK options\n const sdkOptions: Options = {\n settingSources: ['project'],\n permissionMode: 'bypassPermissions',\n allowDangerouslySkipPermissions: true,\n plugins: [{ type: 'local', path: getPluginPath(cwd) }],\n\t systemPrompt: {\n\t\t\t\t\tpreset: 'claude_code',\n\t\t type: 'preset',\n\t },\n cwd,\n ...additionalOptions,\n };\n\n // Add resume options if resuming\n if (resumeSession && sessionId) {\n sdkOptions.resume = sessionId;\n sdkOptions.forkSession = forkSession;\n }\n\n console.log(`[Agent.run] resume=${resumeSession} | sdkResume=${sdkOptions.resume ?? 'none'} | pluginPath=${getPluginPath(cwd)}`);\n console.log(`[Agent.run] prompt=${prompt.substring(0, 300)}...`);\n\n // Run the agent\n this.activeQuery = query({ prompt, options: sdkOptions });\n for await (const message of this.activeQuery) {\n // Check for interrupt flag\n if (this.isInterrupted) {\n console.log('Interrupt flag detected, stopping agent...');\n await this.activeQuery.interrupt();\n wasInterrupted = true;\n break;\n }\n\n // Capture session ID from init message\n if (message.type === 'system') {\n const sysMsg = message as SDKSystemMessage;\n if (sysMsg.subtype === 'init') {\n resultSessionId = sysMsg.session_id;\n this.currentSessionId = sysMsg.session_id;\n console.log(`[Agent.run] SDK session initialized: ${sysMsg.session_id}`);\n }\n }\n\n // Process assistant messages (buffers tool uses)\n if (message.type === 'assistant') {\n await this.processAssistantMessage(message as SDKAssistantMessage);\n }\n\n // Process user messages (contains tool results)\n if (message.type === 'user') {\n await this.processUserMessage(message as SDKUserMessage);\n }\n\n // Handle result message\n if (message.type === 'result') {\n const resultMsg = message as SDKResultMessage;\n if (resultMsg.subtype === 'success' && resultMsg.result) {\n finalResult = resultMsg.result;\n }\n await this.onComplete(resultMsg);\n }\n }\n\n return {\n sessionId: resultSessionId,\n result: finalResult,\n interrupted: wasInterrupted,\n };\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n await this.onError(err);\n\n return {\n sessionId: resultSessionId,\n error: err.message,\n interrupted: wasInterrupted,\n };\n\n } finally {\n this.isRunning = false;\n this.activeQuery = undefined;\n // Clear interrupt flag after we're done\n this.clearInterrupt();\n }\n }\n\n /**\n * Stop the agent session\n * Sets interrupt flag and calls onStop callback\n */\n public async stop(): Promise<void> {\n this.requestInterrupt();\n await this.onStop();\n }\n\n /**\n * Process an assistant message: emit thinking, buffer tool uses for later matching\n */\n private async processAssistantMessage(message: SDKAssistantMessage): Promise<void> {\n const content = message.message.content;\n const isSubagent = message.parent_tool_use_id !== null;\n\n for (const block of content) {\n if (block.type === 'text') {\n await this.onThinking(block, isSubagent);\n }\n\n if (block.type === 'tool_use') {\n if (block.name === 'TodoWrite') {\n const input = block.input as { todos?: PlanStep[] };\n if (input.todos) {\n await this.onPlanUpdate(input.todos, isSubagent);\n }\n } else {\n await this.onToolUse(block, isSubagent);\n // Buffer tool use — result arrives in the next user message\n this.pendingToolUses.set(block.id, { block, isSubagent });\n }\n }\n }\n }\n\n /**\n * Process a user message: match tool results to buffered tool uses\n */\n private async processUserMessage(message: SDKUserMessage): Promise<void> {\n const content = message.message.content;\n if (typeof content === 'string') return;\n\n for (const block of content) {\n if (block.type !== 'tool_result') continue;\n\n const resultBlock = block as ToolResultBlockParam;\n const pending = this.pendingToolUses.get(resultBlock.tool_use_id);\n if (!pending) continue;\n\n this.pendingToolUses.delete(resultBlock.tool_use_id);\n\n // Extract result text\n let result = '';\n if (typeof resultBlock.content === 'string') {\n result = resultBlock.content;\n } else if (Array.isArray(resultBlock.content)) {\n result = resultBlock.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map(b => b.text)\n .join('\\n');\n }\n\n await this.onToolResult(pending.block, result, pending.isSubagent);\n }\n }\n}\n\nexport { TextBlock, ToolUseBlock }\n","import { appendFileSync, cpSync, existsSync, mkdirSync, readFileSync, renameSync } from 'fs';\nimport { dirname, resolve, join } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst PLUGIN_DIRNAME = 'agent-plugin';\n\n/**\n * Get the path to the bundled claude-config directory\n */\nfunction getBundledConfigPath(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n return resolve(__dirname, 'claude-config');\n}\n\n/**\n * Get the plugin path relative to a working directory\n */\nexport function getPluginPath(cwd: string = process.cwd()): string {\n return join(cwd, PLUGIN_DIRNAME);\n}\n\n/**\n * Install the bundled kartman plugin to <cwd>/agent-plugin/.\n *\n * The bundled files use underscores instead of dots (npm strips dotfiles).\n * This function copies them and renames back:\n * _claude-plugin/ → .claude-plugin/\n * _mcp.json → .mcp.json\n */\nexport function installClaudeConfig(cwd: string = process.cwd()): void {\n const bundledPath = getBundledConfigPath();\n\n if (!existsSync(bundledPath)) {\n console.warn('Warning: Bundled claude-config not found. Skipping plugin installation.');\n return;\n }\n\n const pluginDir = getPluginPath(cwd);\n\n // Copy entire bundled directory\n mkdirSync(pluginDir, { recursive: true });\n cpSync(bundledPath, pluginDir, { recursive: true, force: true });\n\n // Restore dotfiles: _claude-plugin → .claude-plugin\n const underscorePlugin = join(pluginDir, '_claude-plugin');\n const dotPlugin = join(pluginDir, '.claude-plugin');\n if (existsSync(underscorePlugin)) {\n renameSync(underscorePlugin, dotPlugin);\n }\n\n // Restore dotfiles: _mcp.json → .mcp.json\n const underscoreMcp = join(pluginDir, '_mcp.json');\n const dotMcp = join(pluginDir, '.mcp.json');\n if (existsSync(underscoreMcp)) {\n renameSync(underscoreMcp, dotMcp);\n }\n\n // Ensure agent-plugin/ is gitignored so the agent doesn't commit it\n const gitignorePath = join(cwd, '.gitignore');\n if (existsSync(gitignorePath)) {\n const content = readFileSync(gitignorePath, 'utf-8');\n if (!content.includes(PLUGIN_DIRNAME)) {\n appendFileSync(gitignorePath, `\\n# Kartman agent plugin (installed at runtime)\\n${PLUGIN_DIRNAME}/\\n`);\n }\n }\n\n console.log(`Installed agent plugin to ${pluginDir}`);\n}\n","import { Agent } from './agent';\nimport {createLinearAgent, LinearAgent} from './linear/agent';\n\n/**\n * Supported platforms\n */\nexport enum Platform {\n Linear = 'linear',\n}\n\n/**\n * Create an agent for the specified platform\n */\nexport function createAgent(platform: Platform, sessionId: string): Agent {\n switch (platform) {\n case Platform.Linear:\n\t\t\treturn createLinearAgent(sessionId)\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n}\n","/**\n * HTTP callback client for updating session state on the server\n */\n\nimport type { AgentRunResult } from '@/agent';\n\nexport enum SessionState {\n Running = 'running',\n Completed = 'completed',\n Error = 'error',\n}\n\nexport interface SessionUpdate {\n externalSessionId: string;\n claudeSessionId?: string;\n state: SessionState;\n error?: string;\n}\n\nexport async function sendSessionUpdate(\n callbackUrl: string,\n callbackSecret: string,\n update: SessionUpdate\n): Promise<void> {\n try {\n const response = await fetch(callbackUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${callbackSecret}`,\n },\n body: JSON.stringify(update),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n console.error(`[callback] Failed: ${response.status} ${response.statusText} - ${body}`);\n }\n } catch (error) {\n console.error('[callback] Failed to send session update:', error);\n }\n}\n\nexport async function reportResult(\n callbackUrl: string | undefined,\n externalSessionId: string,\n result: AgentRunResult\n): Promise<void> {\n const callbackSecret = process.env.CLAUDE_LINEAR_CALLBACK_SECRET;\n\n if (!callbackUrl || !callbackSecret) {\n return;\n }\n\n // Report running status with session ID\n if (result.sessionId) {\n await sendSessionUpdate(callbackUrl, callbackSecret, {\n externalSessionId,\n claudeSessionId: result.sessionId,\n state: SessionState.Running,\n });\n }\n\n // Report final status\n if (result.error) {\n await sendSessionUpdate(callbackUrl, callbackSecret, {\n externalSessionId,\n state: SessionState.Error,\n error: result.error,\n });\n } else if (!result.interrupted) {\n await sendSessionUpdate(callbackUrl, callbackSecret, {\n externalSessionId,\n claudeSessionId: result.sessionId,\n state: SessionState.Completed,\n });\n }\n}\n","import { Command } from 'commander';\nimport { createAgent, type Platform } from '@/factory';\n\nexport const stopCommand = new Command('stop')\n .description('Stop an agent session gracefully')\n .requiredOption('--platform <platform>', 'Platform type (linear)')\n .requiredOption('--session-id <id>', 'External session ID (e.g., Linear session ID)')\n .action(async (options) => {\n const { platform, sessionId } = options;\n\n try {\n const agent = createAgent(platform as Platform, sessionId);\n await agent.stop();\n\n console.log(JSON.stringify({\n status: 'stopped',\n sessionId,\n }));\n process.exit(0);\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(JSON.stringify({\n status: 'error',\n error: errorMessage,\n }));\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { createAgent, type Platform } from '@/factory';\nimport { reportResult } from '@/callback';\n\nexport const resumeCommand = new Command('resume')\n .description('Resume an existing agent session')\n .requiredOption('--platform <platform>', 'Platform type (linear)')\n .requiredOption('--session-id <id>', 'External session ID (e.g., Linear session ID)')\n .requiredOption('--claude-session-id <id>', 'Claude SDK session ID to resume')\n .requiredOption('--prompt <prompt>', 'New prompt/user input')\n .option('--callback-url <url>', 'Server callback URL for session updates')\n .option('--working-dir <dir>', 'Working directory', process.cwd())\n .action(async (options) => {\n const { platform, sessionId, claudeSessionId, prompt, callbackUrl, workingDir } = options;\n\n const agent = createAgent(platform as Platform, sessionId);\n\n try {\n console.log(`[CLI.resume] sessionId=${sessionId} | claudeSessionId=${claudeSessionId} | cwd=${workingDir}`);\n\n const result = await agent.run({\n prompt,\n sessionId: claudeSessionId,\n resumeSession: true,\n forkSession: false,\n cwd: workingDir,\n });\n\n await reportResult(callbackUrl, sessionId, result);\n\n console.log(JSON.stringify({\n status: result.error ? 'error' : (result.interrupted ? 'interrupted' : 'completed'),\n claudeSessionId: result.sessionId,\n result: result.result,\n error: result.error,\n }));\n\n process.exit(result.error ? 1 : 0);\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(JSON.stringify({ status: 'error', error: errorMessage }));\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { installClaudeConfig } from '../config';\n\nexport const initCommand = new Command('init')\n .description('Install agent plugin (MCP servers, skills)')\n .action(() => {\n installClaudeConfig();\n });","import { Command } from 'commander';\nimport { execSync, execFileSync } from 'child_process';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n/**\n * Get the current package name (kartman or kartman-dev)\n * Reads from package.json to determine which package is installed\n */\nfunction getCurrentPackageName(): string {\n try {\n // Get the directory of the current module\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n\n // Navigate up to find package.json (dist/commands/update.js -> package.json)\n const packageJsonPath = join(__dirname, '../../package.json');\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\n return packageJson.name;\n } catch (error) {\n // Fallback to kartman if we can't read package.json\n console.warn('Could not determine package name, defaulting to kartman');\n return 'kartman';\n }\n}\n\n/**\n * Build the pnpm install arguments for updating the CLI\n *\n * @param cliPackage - Package name (kartman or kartman-dev)\n * @param cliVersion - Optional version to install\n * @returns Array of pnpm arguments [cmd, ...args]\n */\nfunction buildInstallArgs(\n cliPackage: string,\n cliVersion?: string\n): string[] {\n // Validate package name to prevent command injection\n if (!['kartman', 'kartman-dev'].includes(cliPackage)) {\n throw new Error(`Invalid package name: ${cliPackage}. Must be 'kartman' or 'kartman-dev'`);\n }\n\n // Validate version format if provided\n if (cliVersion && !/^[\\w.-]+$/.test(cliVersion)) {\n throw new Error(`Invalid version format: ${cliVersion}`);\n }\n\n if (!cliVersion) {\n // No version specified - always get latest\n // This is important because kartman-dev has different versions than kartman\n return ['pnpm', 'add', '-g', `${cliPackage}@latest`];\n }\n\n // Check if version looks like a full version or just a suffix\n if (cliVersion.match(/^\\d+\\.\\d+\\.\\d+/)) {\n // Full version (e.g., \"0.2.11\")\n return ['pnpm', 'add', '-g', `${cliPackage}@${cliVersion}`];\n }\n\n // Version suffix for dev packages (e.g., \"KAR-14\")\n if (cliPackage === 'kartman-dev') {\n try {\n const currentVersion = execSync('kartman --version', { encoding: 'utf-8' }).trim();\n const baseVersion = currentVersion.replace(/-dev\\..+$/, '');\n return ['pnpm', 'add', '-g', `${cliPackage}@${baseVersion}-dev.${cliVersion}`];\n } catch {\n // If we can't get current version, just use latest\n return ['pnpm', 'add', '-g', `${cliPackage}@latest`];\n }\n }\n\n // For kartman with non-standard version suffix\n return ['pnpm', 'add', '-g', `${cliPackage}@${cliVersion}`];\n}\n\nexport const updateCommand = new Command()\n .name('update')\n .description('Update kartman CLI to the latest version')\n .option('--version <version>', 'Specific version to install (e.g., \"KAR-14\" for kartman-dev@0.2.10-dev.KAR-14)')\n .action(async (options) => {\n const { version } = options;\n\n // Auto-detect the current package name (kartman or kartman-dev)\n const packageName = getCurrentPackageName();\n\n try {\n const installArgs = buildInstallArgs(packageName, version);\n\n console.log(`Updating CLI: ${installArgs.join(' ')}`);\n\n // Use execFileSync to avoid shell interpretation and command injection\n const [cmd, ...args] = installArgs;\n if (!cmd) {\n throw new Error('Invalid install command');\n }\n execFileSync(cmd, args, {\n stdio: 'inherit',\n encoding: 'utf-8'\n });\n\n // Show new version\n const newVersion = execSync('kartman --version', { encoding: 'utf-8' }).trim();\n console.log(`Current version: ${newVersion}`);\n console.log('✓ CLI updated successfully');\n\n } catch (error) {\n console.error('Failed to update CLI:', error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["Command","Command","Command","Command","Command","Command","Command","Command","readFileSync","fileURLToPath","dirname","join","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/start.ts","../src/linear/agent.ts","../src/agent.ts","../src/config.ts","../src/factory.ts","../src/callback.ts","../src/commands/stop.ts","../src/commands/resume.ts","../src/commands/init.ts","../src/commands/update.ts"],"sourcesContent":["import { Command } from 'commander';\nimport startCommand from './commands/start';\nimport { stopCommand } from './commands/stop';\nimport { resumeCommand } from './commands/resume';\nimport { initCommand } from './commands/init';\nimport { updateCommand } from './commands/update';\n\nconst program = new Command();\n\nprogram\n .name('kartman')\n .description('CLI for running Claude agents in Vercel sandboxes')\n .version('0.1.0');\n\nprogram.addCommand(initCommand);\nprogram.addCommand(startCommand);\nprogram.addCommand(stopCommand);\nprogram.addCommand(resumeCommand);\nprogram.addCommand(updateCommand);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport { createAgent, type Platform } from '@/factory';\nimport { reportResult } from '@/callback';\nimport type { AgentRunResult } from '@/agent';\n\nconst startCommand = new Command('start')\n .description('Start a new agent session')\n .requiredOption('--platform <platform>', 'Platform type (linear)')\n .requiredOption('--session-id <id>', 'External session ID (e.g., Linear session ID)')\n .requiredOption('--prompt <prompt>', 'Initial prompt for the agent')\n .option('--callback-url <url>', 'Server callback URL for session updates')\n .option('--working-dir <dir>', 'Working directory', process.cwd())\n .action(async (options) => {\n const { platform, sessionId, prompt, callbackUrl, workingDir } = options;\n\n try {\n console.log(`[CLI.start] sessionId=${sessionId} | cwd=${workingDir}`);\n console.log(`[CLI.start] prompt=${prompt.substring(0, 300)}...`);\n\n const agent = createAgent(platform as Platform, sessionId);\n\n const result = await agent.run({\n prompt,\n cwd: workingDir,\n });\n\n await reportResult(callbackUrl, sessionId, result);\n\n console.log(JSON.stringify({\n status: result.error ? 'error' : (result.interrupted ? 'interrupted' : 'completed'),\n claudeSessionId: result.sessionId,\n result: result.result,\n error: result.error,\n }));\n\n process.exit(result.error ? 1 : 0);\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n await reportResult(callbackUrl, sessionId, { sessionId: '', error: errorMessage } as AgentRunResult);\n console.error(JSON.stringify({ status: 'error', error: errorMessage }));\n process.exit(1);\n }\n });\n\nexport default startCommand;\n","import { LinearClient } from '@linear/sdk';\nimport type { SDKResultMessage } from '@anthropic-ai/claude-agent-sdk';\nimport {\n Agent,\n type PlanStep,\n type TextBlock,\n type ToolUseBlock,\n} from '@/agent';\n\nexport interface LinearAgentConfig {\n linearAccessToken: string;\n linearSessionId: string;\n}\n\nenum LinearActivityType {\n\tThought = 'thought',\n\tAction = 'action',\n\tResponse = 'response',\n\tError = 'error',\n\tElicitation = 'elicitation',\n}\n\nexport class LinearAgent extends Agent {\n private linearClient: LinearClient;\n private linearSessionId: string;\n private lastThoughtTime = 0;\n private thoughtDebounceMs = 1000;\n private isCompleted = false;\n\n constructor(config: LinearAgentConfig) {\n super(config.linearSessionId);\n this.linearClient = new LinearClient({ accessToken: config.linearAccessToken });\n this.linearSessionId = config.linearSessionId;\n }\n\n protected async onStart(): Promise<void> {\n await this.sendActivity(LinearActivityType.Thought, 'Starting work...', true);\n }\n\n protected async onThinking(block: TextBlock, isSubagent: boolean): Promise<void> {\n if (this.isCompleted) return;\n\n const now = Date.now();\n if (now - this.lastThoughtTime < this.thoughtDebounceMs) return;\n this.lastThoughtTime = now;\n\n const content = block.text;\n if (content.length < 20) return;\n\n await this.sendActivity(LinearActivityType.Thought, content, false);\n }\n\n /** Tools that should show immediately on use (not wait for result) */\n private static SHOW_ON_USE = new Set(['Task', 'Read', 'Grep', 'Glob', 'WebSearch', 'WebFetch']);\n\n protected async onToolUse(block: ToolUseBlock, isSubagent: boolean): Promise<void> {\n if (this.isCompleted) return;\n if (!LinearAgent.SHOW_ON_USE.has(block.name)) return;\n\n if (block.name === 'Task') {\n const subagentType = String((block.input as Record<string, unknown>).subagent_type ?? 'subagent');\n await this.sendActionActivity('Delegating', subagentType, undefined, false);\n return;\n }\n\n const { action, parameter } = this.formatToolAction(block);\n await this.sendActionActivity(action, parameter, undefined, isSubagent);\n }\n\n protected async onToolResult(block: ToolUseBlock, result: string, isSubagent: boolean): Promise<void> {\n if (this.isCompleted) return;\n // Skip tools already shown in onToolUse\n if (LinearAgent.SHOW_ON_USE.has(block.name)) return;\n\n const { action, parameter } = this.formatToolAction(block);\n const truncatedResult = result.length > 1000 ? result.substring(0, 1000) + '...' : result;\n await this.sendActionActivity(action, parameter, truncatedResult || undefined, isSubagent);\n }\n\n protected async onPlanUpdate(steps: PlanStep[], isSubagent: boolean): Promise<void> {\n if (steps.length === 0) return;\n\n const linearSteps = steps.map(step => ({\n content: step.content,\n status: this.mapStatusToLinear(step.status),\n }));\n\n try {\n await this.linearClient.updateAgentSession(this.linearSessionId, {\n plan: linearSteps,\n });\n } catch (error) {\n console.error('Failed to update Linear plan:', error);\n }\n }\n\n protected async onComplete(message: SDKResultMessage): Promise<void> {\n this.isCompleted = true;\n\n const text = message.subtype === 'success' && message.result\n ? message.result\n : 'Task completed successfully.';\n await this.sendActivity(LinearActivityType.Response, text, false);\n }\n\n protected async onError(error: Error): Promise<void> {\n this.isCompleted = true;\n await this.sendActivity(LinearActivityType.Error, `Error: ${error.message}`, false);\n }\n\n\tprotected async onStop(): Promise<void> {\n\t\tthis.isCompleted = true;\n\t\tawait this.sendActivity(LinearActivityType.Response, 'Session stopped', false);\n\t}\n\n // ============================================\n // Helper methods\n // ============================================\n\n private async sendActivity(\n type: LinearActivityType,\n body: string,\n ephemeral: boolean\n ): Promise<void> {\n try {\n await this.linearClient.createAgentActivity({\n agentSessionId: this.linearSessionId,\n content: { type, body },\n ephemeral,\n });\n } catch (error) {\n console.error('Failed to send Linear activity:', error);\n }\n }\n\n private async sendActionActivity(\n action: string,\n parameter: string,\n result: string | undefined,\n ephemeral: boolean\n ): Promise<void> {\n try {\n const content: Record<string, string> = {\n type: LinearActivityType.Action,\n action,\n parameter,\n };\n if (result) content.result = result;\n\n await this.linearClient.createAgentActivity({\n agentSessionId: this.linearSessionId,\n content,\n ephemeral,\n });\n } catch (error) {\n console.error('Failed to send Linear activity:', error);\n }\n }\n\n private formatToolAction(block: ToolUseBlock): { action: string; parameter: string } {\n const { name, input } = block;\n const params = input as Record<string, unknown>;\n\n switch (name) {\n case 'Write':\n return { action: 'Creating file', parameter: String(params.file_path ?? '') };\n\n case 'Edit':\n return { action: 'Editing file', parameter: String(params.file_path ?? '') };\n\n case 'Read':\n return { action: 'Reading file', parameter: String(params.file_path ?? '') };\n\n case 'Bash': {\n const cmd = String(params.command ?? '');\n return { action: 'Running command', parameter: cmd.length > 80 ? cmd.substring(0, 80) + '...' : cmd };\n }\n\n case 'Grep':\n return { action: 'Searching', parameter: String(params.pattern ?? '') };\n\n case 'Glob':\n return { action: 'Finding files', parameter: String(params.pattern ?? '') };\n\n case 'Task':\n return { action: 'Delegating', parameter: String(params.subagent_type ?? 'subagent') };\n\n case 'Skill':\n return { action: 'Using skill', parameter: String(params.skill ?? '') };\n\n default:\n return { action: name, parameter: JSON.stringify(params).substring(0, 100) };\n }\n }\n\n private mapStatusToLinear(\n status: PlanStep['status']\n ): 'pending' | 'inProgress' | 'completed' | 'canceled' {\n switch (status) {\n case 'in_progress': return 'inProgress';\n case 'completed': return 'completed';\n case 'canceled': return 'canceled';\n case 'pending':\n default: return 'pending';\n }\n }\n}\n\n\nexport const createLinearAgent = (sessionId: string) => {\n\tconst linearAccessToken = process.env.LINEAR_ACCESS_TOKEN;\n\tif (!linearAccessToken) {\n\t\tthrow new Error('Linear access token is missing');\n\t}\n\n\treturn new LinearAgent({ linearAccessToken, linearSessionId: sessionId })\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n query as origQuery,\n type Query,\n type Options,\n type SDKAssistantMessage,\n type SDKUserMessage,\n type SDKResultMessage,\n type SDKSystemMessage,\n} from '@anthropic-ai/claude-agent-sdk';\nimport type { TextBlock, ToolUseBlock, ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages';\nimport { Laminar } from '@lmnr-ai/lmnr';\nimport { getPluginPath } from './config.js';\n\n// Initialize Laminar\nif (process.env.LMNR_PROJECT_API_KEY) {\n Laminar.initialize({\n projectApiKey: process.env.LMNR_PROJECT_API_KEY,\n });\n}\n\n// Wrap the query function with Laminar instrumentation\nconst query = process.env.LMNR_PROJECT_API_KEY\n ? Laminar.wrapClaudeAgentQuery(origQuery)\n : origQuery;\n\n/**\n * Plan step for tracking progress\n */\nexport interface PlanStep {\n content: string;\n status: 'pending' | 'in_progress' | 'completed' | 'canceled';\n}\n\n/**\n * Agent run options\n */\nexport interface AgentRunOptions {\n prompt: string;\n sessionId?: string; // SDK session ID for resumption\n resumeSession?: boolean; // Whether to resume existing session\n forkSession?: boolean; // Whether to fork when resuming\n cwd?: string; // Working directory\n options?: Partial<Options>; // Additional SDK options\n}\n\n/**\n * Agent run result\n */\nexport interface AgentRunResult {\n sessionId: string;\n result?: string;\n error?: string;\n interrupted?: boolean;\n}\n\n/**\n * Base Agent class\n *\n * Runs Claude Agent SDK and calls event methods for each message type.\n * Extend this class and override the event methods you need to integrate\n * with different platforms (Linear, Slack, etc.)\n */\nexport abstract class Agent {\n protected currentSessionId?: string;\n protected isRunning = false;\n protected externalSessionId: string;\n private activeQuery?: Query;\n private pendingToolUses = new Map<string, { block: ToolUseBlock; isSubagent: boolean }>();\n\n constructor(externalSessionId: string) {\n this.externalSessionId = externalSessionId;\n }\n\n // ============================================\n // Interrupt mechanism (private)\n // ============================================\n\n private get interruptPath(): string {\n return path.join('/tmp', `agent-${this.externalSessionId}.interrupt`);\n }\n\n private get isInterrupted(): boolean {\n try {\n if (fs.existsSync(this.interruptPath)) {\n return fs.readFileSync(this.interruptPath, 'utf-8').trim() === 'true';\n }\n return false;\n } catch {\n return false;\n }\n }\n\n private requestInterrupt(): void {\n fs.writeFileSync(this.interruptPath, 'true', 'utf-8');\n }\n\n private clearInterrupt(): void {\n try {\n if (fs.existsSync(this.interruptPath)) {\n fs.unlinkSync(this.interruptPath);\n }\n } catch {\n // Ignore errors\n }\n }\n\n // ============================================\n // Event methods - Override in subclasses\n // ============================================\n\n /**\n * Called when agent starts processing\n */\n protected async onStart(): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent emits a thinking/reasoning text\n */\n protected async onThinking(block: TextBlock, isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent starts using a tool (before result is available)\n */\n protected async onToolUse(block: ToolUseBlock, isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when a tool completes with its result\n */\n protected async onToolResult(block: ToolUseBlock, result: string, isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent updates its plan (via TodoWrite)\n */\n protected async onPlanUpdate(todos: PlanStep[], isSubagent: boolean): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent completes successfully\n */\n protected async onComplete(message: SDKResultMessage): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent encounters an error\n */\n protected async onError(error: Error): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called when agent is stopped via stop command\n */\n protected async onStop(): Promise<void> {\n // Override in subclasses\n }\n\n // ============================================\n // Main execution logic\n // ============================================\n\n /**\n * Run the agent with the given prompt\n */\n public async run(runOptions: AgentRunOptions): Promise<AgentRunResult> {\n const {\n prompt,\n sessionId,\n resumeSession = false,\n forkSession = false,\n cwd = process.cwd(),\n options: additionalOptions = {},\n } = runOptions;\n\n this.isRunning = true;\n let resultSessionId = sessionId ?? '';\n let finalResult: string | undefined;\n let wasInterrupted = false;\n\n // Clear any existing interrupt flag before starting\n this.clearInterrupt();\n\n try {\n await this.onStart();\n\n // Set env vars before spawning (SDK env option replaces process env)\n process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';\n\n // Build SDK options\n const sdkOptions: Options = {\n settingSources: ['project'],\n permissionMode: 'bypassPermissions',\n allowDangerouslySkipPermissions: true,\n plugins: [{ type: 'local', path: getPluginPath(cwd) }],\n\t systemPrompt: {\n\t\t\t\t\tpreset: 'claude_code',\n\t\t type: 'preset',\n\t },\n cwd,\n ...additionalOptions,\n };\n\n // Add resume options if resuming\n if (resumeSession && sessionId) {\n sdkOptions.resume = sessionId;\n sdkOptions.forkSession = forkSession;\n }\n\n console.log(`[Agent.run] resume=${resumeSession} | sdkResume=${sdkOptions.resume ?? 'none'} | pluginPath=${getPluginPath(cwd)}`);\n console.log(`[Agent.run] prompt=${prompt.substring(0, 300)}...`);\n\n // Run the agent\n this.activeQuery = query({ prompt, options: sdkOptions });\n for await (const message of this.activeQuery) {\n // Check for interrupt flag\n if (this.isInterrupted) {\n console.log('Interrupt flag detected, stopping agent...');\n await this.activeQuery.interrupt();\n wasInterrupted = true;\n break;\n }\n\n // Capture session ID from init message\n if (message.type === 'system') {\n const sysMsg = message as SDKSystemMessage;\n if (sysMsg.subtype === 'init') {\n resultSessionId = sysMsg.session_id;\n this.currentSessionId = sysMsg.session_id;\n console.log(`[Agent.run] SDK session initialized: ${sysMsg.session_id}`);\n }\n }\n\n // Process assistant messages (buffers tool uses)\n if (message.type === 'assistant') {\n await this.processAssistantMessage(message as SDKAssistantMessage);\n }\n\n // Process user messages (contains tool results)\n if (message.type === 'user') {\n await this.processUserMessage(message as SDKUserMessage);\n }\n\n // Handle result message\n if (message.type === 'result') {\n const resultMsg = message as SDKResultMessage;\n if (resultMsg.subtype === 'success' && resultMsg.result) {\n finalResult = resultMsg.result;\n }\n await this.onComplete(resultMsg);\n }\n }\n\n return {\n sessionId: resultSessionId,\n result: finalResult,\n interrupted: wasInterrupted,\n };\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n await this.onError(err);\n\n return {\n sessionId: resultSessionId,\n error: err.message,\n interrupted: wasInterrupted,\n };\n\n } finally {\n this.isRunning = false;\n this.activeQuery = undefined;\n // Clear interrupt flag after we're done\n this.clearInterrupt();\n }\n }\n\n /**\n * Stop the agent session\n * Sets interrupt flag and calls onStop callback\n */\n public async stop(): Promise<void> {\n this.requestInterrupt();\n await this.onStop();\n }\n\n /**\n * Process an assistant message: emit thinking, buffer tool uses for later matching\n */\n private async processAssistantMessage(message: SDKAssistantMessage): Promise<void> {\n const content = message.message.content;\n const isSubagent = message.parent_tool_use_id !== null;\n\n for (const block of content) {\n if (block.type === 'text') {\n await this.onThinking(block, isSubagent);\n }\n\n if (block.type === 'tool_use') {\n if (block.name === 'TodoWrite') {\n const input = block.input as { todos?: PlanStep[] };\n if (input.todos) {\n await this.onPlanUpdate(input.todos, isSubagent);\n }\n } else {\n await this.onToolUse(block, isSubagent);\n // Buffer tool use — result arrives in the next user message\n this.pendingToolUses.set(block.id, { block, isSubagent });\n }\n }\n }\n }\n\n /**\n * Process a user message: match tool results to buffered tool uses\n */\n private async processUserMessage(message: SDKUserMessage): Promise<void> {\n const content = message.message.content;\n if (typeof content === 'string') return;\n\n for (const block of content) {\n if (block.type !== 'tool_result') continue;\n\n const resultBlock = block as ToolResultBlockParam;\n const pending = this.pendingToolUses.get(resultBlock.tool_use_id);\n if (!pending) continue;\n\n this.pendingToolUses.delete(resultBlock.tool_use_id);\n\n // Extract result text\n let result = '';\n if (typeof resultBlock.content === 'string') {\n result = resultBlock.content;\n } else if (Array.isArray(resultBlock.content)) {\n result = resultBlock.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map(b => b.text)\n .join('\\n');\n }\n\n await this.onToolResult(pending.block, result, pending.isSubagent);\n }\n }\n}\n\nexport { TextBlock, ToolUseBlock }\n","import { appendFileSync, cpSync, existsSync, mkdirSync, readFileSync, renameSync } from 'fs';\nimport { dirname, resolve, join } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst PLUGIN_DIRNAME = 'agent-plugin';\n\n/**\n * Get the path to the bundled claude-config directory\n */\nfunction getBundledConfigPath(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n return resolve(__dirname, 'claude-config');\n}\n\n/**\n * Get the plugin path relative to a working directory\n */\nexport function getPluginPath(cwd: string = process.cwd()): string {\n return join(cwd, PLUGIN_DIRNAME);\n}\n\n/**\n * Install the bundled kartman plugin to <cwd>/agent-plugin/.\n *\n * The bundled files use underscores instead of dots (npm strips dotfiles).\n * This function copies them and renames back:\n * _claude-plugin/ → .claude-plugin/\n * _mcp.json → .mcp.json\n */\nexport function installClaudeConfig(cwd: string = process.cwd()): void {\n const bundledPath = getBundledConfigPath();\n\n if (!existsSync(bundledPath)) {\n console.warn('Warning: Bundled claude-config not found. Skipping plugin installation.');\n return;\n }\n\n const pluginDir = getPluginPath(cwd);\n\n // Copy entire bundled directory\n mkdirSync(pluginDir, { recursive: true });\n cpSync(bundledPath, pluginDir, { recursive: true, force: true });\n\n // Restore dotfiles: _claude-plugin → .claude-plugin\n const underscorePlugin = join(pluginDir, '_claude-plugin');\n const dotPlugin = join(pluginDir, '.claude-plugin');\n if (existsSync(underscorePlugin)) {\n renameSync(underscorePlugin, dotPlugin);\n }\n\n // Restore dotfiles: _mcp.json → .mcp.json\n const underscoreMcp = join(pluginDir, '_mcp.json');\n const dotMcp = join(pluginDir, '.mcp.json');\n if (existsSync(underscoreMcp)) {\n renameSync(underscoreMcp, dotMcp);\n }\n\n // Ensure agent-plugin/ is gitignored so the agent doesn't commit it\n const gitignorePath = join(cwd, '.gitignore');\n if (existsSync(gitignorePath)) {\n const content = readFileSync(gitignorePath, 'utf-8');\n if (!content.includes(PLUGIN_DIRNAME)) {\n appendFileSync(gitignorePath, `\\n# Kartman agent plugin (installed at runtime)\\n${PLUGIN_DIRNAME}/\\n`);\n }\n }\n\n console.log(`Installed agent plugin to ${pluginDir}`);\n}\n","import { Agent } from './agent';\nimport {createLinearAgent, LinearAgent} from './linear/agent';\n\n/**\n * Supported platforms\n */\nexport enum Platform {\n Linear = 'linear',\n}\n\n/**\n * Create an agent for the specified platform\n */\nexport function createAgent(platform: Platform, sessionId: string): Agent {\n switch (platform) {\n case Platform.Linear:\n\t\t\treturn createLinearAgent(sessionId)\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n}\n","/**\n * HTTP callback client for updating session state on the server\n */\n\nimport type { AgentRunResult } from '@/agent';\nimport { Laminar } from '@lmnr-ai/lmnr';\n\nexport enum SessionState {\n Running = 'running',\n Completed = 'completed',\n Error = 'error',\n}\n\nexport interface SessionUpdate {\n externalSessionId: string;\n claudeSessionId?: string;\n state: SessionState;\n error?: string;\n traceId?: string;\n}\n\nexport async function sendSessionUpdate(\n callbackUrl: string,\n callbackSecret: string,\n update: SessionUpdate\n): Promise<void> {\n try {\n const response = await fetch(callbackUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${callbackSecret}`,\n },\n body: JSON.stringify(update),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n console.error(`[callback] Failed: ${response.status} ${response.statusText} - ${body}`);\n }\n } catch (error) {\n console.error('[callback] Failed to send session update:', error);\n }\n}\n\nexport async function reportResult(\n callbackUrl: string | undefined,\n externalSessionId: string,\n result: AgentRunResult\n): Promise<void> {\n const callbackSecret = process.env.CLAUDE_LINEAR_CALLBACK_SECRET;\n\n if (!callbackUrl || !callbackSecret) {\n return;\n }\n\n // Report running status with session ID\n if (result.sessionId) {\n await sendSessionUpdate(callbackUrl, callbackSecret, {\n externalSessionId,\n claudeSessionId: result.sessionId,\n state: SessionState.Running,\n });\n }\n\n // Get Laminar trace ID if available\n let traceId: string | undefined;\n if (process.env.LMNR_PROJECT_API_KEY) {\n try {\n traceId = Laminar.getCurrentTraceId() ?? undefined;\n } catch (error) {\n console.error('[callback] Failed to get Laminar trace ID:', error);\n }\n }\n\n // Report final status (include traceId if available)\n if (result.error) {\n await sendSessionUpdate(callbackUrl, callbackSecret, {\n externalSessionId,\n state: SessionState.Error,\n error: result.error,\n traceId,\n });\n } else if (!result.interrupted) {\n await sendSessionUpdate(callbackUrl, callbackSecret, {\n externalSessionId,\n claudeSessionId: result.sessionId,\n state: SessionState.Completed,\n traceId,\n });\n }\n}","import { Command } from 'commander';\nimport { createAgent, type Platform } from '@/factory';\n\nexport const stopCommand = new Command('stop')\n .description('Stop an agent session gracefully')\n .requiredOption('--platform <platform>', 'Platform type (linear)')\n .requiredOption('--session-id <id>', 'External session ID (e.g., Linear session ID)')\n .action(async (options) => {\n const { platform, sessionId } = options;\n\n try {\n const agent = createAgent(platform as Platform, sessionId);\n await agent.stop();\n\n console.log(JSON.stringify({\n status: 'stopped',\n sessionId,\n }));\n process.exit(0);\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(JSON.stringify({\n status: 'error',\n error: errorMessage,\n }));\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { createAgent, type Platform } from '@/factory';\nimport { reportResult } from '@/callback';\n\nexport const resumeCommand = new Command('resume')\n .description('Resume an existing agent session')\n .requiredOption('--platform <platform>', 'Platform type (linear)')\n .requiredOption('--session-id <id>', 'External session ID (e.g., Linear session ID)')\n .requiredOption('--claude-session-id <id>', 'Claude SDK session ID to resume')\n .requiredOption('--prompt <prompt>', 'New prompt/user input')\n .option('--callback-url <url>', 'Server callback URL for session updates')\n .option('--working-dir <dir>', 'Working directory', process.cwd())\n .action(async (options) => {\n const { platform, sessionId, claudeSessionId, prompt, callbackUrl, workingDir } = options;\n\n const agent = createAgent(platform as Platform, sessionId);\n\n try {\n console.log(`[CLI.resume] sessionId=${sessionId} | claudeSessionId=${claudeSessionId} | cwd=${workingDir}`);\n\n const result = await agent.run({\n prompt,\n sessionId: claudeSessionId,\n resumeSession: true,\n forkSession: false,\n cwd: workingDir,\n });\n\n await reportResult(callbackUrl, sessionId, result);\n\n console.log(JSON.stringify({\n status: result.error ? 'error' : (result.interrupted ? 'interrupted' : 'completed'),\n claudeSessionId: result.sessionId,\n result: result.result,\n error: result.error,\n }));\n\n process.exit(result.error ? 1 : 0);\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(JSON.stringify({ status: 'error', error: errorMessage }));\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { installClaudeConfig } from '../config';\n\nexport const initCommand = new Command('init')\n .description('Install agent plugin (MCP servers, skills)')\n .action(() => {\n installClaudeConfig();\n });","import { Command } from 'commander';\nimport { execSync, execFileSync } from 'child_process';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n/**\n * Get the current package name (kartman or kartman-dev)\n * Reads from package.json to determine which package is installed\n */\nfunction getCurrentPackageName(): string {\n try {\n // Get the directory of the current module\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n\n // Navigate up to find package.json (dist/commands/update.js -> package.json)\n const packageJsonPath = join(__dirname, '../../package.json');\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\n return packageJson.name;\n } catch (error) {\n // Fallback to kartman if we can't read package.json\n console.warn('Could not determine package name, defaulting to kartman');\n return 'kartman';\n }\n}\n\n/**\n * Build the pnpm install arguments for updating the CLI\n *\n * @param cliPackage - Package name (kartman or kartman-dev)\n * @param cliVersion - Optional version to install\n * @returns Array of pnpm arguments [cmd, ...args]\n */\nfunction buildInstallArgs(\n cliPackage: string,\n cliVersion?: string\n): string[] {\n // Validate package name to prevent command injection\n if (!['kartman', 'kartman-dev'].includes(cliPackage)) {\n throw new Error(`Invalid package name: ${cliPackage}. Must be 'kartman' or 'kartman-dev'`);\n }\n\n // Validate version format if provided\n if (cliVersion && !/^[\\w.-]+$/.test(cliVersion)) {\n throw new Error(`Invalid version format: ${cliVersion}`);\n }\n\n if (!cliVersion) {\n // No version specified - always get latest\n // This is important because kartman-dev has different versions than kartman\n return ['pnpm', 'add', '-g', `${cliPackage}@latest`];\n }\n\n // Check if version looks like a full version or just a suffix\n if (cliVersion.match(/^\\d+\\.\\d+\\.\\d+/)) {\n // Full version (e.g., \"0.2.11\")\n return ['pnpm', 'add', '-g', `${cliPackage}@${cliVersion}`];\n }\n\n // Version suffix for dev packages (e.g., \"KAR-14\")\n if (cliPackage === 'kartman-dev') {\n try {\n const currentVersion = execSync('kartman --version', { encoding: 'utf-8' }).trim();\n const baseVersion = currentVersion.replace(/-dev\\..+$/, '');\n return ['pnpm', 'add', '-g', `${cliPackage}@${baseVersion}-dev.${cliVersion}`];\n } catch {\n // If we can't get current version, just use latest\n return ['pnpm', 'add', '-g', `${cliPackage}@latest`];\n }\n }\n\n // For kartman with non-standard version suffix\n return ['pnpm', 'add', '-g', `${cliPackage}@${cliVersion}`];\n}\n\nexport const updateCommand = new Command()\n .name('update')\n .description('Update kartman CLI to the latest version')\n .option('--version <version>', 'Specific version to install (e.g., \"KAR-14\" for kartman-dev@0.2.10-dev.KAR-14)')\n .action(async (options) => {\n const { version } = options;\n\n // Auto-detect the current package name (kartman or kartman-dev)\n const packageName = getCurrentPackageName();\n\n try {\n const installArgs = buildInstallArgs(packageName, version);\n\n console.log(`Updating CLI: ${installArgs.join(' ')}`);\n\n // Use execFileSync to avoid shell interpretation and command injection\n const [cmd, ...args] = installArgs;\n if (!cmd) {\n throw new Error('Invalid install command');\n }\n execFileSync(cmd, args, {\n stdio: 'inherit',\n encoding: 'utf-8'\n });\n\n // Show new version\n const newVersion = execSync('kartman --version', { encoding: 'utf-8' }).trim();\n console.log(`Current version: ${newVersion}`);\n console.log('✓ CLI updated successfully');\n\n } catch (error) {\n console.error('Failed to update CLI:', error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["Command","Laminar","Laminar","Command","Command","Command","Command","Command","Command","Command","readFileSync","fileURLToPath","dirname","join","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kartman-dev",
3
- "version": "1.0.0-dev.0",
3
+ "version": "1.0.0-dev.2",
4
4
  "description": "CLI for running Claude agents in Vercel sandboxes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,6 +24,7 @@
24
24
  "@anthropic-ai/claude-agent-sdk": "^0.1.76",
25
25
  "@anthropic-ai/sdk": "^0.71.2",
26
26
  "@linear/sdk": "^74.0.0",
27
+ "@lmnr-ai/lmnr": "^0.8.11",
27
28
  "commander": "^12.1.0"
28
29
  },
29
30
  "devDependencies": {
@@ -1,11 +0,0 @@
1
- {
2
- "name": "claude-linear-agent",
3
- "version": "0.1.0",
4
- "description": "Skills and MCP integrations for the Linear AI agent — Linear, GitHub, Notion, and Context7",
5
- "author": {
6
- "name": "Matt Aliev"
7
- },
8
- "repository": "https://github.com/mattaliev/claude-linear-agent",
9
- "license": "MIT",
10
- "keywords": ["linear", "agent", "mcp", "notion", "github", "context7"]
11
- }
@@ -1,23 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "linear": {
4
- "type": "http",
5
- "url": "https://mcp.linear.app/mcp",
6
- "headers": {
7
- "Authorization": "Bearer ${LINEAR_ACCESS_TOKEN}"
8
- }
9
- },
10
- "notion": {
11
- "type": "http",
12
- "url": "https://mcp.notion.com/mcp",
13
- "headers": {
14
- "Authorization": "Bearer ${NOTION_API_KEY}",
15
- "Notion-Version": "2025-09-03"
16
- }
17
- },
18
- "context7": {
19
- "command": "npx",
20
- "args": ["-y", "@upstash/context7-mcp", "--api-key", "${CONTEXT7_API_KEY}"]
21
- }
22
- }
23
- }
@@ -1,13 +0,0 @@
1
- {
2
- "enabledPlugins": {
3
- "agent-sdk-dev@claude-plugins-official": true,
4
- "plugin-dev@claude-plugins-official": true,
5
- "code-simplifier@claude-plugins-official": true,
6
- "code-review@claude-plugins-official": true,
7
- "pr-review-toolkit@claude-plugins-official": true
8
- },
9
- "env": {
10
- "ENABLE_TOOL_SEARCH": "true",
11
- "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
12
- }
13
- }
@@ -1,140 +0,0 @@
1
- ---
2
- name: Doc Drift Check
3
- description: This skill should be used when the user asks to "check docs for drift", "compare code changes against documentation", "review docs after PR", "find outdated documentation", "check if docs match the code", "verify documentation is up to date", or after completing a pull request review to verify documentation accuracy. Analyzes code changes against project docs, CLAUDE.md, database schema, Notion module pages, and Notion processes to catch mismatches.
4
- ---
5
-
6
- # Doc Drift Check
7
-
8
- Analyze code changes from a PR or issue against all project documentation — both in the repository and in Notion — to catch mismatches that would lead to stale docs. Write a severity-categorized comment to the Linear issue only when meaningful drift is found.
9
-
10
- ## When to Use
11
-
12
- Invoke manually after reviewing a pull request or completing an issue review. Skip for trivial changes (typo fixes, formatting, dependency bumps) where doc drift is impossible.
13
-
14
- ## Workflow
15
-
16
- ### 1. Gather Context
17
-
18
- Collect three inputs before analysis:
19
-
20
- **Code changes** — Get the diff for the issue's PR:
21
- - Use GitHub MCP to read the PR diff
22
- - Note which files changed and the nature of changes (new files, modified APIs, removed features, config changes, model changes, service changes)
23
-
24
- **Linear issue** — Read the issue description and metadata:
25
- - Issue title, description, and acceptance criteria
26
- - Team identifier (determines which Notion workspace to check):
27
- - `KPL-` → Platform
28
- - `KPE-` → Personal
29
- - `KBU-` → Business
30
- - Links to Notion pages or external docs in the description
31
-
32
- **Repository documentation** — Read relevant local docs:
33
- - `docs/` directory — scan for files related to changed code areas
34
- - `CLAUDE.md` — project overview, architecture, env vars, structure
35
- - Database schema files — check if schema changes are reflected
36
-
37
- ### 2. Identify Relevant Notion Documentation
38
-
39
- Based on the team identifier from the Linear issue, fetch the corresponding Product Development page in Notion. These pages contain module documentation, processes, and feature documents for each team.
40
-
41
- **Team → Notion Product Development page mapping:**
42
-
43
- | Team Prefix | Team | Notion Page ID |
44
- |---|---|---|
45
- | `KPL-` | Platform | `24c80383e1518012a3c2c410588782d5` |
46
- | `KPE-` | Personal | `23a80383e15180ae91bae32b407ebaf9` |
47
- | `KBU-` | Business | `24c80383e15180e19e78cfca4b49fe66` |
48
-
49
- **Scan the Product Development page** for the appropriate team:
50
- 1. Fetch the page and scan its child pages
51
- 2. Identify module pages that relate to the changed code area
52
- 3. Read those module pages — they describe models, services, and APIs for each module
53
-
54
- **Check the Processes database** (`252cc951ac514d86ad3b6d9fc689409c`):
55
- 1. The Processes database has a "Модули" relation linking processes to modules
56
- 2. If code changes affect a module, find linked processes
57
- 3. Check if process descriptions still match the implementation
58
-
59
- ### 3. Analyze for Mismatches
60
-
61
- Compare code changes against each relevant documentation source. Look for:
62
-
63
- - **Model drift** — Code adds/removes/renames model fields, but module documentation in Notion still describes the old schema
64
- - **Service drift** — New services added or service logic changed, but module page doesn't list them
65
- - **API drift** — Endpoints added/changed/removed, but docs still reference old API
66
- - **Process drift** — Implementation changes how a process works, but the process page in Notion doesn't reflect it
67
- - **Missing documentation** — New module, feature, or config with no corresponding docs
68
- - **Stale references** — Docs reference removed code, old file paths, or deprecated models
69
- - **Issue description mismatch** — What was implemented differs from what the issue describes
70
- - **Structural drift** — File/directory structure changed but project structure docs not updated
71
- - **Environment drift** — New env vars, config values, or dependencies not documented
72
-
73
- For detailed severity classification examples, consult `references/severity-guide.md`.
74
-
75
- ### 4. Decision Gate
76
-
77
- After analysis, decide whether to comment:
78
-
79
- - **No mismatches found** → Do nothing. Do not write a "no issues found" comment.
80
- - **Only trivial mismatches** (e.g., a slightly outdated example that doesn't mislead) → Skip.
81
- - **Meaningful mismatches** → Proceed to write comment.
82
-
83
- The bar for commenting: would someone reading the docs be misled or confused by the current state? If yes, comment. If not, skip.
84
-
85
- ### 5. Write Linear Comment
86
-
87
- Post a comment on the Linear issue using this format:
88
-
89
- ```
90
- 📋 Doc Drift Report
91
-
92
- [1-2 sentence summary of what was found]
93
-
94
- 🔴 Critical
95
- - [Notion: Module "Payments" → Models section] — Code adds TransferFee model but module page doesn't list it
96
- - [File: `CLAUDE.md` env vars table] — New SYNC_API_KEY env var required but not listed
97
-
98
- 🟡 Moderate
99
- - [Notion: Process "Customer Onboarding"] — Step 3 now calls ProviderService instead of direct API, process diagram outdated
100
- - [File: `docs/architecture.md`] — New endpoint POST /api/v2/transfers not documented
101
-
102
- 🟢 Light
103
- - [Notion: Module "Crypto" → Services section] — CryptoSigningService renamed to AccessKeyService in code
104
-
105
- ---
106
- Suggested actions:
107
- - Update Notion module page "Payments" with new TransferFee model
108
- - Add SYNC_API_KEY to CLAUDE.md environment variables table
109
- - Update process diagram in "Customer Onboarding" process page
110
- ```
111
-
112
- **Formatting rules:**
113
- - Use severity emojis: 🔴 Critical, 🟡 Moderate, 🟢 Light
114
- - Prefix with source: `[Notion: ...]` or `[File: ...]`
115
- - Include specific page/section references
116
- - Include a "Suggested actions" section with concrete fixes
117
- - Omit empty severity categories
118
-
119
- ## Severity Classification Quick Reference
120
-
121
- | Severity | Description |
122
- |---|---|
123
- | 🔴 Critical | Model/schema changes undocumented, API changes, env var changes, breaking behavior, architecture shifts — someone would build against wrong assumptions |
124
- | 🟡 Moderate | New services undocumented, process flow changes, new features without docs, workflow changes — someone would miss important capabilities |
125
- | 🟢 Light | Renamed entities, outdated examples, minor wording, service method renames — someone might be briefly confused |
126
-
127
- For detailed examples and edge cases, see `references/severity-guide.md`.
128
-
129
- ## Tools Used
130
-
131
- - **GitHub MCP** — read PR diffs and changed files
132
- - **Linear MCP** — read issue description and team, post comments
133
- - **Notion MCP** — fetch Product Development pages, module pages, process pages
134
- - **Read, Grep, Glob** — scan local documentation files in the repository
135
-
136
- ## Additional Resources
137
-
138
- ### Reference Files
139
-
140
- - **`references/severity-guide.md`** — Detailed severity classification with examples, edge cases, and per-source guidance
@@ -1,174 +0,0 @@
1
- # Severity Classification Guide
2
-
3
- Detailed guide for categorizing doc drift findings by severity level. Use this when analyzing mismatches between code changes and documentation.
4
-
5
- ## 🔴 Critical — Would Cause Wrong Assumptions
6
-
7
- These mismatches would cause someone to build against incorrect assumptions or make wrong decisions.
8
-
9
- ### Model/Schema Changes
10
-
11
- - Code adds a new model but the Notion module page doesn't list it
12
- - Code removes or renames a model field, but the module documentation still references the old field
13
- - Relationship between models changed (e.g., ForeignKey → ManyToMany) but not reflected in docs
14
- - New required field added to a model but not documented in the module's models section
15
-
16
- **Example:**
17
- > Code adds `AccessKey` model to `andgate_crypto` module, but the Crypto module page in Notion under Platform's Product Development doesn't mention it.
18
-
19
- ### API/Endpoint Changes
20
-
21
- - New endpoint added without documentation
22
- - Endpoint removed but still listed in docs
23
- - Request/response format changed but docs show old format
24
- - Authentication requirements changed
25
-
26
- ### Environment & Configuration
27
-
28
- - New environment variable required but not in CLAUDE.md or deployment docs
29
- - Configuration option removed but still documented
30
- - Default value changed for existing config
31
-
32
- ### Architecture Changes
33
-
34
- - New module/app created without corresponding Notion documentation
35
- - Service dependencies changed (module A now depends on module B, but docs don't show this)
36
- - Database migration adds/removes tables not reflected in schema docs
37
-
38
- ---
39
-
40
- ## 🟡 Moderate — Would Miss Important Capabilities
41
-
42
- These mismatches would cause someone to miss important features or follow outdated procedures.
43
-
44
- ### Service Changes
45
-
46
- - New service class added to a module but module page doesn't list it in the services section
47
- - Service method signature changed (different params) but process docs reference old signature
48
- - Service now calls a different external provider but process diagrams show old flow
49
-
50
- **Example:**
51
- > Code adds `AccessKeyService` to handle crypto signing, but the Crypto module page doesn't list it under Services.
52
-
53
- ### Process Flow Changes
54
-
55
- - Steps in a business process reordered or modified
56
- - New step added to a process (e.g., new validation step in onboarding)
57
- - Conditional logic changed (e.g., different handling for B2B vs B2C)
58
- - Process now has prerequisites that aren't documented
59
-
60
- **Example:**
61
- > Customer onboarding now requires provider-specific KYC before account creation, but the process page still shows a single KYC step.
62
-
63
- ### Feature Documentation Gaps
64
-
65
- - New feature implemented but no feature document exists
66
- - Feature behavior changed significantly but feature docs describe old behavior
67
- - Feature flag added without documentation in relevant places
68
-
69
- ### Workflow Changes
70
-
71
- - Webhook handling changed but webhook documentation outdated
72
- - Background task behavior modified but not reflected in process docs
73
- - Error handling strategy changed for a module
74
-
75
- ---
76
-
77
- ## 🟢 Light — Brief Confusion Only
78
-
79
- These mismatches would cause someone brief confusion but wouldn't lead to incorrect work.
80
-
81
- ### Naming/Renaming
82
-
83
- - Service or utility class renamed but docs use old name
84
- - File moved to different directory but docs reference old path
85
- - Variable or constant renamed
86
-
87
- **Example:**
88
- > `CryptoSigningService` renamed to `AccessKeyService` in code but Notion module page still says `CryptoSigningService`.
89
-
90
- ### Outdated Examples
91
-
92
- - Code example in docs uses old import path
93
- - Example shows deprecated API usage but functionally equivalent
94
- - Test examples reference old fixtures
95
-
96
- ### Minor Wording
97
-
98
- - Documentation says "will be implemented" for already-implemented features
99
- - Status markers (TODO, WIP) left in docs for completed work
100
- - Comments in code reference old Notion page names
101
-
102
- ---
103
-
104
- ## Per-Source Analysis Guide
105
-
106
- ### Notion Module Pages
107
-
108
- Module pages describe models and services for each module. When checking:
109
-
110
- 1. **Models section** — Compare listed models against actual Django models in the code
111
- 2. **Services section** — Compare listed services against actual service classes
112
- 3. **API section** — Compare listed endpoints against actual URL configs
113
- 4. **Shared models** — Verify cross-module dependencies are still accurate
114
- 5. **Dependency graph** — Check if module interdependencies changed
115
-
116
- ### Notion Processes Database
117
-
118
- Process pages describe business workflows. When checking:
119
-
120
- 1. **Process steps** — Do the documented steps match the actual code flow?
121
- 2. **Prerequisites** — Are process prerequisites still accurate?
122
- 3. **Provider interactions** — Do provider-specific flows match current implementation?
123
- 4. **Status transitions** — Do documented state machines match code?
124
- 5. **Related modules** — Is the "Модули" relation still correct?
125
-
126
- ### Repository docs/ Directory
127
-
128
- Local documentation files. When checking:
129
-
130
- 1. **Architecture docs** — Do they reflect current module structure?
131
- 2. **API docs** — Do endpoint descriptions match implementations?
132
- 3. **Setup/deployment docs** — Are instructions still accurate?
133
-
134
- ### CLAUDE.md
135
-
136
- Project-level documentation. When checking:
137
-
138
- 1. **Environment variables table** — All required vars listed?
139
- 2. **Project structure** — Does the tree match actual directory layout?
140
- 3. **Technology stack** — Any new dependencies or tools?
141
- 4. **Key documentation links** — Do referenced docs still exist?
142
-
143
- ### Database Schema
144
-
145
- Schema documentation. When checking:
146
-
147
- 1. **Table definitions** — Do they match current migrations?
148
- 2. **Relationships** — Are FK/M2M relations documented correctly?
149
- 3. **Indexes** — Any new indexes not mentioned in schema docs?
150
- 4. **New tables** — Any new migrations creating tables not in schema docs?
151
-
152
- ---
153
-
154
- ## Edge Cases
155
-
156
- ### When NOT to Flag
157
-
158
- - Code comments that are slightly outdated (not worth a Linear comment)
159
- - Test file documentation being slightly behind (tests are self-documenting)
160
- - Third-party library version bumps with no behavior change
161
- - Formatting-only changes to documentation files
162
- - Internal refactoring that doesn't change public interfaces or behavior
163
-
164
- ### When to Escalate to Critical
165
-
166
- Even if a change seems small, escalate if:
167
- - It affects an external-facing API that developers build against
168
- - It changes model fields that other services query
169
- - It modifies environment variables needed for deployment
170
- - It alters the behavior described in a process that operations follows
171
-
172
- ### Multiple Small Issues
173
-
174
- If there are many Light issues (5+) concentrated in one documentation area, consider grouping them and elevating to a single Moderate finding with a suggestion to do a documentation review for that area.
@@ -1,11 +0,0 @@
1
- {
2
- "name": "kartman",
3
- "version": "0.1.0",
4
- "description": "Skills and MCP integrations for the Linear AI agent — Linear, GitHub, Notion, and Context7",
5
- "author": {
6
- "name": "Matt Aliev"
7
- },
8
- "repository": "https://github.com/mattaliev/kartman",
9
- "license": "MIT",
10
- "keywords": ["linear", "agent", "mcp", "notion", "github", "context7"]
11
- }
@@ -1,23 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "linear": {
4
- "type": "http",
5
- "url": "https://mcp.linear.app/mcp",
6
- "headers": {
7
- "Authorization": "Bearer ${LINEAR_ACCESS_TOKEN}"
8
- }
9
- },
10
- "notion": {
11
- "type": "http",
12
- "url": "https://mcp.notion.com/mcp",
13
- "headers": {
14
- "Authorization": "Bearer ${NOTION_API_KEY}",
15
- "Notion-Version": "2025-09-03"
16
- }
17
- },
18
- "context7": {
19
- "command": "npx",
20
- "args": ["-y", "@upstash/context7-mcp", "--api-key", "${CONTEXT7_API_KEY}"]
21
- }
22
- }
23
- }
@@ -1,59 +0,0 @@
1
- ---
2
- name: linear-issue
3
- description: Load a Linear issue into context. Provide an issue ID or derive it from the current branch name.
4
- argument-hint: "[ISSUE-ID] [--branch]"
5
- ---
6
-
7
- # Load Linear Issue
8
-
9
- Load a Linear issue into context to work on it.
10
-
11
- **User arguments:** $ARGUMENTS
12
-
13
- ## Step 1: Parse Arguments
14
-
15
- Parse the arguments string above:
16
- - If it contains an issue identifier (e.g. `KPE-143`, `KR-1032` — format: 2-4 uppercase letters, dash, number), use that as the issue ID
17
- - If it contains `--branch`, the user wants a branch created for this issue
18
- - If no issue identifier is provided, derive it from the current git branch name:
19
- 1. Run `git branch --show-current` to get the current branch
20
- 2. Extract the issue identifier from the branch name. Common patterns:
21
- - `{prefix}-{TEAM}-{number}-{slug}` → extract `{TEAM}-{number}` (e.g. `MAT-KPL-56-add-auth` → `KPL-56`)
22
- - `feature/{TEAM}-{number}_{slug}` → extract `{TEAM}-{number}`
23
- - `{TEAM}-{number}-{slug}` → extract `{TEAM}-{number}`
24
- 3. If no identifier can be extracted, ask the user for the issue ID
25
-
26
- ## Step 2: Fetch the Issue from Linear
27
-
28
- Use the Linear MCP to fetch the issue details:
29
- 1. Search for the issue by its identifier
30
- 2. Load the full issue including: title, description, state, priority, assignee, labels, comments, and parent issue/project info
31
- 3. If the issue has a project, note the project name and ID for context
32
-
33
- ## Step 3: Display Issue Context
34
-
35
- Present the issue information clearly:
36
- - **Identifier and Title**
37
- - **Status** and **Priority**
38
- - **Description** (full text)
39
- - **Labels** and **Assignee**
40
- - **Project** (if any)
41
- - **Key comments** (especially any progress checkpoints from previous sessions)
42
-
43
- ## Step 4: Branch Creation (only if --branch was passed)
44
-
45
- If `--branch` was in the arguments:
46
-
47
- 1. Read the repository's `CLAUDE.md` and `docs/git-conventions.md` (if it exists) to understand branching conventions
48
- 2. Also check recent branches with `git branch -a` to understand the naming pattern used in this repo
49
- 3. Determine the correct branch name following the repo's conventions. If no convention is found, default to: `feature/{issue-identifier}_{short-slug}` where `{short-slug}` is a kebab-case summary of the issue title (keep it concise, 2-4 words)
50
- 4. Check if a branch for this issue already exists: `git branch -a | grep -i {issue-identifier}`
51
- - If a branch already exists, check it out instead of creating a new one
52
- - Tell the user you found an existing branch and checked it out
53
- 5. If no existing branch, create and checkout the new branch from the current branch: `git checkout -b {branch-name}`
54
-
55
- ## Important Notes
56
-
57
- - This command is used across multiple repositories. Always check the current repository's `CLAUDE.md` and recent branches/PRs to follow its specific conventions.
58
- - If the issue has checkpoint comments from previous sessions, highlight the most recent one — it contains the continuation point.
59
- - Keep the output concise but complete. The user needs enough context to start working on the issue.
@@ -1,70 +0,0 @@
1
- ---
2
- name: linear-project
3
- description: Load a Linear project into context. Provide a project name or derive it from the current branch's issue.
4
- argument-hint: "[PROJECT-NAME] [--branch]"
5
- ---
6
-
7
- # Load Linear Project
8
-
9
- Load a Linear project into context to work on it.
10
-
11
- **User arguments:** $ARGUMENTS
12
-
13
- ## Step 1: Parse Arguments
14
-
15
- Parse the arguments string above:
16
- - If it contains a project name (any text that isn't `--branch`), use that to search for the project in Linear
17
- - If it contains `--branch`, the user wants a feature branch created for this project
18
- - If no project name is provided, derive it from the current branch:
19
- 1. Run `git branch --show-current` to get the current branch
20
- 2. Extract the issue identifier from the branch name. Common patterns:
21
- - `{prefix}-{TEAM}-{number}-{slug}` → extract `{TEAM}-{number}` (e.g. `MAT-KPL-56-add-auth` → `KPL-56`)
22
- - `feature/{TEAM}-{number}_{slug}` → extract `{TEAM}-{number}`
23
- - `{TEAM}-{number}-{slug}` → extract `{TEAM}-{number}`
24
- 3. Use the Linear MCP to fetch that issue and find which project it belongs to
25
- 4. If the issue doesn't belong to a project, or no identifier can be extracted, ask the user for the project name
26
-
27
- ## Step 2: Fetch the Project from Linear
28
-
29
- Use the Linear MCP to load the full project details:
30
- 1. Project name, description, status, lead, and members
31
- 2. All issues in the project — with their identifiers, titles, statuses, priorities, and assignees
32
- 3. Any project updates or milestones
33
-
34
- ## Step 3: Display Project Context
35
-
36
- Present the project information clearly:
37
-
38
- - **Project Name** and **Status**
39
- - **Description** (full text)
40
- - **Lead** and **Members**
41
- - **Progress** — count of issues by status (e.g. 5 Done, 3 In Progress, 8 Todo)
42
-
43
- ### Issues Breakdown
44
-
45
- List all project issues grouped by status, showing:
46
- - Identifier, title, priority, assignee
47
- - Highlight any blocked issues
48
-
49
- ### Recent Updates
50
-
51
- Show any recent project updates or milestone comments.
52
-
53
- ## Step 4: Branch Creation (only if --branch was passed)
54
-
55
- If `--branch` was in the arguments:
56
-
57
- 1. Read the repository's `CLAUDE.md` and `docs/git-conventions.md` (if it exists) to understand branching conventions for feature/project branches
58
- 2. Also check recent branches with `git branch -a` to understand the naming pattern used in this repo
59
- 3. Determine the correct branch name following the repo's conventions. If no convention is found, default to: `feature/{short-project-slug}` where `{short-project-slug}` is a kebab-case version of the project name (e.g. "Модуль Payments" → `feature/payments`)
60
- 4. Check if a branch for this project already exists: look for branches that match the project theme in `git branch -a`
61
- - If a matching branch already exists, check it out instead of creating a new one
62
- - Tell the user you found an existing branch and checked it out
63
- 5. If no existing branch, create and checkout the new branch from the current branch: `git checkout -b {branch-name}`
64
-
65
- ## Important Notes
66
-
67
- - This command is used across multiple repositories. Always check the current repository's `CLAUDE.md` and recent branches/PRs to follow its specific conventions.
68
- - For projects with many issues, organize the display so it's scannable — group by status, sort by priority within groups.
69
- - If the project has a Notion planning document linked, mention it so the user can reference it.
70
- - Keep the output concise but complete. The user needs the full project picture to make decisions.
@@ -1,13 +0,0 @@
1
- {
2
- "enabledPlugins": {
3
- "agent-sdk-dev@claude-plugins-official": true,
4
- "plugin-dev@claude-plugins-official": true,
5
- "code-simplifier@claude-plugins-official": true,
6
- "code-review@claude-plugins-official": true,
7
- "pr-review-toolkit@claude-plugins-official": true
8
- },
9
- "env": {
10
- "ENABLE_TOOL_SEARCH": "true",
11
- "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
12
- }
13
- }
@@ -1,140 +0,0 @@
1
- ---
2
- name: Doc Drift Check
3
- description: This skill should be used when the user asks to "check docs for drift", "compare code changes against documentation", "review docs after PR", "find outdated documentation", "check if docs match the code", "verify documentation is up to date", or after completing a pull request review to verify documentation accuracy. Analyzes code changes against project docs, CLAUDE.md, database schema, Notion module pages, and Notion processes to catch mismatches.
4
- ---
5
-
6
- # Doc Drift Check
7
-
8
- Analyze code changes from a PR or issue against all project documentation — both in the repository and in Notion — to catch mismatches that would lead to stale docs. Write a severity-categorized comment to the Linear issue only when meaningful drift is found.
9
-
10
- ## When to Use
11
-
12
- Invoke manually after reviewing a pull request or completing an issue review. Skip for trivial changes (typo fixes, formatting, dependency bumps) where doc drift is impossible.
13
-
14
- ## Workflow
15
-
16
- ### 1. Gather Context
17
-
18
- Collect three inputs before analysis:
19
-
20
- **Code changes** — Get the diff for the issue's PR:
21
- - Use GitHub MCP to read the PR diff
22
- - Note which files changed and the nature of changes (new files, modified APIs, removed features, config changes, model changes, service changes)
23
-
24
- **Linear issue** — Read the issue description and metadata:
25
- - Issue title, description, and acceptance criteria
26
- - Team identifier (determines which Notion workspace to check):
27
- - `KPL-` → Platform
28
- - `KPE-` → Personal
29
- - `KBU-` → Business
30
- - Links to Notion pages or external docs in the description
31
-
32
- **Repository documentation** — Read relevant local docs:
33
- - `docs/` directory — scan for files related to changed code areas
34
- - `CLAUDE.md` — project overview, architecture, env vars, structure
35
- - Database schema files — check if schema changes are reflected
36
-
37
- ### 2. Identify Relevant Notion Documentation
38
-
39
- Based on the team identifier from the Linear issue, fetch the corresponding Product Development page in Notion. These pages contain module documentation, processes, and feature documents for each team.
40
-
41
- **Team → Notion Product Development page mapping:**
42
-
43
- | Team Prefix | Team | Notion Page ID |
44
- |---|---|---|
45
- | `KPL-` | Platform | `24c80383e1518012a3c2c410588782d5` |
46
- | `KPE-` | Personal | `23a80383e15180ae91bae32b407ebaf9` |
47
- | `KBU-` | Business | `24c80383e15180e19e78cfca4b49fe66` |
48
-
49
- **Scan the Product Development page** for the appropriate team:
50
- 1. Fetch the page and scan its child pages
51
- 2. Identify module pages that relate to the changed code area
52
- 3. Read those module pages — they describe models, services, and APIs for each module
53
-
54
- **Check the Processes database** (`252cc951ac514d86ad3b6d9fc689409c`):
55
- 1. The Processes database has a "Модули" relation linking processes to modules
56
- 2. If code changes affect a module, find linked processes
57
- 3. Check if process descriptions still match the implementation
58
-
59
- ### 3. Analyze for Mismatches
60
-
61
- Compare code changes against each relevant documentation source. Look for:
62
-
63
- - **Model drift** — Code adds/removes/renames model fields, but module documentation in Notion still describes the old schema
64
- - **Service drift** — New services added or service logic changed, but module page doesn't list them
65
- - **API drift** — Endpoints added/changed/removed, but docs still reference old API
66
- - **Process drift** — Implementation changes how a process works, but the process page in Notion doesn't reflect it
67
- - **Missing documentation** — New module, feature, or config with no corresponding docs
68
- - **Stale references** — Docs reference removed code, old file paths, or deprecated models
69
- - **Issue description mismatch** — What was implemented differs from what the issue describes
70
- - **Structural drift** — File/directory structure changed but project structure docs not updated
71
- - **Environment drift** — New env vars, config values, or dependencies not documented
72
-
73
- For detailed severity classification examples, consult `references/severity-guide.md`.
74
-
75
- ### 4. Decision Gate
76
-
77
- After analysis, decide whether to comment:
78
-
79
- - **No mismatches found** → Do nothing. Do not write a "no issues found" comment.
80
- - **Only trivial mismatches** (e.g., a slightly outdated example that doesn't mislead) → Skip.
81
- - **Meaningful mismatches** → Proceed to write comment.
82
-
83
- The bar for commenting: would someone reading the docs be misled or confused by the current state? If yes, comment. If not, skip.
84
-
85
- ### 5. Write Linear Comment
86
-
87
- Post a comment on the Linear issue using this format:
88
-
89
- ```
90
- 📋 Doc Drift Report
91
-
92
- [1-2 sentence summary of what was found]
93
-
94
- 🔴 Critical
95
- - [Notion: Module "Payments" → Models section] — Code adds TransferFee model but module page doesn't list it
96
- - [File: `CLAUDE.md` env vars table] — New SYNC_API_KEY env var required but not listed
97
-
98
- 🟡 Moderate
99
- - [Notion: Process "Customer Onboarding"] — Step 3 now calls ProviderService instead of direct API, process diagram outdated
100
- - [File: `docs/architecture.md`] — New endpoint POST /api/v2/transfers not documented
101
-
102
- 🟢 Light
103
- - [Notion: Module "Crypto" → Services section] — CryptoSigningService renamed to AccessKeyService in code
104
-
105
- ---
106
- Suggested actions:
107
- - Update Notion module page "Payments" with new TransferFee model
108
- - Add SYNC_API_KEY to CLAUDE.md environment variables table
109
- - Update process diagram in "Customer Onboarding" process page
110
- ```
111
-
112
- **Formatting rules:**
113
- - Use severity emojis: 🔴 Critical, 🟡 Moderate, 🟢 Light
114
- - Prefix with source: `[Notion: ...]` or `[File: ...]`
115
- - Include specific page/section references
116
- - Include a "Suggested actions" section with concrete fixes
117
- - Omit empty severity categories
118
-
119
- ## Severity Classification Quick Reference
120
-
121
- | Severity | Description |
122
- |---|---|
123
- | 🔴 Critical | Model/schema changes undocumented, API changes, env var changes, breaking behavior, architecture shifts — someone would build against wrong assumptions |
124
- | 🟡 Moderate | New services undocumented, process flow changes, new features without docs, workflow changes — someone would miss important capabilities |
125
- | 🟢 Light | Renamed entities, outdated examples, minor wording, service method renames — someone might be briefly confused |
126
-
127
- For detailed examples and edge cases, see `references/severity-guide.md`.
128
-
129
- ## Tools Used
130
-
131
- - **GitHub MCP** — read PR diffs and changed files
132
- - **Linear MCP** — read issue description and team, post comments
133
- - **Notion MCP** — fetch Product Development pages, module pages, process pages
134
- - **Read, Grep, Glob** — scan local documentation files in the repository
135
-
136
- ## Additional Resources
137
-
138
- ### Reference Files
139
-
140
- - **`references/severity-guide.md`** — Detailed severity classification with examples, edge cases, and per-source guidance
@@ -1,174 +0,0 @@
1
- # Severity Classification Guide
2
-
3
- Detailed guide for categorizing doc drift findings by severity level. Use this when analyzing mismatches between code changes and documentation.
4
-
5
- ## 🔴 Critical — Would Cause Wrong Assumptions
6
-
7
- These mismatches would cause someone to build against incorrect assumptions or make wrong decisions.
8
-
9
- ### Model/Schema Changes
10
-
11
- - Code adds a new model but the Notion module page doesn't list it
12
- - Code removes or renames a model field, but the module documentation still references the old field
13
- - Relationship between models changed (e.g., ForeignKey → ManyToMany) but not reflected in docs
14
- - New required field added to a model but not documented in the module's models section
15
-
16
- **Example:**
17
- > Code adds `AccessKey` model to `andgate_crypto` module, but the Crypto module page in Notion under Platform's Product Development doesn't mention it.
18
-
19
- ### API/Endpoint Changes
20
-
21
- - New endpoint added without documentation
22
- - Endpoint removed but still listed in docs
23
- - Request/response format changed but docs show old format
24
- - Authentication requirements changed
25
-
26
- ### Environment & Configuration
27
-
28
- - New environment variable required but not in CLAUDE.md or deployment docs
29
- - Configuration option removed but still documented
30
- - Default value changed for existing config
31
-
32
- ### Architecture Changes
33
-
34
- - New module/app created without corresponding Notion documentation
35
- - Service dependencies changed (module A now depends on module B, but docs don't show this)
36
- - Database migration adds/removes tables not reflected in schema docs
37
-
38
- ---
39
-
40
- ## 🟡 Moderate — Would Miss Important Capabilities
41
-
42
- These mismatches would cause someone to miss important features or follow outdated procedures.
43
-
44
- ### Service Changes
45
-
46
- - New service class added to a module but module page doesn't list it in the services section
47
- - Service method signature changed (different params) but process docs reference old signature
48
- - Service now calls a different external provider but process diagrams show old flow
49
-
50
- **Example:**
51
- > Code adds `AccessKeyService` to handle crypto signing, but the Crypto module page doesn't list it under Services.
52
-
53
- ### Process Flow Changes
54
-
55
- - Steps in a business process reordered or modified
56
- - New step added to a process (e.g., new validation step in onboarding)
57
- - Conditional logic changed (e.g., different handling for B2B vs B2C)
58
- - Process now has prerequisites that aren't documented
59
-
60
- **Example:**
61
- > Customer onboarding now requires provider-specific KYC before account creation, but the process page still shows a single KYC step.
62
-
63
- ### Feature Documentation Gaps
64
-
65
- - New feature implemented but no feature document exists
66
- - Feature behavior changed significantly but feature docs describe old behavior
67
- - Feature flag added without documentation in relevant places
68
-
69
- ### Workflow Changes
70
-
71
- - Webhook handling changed but webhook documentation outdated
72
- - Background task behavior modified but not reflected in process docs
73
- - Error handling strategy changed for a module
74
-
75
- ---
76
-
77
- ## 🟢 Light — Brief Confusion Only
78
-
79
- These mismatches would cause someone brief confusion but wouldn't lead to incorrect work.
80
-
81
- ### Naming/Renaming
82
-
83
- - Service or utility class renamed but docs use old name
84
- - File moved to different directory but docs reference old path
85
- - Variable or constant renamed
86
-
87
- **Example:**
88
- > `CryptoSigningService` renamed to `AccessKeyService` in code but Notion module page still says `CryptoSigningService`.
89
-
90
- ### Outdated Examples
91
-
92
- - Code example in docs uses old import path
93
- - Example shows deprecated API usage but functionally equivalent
94
- - Test examples reference old fixtures
95
-
96
- ### Minor Wording
97
-
98
- - Documentation says "will be implemented" for already-implemented features
99
- - Status markers (TODO, WIP) left in docs for completed work
100
- - Comments in code reference old Notion page names
101
-
102
- ---
103
-
104
- ## Per-Source Analysis Guide
105
-
106
- ### Notion Module Pages
107
-
108
- Module pages describe models and services for each module. When checking:
109
-
110
- 1. **Models section** — Compare listed models against actual Django models in the code
111
- 2. **Services section** — Compare listed services against actual service classes
112
- 3. **API section** — Compare listed endpoints against actual URL configs
113
- 4. **Shared models** — Verify cross-module dependencies are still accurate
114
- 5. **Dependency graph** — Check if module interdependencies changed
115
-
116
- ### Notion Processes Database
117
-
118
- Process pages describe business workflows. When checking:
119
-
120
- 1. **Process steps** — Do the documented steps match the actual code flow?
121
- 2. **Prerequisites** — Are process prerequisites still accurate?
122
- 3. **Provider interactions** — Do provider-specific flows match current implementation?
123
- 4. **Status transitions** — Do documented state machines match code?
124
- 5. **Related modules** — Is the "Модули" relation still correct?
125
-
126
- ### Repository docs/ Directory
127
-
128
- Local documentation files. When checking:
129
-
130
- 1. **Architecture docs** — Do they reflect current module structure?
131
- 2. **API docs** — Do endpoint descriptions match implementations?
132
- 3. **Setup/deployment docs** — Are instructions still accurate?
133
-
134
- ### CLAUDE.md
135
-
136
- Project-level documentation. When checking:
137
-
138
- 1. **Environment variables table** — All required vars listed?
139
- 2. **Project structure** — Does the tree match actual directory layout?
140
- 3. **Technology stack** — Any new dependencies or tools?
141
- 4. **Key documentation links** — Do referenced docs still exist?
142
-
143
- ### Database Schema
144
-
145
- Schema documentation. When checking:
146
-
147
- 1. **Table definitions** — Do they match current migrations?
148
- 2. **Relationships** — Are FK/M2M relations documented correctly?
149
- 3. **Indexes** — Any new indexes not mentioned in schema docs?
150
- 4. **New tables** — Any new migrations creating tables not in schema docs?
151
-
152
- ---
153
-
154
- ## Edge Cases
155
-
156
- ### When NOT to Flag
157
-
158
- - Code comments that are slightly outdated (not worth a Linear comment)
159
- - Test file documentation being slightly behind (tests are self-documenting)
160
- - Third-party library version bumps with no behavior change
161
- - Formatting-only changes to documentation files
162
- - Internal refactoring that doesn't change public interfaces or behavior
163
-
164
- ### When to Escalate to Critical
165
-
166
- Even if a change seems small, escalate if:
167
- - It affects an external-facing API that developers build against
168
- - It changes model fields that other services query
169
- - It modifies environment variables needed for deployment
170
- - It alters the behavior described in a process that operations follows
171
-
172
- ### Multiple Small Issues
173
-
174
- If there are many Light issues (5+) concentrated in one documentation area, consider grouping them and elevating to a single Moderate finding with a suggestion to do a documentation review for that area.
@@ -1,32 +0,0 @@
1
- name: Claude Code Review
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, ready_for_review, reopened]
6
-
7
- jobs:
8
- claude-review:
9
- runs-on: ubuntu-latest
10
- permissions:
11
- contents: write
12
- pull-requests: write
13
- issues: write
14
- id-token: write
15
-
16
- steps:
17
- - name: Checkout repository
18
- uses: actions/checkout@v4
19
- with:
20
- fetch-depth: 1
21
-
22
- - name: Run Claude Code Review
23
- id: claude-review
24
- uses: anthropics/claude-code-action@v1
25
- with:
26
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
27
- plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
28
- plugins: 'code-review@claude-code-plugins'
29
- prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
30
- # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
31
- # or https://code.claude.com/docs/en/cli-reference for available options
32
-
@@ -1,37 +0,0 @@
1
- name: Claude Code
2
-
3
- on:
4
- issue_comment:
5
- types: [created]
6
- pull_request_review_comment:
7
- types: [created]
8
- issues:
9
- types: [opened, assigned]
10
- pull_request_review:
11
- types: [submitted]
12
-
13
- jobs:
14
- claude:
15
- if: |
16
- (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17
- (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18
- (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19
- (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20
- runs-on: ubuntu-latest
21
- permissions:
22
- contents: write
23
- pull-requests: write
24
- issues: write
25
- id-token: write
26
- actions: read # Required for Claude to read CI results on PRs
27
- steps:
28
- - name: Checkout repository
29
- uses: actions/checkout@v4
30
- with:
31
- fetch-depth: 1
32
-
33
- - name: Run Claude Code
34
- id: claude
35
- uses: anthropics/claude-code-action@v1
36
- with:
37
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
@@ -1,11 +0,0 @@
1
- *.yml
2
- *.yaml
3
- *.d.ts
4
- node_modules
5
- coverage
6
- .nuxt
7
- .output
8
- .npmrc
9
- .nvmrc
10
- dist
11
- public