From rpw-building
Use when setting up versioning for a project, comparing versions between components, or implementing version checks. Enforces git-hash-based versioning standard across all projects.
npx claudepluginhub randypitcherii/rpw-agent-marketplace --plugin rpw-buildingThis skill uses the workspace's default tool permissions.
Every deployable component MUST expose a version composed of:
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Every deployable component MUST expose a version composed of:
Display format: v{semver} · {hash} · {date} (e.g., v1.0.0 · 350625c · 2026-03-09)
One semver source per component
package.json version fieldpyproject.toml [project].version fieldVERSION file at the project rootRuntime git info resolution
git rev-parse --short HEAD for hashgit log -1 --format=%as for commit date (YYYY-MM-DD)Security: no shell injection
subprocess.run(['git', ...]) — never os.popen() or subprocess.run(shell=True)execFileSync('git', [...]) — never execSync('git ...')Multi-component version comparison
"unknown", never "0.1.0")Health endpoint schema (for services)
{
"version": "1.0.0",
"git_hash": "350625c",
"git_commit_date": "2026-03-09"
}
import subprocess
from pathlib import Path
from typing import Optional
_git_info_cache: Optional[tuple] = None
def get_git_info() -> tuple[Optional[str], Optional[str]]:
"""Return (short_hash, commit_date), cached after first call."""
global _git_info_cache
if _git_info_cache is not None:
return _git_info_cache
for cwd in [Path(__file__).parent, Path.cwd()]:
try:
hash_r = subprocess.run(
['git', 'rev-parse', '--short', 'HEAD'],
capture_output=True, text=True, timeout=1, cwd=str(cwd))
date_r = subprocess.run(
['git', 'log', '-1', '--format=%as'],
capture_output=True, text=True, timeout=1, cwd=str(cwd))
if hash_r.returncode == 0:
h = hash_r.stdout.strip()
d = date_r.stdout.strip() if date_r.returncode == 0 else None
_git_info_cache = (h, d)
return _git_info_cache
except Exception:
continue
_git_info_cache = (None, None)
return _git_info_cache
import { execFileSync } from "child_process";
function resolveGitInfo(): { hash?: string; date?: string } {
try {
const hash = execFileSync("git", ["rev-parse", "--short", "HEAD"], {
encoding: "utf8", timeout: 3000,
}).trim();
let date: string | undefined;
try {
date = execFileSync("git", ["log", "-1", "--format=%as"], {
encoding: "utf8", timeout: 3000,
}).trim();
} catch { /* date is optional */ }
return { hash, date };
} catch {
return {};
}
}
const gitInfo = resolveGitInfo();
export const GIT_HASH = gitInfo.hash;
export const GIT_DATE = gitInfo.date;
export function versionsMatch(
localHash: string | undefined,
remoteHash: string | undefined,
): boolean {
if (!localHash?.trim() || !remoteHash?.trim()) return true;
return localHash.trim() === remoteHash.trim();
}