Skill 寫法圖鑑

payroll-prep

Anthropic | 商業與營運 | 原文 | Apache-2.0

彙整工時、標出每個薪資異常,排好發薪批次等老闆核准

中文翻譯

---
name: payroll-prep
description: >
  讓薪資在沒人被少付的前提下準備好可以執行:從 Gusto、QuickBooks Payroll
  或上傳的試算表拉出工時表,依人加總正常工時、加班和 PTO 時數,標出找到的
  每一個異常(漏打卡、加班暴增、費率變動、期中到職與離職、偏離排班的工時),
  並把這次發薪排好,讓老闆在任何一塊錢動之前逐行核准。異常一律提出來,
  絕不默默修正。老闆執行之後,傳票會入帳到帳本或交給記帳人員。只要提到
  薪資就該用,例如「run payroll」、「payroll is due」、「check the
  timecards」、「did everyone clock out」、「how many hours did the crew
  put in」、「why is payroll so high this week」、「I need to pay the guys
  Friday」,而且在老闆擔心薪資付不付得出來時,接在 cash-flow-snapshot
  之後使用。
allowed-tools: Read, WebFetch
---

# 薪資準備(Payroll Prep)

在任何人領到錢之前,先把工時弄對。

薪資是財務工作流程裡最容不得出錯的一個。開錯的發票下週可以更正。發錯的薪水,是一個付不出房租的人,也是老闆失去一整組班底最快的方式。這個 skill 裡的一切都是圍繞這種不對稱而建的:機器負責彙整和檢查,老闆負責決定。

## 步驟 1:先把期間定下來,其他都在後面

確認發薪期間的起訖日、發薪日,以及這次發薪包含哪些人。期間弄錯,會讓某人一週的薪水重複或漏掉,而當期間橫跨月底時,這個錯誤出乎意料地容易發生。

名單也要確認:期中到職的新人、任何離職的人、任何請假的人。請見 `reference/timesheet_intake.md`。

## 步驟 2:拉工時表

**連了 Gusto 時**,先問 Gusto 自己有什麼擋在前面:在建立任何東西之前,先呼叫它的 payroll-blockers 檢查(`list_payroll_blockers`)。如果有回傳 blocker,把每一個翻成白話:它是什麼意思、誰來修、在哪裡修。例如:「check payments unsupported」代表這家公司用紙本支票發薪,整合沒辦法排這種,所以老闆要直接在 Gusto 裡執行那部分;「bank account not connected via Plaid」代表老闆要到 Gusto 的設定裡連接銀行;「hourly employees unsupported」即使這次發薪只有月薪制,也可能在帳號層級擋住。blocker 是導向訊號,不是失敗:發薪批次仍然會在這裡建立和驗證,交付物會變成發薪清單,並附上 blocker 清單。

接著拉出這個期間的輸入資料,各從各的工具。**工時:** 對這個發薪期間呼叫 `list_time_records`;先讀它的 `source` 欄位,其他都在後面。`native` 會回傳含上班打卡、下班打卡和休息的班次;`third_party` 會回傳公司工時追蹤夥伴的工時表,`get_time_sheet` 能給任何一份的逐日明細(它會拒絕 native 的班次 id);`none` 代表 Gusto 沒有這家公司的工時,所以由下面的試算表路徑提供。**請假:** 對該期間呼叫 `list_time_off_requests`,帶 `status: approved`,每一個核准的日子都以 PTO 或病假計薪,絕不算作工作,而待核准的請求是一個旗標,不是一個付薪的日子。**餘額:** `get_time_off_balances`,步驟 4 的「PTO 超過可用餘額」檢查就是拿它來讀。**費率與分類:** 從 `list_employees` 取得名單,附每個人的薪資設定(compensations)。費率來自 Gusto,絕不來自工時表。這些的呼叫格式在 `../../shared/connector-call-shapes.md`。

**老闆可以補的漏打卡。** 當步驟 4 標出一個沒有下班打卡的班次,而老闆給了真正的時間,`record_time` 會把它們寫進去:只寫老闆說的時間,先給他們看過,而且是對既有班次做 `update`,不是再新增一筆。缺少就會被拒絕的參數(時區、Gusto 自己追蹤的工作(job)、哪個 id 算是這個班次),以及一個重讀陷阱(外包人員已確認的工時回傳時打卡時間是空白的,不要再寫一次),都在 `../../shared/connector-call-shapes.md` 的 `record_time` 那一列。呼叫之前先讀那一列。這是這個 skill 唯一會改動打卡的方式;假設的時間絕不寫入。

