← back to Cli Printing Press
fix(cli,skills): manifest display_name preservation + divergence-check exemptions (#390)
401bda54e3059fe89fc55dd2be53541a74a57424 · 2026-04-29 10:55:50 -0700 · Trevin Chow
* fix(cli): mcp-sync no longer propagates stale display_name from .printing-press.json
populateMCPMetadata refused to update m.DisplayName when it was already
set, so once .printing-press.json carried a slug-derived value (e.g.,
"Cal Com" instead of "Cal.com"), every subsequent mcp-sync run would
clobber a hand-fixed manifest.json by reading the stale value back from
.printing-press.json. The upstream chain in mcpsync/sync.go preserves
manifest.json's display_name into parsed.DisplayName before this runs,
so the empty-check is the only thing blocking the chain from working.
Drop the empty-check; always refresh m.DisplayName from
parsed.EffectiveDisplayName(). After this, the workflow is: fix
manifest.json once, then mcp-sync stops reverting it.
TestRefreshCLIManifestFromSpecRefreshesDisplayName pins the contract.
Closes #385
* fix(skills): polish divergence check exempts publish-rewritten paths
The publish step rewrites a CLI's Go module path from <api>-pp-cli to
github.com/mvanhorn/printing-press-library/library/<category>/<api>,
which propagates through go.mod, go.sum, and every .go file's internal
imports. The divergence check's previous exclusion list (build
artifacts, the ledger, the binary) flagged all of these as drift on
every run, drowning out real local edits.
Add go.mod, go.sum to the exclude list. Document that .go file diffs
are expected to show the module-path prefix swap — the agent should
scan for substantive changes beyond the prefix when reading the diff
output.
Don't exclude binary names (<api>-pp-cli, <api>-pp-mcp): those
patterns match both the root-level binary files AND the cmd/ source
directories, so passing them to --exclude silently skips the entire
cmd/ subtree and hides real divergence in main.go. One "Only in local"
line for the built binary is acceptable noise; skipping cmd/ is not.
Closes #387
Files touched
M internal/pipeline/climanifest.goM internal/pipeline/climanifest_test.goM skills/printing-press-polish/SKILL.md
Diff
commit 401bda54e3059fe89fc55dd2be53541a74a57424
Author: Trevin Chow <trevin@trevinchow.com>
Date: Wed Apr 29 10:55:50 2026 -0700
fix(cli,skills): manifest display_name preservation + divergence-check exemptions (#390)
* fix(cli): mcp-sync no longer propagates stale display_name from .printing-press.json
populateMCPMetadata refused to update m.DisplayName when it was already
set, so once .printing-press.json carried a slug-derived value (e.g.,
"Cal Com" instead of "Cal.com"), every subsequent mcp-sync run would
clobber a hand-fixed manifest.json by reading the stale value back from
.printing-press.json. The upstream chain in mcpsync/sync.go preserves
manifest.json's display_name into parsed.DisplayName before this runs,
so the empty-check is the only thing blocking the chain from working.
Drop the empty-check; always refresh m.DisplayName from
parsed.EffectiveDisplayName(). After this, the workflow is: fix
manifest.json once, then mcp-sync stops reverting it.
TestRefreshCLIManifestFromSpecRefreshesDisplayName pins the contract.
Closes #385
* fix(skills): polish divergence check exempts publish-rewritten paths
The publish step rewrites a CLI's Go module path from <api>-pp-cli to
github.com/mvanhorn/printing-press-library/library/<category>/<api>,
which propagates through go.mod, go.sum, and every .go file's internal
imports. The divergence check's previous exclusion list (build
artifacts, the ledger, the binary) flagged all of these as drift on
every run, drowning out real local edits.
Add go.mod, go.sum to the exclude list. Document that .go file diffs
are expected to show the module-path prefix swap — the agent should
scan for substantive changes beyond the prefix when reading the diff
output.
Don't exclude binary names (<api>-pp-cli, <api>-pp-mcp): those
patterns match both the root-level binary files AND the cmd/ source
directories, so passing them to --exclude silently skips the entire
cmd/ subtree and hides real divergence in main.go. One "Only in local"
line for the built binary is acceptable noise; skipping cmd/ is not.
Closes #387
---
internal/pipeline/climanifest.go | 7 ++++---
internal/pipeline/climanifest_test.go | 25 +++++++++++++++++++++++++
skills/printing-press-polish/SKILL.md | 9 ++++++++-
3 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/internal/pipeline/climanifest.go b/internal/pipeline/climanifest.go
index b91da34f..7682439a 100644
--- a/internal/pipeline/climanifest.go
+++ b/internal/pipeline/climanifest.go
@@ -245,9 +245,10 @@ func populateMCPMetadata(m *CLIManifest, parsed *spec.APISpec) {
m.AuthEnvVars = parsed.Auth.EnvVars
m.AuthKeyURL = parsed.Auth.KeyURL
m.AuthOptional = parsed.Auth.Optional
- if m.DisplayName == "" {
- m.DisplayName = parsed.EffectiveDisplayName()
- }
+ // Always refresh from parsed; an empty-check here would let a
+ // stale .printing-press.json overwrite the spec on the next
+ // mcp-sync cycle.
+ m.DisplayName = parsed.EffectiveDisplayName()
}
// GenerateManifestParams holds the information available at generate time
diff --git a/internal/pipeline/climanifest_test.go b/internal/pipeline/climanifest_test.go
index c1f7229e..3a3aa053 100644
--- a/internal/pipeline/climanifest_test.go
+++ b/internal/pipeline/climanifest_test.go
@@ -808,6 +808,31 @@ func TestWriteMCPBManifestPreservesExistingDescription(t *testing.T) {
})
}
+func TestRefreshCLIManifestFromSpecRefreshesDisplayName(t *testing.T) {
+ // RefreshCLIManifestFromSpec must overwrite an existing
+ // DisplayName, not preserve it — otherwise stale slug-derived
+ // values survive across mcp-sync cycles.
+ dir := t.TempDir()
+ writeManifest(t, dir, CLIManifest{
+ APIName: "cal-com",
+ DisplayName: "Cal Com", // stale slug-derived value
+ MCPBinary: "cal-com-pp-mcp",
+ MCPReady: "full",
+ })
+ parsed := &spec.APISpec{
+ Name: "cal-com",
+ DisplayName: "Cal.com", // authoritative value from upstream preservation
+ }
+
+ require.NoError(t, RefreshCLIManifestFromSpec(dir, parsed))
+
+ data, err := os.ReadFile(filepath.Join(dir, CLIManifestFilename))
+ require.NoError(t, err)
+ var got CLIManifest
+ require.NoError(t, json.Unmarshal(data, &got))
+ assert.Equal(t, "Cal.com", got.DisplayName)
+}
+
func writeManifest(t *testing.T, dir string, m CLIManifest) {
t.Helper()
data, err := json.Marshal(m)
diff --git a/skills/printing-press-polish/SKILL.md b/skills/printing-press-polish/SKILL.md
index 9870c948..a751c2b1 100644
--- a/skills/printing-press-polish/SKILL.md
+++ b/skills/printing-press-polish/SKILL.md
@@ -124,7 +124,14 @@ The internal copy at `$CLI_DIR` can drift from the public library (`mvanhorn/pri
1. **Locate the public library clone.** Honor `$PRINTING_PRESS_LIBRARY_PUBLIC` if set; otherwise scan the user's filesystem however fits this platform. Validate every candidate by checking the git remote points at `mvanhorn/printing-press-library` — other directories may share the name (forks, accidental name collisions). If multiple valid clones exist, prefer the most recently modified; ask the user to disambiguate only if still unclear.
2. **Locate this CLI inside the clone.** `find <clone>/library -type d -name "<api>-pp-cli"` or equivalent.
-3. **Run `diff -r <public-cli-dir> $CLI_DIR`** (excluding build artifacts, the `.printing-press-tools-polish.json` ledger, and the binary).
+3. **Run `diff -r <public-cli-dir> $CLI_DIR`** with these exclusions, all of which are expected to diverge after publish:
+ - `.printing-press-tools-polish.json` (local ledger, not published)
+ - `go.mod` and `go.sum` — publish rewrites the module path from `<api>-pp-cli` to `github.com/mvanhorn/printing-press-library/library/<category>/<api>`
+ - All `.go` files where the only difference is the rewritten import path (the publish step propagates the new module path through every internal import). When inspecting `.go` diffs, scan for substantive changes — anything beyond the module-path prefix swap is real divergence.
+
+ Concretely: `diff -r --exclude=go.mod --exclude=go.sum --exclude=.printing-press-tools-polish.json <public-cli-dir> $CLI_DIR`.
+
+ Don't pass `--exclude='<api>-pp-cli'` or `--exclude='<api>-pp-mcp'` — those names match both the root-level binary files **and** the `cmd/<api>-pp-cli/` and `cmd/<api>-pp-mcp/` source directories. Excluding by binary name silently skips the entire `cmd/` subtree, hiding real divergence in `main.go`. The "Only in $CLI_DIR: <api>-pp-cli" line for the built binary is one row of expected output, not noise worth filtering at the cost of completeness.
4. **Surface the result** before continuing.
Outcomes:
← 0320269d feat(cli,skills): polish ledger per-item enforcement + AGENT
·
back to Cli Printing Press
·
feat(cli): mcp-sync reads display_name from public library r 64f67981 →