Deliverable Pack Check
Find out a piece of the pack is missing three days out, not the morning it ships.
What it does
Reads your DeliverablePack sheet — one row per thing the client is owed — and checks the matching folder:
<DELIVERABLE_ROOT>/<client>/<engagement>/<expected_filename>
Then reports incomplete packs worst-deadline-first, naming each missing deliverable and its owner, flagging anything already late, and finally breaking the whole list down by owner so each person sees exactly their own outstanding pieces.
That last part is the difference between this and a status meeting: a project lead chasing four people for four pieces of one deck gets four lists, not one.
What it does NOT do
It does not open a single file. This is a presence-and-naming check. "Present" means a file with that name exists in that folder — not that it is finished, not that it covers the right period, not that it is this engagement's rather than a copy from the last one.
That boundary is deliberate. A check that claims to verify content and does it badly is worse than one that honestly checks existence, because people stop looking. This tells you what is missing; you still review what is there.
It does not generate a deliverable. It will not build you a deck, fill a template, or apply your branding. Nothing in the Hub does that today, and a workflow that implied otherwise would disappoint on first run.
How this differs from month-end-report-pack
Same idea, different unit of work. month-end-report-pack is keyed on client and period for a recurring monthly close. This one is keyed on client and engagement, which is how consulting work is actually shaped, and adds the per-owner breakdown. Use that one for a bookkeeping book, this one for project work.
Setup
1. Google Sheet
Tab DeliverablePack with this header:
| client | engagement | deliverable | expected_filename | owner | due_date | status |
|---|---|---|---|---|---|---|
- One row per deliverable
clientandengagementmust match the folder names on disk exactlystatus=doneorskipremoves a row from the checkdue_dateinYYYY-MM-DD; the earliest outstanding date drives the ordering and the LATE flag
2. Folder layout
Create <<DELIVERABLE_ROOT>> with one folder per client, then per engagement, readable by the InTouch server. Nothing is written — read access is enough.
3. Credential + contact
Replace the placeholders:
- <<GOOGLE_WORKSPACE_CREDENTIAL>> — Google Workspace credential with Sheets read scope
- <<DELIVERABLES_SHEET_ID>> — the sheet ID from its URL
- <<DELIVERABLE_ROOT>> — the folder root, e.g. /srv/clients/deliverables
- <<PROJECT_LEAD_PUBLISHER>> — who receives the digest
4. Schedule
Daily in the run-up to a delivery date. Weekly the rest of the time.
Customization
- Minimum file size. A zero-byte export is a failed export. Add
os.path.getsize(target) > 0alongsideos.path.isfileincompose. - Per-owner sends. The
by_ownerdict is already built. Filter on one owner and run the workflow once per person to send each their own list instead of the lead getting all of it. - Flat folders. Leave
engagementblank in the sheet and the path collapses to<root>/<client>/— already handled. - Client-visible copy. Point a second run at whatever folder you actually deliver from, to confirm the file reached the client and not just your share.
Source
workflow.iml