**然後在排任何東西之前,先證明來源有回傳資料。** 拉名單(`list_employees`)和排程(`list_pay_schedules`)。如果一家公司回報有人數,但其中任一份清單回傳是空的,或 blockers 呼叫出錯而不是回答,那就是一個已連接但沒有交付資料的薪資來源。停下排程路徑,用一行話說明(「Gusto is connected but returned no employees or pay schedules, so I cannot stage a run against it」),並提議下面的試算表路徑。絕對不要用空名單建立發薪批次,也絕對不要把連線狀態的綠色標示當成資料存在的證明。

**連了 QuickBooks Payroll 時**,從那裡拉同樣的欄位。這裡有兩種不同的失敗看起來很像,而老闆聽到的意思也不同。**空的來源**(Gusto 的清單在一家回報有人數的公司上沒回傳任何列)是資料缺口:說明這點,並使用發薪清單。**自相矛盾的來源**是工具缺陷:`qbo_payroll_get_company_payroll_readiness` 回答 `has_employees: false` 和 `run_payroll_ready: false`,同一家公司的 `qbo_payroll_get_employees` 卻回傳 `total_count` 為 50,兩者不可能同時為真。這跟公司有多少資料無關。發生這種情況時,名單用員工清單(那是真的回傳了列的呼叫),readiness 說還沒就緒時就不要排發薪批次,並且用一行話把兩個數字都告訴老闆,讓矛盾有紀錄,而不是藏在「not ready」後面。然後用那份名單走下面的試算表路徑:一份驗證過、由老闆自己鍵入 QuickBooks Payroll 的發薪清單就是成果,跟空的來源一樣。這是一級來源,不是備援。它帶有完整的員工名單,含薪資類型、費率和頻率、在職狀態、PTO 政策餘額;發薪排程和其頻率;以及最近一次完成的發薪,含每位員工的毛薪、工時和稅額明細。當工時來自工時表時,紀錄會註明,這正是步驟 4 的異常檢查所需要的。

這個來源有兩點特別要注意。員工有一個獨立於 active 旗標之外的在職狀態,所以被標為 active 的人仍然可能不在薪資名單上,或在帶薪假中;把任何人放進發薪批次之前,兩個都要讀。另外,一位員工可以持有十幾個以上的薪資費率,大多數的工時是零,所以要從真正有工時的那個費率加總,不要從列出的第一個費率。

**兩者都沒有時**,就接受上傳的試算表或 CSV。這是完整支援的路徑:一份驗證過、由老闆鍵入他們薪資供應商的發薪清單就是完整的成果。許多小型班底仍然靠週末拍照的紙本工時表運作,這樣也行。

正規化成每人每天一列:日期、上班、下班、休息、正常工時、加班工時、PTO,以及如果企業會把人工歸到工作(job)上,就加上工作或 class。

## 步驟 3:加總工時

計算每個人、再每個班組、再整批的正常、加班、雙倍薪資、PTO、假日和無薪時間。

加班規則依州別和企業如何分類人員而不同,弄錯會讓某人被少付。使用老闆說的規則,沒有的話,就用單純的每週加班預設值,並說明你套用的是哪一條。`reference/anomaly_rules.md` 涵蓋了計算上的邊界情況:週中費率變動、一天多個工作,以及跨越午夜的班次。

**絕對不要用假設的時間填補漏掉的打卡。** 有上班打卡沒有下班打卡的班次,工時是未知的,回報的就是未知的工時。

## 步驟 4:標出每一個異常

這是這個 skill 的核心。執行 `reference/anomaly_rules.md` 裡的完整檢查,並把它找到的一切都呈現出來,每一項都附上人名、日期,以及具體看起來哪裡不對:

- 漏打卡和沒有下班打卡的班次
- 超過這個人一般模式的加班,兩個數字都要附
- 平常有上班的人工時為零
- 工時遠高於排班預期
- 自上次發薪以來的費率變動
- 重複或重疊的紀錄
- 請假超過可用餘額
- 上一期有領錢、這一期卻不見的人
- 出現一位沒有到職紀錄的新人

