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)
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 byscripts/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.pyregenerates all derived artifacts fromregistry.json.site-template/-- shared GitHub Pages build system for tool repos.build_site.pyreads.cursor-plugin/plugin.json,site.json,skills/,rules/, andmcp-tools.jsonfrom a tool repo and rendersdocs/index.htmlviatemplate.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). Readsregistry.jsonat runtime, falls back to an embedded copy.assets/-- logo image..github/workflows/-- CI/CD for this repo. See.github/workflows/README.mdfor the action-pinning convention and the full list.
- Single branch:
mainonly. No develop/release branches. - All changes land via pull request.
mainis 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 templatefix:-- corrections to existing contentchore:-- dependency updates, CI changesdocs:-- documentation-only changes
- Commit messages should be concise and describe the "why", not the "what".
Every PR must pass these 7 checks before it can be merged:
Validate registry.jsonValidate docs siteValidate scaffoldRegistry sync checkPublic-repo safety scanfeat/fix commits require VERSION bumpCodeQL
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).
Checks:
registry.jsonis valid JSON with correct schema (required fields, valid types, integer counts)docs/index.html,docs/style.css,docs/script.jsexistscaffold/create-tool.pycompiles without syntax errors- Scaffold dry-run test: generates a test repo and verifies key files exist
- Copies
registry.jsonintodocs/for client-side fetch - Copies
assets/intodocs/assets/ - Uploads
docs/as a Pages artifact - Deploys to GitHub Pages via
actions/deploy-pages
check-versionreadsVERSIONat the repo root and compares it with the latest git tag- If they match, the workflow exits cleanly - no release needed
- If
VERSIONis ahead,releasecreates annotated tagv<VERSION>, pushes it, and creates a GitHub Release - Release notes come from release-drafter's current draft body when available, else from the commit log since the previous tag
- If
VERSIONis 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.
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.
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.
Runs GitHub CodeQL security scanning for Python code.
Audits new dependencies for known vulnerabilities. Comments a summary in the PR. Fails on high severity.
Auto-labels PRs by changed file paths: standards/ -> standards, scaffold/ -> scaffold, docs/ -> documentation, registry.json -> registry, .github/ -> ci.
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 |
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.
Pure-stdlib Python script that regenerates every derived artifact from registry.json:
README.mdtools table (between<!-- registry:tools:start -->/<!-- registry:tools:end -->)README.mdtool descriptions (between<!-- registry:descriptions:start -->/<!-- registry:descriptions:end -->)README.mdaggregate stats (between<!-- registry:stats:start -->/<!-- registry:stats:end -->)CLAUDE.mdcataloged tools and totals (same markers)docs/index.htmlembedded registry JSON (inside the<script id="registry-data">tag)
Modes:
python scripts/sync_from_registry.py- rewrite artifacts in placepython scripts/sync_from_registry.py --check- exit 1 if anything would change; used by CI (sync-checkjob invalidate.yml)python scripts/sync_from_registry.py --about- print thegh repo editcommand to update the GitHub About section; run locally
Python script using Jinja2. Templates live in scaffold/templates/. The script accepts CLI args (--name, --description, --type, --mcp-server, --skills, --rules, --license, --output).
Pure documentation -- no code. Each file documents a convention derived from analyzing existing TMHSDigital tool repos (CFX, Docker, Steam, Home Lab, etc.).
- Add an entry to
registry.jsonfollowing the schema above. - Run
python scripts/sync_from_registry.pyto regenerate README, CLAUDE.md, and the embedded registry indocs/index.html. - Run
python scripts/sync_from_registry.py --checkto confirm clean. - Commit with
feat:prefix andgit commit -s(DCO sign-off required). - Locally, run
python scripts/sync_from_registry.py --aboutand execute the printedgh repo editcommand to refresh the GitHub About section.
- Edit or create the file in
standards/ - If new, add a row to the standards table in
README.mdand instandards/README.md - If the standard affects the scaffold output, update the corresponding
.j2template inscaffold/templates/ - Use
docs:commit prefix for docs-only changes,feat:if adding a new standard
- Edit templates in
scaffold/templates/ - If adding a new template file, update
scaffold/create-tool.pyto render it - Test with:
python scaffold/create-tool.py --name "Test" --description "Test" --mcp-server --skills 2 --rules 1 --output /tmp/test - CI runs a dry-run test on every push
- Every entry requires all fields listed in the schema table above. CI validates this on every push and PR.
typemust be exactlycursor-pluginormcp-server. No other values are accepted.skills,rules, andmcpToolsmust be integers, not strings.statusmust be one of the six lifecycle values; seestandards/lifecycle.md.- After adding or modifying an entry, run
python scripts/sync_from_registry.pyto regenerate every derived artifact. Do not edit those artifacts by hand - thesync-checkCI job blocks PRs that drift. - Use
feat:commit prefix when adding a new tool,fix:when correcting existing entries.
- 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.mdfor the full prose conventions. - If adding a new standard document:
- Create the
.mdfile instandards/ - Add a row to the table in
standards/README.md - Add a row to the Standards table in the main
README.md
- Create the
- If a standard change affects what the scaffold should generate, update the corresponding
.j2template inscaffold/templates/to match. - Use
docs:commit prefix for edits,feat:for entirely new standards.
- The generator script is
scaffold/create-tool.py. It uses Jinja2EnvironmentwithFileSystemLoaderpointed atscaffold/templates/. - Templates use
.j2extension. 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:
- Create the
.j2file inscaffold/templates/(or a subdirectory for MCP server templates) - Add a
write_file()call increate-tool.pyto render and write it - If the file is conditional (e.g., MCP-only), wrap the call in
if args.mcp_server
- Create the
- 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 -fcheck to thevalidate.ymlscaffold test step. - The
LICENSE.j2template 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 theLICENSE_FILES/SPDXdicts increate-tool.py.
site-template/build_site.pyis the build script that generates GitHub Pages sites for tool repos. It reads data from the tool repo and renders HTML viatemplate.html.j2.site-template/template.html.j2is 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.mdis a copy-paste prompt for applying the template to a new tool repo.- Tool repos consume this template via their
pages.ymlworkflow, which clones Developer-Tools-Directory with sparse checkout and runsbuild_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
docs/index.htmlis the single-page catalog site. It embeds a copy ofregistry.jsoninside a<script type="application/json" id="registry-data">tag as a fallback for when the direct fetch fails.docs/script.jsfetchesregistry.jsonat 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.csscontains 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.ymlworkflow copiesregistry.jsonandassets/intodocs/at deploy time. You do not need to manually place these files indocs/. - When testing locally, open
docs/index.htmldirectly in a browser. The embedded fallback will kick in sinceregistry.jsonwon't be indocs/locally. - Do not use
innerHTMLorevalwith registry data. UsetextContentfor any user-facing text to prevent XSS.
validate.ymlruns 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.ymlruns on push to main whenregistry.jsonchanges. Regenerates derived artifacts and opens a PR viapeter-evans/create-pull-requestrather than pushing directly. Uses only the defaultGITHUB_TOKEN- no PAT required.pages.ymldeploys to GitHub Pages on push to main whendocs/,assets/, orregistry.jsonchange. It copiesregistry.jsonintodocs/andassets/intodocs/assets/before uploading. Usesactions/deploy-pages.release.ymlcreates a GitHub release on push to main whenVERSIONis ahead of the latest git tag (excluding docs/md/standards changes). Version is read from theVERSIONfile at the repo root; release notes come from release-drafter's draft body or the commit log since the previous tag.validate.yml'sversion-bump-checkensuresfeat:andfix:commits come with aVERSIONbump (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 viapython scripts/sync_from_registry.py --about, never by this workflow.release-drafter.ymlauto-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.ymlruns 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) andpinned,security(PRs).codeql.ymlruns Python security scanning on push/PR to main and weekly (Monday 06:00 UTC). Usesgithub/codeql-actionv3.dependency-review.ymlruns on PRs to main. Audits new dependencies and comments a summary in the PR. Fails onhighseverity vulnerabilities.label-sync.ymlruns on PR open/sync. Labels PRs based on changed paths:standards/-> standards,scaffold/-> scaffold,docs/-> documentation,registry.json-> registry,.github/-> ci.
- 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.jsonmust 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/evalon registry data. - Conventional commits are required (
feat:,fix:,chore:,docs:), with aSigned-off-by:trailer (DCO; seeCONTRIBUTING.md). - Single branch:
mainonly.
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_forwardrule). - Branch deletion blocked (
deletionrule). - 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>
This repo has one Python dependency: Jinja2 (in requirements.txt). The sync script is pure stdlib. The docs site has zero runtime dependencies.
Outbound: CC-BY-NC-ND-4.0. Inbound: DCO + broader grant (see CONTRIBUTING.md and standards/licensing.md).