Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,039 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

soma-work

AI Coding Assistant for Slack — Powered by Claude Code SDK

CI License TypeScript Node.js Claude Code SDK

한국어


What is soma-work?

A multi-tenant Slack bot that turns every workspace conversation into an AI-powered coding session. Send a DM, mention in a channel, or reply in a thread — the bot reads code, reviews PRs, plans Jira issues, and writes solutions with full context awareness.

You:   Review this PR https://github.com/org/repo/pull/42
Bot:   [Analyzes diff, reads source, posts line-by-line review comments]

You:   Summarize issue PROJ-1234
Bot:   [Fetches Jira issue, cross-references PRs/code, generates executive summary]

You:   Optimize this function [attaches file]
Bot:   [Analyzes uploaded code, identifies bottlenecks, proposes optimized version]

Documentation


✨ Key Features

🔀 Automatic Workflow Dispatch

The bot classifies user input and routes it to the optimal workflow — no manual selection needed.

Workflow Trigger What Happens
PR Review GitHub PR URL Full code review with inline comments
PR Fix & Update fix + PR URL Implements fix, commits, pushes
PR Docs document + PR URL Generates Confluence documentation
Jira Planning Jira issue + plan Task decomposition & work breakdown
Jira Summary Jira issue + summary Executive report generation
Jira Brainstorming Jira issue + brainstorm Idea divergence & synthesis
Jira → PR Jira issue + create PR Auto-creates pull request from issue
Deploy Deploy-related request Deployment workflow orchestration
Onboarding New user / onboarding Interactive guided setup
Default Everything else General-purpose coding assistant