**旗標交給老闆。絕不默默修正。** 漏打卡有一個只有員工和老闆知道的真實答案,在中間插入一個合理的猜測,會變成報表上看起來正確的錯誤薪水。

## 步驟 5:核准之前先展示發薪批次

呈現發薪清單:逐人列出,依類型分工時,毛薪,以及附在其所屬那個人身上的每一個旗標。然後是總計:總工時、總毛薪、雇主稅和提撥(如果有的話)、需要的現金總額,以及發薪日。

跟前一期比較,並解釋任何超過 10% 的變動。一份跳了 USD 4,000 的薪資是有原因的,老闆應該從這個 skill 聽到,而不是在銀行餘額裡才發現。

如果有現金資料,說明這個批次付不付得出來。如果沒有,就明白說出來,不要暗示沒問題。

## 步驟 6:一次解決一個旗標

帶老闆逐一走過每個旗標。每一個:找到了什麼、如果維持原樣會是什麼意思、他們想怎麼處理。記錄答案並套用。

不要把旗標合併成一個「看起來沒問題嗎?」的問題。每一個都是某個人的薪水。

## 步驟 7:核准關卡

**老闆明確核准這個發薪批次之前,什麼都不准排。**

詢問之前先說清楚:人數、總工時、總毛薪、會離開帳戶的現金總額、發薪日,以及他們選擇留著未處理的旗標數量。

然後再問。想跳過這道關卡的老闆,應該被告知一次,而且不要說教:這道關卡會留著,因為錯誤的發薪批次在直接存款入帳之後就收不回來了。

連了 Gusto 時,排發薪批次的方式:用 `list_payrolls` 找出未處理的薪資,篩選 `processing_statuses: unprocessed`,`end_date` 設在幾週之後(它的日期篩選是針對發薪期間,光禿禿的呼叫可能漏掉還沒結束的期間),取支票日最近的那一個,用 `get_payroll` 讀取,然後用 `update_payroll` 寫入核准的工時、PTO 和任何獎金明細。兩種格式很重要,都在 `../../shared/connector-call-shapes.md`:值是**取代**而不是相加,所以「給 Maria 再多五小時」意思是送出她新的總數,並先以「40 → 45」的形式給老闆看;而名單還沒生成的薪資批次,要先呼叫一次空的 `update_payroll` 來填入名單,才能做真正的那一次。不要碰 `run_payroll`,那是老闆在 Gusto 裡的按鈕。連了 QuickBooks Payroll 時,connector 只有讀取(名單、費率、排程、readiness、最近一次發薪),沒有排發薪批次的寫入,所以那邊的成果是驗證過、由老闆鍵入的發薪清單;這是 connector 目前擁有的,不是比較差的路徑。**由老闆送出**,無論在哪個系統。兩者都沒有時,產出驗證過的發薪清單供手動輸入。如果步驟 2 的 Gusto blocker 讓透過連線排程做不到,成果就是驗證過的發薪清單加上白話的 blocker 清單,直接說明,不要當成失敗。

## 步驟 8:同步到帳務

發薪批次送出之後,把傳票入帳到帳本:毛薪、雇主稅,以及任何歸到工作(job)上的人工。測試的是能力,不是 logo:已連接的帳本如果它的 connector 沒有傳票寫入路徑,就無法接受入帳,所以用一行話說明,並把平衡的分錄交給老闆或記帳人員鍵入,這是完整的成果,不是失敗。確認金額跟實際執行的相符,不是跟提案的相符,只要老闆在最後一步改過什麼,兩者就會不同。

## 不要做的事

