---
name: scout7-run-engagement-loop
description: >-
  Set up Scout7's engagement engine for a brand — the always-on system that
  likes, follows, and comments in the brand's voice across the social accounts
  the user signs in to. Pulls brand, voice, and canonical facts from the
  connected Scout7 workspace so the user only picks platforms and signs in.
  Claude drives the whole zero-to-hero path invisibly — scaffolds the engine
  folder, dry-runs it, registers one scheduled task per platform, pre-approves
  browser control, and proves each schedule fires (heartbeat in runs.jsonl)
  before handing over. Use when the user asks Scout7 to start engaging, turn on
  commenting or likes/follows, or "get the engagement engine running" — for
  their own brand or another operator's, or when porting to another machine.
---

# Engagement setup — zero to hero

The engine itself is a folder of Python + playbooks (identity.json,
CONTROLS.json, lib/cycle.py, docs/RUNNER.md). **The user should never see
those names.** Claude scaffolds the folder, writes the config, registers the
scheduled runs, and proves the schedule actually fires — the user only makes
the three decisions no automation can make for them.

## The exit gate — what "done" means

This skill is not done when the folder is generated. It is done when **each
enabled platform has a scheduled task that has fired at least once and left a
heartbeat in `state/runs.jsonl`.** Paused-skip heartbeats count — they prove
the schedule works. Do not hand off before that gate.

## What the user actually decides

1. **Which accounts to engage as** — one login per platform, verified live
2. **Which platforms to turn on** — from the eleven the engine supports
3. **A one-line OK** at the end before unpausing (the schedule itself starts
   proving out immediately after step 5, paused)

Everything else — brand name, voice, canonical facts, targets, ramp, mention
mix, quiet hours, hard-stops, ICP targeting — comes from the connected Scout7
workspace or safe template defaults. Do not run a long questionnaire.

## Workflow

### 0. Preflight (silent — before the first user question)

If any of these fails, stop and say so plainly. Do not begin the interview.

| Requires                                                                                             | Check                   | If missing                                                                                                                                                                                                                                    |
| ---------------------------------------------------------------------------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Chrome extension** (`mcp__claude-in-chrome__*`)                                                    | Call `tabs_context_mcp` | Tell the user to install "Claude for Chrome" and reconnect. **Do not** fall back to the in-app browser (`mcp__Claude_Browser__*`) — its session won't persist to the scheduled runner, and everything downstream depends on that persistence. |
| **Python 3** on PATH                                                                                 | `python3 --version`     | Tell the user which install to use (Homebrew python@3, uv, pyenv). The engine is stdlib-only, so no pip step.                                                                                                                                 |
| **A scheduler** — prefer `mcp__scheduled-tasks__*`; user's productivity plugin scheduler is fine too | List available tools    | If none: note it — you'll fall back to a cron block at step 5, but say so up front.                                                                                                                                                           |

Also note the **per-session scoping gotcha** early in your head — Cowork
scheduled tasks show up only in the Scheduled sidebar of the session that
created them. Register them from the session the user will keep coming back
to. If they might switch sessions, warn once.

### 1. Sign in — in real Chrome (the same browser the scheduler will drive)

Nothing downstream matters if the scheduled runs can't reach the accounts.
Use **`mcp__claude-in-chrome__*` only.** Do not use the in-app browser.

1. Ask **"which platforms should this brand engage on?"** — pick from
   threads, x, instagram, reddit, hackernews, quora, youtube, facebook,
   indiehackers, cofounderslab, discord.
2. For each picked platform:
   - Navigate in Chrome via `mcp__claude-in-chrome__navigate`. If it's not
     already signed into the right account, hand the login page to the user.
     **Never type their password, OTP, or any credential, and never create
     an account** — that is theirs to do. Wait for confirmation.
   - **Verify the visible handle on screen** matches the brand's account
     (`mcp__claude-in-chrome__read_page` → find the handle in the header/nav).
     This is the one check that stops the engine ever posting as the wrong
     person (once, it posted as `@MuraliSid` on X). Do not skip. Do not
     trust memory.
   - If a platform can't be signed in right now, note it and move on. It
     stays disabled until they're ready.

