The GM operating-rhythm skill for a small company run from Google Docs/Sheets. Reads the source-of-record chain in precedence order (strategy alignment section → H2 project tracker (status SOR) → the ops team's weekly log → OKR & KPI tracker → per-function progress sheets), derives per-item state (ends-soon · overdue · undated · propose-done · direction-unlabelled), and produces a fixed-shape WEEKLY GM BRIEF: runway line first, the ≤3 things only the GM can unblock, two clocks, P0/P1 status b...
Scanned 9/19/2026
Install to Claude Code
npx -y skills add peter-tu-zynkr/zynkr-skill-builder --skill zynkr-gm --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Zynkr Gm?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/peter-tu-zynkr-zynkr-gm)More formats (shields.io, HTML) on the badges page.
---
name: zynkr-gm
sheetId: "0.02"
description: >-
The GM operating-rhythm skill for a small company run from Google Docs/Sheets. Reads the
source-of-record chain in precedence order (strategy alignment section → H2 project tracker
(status SOR) → the ops team's weekly log → OKR & KPI tracker → per-function progress sheets),
derives per-item state (ends-soon · overdue · undated · propose-done · direction-unlabelled),
and produces a fixed-shape WEEKLY GM BRIEF: runway line first, the ≤3 things only the GM can
unblock, two clocks, P0/P1 status by LOB, per-owner rollup, KPI off-target + asks, decisions
register, deliberately-not-this-week, machine health. Delivers as a Gmail draft (interactive)
or an auto-sent email (the Monday cloud routine rendered from this skill). Trigger EAGERLY on
"/zynkr-gm", "zynkr-gm week", "GM 週報", "這週重點", "本週 focus", "本月重點", "what should I
focus on this week", "as a GM what will I do this week", "week focus", "month focus", "GM
brief", "run the GM pass", "哪些 P0 delay 了", "KPI 有沒有 off target", "H2 進度盤點", "幫我盤一下
H2 專案", or any ask for a company-level (not one project's) week/month focus, progress
roll-up, or KPI variance. BOUNDARY — do NOT hijack: /project-status-update (one project's
weekly status email from its own tracker), /consult-status-report and /consult-governance
(consulting portfolio), /admin-governance (file-level Drive↔local index drift),
/admin-meeting-prep (per-meeting packets), /skill-finder (which skill for a task),
/planning-tracker-sync (the TEAM weekly tracker block, nudges and snapshots — it consumes this
skill's derived-state rules, but the founder brief stays here), the rest of the planning suite
0.03-0.10 (a planning CYCLE: pre-work, offsite synthesis, tracker build, OKR reconcile),
/curate-livestream-transcripts (it produces the notes this skill only health-checks). This
skill reads broadly and writes narrowly: it never edits the tracker, the onboarding master
doc, or another owner's doc.
category: strategy
project: zynkr-gm
platform: claude
status: WIP
author: Peter Tu
input: "Optional sub-command (week | progress [LOB] | send) and an optional 'as of' date; identifiers come from the private config (~/.config/zynkr/gm.json) or the rendered routine prompt."
process: "Anchor on today → load private config → idempotency check → read the SOR chain in precedence order (script-first) → derive per-item state + per-owner rollup → compose the fixed-shape brief, every number cited → draft or send → report."
output: "Weekly GM brief in English as an HTML email: runway · ≤3 decision cards, each with options and a link to the closing cell · two clocks · P0/P1 by LOB · owners · KPI · decisions"
synergy: [admin-governance, project-status-update, consult-governance, skill-finder, curate-livestream-transcripts, admin-meeting-prep, planning-tracker-sync, planning-evidence-pack]
house-style: bound
---
# zynkr-gm
```bash
npx skills add https://github.com/peter-tu-zynkr/zynkr-skill-builder --skill zynkr-gm
```
`zynkr-gm` is the general manager's Monday. It reads the company's source-of-record chain in
the order the knowledge directory says wins (strategy alignment → project tracker → weekly ops
log → OKR/KPI sheet → per-function progress sheets), works out which H2 items are moving,
stuck, undated or about to expire, and turns that into one fixed-shape brief whose first line
is always runway and whose second block is always the ≤3 things only the GM can unblock. It
exists to replace a ~40-tool-call manual read pass, and to be the instrument for "we have no
instrumentation": the KPI dashboard's Actual column, the missing decide-by dates, the P0s
nobody put dates on. It **reads broadly and writes narrowly** — the brief is the only output;
it never edits the tracker, the onboarding master doc, or another owner's document.
---
## Configuration (private — never in this repo)
This repository is public. The skill's method is here; the **identifiers are not**. At
runtime the skill loads `~/.config/zynkr/gm.json` (schema and placeholder values in
`references/config.example.json`; see `references/config.README.md`). The cloud routine gets
the same values baked into its prompt by `scripts/render_routine_prompt.py` from
`references/routine-prompt.tmpl`. If the config file is missing in an interactive run, ask for
it — do not guess IDs and do not proceed with placeholders.
| Config key | Role (see `references/source-map.md`) |
|---|---|
| `google_account` | account for all `google-workspace` MCP calls |
| `recipients[]` | who receives the brief (default: the GM only) |
| `sources.main_tracker` | H2 project tracker sheet + tab — **the status source of record** |
| `sources.ops_weekly` | the ops lead's weekly log doc (newest week on top) — read-only |
| `sources.okr_kpi_tracker` | OKR & KPI tracker (tabs `okrs`, `kpi_dashboard`) — the metrics SOR |
| `sources.ops_heal_tracker` | ops gap-heal action sheet (tabs `fixes`, `decisions`) |
| `sources.course_tracker` | flagship course project tracker (milestone dates only) |
| `sources.finance_ledger` | **the books** — runway · burn · cash-basis revenue. Read-only |
| `sources.vms_v2` · `sources.integrated_refresh` | strategy docs — read the authoritative TOP section only |
| `sources.plan_docs.<lob>` · `sources.eae_readme` | per-function H2 plan docs — Refresh block only, on change |
| `sources.knowledge_directory` · `sources.org_taxonomy` | governance docs (SOR precedence table, DRIs) |
| `sources.livestream_notes_folder` | health-check only: date of the newest weekly note |
| `constraints.*` | runway floor (months), books-stale days, burn cap, **burn window**, Q3/H2 end dates |
| `routine.*` | trigger id, cron, connectors, model, subject prefix — for `render_routine_prompt.py` |
---
## Required reading (before acting)
| File | Read when |
|---|---|
| `references/source-map.md` | Always — what each source is, which section/tab is authoritative, precedence, read policy, cloud vs local availability |
| `references/brief-template.md` | Always — the exact 00–08 anatomy, headings, HTML skeleton, evidence-citation rule |
| `references/derived-state-rules.md` | Always — ENDS_SOON / OVERDUE / UNDATED / PROPOSE_DONE / DIRECTION_UNLABELLED / STALLED, priority weighting |
| `references/kpi-map.md` | When composing block 05 — per-metric class (AUTO/SEMI/HUMAN), where an Actual comes from, cloud availability |
| `references/lob-skills-seed.md` | When a "what's next" needs an instrument — chain order, which skill moves which P0, and the category-0 weekly boundary. **Which skills exist is NOT in this file** — read it from `sources.skills_knowledge_map` (the skills KB Doc), one category section per LOB |
---
## Sub-commands & cadence
| Invocation | What runs | Cadence |
|---|---|---|
| `/zynkr-gm` (no arg) | Monday → `week`; 1st of month → `month` (P2, not yet built) then `week`; otherwise ask which | — |
| `/zynkr-gm week` | full read pass → weekly brief → Gmail **draft** | interactive |
| `/zynkr-gm week send` | same, but **sends** to `recipients` (idempotent per ISO week) | scheduled / explicit |
| `/zynkr-gm progress [LOB]` | Steps 1–4 only, printed in chat; optional LOB filter (`1.0` … `8.0`) | on demand |
| Monday cloud routine | `week send` rendered as a self-contained prompt for the claude.ai routine (Drive + Gmail connectors) | Mon 09:00 local |
`kpi` (writes Actuals), `month` (monthly review + quarter/half escalation) and `learn`
(knowledge-directory curation) are P1–P3 — see Limitations.
---
## Step 1 — Anchor on today and resolve the mode
Determine today's date in `timezone` (default Asia/Taipei). The **ISO week** containing today
is the brief's key (e.g. `2026-W34`); the week window is Monday→Sunday. If the user gave an
"as of" date, use that instead. Resolve the sub-command from the args table above.
Compute the two clocks up front: **cash clock** (runway months, from Step 3.4) and
**calendar clock** (days to `constraints.q3_end` and `constraints.h2_end`, plus any P0/P1
whose 結束 falls within 30 days).
## Step 2 — Load config and check idempotency
1. Read `~/.config/zynkr/gm.json`. Missing → stop and ask for it (interactive) / fail loud
(unattended).
2. Idempotency (only when the mode will **send**): search Gmail
`in:sent newer_than:8d` and read subjects; if one starts with
`routine.subject_prefix` and carries this ISO week's key, report
`This week's GM brief has already been sent — skipping (idempotent).` and stop. Do not
search by CJK subject text —
list recent sent mail and match the prefix + week key yourself.
## Step 3 — Read the source-of-record chain (precedence order, script-first)
Never load a whole large doc into context. Big docs are dumped to a file by the harness when
the tool result exceeds the limit — slice them with the scripts. Read in this order and stop
reading a source once you have what the brief needs.
### 3.0 Resolve link targets first (every run, one call per spreadsheet)
The brief links every source it names (template C1), and a link to a row or cell needs the
tab's numeric `gid`. Before reading values, call `mcp__google-workspace__get_spreadsheet_info`
once per spreadsheet in `sources.*` that the brief will cite — it returns each tab's ID — and
keep a `{spreadsheet → {tab → gid}}` map for the rest of the run. Then a cell link is
`https://docs.google.com/spreadsheets/d/<id>/edit#gid=<gid>&range=<col><row>`.
Track the **row number** alongside every row you keep (sheet rows are 1-indexed and row 1 is
the header, so the first data row is 2), and the **column letter** of any cell the brief will
ask the reader to type into — `決議紀錄` and `狀態` on the decisions tab, `結束` on the tracker.
Without those two facts the brief can only link to a file, which is the weaker fallback.
In the cloud routine the Drive connector does not expose gid: link the file, name the tab and
row in the text, and note the degradation once in block 08.
### 3.1 Tracker — the status source (every run)
`mcp__google-workspace__read_sheet_values` on `sources.main_tracker.id`, range
`<tab>!A1:M200`. Keep rows whose `#` looks like `N.NN` and whose 項目 is non-empty (rows like
`1.0` with an empty 項目 are category headers). Save as JSON rows (keys = header cells) to the
dump dir. Status vocabulary is 未開始 · 進行中 · 放棄 · 完成 · 暫停 (完成 · 暫停 added 2026-08-24).
完成 and 放棄 are **terminal** — exclude them from open-work counts and from owner load; 暫停 keeps
its owner but carries no schedule. 延遲 still does not exist and stays **derived** (Step 4).
### 3.2 What actually happened — the ops weekly log (every run)
`mcp__google-workspace__get_doc_as_markdown` on `sources.ops_weekly.id` with
`include_comments=false`. The result is large and lands in a file → run
`python3 scripts/extract_newest_block.py <file> --blocks 2 --json`. Block 1 = the newest
week; block 2 is only for stall detection. The block has a fixed skeleton (Team update ·
Demand Marketing · AI consulting & Sales · Operation · Knowledge product · AI assistant dev ·
Tech/People/Finance, each with `Metrics` bullets, mostly bare `#` placeholders). Pull: event
list with registration counts, course milestone checklist, anything under `#Team update`.
**Never write to this doc.**
### 3.3 Measures — OKR & KPI tracker (every run)
`read_sheet_values` on `sources.okr_kpi_tracker.id`, tabs `okrs` and `kpi_dashboard`
(the `Initiatives` tab is a stale mirror of the tracker — ignore it). Resolve columns by
header text (`Tracker #`, `Q3 target`, `Q4 target`, `Actual`, and — if present — `As of`,
`Source`). Use `scripts/kpi_locate.py` when you need a specific row.
### 3.4 Function-specific progress sheets (every run)
- `sources.ops_heal_tracker`: tabs `fixes` (修復清單: # · 波次 · 動作 · 嚴重度 · 目標 · 負責人 ·
狀態) and `decisions` (待決事項: # · 事項 · 決策者 · 期限/備註 · 狀態 · 決議紀錄). Open
決策 rows feed block 06.
- `sources.course_tracker`: tab per config; take stage/milestone rows with End dates and
Status only (this skill does **not** produce that project's status email —
/project-status-update does).
- `sources.finance_ledger` (Zynkr Finance Ledger): tab `Monthly Summary` — the books, and the
runway/burn source since 2026-09-13. Readable in **both** environments, so the runway line is no
longer environment-dependent. **Read-only**; never append, and never write into the
`Financial Model` tab's month columns (spilled arrays → `#REF!`).
- Local runs may add CRM (`mcp__zynkr__list_deals`, `list_tasks`) for sales/consulting
evidence. In the cloud routine the CRM is unavailable — the brief marks those lines
`(排程執行無法讀取 · 待本地補)` rather than guessing.
- Runway: computed from the ledger per `references/kpi-map.md` § *How to compute it* — cash =
cumulative `total` at the last closed month (**not** the 富邦 bank balance), burn = mean `net`
over `constraints.burn_window`. The KPI Dashboard's runway/burn `Actual` cells are a **mirror**,
not the source: if they disagree with the ledger, the ledger wins and block 05 asks Peter to
refresh them. ⚠ While `constraints.burn_window` is null the brief prints **both** candidate
numbers and says which ruling would settle it — it never picks one silently. If the ledger
itself cannot be read → **RED · 未計量**.
### 3.5 Strategy + plan docs (only on change)
Use `mcp__google-workspace__search_drive_files` (or file metadata) to get `modifiedTime` for
`sources.vms_v2`, `sources.integrated_refresh`, each `sources.plan_docs.<lob>` and
`sources.eae_readme` (key on the **target** doc IDs, not folder shortcuts). Read a doc only if
it changed within the last 7 days (P0; the P1 `doc-watch` tab replaces this with last-seen
timestamps) — and then read **only** the authoritative section named in `source-map.md`
(the TOP alignment / Refresh block). Otherwise the fixed facts in config (`constraints.*`)
and `references/` are enough. Any change here goes into block 08 as "SOR doc changed".
### 3.6 Machine health + calendar (cheap)
- `sources.livestream_notes_folder`: list files, take the newest `逐字稿_*` date; if older
than 8 days → flag "weekly curation did not run".
- Calendar (local only, if the Calendar API is enabled): this week's events as anchors.
Skip silently in unattended mode.
## Step 4 — Derive state, then roll up
Run `python3 scripts/derive_state.py rows.json --today <YYYY-MM-DD> [--prev prev_rows.json]
--json`. It emits per-item states (ENDS_SOON · OVERDUE · UNDATED · CHANGED · PROPOSE_DONE)
and a per-owner rollup. Apply `references/derived-state-rules.md` for the judgement calls the
script cannot make: DIRECTION_UNLABELLED (a P0 whose direction lacks 已定案/還在摸索),
STALLED (needs two snapshots — mark "not available yet" until P1), and priority weighting
(P0 UNDATED for >2 weeks → escalate into block 01; P2 issues → status table only).
## Step 5 — Compose the brief
Follow `references/brief-template.md` **exactly**, in order:
- **00 Runway line** — always first. Months · burn vs `constraints.burn_cap_ntd_per_month` ·
books as-of. RED if < `runway_floor_months` or as-of older than `books_stale_days`, or if
un-metered.
- **01 ≤3 decisions only the GM can close** — from open decisions past/near their decide-by,
P0s owned by the GM with 結束 ≤14d, and P0 UNDATED >2 weeks. Three at most. Each one is a
**decision card** in the exact shape the template gives: one question ending in `?` · real
options A/B (or the exact value and cell to fill) · the consequence of not deciding · the
single action that closes it, hyperlinked to the cell · where it came from. This block is
the test of whether the brief changes the week — see the template's D1–D5 before writing it.
- **02 Two clocks** — cash clock + calendar clock (Q3/H2 end + P0/P1 ending ≤30d).
- **03 P0/P1 status by LOB** — state · evidence (tracker Δ / weekly-log mention / sheet
activity) · next. Coarse on purpose.
- **04 Per-owner rollup** — for each owner: their P0s · missing dates · asks · last heard
from (newest weekly-log mention). Include a GM-load line (share of P0s held by the GM).
- **05 KPI off-target + asks** — only rows with both a target and an Actual can be
off-target; rows without an Actual are listed as asks to their owner (batch, don't nag).
- **06 Decisions register** — open 決策 rows + strategy-doc open decisions + inferred ones,
each with label (已定案/還在摸索/未標), owner, decide-by (or "無期限"), status.
- **07 Deliberately not this week** — named skips.
- **08 Machine health** — routines that did/didn't fire, SOR docs that changed, sources the
run could not read.
Rules while composing (the template states these in full as C1–C5 and D1–D5 — read them, they
are the difference between a brief that gets acted on and one that gets skimmed):
- **English prose, verbatim source strings.** Write the brief in English. Never translate a
string the reader must match against a source — item names, 狀態 values, tab names, doc
titles, column headers stay in their original script, glossed once in parentheses.
- **Link, don't cite.** Every doc, sheet, tab, row and cell named anywhere in the brief is a
hyperlink to that exact place; the `(來源:… · 讀取於 …)` parenthetical is retired. Show an
as-of date only where it changes the reading (state-driving numbers, stale sources).
- **A decision needs options.** If you cannot state the alternatives, it is research, not a
decision — it does not belong in block 01.
- **Open the source before writing the question.** A decision row's own shorthand is not a
summary; resolve it to the real choice, or report under C5 that it could not be resolved.
- **A dead reference is a finding.** A `[N.N]` code or `§` section that resolves to no real
document goes to block 08 as a dead reference — never passed through as though it were an
address.
- Never restate numbers from narrative docs; never invent a HUMAN metric; when a source could
not be read, say so in 08 instead of filling in.
- Respect the word budgets. If block 03 is over, it is carrying prose that belongs nowhere.
## Step 6 — Deliver
Render the brief as an HTML email with **all CSS inline** (Gmail strips `<style>`), using the
skeleton and palette notes in `references/brief-template.md`. Subject:
`<routine.subject_prefix><YYYY-MM-DD> (W<ww>) — <one-line focus>`, the focus clause in plain
English, ≤10 words, naming the thing at stake rather than its code.
The plain-text alternative part carries the 00 line and each 01 card in full (question,
options, close-it action with the raw URL). It is what the reader sees on a watch or in a
preview pane — it must be answerable on its own, never "see the HTML version".
- Interactive `week` → `mcp__google-workspace__draft_gmail_message` to `recipients` (draft,
never send) **and** print the brief in chat.
- `week send` (explicit or scheduled) → send exactly one message to `recipients`; if the
send tool is refused, fall back to a draft and say so in the report.
- `progress` → chat only.
## Step 7 — Report back
One paragraph: ISO week · delivered as draft/sent (+ id) · the 01 list verbatim · counts
(P0 overdue / undated / ends-soon) · anything unreadable. If idempotency skipped the send,
say exactly that.
---
## Unattended / scheduled runs (the Monday routine)
The cloud routine is this skill rendered into one self-contained prompt:
`python3 scripts/render_routine_prompt.py --config ~/.config/zynkr/gm.json
--template references/routine-prompt.tmpl --out <rendered.md>` — then create/update the
claude.ai routine with that prompt (`routine.*` in config: cron, environment, Drive + Gmail
connectors, model). Differences from a local run, by design:
- Reads go through the **Google-Drive connector** (`read_file_content` returns Sheets as
markdown tables and Docs as text; large docs may be truncated — the ops weekly log's newest
week is at the top, so that is safe). The finance ledger IS readable here, so runway is computed
on scheduled runs too. No CRM, no calendar → those lines are marked unavailable, never guessed.
- Delivery is **send** via the Gmail connector (`send_message`); if refused → `create_draft`
and the run report says so. Idempotent per ISO week via the sent-mail check.
- Ask nothing; fail loud (a missing-data brief is worse than a visible failure); one message
max.
- When the skill changes, **re-render and update the routine** — the prompt is derived, not
hand-edited. That is the whole point of the template.
---
## Guardrails
- Never edit the H2 tracker's status, dates or owners — owners push schedules.
- Never write to the onboarding master doc or any shared fact; propose to the GM instead.
- Never write into another owner's doc (the ops weekly log is read-only for this skill).
- Every number cites source + as-of; HUMAN metrics are asked, not invented.
- Precedence is enforced, not debated: strategy alignment section > body; Refresh block >
plan body; tracker > OKR sheet > plan docs. Deprecated paths in the knowledge directory
stay deprecated.
- Read caps: no whole-doc loads; plan docs only on change; target ≲100k tokens per run.
- Unattended: draft-fallback, ask nothing, fail loud, idempotent per ISO week.
## Outputs
- The weekly GM brief (HTML email: draft or sent) — see `references/brief-template.md`.
- In chat: the same brief in markdown, plus the Step 7 report.
- (P1+) rows in the OKR & KPI tracker's `gm-weekly` / `kpi-history` / `decisions` /
`doc-watch` tabs; KPI `Actual` cells for AUTO/SEMI metrics.
## Reference files
- `references/source-map.md` · `references/derived-state-rules.md` ·
`references/brief-template.md` · `references/kpi-map.md` · `references/lob-skills-seed.md`
- `references/routine-prompt.tmpl` · `references/config.example.json` ·
`references/config.README.md`
- `scripts/extract_newest_block.py` · `scripts/derive_state.py` · `scripts/tracker_diff.py`
· `scripts/kpi_locate.py` · `scripts/render_routine_prompt.py` (all stdlib; `--selftest`)
## Limitations (v1 = P0)
- **Read-only.** No KPI cell writes, no state tabs yet → STALLED cannot be computed (needs
two snapshots) and "changed since last week" relies on `--prev` if you saved last week's
rows. P1 adds the tabs and `kpi` writes; P2 adds `month` (+ Q3/H2 checkpoint scoring); P3
adds `learn` (knowledge-directory curation, propose → `--apply` interactive only).
- The tracker's status vocabulary has no 延遲; overdue and undated are inferred from
dates that are often placeholders — the brief makes that visible rather than hiding it.
- Cloud runs cannot see CRM/calendar; those lines say so. (Runway is no longer in that set — the
finance ledger is a Drive Sheet the connector can read.)
- The brief is company-level. One project's status email is `/project-status-update`.
## Self-checks
- Runway line present and first? Un-metered → RED, not blank?
- Block 01 has ≤3 items, each something only the GM can do?
- Every P0 appears in 03 exactly once, with a state?
- Any HUMAN metric invented? (must be none)
- Unattended: exactly one send or one draft; idempotency respected; nothing asked?
**Plain-language check** (the template's closing section, run before delivering — any "no" is a
rewrite, not a note):
- Does every card in 01 ask **one** question, ending in a question mark?
- Could the reader answer each one **without opening another document**?
- Does every card offer real **options** — or name the exact value and the exact cell?
- Is every document, tab, row and cell mentioned anywhere in the brief a **hyperlink**?
- Is there any `[N.N]` code, `§` reference or acronym that is never expanded?
- Is any reference **dead**, and reported in 08 as a finding rather than passed through?
- Is the brief in English, with source strings left verbatim and glossed once?
- Read block 01 aloud: does it sound like a person telling you what they need?
## House style
Writing style is **not owned by this file**. The house voice lives in two Google Docs under
`[@] 寫作指南` (`12DBdFz3SK22ie9im_ThFMI7IBRXsTZsV`), read at runtime:
- 《[2.0] Zynkr 通用風格指南 House Voice》 `10bOIQwRm9Pxwgct4hlwCwK_B4Pipai1HqBPZKzyRHSE` —
the universal core, plus the addendum for this surface
- 《[3.2] 禁用詞清單 Forbidden Words》 `1N5sHLP4qzmmhpCGsi6KElxi1z0MFe4QZ0Q_35T10Uyg`
Read both before producing client- or reader-facing text, and scan the draft against 《[3.2]》
before handing it over. If Drive is unreachable, say so in the output rather than proceeding
unchecked. Never re-implement either list inside this file.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!