- **不要猜打卡、費率或分類。** 未知的工時要連同人名和日期一起點名。
- **不要默默修正異常**,即使看起來很明顯也一樣。老闆可能知道你不知道的事。
- **不要送出薪資。** 排好它;由老闆送出。這個 skill 絕不呼叫 `run_payroll`。這對 QuickBooks Payroll 跟對 Gusto 完全一樣:連了薪資系統不代表有權限執行薪資。
- **不要把差額送給 `update_payroll`。** 它的值是取代。從 `get_payroll` 算出新的總數,兩個數字都顯示,送出總數。
- **不要寫入老闆沒說過的打卡。** `record_time` 只帶老闆給的時間,而且只在他們看過那筆紀錄之後。
- **讀薪資費率時,不要不去核對對應的工時。** 在 QuickBooks Payroll 裡,一個人可以帶有很多費率,其中大多數工時為零。
- **不要把旗標埋在摘要裡。** 把每一個都附在它影響的那個人身上。
- **不要批次檢視旗標。** 每個人每個問題一個決定。
- **不要把缺少 connector 當成阻礙。** 試算表進、驗證過的發薪清單出,是設計好的路徑。
- **不要略過跟前一期的比較。** 沒有解釋的大幅變動,是手邊最有用的警告。
- **不要用一個回報有員工卻沒回傳任何員工的薪資來源去排發薪批次。** 已連接的標示不是資料。要說明來源沒有交付資料,並改走試算表路徑。
- **不要在發薪清單、聊天或任何渲染的頁面中重現員工的 SSN、生日、住家地址,或銀行或信用卡號碼。** Gusto 和 QuickBooks Payroll 的 payload 都帶有這些;要略過去讀(`../../shared/personal-data.md`)。

## 輸出

**依老闆儲存的輸出偏好交付驗證過的發薪清單,絕對不要預設產出 markdown 檔。** 檢查 `## Business context` 區塊裡的 `Output preference`(共用風格指南規則,`../../shared/artifact-style.md`):

- **視覺化 artifact(預設):** 用 house style 把發薪清單渲染成 HTML 頁面,人數、總毛薪和離開帳戶的現金做成數字卡片(stat tile),每個人一列,工時和薪資用 tabular-nums,每個旗標都附在所屬那個人身上,並帶一個標籤。Gusto 回報 blocker 時,blocker 有自己的白話面板。
- **docx / md / notion / canva 偏好:** 用該格式交付同樣的內容:DOCX 或 markdown 檔、透過 connector 建立的 Notion 頁面(指定目的地,絕不覆寫),或透過 Canva connector 建立的 Canva Doc(每次執行都建新設計,用日期命名;表格改成清單);如果 Notion 或 Canva 沒連,就退回視覺化 artifact,並說明這就是原因。
- **Best for skill:** 用視覺化 artifact,因為這份輸出是老闆逐人核准的清單。

## 執行之後

發薪批次已排好,旗標已解決,帳務分錄已入帳。如果一開始擔心的是現金,很自然的下一步是「can I make payroll」,`/plan-payroll` 會在下一次發薪之前先跑預測和催收發票。附近還有:「cash forecast」(`cash-flow-snapshot`)看這個批次對接下來 30 天的影響,以及季度預估稅或 1099 快到期時的「taxes」(`/tax-prep`)。最多提議三個,而且這個 session 裡老闆已經拒絕過的提議就跳過。

## Reference 檔案

- `reference/timesheet_intake.md`:Gusto 拉取、試算表上傳、名單和期間設定
- `reference/anomaly_rules.md`:每一項檢查、它的門檻,以及怎麼措辭
- `reference/run_sheet_format.md`:發薪清單版面和總計區塊
- `reference/books_sync.md`:傳票結構和工作成本分攤
- `reference/gotchas.md`:會讓人被少付或讓某個期間被重複付款的錯誤

## 使用沒列出來的工具

這個 skill 裡提到的 connector 是測試過的路徑,不是一道牆。如果老闆想讓這個流程用沒連接或沒列出來的工具,就提議 `build-connector`:它會先查 connector 目錄,找不到才透過 Zapier 連接,絕不直接對原始 API 手刻。連線建立之後,這個工具就像任何其他選用的 connector 一樣加入這個 skill,並遵守同樣的核准關卡。

英文原文

---
name: payroll-prep
description: >
  Gets payroll ready to run without anyone getting shorted: pulls timesheets
  from Gusto, QuickBooks Payroll, or an uploaded spreadsheet, totals regular,
  overtime, and PTO
  hours by person, flags every anomaly it finds — missed punches, overtime
  spikes, rate changes, mid-period hires and terminations, hours off the
  schedule — and stages the run for the owner to approve line by line before
  a dollar moves. Anomalies are always raised, never quietly corrected. Once
  the owner runs it, the journal posts to the ledger or goes to the
  bookkeeper. Reach for this whenever payroll comes up at all
  — "run payroll," "payroll is due," "check the timecards," "did everyone
  clock out," "how many hours did the crew put in," "why is payroll so high
  this week," "I need to pay the guys Friday" — and use it after
  cash-flow-snapshot when the owner is worried about whether payroll clears.
