A coding, helping, documenting teammate in Slack

Scout

Work in public, so everyone can help and learn.

Mention @Scout in a public Slack channel and it reads the code, runs the tests, makes the change and opens a pull request, in a thread anyone can follow, join, redirect and learn from. It declines direct messages and private channels. Each thread is a durable conversation with its own sandbox, credentials never leave the host, and what Scout knows lives in a profile of plain files that people review like any other change.

1.0 Fallback models: when a provider stops answering, Scout switches to a fallback model and says so in the thread

Work happens in a thread

One Slack thread is one piece of work. Scout keeps a single message up to date while it works, and replaces it with the answer. The reaction on the request follows along: 🧠 thinking, 📖 reading, 🧪 testing, ending ✅, ⚠️ or 🙋. Anyone in the thread can add context or change course while it runs.

Fragments of a real Scout thread in Slack's dark theme, laid over one another. Jason asks Scout to fix a cent-off rounding bug: three $2.35 stickers with SPRING15 show $6.00 instead of $5.99, and a test for it fails on main. The request carries Scout's finished ✅ reaction and five replies. Scout's answer links the pull request, explains that lineTotal rounded each line before cartTotal summed them, so the total is now rounded once ($5.9925 to $5.99), and says it also fixed the order email, which had the same per-line rounding. Scout then announces in the channel that it opened jrimmer/storefront#1 and requested a review, and reports that CI passed on it. Jason points out that the order confirmation emails build their totals in src/orders/summary.ts. Scout replies that it was the same bug, that checking it turned up a second one it had missed, and that the pull request is updated: the email's own total now comes from cartTotal, so the email and the cart can't disagree.
A real Scout thread, in fragments. Scout answers in one message per run, opens the pull request and says when CI passes. A follow-up in the thread starts a new run on the same branch, so the fix lands on the same pull request. The reaction on the request shows where it ended up.

Credit where it's due

Based on Shopify's River

River is the coding agent Shopify's people work with in public Slack channels. It works only in the open, so everyone learns from watching everyone else's sessions, and teams teach it what they know. Tobi Lütke and Shopify Engineering wrote about it generously and in detail, and Scout is built from what they described.

Scout is an independent, open-source take on that idea, for teams outside Shopify. It isn't affiliated with or endorsed by Shopify. Thank you to Tobi and the River team for showing the way so openly.

How it fits together

One Node process, SQLite and Slack's Socket Mode: no public address, no Postgres, no job queue. Pi Durable runs the agent, checkpointing every model call and tool call, so a crash or a deploy carries on mid-run, and a second person can steer work already in progress.

Ways in

anything can start a thread

  • Slack mentions in public channels, follow-ups, reactions, Ask Scout, a Workflow Builder step, /scout
  • Code host review requests, mentions in issues and pull request comments, CI results
  • Alerts Gatus, Grafana
  • Schedules set up by asking in a channel
  • Jobs npm run job, no Slack

Scout

one Node process, on the host

Slack adapter and admission

Socket Mode; roles, requester checks, spend limits and capacity, before work starts

Pi Durable harness SQLite

Every model call and tool call is checkpointed, so runs survive restarts and the people in the thread can steer

Profile

Prompts, skills and channel instructions, in a git repository Scout keeps pulled

Host-side tools, with credentials

Pushes, pull requests and reviews from a host-owned mirror; MCP servers (Grafana, CI logs, Gatus), writes behind approval

Learning loop

Notes while it works, a nightly reflection, then pull requests against the profile

Replies and telemetry

One Slack message per run; dashboard :8893, /metrics, OTLP traces

What it reaches

the host holds the keys

  • A sandbox per thread Docker or a spoond microVM, over pi-env and git bundles. Its own clone, a real shell and tests, no credentials. Network: none, open, or an approved allowlist. Starts from an image built by the repository's .scout/setup.sh; sleeps when quiet
  • Model gateway any provider or a compatible gateway, with fallback models
  • Code host Forgejo or GitHub
  • Litestream backs the SQLite databases up to object storage

In short: requests arrive from Slack, the code host, alerts, schedules and one-off jobs. Scout, a single process on the host, checks who may ask, runs the agent on Pi Durable, and answers in Slack. Its tools reach a sandbox per thread, a model provider or gateway, the code host and Litestream's backup, and only Scout holds credentials.

Every file operation and command goes through a pi-env daemon in the sandbox, and git crosses as bundles: a host-owned mirror fetches the thread's commits and pushes them. The host never runs git inside a thread's clone.

Scout learns, and people decide what

Scout learns from its own work. As it goes, it keeps notes on what it found out; each night it reflects on the day's threads and proposes what it should know from now on, as a pull request against its own profile. People review that like any other change, and once it's merged, Scout knows it in every thread.

River showed why this matters: its merge rate rose because people noticed where it got stuck or could do more and told it. Scout remembers the lesson so it can improve.

  1. Notes as it works

    Scout remembers what it learns in a thread and can forget it again. Unreviewed notes are on the dashboard, and they retire once a merged proposal covers them.

  2. A nightly reflection

    Every night it reads each thread with new activity: who asked what, what it did, which steps failed and how it ended, plus its notes and what reviewers said about its last proposals.

  3. A pull request on its profile

    It edits a clone of its profile repository, with file tools only, and opens a pull request that explains each change with the thread it came from.

  4. Merge it, and every thread has it

    Scout keeps its profile pulled, so the next request in every thread gets the change. Each Monday it reports its merge rate and each channel's week.

The profile is files in git: a system prompt, skills, and each channel's instructions, repositories and zones. One team's skill can be reused by every other.

What you get

Running it

Scout is meant to be installed and run by people who didn't build it, on a small machine: two cores and 4 GB is plenty, since the work happens in sandboxes.

Watching it work

A read-only dashboard, after spoond's, live over a stream: what Scout is working on now, its merge rate this week and the week before, which model is answering and what it falls back to, runs and sandboxes against their limits, recent threads, the learning loop, spend by model and by channel against its budget, the notes nobody has reviewed yet, reviews in progress and the schedules.

The Scout dashboard, a character grid on a dark background: three threads working now in #web, #payments and #data with their latest steps; pull requests merged at 83% this week against 70% the week before, with the latest six; a capacity panel with the model, its fallback, 3 of 8 runs, 2 of 6 model calls and 5 open sandboxes; ten recent threads; the last nightly reflection and its merged proposal; spend since start by model and this week by channel against budgets; three unreviewed notes; three pull request reviews; and two schedules.
The dashboard, drawn from demo data. It listens on 127.0.0.1:8893 by default and needs a login anywhere else.

Get started

Node 24, Docker and git with access to your repositories. Give Scout its own code host account, token and SSH key, so its work is its own. The setup guide goes from nothing to Scout answering in a channel.

$ git clone https://github.com/jrimmer/scout.git && cd scout
$ npm ci
$ docker build -t scout-sandbox:latest sandbox    # your repos' toolchains go in sandbox/Dockerfile
$ cp .env.example .env                            # create the Slack app from slack-manifest.yaml
$ npm run doctor                                  # checks everything, says how to fix it
$ npm start

Tell it who may ask for work (step 8 of the guide), then invite Scout to a public channel and mention it. For the learning loop, put profile/ in a repository of its own.

Read more