Additional session-handoff entrypoints (z-plan-to-work, z-epic-update) exist for z controller handoffs (#695) — they enter via CONTINUE_SESSION handoff, not free-text classification. Source of truth: WorkflowType in somalib/model-commands/session-types.ts and VALID_WORKFLOWS in src/dispatch-service.ts; prompt files live in src/prompt/workflows/.

🎭 Genius Personas

Switch the bot's personality and reasoning style. Each persona brings a distinct approach to problem-solving.

/z persona set einstein    → First-principles physics thinking
/z persona set linus       → Ruthless code review, no BS
/z persona set feynman     → "If I can't explain it simply..."
/z persona set vonneumann  → Mathematical precision

Available: default · linus · buddha · davinci · einstein · elon · feynman · jesus · newton · turing · vonneumann — source of truth: src/persona/

🔌 MCP Tool Ecosystem

Connect any MCP-compatible server (stdio/SSE/HTTP) to extend Claude's capabilities infinitely. Built-in statistics tracking and estimated completion times.

🔐 Interactive Permissions

Slack-native button/form UX for permission approvals, option selection, and session management. Bypass mode available for trusted users.

📎 File Analysis

Upload images (JPG/PNG/GIF/WebP), text, or code files directly in Slack. 50MB limit per file.

🔑 GitHub Integration

GitHub App (recommended) or Personal Access Token authentication with automatic token renewal.

🤖 Multi-Agent Architecture

Run multiple independent AI agents within a single process. Each sub-agent is a separate Slack App with its own persona, system prompt, and session isolation.

@soma          → Main bot (제갈공명 persona)
@soma-jangbi   → Code review specialist (장비 persona)
@soma-gwanu    → DevOps & infrastructure (관우 persona)
  • Direct mention (pending): sub-agent apps connect via Socket Mode and receive @mentions/DMs, but handling is not yet wired (see TODO in src/agent-instance.ts)
  • Delegation (partial): main bot reaches agents via the agent_chat MCP tool; Claude SDK query integration is still a placeholder
  • Zero-config scaling: Add agents by editing config.json — no code changes needed
  • Error isolation: One agent crashing doesn't affect others

Note: multi-agent integration is partial. The agent MCP server (packages/mcp-servers/agent/) exposes agent_chat/agent_reply and routes to configured agents, but the actual Claude SDK query integration is still a placeholder (see TODO in agent-mcp-server.ts). Direct @mention/DM handling on sub-agent apps is likewise pending full SlackHandler integration (see TODO in src/agent-instance.ts).

See How to Add a New Agent for setup instructions.


Architecture

┌─────────────────────────────────────────────────────────────┐
│                       Slack Events                            │
│                 (DM / Mention / Thread)                       │
└──────────┬──────────────────────────────────┬─────────────────┘
           │                                  │
    ┌──────▼──────┐                  ┌────────▼─────────┐
    │ Main Bot    │                  │  AgentManager     │
    │ SlackHandler│                  │  ┌─────────────┐  │
    └──────┬──────┘                  │  │ jangbi      │  │
           │                         │  │  App+Handler│  │
  ┌────────┼──────────┐              │  └─────────────┘  │
  │        │          │              │  ┌─────────────┐  │
┌─▼──┐ ┌──▼───┐ ┌────▼───┐         │  │ gwanu       │  │
│Evt │ │ Cmd  │ │ Stream │         │  │  App+Handler│  │
│Rtr │ │ Rtr  │ │ Proc   │         │  └─────────────┘  │
└─┬──┘ └──┬───┘ └────┬───┘         └───────────────────┘
  │        │          │
  │  ┌─────▼────┐ ┌───▼──────┐
  │  │ Command  │ │ Pipeline │
  │  │ Handlers │ │ in→sess→ │
  │  └──────────┘ │ stream   │
  │               └────┬─────┘
  │                    │
  ┌────────────────────▼────────────────────┐
  │            ClaudeHandler              │
  │ ┌──────────┐ ┌──────────┐ ┌────────┐ │
  │ │ Session  │ │ Prompt   │ │Dispatch│ │
  │ │ Registry │ │ Builder  │ │Service │ │
  │ └──────────┘ └──────────┘ └────────┘ │
  └──────────────────┬──────────────────────┘
                     │
       ┌─────────────┼──────────────┐
       │             │              │
  ┌────▼────┐  ┌────▼────┐  ┌─────▼─────┐
  │   MCP   │  │ GitHub  │  │ Permission│
  │ Manager │  │  Auth   │  │  Service  │
  └────┬────┘  └─────────┘  └───────────┘
       │
  ┌────▼─────────────────────────────────┐
  │         Internal MCP Servers          │
  │  llm · model-command · slack-mcp      │
  │  cron · agent · server-tools          │
  │  permission · mcp-tool-permission     │
  └─────────────────────────────────────────┘

Key FacadesSlackHandler, ClaudeHandler, McpManager, AgentManager — present simple interfaces over complex subsystems. Each module follows Single Responsibility Principle.


Commands

Four prefix families — each with a clear, non-overlapping purpose:

Prefix Scope Persistence Example
/z <topic> … Primary command surface (Block Kit UI where it makes sense) User-global /z persona set linus
%<sub> … Current session only — override without saving Ephemeral (reset on new/renew) %model opus
$<skill> / $<plugin>:<skill> Force skill invocation (reads SKILL.md, emits RPG banner) Per-message $z, $stv:new-task
naked text Whitelisted bare forms (see below) or chat / workflow dispatch n/a sessions, new, fix PR 123

Split history (#508): $ used to double as both "force skill" and "session setting". It was split — % took over session settings, $ is now skill-only. Legacy $model / $verbosity / $effort / $thinking / $thinking_summary still work during the deprecation grace period but emit a one-line notice nudging users to %.

/z — primary surface

Grammar: /z <topic> [verb] [args...]. See docs/current/spec/01-slack-integration.md for the full surface, docs/runbook/rollback-z-refactor.md for emergency rollback.

Command Description
/z help Show all topics
/z cwd [set <path>] Show / set working directory
/z mcp [list|reload] List MCP servers / reload config
/z bypass [set on|off] Toggle permission bypass
/z persona [set <name>|list] Switch persona
/z model [set <name>|list] Switch model (sonnet, opus, haiku)
/z verbosity [set <level>] Set output verbosity
/z session · sessions List active sessions (sessions naked form still accepted)
/z new · /z renew Reset / renew session (naked new / renew also accepted)
/z close Close current thread session
/z restore Restore a session
/z context · /z compact Show / compact the context window
/z link <type> <url> Attach issue/PR/doc links
/z onboarding Run onboarding workflow
/z admin [accept|deny|users|config|llmchat|session list] Admin commands
/z cct [set <name>|next] CCT token status / manual switch
/z auth [llmux|cct|switch <name>] Auth backend card: runtime mode switch (llmux default / cct legacy), llmux pool usage, account switch/add/remove
/z marketplace [add <x>] Plugin marketplace
/z plugin [add|update|remove|rollback|backups] Manage installed plugins
/z skill [list|download] Skills directory
/z report [today|daily|weekly] Usage reports

% — session-scoped (ephemeral)

Overrides that apply only to the current session and do not persist. Cleared on /z new or /z renew.

Command Description
% Show session info (model, verbosity, effort, thinking flags)
%model [<name>] Get / set session model (e.g. %model opus)
%verbosity [<level>] Get / set session verbosity
%effort [<level>] Get / set session effort
%thinking [on|off] Toggle extended thinking for this session
%thinking_summary [on|off] Toggle thinking-output display

The $ prefix is still accepted for these subcommands ($model opus, …) during the deprecation grace period — the bot will reply with a one-line hint directing you to %.

$ — forced skill invocation

Forces the bot to read a skill's SKILL.md and follow it. Emits a red RPG banner ("⚡ skill 강제 발동") on resolution.

Syntax Resolves to
$<skill> src/local/skills/<skill>/SKILL.md (bare shorthand for local skills)
$local:<skill> Same as above, explicit form
$user:<skill> DATA_DIR/{userId}/skills/<skill>/SKILL.md (per-user skills)
$<plugin>:<skill> plugins/<plugin>/skills/<skill>/SKILL.md

Representative examples: $z, $zcheck, $stv:new-task. For the current inventory see src/local/skills/ (hardcoded lists drift — always check the directory).

Nested $plugin:skill references inside skill content are resolved recursively (max depth 10).

naked — bare-text compatibility

A whitelist of bare (no-prefix) forms is still accepted for legacy reasons. Source of truth is split across two layers: src/slack/z/whitelist.ts (z-topic forms) and the CommandParser.is*Command matchers routed by src/slack/commands/command-router.ts (operational cards such as auth, cct).

Form Notes
session · sessions List active sessions
sessions public Public session listing
sessions terminate <key> Terminate a session by key
theme · theme <name> · theme set <name> · theme=<name> Theme get/set (both set-prefixed and bare-value forms accepted)
sessions theme [<name>] · sessions theme=<name> Session-scoped theme
new [<prompt>] · renew [<prompt>] Reset / renew session, optional prompt carries over
auth · auth llmux|cct · set auth <mode> · auth switch <name> Auth backend card / runtime mode switch (#1189; mutations admin-only)
cct · cct set <n> · cct next · cct usage [<n>] · cct auto [dry] CCT token status / rotation; auto = admin-only manual auto-rotate (token mutation is card-only since #569)
cron · schedule (also 크론 · 스케줄) Interactive cron card — per-job model/output-target dropdowns + delete button; routed as a command so autogoal can never swallow it; admins see all users' jobs with the owner shown
cron model <name> <default|fast|model> · cron target <name> <channel|dm|thread> · cron delete <name> Change a job's model (default = creator's current model at fire time) / delivery target / delete; admins address another user's job by appending <@owner>
$ · $model <v> · $verbosity <v> · $effort <v> · $thinking <v> · $thinking_summary <v> Legacy session prefix during deprecation grace period (emits one-line notice, use % going forward)

Any free-form text not matching the whitelist is treated as a chat / workflow dispatch prompt.

Migration (#506): Legacy naked command forms (persona linus, model sonnet, show_prompt, …) outside this whitelist are deprecated. First use per user shows a tombstone hint; subsequent uses are dropped. Set SOMA_ENABLE_LEGACY_SLASH=true to restore the pre-refactor behavior during rollback.


Quick Start

1. Clone & Install

git clone https://github.com/2lab-ai/soma-work.git
cd soma-work
npm install

2. Create Slack App

  1. Go to api.slack.com/appsCreate New AppFrom an app manifest
  2. Paste the contents of infra/slack/slack-app-manifest.json
  3. After creation:
    • OAuth & Permissions → copy Bot User OAuth Token (xoxb-...)
    • Basic Information → generate App-Level Token with connections:write scope (xapp-...)
    • Basic Information → copy Signing Secret

3. Configure Environment

cp .env.example .env
# Required
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
SLACK_SIGNING_SECRET=...
BASE_DIRECTORY=/path/to/code/

# Optional
ANTHROPIC_API_KEY=...              # Only needed without Claude Code subscription
GITHUB_APP_ID=123456
GITHUB_PRIVATE_KEY="-----BEGIN RSA..."
GITHUB_INSTALLATION_ID=12345678
GITHUB_TOKEN=ghp_...               # Fallback when GitHub App not configured
CLAUDE_CODE_USE_BEDROCK=1          # Use AWS Bedrock
CLAUDE_CODE_USE_VERTEX=1           # Use Google Vertex AI
DEBUG=true

4. Configure MCP Servers (Optional)

Edit the mcpServers section of config.json:

cp config.example.json config.json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "..." }
    }
  }
}