allowed-tools: Read, WebFetch
---

# Payroll Prep

Get the hours right before anyone gets paid.

Payroll is the finance workflow with the least room for error. A wrong invoice gets corrected next week. A wrong paycheck is a person who cannot cover rent, and it is the fastest way for an owner to lose a crew. Everything in this skill is built around that asymmetry: the machine assembles and checks, the owner decides.

## Step 1 — Fix the period before anything else

Confirm the pay period start and end dates, the pay date, and who is in this run. Getting the period wrong duplicates or skips a week of someone's pay, and it is a surprisingly easy mistake when a period straddles a month end.

Confirm the roster too: new hires who started mid-period, anyone terminated, anyone on leave. See `reference/timesheet_intake.md`.

## Step 2 — Pull the timesheets

**With Gusto connected**, first ask Gusto itself what stands in the way: call its payroll-blockers check (`list_payroll_blockers`) before building anything. If blockers come back, translate each into plain English — what it means, who fixes it, and where. For example: "check payments unsupported" means this company pays by paper check, which the integration cannot stage, so the owner runs that part in Gusto directly; "bank account not connected via Plaid" means the owner connects the bank in Gusto's settings; "hourly employees unsupported" can block at the account level even when this run is salaried-only. Blockers are a routing signal, not a failure — the run still gets built and validated here, and the deliverable becomes the run sheet with the blocker list riding along.

Then pull the period's inputs, each from its own tool. **Hours:** `list_time_records` for the pay period; read its `source` field before anything else. `native` returns shifts with clock-in, clock-out, and breaks; `third_party` returns timesheets from the company's time-tracking partner, and `get_time_sheet` gives the per-day line items for any one of them (it refuses native shift ids); `none` means Gusto holds no hours for this company, so the spreadsheet path below supplies them. **Leave:** `list_time_off_requests` for the period with `status: approved` — every approved day is paid as PTO or sick, never as worked, and a pending request is a flag, not a paid day. **Balances:** `get_time_off_balances`, which is what the "PTO beyond available balance" check in Step 4 reads against. **Rates and classifications:** the roster from `list_employees` with each person's compensations. Rates come from Gusto, never from a timesheet. Call shapes for these are in `../../shared/connector-call-shapes.md`.

**A missing punch the owner can fill.** When Step 4 flags a shift with no clock-out and the owner gives the real times, `record_time` writes them — only the times the owner stated, shown to them first, and as an `update` of the existing shift rather than a second entry. The parameters that refuse if missing (timezone, job on Gusto's own tracking, which id counts as the shift) and the one re-read trap (a contractor's confirmed hours come back with blank clock times; do not write again) are in the `record_time` row of `../../shared/connector-call-shapes.md`. Read that row before the call. This is the only way the skill ever changes a punch; an assumed time is never written.

**Then prove the source is returning its data before anything is staged.** Pull the roster (`list_employees`) and the schedules (`list_pay_schedules`). A company that reports a headcount while either list comes back empty, or a blockers call that errors instead of answering, is a payroll source that is connected but not delivering. Stop the staging path, say so in one line ("Gusto is connected but returned no employees or pay schedules, so I cannot stage a run against it"), and offer the spreadsheet path below. Never build a run from an empty roster, and never treat a green connection badge as proof the data is there.

