# Agent Manager Client TypeScript-based Claude Agent SDK client for automated issue handling in Gogs repositories. ## Overview This client uses the [@anthropic-ai/claude-agent-sdk](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) to provide AI-powered issue automation. It replaces the previous bash-based Claude Code implementation with a more robust, type-safe TypeScript solution. ## Features - **TypeScript Implementation**: Fully typed code with compile-time safety - **MCP Integration**: Connects to gogs-mcp server for Gogs API operations - **Issue Automation**: Automatically handles issues assigned to Claude - **Comment Processing**: Responds to issue comments and updates - **Label-Aware Behavior**: Adjusts behavior based on issue labels (question, documentation, bug, enhancement) - **Environment-Specific Configuration**: Supports different gogs-mcp paths via environment variables - **Per-Repository MCP Configuration**: Different repositories can use different MCP servers - **Dynamic Tool Discovery**: Automatically discovers and enables tools from all configured MCP servers - **Automatic Repository Management**: Clones repositories on demand and pulls latest changes - **Dynamic Git URL Fetching**: Retrieves SSH URLs from Gogs API instead of hardcoding - **Environment Setup**: Handles HOME, PATH, and XDG directory configuration automatically - **Project Memory Support**: Reads and includes CLAUDE.md files for project-specific context ## Architecture The client is organized into focused modules with clear responsibilities: ``` client/ ├── src/ │ ├── claude-client.ts # Main Claude Agent SDK client │ │ # - Handles issue automation requests │ │ # - Builds prompts with label-aware instructions │ │ # - Manages Claude Agent SDK sessions │ │ # - Reads and includes CLAUDE.md project memory │ │ │ ├── config.ts # Configuration management │ │ # - Loads .env files │ │ # - Generates MCP configurations │ │ # - Manages GOGS_MCP_PATH setting │ │ │ ├── mcpConfigManager.ts # MCP configuration loader │ │ # - Per-repository config support │ │ # - Global default config │ │ # - Environment variable substitution │ │ # - Security checks (file permissions) │ │ │ ├── toolDiscovery.ts # Dynamic tool discovery │ │ # - Discovers tools from MCP servers │ │ # - Includes built-in Claude Code tools │ │ # - Formats tool names (mcp__{server}__{tool}) │ │ │ ├── repository-manager.ts # Git repository operations │ │ # - Clones repositories on demand │ │ # - Pulls latest changes │ │ # - Environment setup (HOME, PATH, XDG) │ │ # - Agent Manager path detection │ │ │ ├── gogs-helper.ts # Gogs API helper functions │ │ # - Fetches SSH URLs from Gogs API │ │ # - Reads existing Git remote URLs │ │ # - Direct API access (pre-MCP) │ │ │ ├── types.ts # TypeScript type definitions │ │ # - IssueData, IssueHandlerResult │ │ # - ClaudeClientConfig, MCPServerConfig │ │ # - Type-safe interfaces │ │ │ └── index.ts # CLI entry point │ # - Parses command-line arguments │ # - Orchestrates repository management │ # - Invokes ClaudeClient │ ├── dist/ # Compiled JavaScript (generated by tsc) ├── package.json # Dependencies and scripts └── tsconfig.json # TypeScript configuration ``` ### Key Components **ClaudeClient** (`claude-client.ts`) - Main orchestrator for issue automation - Builds context-rich prompts with label-aware behavior - Manages Claude Agent SDK query lifecycle - Tracks costs, session IDs, and execution metrics **McpConfigManager** (`mcpConfigManager.ts`) - Three-tier configuration priority (repo → global → fallback) - Secure secret management with environment variables - File permission validation - Configuration creation and listing utilities **ToolDiscovery** (`toolDiscovery.ts`) - Connects to all configured MCP servers - Queries each server for available tools - Merges with built-in Claude Code tools - Returns complete tool list for Agent SDK **RepositoryManager** (`repository-manager.ts`) - Automatic Git operations (clone/pull) - Environment variable setup for systemd compatibility - XDG directory creation and management - Multi-location path detection ## Installation ```bash cd client npm install ``` ## Building ```bash npm run build ``` This compiles TypeScript to JavaScript in the `dist/` directory. ## Usage ### Programmatic API ```typescript import { ClaudeClient, Config, ToolDiscovery } from './client/dist/index.js'; // Load configuration Config.load('/path/to/repo'); // Generate MCP config (with dynamic per-repo support) const mcpConfig = Config.generateMcpConfig('/path/to/repo', 'owner', 'repo'); // Discover available tools automatically const allowedTools = await ToolDiscovery.discoverTools(mcpConfig); // Create client const client = new ClaudeClient({ workingDirectory: '/path/to/repo', mcpConfigPath: '/path/to/repo/.mcp-gogs.json', allowedTools, // Automatically discovered tools dangerouslySkipPermissions: true }); // Handle issue const result = await client.handleIssue({ owner: 'username', repo: 'repo-name', number: 42, title: 'Issue title', body: 'Issue description', action: 'opened', pusher: 'username', assignee: 'claude' }); console.log(result); ``` ### Command Line ```bash node dist/index.js [comment_body] [assignee] ``` ### Webhook Integration The client is called directly from `commands.json` for issue and issue_comment events. The TypeScript client handles all environment setup, repository management, and issue processing. ## Configuration ### Environment Variables The client loads environment variables from **two locations** (in priority order): 1. **Global configuration**: `~/.config/agent-manager/.env` (shared across all repositories) 2. **Repository-specific configuration**: `.env` in repository root (overrides global) This allows you to set common values (like `GOGS_ACCESS_TOKEN`) once in the global file, eliminating the need to duplicate them in every cloned repository. #### Global Configuration (`~/.config/agent-manager/.env`) Create this file to set global defaults for all repositories: ```env # Required: Gogs API authentication (applies to all repositories) GOGS_ACCESS_TOKEN=your-token-here GOGS_BASE_URL=https://git.smartbotics.ai # Optional: Path to gogs-mcp server GOGS_MCP_PATH=/data/gogs-mcp/dist/index.js ``` **Setup**: ```bash mkdir -p ~/.config/agent-manager cp /path/to/agent-manager/examples/global-env.example ~/.config/agent-manager/.env chmod 600 ~/.config/agent-manager/.env # Edit the file and add your values ``` #### Repository-Specific Configuration (`.env` in repository) Optional. Use this to override global values for specific repositories: ```env # Example: Use a different Gogs token for this specific repository GOGS_ACCESS_TOKEN=repo-specific-token # Example: Custom home directory for this repository HOME=/custom/home/path ``` **Notes**: - Repository-specific values **override** global values - If a repository doesn't have a `.env` file, it uses only global values - You no longer need to manually create `.env` files in every cloned repository ### Webhook Variables When called from `commands.json`, the client receives these variables from webhooks: - `{{repo_owner}}` - Repository owner (e.g., "fszontagh") - `{{repo}}` - Repository name (e.g., "agent-manager") - `{{pusher}}` - Username who triggered the webhook - `{{issue_number}}` - Issue number - `{{issue_title}}` - Issue title - `{{issue_body}}` - Issue description - `{{issue_action}}` - Action (opened, assigned, closed, reopened) - `{{comment_body}}` - Comment text (for issue_comment events) - `{{issue_assignee}}` - Assigned username (e.g., "claude") - `{{issue_labels}}` - Comma-separated label names (e.g., "bug,enhancement") ## Dynamic Tool Discovery The client **automatically discovers** available tools from all configured MCP servers at runtime. You don't need to manually configure the tool list. ### How It Works 1. The client loads the MCP configuration for the repository 2. `ToolDiscovery` connects to each configured MCP server 3. It queries each server for available tools using the MCP protocol 4. Tools are formatted as `mcp__{server-name}__{tool-name}` 5. Built-in Claude Code tools are added automatically 6. The complete list is passed to the Claude Agent SDK ### Built-in Tools (Always Available) - **File Operations**: `Read`, `Write`, `Edit` - **Shell Operations**: `Bash`, `Grep`, `Glob` - **Task Management**: `TodoWrite`, `Task` - **Web Access**: `WebFetch`, `WebSearch` - **Advanced**: `NotebookEdit`, `BashOutput`, `KillShell`, `Skill`, `SlashCommand` ### Default MCP Tools (from gogs-mcp) When using the default gogs-mcp server, these tools are automatically discovered: **User Tools:** - `mcp__gogs__get_current_user`, `mcp__gogs__get_user`, `mcp__gogs__search_users` **Repository Tools:** - `mcp__gogs__list_user_repositories`, `mcp__gogs__search_repositories`, `mcp__gogs__get_repository` - `mcp__gogs__create_repository`, `mcp__gogs__delete_repository` **Content Tools:** - `mcp__gogs__get_contents`, `mcp__gogs__get_raw_content` - `mcp__gogs__list_branches`, `mcp__gogs__get_commits` **Issue Tools:** - `mcp__gogs__list_issues`, `mcp__gogs__get_issue`, `mcp__gogs__create_issue`, `mcp__gogs__update_issue` - `mcp__gogs__list_issue_comments`, `mcp__gogs__create_issue_comment`, `mcp__gogs__update_issue_comment` ### Custom MCP Servers When you add a custom MCP server to your repository configuration, its tools are **automatically discovered and available** to Claude. No additional configuration needed! For example, if you configure a "github" MCP server with tools like "create_pr" and "list_repos", they will automatically be available as `mcp__github__create_pr` and `mcp__github__list_repos`. ## Label-Aware Behavior The Claude agent automatically adjusts its behavior based on issue labels. Labels are extracted from webhook payloads and influence how Claude approaches the task. ### Supported Labels **🔴 "question" Label** - **Behavior**: DO NOT implement code changes - **Purpose**: Provide information, guidance, and answers only - **Actions**: May read code for context but won't modify files - **Focus**: Helpful explanations, suggestions, and clarifications **📚 "documentation" Label** - **Behavior**: Focus on documentation files only - **Purpose**: Create, update, or improve documentation - **Acceptable Changes**: README.md, CLAUDE.md, other .md files, code comments - **Restrictions**: Avoid implementation changes unless needed for examples **🐛 "bug" Label** - **Behavior**: Identify and fix the root cause - **Purpose**: Resolve bugs and defects - **Actions**: Implement minimal changes to fix the bug - **Best Practice**: Add tests to prevent regression when appropriate **✨ "enhancement" Label** - **Behavior**: May implement code changes as requested - **Purpose**: Add new features or improvements - **Guidelines**: Follow existing patterns, consider backward compatibility ### How It Works 1. When an issue is assigned or commented on, the webhook includes label information 2. The `claude-client.ts` parses labels from the `{{issue_labels}}` variable 3. Based on detected labels, specific instructions are injected into the prompt 4. Claude receives clear guidance on expected behavior for the issue type ### Example If an issue is labeled with "question": ``` ⚠️ QUESTION LABEL DETECTED: - This issue is labeled as "question" - DO NOT implement any code changes or features - Your role is to provide information, guidance, and answers only - You may read code to understand context, but do not modify files - Respond with helpful explanations, suggestions, or clarifications ``` ## MCP Configuration System The client supports flexible MCP server configuration with three priority levels. This allows different repositories to use different MCP servers and tools. ### Configuration Priority 1. **Repository-specific config**: `~/.config/agent-manager/mcp/{owner}/{repo}.json` 2. **Global default config**: `~/.config/agent-manager/mcp/default.json` 3. **Hardcoded fallback**: Built-in gogs-mcp configuration (automatic) ### Configuration File Format ```json { "mcpServers": { "gogs": { "type": "stdio", "command": "node", "args": ["/data/gogs-mcp/dist/index.js"], "env": {} }, "custom-server": { "type": "stdio", "command": "node", "args": ["/path/to/custom-mcp/dist/index.js"], "env": { "API_KEY": "${MY_API_KEY}" } } } } ``` ### Environment Variable Substitution Configuration files support `${VAR_NAME}` syntax for secure secret management: ```json { "mcpServers": { "api-service": { "type": "stdio", "command": "node", "args": ["/path/to/api-mcp/dist/index.js"], "env": { "API_KEY": "${MY_API_KEY}", "JWT_TOKEN": "${JWT_TOKEN}" } } } } ``` Variables are resolved from the process environment at runtime. ### Security - **File Permissions**: Configuration files should have mode 600 (owner read/write only) - **Directory Permissions**: Config directory should have mode 700 - **Secret Management**: Never hardcode secrets; always use environment variable substitution - **Storage Location**: Files are stored in `~/.config/agent-manager/mcp/` outside repository directories ### Examples For detailed configuration examples and setup instructions, see: - **Documentation**: [`examples/MCP-CONFIG.md`](../examples/MCP-CONFIG.md) - **Simple Example**: [`examples/mcp-config-default.json`](../examples/mcp-config-default.json) - **Multi-Server Example**: [`examples/mcp-config-multi-server.json`](../examples/mcp-config-multi-server.json) ## Automatic Repository Management The client automatically manages Git repositories for issue handling: ### Features **Automatic Cloning** - When an issue is assigned for a repository that doesn't exist locally - Clones the repository to `/home/claude/{owner}/{repo}` - Uses SSH URL fetched dynamically from Gogs API **Automatic Updates** - If repository already exists, pulls latest changes - Ensures Claude always works with current code **Dynamic Git URL Fetching** - Fetches SSH URL from Gogs API using `fetchRepositorySshUrl()` - No hardcoded repository URLs - Works with any repository accessible via Gogs API **Environment Setup** - Automatically configures HOME directory - Sets up PATH to include `~/.local/bin` - Creates and configures XDG directories (cache, config, data, state) - Ensures proper environment even when running as systemd service ### Implementation Repository management is handled by `repository-manager.ts`: ```typescript // Clone repository if it doesn't exist cloneRepository(sshUrl, targetPath); // Pull latest changes if repository exists pullRepository(repoPath); // Setup environment variables setupEnvironment(); // Detect agent-manager installation path detectAgentManagerPath(); ``` ## Project Memory (CLAUDE.md) The client automatically reads and includes the `CLAUDE.md` file from the repository root if it exists. This provides Claude with: - Project-specific guidelines and conventions - Architecture details and module structure - Development patterns and best practices - Important context about the codebase When processing an issue, the `CLAUDE.md` content is injected into the prompt, ensuring Claude has full context about the project. ## Development ### Watch Mode ```bash npm run watch ``` ### Clean Build ```bash npm run clean npm run build ``` ## Requirements - **Node.js** >= 18.0.0 - **TypeScript** >= 5.3.0 (devDependency) - **@anthropic-ai/claude-agent-sdk** >= 0.1.28 - **@modelcontextprotocol/sdk** >= 1.0.4 - **@types/node** >= 20.0.0 (devDependency) ## Dependencies The client has minimal production dependencies: ```json { "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.28", "@modelcontextprotocol/sdk": "^1.0.4" }, "devDependencies": { "@types/node": "^20.0.0", "typescript": "^5.3.0" } } ``` ## Integration with Agent Manager The client integrates seamlessly with the main Agent Manager webhook server through `commands.json`: ```json { "commands": { "issues": [ { "name": "handle-issue-assigned", "description": "Handle issues assigned to Claude", "type": "node", "command": "client/dist/index.js", "args": [ "{{repo_owner}}", "{{repo}}", "{{pusher}}", "{{issue_number}}", "{{issue_title}}", "{{issue_body}}", "{{issue_action}}", "", "{{issue_assignee}}", "{{issue_labels}}" ], "filterActions": ["assigned"], "filterAssignee": "claude" } ], "issue_comment": [ { "name": "handle-issue-comment", "description": "Handle comments on issues assigned to Claude", "type": "node", "command": "client/dist/index.js", "args": [ "{{repo_owner}}", "{{repo}}", "{{pusher}}", "{{issue_number}}", "{{issue_title}}", "{{issue_body}}", "{{issue_action}}", "{{comment_body}}", "{{issue_assignee}}", "{{issue_labels}}" ], "filterAssignee": "claude" } ] } } ``` ## Troubleshooting ### Issue: Repository clone fails **Solution**: Ensure SSH keys are configured and GOGS_ACCESS_TOKEN is set ### Issue: MCP tools not discovered **Solution**: Check that MCP configuration exists and servers are accessible. Review logs for connection errors. ### Issue: Permission denied errors **Solution**: Verify HOME, XDG directories exist and have correct permissions (700 for directories, 600 for config files) ### Issue: Label-aware behavior not working **Solution**: Ensure `{{issue_labels}}` variable is passed from commands.json and labels are set on the issue in Gogs ### Issue: CLAUDE.md not loaded **Solution**: Verify CLAUDE.md exists in repository root and is readable by the claude user ## License ISC