End with a one-line summary — "ready: threads (@acme), x (@acme); skipped:
instagram (not signed in) — continuing" — and carry these results into step 3
so `platforms_enabled` and `handles` are already correct.

### 2. Pull the brand from Scout7 (no interview needed)

Call `scout7_get_workspace_context`, then `scout7_get_brand_context` for the
active brand. From those you already have:

- brand name, domain, one-line
- voice / stance (Scout7's brand context)
- what the brand may claim (canonical facts)

Show a short recap — "setting this up for **Acme** (acme.dev) — the AI copilot
for solo founders. Voice from your Scout7 brand context. OK?" — and apply any
correction they call out. **Do not re-ask fields Scout7 already knows.**

If no Scout7 brand is connected, ask three essentials and stop there: name,
domain, one-line. Voice tightens via feedback over the first days.

### 3. Build it (silently, under the hood)

In the scratchpad, assemble an `identity.json` from steps 1–2, then run:

```bash
python3 scripts/generate.py --identity <scratchpad>/identity.json --out <install-dir>
```

Install dir defaults to `~/scout7-engagement/<brand-slug>` unless the user
names another. Report in one line: "engine scaffolded at
`~/scout7-engagement/acme`, paused." Do not paste the generator's stdout.

Defaults Claude fills without asking:

| Field                                                | Default                                                                   |
| ---------------------------------------------------- | ------------------------------------------------------------------------- |
| targets, ramp, mention ladder, quiet hours           | template defaults in `config.base.json`                                   |
| hard-stops                                           | empty (user adds later via natural-language feedback)                     |
| stance / facts markdown                              | from Scout7 brand context; placeholders if absent                         |
| ICP community targeting (subreddits, spaces, groups) | template defaults; refined later                                          |
| `paused`                                             | **true** — flipped only after the schedule is proven and the user says go |

Schema and example for the internal team: [identity.schema.json](references/identity.schema.json),
[identity.example.json](examples/identity.example.json).

### 4. Local dry-run — prove the engine plans a cycle

Before scheduling anything, prove `cycle.py` runs cleanly. This catches
config mistakes while the user is still at the keyboard.

```bash
cd <install-dir> && python3 lib/cycle.py <first-enabled-platform>
```

Expected: prints a plan JSON, and because `paused: true`, `plan.skip` is
`"paused"`. A row appends to `state/runs.jsonl`. If it errors instead, fix
before moving on — the schedule cannot fix an engine that can't plan.

Report: "engine plans a cycle cleanly — skipping because paused, as
expected." One line, no JSON dump.

### 5. Register one scheduled task per enabled platform

**Naming:** `engagement-<brand-slug>-<platform>` — e.g. `engagement-acme-threads`.

**Cadence:** every 30 minutes. The scheduler self-jitters so they don't fire
in lockstep.

**Prompt** (per the runner contract, `docs/RUNNER.md` §2, with placeholders
filled in):

```
Run one engagement cycle for <platform> as <@handle>.

Read <install-dir>/CYCLE.md and follow it exactly.

Start with:
  cd <install-dir> && python3 lib/cycle.py <platform>

If the plan's "skip" is non-null, log it and stop.

You have no memory of previous runs — the plan and the ledger are the only truth.
You do the work yourself in the browser; the Python is bookkeeping only.
There is no approval step: what you write, you post.
Budget: 25 minutes. Stop cleanly when it is up.

Reuse ONE browser tab — navigate in place, do not open a tab per post.
Before you exit — for ANY reason, including errors — close every tab you opened.
Never close a tab you did not open.
```

**How to register:**

- **Preferred** — `mcp__scheduled-tasks__create_scheduled_task` per platform,
  cwd = `<install-dir>`, cron = `*/30 * * * *`, prompt = the block above.
  Pass any browser-control pre-approval option the tool exposes, so the
  first fire doesn't stall.
- **Fallback (no scheduler tool available)** — print a ready-to-paste cron
  block, one line per platform (`3,33 * * * *`, `9,39 * * * *`,
  `16,46 * * * *` — offset minutes so they stagger). Say plainly "I don't
  have a scheduler in this session, so paste this into your crontab" and
  wait for the user to confirm. **Do not** point them at `docs/RUNNER.md`.

**Warn once about session scoping** (Cowork only): "these tasks show up in
the Scheduled sidebar of this Claude session — if you switch to a different
session and don't see them, they're still running, just recreate from that
session if you want them visible there."

Confirm in one line: "scheduled 3 runs — threads, x, instagram — every 30
min. They're paused, so nothing posts."

### 6. Prove the schedule fires (this is the exit gate)

For each just-registered task:

1. Trigger it once. With the scheduled-tasks tool, that's the "Run now"
   equivalent (the user hits it in the Scheduled sidebar, OR you invoke a
   trigger call if the tool exposes one). This also grants the browser-control
   pre-approval for future unattended fires. With cron fallback, wait for the
   next scheduled minute, or run the exact command once by hand:
   `cd <install-dir> && python3 lib/cycle.py <platform>`.
2. Verify a fresh row landed in `<install-dir>/state/runs.jsonl` for that
   platform. Look for `"skip":"paused"` — that's the correct state right now.
3. Only after all enabled platforms show a heartbeat: report "schedule
   proven: threads, x, instagram each fired and logged a paused-skip. Safe
   to unpause when you're ready."

If any platform's heartbeat is missing after two tries, **stop and diagnose**
— do not hand off. Common causes: task registered in a different session
(sidebar shows nothing here — re-register from this session), cwd wrong,
python3 not on the scheduled task's PATH, browser-control approval not granted.

### 7. Supervised first live run (user's call)

- Ask **"schedule is proven and paused. Want to unpause and watch one live
  cycle now, or leave it paused until later?"**
- On unpause: flip `paused: false` in `<install-dir>/control/CONTROLS.json`,
  trigger one cycle for the first platform, and read back what it did in
  plain English — "liked 4, followed 1, commented on 2 threads. Handle
  checked as @acme." Do not paste `state/runs.jsonl`.
- On leave-paused: leave it. The scheduled tasks keep firing paused-skips
  (harmless, few seconds each). Tell the user "say 'unpause the engagement
  engine' when you're ready and I'll flip it."

### 8. Hand-off

Give the user, in plain language:

- Where the engine lives (`<install-dir>`) — so they can peek if they want
- **How to give feedback** — "tell me 'that comment was too salesy' or 'never
  engage with @spam-account' — I write it into the engine and the next cycle
  picks it up." No file editing.
- **How to pause / unpause / enable a new platform** — all via natural
  language to Claude.
- Print the short user-facing checklist: [HUMAN-CHECKLIST.md](references/HUMAN-CHECKLIST.md).

## What Claude never surfaces unprompted

Do not say these names to the user unless they ask by name:

- `identity.json`, `config.json`, `CONTROLS.json`, `state/runs.jsonl`
- `lib/cycle.py`, `dashboard/serve.py`, `scripts/generate.py`
- `docs/RUNNER.md`, `docs/PORTING.md`, `docs/SCHEDULE.md`
- Chrome profile names (read them off the browser Claude is already driving)
- Ramp percentages, mention ladder mix, per-platform target overrides
- Reddit tiers, Quora spaces, Facebook groups — Scout7 already knows the ICP

If the user _does_ ask ("show me config.json"), open it and explain. Don't
preempt.

## Guardrails

- **Never** use the in-app browser (`mcp__Claude_Browser__*`) for the sign-in
  step. Its session won't persist to the scheduled runner. `claude-in-chrome`
  only.
- **Never** type passwords, OTPs, or create accounts on the user's behalf
- **Never** enable a platform whose visible handle wasn't verified
- **Never** register scheduled tasks before step 4's dry-run passes
- **Never** claim the schedule is set up before step 6's heartbeat check
- **Never** copy another operator's `state/` into a new install
- **Never** flip `paused` to false without an explicit user confirmation
- Do **not** edit the live source repo at `engagement-engine/` unless the
  user explicitly asks — this skill always scaffolds a **new** folder
