@desplega.ai/agent-swarm 1.10.3 → 1.20.0

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 (181) hide show
  1. package/.claude/settings.local.json +14 -1
  2. package/.env.docker.example +6 -0
  3. package/.env.example +14 -0
  4. package/.github/workflows/ci.yml +76 -0
  5. package/.github/workflows/{docker-publish.yml → docker-and-deploy.yml} +26 -1
  6. package/.wts-config.json +4 -0
  7. package/.wts-setup.ts +102 -0
  8. package/CLAUDE.md +81 -88
  9. package/DEPLOYMENT.md +228 -14
  10. package/Dockerfile +6 -3
  11. package/Dockerfile.worker +21 -4
  12. package/MCP.md +158 -1
  13. package/README.md +83 -0
  14. package/assets/agent-swarm.mp4 +0 -0
  15. package/biome.json +4 -1
  16. package/deploy/prod-db.ts +1 -1
  17. package/docker-compose.example.yml +25 -2
  18. package/docker-entrypoint.sh +71 -0
  19. package/ecosystem.config.cjs +66 -0
  20. package/package.json +12 -3
  21. package/plugin/commands/close-issue.md +86 -0
  22. package/plugin/commands/create-pr.md +93 -0
  23. package/plugin/commands/implement-issue.md +131 -0
  24. package/plugin/commands/investigate-sentry-issue.md +138 -0
  25. package/plugin/commands/respond-github.md +94 -0
  26. package/plugin/commands/review-pr.md +227 -0
  27. package/plugin/commands/start-leader.md +32 -12
  28. package/plugin/commands/swarm-chat.md +4 -0
  29. package/plugin/commands/work-on-task.md +12 -3
  30. package/pyproject.toml +9 -0
  31. package/scripts/generate-mcp-docs.ts +4 -4
  32. package/slack-manifest.json +2 -0
  33. package/src/be/db.ts +2335 -176
  34. package/src/claude.ts +8 -8
  35. package/src/commands/runner.ts +1128 -93
  36. package/src/github/app.ts +231 -0
  37. package/src/github/handlers.ts +918 -0
  38. package/src/github/index.ts +31 -0
  39. package/src/github/mentions.test.ts +104 -0
  40. package/src/github/mentions.ts +30 -0
  41. package/src/github/reactions.ts +153 -0
  42. package/src/github/types.ts +156 -0
  43. package/src/hooks/hook.ts +314 -5
  44. package/src/http.ts +1134 -86
  45. package/src/prompts/base-prompt.ts +168 -17
  46. package/src/scheduler/index.ts +1 -0
  47. package/src/scheduler/scheduler.test.ts +149 -0
  48. package/src/scheduler/scheduler.ts +164 -0
  49. package/src/server.ts +62 -2
  50. package/src/slack/files.ts +302 -0
  51. package/src/slack/handlers.test.ts +165 -0
  52. package/src/slack/handlers.ts +158 -5
  53. package/src/slack/index.ts +15 -0
  54. package/src/slack/responses.ts +10 -2
  55. package/src/tests/concurrency.test.ts +213 -0
  56. package/src/tests/db-capacity.test.ts +212 -0
  57. package/src/tests/epics.test.ts +370 -0
  58. package/src/tests/generate-default-claude-md.test.ts +90 -0
  59. package/src/tests/get-inbox-message.test.ts +145 -0
  60. package/src/tests/rest-api.test.ts +633 -0
  61. package/src/tests/runner-polling-api.test.ts +84 -12
  62. package/src/tests/scheduled-tasks-api.test.ts +352 -0
  63. package/src/tests/scheduled-tasks.test.ts +501 -0
  64. package/src/tests/session-costs.test.ts +725 -0
  65. package/src/tests/store-progress-cost.test.ts +209 -0
  66. package/src/tests/task-cancellation.test.ts +511 -0
  67. package/src/tests/task-pause-resume.test.ts +737 -0
  68. package/src/tests/trigger-claiming.test.ts +631 -0
  69. package/src/tests/update-profile-api.test.ts +561 -0
  70. package/src/tools/cancel-task.ts +111 -0
  71. package/src/tools/create-channel.ts +1 -0
  72. package/src/tools/epics/assign-task-to-epic.ts +128 -0
  73. package/src/tools/epics/create-epic.ts +111 -0
  74. package/src/tools/epics/delete-epic.ts +119 -0
  75. package/src/tools/epics/get-epic-details.ts +90 -0
  76. package/src/tools/epics/index.ts +7 -0
  77. package/src/tools/epics/list-epics.ts +83 -0
  78. package/src/tools/epics/unassign-task-from-epic.ts +108 -0
  79. package/src/tools/epics/update-epic.ts +171 -0
  80. package/src/tools/get-inbox-message.ts +89 -0
  81. package/src/tools/get-swarm.ts +1 -0
  82. package/src/tools/get-task-details.ts +1 -0
  83. package/src/tools/get-tasks.ts +10 -1
  84. package/src/tools/inbox-delegate.ts +113 -0
  85. package/src/tools/join-swarm.ts +24 -11
  86. package/src/tools/list-channels.ts +1 -0
  87. package/src/tools/list-services.ts +1 -0
  88. package/src/tools/my-agent-info.ts +3 -0
  89. package/src/tools/poll-task.ts +42 -3
  90. package/src/tools/post-message.ts +1 -0
  91. package/src/tools/read-messages.ts +4 -0
  92. package/src/tools/register-service.ts +1 -0
  93. package/src/tools/schedules/create-schedule.ts +226 -0
  94. package/src/tools/schedules/delete-schedule.ts +125 -0
  95. package/src/tools/schedules/index.ts +5 -0
  96. package/src/tools/schedules/list-schedules.ts +104 -0
  97. package/src/tools/schedules/run-schedule-now.ts +123 -0
  98. package/src/tools/schedules/update-schedule.ts +243 -0
  99. package/src/tools/send-task.ts +39 -8
  100. package/src/tools/slack-download-file.ts +174 -0
  101. package/src/tools/slack-list-channels.ts +168 -0
  102. package/src/tools/slack-post.ts +103 -0
  103. package/src/tools/slack-read.ts +385 -0
  104. package/src/tools/slack-reply.ts +142 -0
  105. package/src/tools/slack-upload-file.ts +376 -0
  106. package/src/tools/store-progress.ts +44 -6
  107. package/src/tools/task-action.ts +92 -2
  108. package/src/tools/unregister-service.ts +1 -0
  109. package/src/tools/update-profile.ts +45 -8
  110. package/src/tools/update-service-status.ts +1 -0
  111. package/src/types.ts +169 -1
  112. package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +568 -0
  113. package/thoughts/shared/plans/{2025-12-18-inverse-teleport.md → 2026-01-09-inverse-teleport.md} +562 -188
  114. package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +1133 -0
  115. package/thoughts/shared/plans/2026-01-12-github-app-integration.md +380 -0
  116. package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +876 -0
  117. package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +463 -0
  118. package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +691 -0
  119. package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +690 -0
  120. package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +1071 -0
  121. package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +507 -0
  122. package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +565 -0
  123. package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +1479 -0
  124. package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +1230 -0
  125. package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +420 -0
  126. package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +223 -0
  127. package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +277 -0
  128. package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +376 -0
  129. package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +787 -0
  130. package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +390 -0
  131. package/thoughts/shared/research/2026-01-16-epics-feature-research.md +437 -0
  132. package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +98 -0
  133. package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +617 -0
  134. package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +214 -0
  135. package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +287 -0
  136. package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +311 -0
  137. package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +383 -0
  138. package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +240 -0
  139. package/tsconfig.json +1 -1
  140. package/ui/CLAUDE.md +49 -0
  141. package/ui/bun.lock +81 -2
  142. package/ui/package-lock.json +5290 -0
  143. package/ui/package.json +1 -0
  144. package/ui/pnpm-lock.yaml +307 -0
  145. package/ui/src/App.tsx +25 -5
  146. package/ui/src/components/ActivityFeed.tsx +121 -96
  147. package/ui/src/components/AgentDetailPanel.tsx +243 -44
  148. package/ui/src/components/AgentsPanel.tsx +328 -62
  149. package/ui/src/components/ChatPanel.tsx +236 -136
  150. package/ui/src/components/ConfigModal.tsx +31 -10
  151. package/ui/src/components/Dashboard.tsx +324 -26
  152. package/ui/src/components/EditAgentProfileModal.tsx +433 -0
  153. package/ui/src/components/EpicDetailPage.tsx +741 -0
  154. package/ui/src/components/EpicsPanel.tsx +566 -0
  155. package/ui/src/components/Header.tsx +4 -12
  156. package/ui/src/components/JsonViewer.tsx +171 -0
  157. package/ui/src/components/ScheduledTaskDetailPanel.tsx +517 -0
  158. package/ui/src/components/ScheduledTasksPanel.tsx +639 -0
  159. package/ui/src/components/ServicesPanel.tsx +20 -10
  160. package/ui/src/components/SessionLogPanel.tsx +928 -142
  161. package/ui/src/components/StatsBar.tsx +58 -25
  162. package/ui/src/components/StatusBadge.tsx +48 -4
  163. package/ui/src/components/TaskDetailPanel.tsx +150 -74
  164. package/ui/src/components/TasksPanel.tsx +76 -37
  165. package/ui/src/components/UsageCharts.tsx +216 -0
  166. package/ui/src/components/UsageTab.tsx +394 -0
  167. package/ui/src/hooks/queries.ts +179 -5
  168. package/ui/src/hooks/useAutoScroll.ts +37 -9
  169. package/ui/src/index.css +60 -38
  170. package/ui/src/lib/api.ts +109 -12
  171. package/ui/src/lib/contentPreview.ts +208 -0
  172. package/ui/src/lib/theme.ts +24 -24
  173. package/ui/src/lib/utils.ts +41 -1
  174. package/ui/src/main.tsx +5 -9
  175. package/ui/src/types/api.ts +145 -1
  176. package/ui/tailwind.config.js +3 -1
  177. package/ui/vite.config.ts +20 -7
  178. package/plugin/.claude-plugin/plugin.json +0 -13
  179. package/plugin/commands/create-plan.md +0 -415
  180. package/plugin/commands/implement-plan.md +0 -89
  181. package/plugin/commands/research.md +0 -200
