Skip to content

Blog

Seven New Skills: Teaching AI Agents to Enforce Your Standards

We’ve added seven new skills to the Coding Standards framework. Each one teaches AI coding agents (Claude Code, Cursor, Copilot, and others) how to enforce a specific aspect of your standards — from security scanning to coverage thresholds to dependency age gates.

Skills are markdown files that describe a workflow an AI agent should follow. They live in standards/agents/claude-code/skills/ and contain structured instructions: when to trigger, what to check, how to report results. Think of them as runbooks that your AI assistant can execute on demand.

Unlike static linter rules, skills can reason about context. They can ask clarifying questions, combine multiple checks, and explain why something is a violation — not just that it is one.

Skill: standards-audit | Issue: #49

Wraps the existing lint-standards.sh compliance linter. Runs all applicable check modules for your detected languages, parses the structured JSON output, and reports violations grouped by severity (FAIL, WARN, PASS). This is the broadest skill — it covers everything from conventional commits to banned functions to test directory structure.

Standards audit: 14 passed, 2 warnings, 1 failure out of 17 checks.

Skill: security-gate | Issue: #50

Scans your codebase for P0 and P1 security violations from sec-01. Detects banned functions (eval(), exec(), pickle.loads(), etc.) per language, finds XSS patterns (innerHTML, dangerouslySetInnerHTML), flags hardcoded secrets, and checks for weak randomness. P0 and P1 findings are merge-blocking — the skill clearly states that the PR should not merge until they’re fixed.

Skill: dependency-age-gate | Issue: #51

Born from the axios supply chain attack — this skill verifies that every dependency version in your lockfile was published at least 72 hours ago. It queries registry APIs (npm, PyPI, crates.io, RubyGems, Maven Central, pub.dev) for publish timestamps and flags anything too fresh. Includes the exception process for emergency security patches.

Skill: config-assembly | Issue: #52

Drives the block composition system. Reads your .standards.yml, assembles agent configs from content blocks (architecture, testing, security, naming, language-specific, role-specific), and writes them to the correct output files. Respects the checksum system — customized files aren’t overwritten, they’re written to .standards-pending/ for the merge-standards skill to resolve.

Skill: setup-wizard | Issue: #53

Guided onboarding for new projects. Detects languages from manifest files, asks about project role and desired agents, generates a .standards.yml, runs setup with dry-run preview, and finishes with a health check. Turns a multi-step manual process into a conversation.

Skill: coverage-enforcer | Issue: #54

Enforces the layer-specific test coverage thresholds from the standards: 100% for domain/core, 95%+ for application and infrastructure, 95% minimum overall. Knows which coverage tool to use per language (coverage.py, c8, simplecov, tarpaulin, JaCoCo) and can break down coverage by architecture layer. Also checks test naming conventions and file mirroring.

Skill: naming-convention | Issue: #55

Lints identifiers against the language-specific naming rules: snake_case for Python, camelCase for JavaScript, PascalCase for Go exports, ? predicates for Ruby, and so on across all 13 supported languages. Uses grep patterns for quick scans and delegates to language-specific linters (ruff, eslint, rubocop, clippy) for deeper analysis.

The previously released merge-standards skill (#56) already handles the pending merge workflow — intelligently merging upstream standards updates into customized agent configs while preserving project-specific content.

The skills form a pipeline that covers the full lifecycle:

  1. setup-wizard onboards the project
  2. config-assembly generates agent configs
  3. standards-audit checks overall compliance
  4. security-gate enforces P0/P1 rules
  5. dependency-age-gate validates supply chain safety
  6. coverage-enforcer verifies test coverage by layer
  7. naming-convention catches identifier inconsistencies
  8. merge-standards keeps configs current as standards evolve

Each skill is self-contained — use any one independently or chain them in CI.

Update your standards submodule:

Terminal window
make sync-standards

The new skills are available immediately to any agent with access to the .standards/ directory. In Claude Code, reference them by name — for example, “run the standards-audit skill” or “check the dependency age gate.”

See all skills in standards/agents/claude-code/skills/.

Automated Standards Review on Every Pull Request

The standards compliance linter shipped in Phase 2 can now run automatically on every pull request and post its findings as a structured comment — without any manual CI configuration from your team. Phase 3 ships the standards-review composite GitHub Action and installs the workflow into consumer projects during setup.

The PR review bot runs the full lint-standards.sh suite on every pull request. That includes:

  • Conventional Commits — verifies recent commit messages match type(scope): subject format.
  • Test directory — confirms a non-empty tests/, spec/, or __tests__/ directory exists.
  • Secret detection — scans source files for AWS keys, private key blocks, and hardcoded passwords.
  • Coverage configuration — checks that a coverage threshold is declared in CI or .standards.yml.
  • Language-specific checks — type annotations, banned functions, linter configs — activated by your .standards.yml language list.

See the linter blog post for the full check catalogue.

When the action runs it posts a comment with a summary line and a table of results:

## Standards Review
:x: 1 failure(s) found
| Status | Check | Details |
|--------|-------|---------|
| :white_check_mark: PASS | conventional-commits | All recent commits follow Conventional Commits format |
| :white_check_mark: PASS | no-secrets | No hardcoded secrets detected |
| :warning: WARN | test-directory | Test directory found but appears empty |
| :x: FAIL | python/banned-functions | eval() usage detected in src/utils.py |
| :white_check_mark: PASS | python/ruff-config | [tool.ruff] section configured in pyproject.toml |
---
*Generated by Coding Standards linter*

If any check returns FAIL, the action exits with a non-zero code and the workflow step is marked as failed — blocking merge when branch protection is configured.

Running make setup (or the one-line curl installer) now copies the workflow template automatically:

Terminal window
curl -fsSL https://raw.githubusercontent.com/c65llc/coding-standards/main/install.sh | bash

This places .github/workflows/standards-review.yml in your project on first setup. The workflow references the composite action from the .standards/ submodule, so it stays in sync with the rest of your standards configuration.

Copy the template from the standards repository:

Terminal window
cp .standards/templates/standards-review.yml.example .github/workflows/standards-review.yml

Then grant the workflow permission to comment on pull requests by ensuring your repository’s Settings > Actions > General > Workflow permissions allows pull requests write access, or rely on the permissions block already present in the template.

SARIF integration for GitHub Code Scanning

Section titled “SARIF integration for GitHub Code Scanning”

The linter also supports --format sarif output (SARIF 2.1.0). You can extend the workflow to upload results to GitHub Code Scanning, which surfaces violations as inline annotations directly on the diff:

- name: Run standards linter (SARIF)
run: |
.standards/scripts/lint-standards.sh --format sarif > standards.sarif || true
- name: Upload SARIF to Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: standards.sarif

SARIF maps WARN checks to warning level and FAIL checks to error level in the Code Scanning UI. PASS results are omitted to keep the annotation list focused.

Phase 4 adds --dry-run support and a make diff-standards target so you can preview what a standards sync would change before applying it.

Declarative Config and make doctor: Phase 1 of Standards Tooling

Two new additions land in Phase 1 of our standards tooling roadmap: .standards.yml — a declarative configuration file that replaces the old shell-variable-based approach — and make doctor, a health check command that audits your project’s standards setup and tells you exactly what to fix.

.standards.yml: Declarative Standards Configuration

Section titled “.standards.yml: Declarative Standards Configuration”

Previously, consumer projects configured standards through a .standards-config file using KEY=value shell variables. It worked, but it was limited: no schema, no version field, no way to express nested settings like coverage thresholds.

.standards.yml replaces that with a proper YAML config:

# .standards.yml — Project standards configuration
version: 1
languages:
- python
- typescript
agents:
- claude-code
- cursor
- copilot
role: service
coverage:
minimum: 95
domain: 100
architecture: clean
security: strict
Field Purpose
version Config schema version — enables forward-compatible migrations
languages Which language standards to load during assembly
agents Which AI agents get config files during setup and sync
role Project type — service, library, app, or data-pipeline
coverage.minimum Overall test coverage floor (%)
coverage.domain Domain-layer coverage requirement (%)
architecture clean enforces Clean Architecture; none removes constraints
security strict makes P0/P1 merge-blocking; moderate warns on P1

The setup.sh script generates .standards.yml automatically during installation using language detection. You can edit it afterward to adjust agents, coverage thresholds, or architecture mode. sync-standards.sh reads it on every run to assemble only the configs you need.

The legacy .standards-config format remains supported for backward compatibility — make doctor will warn you if you’re on the old format.

make doctor runs a seven-point audit of your project’s standards setup and produces a scored report:

Standards Health Check
=======================================
✅ PASS Configuration .standards.yml found (version 1)
✅ PASS Claude Code CLAUDE.md present
✅ PASS Cursor .cursorrules present
⚠️ WARN Copilot .github/copilot-instructions.md missing
✅ PASS Checksums All config checksums match
⚠️ WARN Languages Detected 'go' not in .standards.yml
✅ PASS Submodule .standards/ is a valid git repo
❌ FAIL Git Hooks post-merge hook not installed
✅ PASS Gitignore All required entries present
=======================================
Score: 6/9 (67%)
Fixes needed:
-> Run: make setup-agents (to install missing Copilot config)
-> Add: 'go' to .standards.yml languages list
-> Run: make setup (to install git hooks for automatic standards sync)
  1. Configuration.standards.yml exists (or legacy .standards-config)
  2. Agent files — each agent declared in config has its expected file on disk
  3. Checksums.standards-checksums exists and config hashes match stored values, detecting unauthorized edits
  4. Languages — runs detect-languages.sh and compares against declared languages, flagging gaps
  5. Submodule.standards/ is a valid initialized git repo (skipped when running in the standards repo itself)
  6. Git hooks.git/hooks/post-merge exists and references standards sync
  7. Gitignore.gitignore contains .standards-pending/ and *.pre-standards-setup

Every warning and failure includes a concrete fix command so you know exactly what to run.

Update your standards submodule and run the health check:

Terminal window
cd .standards && git pull origin main && cd ..
make doctor

If you haven’t installed standards yet:

Terminal window
curl -fsSL https://raw.githubusercontent.com/c65llc/coding-standards/main/install.sh | bash
make doctor

A perfect score means your project is fully configured, checksums are clean, and automatic sync is in place via git hooks.

Preview Before You Commit: --dry-run and make diff-standards

Phase 4 of the standards tooling roadmap adds two preview capabilities that let you see exactly what setup and sync-standards would change before a single file is modified.

When you run make setup or make sync-standards in an existing project, files get written. For a solo developer that is usually fine, but for a team rollout — or any project with carefully tuned AI agent configs — you want to review changes before committing to them. The new --dry-run flag and make diff-standards target solve this.

Both scripts/setup.sh and scripts/sync-standards.sh now accept a --dry-run flag. When active, no files are created, modified, or deleted. Instead, each write operation prints a [dry-run] line describing what would have happened.

$ ./scripts/setup.sh --dry-run
🔍 DRY RUN — showing what would change (no files modified)
📝 Assembling claude-code config...
[dry-run] Would write: /project/CLAUDE.md
✅ claude-code config (dry-run)
📝 Assembling cursor config...
[dry-run] Would write: /project/.cursorrules
✅ cursor config (dry-run)
[dry-run] Would write: /project/.standards.yml
[dry-run] Would write: /project/.git/hooks/post-merge
[dry-run] Would append to: /project/.gitignore

Nothing was written. You can now review the list and decide whether to proceed.

The same flag works for sync:

$ ./scripts/sync-standards.sh --dry-run
🔍 DRY RUN — showing what would change (no files modified)
[dry-run] Would pull latest standards (submodule has updates)
[dry-run] Would re-assemble: /project/CLAUDE.md
[dry-run] Would re-assemble: /project/.cursorrules
[dry-run] Would create: /project/.gemini/GEMINI.md

--dry-run tells you which files would change. make diff-standards tells you exactly what would change inside each file. It assembles every declared agent config to a temp file, diffs it against the installed version, and prints color-coded output.

$ make diff-standards
Standards Diff
=======================================
→ claude-code (CLAUDE.md)
~ Changes: +12/-3 lines
--- CLAUDE.md
+++ (assembled)
@@ -45,7 +45,7 @@
...
→ cursor (.cursorrules)
✅ Up to date
→ copilot (copilot-instructions.md)
+ Would create: .github/copilot-instructions.md
=======================================
Summary: 1 up to date 1 would change 1 new
Run make sync-standards to apply changes.

No temp files are left behind. If everything is up to date you see only checkmarks.

  1. make diff-standards — review what would change across all agents
  2. ./scripts/sync-standards.sh --dry-run — confirm the list of write operations
  3. make sync-standards — apply once you are satisfied
  4. Commit the updated agent configs in a single PR for team review

This workflow is especially useful when pulling a new version of the standards submodule: diff first, sync second, never surprise your teammates.

Standards Compliance Linter: Enforce Your Standards in CI

Phase 2 of the standards tooling roadmap ships make lint-standards — a multi-language compliance linter that checks your project against coding standards and reports results in text, JSON, or SARIF format for GitHub Code Scanning integration.

The linter is organized into two tiers: common checks that run on every project, and language-specific checks that activate based on your .standards.yml configuration.

Check What it verifies
conventional-commits Last 10 git commits match type(scope): subject pattern
test-directory A tests/, test/, spec/, or __tests__/ directory exists and is non-empty
no-secrets No AWS keys, private key blocks, or hardcoded passwords/API keys in source files
coverage-config CI workflows, jest config, pytest config, or .standards.yml declare a coverage threshold
Check What it verifies
python/type-annotations mypy is configured; WARN if not in strict mode, FAIL if not configured at all
python/banned-functions No eval(), exec(), pickle.loads(), os.system(), or subprocess with shell=True
python/ruff-config ruff.toml, .ruff.toml, or [tool.ruff] in pyproject.toml
Check What it verifies
typescript/strict-tsconfig "strict": true in tsconfig.json
typescript/banned-functions No eval(), new Function(), .innerHTML =, document.write(), or setTimeout with string literal
typescript/eslint-config An .eslintrc*, eslint.config.*, or eslintConfig in package.json
Check What it verifies
go/golangci-config .golangci.yml, .golangci.yaml, or .golangci.toml present
go/error-handling No bare _ = or , _ := patterns that discard return values (likely errors)
Check What it verifies
elixir/credo-config :credo in mix.exs dependencies
elixir/dialyzer-config :dialyxir in mix.exs dependencies

Each check is a standalone bash script in scripts/lint-checks/<language>/. The interface is minimal: receive the project root as $1, print one line (PASS|WARN|FAIL <check-name> <message>), exit with 0, 1, or 2. Adding a new check is as simple as dropping a new script in the right directory — the orchestrator discovers it automatically.

The orchestrator (scripts/lint-standards.sh) reads .standards.yml to determine which language-specific check directories to activate. Common checks always run.

🔎 Standards Compliance Check
═══════════════════════════════════════
✅ PASS conventional-commits All recent commits follow Conventional Commits format
⚠️ WARN test-directory Test directory found but appears empty
✅ PASS no-secrets No hardcoded secrets detected
✅ PASS coverage-config Coverage gate found in .standards.yml (minimum: 95%)
✅ PASS python/type-annotations mypy strict mode enabled in pyproject.toml
❌ FAIL python/banned-functions eval() at src/utils.py:42
✅ PASS python/ruff-config [tool.ruff] section configured in pyproject.toml
═══════════════════════════════════════
Results: 5 pass, 1 warn, 1 fail
Terminal window
./scripts/lint-standards.sh --format json

Produces a structured JSON object with summary counts and a results array — suitable for parsing in scripts, dashboards, or custom reporters.

Terminal window
./scripts/lint-standards.sh --format sarif > results.sarif

SARIF 2.1.0 output maps WARN to warning and FAIL to error. Upload to GitHub Code Scanning to get inline annotations on pull requests:

- name: Run standards linter
run: ./scripts/lint-standards.sh --format sarif > standards.sarif || true
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: standards.sarif
Terminal window
make lint-standards

Or directly with a format flag:

Terminal window
./scripts/lint-standards.sh --format json
./scripts/lint-standards.sh --format sarif

The linter exits with code 1 if any checks fail, making it CI-friendly as a blocking gate.

Drop a new executable *.sh script in scripts/lint-checks/common/ or scripts/lint-checks/<language>/. Follow the one-line output contract and the orchestrator picks it up automatically on the next run. Run make test-scripts to validate syntax before committing.