Patrick Buckley 0d3516d6e0 fix(slack): post-merge fixes from Copilot + eous review
Combines the substantive bot.py fixes flagged in both review trails on
PR #355.  Discord parity items grouped here too since they're the same
surface (slack/bot.py).

From Copilot:

- _notify_reply_routes was read on StreamEndEvent but never popped on
  the success path.  Result: one notification reply pinned every later
  response for that ws_id to the notification thread until the bot
  restarted.  Pop after read; combine the surrounding ifs (SIM102).

- PlanReviewEvent embedded raw event.content inside a triple-backtick
  mrkdwn fence without escaping.  A plan with ``` (very common — plans
  often quote code) would break the fence and let later content render
  as live markup, including unintended Slack mentions/links.  Rewrite
  _sanitize_slack_preview to splice a zero-width space inside any ```
  sequence (Slack stops recognizing it as a delimiter) instead of
  escaping every single backtick — keeps single-backtick code snippets
  readable while still protecting the fence.  Apply to plan-review.

- _send_approval_request joined unbounded tool_lines into one mrkdwn
  section, but Slack section.text caps at 3000 chars.  Multi-tool
  batches with large previews silently failed chat_postMessage,
  leaving the user unable to approve/deny.  Cap each preview to 600
  chars under a 2700-char total budget; append "+N more" when truncated.

From eous (parity with Discord):

- Pass `client_type="chat"` from both `get_or_create_workstream` call
  sites (slash-command session + DM).  Without it Slack-routed
  workstreams loaded the web-default prompt; the chat-specific
  system prompt now applies as it does for Discord.

- Add `exc_info=True` to the eleven `log.debug(...)` exception handlers
  so underlying tracebacks are available when debug logging is on
  instead of being silently dropped.  Level stays debug — these are
  benign-by-default sites (chat_update on a deleted message, etc.) so
  only the visibility changes.  Typed-exception handlers
  (RemoteProtocolError, etc.) keep their bare debug log.

- Module docstring on slack/__init__.py so pydoc / import errors have
  human-readable context.

Tests: rewrite the sanitizer test to match the new (more permissive)
single-backtick behaviour; add coverage for the triple-backtick
neutralization + short-input passthrough; patch httpx.AsyncClient at
all five TurnstoneSlackBot construction sites so each test doesn't
leak an unclosed real client.
2026-04-16 14:45:01 -07:00

Turnstone

CI PyPI Python License

Multi-node AI orchestration platform. Deploy tool-using AI agents across a cluster of servers with direct HTTP routing, interactive interfaces, and enterprise governance.

Turnstone console — multi-workstream AI orchestration with mermaid diagrams

Named after the Ruddy Turnstone (Arenaria interpres) — a shorebird that flips stones to discover what's hiding underneath.

Release Tracks

Track Install Docker Description
Stable pip install turnstone ghcr.io/turnstonelabs/turnstone:stable Production-grade. Bugfixes only.
Experimental pip install turnstone --pre ghcr.io/turnstonelabs/turnstone:experimental New features. May have rough edges.

See docs/releasing.md for the full release process.

What it does

Turnstone gives LLMs tools — shell, files, search, web, planning — and orchestrates multi-turn conversations where the model investigates, acts, and reports.

  • Interactive sessions — terminal CLI or browser UI with parallel workstreams
  • Cluster dashboard — real-time view of all nodes and workstreams with console routing proxy
  • Intent validation — LLM judge evaluates every tool call with risk assessments and evidence
  • Governance — RBAC, OIDC SSO, tool policies, skills, usage tracking, audit logs
  • Multi-provider — OpenAI-compatible APIs (vLLM, llama.cpp, NIM), Anthropic Messages API, and Google Gemini
  • MCP support — external tool servers with native deferred loading (Anthropic/OpenAI) or BM25 fallback

Turnstone system architecture

Quickstart

pip install turnstone

# Terminal REPL
turnstone --base-url http://localhost:8000/v1

# Browser UI
turnstone-server --port 8080 --base-url http://localhost:8000/v1

# Cluster dashboard
pip install turnstone[console]
turnstone-console --port 8090

For PostgreSQL (recommended for production):

pip install turnstone[postgres]
export TURNSTONE_DB_BACKEND=postgresql
export TURNSTONE_DB_URL="postgresql+psycopg://user:pass@localhost:5432/turnstone"
turnstone-server --port 8080 --base-url http://localhost:8000/v1

Docker

cp .env.example .env  # edit LLM_BASE_URL, OPENAI_API_KEY, etc.
docker compose --profile production up

See QUICKSTART.md for the bootstrap wizard and docs/docker.md for Docker configuration and profiles.

Programmatic (SDK)

from turnstone.sdk import TurnstoneServer

with TurnstoneServer("http://localhost:8080", token="tok_xxx") as client:
    ws = client.create_workstream(name="demo")
    result = client.send_and_wait("Analyze the error logs", ws.ws_id, auto_approve=True)
    print(result.content)

Tools

Built-in tools for shell, files, search, web, memory, notifications, and autonomous sub-agents — plus external tools via MCP with native deferred loading. See docs/tools.md for the full reference and docs/mcp.md for MCP configuration.

Architecture

Single-node: Client → Server (direct HTTP + SSE). No external dependencies beyond the database.

Multi-node: Client → Console (hash ring routing proxy) → Server nodes. The console maintains a 65536-entry bucket cache for O(1) workstream routing. A rebalancer daemon redistributes buckets when nodes join or leave.

Component Purpose
turnstone Terminal CLI (REPL)
turnstone-server Web UI + REST API + SSE events
turnstone-console Cluster dashboard + routing proxy + admin panel
turnstone-channel Channel gateway (Discord, with adapters for Slack/Teams planned)
turnstone-admin User/token management CLI
turnstone-eval Eval harness for prompt/tool optimization
turnstone-bootstrap LLM-guided setup wizard

Diagrams

UML diagrams in docs/diagrams/:

Diagram Description
System Context Components and external dependencies
Package Structure Python modules and dependency graph
Core Engine SessionUI, ChatSession, LLMProvider
Conversation Turn Message lifecycle through the engine
Tool Pipeline Prepare / approve / execute
Workstream States State machine transitions
Console Data Flow Dashboard data collection
Deployment Docker Compose topology
Auth JWT, scopes, login flows
Channels Discord adapter + routing
Judge Intent validation pipeline
OIDC SSO authorization code flow

Documentation

Topic Link
Configuration reference docs/settings.md
API reference docs/api-reference.md
Docker deployment docs/docker.md
Intent validation (judge) docs/judge.md
Governance & RBAC docs/governance.md
OIDC SSO docs/oidc.md
TLS / mTLS docs/tls.md
Channel integrations docs/channels.md
Console dashboard docs/console.md
Eval harness docs/eval.md
Tools reference docs/tools.md
MCP integration docs/mcp.md

Requirements

  • Python 3.11+
  • An OpenAI-compatible API endpoint, Anthropic API key, or Google Gemini API key
  • Optional: PostgreSQL (pip install turnstone[postgres]), Anthropic (pip install turnstone[anthropic])
  • Git LFS for cloning (diagram PNGs)

License

Business Source License 1.1 — free for all use except hosting as a managed service. Converts to Apache 2.0 on 2030-03-01.

S
Description
No description provided
Readme Apache-2.0 114 MiB
Languages
Python 87.6%
JavaScript 8.7%
CSS 1.8%
HTML 1%
TypeScript 0.5%
Other 0.3%