@@ -24,7 +24,20 @@
24
24
  "WebFetch(domain:geminicli.com)",
25
25
  "Bash(bun run docs:mcp:*)",
26
26
  "Bash(bun test:*)",
27
- "Bash(curl:*)"
27
+ "Bash(curl:*)",
28
+ "WebFetch(domain:github.com)",
29
+ "Bash(gh pr checks:*)",
30
+ "Bash(gh run view:*)",
31
+ "Bash(timeout 5 bun run:*)",
32
+ "Bash(bun run typecheck:*)",
33
+ "Bash(npx tsc:*)",
34
+ "WebFetch(domain:docs.github.com)",
35
+ "Bash(bun run lint:fix:*)",
36
+ "Skill(desplega:research)",
37
+ "Bash(bun run check:*)",
38
+ "Bash(bun build:*)",
39
+ "WebFetch(domain:www.npmjs.com)",
40
+ "Bash(sentry-cli:*)"
28
41
  ]
29
42
  },
30
43
  "enableAllProjectMcpServers": true,
@@ -31,3 +31,9 @@ SYSTEM_PROMPT_FILE=
31
31
 
32
32
  # For the agent exposed services (optional)
33
33
  SWARM_URL=swarm.example.com
34
+
35
+ # Sentry Integration (optional - for issue investigation)
36
+ # Create an Organization Auth Token at https://sentry.io/settings/{org}/auth-tokens/
37
+ # Required scopes: event:read, project:read, org:read
38
+ SENTRY_AUTH_TOKEN=
39
+ SENTRY_ORG=
package/.env.example CHANGED
@@ -19,8 +19,22 @@ SLACK_APP_TOKEN=xapp-... # App-Level Token (for Socket Mode)
19
19
  SLACK_SIGNING_SECRET=... # Signing Secret (optional for Socket Mode)