5. Inject env vars into the Claude Agent SDK (Optional)

Sometimes you need to set env vars on the SDK subprocess only (not on the host process), for example to disable a built-in MCP server bundled with the SDK. Add a claude.env block to config.json:

{
  "claude.env": {
    "ENABLE_CLAUDEAI_MCP_SERVERS": false,
    "FOO": "bar",
    "MAX_TOKENS": 4096
  }
}

This is equivalent to running ENABLE_CLAUDEAI_MCP_SERVERS=false claude ... as a shell prefix — the values are forwarded to every Claude Agent SDK query() call across the app. Internals: setQueryEnvAdditional in src/auth/query-env-builder.ts installs the map at boot; buildQueryEnv overlays it between the inherited process.env and the per-lease CLAUDE_CODE_OAUTH_TOKEN override.

Value coercion. boolean and finite number JSON values are String()-coerced before injection (env-var values must be strings). Empty string is allowed — it's the explicit "clear an inherited var" form.

Reserved keys (denylist). The following are dropped on load with a warning. They are owned by the lease/auth path and operator overrides would either re-route auth, redirect credential storage, or widen the TLS trust surface:

  • CLAUDE_CODE_OAUTH_TOKEN (lease token wins)
  • ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN
  • CLAUDE_CONFIG_DIR
  • CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX
  • HTTP_PROXY, HTTPS_PROXY, NODE_EXTRA_CA_CERTS

