<!-- Markdown rendering of https://salesascode.com/docs/library/rollup. The HTML page is canonical. -->

# Activity · Docs · Sales as Code

[← All feature docs](https://salesascode.com/docs/library)

Feature docs · /rollup

# Activity

A read-only rollup of what your scheduled runs produced: every run, its outcome and counts, and the brain state behind it, assembled from the telemetry and brain sync the runtime records.

[Open Activity →](https://salesascode.com/rollup) [All docs](https://salesascode.com/docs/library)

## Overview

The work runs on a schedule, on our servers; this is where you see the result. Every skill reports `emit_telemetry` when it finishes and `sync_brain` for the brain files it touched. Activity at [/rollup](https://salesascode.com/rollup) turns that stream into a per-account cockpit.

Scoped to your account. A run by your roles never appears on anyone else's Activity.

## What it shows

- **What changed (last 30 days).** Real output, not just run counts, the totals each role reported (emails drafted, meetings prepped, hours saved, and any other numbers a skill emits), plus runs and "actions" this week versus last week *and* this month versus last with the percentage change. "This month" is the trailing 30 days compared to the 30 days before them, rolling windows of equal length, so opening the page on the 2nd never compares two days against a full month. Outcome totals come straight from the `counts` a skill sends to `emit_telemetry`, no extra wiring.
- **Is everything running?** Every role you own and whether it is actually working: "Healthy", "Not started yet" (held but never run, the clearest signal to act on), or "Last run failed". A header tally flags how many are erroring or unused. It shows before anything has run, so a new account sees its roles listed straight away.
- **By role.** A card per role with total runs, the last run time, any errors, and a runs-per-day trend sparkline (see below). Each name links to that role's drill-down (see below).
- **Recent runs.** The latest runs across every role you own, with role, skill, outcome, the counts line the skill produced, and when. Failed runs carry a categorized error badge (see below), and every row links to its run drill-down page.
- **Brain state.** One row per scope (signal-weights, icp-registry, decision-log, funnel-brain, content calendar, and so on) with its latest sync time, key and snapshot counts, and a change highlight, e.g. "+5 keys, 2 changed since last sync 3d ago". Each row links to that scope's full snapshot timeline (see below).
- **How your work connects.** A dependency and data-flow diagram over what you own, with missing-dependency and stale-upstream warnings (see below).
- **Drafts ready to send.** Outreach drafted for you on your schedule, waiting on your review (see below).
- **Your hosted drafts** moved to [Home](https://salesascode.com/docs/library/home), where they are the Waiting on you block and carry how long each has waited.
- **Delivered to your Drive.** When Drive delivery is turned on for your account, each hosted run also writes its report into your Google Drive "Accounts" folder, a native Google Doc plus a raw `.md` copy, so you can open it where you already work. The card lists recent deliveries with *Open Doc* / *.md* links (see below). Off by default; the card stays hidden until the first delivery lands.
- **Questions to ask.** Worked deals with a real gap in what you know, and the specific question to close it (see below).

## Delivered to your Drive

The runtime can put its reports where you actually read them: your Google Drive. When Drive delivery is enabled for your account, the daily run writes each report into your Drive **"Accounts"** folder as a native Google Doc (so it opens formatted and you can comment on it) plus a raw `.md` copy (the exact model output). The **Delivered to your Drive** card links each one, you never dig for a file.

This is a deployment option, off by default. It only runs when your operator enables owned connectors, your account opts in, and you've connected Google with Drive access. Writing a file into your own Drive folder is delivery, not an outbound send, nothing leaves your account. A delivery that fails is flagged on the card and never affects the run itself.

## Drafts ready to send

On each scheduled pass, a run reads your account signals and drafts outreach for the contacts worth a touch that day. Those drafts land in the **Drafts ready to send** card, highest-quality first. Nothing is ever sent for you, every send is an explicit click.

- **Send.** Emails the draft as written, via your connected Gmail.
- **Use my edits.** Edit the draft in place, then toggle this before sending to send your version instead of the original. Your edits are recorded and feed back into how future drafts are written.
- **Skip.** Drops the draft, no send, no re-surface.
- **Snooze 24h.** Re-surfaces the same draft tomorrow.

A draft with no email address on the contact shows "no email" and can't be sent until you add one. Leads sourced from someone engaging with your content appear on [Content Studio](https://salesascode.com/docs/library/studio) under Warm leads instead, so the same person never shows up in both places.

## Questions to ask

On a scheduled pass, a run looks at your *worked* deals, the ones past qualification, with a live close date and real MEDDPICC evidence, and finds the specific thing you still don't know about each: no economic buyer named, no decision process mapped, no compelling metric quantified. For each gap it drafts the actual question to ask that buyer next, in a discovery style that opens a conversation instead of inviting a one-word answer.

- **Ask this first.** Each deal leads with the single highest-leverage question, the one you can't leave the next conversation without asking. Questions are ranked by leverage (gain times impact, minus how hard they are to ask), shown as a small "lev" tag.
- **Why this is a real test.** Under each question, a short certificate shows the assumption it tests, the falsifiable hypothesis about the answer, and what you would do differently based on it. That is the difference between a checklist and a real discovery question.
- **Asked it.** Marks the question handled and retires the card. The record is kept, not deleted.
- **Dismiss.** Drops it if it's not useful.

Only worked deals ever appear here, a deal you opened yesterday won't generate "ask who the economic buyer is", because an unstarted deal is *supposed* to have gaps. So an empty card means "nothing worth asking right now", never noise. Questions surface only once your pipeline actually holds opportunities with MEDDPICC detail; until then the card stays quiet.

## Brain-state timeline

Brain sync is append-only, so every scope keeps a history of snapshots. The Brain State card links each scope to `/rollup/brain/[scope]`, where you can see how that brain evolved:

- **Sync timeline.** An inline chart (no external libraries) with one dot per sync, oldest to newest. A filled dot changed the brain; a hollow dot re-synced with no key changes; a grey dot is the first sync. Hover a dot for its date, key count, and change count.
- **Snapshots & changes.** A feed of every sync, newest first, and exactly what changed versus the one before it, keys *added*, *changed*, or *removed*, plus a count of unchanged keys. The card highlights on Activity are the diff of the two most recent snapshots.
- **Key names and counts only.** The timeline shows top-level key *names* and counts, never raw values. "Changed" is detected by comparing a stable hash of each value between snapshots, so the page can tell you a key's value moved without ever exposing what it holds.
- **Honest empty states.** A scope with a single snapshot shows "no prior sync to compare"; a scope that was never synced (or belongs to another account) is not found. The same data is available as JSON at `/api/me/brain-timeline?scope=<scope>`.
- **Your reflection.** Below the timeline, this page also shows what your daily reflection has learned from your own activity: the insights, open gaps, and recommended next actions it is tracking for you. Unlike the snapshot timeline (key names and counts only), this is the reflection content itself, private to your account and shown only to you. Empty until you have logged enough account and prospect activity for a reflection to run.
- **Gaps close as well as open.** A gap the daily reflection raises again is the same gap, so it refreshes rather than appearing twice. One it stops finding in your activity, across two consecutive days, resolves and drops out of your open count and out of what your AI answers are grounded in. Resolved gaps stay on the page, so you can see what you cleared rather than watching it silently disappear. The same rule applies to recommended actions.

## Live activity

Skills that declare their start (the `start_run` MCP tool) show up while they work, not just after:

- **Running now.** A strip at the top of the page with each in-flight run, skill, role, a spinner, and the elapsed time ticking live. It refreshes about every 30 seconds while the tab is open (nothing polls in the background), and when a run finishes the spinner flips to its outcome badge with a link to the drill-down.
- **Stale runs.** A run that declared a start but has been silent for 30 minutes, no heartbeat, no final report, is flagged *stale* instead of pretending to run forever. Stale usually means the skill crashed or the session was abandoned; re-run it.
- **Timeline.** The same recent runs grouped per day as a compact started &rarr; completed view (collapsible; today open by default). Runs still in flight show an open arrow.

Product versions that don't declare starts never appear as running, their runs land directly in Recent runs when they finish, exactly as before.

## Performance trends

Each role card carries a runs-per-day sparkline for the active window, with a **7d / 30d / 90d** toggle above the grid. Under the sparkline: that role's median run duration and its error rate over the window. Bars for days with at least one failed run are tinted red; hover any bar for that day's exact counts.

- **Deterministic math, no AI.** Runs are bucketed per UTC day; duration is the standard median over finished runs; error rate is errors divided by finished runs. Every number is reproducible from your run history.
- **Honest error rates.** Runs still *running*, or gone *stale*, have no outcome yet, so they count as activity but are excluded from the error-rate denominator and the duration median. A day where nothing finished shows a placeholder, not a fake 0%.
- **Honest history.** A role with fewer than two active days in the window shows "Not enough history yet" instead of a made-up flat line.

The trend data (per role, and per skill within each role) comes from `GET /api/me/rollup-trends?window=7d|30d|90d`, scoped to your account.

## How your work connects

The roles are built to feed each other: your business record carries your company, offer and voice, each role reads it, and each produces brain scopes the next one consumes. The **How your work connects** card draws that as a small diagram (inline SVG, no external libraries) over what you actually own:

- **Nodes are what you own.** The one everything else reads from sits on top (marked with a star); the rest hang off it. Each node's ring is green when healthy, amber when never started, red when its last run failed, and the glyph shows its run count. Hover a node for its status.
- **Solid lines are requirements.** The solid edges show which of the things you own depend on another.
- **Dashed lines are real data-flow.** A dashed arrow from A to B means A synced a brain scope that B reads, derived by intersecting each one's declared scope interests (what it writes against what it reads) with the scopes actually observed in your brain sync. No observed sync, no arrow. Hover an arrow for the scope flowing across it.

Below the diagram, **coordination warnings** flag things to fix, each linking straight to the fix:

- **Missing dependency.** You licensed a role engine but not the Company OS Core it depends on, links to pricing.
- **Ran before Core set up.** An engine has runs but the Core dossier was never synced, so it never read your company context. Run Core's setup first.
- **Idle.** Something you own that has not run in the last 7 days (or never has), a churn signal, links to Connect.
- **Stale upstream.** Something active is reading brain data from a producer that has not re-synced in over two weeks, so it is working from stale inputs. Re-run the producer.

Honest empty state: owning one thing means there is nothing to coordinate, so the card says so and links to the catalog. Warnings are deterministic rules over your own run and sync history, no AI, every one reproducible.

## Goals & targets

The **Goals** card turns Activity from a receipt into a pace check. Set a target against any outcome your roles actually report and see how far along you are this week or month:

- **Any metric your roles emit.** The metric dropdown is built from the outcome keys your telemetry has actually carried (like `contacts_researched`, `meetings_prepped`, `emails_drafted`), never a hardcoded list. If a role has never reported a number, there is nothing to set a goal on yet, and the card says so.
- **Deterministic progress.** Progress is the plain sum of that metric's counts across your runs inside the window, a run missing the key counts as 0, and multiple roles reporting the same key all add up. Every number is reproducible from your run history; no AI in the math.
- **Week or month, calendar-aligned.** "Per month" is the current calendar month (UTC); "per week" is the current week starting Monday. A progress bar fills toward the target with the current total and percentage.
- **Personal or team goals.** A personal goal tracks your own telemetry. If you own a team, you can set a *team* goal that sums every member's telemetry, only the team owner can create, edit, or delete team goals.
- **Edit & delete.** Adjust a target or remove a goal any time from the card. Honest empty state: with no goals set, the card reads "Set a goal to track pace."

The same data is available as JSON at `GET /api/me/goals`.

## Pace & behind-pace alerts

Each goal shows a **pace** badge, Ahead, On pace, or Behind, computed deterministically by comparing how far through the window you are with how far toward target you are (within a plus-or-minus 15% band of the straight-line expectation). The progress bar tints red when you fall behind. Nothing here is a guess; every status is reproducible from your run history.

- **Behind-pace email.** A daily cron checks every active goal and, when one is behind pace, emails the owner once per window (never more than once a month for a monthly goal, or once a week for a weekly one). The email carries the exact progress, how far the window has elapsed, and the single suggested next action.
- **Optional Slack nudge.** If you have configured a personal Slack incoming webhook (Settings, API), the same behind-pace nudge is also posted there. It is best-effort, a Slack hiccup never blocks the email.
- **Quiet by design.** On-pace and ahead goals are never alerted. If email is not configured on the deployment, the cron simply logs instead of sending, and the once-per-window ledger still prevents duplicates.

## What moved to Home

Activity is the record of what ran. Deciding what to do about it belongs on [Home](https://salesascode.com/docs/library/home), where everything competing for your attention is ranked against everything else rather than in its own card.

Two cards moved there. **Suggested next actions**, a fixed rule table over your telemetry, is now part of the ranked line, so a nudge from your run history sits in the same order as a deal about to slip instead of in a separate list you might not scroll to. **Your hosted drafts** is now the Waiting on you block, which shows how long each has waited, because an approval that quietly piles up is the failure that card could not surface.

Nothing was lost and nothing new is hidden. This page keeps the full run history, the health and coordination views, your goals, and the drill-downs below.

## Run drill-down

Every row in Recent Runs links to `/rollup/run/[id]`, one run, in full:

- **At a glance.** Outcome, duration, when it ran, and the run id.
- **What went wrong.** When a run failed, a categorized error badge, `auth`, `entitlement`, `rate limit`, `provider`, `skill logic`, or `unknown`, with the detail line the skill sent and a one-line hint on what to do about that category. Runs from versions that predate the taxonomy show as "uncategorized".
- **Full run payload.** Everything the skill reported to `emit_telemetry`, rendered as a key/value table (stored whole, 64KB cap at ingest). Runs recorded before payload capture shipped fall back to their counts line, honestly labeled.
- **Brain syncs from the run.** When the role passes the shared run id (`run_ref`) on its `sync_brain` calls, the drill-down shows exactly the snapshots that run produced, labeled as an exact match. Older runs without it fall back to a time-window match, honestly labeled: treat that as "what landed around this run", not a guaranteed causal link.
- **Re-run.** A one-click re-run of the same skill, carrying the previous run's outcome, counts, and error context.

## Per-role drill-down

Every role you own has its own page at `/rollup/[pluginId]`, reachable by clicking its name anywhere it appears on Activity: the **Is everything running?** card, the **By role** card, or its node in **How your work connects**. It pulls that role's slice into one place:

- **Health at a glance.** Status (Healthy / Not started yet / Last run failed), total runs, error count, and last-run time.
- **Trend.** That role's runs-per-day sparkline for the active window (7d / 30d / 90d toggle), plus median duration and error rate, and a sparkline *per skill* underneath, from the same `/api/me/rollup-trends` data. No chart library; the same inline-SVG sparklines used across Activity.
- **Coordination.** Just this role's edges from the map, what it *requires*, what *requires* it, the brain scopes it *feeds* to others, and the scopes it is *fed by*, with any warnings that name it. Each link opens that role's own drill-down.
- **Brain scopes.** The scopes this role has synced, each with its change highlight and a link to that scope's full timeline.
- **Error log.** This role's recent failed runs with their categorized error badge, each linking to the run drill-down, plus a one-click **Retry** that re-runs the failed skills.
- **Run history.** The most recent runs of just this role, in the same table used on the main Activity (the role column dropped, since it is redundant here).

Honest scoping: something you do not own, or a made-up id, reads as not found, indistinguishable from one that does not exist. Every section has an empty state (a role that has never run shows a connect prompt, not fake data).

## Filter by account

When your skills tag their runs with an account (the optional `account_ref` label they pass to `emit_telemetry`, a domain or account name), Activity gains an **Account** filter above the runs:

- **Scope to one account.** Pick an account from the dropdown (each option shows its run count) to scope the **Recent runs** table, the **By role** summary, and the **Timeline** to just that account's runs. "All accounts" clears it. The filter lives in the URL (`/rollup?account=acme.com`), so a scoped view is linkable.
- **A label, not a record.** `account_ref` is a free-text label, a domain like `acme.com` or a name, not a synced CRM record. It is the same account you already know; Activity just groups by it.
- **Honest empty state.** Until a skill passes an account, the card reads "No account labels yet" and explains what unlocks the filter. Versions that do not send `account_ref` still appear in every unscoped view exactly as before.

Whether a skill tags its runs is up to the skill. One that works a specific account should pass its domain; one with no single account omits it. See [the API reference](https://salesascode.com/docs/api#account-ref) for the label convention.

## Dossier completeness

A compact **GTM Context Dossier** card rides along near the top of Activity: a meter scoring how many of the six dossier sections are filled (company, products, founder, voice, ICP, competitors) and a **consumed-by** line showing which roles have actually read your context, **Core** once your session pulls config, and each role with when it last synced brain state against it. The card appears only when it's relevant (you own the Content Engine, a dossier exists, or something has consumed it) and links to [/onboarding/dossier](https://salesascode.com/onboarding/dossier) to sharpen it. Full detail: [GTM Context Dossier](https://salesascode.com/docs/library/gtm-context-dossier).

## How it fills up

- [Connect your tools](https://salesascode.com/settings/connect) and finish the setup for the roles you hold.
- As the scheduled runs happen, they call `emit_telemetry` and `sync_brain` against the runtime.
- This page reads the resulting `plugin_runs` and `brain_sync` records, scoped to your account.

Until a run happens, Activity shows an empty state with a link to connect.

## Weekly digest email

Every Monday, we email you a recap of the same data, runs and "actions" this week versus last, what changed, and any role that is idle or erroring, so you stay in the loop without logging in. You only get it if your runs happened in the last week. Every email has a one-click unsubscribe; you can also opt out from account settings.

## How you compare

When your deployment enables cross-tenant benchmarks, a "How you compare" card shows your activity per won opportunity against the **anonymized median band across every team** on the deployment, never any other team's raw data. It appears only when the deployment flag is on, at least five teams have data, and you have not opted out (Settings, Data). Read-only. Full detail: `docs/privacy/cross-tenant-benchmarks.md`.

## Data & privacy

The work runs on our servers, so we process the data you connect to do it. That data is encrypted at rest, isolated to your tenant, never sold, and never used to train models, and you can export or delete it at any time. Two different things flow into Activity, and they carry different sensitivity:

- **Run telemetry is metadata.** Run counts, outcomes, durations, and brain-state key names and counts. This is what most of Activity shows.
- **Generated drafts hold content.** A drafted email or report contains real text. It stays in your account, draft-only, until you send it. Nothing is ever sent on your behalf.

A short **"Your data"** card sits at the top of Activity linking to the full explainer on the [Trust & security](https://salesascode.com/trust) page (which also carries the security one-pager and our honest SOC 2 roadmap statement).

## Related

- [Connect your tools](https://salesascode.com/docs/library/connect), get your scheduled runs going so this fills up.
- [API Keys & MCP](https://salesascode.com/docs/library/api-keys), the advanced tools that also feed this rollup.
- **Team rollup** (`/team-admin/rollup`), the same outcome metrics across a team, plus a rep-vs-team leaderboard (members ranked by actions, each compared to the team median) and the team's week-over-week.

---

More for agents: [llms.txt](https://salesascode.com/llms.txt), [full reference](https://salesascode.com/llms-full.txt), [OpenAPI](https://salesascode.com/openapi.json), [sitemap](https://salesascode.com/sitemap.xml).
