name: vc-publish description: Use when publishing harness improvements to the remote kit repo. Diffs managed files, shows what changed, bumps version, and pushes. Counterpart to vc-update (pull). trigger_keywords: publish kit, push harness, release kit, update remote layer: contract metadata: author: vibecode version: "3.0.0"
vc-publish
Output style: Follow
process/development-protocols/communication-standards.md— answer-first, plain language, no unexplained jargon, TL;DR on long responses.
Push harness improvements from the current development repo to the remote kit repository (vibecode-pro-max-kit). This is the maintainer counterpart to vc-update.
vc-update= user pulls latest harness INTO their project FROM the remotevc-publish= maintainer pushes improvements FROM the development repo TO the remote kit repo
Prerequisites
- Local checkout of the kit repo (
git clone git@github.com:withkynam/vibecode-pro-max-kit.git) .vc-publish-configfile in the current repo root (see Configuration below)- Git push access to the remote kit repo
Configuration
Create .vc-publish-config in the repo root:
{"kitRepoPath": "/path/to/vibecode-pro-max-kit"}
If this file is missing, ask the user for the kit repo checkout path and offer to create it.
Workflow
Step 1: Load Configuration
- Read
.vc-publish-configfrom the current repo root. - If missing, ask the user for the kit repo local checkout path.
- Verify the path exists and contains
vc-manifest.json. - Verify the kit repo worktree is clean (
git -C <kitRepoPath> status --porcelain). If dirty, warn and ask whether to proceed or abort.
Step 2: Read Manifest
- Read
vc-manifest.jsonfrom the kit repo checkout. - Extract the current
version. - Before computing a version bump, check if the current kit version already matches the intended target version (e.g.
3.0.0). If the kitversionalready equals the target: skip the bump step entirely and proceed directly to Step 3 with atag-as-isnote — do not increment the version. Record in the publish summary that the version was unchanged.
Catalog-regen (pre-publish): Before resolving files in Steps 3–4, regenerate the skills catalog in the dev repo:
node .claude/skills/vc-audit-context/scripts/generate-skills-catalog.mjs --write
This ensures process/context/generated-skills-catalog.json is current before it is copied into the kit repo.
Step 3: Resolve Kit File Set
Run the resolver against the kit repo to get the kit file list:
node <kitRepoPath>/resolve-manifest.mjs --root <kitRepoPath> --jsonExtract
files(kit managed files) andkitOnly(kit-exclusive files).Note:
resolve-manifest.mjsreadsvc-manifest.jsonfrom its--rootdirectory and also scans files from that same root.vc-manifest.jsonis NOT installed into dev/user projects byinstall.sh, so the resolver must always be pointed at the kit repo checkout (which does have it). There is no separate dev-repo resolver call — the dev-side file comparison happens insidecompute-sync-plan.mjsin Step 4.
Step 4: Compute Diff
Computation via
compute-sync-plan.mjs: Use the shared computation core to produce the diff between the dev repo's managed files and the kit repo's current managed files.Direction note:
compute-sync-plan.mjsloadsvc-manifest.jsonfrom--kit-rootand runs the resolver with--root <kit-root>. Sincevc-manifest.jsonlives in the kit repo (not the dev repo),--kit-rootmust always be the kit repo checkout.--rootis the dev repo (the project being compared). This is the same direction as a normal install — vc-publish uses it to see what a fresh install FROM dev INTO the kit would change.# --root = dev repo (the "project" being compared against the kit source) # --kit-root = kit repo (where vc-manifest.json lives; source of truth for file lists) # --resolver overrides the resolver path because compute-sync-plan # would otherwise look for resolve-manifest.mjs inside --kit-root, # which IS the kit repo here, so --resolver is optional but explicit for clarity. node <kitRepoPath>/compute-sync-plan.mjs \ --root <devRepoRoot> \ --kit-root <kitRepoPath> \ --resolver <kitRepoPath>/resolve-manifest.mjs \ --jsonParse the JSON output:
{ toAdd, toModify, toDelete, toPreserve, staleWarnings }.toAdd— files to copy from dev to kit (present in dev, not yet in kit).toModify— files to overwrite in kit (tracked in both, content differs).toDelete— files to remove from kit (no longer in dev managed set).toPreserve— files to leave untouched (merge/copyIfMissing survivors, unchanged files).staleWarnings— paths that failed the namespace guard — print to user; do NOT delete.
The ownedPaths for the publish direction are the dev repo's resolved
ownedPaths. CLAUDE.md and AGENTS.md are always in themergecategory — they require special stripping regardless of diff status (see Step 7).
Step 5: Print Diff Summary
- Print a summary table:
vc-publish diff: current repo -> kit repo (v2.1.0)
================================================
FILES:
[modified] .claude/agents/vc-execute-agent.md (+8 -3)
[modified] .claude/hooks/lib/scout-checker.cjs (+2 -1)
[new] .claude/skills/vc-new-skill/SKILL.md
[merge] CLAUDE.md (needs content review)
[merge] AGENTS.md (needs content review)
[unchanged] .claude/settings.json
... (350 more unchanged)
Total changes: 4 files modified, 1 new, 0 removed
Step 6: STOP -- Confirm Publish
- STOP and ask the user:
- Confirm they want to publish these changes.
- Specify version bump type: patch, minor, or major.
- Optionally provide release notes (1–3 sentences for the GitHub Release body). Leave blank to auto-generate from the diff summary (e.g. "4 modified, 1 new, 0 removed.").
- Or abort.
Version bump semantics:
- Patch (2.1.0 -> 2.1.1): hook fixes, skill doc updates, minor agent prompt tweaks
- Minor (2.1.0 -> 2.2.0): new skills, new agents, new development protocols
- Major (2.1.0 -> 3.0.0): CLAUDE.md structure changes, manifest schema changes, breaking workflow changes
Step 7: Apply Changes
- On confirm:
Copy all modified and new managed files from current repo to kit repo checkout.
For each removed file: delete it from the kit repo checkout.
CLAUDE.md and AGENTS.md stripping: Do NOT copy the current repo's project-specific versions directly. Instead:
- Read the current repo's CLAUDE.md/AGENTS.md.
- Read the kit repo's existing harness-only version as base.
- Apply only methodology/structural changes from the dev repo to the kit's harness-only version.
- Strip all project-specific content:
- Technology stack details (frameworks, databases, versions)
- Feature list / "Current features" entries
- Project-specific context groups
- Hardcoded package manager (replace with generic)
- MCP server instructions (project-specific config)
- Project-specific routing rules
- Absolute paths (
/Users/...) - Product name references (the project's product name and repo/directory name)
- Verify the result is harness-only methodology with no project leaks.
Manifest reconciliation (
vc-manifest.json) — the manifest is NOT a normally-copied managed file (it is dev-only on one side and kit-resolved on the other), so its fields do NOT auto-sync. Handle it explicitly:version: bump per the chosen bump type. Kit-authoritative.legacyDeletions(the deprecation ledger): dev is authoritative and always the superset. Whenever dev removes a skill/dir/file from the harness it appends the path here so downstream projects clean it up on their nextvc-update. Setkit.legacyDeletions = dev.legacyDeletions(preserve dev order). This field is a literal path array, NOT a glob — it genuinely changes every time the harness deprecates something, so it MUST be reconciled at every publish. (Historically this was skipped, which silently stranded the kit with stale deletions — never skip it.)- All OTHER non-version fields (
include,exclude,strip,merge,copyIfMissing,symlinks,kitOnly): these legitimately diverge — the kit carries packaging-only rules (e.g. excluding**/*.test.mjsand__tests__/**so tests are not shipped to users;kitOnlytooling likecompute-sync-plan.mjs). Do NOT blindly overwrite them — a blanket dev→kit copy would strip the kit's test-excludes and ship test files. Instead run the field-level drift report below and reconcile any unexpected drift by hand.
Drift-report command (run during Step 4 summary AND here before writing):
node -e ' const d=require("<devRepoPath>/vc-manifest.json"); const k=require("<kitRepoPath>/vc-manifest.json"); let drift=0; for(const key of new Set([...Object.keys(d),...Object.keys(k)])){ if(key==="version") continue; if(JSON.stringify(d[key])!==JSON.stringify(k[key])){ drift++; console.log("DRIFT field:",key); console.log(" dev:",JSON.stringify(d[key])); console.log(" kit:",JSON.stringify(k[key])); } } console.log(drift?("\n"+drift+" manifest field(s) drift — legacyDeletions auto-syncs dev→kit; reconcile the rest consciously."):"manifest in sync (besides version)"); 'legacyDeletionsappearing in the drift report is EXPECTED and is auto-resolved (dev→kit). Any OTHER field in the report is a conscious decision: confirm the kit value is the intended packaging rule, or update dev/kit so they converge. Never let a drift go unexamined.Create symlinks if missing (
.agents/skills -> ../.claude/skills).
Step 8: Leak Detection
Verify no project-specific content leaked into the kit repo. This is a resolved-set, two-check gate that scans the full shipped TEXT surface, not just
CLAUDE.md/AGENTS.md.Resolve the shipped set via the kit's resolver, then restrict to TEXT surfaces:
node <kitRepoPath>/resolve-manifest.mjs --root <kitRepoPath> --jsonTake the resolved
filesand keep only TEXT surfaces:.claude/skills/**matching*.md,*.cjs,*.mjs,*.py,*.js,*.json.claude/agents/**matching*.md.codex/**process/development-protocols/**- plus
CLAUDE.md,AGENTS.md
Exclude binaries and
**/node_modules/**.Check (a) -- product-name grep over the resolved text set. Scan for the product names in the grep below ONLY.
tRPC/Prismaare DROPPED from this skill-prose scan to avoid false positives in legitimate generic test guidance; the hosted-database product name is KEPT (see the pattern):grep -rIin "flowser\|CloakBrowser\|OpenClaw\|Supabase" <resolved-text-files>Allowlist the Bucket-4 lines that MUST keep the literal to function (otherwise the gate flags itself):
author: flowserfrontmatter; theisFlowserActivePlanPathidentifier; this skill's OWN scrub-grep pattern lines below; the new validator's own pattern strings; and the one internal plan-generation validation comment insession-init.cjs.Check (b) -- non-portable context-path grep: any concrete backticked
process/context/...file reference in the resolved text set, MINUS the shipped/seeded survivors, is a dangling-link leak → FAIL with file:line. Survivors (allowed):process/context/all-context.md,process/context/tests/all-tests.md. Portable directory refs (e.g.process/context/tests/) and theprocess/context/...placeholder are fine.Keep the existing narrow
CLAUDE.md/AGENTS.mdgrep (this stays as-is on just those two files;tRPC/Prismaplus the hosted-database product name all REMAIN here, as shown in the pattern below):# Must return empty -- any matches indicate leaked content grep -ri "flowser\|tRPC\|Prisma\|Supabase\|CloakBrowser\|OpenClaw" CLAUDE.md AGENTS.md # Must return empty -- no absolute paths grep -r "/Users/" .Check (c) -- README badge counts: Verify the kit README.md badge counts match actual agent and skill counts:
actual_agents=$(ls <kitRepoPath>/.claude/agents/*.md | wc -l | tr -d ' ') actual_skills=$(ls -d <kitRepoPath>/.claude/skills/vc-*/ | wc -l | tr -d ' ') readme_agents=$(grep -oE '[0-9]+-Agents' <kitRepoPath>/README.md | grep -oE '[0-9]+') readme_skills=$(grep -oE '[0-9]+-Skills' <kitRepoPath>/README.md | grep -oE '[0-9]+') echo "Agents: actual=$actual_agents badge=$readme_agents" echo "Skills: actual=$actual_skills badge=$readme_skills" [ "$actual_agents" = "$readme_agents" ] && [ "$actual_skills" = "$readme_skills" ] && echo "PASS" || echo "FAIL: badge counts mismatch"If FAIL: update README.md badges to match actual counts before committing.
NOTE: the brand grep matches product names ONLY. It does NOT match
.ck.json/.ckignore-- those Phase-2 legacy-fallback literals are intentional and must NOT be flagged. Do not addck/ckignoreto any leak grep.The standing
validate-kit-portability.mjsvalidator (run byvc-audit-vc) mirrors checks (a) and (b) for between-release drift; this Step-8 gate is the publish-time enforcement.If leak detection fails:
- Print the offending lines (file:line).
- Revert the changes in the kit repo (
git -C <kitRepoPath> checkout .). - STOP and report the leak. Do NOT commit or push.
Step 9a: Commit and Tag
- In the kit repo. If the version was already at the target (skip-bump path from Step 2): use
tag-as-isand commit with the existing version number. Otherwise: bump the version invc-manifest.jsonand commit with the new version.
cd <kitRepoPath>
git add -A
git commit -m "Release vX.Y.Z"
git tag vX.Y.Z
Step 9b: STOP — Explicit Push Approval (separate from Step 6 confirm)
Leak detection passed. The commit and tag are ready locally. Before running git push, you MUST stop and get explicit user approval:
"Leak detection passed. The commit is ready locally (
git log --oneline -1shows the new commit). Type 'push' to publish to remote, or 'abort' to keep the commit local."
Do NOT run git push or git push --tags until the user types 'push' (or a clear affirmative). This is a separate gate from the publish-confirm at Step 6 — even if the user approved publishing in Step 6, they must re-confirm before the actual remote push.
If the user says 'abort':
- The local commit and tag are preserved.
- Print: "Commit and tag preserved locally. Run
git push origin main && git push --tagswhen ready." - Stop.
Only on explicit 'push': proceed to Step 10 (git push origin main && git push --tags).
Step 10: Push
- Push to remote (only after Step 9b approval):
git push origin main && git push --tags
- If push fails (e.g., rejected, auth error), report the error. The commit and tag are preserved locally for retry.
Step 11: Create GitHub Release
After a successful push, create a GitHub Release so watchers are notified and the release appears in the Releases tab:
gh release create vX.Y.Z \ --repo <remote-owner>/<remote-repo> \ --title "vX.Y.Z: <first sentence of release notes>" \ --notes "<full release notes>"- If the user provided release notes at Step 6, use them verbatim.
- If left blank, auto-generate:
"N modified, M new, P removed. See commit log for details." - The
--titleone-liner should be the first sentence of the notes (truncate at 72 chars if longer). - If
ghis unavailable or the push to remote failed, skip this step and note it in the summary.
Step 12: Post-Publish Remote Verify
After a successful push, clone the kit from remote to a temp dir and verify the catalog works on a fresh install:
TS=$(date +%s)
git clone <remote-kit-url> /tmp/vc-kit-verify-$TS
node /tmp/vc-kit-verify-$TS/.claude/skills/vc-context-discovery/scripts/discover-skills.mjs 2>&1
rm -rf /tmp/vc-kit-verify-$TS
Expected: exit 0 and expected skill count in output. If FAIL: note the error in the publish summary — the push succeeded but the remote install may have a catalog issue.
Step 13: Print Summary
- Print publish summary:
vc-publish complete
===================
Version: v2.2.0 (was v2.1.0)
Files changed: 4
Remote: git@github.com:withkynam/vibecode-pro-max-kit.git
Tag: v2.2.0
Release: https://github.com/<owner>/<repo>/releases/tag/v2.2.0
Key Changes from v1.0
- Glob arrays are stable; the deprecation ledger is not. The glob patterns in
include/exclude/kitOnlyare stable — adding a new skill or agent requires zero manifest edits (new files are auto-included by the globs). BUTlegacyDeletionsis a literal path array, not a glob: it grows every time the harness deprecates a skill/dir/file, and it MUST be reconciled dev→kit at every publish (see Step 7 Manifest reconciliation). Skipping it strands the kit with a stale deletion ledger so downstreamvc-updates never clean up the newly deprecated dirs. So publish-time manifest edits are: (1) version bump, (2)legacyDeletionssync, (3) conscious reconciliation of any other field flagged by the drift report. - Resolver-driven diffing. The kit repo is resolved via
resolve-manifest.mjs(which requiresvc-manifest.jsonin its--root). The dev-side file comparison is handled insidecompute-sync-plan.mjs, which reads the manifest from--kit-root(always the kit checkout). Dev repos do not carryvc-manifest.json. - No
managed/managedDirsarrays to update. The old workflow of adding new files to these arrays is eliminated.
Rules
- ALWAYS run the full resolver diff (Steps 3-4) even when changes already exist in the kit repo. Direct kit edits (README, translations, community files) do not replace the dev→kit diff. Both change sources must be captured in the same publish.
- NEVER copy project-specific files:
process/context/all-context.md(with real content),process/features/*,process/general-plans/*(with real plans) - ALWAYS verify no project-specific content leaked before committing (Step 8)
- ALWAYS show the diff summary before publishing (Step 5-6)
- NEVER auto-push.
git pushmust be preceded by a separate explicit 'push' confirmation (Step 9b), distinct from the publish-confirm at Step 6. This rule holds even whenVC_KIT_SOURCEis a local path. - CLAUDE.md and AGENTS.md require special handling -- never copy the development repo's project-specific versions directly
- Kit repo checkout path is stored in
.vc-publish-config(add to.gitignore) - The only manifest edit at publish time is the version bump -- glob patterns are stable
Reference
See references/vc-publish.md for the detailed algorithm, CLAUDE.md/AGENTS.md stripping rules, error handling, and example outputs.