Skip to content
Marketing
Skill

/outcomes-ledger

Shared step of the marketing playbooks (research-audience, write-outreach, work-with-creators): keeps the brand's record of the prospects or creators that were handed over. Tracks a status for each person, permanent opt-outs, re-check dates and dated lessons, which the next run

BOOST
From plugin
goose-skills
1.3k200 skills
Install
$ npx -y skills add gooseworks-ai/goose-skills --skill outcomes-ledger --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/outcomes-ledger

Context preview

The summary Claude sees to decide when to auto-load this skill.

Shared step of the marketing playbooks (research-audience, write-outreach, work-with-creators): keeps the brand's record of the prospects or creators that were handed over. Tracks a status for each person, permanent opt-outs, re-check dates and dated lessons, which the next run

SKILL.md

outcomes-ledger.SKILL.md
name: outcomes-ledger
description: >-
  Shared step of the marketing playbooks (research-audience, write-outreach, work-with-creators):
  keeps the brand's record of the prospects or creators that were handed over. Tracks a status for
  each person, permanent opt-outs, re-check dates and dated lessons, which the next run reads. Loaded
  by those playbooks; not for direct use.
version: 0.1.1

outcomes-ledger

Every list a playbook hands over gets acted on outside GooseWorks: the human emails the prospects, messages the creators. This atom is how what happened comes back, so the next run never repeats a person who said no and gets better from what worked. It never contacts anyone and never requires outcomes: no outcomes, carry on.

Parameters (the loading playbook sets them)

| | `entity: person` | `entity: creator` | |---|---|---| | Loaded by | research-audience (writes rows when a list is shown), write-outreach (updates statuses from replies and results) | work-with-creators | | Ledger file | `research/audience/ledger.csv` | `creators/roster.csv` | | Lessons document (file → brand document) | `research/audience/lessons/<YYYY-MM-DD>.md` → `Outreach lessons — <Brand> — <YYYY-MM-DD>` | `creators/lessons/<YYYY-MM-DD>.md` → `Creator lessons — <Brand> — <YYYY-MM-DD>` | | Entity columns (after the required ones) | `segment, tier, value_tier, signal_type, email_status, region_flag, email, email_candidate, profile_url, root_domain, route, sequence_id, opener_id, first_touch_date, last_touch, reply_category, recontact_after` | `role, tier, deal_structure, vetting_depth, wave, wave_criterion, wave_result, quoted_rate`, then the roster's own columns | | Status values | `listed · contacted · replied · meeting · not-a-fit · bounced · unsubscribed · do-not-contact` | `shortlisted · contacted · replied · quoted · declined · signed · posted · never-again` | | Suppressing statuses (permanent) | `bounced · unsubscribed · do-not-contact` | `never-again` | | Timed exclusions (not suppression) | `not-a-fit` — the account is skipped for 6 months, then eligible again; `contacted` with no reply after the sequence ended — the person is skipped for 12 weeks on every channel (cool-down) | `declined` — skipped until the human re-opens it | | Match keys, in order | email (or email_candidate) → profile URL → name + root domain; account rows: root domain + route | handle + platform → profile URL | | Grouped by (for lessons) | segment, tier, signal type, email status, region flag, sequence, opener and touch, reply category | role, tier, deal structure, vetting depth, wave | | Re-check | `recheck_by` = date listed + 30 days | `revet_by` = vetted on + 30 days |

Files and scope

  • Brand coworker workspace (`file_*` scope agent = the brand's `coworker_agent_id` from the `brand_read` list). No coworker → the default workspace with every path prefixed `brands/<brand-slug>/`, and tell the human teammates won't see it.
  • **Read before write**: `file_write` replaces the whole file. Read the ledger, change rows, write it back complete.
  • Every row a playbook *shows* the human is ledgered at the moment it is shown — sample rows included — not only at handover. Rows from a sample whose definition the human then rejected get status `listed-sample-rejected` and are **not** excluded later (the person was never handed over for outreach).
  • Required columns, first and in this order (both entities): `row_type, key, key_hash, name_or_handle, account_or_platform, date_listed, list_id, status, status_date, suppressed, suppressed_reason, suppressed_date, recheck_by|revet_by, outcome, notes`. `key` is the first available match key (person: email, else profile URL, else name + root domain; creator: `platform:handle`). Then the entity columns above, then the loading playbook's own columns. Never drop a column on write-back; unknown columns are kept as they are.
  • A new entity (another playbook wanting a ledger) needs its row in the tables above, added by this atom's owner — ask before loading it.

On every run (before any new sourcing)

1. Read the ledger. If it does not exist, create it with the header; carry on. 2. **Flag stale rows for free**: rows past `recheck_by` / `revet_by` that are not yet contacted. Tell the human in one line ("12 people from the 2026-09-10 list haven't been contacted and are past their re-check date"). Re-checking them is paid → the loading playbook's spend step (the `spend-gate` skill, `../spend-gate/SKILL.md`). 3. **Ask for outcomes once, never require them — in the run's closing decisions, never before the first result**: "Anything to report since <last list date> — replies, meetings, bounces, unsubscribes, declines, quotes? Paste, upload, or tell me in a sentence." Creators past a wave's read window (in `creators/<date>/wave-1.md`): also ask for each creator's views, orders on their code or link, and whether they posted. No answer → skip to step 6. 4. **Match** each reported outcome to a row by the match keys in order. Unmatched lines are shown back, never guessed onto a row. A `stop`, unsubscribe, complaint or bounce from an address not in the ledger gets a **suppression-only row: the `key_hash`, the reason and the date — never the address** (§ Suppression without personal data). Keeping the raw address needs the human's yes, asked once in the closing decisions. 5. **Update** `status`, `status_date`, `outcome` — and for people, `first_touch_date` when the first send is reported (never overwritten afterwards; it anchors rates and the cool-down), `last_touch`, `reply_category`, and `recontact_after` for a "not now, try in <month>" reply (and for creators `quoted_rate` when reported). Creators with wave results: score each against its `wave_criterion` → `wave_result` = `win · partial · miss · no-data`. A suppressing status sets `suppressed` with reason and date, and reduces the row to its suppression form (below); a timed exclusion sets `outcome` and the date it lapses. **Suppression is permanen

Read more
Ships withgoose-skills

Put your AI agent on the growth team. Research customers and competitors, analyze what is working, create the next campaign, and learn from the result.

Get the whole plugin

Other skills on goose-skills.