20
20
  SLACK_DISABLE=true # Set to "true" to disable Slack integration
21
21
 
22
+ # Slack User Filtering (optional - leave empty to allow all users)
23
+ # SLACK_ALLOWED_EMAIL_DOMAINS=desplega.ai,partner.com # Comma-separated email domains
24
+ # SLACK_ALLOWED_USER_IDS=U12345678,U87654321 # Comma-separated Slack user IDs to always allow
25
+
22
26
  # App URL for Slack message links (e.g., https://your-dashboard.com)
23
27
  APP_URL=
24
28
 
25
29
  # Environment mode - set to "development" to add (dev) prefix to agent names in Slack
26
30
  ENV=
31
+
32
+ # GitHub App Integration (optional)
33
+ # GITHUB_DISABLE=true # Set to skip GitHub integration
34
+ GITHUB_WEBHOOK_SECRET= # Webhook secret from GitHub App settings
35
+ GITHUB_BOT_NAME=agent-swarm-bot # Bot name for @mentions (default: agent-swarm-bot)
36
+ GITHUB_APP_ID= # GitHub App ID (from app settings)
37
+ GITHUB_APP_PRIVATE_KEY= # Private key: raw PEM with \n escapes, OR base64-encoded
38
+
39
+ # Scheduler configuration
40
+ SCHEDULER_INTERVAL_MS=10000 # Polling interval for scheduled tasks (default: 10 seconds)
@@ -0,0 +1,76 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+ push:
8
+ branches:
9
+ - main
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ lint-and-typecheck:
14
+ name: Lint and Type Check
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Bun
22
+ uses: oven-sh/setup-bun@v2
23
+ with:
24
+ bun-version: latest
25
+
26
+ - name: Install dependencies
27
+ run: bun install --frozen-lockfile
28
+
29
+ - name: Run Biome linter
30
+ run: bun run lint
31
+
32
+ - name: Run TypeScript type check
33
+ run: bun run tsc:check
34
+
35
+ test:
36
+ name: Run Tests
37
+ runs-on: ubuntu-latest
38
+
39
+ steps:
40
+ - name: Checkout repository
41
+ uses: actions/checkout@v4
42
+
43
+ - name: Setup Bun
44
+ uses: oven-sh/setup-bun@v2
45
+ with:
46
+ bun-version: latest
47
+
48
+ - name: Install dependencies
49
+ run: bun install --frozen-lockfile
50
+
51
+ - name: Run tests
52
+ run: bun test
53
+
54
+ docker-build:
55
+ name: Docker Build Test
56
+ runs-on: ubuntu-latest
57
+ if: github.event_name == 'pull_request'
58
+
59
+ strategy:
60
+ matrix:
61
+ dockerfile: [Dockerfile, Dockerfile.worker]
62
+
63
+ steps:
64
+ - name: Checkout repository
65
+ uses: actions/checkout@v4
66
+
67
+ - name: Set up Docker Buildx
68
+ uses: docker/setup-buildx-action@v3
69
+
70
+ - name: Build Docker image
71
+ uses: docker/build-push-action@v5
72
+ with:
73
+ context: .
74
+ file: ./${{ matrix.dockerfile }}
75
+ push: false
76
+ tags: test-image:latest
@@ -1,4 +1,4 @@
1
- name: Docker Build and Publish
1
+ name: Docker Build + Publish + Deploy
2
2
 
