← back to Cli Printing Press
fix(skill): add 7 improvements from Cal.com CLI run
bc358ef82ed0c8444306c80017d5737f55b8071a · 2026-03-27 22:19:13 -0700 · Trevin Chow
Lessons learned from the first Cal.com printing-press run:
1. Per-endpoint API versioning (Step 2.7) — some APIs use different
version headers per resource, not one global header
2. Codex file deletion guard — verify target file still exists after
Codex returns, count deletion as immediate failure
3. Config env var validation (Step 2.8) — generator's env var name
must match what Phase 0.1 detected
4. Early smoke test (Step 2.9) — test auth + version header with
live API before investing in Phase 3-4
5. DB path consistency in rename step — grep for old name in
filepath.Join and defaultDBPath calls, not just imports
6. External tool interference warning — linters can change method
signatures mid-session, re-read files before writing dependent code
7. Scorecard limitations documented — known blind spots with
hardcoded filenames and narrow prefix lists
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
M skills/printing-press/SKILL.md
Diff
commit bc358ef82ed0c8444306c80017d5737f55b8071a
Author: Trevin Chow <trevin@trevinchow.com>
Date: Fri Mar 27 22:19:13 2026 -0700
fix(skill): add 7 improvements from Cal.com CLI run
Lessons learned from the first Cal.com printing-press run:
1. Per-endpoint API versioning (Step 2.7) — some APIs use different
version headers per resource, not one global header
2. Codex file deletion guard — verify target file still exists after
Codex returns, count deletion as immediate failure
3. Config env var validation (Step 2.8) — generator's env var name
must match what Phase 0.1 detected
4. Early smoke test (Step 2.9) — test auth + version header with
live API before investing in Phase 3-4
5. DB path consistency in rename step — grep for old name in
filepath.Join and defaultDBPath calls, not just imports
6. External tool interference warning — linters can change method
signatures mid-session, re-read files before writing dependent code
7. Scorecard limitations documented — known blind spots with
hardcoded filenames and narrow prefix lists
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
skills/printing-press/SKILL.md | 61 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 55 insertions(+), 6 deletions(-)
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index 19a3ef37..2f168567 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -176,9 +176,9 @@ VERIFY: After changes, run: go build ./... && go vet ./..."
cd ~/cli-printing-press && echo "$CODEX_PROMPT" | codex exec --yolo -
```
-3. **Claude reviews the diff:** Verify non-empty, in-scope, compiles (`go build && go vet`). If lint/format fails, auto-fix.
+3. **Claude reviews the result:** Before anything else, verify the target file still exists and is non-empty (`wc -l <file>`). Codex can delete or empty files instead of rewriting them — if the file is gone or empty, that's an immediate failure. Then verify: in-scope changes, compiles (`go build && go vet`). If lint/format fails, auto-fix.
-4. **On failure:** Fall back to Claude for that task. Track consecutive failures - after 3, disable Codex for remaining tasks.
+4. **On failure:** Fall back to Claude for that task. A deleted/emptied file counts as a failure. Track consecutive failures — after 3, disable Codex for remaining tasks.
### What Gets Delegated vs What Stays on Claude
@@ -1128,10 +1128,39 @@ The generated client may pin to an outdated API version. Fix it:
grep -n "Version" <api>-pp-cli/internal/client/client.go
```
3. If the API uses date-based version headers (like Notion, Stripe), use the LATEST documented version, not the spec's version field or the generator's template default.
-4. Update the header in client.go.
-5. **Test with the live API** (if token available from Phase 0.1) to confirm the version header is accepted.
+4. **Check for per-endpoint versioning.** Some APIs (e.g., Cal.com) use different version headers per resource — bookings may require `2024-08-13` while event-types requires `2024-06-14`. Test at least 2 different resource endpoints with the same version header. If one returns 404 or errors while the other succeeds, the API uses per-endpoint versioning. Implement routing logic in client.go:
+ ```go
+ apiVersion := "2024-06-14" // default
+ if strings.Contains(path, "/bookings") || strings.Contains(path, "/slots") {
+ apiVersion = "2024-08-13"
+ }
+ req.Header.Set("cal-api-version", apiVersion)
+ ```
+5. Update the header in client.go.
+6. **Test with the live API** (if token available from Phase 0.1) to confirm the version header is accepted on at least 2 different resource types.
+
+**Anti-shortcut:** "The generator's default is fine" - NO. Check it. "One version header works for all endpoints" — maybe not. Test two different resources.
+
+### Step 2.8: Validate Config Env Var Matches Phase 0.1
+
+The generator creates a config.go that looks for a specific env var name (e.g., `CAL_COM_USER_TOKEN`). This may not match the env var detected in Phase 0.1 (e.g., `CAL_COM_API_KEY`). If they don't match, live testing will fail with "auth: not configured" even though the user has the key set.
+
+1. Check what env var name(s) Phase 0.1 detected or the user provided
+2. Check what env var name config.go looks for: `grep "Getenv" <api>-pp-cli/internal/config/config.go`
+3. If they differ: patch config.go to accept both names (check the common one first)
+4. Also add any well-known env var names for this API (e.g., for Cal.com: `CAL_COM_API_KEY`, `CAL_API_KEY`, `CALCOM_API_KEY`)
+
+### Step 2.9: Smoke Test (if API key available)
+
+If an API key was provided in Phase 0.1, run a quick smoke test NOW — don't wait until Phase 5.5. This catches auth and version header issues before investing in Phase 3-4.
-**Anti-shortcut:** "The generator's default is fine" - NO. Check it.
+1. Build the CLI: `go build -o ./<product-name> ./cmd/<product-name>`
+2. Run: `<product-name> doctor --json` — verify auth shows "configured"
+3. Run: `<product-name> me <get-subcommand> --json` or equivalent profile endpoint — verify HTTP 200
+4. Run one list endpoint for a different resource — verify no 404 (catches per-endpoint versioning issues)
+5. If any test fails: fix the issue (version header, env var, base URL) before proceeding
+
+This takes 30 seconds and can save hours of debugging in Phase 4.
### PHASE GATE 2
@@ -1141,6 +1170,8 @@ The generated client may pin to an outdated API version. Fix it:
3. List of skipped complex body fields is saved for Phase 3
4. Module path is correct (Step 2.0b)
5. API version header is current (Step 2.7)
+6. Config env var matches Phase 0.1 detection (Step 2.8)
+7. Smoke test passes if API key available (Step 2.9)
Tell the user: "Phase 2 complete: Generated <api>-pp-cli with [N] resources, [M] endpoints. [K] complex body fields noted for Phase 4. Proceeding to Non-Obvious Insight Review."
@@ -1429,7 +1460,7 @@ For each rename: update the `Use:` field, rename the file, verify `go build` pas
2. Update root.go Use field and version template
3. Update go.mod module path to `github.com/<org>/<product-name>`
4. Update client.go User-Agent header
-5. `grep -r "<old-name>" . | grep -v "Generated by"` must return 0 hits
+5. `grep -r "<old-name>" . | grep -v "Generated by"` must return 0 hits — **pay special attention to DB path strings and config path strings** (e.g., `~/.local/share/<old-name>/data.db`, `~/.config/<old-name>/config.toml`). These are easy to miss and will cause the search/analytics/export commands to use a different database than the sync command. If the old name appears in any `filepath.Join` or `defaultDBPath` call, fix it.
6. Update README examples
**Step 3c: Validate API version header**
@@ -2205,6 +2236,24 @@ You ARE the brain. Read the docs yourself and write the spec.
- Untrusted specs: note if not from known-specs registry
- Max 3 retries on quality gate failure
+## External Tool Interference
+
+Linters, formatters, and pre-commit hooks may modify files during the session. This is expected — but be aware:
+
+- **After any external modification to a file you depend on, re-read it before writing dependent code.** A linter may change method signatures (e.g., `GetSyncState` returning 2 values → 4 values), add imports, rename variables, or restructure functions. Code you write against the pre-linter version will fail to compile.
+- **Check the system-reminder after each tool call.** Claude Code shows diffs from external modifications in system reminders — read them.
+- **If a file was modified by a hook, the hook's version wins.** Don't fight it by reverting to your version. Adapt your dependent code to match the new signatures.
+
+## Scorecard Limitations
+
+The scorecard measures file patterns, not behavior. Known blind spots:
+
+- **sync_correctness** and **data_pipeline_integrity** hardcode the filename `sync.go` — sync logic in other files (e.g., `channel_workflow.go`, `sync_cmd.go`) scores 0.
+- **workflows** and **insight** use narrow prefix lists biased toward project-management APIs — scheduling, payment, and communication workflow commands may not match.
+- **dead_code** produces false positives when flags are passed via struct rather than accessed directly.
+
+**When the scorecard and verify disagree, verify is more authoritative.** A CLI that scores 57/100 on the scorecard but passes 91% of runtime tests is better than one that scores 80/100 but crashes on first use. Report both numbers. Don't chase scorecard points at the expense of actual behavior.
+
## Anti-Shortcut Rules
These phrases indicate a phase was shortcut. If you catch yourself writing them, STOP and re-do the phase:
← e3a07f7b fix(skill): enforce Phase 4.9 agent readiness review dispatc
·
back to Cli Printing Press
·
docs(scorecard): add scoring architecture best-practice guid cf3fcd99 →