Skill

Retainer Scope Tracker

Compare delivered work against contracted retainer scope for a month, flagging scope creep and out-of-scope work, computing effective hourly rate and delivery margin per client, and ranking which retainers to renegotiate and which clients…

See an example

Example output from a sample run. Company names and figures are sample data.

Retainer scope and margin: 5-client portfolio, September 2026

Blended margin is 52.4% against a 55.0% target. The team delivered 317 of 295 contracted hours (+7.5%) on $39,000 in fees. Beacon Street Dental and Halcyon Robotics are over scope and under the margin target, and are the two retainers to renegotiate.

ClientFeeScoped hDelivered hMargin %Flags
Beacon Street Dental$4,500406118.0%Scope creep, margin, rate, unscoped work
Cobalt Freight Systems$7,500505258.9%—
Halcyon Robotics$9,000607848.1%Scope creep, margin, rate, unscoped work
Kestrel Outdoor Co.$12,000908659.4%—
Marlow & Finch$6,000554062.2%Under-delivered
Portfolio$39,00029531752.4%
RenegotiateEffective rateContracted rateAnnualized gapReprice toRenewal
Beacon Street Dental$73.77/h$112.50/h$19,992$8,300/mo2026-12-31
Halcyon Robotics$115.38/h$150.00/h$7,416$10,400/mo2026-10-31

Next actions

  • Beacon Street Dental: the contract itself is underpriced. Holding the line at 40h still returns only 46.2% margin, so reprice: $8,300 per month holds 55.0% on 61h. Price or stop the out-of-scope Website copy edits (10h, $710 of cost). Open the conversation by 2026-11-16.
  • Halcyon Robotics: fix delivery discipline before touching price. Delivering exactly 60h returns 60.1% margin on its own. Scope or stop the Sales enablement deck (12h, $900 of cost). Renewal 2026-10-31 is inside the 45-day notice window, so this conversation is already late.
  • Marlow & Finch: delivered 40h against 55h (-27.3%), with 'Email lifecycle' at 3 of 4 and 'SEO content brief' at 0 of 2. Deploy the remaining 15h before renewal on 2027-06-30.
  • Cobalt Freight Systems (58.9%) and Kestrel Outdoor Co. (59.4%) are healthy; no change.

Inputs: contracts, scope, time entries, roster and deliverables for 2026-09, as of 2026-10-05. Margin is fee minus logged hours at internal cost and excludes overhead, software, media and pass-through costs.

Produced by running bash examples/run.sh on the sample data bundled with this skill.

AI for agencies: a practical guide

Browse the technical files
---
name: retainer-scope-tracker
description: Compare delivered work against contracted retainer scope for a month, flagging scope creep and out-of-scope work, computing effective hourly rate and delivery margin per client, and ranking which retainers to renegotiate and which clients are being under-served.
---

# Retainer scope tracker

Answers the two questions every agency owner asks at month end: which clients
are consuming more than they bought, and which retainers are no longer worth
the team's time. Output is a portfolio table, a per-client scope variance
breakdown, a ranked renegotiation list with two concrete levers per client, and
a list of clients who were under-served.

## Before you run

This skill ships scripts and sample data alongside this SKILL.md. Before running any command:

1. **Get the files.** Make sure the skill's other files (`scripts/`, `examples/` and anything else listed with this skill) are in your working folder at the same relative paths. Some environments load only SKILL.md; if yours did, fetch each file from this skill's published files and write it to the matching path. In Type, read them with the skill-file tools. Anywhere else, the Type Skills Library API lists every file with its path, content and `sha256`: GET `https://api.type.com/api/public/library/skills` and take the entry with slug `retainer-scope-tracker`.
2. **Check the copies are exact.** Compare each file's size in bytes, not characters (and its hash, where your tools report one), with the published version before running. A copy written out from the published file is fine once its byte size and hash match; never run a script you summarised or reconstructed from memory.
3. **Run from the skill's folder**, calling interpreters explicitly: `python3 scripts/…` and `bash examples/run.sh`.
4. **Try the sample first.** If the skill ships `examples/run.sh` and `examples/expected_output.txt`, run `bash examples/run.sh`; its output should match the expected file exactly. If it doesn't, stop and report the first differing line rather than running on real data.

## When to use this

- Month-end close, before invoicing and before the next month's capacity plan.
- Before a renewal conversation, to bring numbers instead of impressions.
- When the team feels underwater and the cause needs to be located: one client,
  one deliverable, or systemic underpricing.

