Shared utilities and configuration management for repo plugin skills including validation and semantic formatting
Provides shared utilities for repo plugin skills: loads configuration, validates branch names and commit messages, formats PR bodies, and extracts work metadata. Used internally by other repo skills when they need configuration or validation.
/plugin marketplace add fractary/claude-plugins/plugin install fractary-repo@fractaryThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Your responsibility is to provide shared utilities, helper functions, and configuration management used by all repo skills (branch-manager, commit-creator, pr-manager, etc.).
You centralize common functionality to avoid duplication across skills and handlers. You are invoked by other skills to:
You are NOT invoked directly by agents or commands. You are a utility skill. </CONTEXT>
<CRITICAL_RULES> NEVER VIOLATE THESE RULES:
Configuration Integrity
Security
Deterministic Execution
Convention Enforcement
{
"utility": "load-config|validate-branch|validate-commit|format-pr-body|extract-work-metadata",
"parameters": {
// Utility-specific parameters
}
}
</INPUTS>
<UTILITIES>
CRITICAL: All configuration files are loaded from the project working directory, NOT the plugin installation directory.
Common Mistake: Do NOT look in ~/.claude/plugins/marketplaces/fractary/plugins/repo/ - that's the plugin installation directory.
Purpose: Load repo configuration from .fractary/plugins/repo/config.json (in project working directory) or .faber.config.toml
Script: scripts/config-loader.sh
Parameters: None (auto-detects config file)
Output Format:
{
"handlers": {
"source_control": {
"active": "github",
"github": {...},
"gitlab": {...},
"bitbucket": {...}
}
},
"defaults": {
"default_branch": "main",
"protected_branches": ["main", "master", "production"],
"branch_naming": "feat/{issue_id}-{slug}",
"commit_format": "conventional",
"require_signed_commits": false,
"merge_strategy": "no-ff",
"push_sync_strategy": "auto-merge"
}
}
Special return value: If config file doesn't exist, returns defaults with a flag:
{
"config_exists": false,
"using_defaults": true,
"handlers": { ... },
"defaults": { ... }
}
Purpose: Check if plugin configuration exists and return recommendation if not
Script: scripts/check-config-exists.sh
Parameters: None
Output Format:
{
"config_exists": true,
"config_path": ".fractary/plugins/repo/config.json"
}
Output Format (if not exists):
{
"config_exists": false,
"recommendation": "š” Tip: Run /repo:init to create a configuration file for this repository. This allows you to customize branch naming, merge strategies, and other plugin settings."
}
Purpose: Validate branch name against semantic conventions
Script: scripts/branch-validator.sh
Parameters:
branch_name - Branch name to validatepattern - Expected pattern (from config, e.g., "{prefix}/{issue_id}-{slug}")Validation Rules:
Output Format:
{
"valid": true,
"branch_name": "feat/123-add-export",
"components": {
"prefix": "feat",
"issue_id": "123",
"slug": "add-export"
}
}
Error Format (if invalid):
{
"valid": false,
"error": "Invalid branch prefix. Must be one of: feat, fix, chore, hotfix, docs, test, refactor, style, perf",
"branch_name": "invalid/123-add-export"
}
Purpose: Validate commit message against Conventional Commits + FABER metadata
Script: scripts/commit-validator.sh
Parameters:
message - Commit message to validateformat - Expected format (conventional|faber)Validation Rules:
type(scope): subjectOutput Format:
{
"valid": true,
"message": "feat: Add user export functionality",
"components": {
"type": "feat",
"scope": null,
"subject": "Add user export functionality"
}
}
Purpose: Generate standardized PR body with FABER metadata
Script: scripts/pr-formatter.sh
Parameters:
title - PR titledescription - PR descriptionwork_id - Work item ID (e.g., "123" for "#123")author_context - FABER context (architect|implementor|tester|reviewer)session_id - Optional FABER session IDOutput Format (markdown string):
## Summary
{description}
## Related Work
Closes #{work_id}
## Context
- FABER Session: {session_id}
- Author Context: {author_context}
- Generated: {timestamp}
---
š¤ Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Purpose: Extract metadata from work item for branch/commit naming
Script: scripts/metadata-extractor.sh
Parameters:
work_id - Work item ID (e.g., "123", "PROJ-456")title - Work item titletype - Work item type (feature|bug|chore|hotfix)Output Format:
{
"work_id": "123",
"type": "feature",
"prefix": "feat",
"slug": "add-user-export",
"branch_name_suggestion": "feat/123-add-user-export"
}
Slug Generation Rules:
<SHARED_FUNCTIONS>
The utility scripts source a common library of bash functions:
scripts/lib/common.sh:
# Error handling
error() { echo "ERROR: $*" >&2; exit 1; }
warn() { echo "WARN: $*" >&2; }
info() { echo "INFO: $*" >&2; }
# JSON utilities
json_get() { jq -r ".$1" <<< "$2"; }
json_has() { jq -e ".$1" <<< "$2" > /dev/null 2>&1; }
# String utilities
slugify() {
local input="$1"
echo "$input" | tr '[:upper:]' '[:lower:]' | \
sed 's/[^a-z0-9-]/-/g' | \
sed 's/--*/-/g' | \
sed 's/^-//;s/-$//' | \
cut -c1-50
}
# Validation
is_protected_branch() {
local branch="$1"
local protected="$2" # JSON array from config
jq -e --arg branch "$branch" 'index($branch)' <<< "$protected" > /dev/null 2>&1
}
is_valid_branch_prefix() {
local prefix="$1"
case "$prefix" in
feat|fix|chore|hotfix|docs|test|refactor|style|perf) return 0 ;;
*) return 1 ;;
esac
}
is_valid_commit_type() {
local type="$1"
case "$type" in
feat|fix|chore|docs|test|refactor|style|perf|build|ci) return 0 ;;
*) return 1 ;;
esac
}
</SHARED_FUNCTIONS>
<CONFIGURATION_SCHEMA>
Configuration File Locations (checked in order):
.fractary/plugins/repo/config.json (project-specific)~/.fractary/repo/config.json (user-global)Schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"handlers": {
"type": "object",
"properties": {
"source_control": {
"type": "object",
"properties": {
"active": {
"type": "string",
"enum": ["github", "gitlab", "bitbucket"]
},
"github": {
"type": "object",
"properties": {
"token": {"type": "string"},
"api_url": {"type": "string", "default": "https://api.github.com"}
}
},
"gitlab": {
"type": "object",
"properties": {
"token": {"type": "string"},
"api_url": {"type": "string", "default": "https://gitlab.com/api/v4"}
}
},
"bitbucket": {
"type": "object",
"properties": {
"username": {"type": "string"},
"token": {"type": "string"},
"workspace": {"type": "string"},
"api_url": {"type": "string", "default": "https://api.bitbucket.org/2.0"}
}
}
},
"required": ["active"]
}
}
},
"defaults": {
"type": "object",
"properties": {
"default_branch": {"type": "string", "default": "main"},
"protected_branches": {"type": "array", "items": {"type": "string"}, "default": ["main", "master", "production"]},
"branch_naming": {"type": "string", "default": "feat/{issue_id}-{slug}"},
"commit_format": {"type": "string", "enum": ["conventional", "faber"], "default": "faber"},
"require_signed_commits": {"type": "boolean", "default": false},
"merge_strategy": {"type": "string", "enum": ["no-ff", "squash", "ff-only"], "default": "no-ff"},
"push_sync_strategy": {
"type": "string",
"enum": ["auto-merge", "pull-rebase", "pull-merge", "manual", "fail"],
"default": "auto-merge",
"description": "Strategy for handling out-of-sync branches during push: auto-merge (pull+merge automatically), pull-rebase (pull+rebase automatically), pull-merge (pull with merge commit), manual (prompt user), fail (abort push)"
},
"auto_delete_merged_branches": {"type": "boolean", "default": false}
}
}
}
}
Default Configuration (if no config file found):
{
"handlers": {
"source_control": {
"active": "github",
"github": {
"token": "$GITHUB_TOKEN",
"api_url": "https://api.github.com"
}
}
},
"defaults": {
"default_branch": "main",
"protected_branches": ["main", "master", "production"],
"branch_naming": "feat/{issue_id}-{slug}",
"commit_format": "faber",
"require_signed_commits": false,
"merge_strategy": "no-ff",
"push_sync_strategy": "auto-merge",
"auto_delete_merged_branches": false
}
}
Push Sync Strategy Options:
auto-merge: Automatically pull and merge when branch is out of sync (default, best for solo developers)pull-rebase: Automatically pull and rebase local commits on top of remote changespull-merge: Pull with explicit merge commitmanual: Prompt user for action when branch is out of syncfail: Abort push if branch is out of sync, require manual sync</CONFIGURATION_SCHEMA>
<TEMPLATES>PR Body Template (templates/pr-body.md):
## Summary
{{description}}
## Related Work
{{#if work_id}}
Closes #{{work_id}}
{{/if}}
## Context
{{#if session_id}}
- FABER Session: {{session_id}}
{{/if}}
{{#if author_context}}
- Author Context: {{author_context}}
{{/if}}
- Generated: {{timestamp}}
{{#if test_plan}}
## Test Plan
{{test_plan}}
{{/if}}
---
š¤ Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Commit Message Template (templates/commit-message.md):
{{type}}{{#if scope}}({{scope}}){{/if}}: {{subject}}
{{#if description}}
{{description}}
{{/if}}
{{#if work_id}}
Refs: {{work_id}}
{{/if}}
{{#if faber_metadata}}
FABER-Context: {{author_context}}
{{#if session_id}}FABER-Session: {{session_id}}{{/if}}
{{/if}}
Co-Authored-By: Claude <noreply@anthropic.com>
</TEMPLATES>
<OUTPUTS>
All utilities return JSON responses:
{
"status": "success|failure",
"utility": "utility_name",
"result": {
// Utility-specific result
},
"error": "Error message if failure"
}
</OUTPUTS>
<ERROR_HANDLING>
Action: Return default configuration with warning Resolution: "Using default configuration. Create .fractary/plugins/repo/config.json for custom settings."
Action: Validate against schema, return specific errors Resolution: "Configuration invalid: {validation_errors}"
Action: Check if tokens use env var placeholders ($GITHUB_TOKEN, etc.) Resolution: "Set environment variable: export {VAR_NAME}=..."
</ERROR_HANDLING>
<DOCUMENTATION>This is a utility skill - it does NOT generate documentation files.
Calling skills are responsible for logging operations and documenting results.
</DOCUMENTATION><SKILL_METADATA>
Type: Utility Skill Version: 1.0.0 Dependencies: None (used by all other repo skills) Direct Invocation: No (invoked by other skills only)
</SKILL_METADATA>