This file is the cross-tool agent-instruction surface for this repo, following the open agents.md spec. It is read natively by Claude Code, OpenAI Codex CLI, Cursor, Cline, Aider, Devin, Sourcegraph Amp, Gemini CLI, Continue, Roo Code, Factory Droids, GitHub Copilot, Windsurf, and Amazon Q.
If you are an AI assistant helping a user with this repo, read this file FIRST.
CCSC is a two-way Slack ↔ Claude Code bridge via Slack Socket Mode and MCP stdio. A local TypeScript MCP server (Bun runtime) speaks Socket Mode to Slack and the Model Context Protocol over stdio to a Claude Code session. The whole codebase is a security substrate: every inbound message passes a five-layer prompt-injection defense, every tool call is gated by a declarative policy engine, and every decision is written to a hash-chained tamper-evident audit journal.
Run them through /slack-channel:install (the install skill at skills/install/SKILL.md).
That skill handles prerequisite checks, Slack app creation, the silent-killer
add-bot-to-channel step, token configuration (delegates to /slack-channel:configure),
pairing (delegates to /slack-channel:access pair), and a verification round-trip.
Do NOT make a new user read CLAUDE.md or the design docs in 000-docs/ first —
those are maintainer reference, not onboarding. Point them at README.md for
the human-readable quick start, and use the install skill for hand-holding.
These are the three failure modes that look like "the bot just doesn't work" but are actually unstated prerequisites:
- Slack bot must be ADDED to the channel after app install. Slack installs an app to a workspace WITHOUT joining any channels. The pairing DM works because DMs auto-route, but a channel test message will hit silence because the bot literally isn't in the channel to see the event. Fix: in Slack, open the channel → channel name → Integrations → Add an App → select the bot.
- Bun must be installed. README Option B falls back to Node.js via npx,
but requires editing
.mcp.json. Default path is Bun; install from https://bun.sh. - Claude Code v2.1.80+ with
claude.ailogin is required. This is a Research Preview constraint — API-key-only auth does not work for Channels. If a user hasANTHROPIC_API_KEYset and noclaude.aisession, the plugin fails to load with a non-obvious error.
bun install # Install deps
bun run typecheck # tsc --noEmit
bun test --timeout 15000 # Full suite (986+ tests)
bun test server.test.ts # Unit suite only
bun test features/runner.test.ts # Gherkin scenarios
bunx @biomejs/biome check . # Lint
bash scripts/coverage-floor.sh 95 # 95% coverage gate
bun scripts/crap-score.ts --threshold 30 # Complexity gate (per-function)
bunx depcruise --config .dependency-cruiser.js . # Architecture invariants
bash scripts/gherkin-lint.sh --path features/ --strict # Wall 1 lint
bash scripts/harness-hash.sh --verify # Tamper checkbun server.ts runs the MCP server directly. claude --dangerously-load-development-channels server:slack
runs it inside Claude Code in dev mode (bypasses plugin allowlist).
- TypeScript strict. No
anywithout explicit justification in a comment. - 95% line + function coverage floor. Enforced by
scripts/coverage-floor.sh. - CRAP score per-function max 30. Enforced by
scripts/crap-score.ts. - Architecture invariants (enforced by
.dependency-cruiser.js):server.tsMUST NOT importmanifest.ts(31-A.4 invariant).journal.tsMUST NOT importpolicy.ts(no-journal-imports-policy).admin.tsMUST NOT importmanifest.ts(no-admin-imports-manifest).
- Four runtime deps only:
@modelcontextprotocol/sdk,@slack/web-api,@slack/socket-mode,zod. Adding a fifth needs explicit justification.
Production source (17 modules, all at repo root unless noted):
| File | Role |
|---|---|
server.ts |
Stateful runtime — Slack client bootstrap, MCP server, event handlers |
lib.ts |
Pure functions — gate(), assertSendable(), assertOutboundAllowed() |
journal.ts |
Hash-chained audit log + redactor |
supervisor.ts |
Session lifecycle (SessionSupervisor) |
policy.ts |
Policy engine (evaluate, shadow linter, monotonicity check) |
manifest.ts |
Bot-manifest protocol |
crypto.ts |
Ed25519 signing primitives |
acp-adapter.ts |
Agent-Communication-Protocol adapter |
policy-dispatch.ts |
Policy decision routing |
nonce-hitl.ts |
Nonce-bound human-in-the-loop approval |
admin.ts |
Admin command routing (gate → policy → journal → tmux) |
stream-reply.ts |
Streaming chat.update reply with single-finalize |
audit-key-loader.ts |
SOPS-decryption + boot-time audit-key load |
audit-key-cli.ts |
Operator CLI for audit-key init/rotate |
mute-store.ts |
!mute / !unmute peer-bot state |
peer-bot-rate-limit.ts |
Cross-bot message rate limit |
scripts/audit-key.ts |
Operator entry point for audit-key CLI |
Tests:
server.test.ts— primary unit + integration suite (usesbun:test).features/*.feature— Wall 1 Gherkin acceptance contracts, pinned by.harness-hash.features/runner.ts+features/runner.test.ts+features/steps/*.ts— hand-rolled Gherkin runner.
Design docs (000-docs/):
THREAT-MODEL.md— trust boundaries, T1–T10 threats, invariants.audit-journal-architecture.md— hash chain, redaction, verify command.policy-evaluation-flow.md—evaluate()decision procedure.session-state-machine.md— supervisor contract + lifecycle.bot-manifest-protocol.md— manifest schema + "advertisements are not grants".key-management.md— Ed25519 audit-key lifecycle (SOPS, init, rotate).multi-agent-channels.md— cross-bot recipe (allowBotIds,!mute).ADR-001-capability-token-format.md— capability-token format evaluation.
- Don't propose new code without checking if a sibling-module primitive
already exists. 17 modules cover most concerns.
bd search <keyword>finds historical decisions. - Don't write into
server.ts. Pure logic goes inlib.tsor a new sibling module.server.tsis for stateful wiring (Slack client, MCP server, event listeners, file I/O). - Don't bypass the inbound gate / outbound gate / file exfiltration guard.
These are the five-layer security architecture —
gate(),assertOutboundAllowed(),assertSendable()inlib.ts. Changes to any of these are security-critical. - Don't propose new design docs without a paired bd. All non-trivial work is bead-tracked.
- Don't modify
CLAUDE.md. That's the maintainer's private reference, not user-facing guidance. - Don't add a 5th runtime dependency without explicit justification.
bun run typecheck # No errors
bun test --timeout 15000 # 986+ tests pass
bunx @biomejs/biome check . # Lint clean
bash scripts/coverage-floor.sh 95 # Coverage ≥ 95%
bun scripts/crap-score.ts --threshold 30 # No function over 30
bunx depcruise --config .dependency-cruiser.js . # No architecture violationsThe CI workflow ci.yml runs nine gates in this order: typecheck → Biome lint
→ test → coverage floor → depcruise → gherkin-lint → harness-hash verify →
bun audit → crap-score. All must pass to merge.
- Feature branches always. Never push to main directly. Branch naming:
feat/<description>-bz-<bead-id>for features,fix/<...>-bz-<bead>for bugs,docs/<...>-bz-<bead>for docs-only. - One PR per logical unit. Don't bundle unrelated changes.
- Gemini auto-reviews PRs. Round-1 findings are usually legitimate. Address with fix-up commits — never force-push to "clean up" a PR.
- Required CI:
Typecheckis the required status check withstrict: true. bd close <id> -r "<evidence>"when work ships. Evidence = PR number, commit SHA, and what was verified (tests, lint, CI).
README.md— human-facing quick start.CONTRIBUTING.md— full contributor guide (branching, commits, PR workflow, quality gates, security-sensitive code).skills/install/SKILL.md— fresh-clone install walkthrough (delegate new users here).skills/configure/SKILL.md— token configuration.skills/access/SKILL.md— pairing + allowlist.skills/policy/SKILL.md— policy-rule authoring.ACCESS.md— full access-control schema.ARCHITECTURE.md— component diagram, four-principal model.SECURITY.md— security policy + vulnerability reporting.000-docs/— design docs (read BEFORE touching any subsystem they cover).