## Gathering the inputs

Five CSVs. Full column specs are in `DATA_CONTRACT.md`. Everything is read from
local files; the script makes no network calls and never sees a credential.

1. **`contracts.csv`** — one row per client per month: retainer fee, contracted
   hours, renewal date. Source: the signed statement of work, or the billing
   system (the connected accounting or invoicing integration). Keep historical
   months in the file; only rows matching `--month` are read.
2. **`scope.csv`** — the contracted deliverables for that month, with quantity
   and budgeted hours each. Source: the SOW's scope table. If the SOW has no
   hour estimates per deliverable, allocate the contracted hours across
   deliverables with the account lead before running this; the comparison is
   only as good as that allocation.
3. **`time_entries.csv`** — logged time from the time-tracking or project tool
   (Harvest, Toggl, Clockify, Asana, Jira, Monday). One row per entry, with the
   client, person, deliverable and hours. The `deliverable` value must use the
   same names as `scope.csv` — reconcile the label sets before running, since
   an unmatched name is reported as out-of-scope work.
4. **`roster.csv`** — internal cost per hour by person. Source: payroll or the
   ops spreadsheet. Use fully loaded cost (salary plus employer burden) divided
   by productive hours, or the standard cost the finance lead already maintains.
   This file is sensitive; keep it out of anything client-facing.
5. **`deliverables.csv`** — what actually shipped, with quantities, from the
   project tool. This is what detects "we sent two reports for a
   one-report scope" even when the hours look fine.

## Running it

First run: `bash examples/run.sh` runs the tracker against the bundled sample
agency in `examples/data/` and prints the report you should expect. The
equivalent command is below; to run it on your own exports, replace each
`examples/data/` path with wherever you saved the five CSVs.

```bash
python3 scripts/track_scope.py \
  --contracts examples/data/contracts.csv \
  --scope examples/data/scope.csv \
  --time-entries examples/data/time_entries.csv \
  --roster examples/data/roster.csv \
  --deliverables examples/data/deliverables.csv \
  --month 2026-09 \
  --as-of 2026-10-05
```

- `--as-of` is required and is used only for renewal timing (how long until each
  contract renews, against `--lead-days`, default 45).
- `--target-margin` (default 55) is the delivery-margin bar. Set it to the
  agency's actual target; it drives both the MARGIN flag and the proposed fee.
- `--over-tolerance` (default 10) and `--under-tolerance` (default 15) are the
  percentages of hours variance that trigger SCOPE CREEP and UNDER-DELIVERED.
- `--rate-drop` (default 15) is how far the effective rate may fall below the
  contracted rate before the RATE flag fires.
- `--round-to` (default 100) rounds proposed fees up to a sane number.
- `--json` for machine output.

## Reading and presenting the output

- The **portfolio table** is the internal view. It contains cost and margin per
  client and must not be sent to a client.
- **Scope variance detail** is the evidence. The deliverable table for a single
  client is the right attachment for an internal renewal brief, with the cost
  column removed.
- **Clients to renegotiate** gives two levers per client and says which one is
  sufficient. Lever 1 holds scope at the contracted hours and shows the margin
  that would result; lever 2 reprices at what is actually being delivered. When
  lever 1 alone clears the target, the problem is delivery discipline, not
  price — lead with that internally before proposing an increase.
- **Clients to re-engage** matters as much as the creep list. A client paying
  for hours that were never used is a churn risk who currently looks profitable.
- Keep the **Method and caveats** section attached to any internal circulation
  so the margin figure is not mistaken for net profit.

## Limits

- Delivery margin only: logged hours at internal cost. It excludes overhead,
  software, freelancers billed outside the roster, media and other pass-through
  costs, so real account profitability is lower than what this reports.
- It trusts the time log. Unlogged, late-logged or misattributed hours flow
  straight into the wrong client's margin, and the skill cannot detect that.
- One month at a time. There is no trend, no seasonality adjustment, and no
  rollup across months; run it monthly and keep the outputs.
- Proposed fees are arithmetic (`cost ÷ (1 − target margin)`), not commercial
  advice. They ignore competitive position, switching costs, relationship value
  and the client's own budget cycle.
- Deliverable matching is exact string matching on names. Renaming a deliverable
  mid-month reads as out-of-scope work.
- Single currency, no allocation of shared or non-client internal time.