> ## Documentation Index
> Fetch the complete documentation index at: https://docs.labelbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a chief of staff agent in Slack

> Run an agent that follows a Slack thread's commitments to done, posts short source-linked team briefs on a schedule, and writes cited research memos, asking an approver before it acts outside the thread.

The **Chief of staff** template is an agent for a team that works in Slack. Mention it in a thread, or let it run on a weekday schedule. It handles three jobs, each with its own skill:

| Skill | What it does | When it runs |
| - | - | - |
| `project-manager` | Lists a thread's commitments with owners, due dates, and the evidence that would close each one. Keeps a board in the thread current for days, and nudges when a commitment drifts. | When you ask it to track a thread |
| `team-brief` | Posts a short brief of decisions needed, drifting commitments, what shipped, and risks, each with its source. A brief covers only what changed since the last one. | On the weekday schedule, or when you ask |
| `research-memo` | Researches a question before you decide it, and saves a memo with a recommendation, its confidence, and a source for every claim. | When you ask |

In this tutorial, you set the agent up for the repository `acme/payments`, track a thread's follow-ups, set up a weekday brief, and ask for a memo. Replace the examples with yours. Setup takes about 30 minutes.

> [!NOTE]
>
> You need the Developer or Admin role in the organization; see [Organizations and roles](https://docs.labelbox.com/recursion/organizations-and-roles.md). You also need permission to install a GitHub App on the repository's account and a Slack app in your workspace, or existing connections in Recursion, and a GitHub fine-grained personal access token with **Issues** and **Pull requests** write access to `acme/payments` only. Choose an approver who will not start the threads the agent tracks.

## How it works

* **One session per thread.** An automation starts a session when someone mentions the agent in a thread, and every later mention in that thread wakes the same session. The agent works out what was asked and uses the skill that fits. While it tracks a thread it sleeps between checks. Its own timer wakes it, as does a pull request it is watching.
* **Briefs on a schedule.** A weekday schedule on the same automation starts a run that posts each brief due that day. You set a brief up by asking in a thread. The agent saves what the brief covers and where it posts, so a scheduled run needs no thread.
* **Every fact has a source.** Board entries, brief lines, and memo claims link the pull request, issue, Slack message, meeting, or page they come from. Anything without a source is labeled unverified.
* **Reads are open; writes outside the thread need approval.** The agent reads GitHub through a read-only grant. Its only tools that write to GitHub come from an MCP server whose every tool needs an approval. So a comment, a new issue, or a reviewer request runs only after a listed person approves the exact call in the thread. See [Require approval before a tool runs](https://docs.labelbox.com/recursion/mcp-servers.md#require-approval-before-a-tool-runs).
* **Research in parallel.** For a memo, the agent can hand separate questions to up to four copies of itself at a time. Those copies only read and research; they post nothing and can't request approval.
* **Graded against a rubric.** The agent's rubric checks that every fact is sourced, that every action outside the thread was approved, and the rules of the skill the turn used. Criteria for a skill the turn didn't use are not applicable. See [Outcomes](https://docs.labelbox.com/recursion/outcomes.md).

## Step 1: Connect GitHub and Slack

> [tab] Console
>
> 1. In the sidebar, click **Integrations**, then click **Add integration**.
> 2. Choose **GitHub**, choose the account, and select `acme/payments`.
> 3. In the GitHub connection's tool selection, enable `pull_request_read`, `wait_for_pr`, `list_pull_requests`, `issue_read`, `list_issues`, `actions_list`, and `get_file_contents`.
> 4. Click **Add integration** again, choose **Slack**, and choose the workspace.
> 5. In Slack, invite the Recursion app to the channels where the team makes decisions, and to the channel your brief will post in.

> [tab] cURL
>
> Connect in the console first, then list connections to get the ids you'll use later.
>
> ```bash theme={"theme":"css-variables"}
> curl 'https://api.recursion.labelbox.com/managed-agents/v1/integrations/connections' \
>   -H "Authorization: Bearer $RECURSION_API_KEY"
> ```

To add meetings and upcoming events to briefs, also connect a meeting app such as Zoom, Fireflies, Gong, or Granola, or a calendar app your catalog lists. Allow only its read tools, and grant it to the agent in step 3. See [Integrations](https://docs.labelbox.com/recursion/integrations.md) and [GitHub](https://docs.labelbox.com/recursion/github.md).

## Step 2: Store the token for gated GitHub writes

The approval-gated GitHub server authenticates with your personal access token. Store it in a vault, bound to exactly the server's URL. Create the vault first if you need one.

> [tab] Console
>
> 1. Open the vault and click **Add credential**.
> 2. Under **What will use this secret?**, choose **Token for an MCP server**.
> 3. Enter `https://api.githubcopilot.com/mcp/` as the **Server URL** and the token as the **API token**.
> 4. Enter `Chief of staff GitHub writes` as the **Label**.
> 5. Under **Acknowledgement**, confirm that you understand the credential is shared, then click **Add credential**.

> [tab] cURL
>
> ```bash theme={"theme":"css-variables"}
> jq -n '{
>   credential_type: "bearer_token",
>   display_name: "Chief of staff GitHub writes",
>   mcp_server_url: "https://api.githubcopilot.com/mcp/",
>   secret_value: env.GITHUB_PAT
> }' | curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/vaults/26d4b1a8-73c9-4f60-8a15-9e2c7b5d4f31/credentials' \
>   -H "Authorization: Bearer $RECURSION_API_KEY" \
>   -H 'Content-Type: application/json' \
>   --data-binary @-
> ```
>
> Export `GITHUB_PAT` first. `jq` reads it from the environment, so the token stays out of your shell history and out of process arguments.

See [Vaults and credentials](https://docs.labelbox.com/recursion/vaults.md).

## Step 3: Create the agent from the template

> [tab] Console
>
> 1. In the sidebar, click **Agents**, click **Create agent**, and choose the **Chief of staff** template.
> 2. When asked, choose the GitHub connection and select `acme/payments`. The template grants only the read tools from step 1.
> 3. Click **Create and launch**, then close the launch form: this agent runs from Slack.
> 4. On the agent's **Configuration** tab, under **Integrations**, add the Slack connection with `workspace_tools` access. Boards and briefs need it. Add any meeting or calendar app from step 1.
> 5. Under the default credentials, turn on the token from step 2.
> 6. Click **Save new version**.

The template's agent searches the web, can delegate to eight copies of itself (four at a time), keeps its own rubric, and sets a 40 USD cost cap. The cap is also each session's budget. A session that reaches it pauses until someone replies in its thread after you raise it.

## Step 4: Gate the GitHub write tools

Add the approval-gated server with `createAgentVersion`. Send the full definition you read, with this entry added to `mcpServers` and your approver's Slack user id. See [Update rules](https://docs.labelbox.com/recursion/agents.md#update-rules).

```json theme={"theme":"css-variables"}
{
  "name": "github-gated",
  "url": "https://api.githubcopilot.com/mcp/",
  "allowed_tools": ["add_issue_comment", "issue_write", "update_pull_request"],
  "approval": {
    "tools": ["add_issue_comment", "issue_write", "update_pull_request"],
    "approvers": { "slack_user_ids": ["U0123ABCD"] }
  }
}
```

* Keep this server's tools apart from the GitHub grant's. The grant reaches GitHub without approval, so a write tool selected there would bypass the gate.
* Keep the GitHub grant read-only. It also gives `git` and `gh` in the sandbox the grant's access.
* Don't add Slack reply review to this agent. A session whose Slack replies require review can't request approval.

## Step 5: Create the automation

The automation has two triggers. A mention starts a session for its thread, and later mentions continue it. A weekday schedule starts the brief run.

```bash theme={"theme":"css-variables"}
curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/automations' \
  -H "Authorization: Bearer $RECURSION_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "displayName": "Chief of staff",
    "agentId": "5f0c2a1e-8b7d-4c3a-9e21-6d4f0b9a7c55",
    "agentVersionId": "d8f25b1c-6e4a-4a93-b7c0-3f1e9d5a2c68",
    "environmentId": "9d3e7b52-1a4c-4f80-b6e9-2c8a5d0f7e13",
    "initialPrompt": {
      "type": "literal",
      "text": "You were started by a Slack mention or by a schedule. When a person mentioned you, read the thread, work out what they asked, and activate the matching skill: project-manager, team-brief, or research-memo. When this is a scheduled run, activate team-brief and follow its scheduled-run procedure."
    },
    "triggers": [
      {
        "type": "slack",
        "triggerId": "3dc23fbf-b976-475e-abdf-ba0f280f6bb8",
        "enabled": true,
        "eventSourceId": "d2b8f6a4-3e17-4c95-a0d6-8b1e5f9c2a73",
        "events": ["app_mention"],
        "routing": { "workspaceIds": [], "channelIds": ["C0APQ7Z1K2M"] },
        "botEvents": { "mode": "ignore" },
        "continuation": "resume_thread",
        "firstResponse": "platform"
      },
      {
        "type": "schedule",
        "triggerId": "6ca65f3d-49b8-4f41-a6be-86e9cf19167e",
        "enabled": true,
        "schedule": { "cron": "0 8 * * 1-5", "timezone": "America/New_York" }
      }
    ]
  }'
```

The automation starts paused. Resume it to let mentions and the schedule start runs. See [Run, pause, and resume](https://docs.labelbox.com/recursion/automations.md#run-pause-and-resume) and [Continue a Slack thread](https://docs.labelbox.com/recursion/automations.md#continue-a-slack-thread).

## Step 6: Track a thread

1. In the channel, post the decisions, for example:

   > Decisions from today's retry-storm review:
   >
   > 1. Ana ships the retry backoff fix (acme/payments#412) by Friday.
   > 2. Ben replies on the customer issue (acme/payments#398) once the fix is out.
   > 3. Ana updates the on-call runbook with the new alert threshold by Wednesday.

2. Reply in the thread and mention the agent: `@Chief of staff track this thread`.

3. The agent posts a board in the thread. It asks in the thread about any owner, date, or evidence it couldn't resolve.

When a pull request merges, its commitment moves to done with a link to the merge. Only replies that mention the agent wake it right away. It reads the rest of the thread at its next check.

### Approve an action

When a commitment stalls, the agent nudges its owner in the thread first. When that goes unanswered, or someone in the thread asks for an action outside it, the agent drafts it and calls the gated tool. An approval card appears in the thread with the tool and every argument.

1. Read the arguments on the card. What you approve is exactly what runs.
2. Click **Approve** or **Deny**. Only listed approvers can decide.
3. After an approval, the agent runs the call once and the board shows who approved it. After a denial, the agent doesn't retry and asks in the thread what to do instead.

A request waits 24 hours for a decision, and an approval waits 24 hours to be used. After that the agent asks again on the next work day.

### Read the ledger

Open the session from the automation's run history and choose the **Files** tab. **Outputs** shows `loops/<thread>.json`. Each done commitment has a receipt like this:

```json theme={"theme":"css-variables"}
{
  "at": "2026-11-12T14:05:00Z",
  "event": "PR acme/payments#412 merged into main by U0456EFGH",
  "link": "https://github.com/acme/payments/pull/412",
  "checked_with": "pull_request_read: state closed, merged true, merged_at 2026-11-12T14:03:51Z",
  "approved_by": null
}
```

## Step 7: Set up a team brief

1. In a channel the agent listens to, mention it with what the brief covers and where it posts, for example: `@Chief of staff set up a weekday brief for #payments-leads covering acme/payments, #payments-eng, and the threads you track`.
2. The agent confirms the brief's scope in the thread, saves it, and posts today's brief so you can see it. A brief reads a private channel only when it is also the channel the brief posts to. The agent refuses any other private channel, along with the commitments tracked in its threads, so a brief never carries a private channel's content to people outside it.
3. From the next weekday, the scheduled run posts it in `#payments-leads`.

A brief has at most 12 items, under **Decisions needed**, **Drifting**, **Shipped**, **From meetings**, **Coming up**, and **Risks**. It leaves out empty sections and anything it already reported that hasn't changed. When nothing changed, the brief is one line. A context line at the end names each source it read, and each one it couldn't, with the reason, for example `Calendar not connected`.

With a meeting app granted, the brief adds the decisions and action items from meetings since the last brief. It summarizes rather than quotes and leaves out personal remarks. It lists a meeting's action items and offers to track them, but never adds them to a thread's commitments unless someone asks. With a calendar app granted, it adds the upcoming meetings that a pending decision depends on. To change a brief, ask in a thread. Each brief is saved as `briefs/<profile>/<date>.json`.

## Step 8: Ask for a research memo

1. Mention the agent with the question and the decision it informs, for example: `@Chief of staff should we move feature flags from our in-house service to a hosted vendor? We need to decide by end of quarter.`
2. The agent posts its research plan in the thread, then researches, delegating separate questions to copies of itself.
3. It replies with the recommendation and its confidence, and saves the memo as `memos/<slug>.md`.

The memo has a recommendation, the question and assumptions, an options table, findings, open questions, and a numbered source list. Each source carries its date and the sentence that supports the claims citing it. The agent recommends; the person who asked decides.

## What success means

* The board in a tracked thread lists every commitment under its current status, and every done commitment links its evidence.
* Every GitHub comment, issue, or reviewer request the agent made has an approval card in the thread, approved by a listed approver.
* Each brief links a source for every line and names the sources it couldn't read.
* Every claim in a memo cites a source the agent read in full.
* The session's **Outcome** shows the rubric's verdicts for each turn a mention woke. See [Read the result](https://docs.labelbox.com/recursion/outcomes.md#read-the-result).

## What can go wrong

| Symptom | Cause | Fix |
| - | - | - |
| A mention starts nothing | The automation is paused, or the Recursion app isn't in the channel. | Resume the automation, and invite the app to the channel. |
| The agent answered a reply only later | The reply didn't mention the agent, so it was read at the next check. | Mention the agent when you want an answer right away. |
| No board or brief appears, and the agent says it can't post blocks | The Slack grant has `trigger_thread` access. | Grant the Slack connection with `workspace_tools` access and save a new version. |
| The scheduled run posts nothing | No brief is set up, or none is due that day. | Set one up in a thread (step 7), and check its days. |
| A brief says a source is unavailable | The meeting or calendar app isn't granted to the agent, or its read tools aren't allowed. | Grant the app with its read tools and save a new version. |
| A gated call returns that approval is unavailable | The session didn't start from a Slack mention, or the agent has no Slack grant for that workspace. Scheduled runs never can. | Ask for the action in a thread, with Slack granted on the agent. |
| No approval card appears | The write tool reached GitHub through the GitHub grant instead of the gated server. | Remove write tools from the GitHub grant, so only the gated server can write. |
| A session's tools don't start, naming a gated server | The token's URL is a different spelling of the gated server's URL. | Give the credential exactly `https://api.githubcopilot.com/mcp/`. |
| The agent waits on `wait_for_pr` and nothing arrives | `wait_for_pr` isn't selected on the GitHub connection and the agent. | Select it in both places and save a new version. |
| The session paused with `budget_reached` | It reached the agent's cost cap. | Raise the session's budget, then reply in the thread. |

## Limits

* The agent has no email access, and no calendar access unless you grant a calendar app. It can't prepare for meetings it can't see or triage an inbox.
* An approval request waits 24 hours for a decision, and an approval waits 24 hours to be used. A session tree can make at most 50 approval requests. A scheduled run can't request approval.
* A sleep timer is at most 30 days.
* A board message holds at most 50 blocks, so with many commitments the agent lists several in one section. A brief has at most 12 items.
* See [Limits](https://docs.labelbox.com/recursion/limits.md) for session and automation limits.

## Next steps

> [card] [MCP servers](https://docs.labelbox.com/recursion/mcp-servers.md)
>
> Declare servers, allowlist their tools, and gate them on approval.

> [card] [Automations](https://docs.labelbox.com/recursion/automations.md)
>
> Slack and schedule triggers, thread continuation, and run defaults.

> [card] [Integrations](https://docs.labelbox.com/recursion/integrations.md)
>
> Connect meeting and calendar apps for briefs.

> [card] [Outcomes](https://docs.labelbox.com/recursion/outcomes.md)
>
> Write rubrics a grader can check.
