Thank you for your interest in contributing. This guide covers everything you need to get started.
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/Developer-Tools-Directory.git cd Developer-Tools-Directory - Install dependencies:
pip install -r requirements.txt
- Create a feature branch:
git checkout -b feat/your-feature-name
Developer-Tools-Directory/
registry.json # Tool catalog (source of truth)
standards/ # Convention documentation (see standards/README.md)
scaffold/
create-tool.py # Repo generator script
templates/ # Jinja2 templates for new repos
site-template/
build_site.py # Shared GitHub Pages build for tool repos
template.html.j2 # HTML template with configurable branding
fonts/ # Self-hosted Inter + JetBrains Mono woff2
docs/ # GitHub Pages catalog site
assets/ # Logo image
.github/workflows/ # CI/CD automation
- Open
registry.jsonand add a new entry at the end of the array:
{
"name": "Your Tool Name",
"repo": "TMHSDigital/Your-Tool-Repo",
"slug": "your-tool-repo",
"description": "One-line description of the tool",
"type": "cursor-plugin",
"category": "developer-tooling",
"homepage": "https://tmhsdigital.github.io/Your-Tool-Repo/",
"skills": 0,
"rules": 0,
"mcpTools": 0,
"extras": {},
"topics": ["topic-1", "topic-2"],
"status": "active",
"language": "Python",
"license": "CC-BY-NC-ND-4.0",
"pagesType": "static",
"hasCI": true
}-
Run the sync script - it regenerates every derived artifact (README tables and stats, CLAUDE.md, embedded registry in
docs/index.html):python scripts/sync_from_registry.py
-
Verify the sync is clean:
python scripts/sync_from_registry.py --check
-
Commit with
feat: add <tool-name> to registry. Remember to sign off your commit (see DCO section below).
For a full end-to-end walkthrough including scaffolding the tool repo, see docs/contributors/adding-a-tool.md.
| Field | Type | Constraints |
|---|---|---|
name |
string | Display name |
repo |
string | Owner/RepoName format |
slug |
string | Kebab-case, matches repo name |
description |
string | One line, no em dashes |
type |
string | cursor-plugin or mcp-server |
homepage |
string | URL or empty string |
skills |
int | >= 0 |
rules |
int | >= 0 |
mcpTools |
int | >= 0 |
extras |
object | Optional counts (snippets, templates, etc.) |
topics |
string[] | Discovery tags |
status |
string | active, beta, or deprecated |
version |
string | Semver |
language |
string | Primary language |
license |
string | SPDX identifier |
pagesType |
string | static, mkdocs, or none |
hasCI |
bool | Whether repo has CI workflows |
-
Create a new Markdown file in
standards/:# Example: standards/testing.md -
Structure the document:
- Start with an H1 title
- Include a brief overview paragraph
- Use H2 sections for major topics
- Include concrete examples and code blocks
- Write for public readership - no internal references
-
Add the standard to two index locations:
standards/README.md- add a row to the tableREADME.md- add a row to the Standards table
-
If the standard affects scaffold output, update the corresponding
.j2template inscaffold/templates/. -
Commit with
feat: add <standard-name> standard
Tool repos carry a standards-version signal in their agent files
(AGENTS.md, CLAUDE.md, skills/*/SKILL.md, rules/*.mdc). The
drift checker (scripts/drift_check/) verifies these against the
meta-repo VERSION and surfaces other ecosystem-policy mismatches
(broken standards links, required references, stale aggregate counts).
The checker runs automatically: on push to main (when checker code
or standards change), weekly on schedule, and on demand via
workflow_dispatch. See docs/drift-check-token-setup.md
for the DRIFT_CHECK_TOKEN configuration that enables cross-repo
sparse-checkout.
For local runs:
python scripts/drift_check/cli.py --local /path/to/tool-repo- Edit the
.j2file inscaffold/templates/ - Test locally:
python scaffold/create-tool.py \ --name "Test Plugin" \ --description "Test description" \ --mcp-server \ --skills 2 \ --rules 1 \ --no-register \ --output /tmp/scaffold-test
--no-registerkeeps the test repo out ofregistry.json. - Verify the generated files look correct
- Commit with
fix:orchore:prefix
- Create the
.j2file inscaffold/templates/ - Render it from
_render_repo()inscaffold/generator.pyviawrite_file() - Run a test generation and verify the new file appears
- Update
README.md"What it generates" section if visible to users - Commit with
feat: add <template-name> scaffold template
Templates use Jinja2. Available context variables:
| Variable | Type | Description |
|---|---|---|
name |
string | Display name |
slug |
string | Kebab-case identifier |
description |
string | One-line description |
type |
string | cursor-plugin or mcp-server |
has_mcp |
bool | Whether MCP server scaffold is included |
skills |
list | Skill name strings |
rules |
list | Rule name strings |
skill_count |
int | Number of skills |
rule_count |
int | Number of rules |
license_spdx |
string | SPDX license identifier |
license_key |
string | License key for template selection |
author_name |
string | Author name |
author_email |
string | Author email |
repo_owner |
string | GitHub org (TMHSDigital) |
repo_name |
string | Repository name (same as slug) |
The catalog site lives in docs/ and is vanilla HTML/CSS/JS with zero dependencies.
docs/index.html- the whole site: markup, inline CSS, and inline JS (search, filters, URL state)- Generated regions (tool cards, filter chips, hero stats, embedded registry and search JSON) come from
scripts/sync_from_registry.py; do not edit them by hand
The pages.yml workflow copies registry.json and assets/ into docs/ at deploy time, so you don't need to manually copy files.
To test locally, open docs/index.html in a browser. The script falls back to the embedded registry data.
The unified site template (site-template/) powers GitHub Pages for all tool repos. Changes to the template affect every site at next deploy.
| File | Purpose |
|---|---|
site-template/template.html.j2 |
Jinja2 HTML template rendered by each tool repo |
site-template/build_site.py |
Build script that reads repo data and renders the template |
site-template/fonts/ |
Self-hosted Inter and JetBrains Mono woff2 files |
site-template/SETUP-PROMPT.md |
Full schema reference for site.json, mcp-tools.json, data flow |
python site-template/build_site.py --repo-root /path/to/tool-repo --out /tmp/tool-testOpen the generated index.html in a browser to verify. Repeat for at least one other tool repo to confirm the template works across different data shapes.
After modifying template.html.j2 or build_site.py, rebuild each affected tool repo locally:
for repo in Docker-Developer-Tools Home-Lab-Developer-Tools Steam-Cursor-Plugin Monday-Cursor-Plugin; do
python site-template/build_site.py --repo-root "$TOOLS_ROOT/$repo" --out "$TOOLS_ROOT/$repo/docs"
doneWhere $TOOLS_ROOT is the parent directory containing your checkouts of each tool repo. Then commit the updated docs/index.html in each repo.
- Add the field to
build_site.py- load it fromsite.jsonand pass it in the template context - Use the field in
template.html.j2with a Jinja2 conditional so existing repos without the field still render correctly - Document the field in
site-template/SETUP-PROMPT.md(schema table, example, and customization guide) - Add a default value to the scaffold's
site.json.j2template if applicable - Test with a repo that uses the field and one that doesn't
- Commit with
feat: add <field-name> support to site template
main is protected by an active ruleset (main protection). All contributions, including from the repo owner, must land through a pull request. Direct pushes, force pushes, and branch deletion are blocked. The bypass-actors list is empty.
- Required approvals: 0 (solo-maintainer repo).
- Merge method: squash merge only; merge commits and rebase merges are blocked.
- All 8 required status checks listed under CI checks must pass before merge is allowed.
Use descriptive branch names with a type prefix:
feat/add-tool-name- new registry entries or standardsfix/correct-registry-field- correctionschore/update-jinja2- dependency or CI changesdocs/improve-scaffold-docs- documentation improvements
Follow Conventional Commits:
feat: add kubernetes developer tools to registry
fix: correct homepage URL for steam-mcp
docs: clarify scaffold --license flag usage
chore: bump Jinja2 to 3.1.5
The meta-repo uses a VERSION file at the repo root as the single source of truth for its own version. When your PR lands a user-visible feature or bug fix, bump VERSION in the same PR.
Rules:
VERSIONcontains a single semver line, novprefix, LF line ending (1.6.1).- Any commit whose subject starts with
feat:orfix:(including scoped variants likefeat(registry):) requires aVERSIONbump in the same PR. Theversion-bump-checkCI job enforces this, and it is a required status check in the branch-protection ruleset, so a PR without the bump cannot be merged. chore:,docs:,ci:,refactor:,test:, andstyle:commits do not require a bump.- Bump kind is at your discretion and guided by semver: breaking behavior change to a published contract is major, new capability is minor, correction with no behavior change is patch.
- Escape hatch: add
[skip version]to the commit subject or body for workflow-only changes that slipped into afeat:/fix:subject. Use sparingly.
On merge to main, release.yml compares VERSION against the latest tag. If VERSION is ahead, it creates tag v<VERSION> and a GitHub Release. If they match, the workflow no-ops. If VERSION is lower, the workflow fails and refuses to downgrade.
This model applies to the meta-repo only. Tool repos in the ecosystem use the conventional-commit auto-bump model documented in standards/versioning.md.
Before submitting a PR, verify:
-
registry.jsonis valid JSON (runpython -c "import json; json.load(open('registry.json'))") - No em dashes or en dashes in any content (see
standards/writing-style.md) - No hardcoded credentials, tokens, business emails, or local filesystem paths
- If registry changed: run
python scripts/sync_from_registry.pyand commit the result -
python scripts/sync_from_registry.py --checkexits 0 - If standard added: both
standards/README.mdandREADME.mdtables are updated - If scaffold changed: dry-run test passes
- If any commit is
feat:orfix::VERSIONis bumped in the same PR (see Versioning section) - Commit messages follow conventional format and are
Signed-off-by:(see DCO section)
All PRs must pass these 8 required status checks (enforced by the main protection ruleset, not just advisory):
Validate registry.json- JSON schema and required fieldsValidate docs site-docs/index.htmlexistsValidate scaffold- Python syntax and scaffold dry-runRegistry sync check-scripts/sync_from_registry.py --checkexits 0Public-repo safety scan- no leaked emails, drive paths, unsafe DOM sinks, or committed secretsfeat/fix commits require VERSION bump- enforces the rule in the Versioning section, checking the PR title (the squash commit subject) as well as each commitCodeQL- security scan on Python codeRun drift_check tests- the full pytest suite undertests/
release.yml's Check VERSION vs latest tag runs on every push to main and will fail the release if VERSION is behind the latest tag. It is a post-merge guard, not a PR gate, so it is not in the required-contexts list.
Additional (non-required) checks run on most PRs: dependency review, release-drafter preview, Socket Security. These provide signal but do not gate merges.
- No em dashes. Use regular hyphens (-) or rewrite the sentence.
- No hardcoded credentials. Environment variables or config files only.
- Concise descriptions. No filler text or marketing language.
- Public readership. All content should make sense to external contributors.
- Consistent formatting. Use existing files as reference for Markdown structure.
All contributions must be signed off under the Developer Certificate of Origin 1.1. This is a lightweight way to certify that you wrote the contribution or have the right to submit it.
Add Signed-off-by: Your Name <your-email> to the end of every commit message. Git can do this automatically with the -s flag:
git commit -s -m "feat: add new standard"Your name and email must match your Git identity. Use a real name - pseudonyms are not accepted.
If you forget to sign off, amend the commit:
git commit --amend -s --no-edit
git push --force-with-leaseBy submitting a contribution to this repository, you certify that you have the right to do so under the Developer Certificate of Origin 1.1, and you grant TMHSDigital a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute your contribution under the project's current license (CC-BY-NC-ND-4.0) or any successor license chosen by the project.
This grant exists because CC-BY-NC-ND-4.0's "NoDerivatives" clause would otherwise prevent the project from accepting pull requests (every PR is a derivative). See standards/licensing.md for the full rationale.
The preferred enforcement is the built-in GitHub DCO App. Maintainers enable it from repo settings; no workflow is required. PRs with unsigned commits are blocked by the App's status check.
If the App is unavailable, a pinned fallback workflow can be added. Contributors do not need to do anything different - just sign off.
This project follows the Contributor Covenant Code of Conduct. By participating, you agree to uphold this code.