Restart required. There is no hot reload — the operator must restart the process after editing claude.env for changes to take effect. The boot log prints the active key list (keys only — values are never logged) so misconfigurations are visible.

No $VAR expansion. Values are passed verbatim. If you need shell-style interpolation, set the variable in the host environment before launch instead of in claude.env.

6. Customize UI surfaces (Optional)

The ui section of config.json controls what the thread header, turn-end card and dashboard card header show, and how each field renders. Inspect the built-in defaults in config.default.json (generated, do not edit), copy the sections you want to change into config.json, and restart. Schema and examples: docs/ui-surfaces.md.

7. Run

npm run dev                        # Development (watch mode)
npm start                          # Development (tsx)
npm run build && npm run prod      # Production

Deployment

Docker

docker compose -f infra/docker/docker-compose.yml up -d
docker compose -f infra/docker/docker-compose.yml logs -f

macOS LaunchAgent

./scripts/service.sh install     # Install as LaunchAgent
./scripts/service.sh start       # Start service
./scripts/service.sh logs follow # Stream logs

Service identifier: ai.2lab.soma-work — auto-restarts on crash.

⚠️ Do not run scripts/service.sh during development. Multiple instances with the same Slack token cause message conflicts.


GitHub Integration

GitHub App (Recommended)

  1. Create an app at GitHub Developer Settings
  2. Required permissions: Contents (RW), Issues (RW), Pull Requests (RW), Metadata (R)
  3. Generate and download a Private Key
  4. Install the app on target repositories; note the Installation ID
  5. Set GITHUB_APP_ID, GITHUB_PRIVATE_KEY, GITHUB_INSTALLATION_ID in .env

Personal Access Token (Fallback)

  1. GitHub Settings → Developer Settings → Personal Access Tokens
  2. Required scopes: repo, read:org
  3. Set GITHUB_TOKEN in .env

GitHub App takes priority when configured. Falls back to PAT automatically.


Project Structure

Counts drift — always check the directories themselves. Full component wiring: docs/misc/reference/architecture.md.

