RepoPilotOpen in app →

github/choosealicense.com

A site to provide non-judgmental guidance on choosing a license for your open source project

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3w ago
  • 12 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 76% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/github/choosealicense.com)](https://repopilot.app/r/github/choosealicense.com)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/github/choosealicense.com on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: github/choosealicense.com

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/github/choosealicense.com shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 3w ago
  • 12 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 76% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live github/choosealicense.com repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/github/choosealicense.com.

What it runs against: a local clone of github/choosealicense.com — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in github/choosealicense.com | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch gh-pages exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 49 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>github/choosealicense.com</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of github/choosealicense.com. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/github/choosealicense.com.git
#   cd choosealicense.com
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of github/choosealicense.com and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "github/choosealicense.com(\\.git)?\\b" \\
  && ok "origin remote is github/choosealicense.com" \\
  || miss "origin remote is not github/choosealicense.com (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify gh-pages >/dev/null 2>&1 \\
  && ok "default branch gh-pages exists" \\
  || miss "default branch gh-pages no longer exists"

# 4. Critical files exist
test -f "_config.yml" \\
  && ok "_config.yml" \\
  || miss "missing critical file: _config.yml"
test -f "_data/rules.yml" \\
  && ok "_data/rules.yml" \\
  || miss "missing critical file: _data/rules.yml"
test -f "_data/meta.yml" \\
  && ok "_data/meta.yml" \\
  || miss "missing critical file: _data/meta.yml"
test -f "index.html" \\
  && ok "index.html" \\
  || miss "missing critical file: index.html"
test -f "_layouts/license.html" \\
  && ok "_layouts/license.html" \\
  || miss "missing critical file: _layouts/license.html"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 49 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~19d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/github/choosealicense.com"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

ChooseALicense.com is a Jekyll-based static site that catalogs and explains popular open source licenses through a curated, non-judgmental interface. It renders license metadata (stored as YAML front matter in _licenses/*.txt) into HTML pages and serves as the authoritative source that GitHub vendored into Licensee for license detection and the GitHub Licenses API. Jekyll site structure with three core directories: _licenses/ contains the license catalog (one .txt file per license with YAML front matter and full license text); _data/ holds metadata (fields.yml, rules.yml, meta.yml) that define common license properties; _includes/ and _layouts/ contain Liquid templates for rendering license pages and the homepage. Generated site is static HTML/CSS/JS with minimal JavaScript (8232 bytes, likely just Hint.css tooltips).

👥Who it's for

Open source project maintainers and contributors who need help selecting an appropriate license for their projects, plus GitHub's product team who use this repo's license catalog as the canonical reference for license detection, API responses, and repository license recommendations.

🌱Maturity & risk

Production-ready and actively maintained. The site powers GitHub's official license guidance, appears to have consistent CI/CD via GitHub Actions (test.yml workflow present), and is a long-standing GitHub-owned repository with deep integration into GitHub's license detection infrastructure. The codebase uses Jekyll (standard, proven SSG), Ruby testing via Rakefile, and RuboCop linting for code quality.

Low technical risk but high governance responsibility: this is a single-source-of-truth for license definitions that GitHub and Licensee depend on, so breaking changes to license YAML schemas could cascade. The repo uses Git submodules (.gitmodules present), which require careful --recursive cloning. No obvious dependency bloat (Bower/npm dependencies appear minimal and scoped to Hint.css tooltip library only). Risk is reputational rather than technical—license metadata must be accurate and legally defensible.

Active areas of work

The repo is in maintenance mode—actively monitoring and accepting license additions/updates via CONTRIBUTING.md guidelines, running tests on commits (GitHub Actions workflow present), and syncing changes upstream to Licensee for GitHub's infrastructure. No specific active feature development is evident, but the license catalog itself is being expanded as new OSS licenses emerge.

🚀Get running

git clone https://github.com/github/choosealicense.com.git --recursive
cd choosealicense.com
./script/bootstrap
./script/server

Then open http://localhost:4000 in a browser. The --recursive flag is critical because the repo uses Git submodules.

Daily commands:

./script/bootstrap     # Install Ruby gems and dependencies (requires cmake, make)
./script/server        # Start Jekyll dev server on localhost:4000

The bootstrap script handles dependency installation; see README for OS-specific cmake/make setup (Homebrew on macOS, apt-get on Linux).

🗺️Map of the codebase

  • _config.yml — Jekyll configuration that defines the site structure, collections (_licenses), and build output—essential for understanding how the license catalog is built and served.
  • _data/rules.yml — Defines comparison rules and license attributes (permissions, conditions, limitations) that power the interactive license chooser and comparison logic.
  • _data/meta.yml — License metadata registry used by Jekyll to render individual license pages and populate the site's core decision tree.
  • index.html — Main landing page and entry point for the license chooser interface; sets the tone and navigation for first-time visitors.
  • _layouts/license.html — Template that renders individual license pages using data from _licenses/*.txt files; critical for understanding how each license is presented.
  • assets/js/app.js — Client-side JavaScript for the interactive license chooser, filtering, and comparison—core UX logic.
  • CONTRIBUTING.md — Documents how to add new licenses and the selection criteria; essential for understanding scope and governance of the license catalog.

🛠️How to make changes

Add a New License

  1. Create a new license text file in the _licenses directory following the pattern _licenses/{spdx-id}.txt with the full license text (_licenses/new-license.txt)
  2. Add license metadata entry in _data/meta.yml with fields like title, description, spdx_id, and URL (_data/meta.yml)
  3. Add or update license attributes in _data/rules.yml defining its permissions, conditions, and limitations for comparison (_data/rules.yml)
  4. Submit PR for review against CONTRIBUTING.md criteria (must be popular, have permanent home, clearly defined terms, SPDX ID) (CONTRIBUTING.md)

Customize the License Chooser UI

  1. Edit the index.html to add or modify interactive elements, decision tree questions, or license filtering UI (index.html)
  2. Update assets/js/app.js to add new event handlers, filtering logic, or comparison behavior (assets/js/app.js)
  3. Modify assets/css/application.scss to style new UI elements or adjust responsive layout (assets/css/application.scss)

Modify License Display or Comparison Matrix

  1. Update _data/fields.yml to add or remove columns in the comparison matrix (_data/fields.yml)
  2. Adjust license attributes in _data/rules.yml to change how licenses are compared or displayed (_data/rules.yml)
  3. Edit _layouts/license.html to change the individual license page template and presentation (_layouts/license.html)
  4. Update _includes/license-overview.html to modify the license summary card component (_includes/license-overview.html)

🔧Why these technologies

  • Jekyll (Ruby static site generator) — Generates a fast, SEO-friendly static site from Markdown and YAML; integrates naturally with GitHub Pages for free hosting and CI/CD.
  • Jekyll Collections (_licenses directory) — Provides a clean, declarative way to catalog and iterate over 70+ license files, auto-generating individual license pages without boilerplate.
  • YAML data files (_data/*.yml) — Defines structured license metadata and comparison rules in a human-readable, version-controllable format accessible to both Jekyll templates and client-side JS.
  • Client-side JavaScript (app.js) — Enables interactive filtering, comparison, and chooser flow without backend dependencies; keeps site fully static and performant.
  • Hint.css (tooltip library) — Lightweight CSS tooltip library for providing contextual help on license attributes without adding JavaScript overhead.

⚖️Trade-offs already made

  • Fully static site with client-side interactivity instead of dynamic backend

    • Why: Simplifies deployment, security, and scalability; leverages GitHub Pages free hosting.
    • Consequence: All license data must be pre-baked into the HTML/JS at build time; cannot support real-time license updates without a full rebuild.
  • Single source of truth: license text in _licenses/*.txt files + metadata in YAML

    • Why: Reduces duplication and makes it easy to add licenses following a consistent pattern.
    • Consequence: Adding a license requires touching multiple files (text file + meta.yml + rules.yml); CI validation is needed to catch inconsistencies.
  • Pre-built HTML pages for each license rather than dynamic rendering

    • Why: Maximizes SEO, caching, and page load speed; each license is a first-class URL and can be indexed independently.
    • Consequence: License detail pages are generated at build time; cannot support live customization or conditional rendering based on query params.
  • YAML-based rules rather than a domain-specific DSL or JSON schema

    • Why: Readable by non-technical contributors; integrates naturally with Jekyll templating.
    • Consequence: Validation and schema enforcement require custom Rake tasks or GitHub Actions; less type safety than a compiled config format.

🚫Non-goals (don't propose these)

  • Not a license generator or legal tool—does not produce custom licenses or provide legal advice.
  • Does not support real-time license updates; all content changes require a rebuild and redeploy.
  • Does not authenticate users or provide personalized recommendations based on user history.
  • Does not integrate with code repositories directly; serves as a reference and guidance tool only.

🪤Traps & gotchas

  1. git clone --recursive is mandatory because the repo uses Git submodules (defined in .gitmodules); cloning without --recursive will leave dependencies missing. 2) Running ./script/bootstrap requires cmake and make installed system-wide; macOS users must use Homebrew, not just have Xcode CLT. 3) License YAML front matter is parsed strictly—missing required fields in _data/fields.yml will break rendering or fail CI tests. 4) The _licenses/ files are vendored into the separate Licensee gem; changes here must be coordinated or they won't appear in GitHub's license detection until Licensee is bumped. 5) Jekyll requires --recursive clone or git submodule update --init --recursive to fetch transitive dependencies.

🏗️Architecture

💡Concepts to learn

  • Jekyll Collections — The license catalog in _licenses/ is a Jekyll Collection, not individual pages; understanding collections is essential to grasping how Jekyll iterates over all licenses and generates pages with a shared template
  • YAML Front Matter — Every license file uses YAML front matter (the key-value metadata at the top of each _licenses/*.txt file) to define structured fields like permissions, conditions, and SPDX ID; this metadata drives both site rendering and GitHub's license detection
  • Liquid Templating — The site uses Liquid (Jekyll's template language) in _layouts/ and _includes/ to render license pages dynamically; understanding Liquid filters and loops is needed to modify how license data is displayed
  • Static Site Generation (SSG) — Jekyll pre-builds the entire site into static HTML/CSS/JS at build time; there is no backend server, which keeps choosealicense.com fast, secure, and trivial to deploy to GitHub Pages
  • SPDX License Identifiers — Each license in the catalog has an spdx_id field that maps to the Software Package Data Exchange standard identifier (e.g., 'MIT', 'Apache-2.0'); this enables machine-readable license detection across GitHub and Licensee
  • Git Submodules — The repo uses .gitmodules to manage dependencies; cloning without --recursive will fail to fetch transitive dependencies, a common gotcha for new contributors
  • licensee/licensee — The Ruby gem that GitHub uses for license detection and identification; consumes the license catalog from choosealicense.com as a vendored copy
  • spdx/license-list-data — Authoritative SPDX license registry maintained by Linux Foundation; choosealicense.com catalogs a curated subset and should stay in sync with SPDX identifiers
  • github/gitignore — Sibling GitHub project providing curated .gitignore templates; same philosophy of non-judgmental guidance for developer setup decisions
  • open-source/licenses — OpenJS Foundation's license guidance documentation; complements choosealicense.com for JavaScript ecosystem-specific licensing advice

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add automated validation tests for _licenses YAML frontmatter

The _licenses directory contains 50+ license files that each require specific YAML frontmatter fields (title, spdx-id, description, how, using, etc.). There's currently no automated test to validate that all licenses conform to the expected schema. This would catch missing fields, malformed data, or inconsistent formatting before they reach production.

  • [ ] Create new test file in test/ directory (check .github/workflows/test.yml for test runner)
  • [ ] Write Ruby tests using the same framework as existing tests to validate each _licenses/*.txt file has required YAML frontmatter fields
  • [ ] Validate spdx-id values match known SPDX identifiers
  • [ ] Add test step to .github/workflows/test.yml to run the new validation suite
  • [ ] Reference _data/fields.yml and _data/rules.yml to understand required fields per license

Add missing SEO metadata and schema.org structured data to _layouts/license.html

Individual license pages (rendered via _layouts/license.html) currently lack proper Open Graph tags, Twitter cards, and structured data markup. Since this is a high-traffic guidance site used for important licensing decisions, adding schema.org markup for CreativeWork/LegalDocument would improve SEO, shareability, and machine readability of license metadata across the web.

  • [ ] Update _layouts/license.html to include og:title, og:description, og:url, og:type meta tags
  • [ ] Add Twitter card meta tags (twitter:card, twitter:title, twitter:description)
  • [ ] Insert JSON-LD structured data block using schema.org/LegalDocument or schema.org/CreativeWork
  • [ ] Include license spdx-id, permissions, conditions from _data/rules.yml in structured data
  • [ ] Test output using OpenGraph debugger and Google's Rich Results Test

Create Rake task to validate license text files against official SPDX canonical texts

The _licenses directory contains license text files that should ideally match official SPDX canonical versions. Currently there's no automation to detect if license texts drift from official sources or to facilitate bulk updates. A Rake task (matching the existing Rakefile pattern) could validate checksums or diffs against SPDX repository, helping maintainers keep the license corpus accurate.

  • [ ] Add new Rake task to Rakefile that fetches official license texts from https://raw.githubusercontent.com/spdx/license-list-data/
  • [ ] For each _licenses/*.txt file, compare against corresponding SPDX canonical text
  • [ ] Report any differences or missing licenses in SPDX official list
  • [ ] Generate a report/manifest of validation results
  • [ ] Document usage in CONTRIBUTING.md under maintenance procedures

🌿Good first issues

  • Add missing SPDX metadata to existing licenses: review _licenses/*.txt files and verify all have correct spdx_id, source, and description fields matching official SPDX definitions; write a script or manually audit the catalog against https://spdx.org/licenses/.
  • Improve license comparison clarity: create a new Liquid template include that generates a side-by-side comparison of permissions/conditions for 2-3 common licenses (MIT vs Apache-2.0 vs GPL-3.0) to help users understand tradeoffs; add it to a new page or sidebar.
  • Expand JavaScript/CSS for accessibility: audit the Hint.css tooltips and license tables for keyboard navigation and screen reader support; the codebase has minimal JS (8232 bytes), making it a good first PR to add semantic ARIA labels and keyboard event handlers.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • ed8cbf2 — Merge pull request #1335 from github/misc-fixes (mlinksva)
  • f3b9912 — Apply suggestion from @Copilot (mlinksva)
  • eeead20 — Revert "wayback as rosenlaw.com appears to be expired" (mlinksva)
  • 9f60a8c — rubocop (mlinksva)
  • 39be3f4 — rubocop (mlinksva)
  • bd3f070 — wayback as rosenlaw.com appears to be expired (mlinksva)
  • 400bea6 — Choco moved to BSD-3-Clause https://github.com/chocoteam/choco-solver/discussions/1169 (mlinksva)
  • abad223 — Remove a subtle extra space in zlib license text (InvictusNavarchus)
  • b4442b3 — Merge pull request #1324 from github/desprite (mlinksva)
  • 21454b2 — rm unncessary class adjustment (mlinksva)

🔒Security observations

The codebase has moderate security concerns, primarily stemming from severely outdated build dependencies (Grunt 0.4.1 and node-sass 4.13.1) that contain known vulnerabilities. The Jekyll-based static site itself presents lower injection risks compared to dynamic applications, but vendoring of dependencies and lack of explicit security headers are notable gaps. Immediate action required: update build tools and implement dependency scanning in CI/CD. The project would benefit from moving away from vendored node_modules and leveraging modern package management with automated security updates.

  • High · Outdated npm dependency with known vulnerabilities — assets/vendor/hint.css/package.json - devDependencies.node-sass. The hint.css package (v2.7.0) uses node-sass v4.13.1, which is severely outdated and contains multiple known security vulnerabilities. Node-sass 4.x reached end-of-life and has unpatched CVEs related to arbitrary code execution and denial of service. Fix: Upgrade to node-sass v8.x or migrate to dart-sass (sass) which is actively maintained. Update all build tools to their latest versions.
  • High · Outdated Grunt build tools with security vulnerabilities — assets/vendor/hint.css/package.json - devDependencies (grunt and grunt-contrib-* packages). Grunt v0.4.1 (from ~0.4.1 specification) is extremely outdated and contains known vulnerabilities. The associated contrib plugins (grunt-contrib-concat, grunt-contrib-cssmin, grunt-contrib-watch) are also unmaintained. Fix: Migrate from Grunt to modern build tools like webpack, Vite, or esbuild. If Grunt is required, upgrade to the latest versions and audit all transitive dependencies.
  • Medium · Vendor dependencies checked into repository — assets/vendor/hint.css/ directory. The hint.css library is vendored directly in the repository under assets/vendor/hint.css/, including node_modules and build configuration. This makes it difficult to track and update security patches for transitive dependencies. Fix: Use a package manager (npm/yarn) with a lockfile instead of vendoring. Remove vendored node_modules and use npm install. Keep a Gemfile.lock or package-lock.json for reproducible builds.
  • Medium · Missing security headers configuration — _config.yml and deployment configuration. The Jekyll configuration (_config.yml) and .github/workflows/test.yml do not show explicit security headers (CSP, X-Frame-Options, X-Content-Type-Options, etc.) for the static site deployment. Fix: Add security headers via _config.yml Jekyll configuration, GitHub Pages settings, or a meta tag approach. Consider adding: Content-Security-Policy, X-Frame-Options: DENY, X-Content-Type-Options: nosniff.
  • Low · Missing dependency vulnerability scanning in CI/CD — .github/workflows/test.yml. The .github/workflows/test.yml does not appear to include automated dependency vulnerability scanning (no evidence of npm audit, Bundler audit, or OWASP Dependency-Check in provided structure). Fix: Add 'npm audit' or 'gem audit' step to the CI/CD pipeline. Consider using Dependabot for automated dependency updates and security alerts.
  • Low · No SBOM (Software Bill of Materials) generation — Repository root / CI/CD pipeline. The repository does not appear to generate or publish a Software Bill of Materials, making it difficult for users to identify supply chain risks. Fix: Add SBOM generation tools like cyclonedx-npm or syft to the build pipeline and publish results with releases.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · github/choosealicense.com — RepoPilot