**With QuickBooks Payroll connected**, pull the same fields from there. Two different failures look alike here, and the owner hears them differently. An **empty source** (Gusto's lists come back with no rows on a company that reports a headcount) is a data gap: say so and use the run sheet. A **self-contradicting source** is a tool defect: `qbo_payroll_get_company_payroll_readiness` answering `has_employees: false` and `run_payroll_ready: false` while `qbo_payroll_get_employees` on the same company returns a `total_count` of 50 cannot both be true. This is independent of how much data the company has. When that happens, use the employee list for the roster (it is the call that returned rows), do not stage a run while readiness says not ready, and say both numbers to the owner in one line so the contradiction is on record rather than hidden behind "not ready." Then take the spreadsheet path below with that roster: a validated run sheet the owner keys into QuickBooks Payroll is the outcome, the same as for an empty source. This is a first-class source, not a fallback. It carries the full employee roster with pay type, rate and frequency, employment status, and PTO policy balances; the pay schedule and its frequency; and the last completed run with per-employee gross pay, hours, and the tax lines. Where hours came from a timesheet the record says so, which is what the anomaly checks in Step 4 need.

Two cautions specific to this source. Employees carry an employment status separate from an active flag, so someone marked active can still be not-on-payroll or on paid leave; read both before putting anyone in the run. And a single employee can hold a dozen or more pay rates, most sitting at zero hours, so total from the rate that actually has hours against it rather than the first rate listed.

**Without either**, take an uploaded spreadsheet or CSV. This is a fully supported path — a validated run sheet the owner keys into their payroll provider is a complete outcome. Many small crews still run on a paper timesheet photographed at the end of the week, and that works too.

Normalize into one row per person per day: date, in, out, break, regular hours, overtime hours, PTO, and the job or class if the business tracks labor to jobs.

## Step 3 — Total the hours

Compute regular, overtime, double time, PTO, holiday, and unpaid time per person, then per crew, then for the run.

Overtime rules vary by state and by how the business classifies people, and getting them wrong underpays someone. Use the owner's stated rule, and when there isn't one, use the plain weekly-overtime default and say which rule you applied. `reference/anomaly_rules.md` covers the calculation edges — mid-week rate changes, multi-job days, and shifts crossing midnight.

**Never fill a missing punch with an assumed time.** A shift with a clock-in and no clock-out has unknown hours, and unknown hours is what gets reported.

## Step 4 — Flag every anomaly

This is the core of the skill. Run the full check in `reference/anomaly_rules.md` and surface everything it finds, each with the person's name, the date, and what specifically looks wrong:

- Missing punches and shifts with no clock-out
- Overtime above this person's normal pattern, with both numbers
- Zero hours for someone who normally works
- Hours well above what the schedule called for
- Rate changes since the last run
- Duplicate or overlapping entries
- PTO taken beyond the available balance
- Someone paid last period who is missing from this one
- A new person appearing with no hire record

**Flags go to the owner. They never get silently corrected.** A missed punch has a real answer that only the employee and the owner know, and a plausible guess in the middle of that becomes a wrong paycheck that looks correct on the report.

## Step 5 — Show the run before approving it

Present the run sheet: person by person, hours by type, gross pay, and every flag attached to the person it belongs to. Then the totals — total hours, total gross, employer taxes and contributions if available, total cash needed, and the pay date.

Compare against the prior period and explain any move over 10%. A payroll that jumped USD 4,000 has a reason, and the owner should hear it from this skill rather than find it in the bank balance.

If cash data is available, say whether the run clears. If it is not available, say that plainly instead of implying it is fine.

## Step 6 — Resolve the flags, one at a time

Walk the owner through each flag. For each: what was found, what it would mean if left as is, and what they want done. Record the answer and apply it.

Do not batch flags into a single "looks good?" question. Each one is a person's pay.

## Step 7 — The approval gate

**Nothing stages until the owner explicitly approves the run.**

State plainly before asking: number of people, total hours, total gross, total cash leaving the account, the pay date, and the count of any flags they chose to leave open.

Then ask. An owner who wants to skip this gate should be told, once and without lecturing, that it stays because a wrong run is not something they can take back after direct deposit lands.

With Gusto connected, stage the run: find the unprocessed payroll with `list_payrolls` filtered to `processing_statuses: unprocessed` and an `end_date` a few weeks ahead (its date filter is on the pay period, and a bare call can miss a period that has not ended yet), take the one with the nearest check date, read it with `get_payroll`, then write the approved hours, PTO, and any bonus lines with `update_payroll`. Two shapes matter and both are in `../../shared/connector-call-shapes.md`: values **replace** rather than add, so "give Maria five more hours" means sending her new total, shown to the owner as "40 → 45" first; and a payroll whose roster is not yet materialized takes one empty `update_payroll` call to populate it before the real one. Leave `run_payroll` alone — that is the owner's button, in Gusto. With QuickBooks Payroll connected, the connector holds the reads (roster, rates, schedules, readiness, last run) and no run-staging write, so the outcome there is the validated run sheet the owner keys in; that is what the connector holds today, not a lesser path. **The owner submits it** in either system. With neither, produce the validated run sheet for manual entry. If Gusto's blockers from Step 2 prevent staging through the connection, the validated run sheet plus the plain-English blocker list is the outcome — say so without treating it as a failure.

## Step 8 — Sync to the books

After the run is submitted, post the journal entry to the ledger: gross wages, employer taxes, and any labor allocated to jobs. Test the capability, not the logo: a connected ledger whose connector has no journal-write path cannot take the post, so say so in one line and hand the balanced entry to the owner or bookkeeper to key in — a complete outcome, not a failure. Confirm the amounts match what actually ran, not what was proposed — those differ whenever the owner edited something at the last step.

## What not to do

- **Do not guess a punch, a rate, or a classification.** Unknown hours get named with the person and the date.
- **Do not correct an anomaly silently,** even an obvious-looking one. The owner may know something you do not.
- **Do not submit payroll.** Stage it; the owner submits. `run_payroll` is never called by this skill. This holds for QuickBooks Payroll exactly as it holds for Gusto — a connected payroll system is not permission to run payroll.
- **Do not send a delta to `update_payroll`.** Its values replace. Compute the new total from `get_payroll`, show both numbers, send the total.
- **Do not write a punch the owner did not state.** `record_time` carries only times the owner gave, and only after they saw the entry.
- **Do not read a pay rate without checking the hours against it.** In QuickBooks Payroll one person can carry many rates with zero hours on most of them.
- **Do not bury flags in a summary.** Attach each one to the person it affects.
- **Do not batch the flag review.** One decision per person per issue.
- **Do not treat a missing connector as a blocker.** A spreadsheet in, a validated run sheet out, is a designed path.
- **Do not skip the prior-period comparison.** A large move with no explanation is the most useful warning available.
- **Do not stage a run from a payroll source that reports employees but returns none.** A connected badge is not data. Say the source is not delivering, and use the spreadsheet path.
- **Do not reproduce an employee's SSN, date of birth, home address, or bank or card number** in the run sheet, the chat, or any rendered page. Gusto and QuickBooks Payroll payloads carry them; read past them (`../../shared/personal-data.md`).

## Output

**Deliver the validated run sheet per the owner's stored output preference — never default to a markdown file.** Check the `## Business context` block's `Output preference` (shared style guide rule, `../../shared/artifact-style.md`):

- **Visual artifact (the default):** render the run sheet as an HTML page in the house style — headcount, total gross, and cash leaving the account as stat tiles, each person a row with hours and pay in tabular-nums, and a pill on every flag attached to the person it belongs to. Blockers, when Gusto reports them, get their own plain-English panel.
- **docx / md / notion / canva preference:** deliver the same content in that form — a DOCX or markdown file, a Notion page created via the connector (named destination, never overwriting), or a Canva Doc created via the Canva connector (a new design each run, named with the date; tables become lists); fall back to the visual artifact if Notion or Canva is not connected — and say that is why.
- **Best for skill:** use the visual artifact — this output is a sheet the owner approves person by person.

## After the run

The run is staged, the flags are resolved, and the books entry is posted. If cash was the worry going in, the natural next step is "can I make payroll" — `/plan-payroll` runs the forecast and the invoice chase in front of the next run. Also nearby: "cash forecast" (`cash-flow-snapshot`) to see what this run does to the next 30 days, and "taxes" (`/tax-prep`) when quarterly estimates or 1099s are coming due. Offer at most three, and skip any offer the owner already declined this session.

## Reference files

- `reference/timesheet_intake.md` — Gusto pull, spreadsheet upload, roster and period setup
- `reference/anomaly_rules.md` — every check, its threshold, and how it is worded
- `reference/run_sheet_format.md` — the run sheet layout and the totals block
- `reference/books_sync.md` — journal entry structure and job-cost allocation
- `reference/gotchas.md` — the mistakes that shortchange a person or double-pay a period

## Using a tool that isn't listed

The connectors named in this skill are the tested paths, not a wall. If the owner wants this flow to use a tool that isn't connected or listed, offer `build-connector` — it checks the connector directory first and connects through Zapier otherwise, never hand-building against a raw API. Once the connection exists, the tool joins this skill like any other optional connector, under the same approval gates.