Voice-first visual Slack agent — authenticated voice commands → typed action planning → confirmation gates → visual trace → auditable execution.
Platform — This build targets Windows (primary dev environment). Mac and mobile (iOS / Android) support are planned for future releases.
This repo is the scaffold: the structure and the typed-action backbone are
in place; feature work follows the phases in docs/product-spec.md.
vigour/
├── apps/
│ ├── web/ Next.js frontend (visual agent, Phase 3)
│ └── slack-server/ Bolt JS server — intent → action → policy → audit
├── services/
│ └── agent-worker/ Python FastAPI sidecar (Phase 7)
├── packages/
│ ├── shared/ risk tiers, visual agent states, id types
│ ├── actions/ zod-backed typed action registry (source of truth)
│ ├── policy/ risk + permission gate (allow/confirm/elevate/deny)
│ ├── audit/ audit event shape + pluggable sinks
│ ├── llm/ pluggable model providers + cost tracking + cascade
│ ├── intent/ transcript → validated SlackAction (the Phase 2 parser)
│ └── confirm/ confirmation manager: read-back, yes/no, elevated challenge, TTL
├── infra/ docker-compose (Postgres + Redis)
└── docs/ product-spec, architecture, threat-model
This project has two environment profiles:
| Aspect | Development (local) | Production (forthcoming) |
|---|---|---|
| LLM provider | Ollama (local, no API key) | Hosted (e.g. Claude, GPT-4o) |
| Slack mode | Socket Mode (ngrok / local tunnel) | HTTP Events API + signing secret |
| Database | Docker Compose (Postgres + Redis on localhost) | Managed cloud services |
| Env file | apps/slack-server/.env |
Injected via CI/CD secrets |
The sections below describe the development setup.
- Windows 10/11
- Node 20+ and pnpm 9 (
corepack enable; on Windows usenvm-windowsorfnmto manage Node versions) - Python 3.11+ (only for
services/agent-worker) - Docker Desktop (only for Postgres/Redis via
infra/docker-compose.yml) - Ollama (recommended local LLM for dev — see Ollama setup below)
The Slack server requires three tokens from a Slack app configured in Socket Mode:
| Variable | Where to get it |
|---|---|
SLACK_BOT_TOKEN |
Slack App Dashboard → OAuth & Permissions — starts with xoxb- |
SLACK_APP_TOKEN |
Slack App Dashboard → Basic Information → App-Level Tokens — starts with xapp- |
SLACK_SIGNING_SECRET |
Slack App Dashboard → Basic Information — 32‑character hex string |
Create a Slack app from slack-app-manifest.yaml at the repo root, then copy the tokens into:
apps/slack-server/.env
A pre-filled example is at apps/slack-server/.env.example — copy it and fill in your values:
Copy-Item apps/slack-server/.env.example apps/slack-server/.envThen open .env and replace the placeholder values (xoxb-..., xapp-..., ...) with your real tokens.
# 1. Install dependencies
pnpm install
# 2. Build the TS packages
pnpm build
# 3. Type-check everything
pnpm typecheck
# 4. Infra (optional — needed for Postgres/Redis features)
docker compose -f infra/docker-compose.yml up -d
# 5. Slack server (Phase 1) — uses the .env you configured above
pnpm --filter @vigour/slack-server dev
# 6. Web placeholder
pnpm --filter @vigour/web dev
# 7. Python worker
cd services/agent-worker
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000PowerShell is the default shell on Windows. All commands above use PowerShell syntax. If you prefer
cmd.exe, replaceCopy-Itemwithcopyand use%CD%for the current directory.
Vigour exposes all Slack actions as MCP (Model Context Protocol) tools on port 3002:
| Tool | Description |
|---|---|
summarize_unread |
Summarize recent messages in a channel |
read_mentions |
Read messages mentioning the user |
draft_reply |
Draft a reply to a thread |
send_message |
Send a message to a channel |
broadcast_message |
Broadcast to multiple channels |
query_system |
Query system info (time/date) |
read_file |
Read a file from the filesystem |
list_directory |
List directory contents |
search_files |
Search for files by pattern |
Connect any MCP host (Claude Desktop, Cursor, etc.) to http://localhost:3002 to use Vigour's Slack capabilities.
Ollama runs the LLM entirely on your machine — zero cost, no API key, no data leaving your PC. It's the recommended provider for local development.
Storage: The Ollama binary itself is ~1.8–2 GB (installer or winget). Pulling
the recommended llama3.1 model adds ~4.9 GB on top, so budget roughly 7 GB
total for the full dev LLM stack.
- Download the installer from ollama.com/download/windows
- Run
OllamaSetup.exe— it installs to%LOCALAPPDATA%\Programs\Ollama - Ollama runs as a background service (system tray). Verify it's running:
ollama --version - Pull the recommended model for Vigour:
ollama pull llama3.1 - Confirm the model responds:
(use
ollama run llama3.1 "Hello"
Ctrl+Dor/byeto exit the chat)
The .env is already pre-configured for Ollama (set as VIGOUR_LLM_PROVIDER).
Just make sure ollama serve is running (it starts automatically on login) and
start the slack server. The model name defaults to llama3.1 — to use a
different one, uncomment and set VIGOUR_OLLAMA_MODEL in .env.
Tip: You can install Ollama via
wingetas well:winget install Ollama.Ollama
The "mind" is pluggable. Set two env vars:
# In apps/slack-server/.env:
VIGOUR_LLM_PROVIDER=ollama # primary
VIGOUR_LLM_FALLBACKS=deepseek # optional, tried in order if primary failsSupported provider ids: ollama (local, $0), deepseek, kimi, openrouter,
groq, openai, claude. The first six (except OpenAI/Claude) are OpenAI-API
compatible and share one adapter; switching is just a base URL + model + key.
To minimise spend, put a free/local provider first and a paid one last — you only pay when the cheap option is unavailable. Every parse records its provider, model, token usage, and estimated USD cost into the audit log, so spend is observable. Rough cost to parse one command (≈140 tokens):
| Provider / model | est. cost per parse |
|---|---|
| Ollama (local) | $0 |
| DeepSeek v4-flash | ~$0.00002 |
| Claude Haiku 4.5 | ~$0.0002 |
Prices live in packages/llm/cost.ts (verify before trusting them). Unknown
models record token counts with a null cost rather than guessing.
Production configuration documentation is forthcoming. Key differences from the development setup above:
- Hosted LLM provider — Claude or GPT-4o with API key management (no Ollama)
- Slack HTTP Events API — public endpoint with signing secret verification (not Socket Mode)
- Managed Postgres/Redis — cloud database services (not Docker local)
- CI/CD-injected env vars — no
.envfile; secrets injected by the deployment platform
The LLM never calls Slack directly. It proposes a structured action; everything after schema validation is deterministic and auditable:
transcript → intent (LLM) → parseAction() [zod] → evaluate() [policy]
→ confirmation? → Slack API → AuditEvent → visual trace + speech
The parser validates the model's JSON against the Zod schema and, on a bad
reply, feeds the schema error back for one retry before giving up. See
docs/architecture.md.
Write actions can't run without approval. The policy outcome maps to a
confirmation level, and the (transport-agnostic) ConfirmationManager drives
the flow — Slack today, voice/visual later:
| Action risk | Policy outcome | Flow |
|---|---|---|
| low | allow |
execute immediately |
| medium | allow |
execute (draft only — never sends) |
| high | confirm |
read-back + Confirm/Cancel buttons |
| critical | elevate |
typed-challenge modal (e.g. "type WX7K") |
| (blocked) | deny |
refuse with reason |
Every pending confirmation has a TTL; a sweep loop expires stale ones and
audits them as timed_out. Approve / reject / expire each write one terminal
audit event carrying the LLM provenance and cost from the parse step. Critical
actions are flat-denied unless the session is cleared for elevation (a
per-workspace kill-switch), so escalation can be turned off entirely.
- ✅ Monorepo structure, tooling (pnpm + turbo + TS project configs)
- ✅ Typed action registry, risk/permission policy engine, audit types + sinks
- ✅ Pluggable multi-provider LLM layer (local/free + paid), cost tracking, cascade fallback
- ✅ Phase 2 intent parser: transcript → validated
SlackAction, with retry + spend auditing - ✅ Phase 5 confirmations: read-back, yes/no buttons, elevated typed-challenge modal, TTL + sweep
- ✅ Bolt
/vigourcommand running the full gated pipeline (heuristic fallback when no provider set) - ⛏️ Phase 3 (visual trace), Phase 4 (voice loop), Phase 6 (auth), real Slack reads/writes
— follow the phases in
docs/product-spec.md
Open question flagged in the threat model: Slack has no clean "my unread messages" endpoint. Resolve the exact mechanism (user token + read-state) before committing to "summarize my unread Slack" as the first demo.