3
3
  on:
4
4
  push:
@@ -50,6 +50,7 @@ jobs:
50
50
  push: true
51
51
  tags: ${{ steps.meta.outputs.tags }}
52
52
  labels: ${{ steps.meta.outputs.labels }}
53
+ no-cache: true
53
54
 
54
55
  build-and-push-worker:
55
56
  runs-on: ubuntu-latest
@@ -90,3 +91,27 @@ jobs:
90
91
  push: true
91
92
  tags: ${{ steps.meta.outputs.tags }}
92
93
  labels: ${{ steps.meta.outputs.labels }}
94
+ no-cache: true
95
+
96
+ deploy:
97
+ name: Deploy
98
+ runs-on: ubuntu-latest
99
+
100
+ needs:
101
+ - build-and-push-server
102
+ - build-and-push-worker
103
+
104
+ steps:
105
+ - name: Checkout
106
+ id: checkout
107
+ uses: actions/checkout@v4
108
+
109
+ - name: Deploy Agent Swarm
110
+ uses: tarasyarema/dokploy-deploy-action@main
111
+ with:
112
+ deployment_type: compose
113
+ compose_id: h4or-knfw2HWkTzjLmrn8
114
+ compose_name: agent-swarm-nrz8v0
115
+ dokploy_url: https://app.dokploy.com
116
+ auth_token: ${{ secrets.DOKPLOY_TOKEN }}
117
+ wait_for_completion: true
@@ -0,0 +1,4 @@
1
+ {
2
+ "autoTmux": true,
3
+ "setupScript": ".wts-setup.ts"
4
+ }
package/.wts-setup.ts ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env bun
2
+ // wts setup script - runs after worktree creation
3
+ //
4
+ // Environment variables:
5
+ // WTS_WORKTREE_PATH - path to the new worktree (also the working directory)
6
+ // WTS_GIT_ROOT - path to the main repository root
7
+
8
+ import { exists, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
9
+ import { join, basename } from "node:path";
10
+
11
+ const worktreePath = process.env.WTS_WORKTREE_PATH!;
12
+ const gitRoot = process.env.WTS_GIT_ROOT!;
13
+ const worktreeName = basename(worktreePath);
14
+
15
+ console.log(`Setting up worktree "${worktreeName}" at ${worktreePath}...`);
16
+
17
+ // Generate a unique port based on worktree index
18
+ // Main repo uses 3013, worktrees use 3014+
19
+ async function getUniquePort(): Promise<number> {
20
+ const basePort = 3013;
21
+ try {
22
+ // Count existing worktrees to determine port offset
23
+ const worktreesDir = join(gitRoot, ".worktrees");
24
+ if (await exists(worktreesDir)) {
25
+ const worktrees = await readdir(worktreesDir);
26
+ return basePort + worktrees.length;
27
+ }
28
+ } catch {
29
+ // Fallback: use a hash of the worktree name
30
+ let hash = 0;
31
+ for (const char of worktreeName) {
32
+ hash = ((hash << 5) - hash + char.charCodeAt(0)) | 0;
33
+ }
34
+ return basePort + 1 + (Math.abs(hash) % 100);
35
+ }
36
+ return basePort + 1;
37
+ }
38
+
39
+ const port = await getUniquePort();
40
+ console.log(`Using port ${port} for this worktree`);
41
+
42
+ // --- Copy and configure .env ---
43
+ const mainEnv = join(gitRoot, ".env");
44
+ const envExample = join(worktreePath, ".env.example");
45
+ const targetEnv = join(worktreePath, ".env");
46
+
47
+ if (await exists(mainEnv)) {
48
+ console.log("Copying .env from main repo...");
49
+ let envContent = await readFile(mainEnv, "utf-8");
50
+ // Update PORT to the unique port
51
+ envContent = envContent.replace(/^PORT=\d+/m, `PORT=${port}`);
52
+ await writeFile(targetEnv, envContent);
53
+ } else if (await exists(envExample)) {
54
+ console.log("Creating .env from .env.example...");
55
+ let envContent = await readFile(envExample, "utf-8");
56
+ envContent = envContent.replace(/^PORT=\d+/m, `PORT=${port}`);
57
+ await writeFile(targetEnv, envContent);
58
+ }
59
+
60
+ // --- Copy and configure .mcp.json ---
61
+ const mainMcp = join(gitRoot, ".mcp.json");
62
+ const targetMcp = join(worktreePath, ".mcp.json");
63
+
64
+ if (await exists(mainMcp)) {
65
+ console.log("Copying .mcp.json with updated port...");
66
+ let mcpContent = await readFile(mainMcp, "utf-8");
67
+ // Update the port in the MCP URL
68
+ mcpContent = mcpContent.replace(/localhost:\d+/g, `localhost:${port}`);
69
+ await writeFile(targetMcp, mcpContent);
70
+ }
71
+
72
+ // --- Copy .claude directory ---
73
+ const mainClaude = join(gitRoot, ".claude");
74
+ const targetClaude = join(worktreePath, ".claude");
75
+
76
+ if (await exists(mainClaude)) {
77
+ console.log("Copying .claude directory...");
78
+ await mkdir(targetClaude, { recursive: true });
79
+ const files = await readdir(mainClaude);
80
+ for (const file of files) {
81
+ const content = await readFile(join(mainClaude, file));
82
+ await writeFile(join(targetClaude, file), content);
83
+ }
84
+ }
85
+
86
+ // --- Copy docker env files if they exist ---
87
+ const dockerEnvFiles = [".env.docker", ".env.docker-lead"];
88
+ for (const envFile of dockerEnvFiles) {
89
+ const mainDockerEnv = join(gitRoot, envFile);
90
+ const targetDockerEnv = join(worktreePath, envFile);
91
+ if (await exists(mainDockerEnv)) {
92
+ console.log(`Copying ${envFile}...`);
93
+ await Bun.$`cp ${mainDockerEnv} ${targetDockerEnv}`;
94
+ }
95
+ }
96
+
97
+ // --- Install dependencies ---
98
+ console.log("Installing dependencies...");
99
+ await Bun.$`bun install`;
100
+
101
+ console.log(`\nSetup complete! Worktree running on port ${port}`);
102
+ console.log(`Start the server with: bun run dev:http`);
package/CLAUDE.md CHANGED
@@ -1,111 +1,104 @@
1
- ---
2
- description: Use Bun instead of Node.js, npm, pnpm, or vite.
3
- globs: "*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json"
4
- alwaysApply: false
5
- ---
1
+ # Agent Swarm MCP
6
2
 
7
- Default to using Bun instead of Node.js.
3
+ Multi-agent orchestration layer for Claude Code, Codex, Gemini CLI. Enables task distribution, agent communication, and service discovery.
8
4
 
9
- - Use `bun <file>` instead of `node <file>` or `ts-node <file>`
10
- - Use `bun test` instead of `jest` or `vitest`
11
- - Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
12
- - Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
13
- - Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
14
- - Bun automatically loads .env, so don't use dotenv.
5
+ **Getting Started**: See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup. Run `bun run start:http` to start the server.
15
6
 
16
- ## APIs
7
+ **Database**: Uses `bun:sqlite` (SQLite with WAL mode). DB file at `./agent-swarm-db.sqlite` (auto-created). Schema defined in `src/be/db.ts`.
17
8
 
18
- - `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
19
- - `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
20
- - `Bun.redis` for Redis. Don't use `ioredis`.
21
- - `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
22
- - `WebSocket` is built-in. Don't use `ws`.
23
- - Prefer `Bun.file` over `node:fs`'s readFile/writeFile
24
- - Bun.$`ls` instead of execa.
9
+ ## Quick Reference
25
10
 
26
- ## Testing
11
+ ```bash
12
+ bun install # Install dependencies
13
+ bun run start:http # Run MCP HTTP server (port 3013)
14
+ bun run dev:http # Dev with hot reload
15
+ bun run lint:fix # Lint & format with Biome
16
+ bun run tsc:check # Type check
27
17
 
28
- Use `bun test` to run tests.
18
+ # PM2 (run API + UI + lead + worker together)
19
+ bun run pm2-start # Start all (API :3013, UI :5274, lead :3201, worker :3202)
20
+ bun run pm2-stop # Stop all services
21
+ bun run pm2-restart # Restart all services
22
+ bun run pm2-logs # View logs
23
+ bun run pm2-status # Check status
24
+ # Note: lead/worker run in Docker. On code changes:
25
+ # bun run docker:build:worker && bun run pm2-restart
26
+ ```
29
27
 
30
- ```ts#index.test.ts
31
- import { test, expect } from "bun:test";
28
+ ## Tech Stack
32
29
 
33
- test("hello world", () => {
34
- expect(1).toBe(1);
35
- });
36
- ```
30
+ - **Runtime**: Bun (not Node.js) - see Bun rules below
31
+ - **Language**: TypeScript (strict mode)
32
+ - **Linter/Formatter**: Biome (2-space indent, double quotes, 100 line width)
33
+ - **MCP SDK**: @modelcontextprotocol/sdk
34
+ - **CLI**: Ink (React for terminal)
35
+ - **Slack**: @slack/bolt
37
36
 
38
- ## Frontend
39
-
40
- Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
41
-
42
- Server:
43
-
44
- ```ts#index.ts
45
- import index from "./index.html"
46
-
47
- Bun.serve({
48
- routes: {
49
- "/": index,
50
- "/api/users/:id": {
51
- GET: (req) => {
52
- return new Response(JSON.stringify({ id: req.params.id }));
53
- },
54
- },
55
- },
56
- // optional websocket support
57
- websocket: {
58
- open: (ws) => {
59
- ws.send("Hello, world!");
60
- },
61
- message: (ws, message) => {
62
- ws.send(message);
63
- },
64
- close: (ws) => {
65
- // handle close
66
- }
67
- },
68
- development: {
69
- hmr: true,
70
- console: true,
71
- }
72
- })
37
+ ## Project Structure
38
+
39
+ ```
40
+ src/
41
+ http.ts # Main HTTP server + MCP endpoints
42
+ stdio.ts # Stdio MCP transport
43
+ cli.tsx # CLI entry point (Ink)
44
+ tools/ # MCP tool definitions
45
+ be/ # Backend utilities (DB, storage)
46
+ github/ # GitHub webhook handlers
47
+ slack/ # Slack integration
48
+ ui/ # Dashboard (separate React app)
73
49
  ```
74
50
 
75
- HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
51
+ ## Code Style
76
52
 
77
- ```html#index.html
78
- <html>
79
- <body>
80
- <h1>Hello, world!</h1>
81
- <script type="module" src="./frontend.tsx"></script>
82
- </body>
83
- </html>
84
- ```
53
+ - Run `bun run lint:fix` before committing (lint + format)
54
+ - Run `bun run format` for formatting only
55
+ - Use Bun APIs, not Node.js equivalents
56
+ - Prefer `Bun.$` over execa for shell commands
85
57
 
86
- With the following `frontend.tsx`:
58
+ ## Related
87
59
 
88
- ```tsx#frontend.tsx
89
- import React from "react";
60
+ - [UI Dashboard](./ui/CLAUDE.md) - React monitoring dashboard
61
+ - [MCP.md](./MCP.md) - MCP tools reference
62
+ - [DEPLOYMENT.md](./DEPLOYMENT.md) - Production deployment
63
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) - Development setup
90
64
 
91
- // import .css files directly and it works
92
- import './index.css';
65
+ ---
93
66
 
94
- import { createRoot } from "react-dom/client";
67
+ ## Local Development
95
68
 
96
- const root = createRoot(document.body);
69
+ **Environment Files:**
70
+ - `.env` - Local dev config (API server, Slack, GitHub)
71
+ - `.env.docker` - Docker worker config
97
72
 
98
- export default function Frontend() {
99
- return <h1>Hello, world!</h1>;
100
- }
73
+ **Testing API locally:**
74
+ ```bash
75
+ # API_KEY from .env (default: 123123)
76
+ curl -H "Authorization: Bearer 123123" http://localhost:3013/api/agents
101
77
 
102
- root.render(<Frontend />);
78
+ # With agent ID header for MCP tools
79
+ curl -H "Authorization: Bearer 123123" -H "X-Agent-ID: <uuid>" http://localhost:3013/mcp
103
80
  ```
104
81
 
105
- Then, run index.ts
82
+ **Key env vars:**
83
+ - `API_KEY` - Auth token for API requests
84
+ - `MCP_BASE_URL` - API server URL (default: http://localhost:3013)
85
+ - `SLACK_DISABLE=true` / `GITHUB_DISABLE=true` - Disable integrations locally
106
86
 
107
- ```sh
108
- bun --hot ./index.ts
109
- ```
87
+ ---
88
+
89
+ ## Bun Rules
90
+
91
+ Use Bun instead of Node.js, npm, pnpm, or vite.
92
+
93
+ - `bun <file>` instead of `node` or `ts-node`
94
+ - `bun test` instead of jest/vitest
95
+ - `bun install` instead of npm/yarn/pnpm install
96
+ - `bun run <script>` instead of npm/yarn run
97
+ - Bun auto-loads .env - don't use dotenv
98
+
99
+ ### Bun APIs
110
100
 
111
- For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.
101
+ - `Bun.serve()` for HTTP/WebSocket. Don't use express/ws.
102
+ - `bun:sqlite` for SQLite. Don't use better-sqlite3.
103
+ - `Bun.file()` over node:fs for file I/O.
104
+ - `Bun.$` for shell commands. Don't use execa.