src/                                # TypeScript source
├── agent-manager.ts                # Sub-agent lifecycle management
├── agent-instance.ts               # Individual agent (Slack App + Handler)
├── agent-runtime/                  # Claude Agent SDK execution runtime
├── slack/                          # Slack integration layer
│   ├── actions/                    # Interactive action handlers
│   ├── commands/                   # Command handlers
│   ├── pipeline/                   # Stream processing pipeline
│   ├── directives/                 # Channel/session link directives
│   ├── formatters/                 # Output formatters
│   └── z/                          # /z command surface + naked whitelist
├── auth/                           # CCT lease + query env injection
├── conversation/                   # Conversation recording & replay
├── model-commands/                 # Model command catalog & validation
├── mcp/                            # MCP server management
├── github/                         # GitHub App auth + Git CLI
├── permission/                     # Permission service + Slack UI
├── plugin/                         # Plugin system (marketplace, cache)
├── prompt/                         # System prompts
│   ├── workflows/                  # Dispatch workflow prompts
│   ├── jangbi/                     # Sub-agent: code review specialist
│   └── gwanu/                      # Sub-agent: DevOps specialist
├── persona/                        # Bot personas
├── sandbox/                        # Execution sandbox gate
├── metrics/                        # Token/cost telemetry
├── notification-channels/          # Slack · DM · Telegram · Webhook routing
└── local/                          # Claude Code SDK extensions
    ├── agents/                     # Agent definitions
    ├── skills/                     # Skill implementations
    ├── hooks/                      # Git/build hooks
    ├── commands/                   # Local slash commands
    └── prompts/                    # Local prompts

packages/                           # Workspace packages
├── mcp-servers/                    # Internal MCP servers
│   ├── agent/                      # agent_chat / agent_reply tools
│   ├── llm/                        # LLM aggregate (codex)
│   ├── model-command/              # Session/UI model commands
│   ├── slack-mcp/                  # Thread context + file upload
│   ├── cron/                       # Cron job management
│   ├── server-tools/               # Server administration
│   ├── permission/                 # Permission prompt service
│   └── mcp-tool-permission/        # Per-tool permission gating
├── common/ · slack/ · process-shared/ · test-utils/

somalib/                            # Shared soma-family library
services/a2t/                       # Audio-to-text Python worker
infra/                              # docker / slack manifest / claude config
scripts/                            # Utility scripts (provision-agent.ts, ...)

docs/                               # Architecture & feature specs
└── README.md                       # Docs routing map — start here

Design Principles

  1. Facade Pattern — Four facades (SlackHandler, ClaudeHandler, McpManager, AgentManager) simplify complex subsystems
  2. Single Responsibility — One responsibility per module
  3. Pipeline Architecture — Input preprocessing → session init → stream execution
  4. Workflow Dispatch — Input classification → specialized workflow prompts
  5. Append-Only Messages — New Slack messages instead of edits (reliability)
  6. Session-Based Context — Per-thread session persistence with auto-resume
  7. Error Isolation — Sub-agent failures don't propagate to the main bot
  8. Dependency Injection — Testability through injected dependencies
  9. Hierarchical CWD — Thread > Channel > User working directory priority

Multi-Agent Setup

Add sub-agents to config.json (or config.dev.json on non-main branches):

{
  "agents": {
    "jangbi": {
      "slackBotToken": "xoxb-...",
      "slackAppToken": "xapp-...",
      "signingSecret": "...",
      "description": "Code review specialist"
    }
  }
}

Automated provisioning:

npx tsx scripts/provision-agent.ts jangbi "코드 리뷰 전문 에이전트"

Full guide: docs/misc/guides/how-to-new-agent.md


Testing

npx vitest run          # Single run
npx vitest              # Watch mode

Test coverage includes: event routing, stream processing, command parsing, permission validation, tool formatting, session management, action handlers, pipeline processing, MCP integration, multi-agent lifecycle, and agent MCP server.


Troubleshooting

Symptom What to Check
Bot not responding Logs (DEBUG=true), Slack token validity, channel invitation
Auth errors API keys, Socket Mode enabled, token expiration
Broken formatting Markdown → Slack mrkdwn conversion edge cases
Session conflicts Multiple instances running with same Slack token
Sub-agent not starting Verify slackBotToken/slackAppToken format in config.json
agent_chat "Unknown agent" Agent name must match config.json key (case-sensitive)

License

MIT

About

Connect your local Claude Code agent with Slack

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages