Skip to content

Latest commit

 

History

History
290 lines (212 loc) · 20.2 KB

File metadata and controls

290 lines (212 loc) · 20.2 KB

AGENTS.md

This file tells AI coding agents how the Developer Tools Directory repo works and how to contribute correctly.

Catalog site: https://tmhsdigital.github.io/Developer-Tools-Directory/ (auto-deployed on push to main)

Repository overview

This is a meta-repository -- it does not contain a Cursor plugin or MCP server itself. It catalogs, standardizes, and scaffolds other TMHSDigital developer tool repos. It contains:

  • registry.json -- single source of truth for all tool repos. README, CLAUDE.md, and the catalog site's embedded registry are generated from it by scripts/sync_from_registry.py.
  • standards/ -- 17 Markdown docs defining conventions for folder structure, CI/CD, plugin manifests, GitHub Pages, commits, README format, AGENTS.md format, versioning, testing, skills, rules, MCP servers, security, licensing, scope, lifecycle, and writing style.
  • scaffold/ -- Python repo generator (create-tool.py) with Jinja2 templates that produce a fully standards-compliant new tool repo.
  • scripts/ -- automation utilities. sync_from_registry.py regenerates all derived artifacts from registry.json.
  • site-template/ -- shared GitHub Pages build system for tool repos. build_site.py reads .cursor-plugin/plugin.json, site.json, skills/, rules/, and mcp-tools.json from a tool repo and renders docs/index.html via template.html.j2. Self-hosts Inter and JetBrains Mono fonts. Tool repos clone this directory in CI and run the build script at deploy time.
  • docs/ -- static GitHub Pages catalog site (vanilla HTML/CSS/JS, no build step). Reads registry.json at runtime, falls back to an embedded copy.
  • assets/ -- logo image.
  • .github/workflows/ -- CI/CD for this repo. See .github/workflows/README.md for the action-pinning convention and the full list.

Branching and commit model

  • Single branch: main only. No develop/release branches.
  • All changes land via pull request. main is protected by an active ruleset (main protection) that blocks direct pushes, force pushes, and branch deletion for every contributor including the repo owner. No bypass actors are configured.
  • Squash merge only. Other merge methods are blocked by the ruleset.
  • Zero required approvals (solo-maintainer repo), but all required status checks must pass before a PR can be merged.
  • Conventional commits are required:
    • feat: -- new tool added to registry, new standard doc, new scaffold template
    • fix: -- corrections to existing content
    • chore: -- dependency updates, CI changes
    • docs: -- documentation-only changes
  • Commit messages should be concise and describe the "why", not the "what".

Required status checks (ruleset-enforced on main)

Every PR must pass these 7 checks before it can be merged:

  • Validate registry.json
  • Validate docs site
  • Validate scaffold
  • Registry sync check
  • Public-repo safety scan
  • feat/fix commits require VERSION bump
  • CodeQL

release.yml's Check VERSION vs latest tag is a post-merge guard that only runs on push to main, so it is deliberately not in the required-contexts list (including it would permanently block every PR).

CI/CD workflows

validate.yml (runs on PR and push to main)

Checks:

  • registry.json is valid JSON with correct schema (required fields, valid types, integer counts)
  • docs/index.html, docs/style.css, docs/script.js exist
  • scaffold/create-tool.py compiles without syntax errors
  • Scaffold dry-run test: generates a test repo and verifies key files exist

pages.yml (runs on push to main when docs/, assets/, or registry.json change)

  1. Copies registry.json into docs/ for client-side fetch
  2. Copies assets/ into docs/assets/
  3. Uploads docs/ as a Pages artifact
  4. Deploys to GitHub Pages via actions/deploy-pages

release.yml (runs on push to main, ignores docs/md/standards changes)

  1. check-version reads VERSION at the repo root and compares it with the latest git tag
  2. If they match, the workflow exits cleanly - no release needed
  3. If VERSION is ahead, release creates annotated tag v<VERSION>, pushes it, and creates a GitHub Release
  4. Release notes come from release-drafter's current draft body when available, else from the commit log since the previous tag
  5. If VERSION is lower than the latest tag, the workflow fails with a clear error

VERSION is the single source of truth for the meta-repo version. Bump it in the same PR that lands a feature or fix. Conventional commit prefixes are still used for commit messages, but they no longer drive version bumps. The version-bump-check job in validate.yml enforces that any feat: or fix: commit also bumps VERSION (opt out with [skip version] in the commit subject or body for workflow-only changes).

Note: tool repos in the ecosystem use a different model (auto-bump from conventional commits, version stored in .cursor-plugin/plugin.json). See standards/versioning.md for the tool-repo rules. The meta-repo deviates intentionally because it does not ship as a plugin and the narrative in ROADMAP.md is human-authored.

Has a concurrency guard -- only one release can run at a time. Commits with [skip ci] are ignored.

The repo About section (description, homepage, topics) is updated locally, not in CI. The GITHUB_TOKEN does not have administration:write and storing a PAT with that scope is an avoidable supply-chain risk. Instead:

python scripts/sync_from_registry.py --about

This prints the exact gh repo edit ... command. Review and run it locally.

release-drafter.yml (runs on push to main and PR activity)

Auto-drafts release notes from merged PR titles/labels. Config in .github/release-drafter.yml defines categories (Features, Standards, Scaffold, Bug Fixes, Documentation, CI) and version resolution rules.

stale.yml (weekly on Sunday midnight UTC)

Marks and closes inactive issues and PRs. Issues: 60-day stale / 14-day close. PRs: 30-day stale / 14-day close. Exempt labels: pinned, security, enhancement.

codeql.yml (push/PR to main + weekly Monday 06:00 UTC)

Runs GitHub CodeQL security scanning for Python code.

dependency-review.yml (runs on PRs to main)

Audits new dependencies for known vulnerabilities. Comments a summary in the PR. Fails on high severity.

label-sync.yml (runs on PR open/sync)

Auto-labels PRs by changed file paths: standards/ -> standards, scaffold/ -> scaffold, docs/ -> documentation, registry.json -> registry, .github/ -> ci.

Key files and what they do

registry.json

Array of tool objects. Required fields per entry:

Field Type Description
name string Display name
repo string Owner/RepoName
slug string Kebab-case identifier
description string One-line summary
type string cursor-plugin or mcp-server
homepage string Docs site URL (empty string if none)
skills int Number of skills
rules int Number of rules
mcpTools int Number of MCP tools
extras object Optional extra counts (snippets, templates, natives, events)
npm string npm package name (empty string or omit if none)
topics string[] Discovery tags
status string experimental, beta, active, maintenance, deprecated, or archived (see standards/lifecycle.md)
version string Current semver version
language string Primary language
license string SPDX identifier
pagesType string static, mkdocs, or none
hasCI bool Whether the repo has CI workflows

docs/index.html

The catalog site. It embeds a copy of the registry data in a <script type="application/json"> tag as a fallback, and also fetches registry.json at runtime. The embedded copy is regenerated from registry.json by scripts/sync_from_registry.py. Do not edit the embedded block by hand.

scripts/sync_from_registry.py

Pure-stdlib Python script that regenerates every derived artifact from registry.json:

  • README.md tools table (between <!-- registry:tools:start --> / <!-- registry:tools:end -->)
  • README.md tool descriptions (between <!-- registry:descriptions:start --> / <!-- registry:descriptions:end -->)
  • README.md aggregate stats (between <!-- registry:stats:start --> / <!-- registry:stats:end -->)
  • CLAUDE.md cataloged tools and totals (same markers)
  • docs/index.html embedded registry JSON (inside the <script id="registry-data"> tag)

Modes:

  • python scripts/sync_from_registry.py - rewrite artifacts in place
  • python scripts/sync_from_registry.py --check - exit 1 if anything would change; used by CI (sync-check job in validate.yml)
  • python scripts/sync_from_registry.py --about - print the gh repo edit command to update the GitHub About section; run locally

scaffold/create-tool.py

Python script using Jinja2. Templates live in scaffold/templates/. The script accepts CLI args (--name, --description, --type, --mcp-server, --skills, --rules, --license, --output).

standards/

Pure documentation -- no code. Each file documents a convention derived from analyzing existing TMHSDigital tool repos (CFX, Docker, Steam, Home Lab, etc.).

Adding a new tool to the registry

  1. Add an entry to registry.json following the schema above.
  2. Run python scripts/sync_from_registry.py to regenerate README, CLAUDE.md, and the embedded registry in docs/index.html.
  3. Run python scripts/sync_from_registry.py --check to confirm clean.
  4. Commit with feat: prefix and git commit -s (DCO sign-off required).
  5. Locally, run python scripts/sync_from_registry.py --about and execute the printed gh repo edit command to refresh the GitHub About section.

Adding or updating a standard

  1. Edit or create the file in standards/
  2. If new, add a row to the standards table in README.md and in standards/README.md
  3. If the standard affects the scaffold output, update the corresponding .j2 template in scaffold/templates/
  4. Use docs: commit prefix for docs-only changes, feat: if adding a new standard

Updating the scaffold

  1. Edit templates in scaffold/templates/
  2. If adding a new template file, update scaffold/create-tool.py to render it
  3. Test with: python scaffold/create-tool.py --name "Test" --description "Test" --mcp-server --skills 2 --rules 1 --output /tmp/test
  4. CI runs a dry-run test on every push

When editing registry.json

  • Every entry requires all fields listed in the schema table above. CI validates this on every push and PR.
  • type must be exactly cursor-plugin or mcp-server. No other values are accepted.
  • skills, rules, and mcpTools must be integers, not strings.
  • status must be one of the six lifecycle values; see standards/lifecycle.md.
  • After adding or modifying an entry, run python scripts/sync_from_registry.py to regenerate every derived artifact. Do not edit those artifacts by hand - the sync-check CI job blocks PRs that drift.
  • Use feat: commit prefix when adding a new tool, fix: when correcting existing entries.

When editing standards/

  • Standards are pure Markdown documentation. They contain no executable code.
  • Each standard should have an H1 title, a brief overview paragraph, and H2 sections for major topics.
  • Write for public readership. Do not reference internal repos, private URLs, or credentials.
  • No em dashes or en dashes - use hyphens or rewrite. See standards/writing-style.md for the full prose conventions.
  • If adding a new standard document:
    1. Create the .md file in standards/
    2. Add a row to the table in standards/README.md
    3. Add a row to the Standards table in the main README.md
  • If a standard change affects what the scaffold should generate, update the corresponding .j2 template in scaffold/templates/ to match.
  • Use docs: commit prefix for edits, feat: for entirely new standards.

When editing scaffold/

  • The generator script is scaffold/create-tool.py. It uses Jinja2 Environment with FileSystemLoader pointed at scaffold/templates/.
  • Templates use .j2 extension. Available context variables: name, slug, description, type, has_mcp, skills, rules, skill_count, rule_count, license_spdx, license_key, author_name, author_email, repo_owner, repo_name.
  • If adding a new template file:
    1. Create the .j2 file in scaffold/templates/ (or a subdirectory for MCP server templates)
    2. Add a write_file() call in create-tool.py to render and write it
    3. If the file is conditional (e.g., MCP-only), wrap the call in if args.mcp_server
  • Always test changes locally before committing:
    python scaffold/create-tool.py --name "Test" --description "Test" --mcp-server --skills 2 --rules 1 --output /tmp/test
    
  • CI runs a scaffold dry-run test on every push. If you add a new required file, add a test -f check to the validate.yml scaffold test step.
  • The LICENSE.j2 template has conditional logic for MIT, Apache-2.0, and CC-BY-NC-ND-4.0. If adding a new license option, update both the template and the LICENSE_FILES/SPDX dicts in create-tool.py.

When editing site-template/

  • site-template/build_site.py is the build script that generates GitHub Pages sites for tool repos. It reads data from the tool repo and renders HTML via template.html.j2.
  • site-template/template.html.j2 is a Jinja2 template producing a single-page site with: sticky nav, hero with animated stats, collapsible MCP tool categories, search/filter, back-to-top, toast copy feedback, and mobile hamburger nav.
  • site-template/fonts/ contains self-hosted Inter (400/500/700) and JetBrains Mono (400) woff2 files.
  • site-template/SETUP-PROMPT.md is a copy-paste prompt for applying the template to a new tool repo.
  • Tool repos consume this template via their pages.yml workflow, which clones Developer-Tools-Directory with sparse checkout and runs build_site.py --repo-root . --out docs.
  • Data sources in each tool repo: .cursor-plugin/plugin.json (metadata), site.json (branding/colors), skills/*/SKILL.md (parsed for name/description via frontmatter), rules/*.mdc (parsed for name/scope/description), mcp-tools.json (manually maintained tool list).
  • Changes to the template or build script affect all tool repos on their next deploy. Test locally before pushing:
    python site-template/build_site.py --repo-root /path/to/tool-repo --out /path/to/tool-repo/docs
    

When editing docs/ (catalog site)

  • docs/index.html is the single-page catalog site. It embeds a copy of registry.json inside a <script type="application/json" id="registry-data"> tag as a fallback for when the direct fetch fails.
  • docs/script.js fetches registry.json at runtime. If the fetch fails, it reads the embedded copy. It renders aggregate stats (total skills, rules, MCP tools) and tool cards with filtering by type and topic.
  • docs/style.css contains all styling -- dark theme, responsive layout, card design. No CSS framework.
  • No external CDN dependencies. The site must work fully offline except for badge images. No jQuery, no Bootstrap, no Google Fonts.
  • The pages.yml workflow copies registry.json and assets/ into docs/ at deploy time. You do not need to manually place these files in docs/.
  • When testing locally, open docs/index.html directly in a browser. The embedded fallback will kick in since registry.json won't be in docs/ locally.
  • Do not use innerHTML or eval with registry data. Use textContent for any user-facing text to prevent XSS.

When editing workflows

  • validate.yml runs on PR and push to main. Jobs: registry schema validation, docs existence checks, scaffold syntax and dry-run test, registry sync-check (scripts/sync_from_registry.py --check), and public-repo safety scan (blocks leaked business email, drive-letter paths, unsafe DOM sinks, committed secrets). Keep checks fast - avoid installing unnecessary dependencies.
  • sync.yml runs on push to main when registry.json changes. Regenerates derived artifacts and opens a PR via peter-evans/create-pull-request rather than pushing directly. Uses only the default GITHUB_TOKEN - no PAT required.
  • pages.yml deploys to GitHub Pages on push to main when docs/, assets/, or registry.json change. It copies registry.json into docs/ and assets/ into docs/assets/ before uploading. Uses actions/deploy-pages.
  • release.yml creates a GitHub release on push to main when VERSION is ahead of the latest git tag (excluding docs/md/standards changes). Version is read from the VERSION file at the repo root; release notes come from release-drafter's draft body or the commit log since the previous tag. validate.yml's version-bump-check ensures feat: and fix: commits come with a VERSION bump (opt out with [skip version]). Has a concurrency guard - only one release can run at a time. Commits containing [skip ci] are ignored. The repo About section is updated locally via python scripts/sync_from_registry.py --about, never by this workflow.
  • release-drafter.yml auto-drafts release notes from merged PR titles/labels. Config is in .github/release-drafter.yml. Categories: Features, Standards, Scaffold, Bug Fixes, Documentation, CI/Infrastructure. The autolabeler assigns labels based on changed file paths.
  • stale.yml runs weekly (Sunday midnight UTC). Issues: 60-day stale, 14-day close. PRs: 30-day stale, 14-day close. Labels exempt from staleness: pinned, security, enhancement (issues) and pinned, security (PRs).
  • codeql.yml runs Python security scanning on push/PR to main and weekly (Monday 06:00 UTC). Uses github/codeql-action v3.
  • dependency-review.yml runs on PRs to main. Audits new dependencies and comments a summary in the PR. Fails on high severity vulnerabilities.
  • label-sync.yml runs on PR open/sync. Labels PRs based on changed paths: standards/ -> standards, scaffold/ -> scaffold, docs/ -> documentation, registry.json -> registry, .github/ -> ci.

Code conventions

  • No hardcoded credentials, business emails, or local filesystem paths anywhere. The safety-scan CI job blocks these.
  • No em dashes or en dashes - use hyphens or rewrite. See standards/writing-style.md.
  • registry.json must be valid JSON at all times - CI enforces this.
  • Derived artifacts (README tables, CLAUDE.md tables, docs embedded registry) are generated by scripts/sync_from_registry.py. Never edit them by hand.
  • The catalog site uses no external CDN dependencies and no innerHTML/eval on registry data.
  • Conventional commits are required (feat:, fix:, chore:, docs:), with a Signed-off-by: trailer (DCO; see CONTRIBUTING.md).
  • Single branch: main only.

Branch protection (active)

main is protected by a GitHub ruleset named main protection. Current configuration:

  • Enforcement: active, target is the default branch, bypass actors list is empty (applies to the repo owner as well).
  • Pull request required: 0 approving reviews, squash-merge only, other merge methods blocked.
  • Required status checks: Validate registry.json, Validate docs site, Validate scaffold, Registry sync check, Public-repo safety scan, feat/fix commits require VERSION bump, CodeQL.
  • Force pushes blocked (non_fast_forward rule).
  • Branch deletion blocked (deletion rule).
  • Signed commits are enforced at commit-sign-off level by the DCO App status check (separate from the ruleset).

Agents must branch, push, and open a PR even for single-file edits. Direct pushes to main will be rejected by the ruleset.

Ruleset configuration lives in repo settings, not in git history. Verify the current state with:

gh api repos/TMHSDigital/Developer-Tools-Directory/rulesets
gh api repos/TMHSDigital/Developer-Tools-Directory/rulesets/<id>

Dependencies

This repo has one Python dependency: Jinja2 (in requirements.txt). The sync script is pure stdlib. The docs site has zero runtime dependencies.

License

Outbound: CC-BY-NC-ND-4.0. Inbound: DCO + broader grant (see CONTRIBUTING.md and standards/licensing.md).