---
title: Running Sally
---

The jobs that come up while Sally is running, for admins and PMs. Most are a button in the admin at
**sally.linchpin.com/admin**. Where it says People or Health, only admins can do it.

## Switch someone on

<!-- wp:docspress/flow {"start":1,"steps":[{"title":"Add them","content":"<p>Add a row for them to <code>scripts/seed-people.sql</code> (name, email, role and ClickUp user id) and run it. It only inserts people who aren’t there yet, and everyone starts switched off and in dry run.</p>"},{"title":"They connect","content":"<p>They run <code>/sally connect</code> in Slack and approve ClickUp. Sally links their Slack account by the email address on their Slack profile.</p>"},{"title":"Check their draft","content":"<p>On <strong>Preview</strong>, build their standup. Nothing is sent. Compare it with what they actually did.</p>"},{"title":"Switch them on","content":"<p>On <strong>People</strong>, select <strong>Switch on</strong>. Check-ins start at their next prompt, still in dry run.</p>"},{"title":"Go live","content":"<p>Once a few drafts match what they did, select <strong>Go live</strong>. From then on their answers are written to ClickUp as them.</p>"}]} /-->

To pause someone, select **Switch off** on People. Their check-ins stop at the next prompt; nothing already written is
changed.

## Mark someone out

- **For one day,** they select **I'm out today** on that day's standup. Sally notes it on the Daily Standup and stops
  asking until their next working day.
- **Ahead of time,** add the days on People with **Add a day off**.
- **For everyone,** add the date to **Rules › Calendar › Company holidays**.

Out days and holidays get no check-ins, and look-backs skip them.

## Change a rule

On **Rules**, change the value and save. It takes effect from the next check-in. Every save is versioned: pick
**Restore an earlier version…** to put one back. Every rule is in the [Configuration reference](configuration.md).

**To send the digest to a channel,** invite @Sally to it, then set **Rules › Slack › Team channel** to the channel's id.
It starts with `C`. Until it's set, admins get the digest by DM.

## Stop Sally writing

- **For one person,** select **Dry run** on People. Sally keeps drafting and asking, and logs what it would have
  written instead of writing it.
- **For everyone,** set `DRY_RUN` to `"true"` in `wrangler.jsonc` and ship it. It's the kill switch, and it overrides
  everyone's own setting.

## A job that kept failing

**Health › Failed jobs** lists every background job that failed all its retries, such as a submit during a ClickUp
outage. **Retry** sends it back to the queue; **Dismiss** drops it. Both are logged.

## The ClickUp webhook

The webhook tells Sally who changed what in ClickUp, for "worked on" and for redrawing open check-ins.

- **First time:** **Health › ClickUp webhook › Register webhook**. It's registered with your own ClickUp connection.
- **Failing or suspended:** when Health shows it as failing or suspended, select **Reactivate**.

## Someone needs to reconnect

**Health › Connections** and People show each person as **Connected**, **Needs reconnecting** or **Not connected**.
When ClickUp stops accepting someone's connection, Sally DMs them to run `/sally connect`. Until they do, Sally writes
nothing for them, and their answers show as not in ClickUp yet.

## Draft a check-in again

The person runs `/standup fresh` (or `/eod fresh`). Sally drafts it again from ClickUp and marks the old thread as
replaced. What their answers already changed in ClickUp stays.

## Look into something

The **Activity log** has everything Sally did, newest first, in plain English, with links to the task and the Slack
message. Each row has a **ref**. When Slack says something like "didn't work (ref `20dc27f2`)", the same ref is on the
row that explains it.

## Ship a change

<!-- wp:docspress/flow {"start":1,"steps":[{"title":"Merge to main","content":"<p>Conventional commits scoped to the ClickUp task, such as <code>fix(LINCHPIN-5818): …</code>. CI runs the checks on every PR.</p>"},{"title":"Merge the release PR","content":"<p>release-please keeps <strong>chore(main): release x.y.z</strong> open with the changelog. Merging it tags the version and publishes the release.</p>"},{"title":"The release deploys","content":"<p><strong>Deploy to Cloudflare</strong> runs <code>npm run check</code>, applies any new migrations, then deploys. Watch it in the Actions tab.</p>"}]} /-->

**Deploying by hand:** run **Deploy to Cloudflare** from the Actions tab, on `main`. Never `wrangler deploy` from a
laptop or a branch, or production stops matching a release. See [Setting Sally up](setup.md#releasing) for what the
workflows need.

**A database change** is a new numbered file in `migrations/`. The release applies it before the new code goes out, so
code never runs against an old schema. Never edit a migration that has already been applied.

## Rotate a secret

Get the new value, store it in 1Password under **Sally (sally.linchpin.com)**, then:

<!-- wp:docspress/terminal-session {"title":"Replace a secret","shell":"bash","prompt":"$","command":"npx wrangler secret put SLACK_BOT_TOKEN --name sally","output":""} /-->

It takes effect straight away, with no deploy. The secrets are listed in the
[Configuration reference](configuration.md#the-worker).

<!-- wp:docspress/callout {"tone":"warning","title":"TOKEN_ENC_KEY is different","content":"<p>It encrypts every person’s ClickUp connection and the webhook’s signing secret. Replacing it means everyone runs <code>/sally connect</code> again, and the webhook has to be registered again from Health.</p>","collapsible":false} /-->

## Work on Sally locally

```sh
npm install
cp .dev.vars.example .dev.vars        # fill in what you need
npm run db:migrate:local
npx wrangler d1 execute sally --local --file scripts/seed-people.sql
```

<!-- wp:docspress/terminal-session {"title":"Run Sally on your machine","shell":"bash","prompt":"$","command":"npm run dev:admin-as","output":""} /-->

Then open <http://localhost:8787/admin/>. It acts as `aaron@linchpin.com`; set `SALLY_DEV_EMAIL` to be someone else.
The override is ignored whenever `CF_ACCESS_AUD` is set, so it can't open production. Plain `npm run dev` shows the
real behaviour: the admin fails closed.

Slack and ClickUp can't reach your machine, so send signed commands instead:

```sh
npx wrangler d1 execute sally --local --command "UPDATE people SET slack_user_id='U_AARON' WHERE id='aaron'"
node scripts/slack-local.mjs /sally status U_AARON
```

Before a PR, run the same checks as CI: `npm run check`, `npm run lint`, `npm run build` and
`npx wrangler deploy --dry-run`.
