This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This repo (Blazemeter/coreteam-claude-utils) is the core team's fork of Blazemeter/claude-base — a project-agnostic Claude Code plugin marketplace + governance framework, not an application. It ships one bundled plugin (base-tools) containing skills, slash commands, sub-agents, and hooks, plus the policy and CI that govern them. Everything is configuration-as-code: YAML frontmatter + Markdown bodies. Tooling is Python-only with a single dependency (pyyaml) — there is no node_modules anywhere.
This is a fork of Blazemeter/claude-base. The team customizes it here while pulling in upstream improvements.
-
Remotes:
origin→Blazemeter/coreteam-claude-utils(this fork),upstream→Blazemeter/claude-base. -
Branch model:
mainis kept as a clean mirror of upstream — do not commit to it directly.developis the team integration branch and the repo's default branch; branch offdevelopand open PRs intodevelop. -
Pull upstream changes (manual — never automatic):
gh repo sync Blazemeter/coreteam-claude-utils # upstream main -> fork main, on GitHub # or locally: git fetch upstream && git checkout main && git merge upstream/main && git push origin main git checkout develop && git merge main && git push origin develop # carry updates into team line
If
mainhas diverged,gh repo syncrefuses rather than clobbering — reconcile locally withmerge/rebase(only--forceifmainis meant to be a pure mirror). -
Opening PRs (fork gotcha): because this is a fork,
gh pr createresolves the PR base repo to the upstream parent (Blazemeter/claude-base, which has nodevelopbranch) unless told otherwise, and fails. Two defenses are in place — do both once per clone:gh repo set-default Blazemeter/coreteam-claude-utils # one-time per clone; fixes gh's base resolution # always create PRs against this fork + develop explicitly: gh pr create --repo Blazemeter/coreteam-claude-utils --base develop --title 'MOB-1234: …' --body '…'
The
enforce-jira-id.shhook now blocks anygh pr createthat omits--repo Blazemeter/coreteam-claude-utilsor--base, so the failure can't recur silently.
Upstream-only contract that does NOT govern this fork:
Blazemeter/claude-baseis itself mirrored byte-for-byte withPerfectoMobileDev/claude-basevia.github/workflows/sync-to-sibling.ymlandverify-sibling-sync.yml(seeLINKED_REPOS.md). Those workflow files were inherited by this fork but the sibling-sync contract is not this fork's workflow — review whether they should run here at all before relying on them, and ignoreLINKED_REPOS.md's "byte-for-byte identical" rule for this repo.
pip install -r scripts/requirements.txt # one-time setup (only dep: pyyaml)
python scripts/validate.py --strict # main validator (schema, standards, tool policy)
python -m unittest discover -s scripts/tests -t scripts # run validator unit tests
python -m unittest scripts.tests.test_validate -v # run a single test module (note -t/module path)
shellcheck plugins/*/hooks/*.sh # lint bash hooks
ruff check plugins/*/hooks/*.py # lint python hooks
python scripts/behavioral_runner.py --lint # validate tests/cases.yaml files (no API calls)
pip install -r scripts/requirements-eval.txt && ANTHROPIC_API_KEY=... python scripts/behavioral_runner.py # opt-in, hits the real API, costs money
claude plugin validate . # Claude Code's canonical schema checkCI runs five jobs on every PR (structural, sast, secret-scan, claude-cli, behavioral); any failure blocks merge.
plugins/base-tools/— the single bundled plugin. Subdirs:skills/,commands/,agents/,hooks/(scripts +hooks.jsonwiring), and.claude-plugin/plugin.json. Each artifact is YAML frontmatter + a Markdown body;descriptionis the most important field. Add a new artifact by copying the matchingexample-*template. Skills follow progressive disclosure — keepSKILL.mdunder 500 lines and push heavy reference material intoreferences/.policy/— governance config:allowed-tools.yaml(the tool allow/deny policy every artifact is validated against),jira-lifecycle.yaml(status names + transition IDs),doc-task.yaml(doc-planning task config,project_keyis__UNSET__until an org configures it).scripts/— Python tooling:validate.py(main validator),behavioral_runner.py,aggregate_telemetry.py, andtests/.STANDARDS.md— the five numbered org rules (summarized below)..github/workflows/— the five CI jobs.
Skills/commands/agents/hooks are auto-discovered from plugins/base-tools/ — adding one needs no manifest registration. But the installed-plugin cache is keyed by version number (~/.claude/plugins/cache/coreteam-claude-base/base-tools/<version>/), so a change that doesn't bump the version never reaches anyone who already has the plugin — they keep loading the stale cache for that version.
- Every PR that touches a skill/command/agent/hook must bump
versioninplugins/base-tools/.claude-plugin/plugin.json(and keep the matching entry in.claude-plugin/marketplace.jsonin sync — a mismatch trips avalidate.pywarning).plugin.jsonis the version that wins at install time. - To pick up a new version, the upgrade flow is
marketplace update+reload-plugins— NOTinstall:/plugin marketplace update coreteam-claude-base # upgrades the installed plugin to the new version (re-fetches the cache) /reload-plugins # reloads the running session (or fully restart Claude Code)/plugin install base-tools@coreteam-claude-baseis a no-op once installed — it checks by name, not version, and just reports "already installed globally." Usemarketplace update, notinstall, to upgrade. - Plugin skills are namespaced (
base-tools:grill-me); they coexist with any personal~/.claude/skills/copy of the same short name (grill-me), which plugin install never touches. - Changing
.claude-plugin/marketplace.json's top-levelnamedoes NOT rename an already-installed marketplace. Claude Code keys installed marketplaces by the identifier assigned at/plugin marketplace addtime (stored in~/.claude/plugins/known_marketplaces.json), not by re-readingnameon everymarketplace update—updateonly refreshes the plugin contents under the existing key. To pick up a renamed marketplace, remove it (/plugins→ Marketplaces → select →d) and re-add it (/plugin marketplace add <owner>/<repo>), then reinstall its plugins under the new@<name>suffix.
plugins/base-tools/hooks.json wires PreToolUse/PostToolUse/PreSkill hooks that actively block tool calls. Know these before running git or creating JIRA issues:
- enforce-jira-id.sh —
git checkout -b,git switch -c,git branch,git push -u, andgh pr createrequire a real JIRA key matching[A-Z][A-Z0-9_]+-[0-9]+. All-zero placeholders likeMOB-00000are rejected. It also blocksgh pr createunless it explicitly targets this fork (--repo Blazemeter/coreteam-claude-utils --base <branch>) — see the fork PR gotcha above. Work on this tooling itself lives under EpicMOB-50371. - enforce-claude-attribution.sh — every
git commitmessage must contain aCo-Authored-By: Claudetrailer. - inject-ai-generated-label.sh — JIRA issues created via the Atlassian MCP must include the
AI_generatedlabel. - Safety guardrails (block destructive actions): pushes/force-push/reset on shared branches, EC2/GCP compute mutations, datastore mutations (DynamoDB/S3/Redis/Mongo writes), credentials in commits, test-skip edits (
@Disabled,pytest.mark.skip,-DskipTests), and hook-bypass attempts (--no-verify,core.hooksPath,HUSKY=0).
Escape hatches (both logged and audited): CLAUDE_STANDARDS_SKIP=1 for process rules, CLAUDE_SAFETY_OVERRIDE=1 for safety guardrails. Note the hook-bypass guard rejects these when inlined as a command prefix — export them in the environment instead.
- Real JIRA key in branch names and PR descriptions (no placeholders).
AI_generatedlabel on every JIRA issue created via an LLM tool path.Co-Authored-By: Claudetrailer on every commit.- Documentation-planning task (
DOC-ready:) for customer-facing work, when confirmed needed (seefile-doc-taskskill). - Forward-only JIRA lifecycle transitions kept in step with the work (see
jira-lifecycleskill).
policy/allowed-tools.yaml is the authority on what tools any skill/command/agent may declare. If an artifact's allowed-tools/tools lists something not in that policy, the structural CI job fails — add the entry in the same PR. Bare Bash, Bash(*), and patterns like Bash(rm *), Bash(sudo *), Bash(curl|sh) are forbidden.