[
  {
    "path": ".claude/settings.local.json",
    "content": "{\n  \"permissions\": {\n    \"allow\": [\n      \"mcp__plugin_context-mode_context-mode__ctx_batch_execute\",\n      \"mcp__plugin_context7_context7__resolve-library-id\",\n      \"mcp__plugin_context7_context7__query-docs\",\n      \"Bash(go:*)\",\n      \"Bash(./awesome-docker:*)\",\n      \"Bash(tmux send-keys:*)\",\n      \"Bash(tmux capture-pane:*)\",\n      \"Bash(tmux:*)\"\n    ]\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "*.css linguist-vendored\n*.* linguist-language=Markdown\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "* @veggiemonk @agebhar1 @dmitrytokarev @gesellix @mashb1t @moshloop @vegasbrianc @noteed\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at julien.bisconti (at) hotmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing to awesome-docker\n\nThanks for taking the time to contribute.\n\nThis repository is a curated list of Docker/container resources plus a Go-based maintenance CLI used by CI. Contributions are welcome for both content and tooling.\n\nPlease read and follow the [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n## What We Accept\n\n- New high-quality Docker/container-related projects\n- Fixes to descriptions, ordering, or categorization\n- Removal of broken, archived, deprecated, or duplicate entries\n- Improvements to the Go CLI and GitHub workflows\n\n## README Entry Rules\n\n- Use one link per entry.\n- Prefer GitHub project/repository URLs over marketing pages.\n- Keep entries alphabetically sorted within their section.\n- Keep descriptions concise and concrete.\n- Use `:yen:` for paid/commercial services.\n- Use `:ice_cube:` for stale projects (2+ years inactive).\n- Do not use `:skull:`; archived/deprecated projects should be removed.\n- Avoid duplicate links and redirect variants.\n\n## Local Validation\n\n```bash\n# Build CLI\nmake build\n\n# Validate README formatting and content\nmake lint\n\n# Run code tests (when touching Go code)\nmake test\n\n# Optional: full external checks (requires GITHUB_TOKEN)\n./awesome-docker check\n./awesome-docker validate\n```\n\n## Pull Request Expectations\n\n- Keep the PR focused to one logical change.\n- Explain what changed and why.\n- If adding entries, include the target category.\n- If removing entries, explain why (archived, broken, duplicate, etc.).\n- Fill in the PR template checklist.\n\n## Maintainer Notes\n\n- Changes should be reviewed before merge.\n- Prefer helping contributors improve a PR over silently rejecting it.\n- Keep `.github` documentation and workflows aligned with current tooling.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/add-a-project.md",
    "content": "---\nname: Add a project\nabout: Add a new project to the list\ntitle: \"add: [PROJECT_NAME] in [SECTION_NAME]\"\nlabels: pending-evaluation\nassignees: ''\n\n---\n\nCategory:\nRepository link:\nDescription (one sentence):\nAuthor:\nWhy this should be in the list:\nNotes (`:yen:` if relevant):\n\nOr directly write it:\n\n```markdown\n[REPO](https://github.com/AUTHOR/REPO) - DESCRIPTION.\n```\n"
  },
  {
    "path": ".github/MAINTENANCE.md",
    "content": "# Maintenance Guide\n\nThis guide describes how maintainers keep the list and automation healthy.\n\n## Automated Workflows\n\n### Pull Requests / Weekly QA (`pull_request.yml`)\n\n- Runs on pull requests and weekly on Saturday.\n- Builds the Go CLI and runs `./awesome-docker validate`.\n\n### Broken Links Report (`broken_links.yml`)\n\n- Runs weekly on Saturday and on manual trigger.\n- Executes `./awesome-docker check`.\n- Opens/updates a `broken-links` issue when problems are found.\n\n### Weekly Health Report (`health_report.yml`)\n\n- Runs weekly on Monday and on manual trigger.\n- Executes `./awesome-docker health` then `./awesome-docker report`.\n- Opens/updates a `health-report` issue.\n\n### Deploy to GitHub Pages (`deploy-pages.yml`)\n\n- Runs on pushes to `master` and manual trigger.\n- Builds website with `./awesome-docker build` and publishes `website/`.\n\n## Day-to-Day Commands\n\n```bash\n# Build CLI\nmake build\n\n# README lint/validation\nmake lint\n\n# Auto-fix formatting issues\n./awesome-docker lint --fix\n\n# Link checks and health checks (requires GITHUB_TOKEN)\nmake check\nmake health\nmake report\n```\n\n## Content Maintenance Policy\n\n- Remove archived/deprecated projects instead of tagging them.\n- Remove broken links that cannot be fixed.\n- Keep sections alphabetically sorted.\n- Keep descriptions short and actionable.\n\n## Suggested Review Cadence\n\n### Weekly\n\n- Triage open `broken-links` and `health-report` issues.\n- Merge straightforward quality PRs.\n\n### Monthly\n\n- Review sections for stale/duplicate entries.\n- Re-run `check` and `health` manually if needed.\n\n### Quarterly\n\n- Review `.github` docs and templates for drift.\n- Confirm workflows still match repository tooling and policies.\n\n## Contributor Support\n\nWhen requesting PR changes, be explicit and actionable:\n\n- point to section/order problems,\n- explain why a link should be removed,\n- suggest exact wording when description quality is the issue.\n\n---\n\nLast updated: 2026-02-27\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Summary\n\nDescribe what changed and why.\n\n## Scope\n\n- [ ] README entries/content\n- [ ] Go CLI/tooling\n- [ ] GitHub workflows or `.github` docs\n\n## If This PR Adds/Edits README Entries\n\n- Category/section touched:\n- New or updated project links:\n\n## Validation\n\n- [ ] `make lint`\n- [ ] `make test` (if Go code changed)\n- [ ] `./awesome-docker check` (if `GITHUB_TOKEN` available)\n\n## Contributor Checklist\n\n- [ ] Entries are alphabetically ordered in their section\n- [ ] Links point to project repositories (no duplicates or redirects)\n- [ ] Descriptions are concise and specific\n- [ ] Archived/deprecated projects were removed instead of tagged\n- [ ] Used `:yen:` only when applicable\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  # Enable version updates for Go modules\n  - package-ecosystem: \"gomod\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n\n  # Enable version updates for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/broken_links.yml",
    "content": "name: Broken Links Report\n\non:\n  schedule:\n    - cron: \"0 2 * * 6\"\n  workflow_dispatch:\n\nconcurrency:\n  group: broken-links-${{ github.ref }}\n  cancel-in-progress: false\n\njobs:\n  check-links:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n      issues: write\n\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6\n\n      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # ratchet:actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n\n      - name: Build\n        run: go build -o awesome-docker ./cmd/awesome-docker\n\n      - name: Run Link Check\n        id: link_check\n        run: ./awesome-docker ci broken-links --issue-file broken_links_issue.md --github-output \"$GITHUB_OUTPUT\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Create/Update Issue for Broken Links\n        if: steps.link_check.outputs.has_errors == 'true'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # ratchet:actions/github-script@v8\n        with:\n          script: |\n            const fs = require('fs');\n            const issueBody = fs.readFileSync('broken_links_issue.md', 'utf8');\n\n            const issues = await github.rest.issues.listForRepo({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              state: 'open',\n              labels: 'broken-links',\n              per_page: 1\n            });\n\n            if (issues.data.length > 0) {\n              await github.rest.issues.update({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                issue_number: issues.data[0].number,\n                body: issueBody\n              });\n            } else {\n              await github.rest.issues.create({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                title: 'Broken Links Detected',\n                body: issueBody,\n                labels: ['broken-links', 'bug']\n              });\n            }\n\n      - name: Close Issue if No Errors\n        if: steps.link_check.outputs.has_errors == 'false'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # ratchet:actions/github-script@v8\n        with:\n          script: |\n            const issues = await github.rest.issues.listForRepo({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              state: 'open',\n              labels: 'broken-links',\n              per_page: 1\n            });\n            if (issues.data.length > 0) {\n              await github.rest.issues.update({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                issue_number: issues.data[0].number,\n                state: 'closed',\n                state_reason: 'completed'\n              });\n            }\n"
  },
  {
    "path": ".github/workflows/deploy-pages.yml",
    "content": "name: Deploy to GitHub Pages\n\non:\n  push:\n    branches:\n      - master\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6\n\n      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # ratchet:actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n\n      - name: Build CLI\n        run: go build -o awesome-docker ./cmd/awesome-docker\n\n      - name: Build website\n        run: make website\n\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # ratchet:actions/upload-pages-artifact@v4\n        with:\n          path: ./website\n\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # ratchet:actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/health_report.yml",
    "content": "name: Weekly Health Report\n\non:\n  schedule:\n    - cron: \"0 9 * * 1\"\n  workflow_dispatch:\n\nconcurrency:\n  group: health-report-${{ github.ref }}\n  cancel-in-progress: false\n\njobs:\n  health-check:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n      issues: write\n\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6\n\n      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # ratchet:actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n\n      - name: Build\n        run: go build -o awesome-docker ./cmd/awesome-docker\n\n      - name: Run Health + Report\n        id: report\n        run: ./awesome-docker ci health-report --issue-file health_report.txt --github-output \"$GITHUB_OUTPUT\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Create/Update Issue with Health Report\n        if: steps.report.outputs.has_report == 'true'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # ratchet:actions/github-script@v8\n        with:\n          script: |\n            const fs = require('fs');\n            const report = fs.readFileSync('health_report.txt', 'utf8');\n            const issueBody = report;\n\n            const issues = await github.rest.issues.listForRepo({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              state: 'open',\n              labels: 'health-report',\n              per_page: 1\n            });\n\n            if (issues.data.length > 0) {\n              await github.rest.issues.update({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                issue_number: issues.data[0].number,\n                body: issueBody\n              });\n            } else {\n              await github.rest.issues.create({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                title: 'Weekly Health Report - Repository Maintenance Needed',\n                body: issueBody,\n                labels: ['health-report', 'maintenance']\n              });\n            }\n"
  },
  {
    "path": ".github/workflows/pull_request.yml",
    "content": "name: Pull Requests / Weekly QA\n\non:\n  pull_request:\n    branches:\n      - master\n  schedule:\n    - cron: \"0 0 * * 6\"\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6\n\n      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # ratchet:actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n\n      - name: Build\n        run: go build -o awesome-docker ./cmd/awesome-docker\n\n      - name: Build website\n        run: ./awesome-docker build\n\n      - name: Validate\n        run: ./awesome-docker validate\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "logs\n*.log\nnpm-debug.log*\nbuild\nnode_modules\n.cache\ndist\nwebsite/index.html\nwebsite/table.html\n\n.idea\n**/.DS_Store\n.worktrees\n\n# Go\n/awesome-docker\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Agent Guidelines for awesome-docker\n\n## Commands\n- Build CLI: `make build` (or `go build -o awesome-docker ./cmd/awesome-docker`)\n- Rebuild from scratch: `make rebuild`\n- Show local workflows: `make help`\n- Format Go code: `make fmt`\n- Run tests: `make test` (runs `go test ./internal/... -v`)\n- Race tests: `make test-race`\n- Lint README rules: `make lint` (runs `./awesome-docker lint`)\n- Auto-fix lint issues: `make lint-fix`\n- Check links: `make check` (runs `./awesome-docker check`; `GITHUB_TOKEN` enables GitHub repo checks)\n- PR-safe link checks: `make check-pr`\n- PR validation: `make validate` (lint + external link checks in PR mode)\n- Build website: `make website` (generates `website/index.html` from `README.md`)\n- Health scoring: `make health` (requires `GITHUB_TOKEN`, refreshes `config/health_cache.yaml`)\n- Print health report (Markdown): `make report`\n- Print health report (JSON): `make report-json` or `./awesome-docker report --json`\n- Generate report files: `make report-file` (`HEALTH_REPORT.md`) and `make report-json-file` (`HEALTH_REPORT.json`)\n- Maintenance shortcut: `make workflow-maint` (health + JSON report file)\n\n## Architecture\n- **Main content**: `README.md` (curated Docker/container resources)\n- **CLI entrypoint**: `cmd/awesome-docker/main.go` (Cobra commands)\n- **Core packages**:\n  - `internal/parser` - parse README sections and entries\n  - `internal/linter` - alphabetical/order/format validation + autofix\n  - `internal/checker` - HTTP and GitHub link checks\n  - `internal/scorer` - repository health scoring and report generation\n  - `internal/cache` - exclude list and health cache read/write\n  - `internal/builder` - render README to website HTML from template\n- **Config**:\n  - `config/exclude.yaml` - known link-check exclusions\n  - `config/website.tmpl.html` - HTML template for site generation\n  - `config/health_cache.yaml` - persisted health scoring cache\n- **Generated outputs**:\n  - `awesome-docker` - compiled CLI binary\n  - `website/index.html` - generated website\n  - `HEALTH_REPORT.md` - generated markdown report\n  - `HEALTH_REPORT.json` - generated JSON report\n\n## Code Style\n- **Language**: Go\n- **Formatting**: Keep code `gofmt`-clean\n- **Testing**: Add/adjust table-driven tests in `internal/*_test.go` for behavior changes\n- **Error handling**: Return wrapped errors (`fmt.Errorf(\"context: %w\", err)`) from command handlers\n- **CLI conventions**: Keep command behavior consistent with existing Cobra commands (`lint`, `check`, `health`, `build`, `report`, `validate`)\n\n## CI/Automation\n- **PR + weekly validation**: `.github/workflows/pull_request.yml`\n  - Triggers on pull requests to `master` and weekly schedule\n  - Builds Go CLI and runs `./awesome-docker validate`\n- **Weekly broken links issue**: `.github/workflows/broken_links.yml`\n  - Runs `./awesome-docker check`\n  - Opens/updates `broken-links` issue when failures are found\n- **Weekly health report issue**: `.github/workflows/health_report.yml`\n  - Runs `./awesome-docker health` then `./awesome-docker report`\n  - Opens/updates `health-report` issue\n- **GitHub Pages deploy**: `.github/workflows/deploy-pages.yml`\n  - On push to `master`, builds CLI, runs `./awesome-docker build`, deploys `website/`\n\n## Makefile Workflow\n- The `Makefile` models file dependencies for generated artifacts (`awesome-docker`, `website/index.html`, `config/health_cache.yaml`, `HEALTH_REPORT.md`, `HEALTH_REPORT.json`).\n- Prefer `make` targets over ad-hoc command sequences so dependency and regeneration behavior stays consistent.\n- Use:\n  - `make workflow-dev` for local iteration\n  - `make workflow-pr` before opening/updating a PR\n  - `make workflow-maint` for health/report maintenance\n  - `make workflow-ci` for CI-equivalent local checks\n\n## Content Guidelines (from CONTRIBUTING.md)\n- Use one link per entry\n- Prefer project/repository URLs over marketing pages\n- Keep entries alphabetically ordered within each section\n- Keep descriptions concise and concrete\n- Use `:yen:` only for paid/commercial services\n- Use `:ice_cube:` for stale projects (2+ years inactive)\n- Remove archived/deprecated projects instead of tagging them\n- Avoid duplicate links and redirect variants\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "Makefile",
    "content": "SHELL := /bin/bash\n\nBINARY ?= awesome-docker\nGO ?= go\nCMD_PACKAGE := ./cmd/awesome-docker\nINTERNAL_PACKAGES := ./internal/...\nWEBSITE_OUTPUT := website/index.html\nHEALTH_CACHE := config/health_cache.yaml\nHEALTH_REPORT_MD := HEALTH_REPORT.md\nHEALTH_REPORT_JSON := HEALTH_REPORT.json\n\nGO_SOURCES := $(shell find cmd internal -type f -name '*.go')\nBUILD_INPUTS := $(GO_SOURCES) go.mod go.sum\nWEBSITE_INPUTS := README.md config/website.tmpl.html\nHEALTH_INPUTS := README.md config/exclude.yaml\n\n.DEFAULT_GOAL := help\n\n.PHONY: help \\\n\tbuild rebuild clean \\\n\tfmt test test-race \\\n\tlint lint-fix check check-pr validate website \\\n\tguard-github-token health health-cache \\\n\treport report-json report-file report-json-file health-report \\\n\tworkflow-dev workflow-pr workflow-maint workflow-ci\n\nhelp: ## Show the full local workflow and available targets\n\t@echo \"awesome-docker Makefile\"\n\t@echo\n\t@echo \"Workflows:\"\n\t@echo \"  make workflow-dev    # local iteration (fmt + test + lint + check-pr + website)\"\n\t@echo \"  make workflow-pr     # recommended before opening/updating a PR\"\n\t@echo \"  make workflow-maint  # repository maintenance (health + JSON report)\"\n\t@echo \"  make workflow-ci     # CI-equivalent checks\"\n\t@echo\n\t@echo \"Core targets:\"\n\t@echo \"  make build           # build CLI binary\"\n\t@echo \"  make test            # run internal Go tests\"\n\t@echo \"  make lint            # validate README formatting/content rules\"\n\t@echo \"  make check           # check links (uses GITHUB_TOKEN when set)\"\n\t@echo \"  make validate        # run PR validation (lint + check --pr)\"\n\t@echo \"  make website         # generate website/index.html\"\n\t@echo \"  make report-file     # generate HEALTH_REPORT.md\"\n\t@echo \"  make report-json-file# generate HEALTH_REPORT.json\"\n\t@echo \"  make health          # refresh health cache (requires GITHUB_TOKEN)\"\n\t@echo \"  make report          # print markdown health report\"\n\t@echo \"  make report-json     # print full JSON health report\"\n\t@echo\n\t@echo \"Generated artifacts:\"\n\t@echo \"  $(BINARY)\"\n\t@echo \"  $(WEBSITE_OUTPUT)\"\n\t@echo \"  $(HEALTH_CACHE)\"\n\t@echo \"  $(HEALTH_REPORT_MD)\"\n\t@echo \"  $(HEALTH_REPORT_JSON)\"\n\n$(BINARY): $(BUILD_INPUTS)\n\t$(GO) build -o $(BINARY) $(CMD_PACKAGE)\n\nbuild: $(BINARY) ## Build CLI binary\n\nrebuild: clean build ## Rebuild from scratch\n\nclean: ## Remove generated binary\n\trm -f $(BINARY) $(HEALTH_REPORT_MD) $(HEALTH_REPORT_JSON)\n\nfmt: ## Format Go code\n\t$(GO) fmt ./...\n\ntest: ## Run internal unit tests\n\t$(GO) test $(INTERNAL_PACKAGES) -v\n\ntest-race: ## Run internal tests with race detector\n\t$(GO) test $(INTERNAL_PACKAGES) -race\n\nlint: build ## Validate README formatting/content rules\n\t./$(BINARY) lint\n\nlint-fix: build ## Auto-fix lint issues when possible\n\t./$(BINARY) lint --fix\n\ncheck: build ## Check links (GitHub checks enabled when GITHUB_TOKEN is set)\n\t./$(BINARY) check\n\ncheck-pr: build ## Check links in PR mode (external links only)\n\t./$(BINARY) check --pr\n\nvalidate: build ## Run PR validation (lint + check --pr)\n\t./$(BINARY) validate\n\n$(WEBSITE_OUTPUT): $(BINARY) $(WEBSITE_INPUTS)\n\t./$(BINARY) build\n\nwebsite: $(WEBSITE_OUTPUT) ## Generate website from README\n\nguard-github-token:\n\t@if [ -z \"$$GITHUB_TOKEN\" ]; then \\\n\t\techo \"GITHUB_TOKEN is required for this target.\"; \\\n\t\techo \"Set it with: export GITHUB_TOKEN=<token>\"; \\\n\t\texit 1; \\\n\tfi\n\n$(HEALTH_CACHE): guard-github-token $(BINARY) $(HEALTH_INPUTS)\n\t./$(BINARY) health\n\nhealth-cache: $(HEALTH_CACHE) ## Update config/health_cache.yaml\n\nhealth: ## Refresh health cache from GitHub metadata\n\t@$(MAKE) --no-print-directory -B health-cache\n\nreport: build ## Print markdown health report from cache\n\t./$(BINARY) report\n\nreport-json: build ## Print full health report as JSON\n\t./$(BINARY) report --json\n\n$(HEALTH_REPORT_MD): $(BINARY) $(HEALTH_CACHE)\n\t./$(BINARY) report > $(HEALTH_REPORT_MD)\n\nreport-file: $(HEALTH_REPORT_MD) ## Generate HEALTH_REPORT.md from cache\n\n$(HEALTH_REPORT_JSON): $(BINARY) $(HEALTH_CACHE)\n\t./$(BINARY) report --json > $(HEALTH_REPORT_JSON)\n\nreport-json-file: $(HEALTH_REPORT_JSON) ## Generate HEALTH_REPORT.json from cache\n\nhealth-report: health report-file ## Refresh health cache then generate HEALTH_REPORT.md\n\nbrowse: build ## Launch interactive TUI browser\n\t./$(BINARY) browse\n\nworkflow-dev: fmt test lint check-pr website ## Full local development workflow\n\nworkflow-pr: fmt test validate ## Recommended workflow before opening a PR\n\nworkflow-maint: health report-json-file ## Weekly maintenance workflow\n\nworkflow-ci: test validate ## CI-equivalent validation workflow\n\nupdate-ga:\n\tratchet upgrade .github/workflows/*\n\nupdate-go:\n\tgo get -u go@latest\n\tgo get -u ./...\n\tgo mod tidy \n"
  },
  {
    "path": "README.md",
    "content": "# Awesome Docker [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)][sindresorhus] [![Track Awesome List](https://www.trackawesomelist.com/badge.svg)](https://www.trackawesomelist.com/veggiemonk/awesome-docker/)[![Last Commit](https://img.shields.io/github/last-commit/veggiemonk/awesome-docker)](https://github.com/veggiemonk/awesome-docker/commits/main)<!-- omit in toc -->\n\n> A curated list of Docker resources and projects\n\nIf you would like to contribute, please read [CONTRIBUTING.md][contributing] first.\nIt contains a lot of tips and guidelines to help keep things organized.\nJust click [README.md][editreadme] to submit a [pull request][editreadme].\nIf this list is not complete, you can [contribute][editreadme] to make it so. Here is a great video tutorial to learn how to [contribute on Github](https://egghead.io/lessons/javascript-identifying-how-to-contribute-to-an-open-source-project-on-github).\n\n> **Please**, help organize these resources so that they are _easy to find_ and _understand_ for newcomers. See how to **[Contribute][contributing]** for tips!\n\n**_If you see a link here that is not (any longer) a good fit, you can fix it by submitting a [pull request][editreadme] to improve this file. Thank you!_**\n\nThe creators and maintainers of this list do not receive any form of payment to accept a change made by any contributor. This page is not an official Docker product in any way. It is a list of links to projects and is maintained by volunteers. Everybody is welcome to contribute. The goal of this repo is to index open-source projects, not to advertise for profit.\n\n# Contents <!-- omit in toc -->\n\n<!-- TOC -->\n\n- [Legend](#legend)\n- [What is Docker](#what-is-docker)\n- [Where to start](#where-to-start)\n- [Where to start (Windows)](#where-to-start-windows)\n- [Projects](#projects)\n  - [Container Operations](#container-operations)\n    - [Container Composition](#container-composition)\n    - [Deployment and Infrastructure](#deployment-and-infrastructure)\n    - [Monitoring](#monitoring)\n    - [Networking](#networking)\n    - [Orchestration](#orchestration)\n    - [PaaS](#paas)\n    - [Reverse Proxy](#reverse-proxy)\n    - [Runtime](#runtime)\n    - [Security](#security)\n    - [Service Discovery](#service-discovery)\n    - [Volume Management / Data](#volume-management--data)\n    - [User Interface](#user-interface)\n      - [IDE integrations](#ide-integrations)\n      - [Desktop](#desktop)\n      - [Terminal](#terminal)\n        - [Terminal UI](#terminal-ui)\n        - [CLI tools](#cli-tools)\n        - [Other](#other)\n      - [Web](#web)\n  - [Docker Images](#docker-images)\n    - [Base Tools](#base-tools)\n    - [Builder](#builder)\n    - [Dockerfile](#dockerfile)\n    - [Linter](#linter)\n    - [Metadata](#metadata)\n    - [Registry](#registry)\n  - [Development with Docker](#development-with-docker)\n    - [API Client](#api-client)\n    - [CI/CD](#cicd)\n    - [Development Environment](#development-environment)\n    - [Garbage Collection](#garbage-collection)\n    - [Serverless](#serverless)\n    - [Testing](#testing)\n    - [Wrappers](#wrappers)\n  - [Services based on Docker (mostly :yen:)](#services-based-on-docker-mostly-yen)\n    - [CI Services](#ci-services)\n    - [CaaS](#caas)\n    - [Monitoring Services](#monitoring-services)\n- [Useful Resources](#useful-resources)\n  - [Awesome Lists](#awesome-lists)\n  - [Demos and Examples](#demos-and-examples)\n  - [Good Tips](#good-tips)\n  - [Raspberry Pi \\& ARM](#raspberry-pi--arm)\n  - [Security](#security-1)\n  - [Videos](#videos)\n- [Communities and Meetups](#communities-and-meetups)\n  - [Brazilian](#brazilian)\n  - [English](#english)\n  - [Russian](#russian)\n  - [Spanish](#spanish)\n  - [Stargazers over time](#stargazers-over-time)\n\n<!-- /TOC -->\n\n# Legend\n\n-   Monetized :yen:\n-   Stale (2+ years inactive) :ice_cube:\n\n# What is Docker\n\n> Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications. Consisting of Docker Engine, a portable, lightweight runtime and packaging tool, and Docker Hub, a cloud service for sharing applications and automating workflows, Docker enables apps to be quickly assembled from components and eliminates the friction between development, QA, and production environments. As a result, IT can ship faster and run the same app, unchanged, on laptops, data center VMs, and any cloud.\n\n_Source:_ [What is Docker](https://www.docker.com/why-docker/)\n\n# Where to start\n\n-   [Benefits of using Docker](https://semaphore.io/blog/docker-benefits) for development and delivery, with a practical roadmap for adoption.\n- [Bootstrapping Microservices](https://www.manning.com/books/bootstrapping-microservices-with-docker-kubernetes-and-terraform) - A practical and project-based guide to building applications with microservices, starts by building a Docker image for a single microservice and publishing it to a private container registry, finishes by deploying a complete microservices application to a production Kubernetes cluster.\n-   [Docker Curriculum](https://github.com/prakhar1989/docker-curriculum): A comprehensive tutorial for getting started with Docker. Teaches how to use Docker and deploy dockerized apps on AWS with Elastic Beanstalk and Elastic Container Service.\n-   [Docker Documentation](https://docs.docker.com/): the official documentation.\n-   [Docker for beginners](https://github.com/groda/big_data/blob/master/docker_for_beginners.md): A tutorial for beginners who need to learn the basics of Docker—from \"Hello world!\" to basic interactions with containers, with simple explanations of the underlying concepts.\n-   [Docker for novices](https://www.youtube.com/watch?v=xsjSadjKXns) An introduction to Docker for developers and testers who have never used it. (Video 1h40, recorded linux.conf.au 2019 — Christchurch, New Zealand) by Alex Clews.\n\n-   [Docker katas](https://github.com/eficode-academy/docker-katas) A series of labs that will take you from \"Hello Docker\" to deploying a containerized web application to a server.\n-   [Docker simplified in 55 seconds](https://www.youtube.com/watch?v=vP_4DlOH1G4): An animated high-level introduction to Docker. Think of it as a visual tl;dr that makes it easier to dive into more complex learning materials.\n-   [Docker Training](https://training.mirantis.com) :yen:\n-   [Dockerlings](https://github.com/furkan/dockerlings): Learn docker from inside your terminal, with a modern TUI and bite sized exercises (by [furkan](https://github.com/furkan))\n\n-   [Introduction à Docker](https://blog.stephane-robert.info/docs/conteneurs/moteurs-conteneurs/docker/) A dedicated section to master Docker on a French site about DevSecOps: From the basics to best practices, including optimizing, securing your containers...\n-   [Learn Docker](https://github.com/dwyl/learn-docker): step-by-step tutorial and more resources (video, articles, cheat sheets) by [dwyl](https://github.com/dwyl)\n- [Learn Docker (Visually)](https://pagertree.com/learn/docker/overview) - A beginner-focused high-level overview of all the major components of Docker and how they fit together. Lots of high-quality images, examples, and resources.\n-   [Play With Docker](https://training.play-with-docker.com/): PWD is a great way to get started with Docker from beginner to advanced users. Docker runs directly in your browser.\n-   [Practical Guide about Docker Commands in Spanish](https://github.com/brunocascio/docker-espanol) This Spanish guide contains the use of basic docker commands with real life examples.\n-   [Setting Python Development Environment with VScode and Docker](https://github.com/RamiKrispin/vscode-python): A step-by-step tutorial for setting up a dockerized Python development environment with VScode, Docker, and the Dev Container extension.\n-   [The Docker Handbook](https://docker-handbook.farhan.dev/) An open-source book that teaches you the fundamentals, best practices and some intermediate Docker functionalities. The book is hosted on [fhsinchy/the-docker-handbook](https://github.com/fhsinchy/the-docker-handbook) and the projects are hosted on [fhsinchy/docker-handbook-projects](https://github.com/fhsinchy/docker-handbook-projects) repository.\n\n**Cheatsheets** by\n\n-   [eon01](https://github.com/eon01/DockerCheatSheet)\n-   [dimonomid](https://github.com/dimonomid/docker-quick-ref) (PDF)\n-   [JensPiegsa](https://github.com/JensPiegsa/docker-cheat-sheet)\n-   [wsargent](https://github.com/wsargent/docker-cheat-sheet) (Most popular)\n\n# Where to start (Windows)\n\n-   [Docker on Windows behind a firewall](https://toedter.com/2015/05/11/docker-on-windows-behind-a-firewall/) by [kaitoedter](https://twitter.com/kaitoedter)\n- [Docker Reference Architecture: Modernizing Traditional .NET Framework Applications](https://docs.mirantis.com/containers/v3.0/dockeree-ref-arch/app-dev/modernize-dotnet-apps.html) - You will learn to identify the types of .NET Framework applications that are good candidates for containerization, the \"lift-and-shift\" approach to containerization.\n-   [Docker with Microsoft SQL 2016 + ASP.NET](https://blog.alexellis.io/docker-does-sql2016-aspnet/) Demonstration running ASP.NET and SQL Server workloads in Docker\n-   [Exploring ASP.NET Core with Docker in both Linux and Windows Containers](https://www.hanselman.com/blog/exploring-aspnet-core-with-docker-in-both-linux-and-windows-containers) Running ASP.NET Core apps in Linux and Windows containers, using [Docker for Windows][docker-for-windows]\n-   [Running a Legacy ASP.NET App in a Windows Container](https://blog.sixeyed.com/dockerizing-nerd-dinner-part-1-running-a-legacy-asp-net-app-in-a-windows-container/) Steps for Dockerizing a legacy ASP.NET app and running as a Windows container\n- [Windows Containers and Docker: The 101](https://www.youtube.com/watch?v=N7SG2wEyQtM) - A 20-minute overview, using Docker to run PowerShell, ASP.NET Core and ASP.NET apps.\n-   [Windows Containers Quick Start](https://learn.microsoft.com/en-us/virtualization/windowscontainers/about/) Overview of Windows containers, drilling down to Quick Starts for Windows 10 and Windows Server 2016\n\n---\n\n# Projects\n\n-   Moby = open source development\n-   Docker CE = free product release based on Moby\n-   Docker EE = commercial product release based on Docker CE.\n\n> Docker EE is on the same code base as Docker CE, so also built from Moby, with commercial components added, such as \"docker data center / universal control plane\"\n\n-   [Moby](https://github.com/moby/moby)\n-   [Docker Images](https://hub.docker.com)\n-   [Docker Compose](https://github.com/docker/compose/) (Define and run multi-container applications with Docker)\n-   [Docker Registry][distribution] (The Docker toolset to pack, ship, store, and deliver content)\n\n## Container Operations\n\n### Container Composition\n\n- [Capitan](https://github.com/byrnedo/capitan) :ice_cube: - Composable docker orchestration with added scripting support by [byrnedo].\n- [Composerize](https://github.com/magicmark/composerize) - Convert docker run commands into docker-compose files.\n- [crowdr](https://github.com/polonskiy/crowdr) :ice_cube: - Tool for managing multiple Docker containers (`docker-compose` alternative).\n- [ctk](https://github.com/ctk-hq/ctk) - Visual composer for container based workloads. By [corpulent](https://github.com/corpulent).\n- [docker-config-update](https://github.com/sudo-bmitch/docker-config-update) :ice_cube: - Utility to update docker configs and secrets for deploying in a compose file.\n- [elsy](https://github.com/cisco/elsy) :ice_cube: - An opinionated, multi-language, build tool based on Docker and Docker Compose.\n- [habitus](https://github.com/cloud66-oss/habitus) :ice_cube: - A Build Flow Tool for Docker.\n- [kompose](https://github.com/kubernetes/kompose) - Go from Docker Compose to Kubernetes.\n- [LLM Harbor](https://github.com/av/harbor) - A CLI and companion app to effortlessly run LLM backends, APIs, frontends, and services with one command. By [av](https://github.com/av).\n- [plash](https://github.com/ihucos/plash) - A container run and build engine - runs inside docker.\n- [podman-compose](https://github.com/containers/podman-compose) - A script to run docker-compose.yml using podman.\n-   [Smalte](https://github.com/roquie/smalte) – Dynamically configure applications that require static configuration in docker container. By [roquie](https://github.com/roquie)\n- [Stitchocker](https://github.com/alexaandrov/stitchocker) - A lightweight and fast command line utility for conveniently grouping your docker-compose multiple container services. By [alexaandrov](https://github.com/alexaandrov).\n\n### Deployment and Infrastructure\n\n- [awesome-stacks](https://github.com/ethibox/awesome-stacks) - Deploy 150+ open-source web apps with one Docker command.\n- [blackfish](https://gitlab.com/blackfish/blackfish) - A CoreOS VM to build swarm clusters for Dev & Production.\n- [BosnD](https://gitlab.com/n0r1sk/bosnd) - BosnD, the boatswain daemon - A dynamic configuration file writer & service reloader for dynamically changing container environments.\n- [Clocker](https://github.com/brooklyncentral/clocker) :ice_cube: - Clocker creates and manages a Docker cloud infrastructure. Clocker supports single-click deployments and runtime management of multi-node applications that run as containers distributed across multiple hosts, on both Docker and Marathon. It leverages [Calico][calico] and [Weave][weave] for networking and [Brooklyn](https://brooklyn.apache.org/) for application blueprints. By [brooklyncentral](https://github.com/brooklyncentral).\n- [Conduit](https://github.com/ehazlett/conduit) :ice_cube: - Experimental deployment system for Docker.\n- [depcon](https://github.com/ContainX/depcon) :ice_cube: - Depcon is written in Go and allows you to easily deploy Docker containers to Apache Mesos/Marathon, Amazon ECS and Kubernetes. By [ContainX][containx].\n- [docker-to-iac](https://github.com/deploystackio/docker-to-iac) - Translate docker run and commit into Infrastructure as Code templates for AWS, Render.com and DigitalOcean.\n- [gitkube](https://github.com/hasura/gitkube) :ice_cube: - Gitkube is a tool for building and deploying docker images on Kubernetes using `git push`. By [Hasura](https://github.com/hasura/).\n- [Grafeas](https://github.com/grafeas/grafeas) - A common API for metadata about containers, from image and build details to security vulnerabilities. By [grafeas](https://github.com/grafeas).\n- [swarm-ansible](https://github.com/LombardiDaniel/swarm-ansible?tab=readme-ov-file) - Swarm-Ansible bootstraps a production-ready swarm cluster using ansible. Comes with tools to automate CI, help monitoring and traefik pre-configured for SSL certificates and simple-auth. Comes with a private registry and more!.\n- [SwarmManagement](https://github.com/hansehe/SwarmManagement) - Swarm Management is a python application, installed with pip. The application makes it easy to manage a Docker Swarm by configuring a single yaml file describing which stacks to deploy, and which networks, configs or secrets to create.\n- [werf](https://github.com/werf/werf) - Werf is a CI/CD tool for building Docker images efficiently and deploying them to Kubernetes using GitOps.\n\n### Monitoring\n\n- [ADRG](https://github.com/jaldertech/adrg) - Dynamic Docker resource governor using cgroups v2 to manage system load.\n- [Autoheal](https://github.com/willfarrell/docker-autoheal) - Monitor and restart unhealthy docker containers automatically.\n- [cAdvisor](https://github.com/google/cadvisor) - Analyzes resource usage and performance characteristics of running containers.\n- [Checkmate](https://github.com/bluewave-labs/checkmate) - Checkmate is an open-source, self-hosted tool designed to track and monitor server hardware, uptime, response times, and incidents in real-time with beautiful visualizations.\n- [DLIA](https://github.com/zorak1103/dlia) - DLIA is an AI-powered Docker log monitoring agent that uses Large Language Models (LLMs) to intelligently analyze container logs, detect anomalies, and provide contextual insights over time. By [zorak1103](https://github.com/zorak1103).\n- [Docker-Alertd](https://github.com/deltaskelta/docker-alertd) :ice_cube: - Monitor and send alerts based on docker container resource usage/statistics.\n- [Docker-Flow-Monitor](https://github.com/docker-flow/docker-flow-monitor) :ice_cube: - Reconfigures Prometheus when a new service is updated or deployed automatically.\n- [DockProbe](https://github.com/deep-on/dockprobe) - Lightweight Docker monitoring dashboard in a single container. Real-time metrics, 6 anomaly detection rules, Telegram alerts, and 16 automated security scans. Zero config, ~50MB RAM. By [DeepOn](https://github.com/deep-on).\n- [DockProc](https://gitlab.com/n0r1sk/dockproc) - I/O monitoring for containers on processlevel.\n- [dockprom](https://github.com/stefanprodan/dockprom) - Docker hosts and containers monitoring with Prometheus, Grafana, cAdvisor, NodeExporter and AlertManager.\n- [Doku](https://github.com/amerkurev/doku) - Doku is a simple web-based application that allows you to monitor Docker disk usage. [amerkurev](https://github.com/amerkurev).\n- [Dozzle](dozzle) - Monitor container logs in real-time with a browser or mobile device. [amir20](https://github.com/amir20).\n- [Drydock](https://github.com/CodesWhat/drydock) - Container update monitoring with web dashboard, 23 registry providers, 20 notification triggers, and distributed agent architecture. By [CodesWhat](https://github.com/CodesWhat).\n- [Dynatrace](https://docs.dynatrace.com/docs/observe/infrastructure-observability/container-platform-monitoring) - :yen: Monitor containerized applications without installing agents or modifying your Run commands.\n- [Glances](https://github.com/nicolargo/glances) - A cross-platform curses-based system monitoring tool written in Python.\n- [Grafana Docker Dashboard Template](https://grafana.com/grafana/dashboards/179-docker-prometheus-monitoring/) - A template for your Docker, Grafana and Prometheus stack [vegasbrianc][vegasbrianc].\n- [HertzBeat](https://github.com/dromara/hertzbeat) - An open-source real-time monitoring system with custom-monitor and agentless.\n\n- [InfluxDB, cAdvisor, Grafana](https://github.com/vegasbrianc/docker-monitoring) :ice_cube: - InfluxDB Time series DB in combination with Grafana and cAdvisor.\n- [Logspout](https://github.com/gliderlabs/logspout) :ice_cube: - Log routing for Docker container logs.\n- [Maintenant](https://github.com/kolapsis/maintenant) - Self-discovering infrastructure monitoring for Docker and Kubernetes. Auto-detects containers via labels, with endpoint monitoring, heartbeats, TLS certificates, resource metrics, update intelligence, and a built-in status page. Single binary with embedded SPA. By [kolapsis](https://github.com/kolapsis).\n- [monit-docker](https://github.com/decryptus/monit-docker) :ice_cube: - Monitor docker containers resources usage or status and execute docker commands or inside containers. [decryptus][decryptus].\n- [NexClipper](https://github.com/NexClipper/NexClipper) :ice_cube: - NexClipper is the container monitoring and performance management solution specialized in Docker, Apache Mesos, Marathon, DC/OS, Mesosphere, Kubernetes.\n- [Out-of-the-box Host/Container Monitoring/Logging/Alerting Stack](https://github.com/uschtwill/docker_monitoring_logging_alerting) :ice_cube: - Docker host and container monitoring, logging and alerting out of the box using cAdvisor, Prometheus, Grafana for monitoring, Elasticsearch, Kibana and Logstash for logging and elastalert and Alertmanager for alerting. Set up in 5 Minutes. Secure mode for production use with built-in [Automated Nginx Reverse Proxy (jwilder's)][nginxproxy].\n- [Sidekick](https://github.com/runsidekick/sidekick) :ice_cube: - Open source live application debugger like Chrome DevTools for your backend. Collect traces and generate logs on-demand without stopping & redeploying your applications.\n- [SwarmAlert](https://github.com/gpulido/SwarmAlert) :ice_cube: - Monitors a Docker Swarm and sends Pushover alerts when it finds a container with no healthy service task running.\n- [Zabbix Docker](https://github.com/gomex/docker-zabbix) :ice_cube: - Monitor containers automatically using zabbix LLD feature.\n- [Zabbix Docker module](https://github.com/monitoringartist/Zabbix-Docker-Monitoring) :ice_cube: - Zabbix module that provides discovery of running containers, CPU/memory/blk IO/net container metrics. Systemd Docker and LXC execution driver is also supported. It's a dynamically linked shared object library, so its performance is (~10x) better, than any script solution.\n### Networking\n\n-   [Calico][calico] - Calico is a pure layer 3 virtual network that allows containers over multiple docker-hosts to talk to each other.\n- [Flannel](https://github.com/coreos/flannel/) - Flannel is a virtual network that gives a subnet to each host for use with container runtimes. By [coreos][coreos].\n- [Freeflow](https://github.com/Microsoft/Freeflow) :ice_cube: - High performance container overlay networks on Linux. Enabling RDMA (on both InfiniBand and RoCE) and accelerating TCP to bare metal performance. By [Microsoft](https://github.com/Microsoft).\n- [MyIP](https://github.com/jason5ng32/MyIP) - All in one IP Toolbox. Easy to check all your IPs, IP geolocation, check for DNS leaks, examine WebRTC connections, speed test, ping test, MTR test, check website availability, whois search and more. By [jason5ng32](https://github.com/jason5ng32).\n- [netshoot](https://github.com/nicolaka/netshoot) - The netshoot container has a powerful set of networking tools to help troubleshoot Docker networking issues.\n- [Pipework](https://github.com/jpetazzo/pipework) - Software-Defined Networking for Linux Containers, Pipework works with \"plain\" LXC containers, and with the awesome Docker. By [jpetazzo][jpetazzo].\n\n### Orchestration\n\n- [Ansible Linux Docker](https://github.com/Peco602/ansible-linux-docker) :ice_cube: - Run Ansible from a Linux container. By [Peco602][peco602].\n- [athena](https://github.com/athena-oss/athena) :ice_cube: - An automation platform with a plugin architecture that allows you to easily create and share services.\n- [CloudSlang](https://github.com/CloudSlang/cloud-slang) - CloudSlang is a workflow engine to create Docker process automation.\n- [clusterdock](https://github.com/clusterdock/clusterdock) :ice_cube: - Docker container orchestration to enable the testing of long-running cluster deployments.\n- [Crane](https://github.com/Dataman-Cloud/crane) :ice_cube: - Control plane based on docker built-in swarm [Dataman-Cloud](https://github.com/Dataman-Cloud).\n- [Docker Flow Swarm Listener](https://github.com/docker-flow/docker-flow-swarm-listener) :ice_cube: - Docker Flow Swarm Listener project is to listen to Docker Swarm events and send requests when a change occurs. By [docker-flow][docker-flow].\n- [docker rollout](https://github.com/Wowu/docker-rollout) - Zero downtime deployment for Docker Compose services.\n- [Haven](https://github.com/codeabovelab/haven-platform) :ice_cube: - Haven is a simplified container management platform that integrates container, application, cluster, image, and registry managements. By [codeabovelab](https://github.com/codeabovelab).\n- [Kubernetes](https://github.com/kubernetes/kubernetes) - Open source orchestration system for Docker containers by Google.\n- [ManageIQ](https://github.com/ManageIQ/manageiq) - Discover, optimize and control your hybrid IT. By [ManageIQ](https://github.com/ManageIQ).\n- [Mesos](https://github.com/apache/mesos) - Resource/Job scheduler for containers, VM's and physical hosts [apache](https://mesos.apache.org/).\n- [Nebula](https://github.com/nebula-orchestrator) - A Docker orchestration tool designed to manage massive scale distributed clusters.\n- [Nomad](https://github.com/hashicorp/nomad) - Easily deploy applications at any scale. A Distributed, Highly Available, Datacenter-Aware Scheduler.\n- [Rancher](https://github.com/rancher/rancher) - An open source project that provides a complete platform for operating Docker in production.\n- [RedHerd Framework](https://github.com/redherd-project/redherd-framework) :ice_cube: - RedHerd is a collaborative and serverless framework for orchestrating a geographically distributed group of assets capable of simulating complex offensive cyberspace operations. By [RedHerdProject](https://github.com/redherd-project).\n- [Swarm-cronjob](https://github.com/crazy-max/swarm-cronjob) - Create jobs on a time-based schedule on Swarm by [crazy-max].\n\n### PaaS\n\n- [caprover](https://github.com/caprover/caprover) - [Previously known as CaptainDuckDuck] Automated Scalable Webserver Package (automated Docker+nginx) - Heroku on Steroids.\n- [Convox Rack](https://github.com/convox/rack) - Convox Rack is open source PaaS built on top of expert infrastructure automation and devops best practices.\n- [Dcw](https://github.com/pbertera/dcw) :ice_cube: - Docker-compose SSH wrapper: a very poor man PaaS, exposing the docker-compose and custom-container commands defined in container labels.\n- [Dokku](https://github.com/dokku/dokku) - Docker powered mini-Heroku that helps you build and manage the lifecycle of applications (originally by [progrium][progrium]).\n- [Empire](https://github.com/remind101/empire) :ice_cube: - A PaaS built on top of Amazon EC2 Container Service (ECS).\n- [Exoframe](https://github.com/exoframejs/exoframe) - A self-hosted tool that allows simple one-command deployments using Docker.\n- [Hephy Workflow](https://github.com/teamhephy/workflow) :ice_cube: - Open source PaaS for Kubernetes that adds a developer-friendly layer to any Kubernetes cluster, making it easy to deploy and manage applications. Fork of [Deis Workflow](https://github.com/deis/workflow).\n- [Krane](https://github.com/krane/krane) :ice_cube: - Toolset for managing container workloads on remote servers.\n- [Nanobox](https://github.com/nanobox-io/nanobox) :ice_cube: - :yen: An application development platform that creates local environments that can then be deployed and scaled in the cloud.\n-   [OpenShift][openshift] - An open source PaaS built on [Kubernetes][kubernetes] and optimized for Dockerized app development and deployment by [Red Hat](https://www.redhat.com/en)\n- [Tsuru](https://github.com/tsuru/tsuru) - Tsuru is an extensible and open source Platform as a Service software.\n\n### Reverse Proxy\n\n- [BunkerWeb](https://github.com/bunkerity/bunkerweb) - Open-source and next-gen Web Application Firewall (WAF). By [Bunkerity](https://www.bunkerity.com).\n- [caddy-docker-proxy](https://github.com/lucaslorentz/caddy-docker-proxy) - Caddy-based reverse proxy, configured with service or container labels. By [lucaslorentz](https://github.com/lucaslorentz).\n- [caddy-docker-upstreams](https://github.com/invzhi/caddy-docker-upstreams) - Docker upstreams module for Caddy, configured with container labels. By [invzhi](https://github.com/invzhi).\n- [Docker Dnsmasq Updater](https://github.com/moonbuggy/docker-dnsmasq-updater) - Update a remote dnsmasq server with Docker container hostnames.\n- [docker-flow-proxy](https://github.com/docker-flow/docker-flow-proxy) - Reconfigures proxy every time a new service is deployed, or when a service is scaled. By [docker-flow][docker-flow].\n- [fabio](https://github.com/fabiolb/fabio) - A fast, modern, zero-conf load balancing HTTP(S) router for deploying microservices managed by consul. By [magiconair](https://github.com/magiconair) (Frank Schroeder).\n- [idle-less](https://github.com/tvup/idle-less) - Reverse proxy with automatic Wake-on-LAN — wakes sleeping backend servers when traffic arrives, shows a waiting screen, and redirects when ready. By [tvup](https://github.com/tvup).\n- [Let's Encrypt Nginx-proxy Companion](https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion) - A lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. By [JrCs](https://github.com/JrCs).\n- [mesh-router](https://github.com/Yundera/mesh-router) - Free domain(nsl.sh) provider for Docker containers with automatic HTTPS routing. Uses Wireguard VPN to securely route subdomain requests across networks. Ideal for self-hosted NAS and cloud deployments. By [Yundera](https://github.com/Yundera).\n- [Nginx Proxy Manager](https://github.com/jc21/nginx-proxy-manager) - A beautiful web interface for proxying web based services with SSL. By [jc21](https://github.com/jc21).\n-   [nginx-proxy][nginxproxy] - Automated nginx proxy for Docker containers using docker-gen by [jwilder][jwilder]\n- [OpenResty Manager](https://github.com/Safe3/openresty-manager) - The easiest using, powerful and beautiful OpenResty Manager(Nginx Enhanced Version), open source alternative to OpenResty Edge. By [Safe3](https://github.com/Safe3/).\n- [Swarm Router](https://github.com/flavioaiello/swarm-router) - A «zero config» service name based router for docker swarm mode with a fresh and more secure approach. By [flavioaiello](https://github.com/flavioaiello).\n- [Træfɪk](https://github.com/containous/traefik) - Automated reverse proxy and load-balancer for Docker, Mesos, Consul, Etcd... By [EmileVauge](https://github.com/emilevauge).\n\n### Runtime\n\n- [cri-o](https://github.com/cri-o/cri-o) - Open Container Initiative-based implementation of Kubernetes Container Runtime Interface by [cri-o](https://github.com/cri-o).\n- [lxc](https://github.com/lxc/lxc) - LXC - Linux Containers.\n- [podman](https://github.com/containers/libpod) - Libpod is a library used to create container pods. Home of Podman.\n- [rlxc](https://github.com/brauner/rlxc) :ice_cube: - LXC binary written in Rust.\n- [runtime-tools](https://github.com/opencontainers/runtime-tools) - Oci-runtime-tool is a collection of tools for working with the OCI runtime specification.\n\n### Security\n\n- [Anchor](https://github.com/SongStitch/anchor/) - A tool to ensure reproducible builds by pinning dependencies inside your Dockerfiles [SongStitch](https://github.com/songStitch/).\n- [Anchor Enterprise](https://anchore.com/) - :yen: Analyze images for CVE vulnerabilities and against custom security policies.\n- [Aqua Security](https://www.aquasec.com) - :yen: Securing container-based applications from Dev to Production on any platform.\n- [bane](https://github.com/genuinetools/bane) :ice_cube: - AppArmor profile generator for Docker containers.\n- [buildcage](https://github.com/dash14/buildcage) - Restricts outbound network access during Docker builds to prevent supply chain attacks, working as a drop-in BuildKit remote driver for Docker Buildx, with ready-to-use GitHub Actions.\n- [CetusGuard](https://github.com/hectorm/cetusguard) - CetusGuard is a tool that protects the Docker daemon socket by filtering calls to its API endpoints.\n- [Checkov](https://github.com/bridgecrewio/checkov) - Static analysis for infrastructure as code manifests (Terraform, Kubernetes, Cloudformation, Helm, Dockerfile, Kustomize) find security misconfiguration and fix them. By [bridgecrew](https://github.com/bridgecrewio).\n- [CIS Docker Benchmark](https://github.com/dev-sec/cis-docker-benchmark) :ice_cube: - This [InSpec][inspec] compliance profile implement the CIS Docker 1.12.0 Benchmark in an automated way to provide security best-practice tests around Docker daemon and containers in a production environment. By [dev-sec](https://github.com/dev-sec).\n- [Clair](https://github.com/quay/clair) - Clair is an open source project for the static analysis of vulnerabilities in appc and docker containers. By [coreos][coreos].\n- [crowdsec-blocklist-import](https://github.com/wolffcatskyy/crowdsec-blocklist-import) - Aggregates 36 free threat intelligence feeds into 120k+ malicious IPs for CrowdSec bouncers, providing 10-20x more blocks than default lists. By [wolffcatskyy](https://github.com/wolffcatskyy).\n- [Dagda](https://github.com/eliasgranderubio/dagda) :ice_cube: - Dagda is a tool to perform static analysis of known vulnerabilities, trojans, viruses, malware & other malicious threats in docker images/containers and to monitor the docker daemon and running docker containers for detecting anomalous activities. By [eliasgranderubio](https://github.com/eliasgranderubio).\n- [Deepfence Enterprise](https://deepfence.io) - :yen: Full life cycle Cloud Native Workload Protection platform for kubernetes, virtual machines and serverless. By [deepfence][deepfence].\n- [Deepfence Threat Mapper](https://github.com/deepfence/ThreatMapper) - Powerful runtime vulnerability scanner for kubernetes, virtual machines and serverless. By [deepfence][deepfence].\n- [docker-bench-security](https://github.com/docker/docker-bench-security) - Script that checks for dozens of common best-practices around deploying Docker containers in production. By [docker][docker].\n- [docker-explorer](https://github.com/google/docker-explorer) - A tool to help forensicate offline docker acquisitions.\n- [dvwassl](https://github.com/Peco602/dvwassl) :ice_cube: - SSL-enabled Damn Vulnerable Web App to test Web Application Firewalls. By [Peco602][peco602].\n- [KICS](https://github.com/checkmarx/kics) - An infrastructure-as-code scanning tool, find security vulnerabilities, compliance issues, and infrastructure misconfigurations early in the development cycle. Can be extended for additional policies. By [Checkmarx](https://github.com/Checkmarx).\n- [oscap-docker](https://github.com/OpenSCAP/openscap) - OpenSCAP provides oscap-docker tool which is used to scan Docker containers and images. By [OpenSCAP](https://github.com/OpenSCAP).\n- [Prisma Cloud](https://www.paloaltonetworks.com/prisma/cloud) - :yen: (Previously Twistlock Security Suite) detects vulnerabilities, hardens container images, and enforces security policies across the lifecycle of applications.\n- [segspec](https://github.com/dormstern/segspec) - Extracts network dependencies from Docker Compose, Kubernetes manifests, Helm charts, and other config files to generate Kubernetes NetworkPolicies with evidence tracing. By [dormstern](https://github.com/dormstern).\n- [Syft](https://github.com/anchore/syft) - CLI tool and library for generating a Software Bill of Materials (SBOM) from container images and filesystems.\n- [Sysdig Falco](https://github.com/falcosecurity/falco) - Sysdig Falco is an open source container security monitor. It can monitor application, container, host, and network activity and alert on unauthorized activity.\n- [Sysdig Secure](https://www.sysdig.com/solutions/cloud-detection-and-response-cdr) - :yen: Sysdig Secure addresses run-time security through behavioral monitoring and defense, and provides deep forensics based on open source Sysdig for incident response.\n- [Trend Micro DeepSecurity](https://www.trendmicro.com/en_us/business/products/hybrid-cloud/deep-security.html) - :yen: Trend Micro DeepSecurity offers runtime protection for container workloads and hosts as well as preruntime scanning of images to identify vulnerabilities, malware and content such as hardcoded secrets.\n- [Trivy](https://github.com/aquasecurity/trivy) - Aqua Security's open source simple and comprehensive vulnerability scanner for containers (suitable for CI).\n\n### Service Discovery\n\n-   [docker-consul](https://github.com/gliderlabs/docker-consul) by [progrium][progrium]\n- [docker-dns](https://github.com/bytesharky/docker-dns) - Lightweight DNS forwarder for Docker containers, resolves container names with custom suffixes (e.g. `.docker`) on the host to simplify service discovery.\n- [etcd](https://github.com/etcd-io/etcd) - Distributed reliable key-value store for the most critical data of a distributed system by [etcd-io](https://github.com/etcd-io) (former part of CoreOS).\n- [istio](https://github.com/istio/istio) - An open platform to connect, manage, and secure microservices.\n- [registrator](https://github.com/gliderlabs/registrator) - Service registry bridge for Docker by [gliderlabs][gliderlabs] and [progrium][progrium].\n\n### Volume Management / Data\n\n-   [Blockbridge](https://github.com/blockbridge/blockbridge-docker-volume) :yen:- The Blockbridge plugin is a volume plugin that provides access to an extensible set of container-based persistent storage options. It supports single and multi-host Docker environments with features that include tenant isolation, automated provisioning, encryption, secure deletion, snapshots and QoS. By [blockbridge](https://github.com/blockbridge)\n-   - [Label Backup](https://github.com/resulgg/label-backup) - A lightweight, Docker-aware backup agent that automatically discovers and backs up containerized databases (PostgreSQL, MySQL, MongoDB, Redis) based on Docker labels. Supports local storage and S3-compatible destinations with flexible scheduling via cron expressions.\n-   [Docker Volume Backup](https://github.com/offen/docker-volume-backup) Backup Docker volumes locally or to any S3 compatible storage. By [offen](https://github.com/offen)\n-   [duplicacy-cli-cron](https://github.com/GeiserX/duplicacy-cli-cron) - Docker-based encrypted dual-storage backup automation using Duplicacy CLI with cross-site redundancy and Telegram notifications. By [GeiserX](https://github.com/GeiserX).\n-   [Netshare](https://github.com/ContainX/docker-volume-netshare) Docker NFS, AWS EFS, Ceph & Samba/CIFS Volume Plugin. By [ContainX][containx]\n- [portworx](https://portworx.com) - :yen: Decentralized storage solution for persistent, shared and replicated volumes.\n- [quobyte](https://www.quobyte.com/) - :yen: Fully fault-tolerant distributed file system with a docker volume driver.\n-   [REX-Ray](https://github.com/rexray/rexray) provides a vendor agnostic storage orchestration engine. The primary design goal is to provide persistent storage for Docker, Kubernetes, and Mesos. By[thecodeteam](https://github.com/thecodeteam) (DELL Technologies)\n\n- [Storidge](https://github.com/Storidge/quick-start) :ice_cube: - :yen: Software-defined Persistent Storage for Kubernetes and Docker Swarm.\n### User Interface\n\n#### IDE integrations\n\n-   JetBrains IDEs (IntelliJ IDEA, GoLand, WebStorm, CLion etc.) has [built-in Docker plugin](https://www.jetbrains.com/help/idea/docker.html#managing-images)\n-   Eclipse [Docker Tooling plugin](https://www.eclipse.org/community/eclipse_newsletter/2016/july/article2.php)\n-   [docker.el](https://github.com/Silex/docker.el) Manage docker from Emacs by [Silex](https://github.com/Silex)\n\n#### Desktop\n\nNative desktop applications for managing and monitoring docker hosts and clusters\n\n- [Docker DB Manager](https://github.com/AbianS/docker-db-manager) - Desktop app for managing Docker database containers with visual interface and one-click operations.\n- [Docker Desktop](https://www.docker.com/products/docker-desktop/) - Official native app. Only for Windows and MacOS.\n- [Simple Docker UI](https://github.com/felixgborrego/simple-docker-ui) - Built on Electron. By [felixgborrego](https://github.com/felixgborrego/).\n- [Stevedore](https://github.com/slonopotamus/stevedore) - Good Docker Desktop replacement for Windows. Both Linux and Windows Containers are supported. [slonopotamus](https://github.com/slonopotamus).\n\n#### Terminal\n\n##### Terminal UI\n- [d4s](https://github.com/jr-k/d4s) - A fast, keyboard-driven terminal UI to manage Docker containers, Compose stacks, and Swarm services with the ergonomics of K9s.\n- [dive](https://github.com/wagoodman/dive) - A tool for exploring each layer in a docker image. By [wagoodman](https://github.com/wagoodman).\n-   [dockdash](https://github.com/byrnedo/dockdash) detailed stats. By [byrnedo]\n- [dockly](https://github.com/lirantal/dockly) - An interactive shell UI for managing Docker containers.\n- [DockMate](https://github.com/shubh-io/dockmate) - Lightweight terminal-based Docker and Podman manager with a text-based user interface,.\n- [DockSTARTer](https://github.com/GhostWriters/DockSTARTer) - DockSTARTer helps you get started with home server apps running in Docker by [GhostWriters](https://github.com/GhostWriters).\n- [dprs](https://github.com/durableprogramming/dprs) - A developer-focused TUI for managing Docker containers with real-time log streaming and container management. Built with Rust. By [durableprogramming](https://github.com/durableprogramming).\n- [dry](https://github.com/moncho/dry) - An interactive CLI for Docker containers.\n- [goManageDocker](https://github.com/ajayd-san/gomanagedocker) - TUI tool to view and manage your docker objects blazingly fast with sensible keybindings, also supports VIM navigation out of the box.\n- [lazydocker](https://github.com/jesseduffield/lazydocker) - The lazier way to manage everything docker. A simple terminal UI for both docker and docker-compose, written in Go with the gocui library. By [jesseduffield](https://github.com/jesseduffield).\n- [lazyjournal](https://github.com/Lifailon/lazyjournal) - A interface for reading and filtering the logs output of Docker and Podman containers like [Dozzle](dozzle) but for the terminal with support for fuzzy find, regex and output coloring.\n- [oxker](https://github.com/mrjackwills/oxker) - A simple tui to view & control docker containers. Written in [Rust](https://rust-lang.org/), making heavy use of [ratatui](https://github.com/tui-rs-revival/ratatui) & [Bollard](https://github.com/fussybeaver/bollard),.\n\n##### CLI tools\n\n- [captain](https://github.com/jenssegers/captain) :ice_cube: - Easily start and stop docker compose projects from any directory. By [jenssegers](https://github.com/jenssegers).\n- [dcinja](https://github.com/Falldog/dcinja) - The powerful and smallest binary size of template engine for docker command line environment. By [Falldog](https://github.com/Falldog).\n- [dcp](https://github.com/exdx/dcp) :ice_cube: - A simple tool for copying files from container filesystems. By [exdx](https://github.com/exdx).\n- [dctl](https://github.com/FabienD/docker-stack) - Dctl is a Cli tool that helps developers by allowing them to execute all docker compose commands anywhere in the terminal, and more. By [FabienD](https://github.com/FabienD).\n- [decompose](https://github.com/s0rg/decompose) - Reverse-engineering tool for docker environments. By [s0rg](https://github.com/s0rg).\n- [docker pushrm](https://github.com/christian-korneck/docker-pushrm) - A Docker CLI plugin that lets you push the README.md file from the current directory to Docker Hub. Also supports Quay and Harbor. By [christian-korneck](https://github.com/christian-korneck).\n- [docker-captain](https://github.com/lucabello/docker-captain) - A friendly CLI to manage multiple Docker Compose deployments with style — powered by Typer, Rich, questionary, and sh.\n- [DVM](https://github.com/howtowhale/dvm) :ice_cube: - Docker version manager.\n- [goinside](https://github.com/iamsoorena/goinside) :ice_cube: - Get inside a running docker container easily.\n- [Pdocker](https://github.com/g31s/Pdocker) :ice_cube: - A simple tool to manage and maintain Docker for personal projects.\n- [proco](https://github.com/shiwaforce/poco) - Proco will help you to organise and manage Docker, Docker-Compose, Kubernetes projects of any complexity using simple YAML config files to shorten the route from finding your project to initialising it in your local environment.\n- [scuba](https://github.com/JonathonReinhart/scuba) - Transparently use Docker containers to encapsulate software build environments,.\n- [skopeo](https://github.com/containers/skopeo) - Work with remote images registries - retrieving information, images, signing content.\n- [supdock](https://github.com/segersniels/supdock) - Allows for slightly more visual usage of Docker with an interactive prompt. By [segersniels](https://github.com/segersniels).\n\n- [tsaotun](https://github.com/qazbnm456/tsaotun) :ice_cube: - Python based Assistance for Docker.\n##### Other\n\n- [dext-docker-registry-plugin](https://github.com/vutran/dext-docker-registry-plugin) :ice_cube: - Search the Docker Registry with the Dext smart launcher. By [vutran](https://github.com/vutran).\n- [docker-ssh](https://github.com/jeroenpeeters/docker-ssh) :ice_cube: - SSH Server for Docker containers ~ Because every container should be accessible. By [jeroenpeeters](https://github.com/jeroenpeeters).\n-   [dockerfile-mode](https://github.com/spotify/dockerfile-mode) An emacs mode for handling Dockerfiles by [spotify][spotify]\n\n- [MultiDocker](https://github.com/marty90/multidocker) :ice_cube: - Create a secure multi-user Docker machine, where each user is segregated into an indepentent container.\n- [Powerline-Docker](https://github.com/adrianmo/powerline-docker) :ice_cube: - A Powerline segment for showing the status of Docker containers.\n#### Web\n\n- [Arcane](https://github.com/getarcaneapp/arcane) - An easy and modern Docker management platform, built with everybody in mind. By [getarcaneapp](https://github.com/getarcaneapp).\n- [CASA](https://github.com/knrdl/casa) - Outsource the administration of a handful of containers to your co-workers,.\n- [Container Web TTY](https://github.com/wrfly/container-web-tty) - Connect your containers via a web-tty [wrfly](https://github.com/wrfly).\n- [dockemon](https://github.com/ProductiveOps/dokemon) :ice_cube: - Docker Container Management GUI.\n- [Docker Registry Browser](https://github.com/klausmeyer/docker-registry-browser) - Web Interface for the Docker Registry HTTP API v2.\n- [docker-registry-web](https://github.com/mkuchin/docker-registry-web) :ice_cube: - Web UI, authentication service and event recorder for private docker registry v2.\n- [docker-swarm-visualizer](https://github.com/dockersamples/docker-swarm-visualizer) - Visualizes Docker services on a Docker Swarm (for running demos).\n- [dockge](https://github.com/louislam/dockge) - Easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.\n- [Komodo](https://github.com/mbecker20/komodo) - A tool to build and deploy software on many servers.\n- [Kubevious](https://github.com/kubevious/kubevious) :ice_cube: - A highly visual web UI for Kubernetes which renders configuration and state in an application centric way.\n- [Mafl](https://github.com/hywax/mafl) - Minimalistic flexible homepage.\n- [netdata](https://github.com/netdata/netdata) - Real-time performance monitoring.\n- [OctoLinker](https://github.com/OctoLinker/OctoLinker) :ice_cube: - A browser extension for GitHub that makes the image name in a `Dockerfile` clickable and redirect you to the related Docker Hub page.\n- [Portainer](https://github.com/portainer/portainer) - A lightweight management UI for managing your Docker hosts or Docker Swarm clusters.\n- [Rapid Dashboard](https://github.com/ozlerhakan/rapid) :ice_cube: - A simple query dashboard to use Docker Remote API.\n- [Seagull](https://github.com/tobegit3hub/seagull) :ice_cube: - Friendly Web UI to monitor docker daemon.\n- [Swarmpit](https://github.com/swarmpit/swarmpit) - Swarmpit provides simple and easy to use interface for your Docker Swarm cluster. You can manage your stacks, services, secrets, volumes, networks etc.\n- [Swirl](https://github.com/cuigh/swirl) :ice_cube: - Swirl is a web management tool for Docker, focused on swarm cluster By [cuigh](https://github.com/cuigh/).\n- [Theia](https://github.com/eclipse-theia/theia) - Extensible platform to develop full-fledged multi-language Cloud & Desktop IDE-like products with state-of-the-art web technologies.\n- [usulnet](https://github.com/fr4nsys/usulnet) - A complete and modern Docker management platform designed for sysadmin, devops with enterprise grade tools, cve scanner, ssh, rdp on web and much more. By [fr4nsys](https://github.com/fr4nsys).\n\n## Docker Images\n\n### Base Tools\n\nTools and applications that are either installed inside containers or designed to be run as a [sidecar](https://learn.microsoft.com/en-us/azure/architecture/patterns/sidecar)\n\n- [amicontained](https://github.com/genuinetools/amicontained) :ice_cube: - Container introspection tool. Find out what container runtime is being used as well as features available.\n- [Chaperone](https://github.com/garywiz/chaperone) :ice_cube: - A single PID1 process designed for docker containers. Does user management, log management, startup, zombie reaping, all in one small package.\n- [ckron](https://github.com/nicomt/ckron) - A cron-style job scheduler for docker,.\n-   [CoreOS][coreos] - Linux for Massive Server Deployments\n- [distroless](https://github.com/GoogleContainerTools/distroless) - Language focused docker images, minus the operating system,.\n- [docker-alpine](https://github.com/gliderlabs/docker-alpine) :ice_cube: - A super small Docker base image _(5MB)_ using Alpine Linux.\n- [docker-gen](https://github.com/jwilder/docker-gen) - Generate files from docker container meta-data.\n- [dockerize](https://github.com/powerman/dockerize) - Utility to simplify running applications in docker containers by [jwilder][jwilder], [powerman][powerman].\n- [GoSu](https://github.com/tianon/gosu) - Run this specific application as this specific user and get out of the pipeline (entrypoint script tool).\n- [is-docker](https://github.com/sindresorhus/is-docker) - Check if the process is running inside a Docker container.\n- [lstags](https://github.com/ivanilves/lstags) :ice_cube: - Sync Docker images across registries.\n- [microcheck](https://github.com/tarampampam/microcheck) - Lightweight health check utilities for Docker containers (75 KB instead of 9.3 MB for httpcheck versus cURL) in pure C - http(s), port checks, and parallel execution are included.\n- [Ofelia](https://github.com/mcuadros/ofelia/) - Ofelia is a modern and low footprint job scheduler for docker environments, built on Go. Ofelia aims to be a replacement for the old fashioned cron. Supports configuration from container labels and/or configuration files.\n- [SparkView](https://github.com/beyondssl/sparkview-container) - Access VMs, desktops, servers or applications anytime and from anywhere, without complex and costly client roll-outs or user management.\n- [su-exec](https://github.com/ncopa/su-exec) - This is a simple tool that will simply execute a program with different privileges. The program will be executed directly and not run as a child, like su and sudo does, which avoids TTY and signal issues. Why reinvent gosu? This does more or less exactly the same thing as gosu but it is only 10kb instead of 1.8MB. By [ncopa](https://github.com/ncopa).\n- [sue](https://github.com/theAkito/sue) :ice_cube: - Executes a program as a user different from the user running sue. This is a maintainable alternative to ncopa/su-exec, which is the better tianon/gosu. This one is far better (higher performance, smaller size), than the original gosu, however it is far easier to maintain, than su-exec, which is written in plain C. Made by [Akito][akito].\n- [supercronic](https://github.com/aptible/supercronic) - Crontab-compatible job runner, designed specifically to run in containers.\n\n- [TrivialRC](https://github.com/vorakl/TrivialRC) :ice_cube: - A minimalistic Runtime Configuration system and process manager for containers [vorakl](https://github.com/vorakl).\n### Builder\n\nApplications designed to help or simplify building **new** images\n\n- [ansible-bender](https://github.com/ansible-community/ansible-bender) - A tool utilising `ansible` and `buildah`.\n- [buildah](https://github.com/containers/buildah) - A tool that facilitates building OCI images.\n- [BuildKit](https://github.com/moby/buildkit) - Concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit.\n- [cekit](https://github.com/cekit/cekit) - A tool used by openshift to build base images using different build engines.\n- [container-factory](https://github.com/mutable/container-factory) :ice_cube: - Produces Docker images from tarballs of application source code.\n- [copy-docker-image](https://github.com/mdlavin/copy-docker-image) :ice_cube: - Copy a Docker image between registries without a full Docker installation.\n- [Derrick](https://github.com/alibaba/derrick) :ice_cube: - A tool help you to automate the generation of Dockerfile and dockerize application by scanning the code. By [alibaba](https://github.com/alibaba).\n- [dlayer](https://github.com/orisano/dlayer) - Docker layer analyzer.\n- [docker-companion](https://github.com/mudler/docker-companion) - A command line tool written in Golang to squash and unpack docker images.\n- [docker-make](https://github.com/CtripCloud/docker-make) :ice_cube: - Build, tag,and push a bunch of related docker images via a single command.\n- [docker-repack](https://github.com/orf/docker-repack) - Repacks a Docker image into a smaller, more efficient version that makes it significantly faster to pull. By [orf](https://github.com/orf).\n- [docker-replay](https://github.com/bcicen/docker-replay) :ice_cube: - Generate `docker run`command and options from running containers. By [bcicen](https://github.com/bcicen).\n-   [DockerSlim](https://github.com/docker-slim/docker-slim) shrinks fat Docker images creating the smallest possible images.\n- [Dockly](https://github.com/swipely/dockly) :ice_cube: - Dockly is a gem made to ease the pain of packaging an application in Docker.\n- [essex](https://github.com/utensils/essex) - Boilerplate for Docker Based Projects: Essex is a CLI utility written in bash to quickly setup clean and consistent Docker projects with Makefile driven workflows. [jamesbrink](https://github.com/jamesbrink).\n- [HPC Container Maker](https://github.com/NVIDIA/hpc-container-maker) - Generates Dockerfiles from a high level Python recipe, including building blocks for High-Performance Computing components.\n- [img](https://github.com/genuinetools/img) - Standalone, daemon-less, unprivileged Dockerfile and OCI compatible container image builder.\n- [packer](https://developer.hashicorp.com/packer/integrations/hashicorp/docker/latest/components/builder/docker) - Hashicorp tool to build machine images including docker image integrated with configuration management tools like chef, puppet, ansible.\n- [portainer](https://github.com/duedil-ltd/portainer) :ice_cube: - Apache Mesos framework for building Docker images.\n- [Production-Ready Python Containers :yen:](https://pythonspeed.com/products/pythoncontainer/) - A template for creating production-ready Docker images for Python applications.\n- [RAUDI](https://github.com/cybersecsi/RAUDI) - A tool to automatically update (and optionally push to Docker Hub) Docker Images for 3rd party software whenever theres is a new release/update/commit. By [SecSI](https://github.com/cybersecsi).\n- [runlike](https://github.com/lavie/runlike) - Generate `docker run`command and options from running containers.\n- [userdef](https://github.com/theAkito/userdef) :ice_cube: - An advanced `adduser` for your Alpine based Docker images. Made by [Akito][akito].\n- [Whaler](https://github.com/P3GLEG/Whaler) - Program to reverse Docker images into Dockerfiles.\n\n- [Whales](https://github.com/Gueils/whales) :ice_cube: - A tool to automatically dockerize your applications.\n### Dockerfile\n\n- [chaperone-docker](https://github.com/garywiz/chaperone-docker) :ice_cube: - A set of images using the Chaperone process manager, including a lean Alpine image, LAMP, LEMP, and bare-bones base kits.\n-   [Dockerfile Generator](https://github.com/ozankasikci/dockerfile-generator) `dfg` is both a Go library and an executable that produces valid Dockerfiles using various input channels.\n- [Dockerfile Project](https://dockerfile.github.io/) - Trusted Automated Docker Builds. Dockerfile Project maintains a central repository of Dockerfile for various popular open source software services runnable on a Docker container.\n- [dockerfilegraph](https://github.com/patrickhoefler/dockerfilegraph) - Visualize your multi-stage Dockerfiles. By [PatrickHoefler](https://github.com/patrickhoefler).\n- [Dockershelf](https://github.com/Dockershelf/dockershelf) - A repository that serves as a collector for docker recipes that are universal, efficient and slim. Images are updated, tested and published daily via a Travis cron job.\n- [Vektorcloud](https://github.com/vektorcloud) - A collection of minimal, Alpine-based Docker images.\n\nExamples by:\n\n-   [0xy](https://gitlab.com/0xy/dockerfiles)\n-   [arun-gupta](https://github.com/arun-gupta/docker-images)\n-   [awesome-startup](https://github.com/awesome-startup/docker-compose)\n-   [crosbymichael](https://github.com/crosbymichael/Dockerfiles)\n-   [jessfraz](https://github.com/jessfraz/dockerfiles)\n-   [komljen](https://github.com/komljen/dockerfile-examples)\n-   [kstaken](https://github.com/kstaken/dockerfile-examples)\n-   [ondrejmo](https://github.com/ondrejmo/Dockerfiles)\n-   [vimagick](https://github.com/vimagick/dockerfiles)\n\n### Linter\n\n- [Dockadvisor](https://github.com/deckrun/dockadvisor) - Lightweight Dockerfile linter with 60+ rules, quality scoring, and security checks.\n- [docker-image-size-limit](https://github.com/wemake-services/docker-image-size-limit) - A tool to keep an eye on your docker images size.\n- [Dockerfile Linter action](https://github.com/buddy-works/dockerfile-linter) :ice_cube: - The linter lets you verify Dockerfile syntax to make sure it follows the best practices for building efficient Docker images.\n- [FROM:latest](https://github.com/replicatedhq/dockerfilelint) :ice_cube: - An opinionated Dockerfile linter.\n- [Hadolint](https://github.com/hadolint/hadolint) - A Dockerfile linter that checks for best practices, common mistakes, and is also able to lint any bash written in `RUN` instructions;.\n\n### Metadata\n\n- [opencontainer](https://github.com/opencontainers/image-spec/blob/main/annotations.md) - A convention and shared namespace for Docker labels defined by OCI Image Spec.\n\n### Registry\n\nServices to securely store your Docker images.\n\n- [Amazon Elastic Container Registry :yen:](https://aws.amazon.com/ecr/) - Amazon Elastic Container Registry (ECR) is a fully-managed Docker container registry that makes it easy for developers to store, manage, and deploy Docker container images.\n- [Azure Container Registry :yen:](https://azure.microsoft.com/en-us/products/container-registry/#overview) - Manage a Docker private registry as a first-class Azure resource.\n- [CargoOS](https://github.com/RedCoolBeans/cargos-buildroot) :ice_cube: - A bare essential OS for running the Docker Engine on bare metal or Cloud. By [RedCoolBeans](https://github.com/RedCoolBeans).\n- [cleanreg](https://github.com/hcguersoy/cleanreg) :ice_cube: - A small tool to delete image manifests from a Docker Registry implementing the API v2, dereferencing them for the GC.\n- [Cloudsmith :yen:](https://cloudsmith.com/product/formats/docker-registry) - A fully managed package management SaaS, with first-class support for public and private Docker registries (and many others, incl. Helm charts for the Kubernetes ecosystem). Has a generous free-tier and is also completely free for open-source.\n- [Container Registry Service :yen:](https://container-registry.com/) - Harbor based Container Management Solution as a Service for teams and organizations. Free tier offers 1 GB storage for private repositories.\n- [Cycle.io :yen:](https://cycle.io/) - Bare-metal container hosting.\n- [DigitalOcean :yen:](https://www.digitalocean.com/products/container-registry) - DigitalOcean Container Registry.\n-   [Docker Hub](https://hub.docker.com/) provided by Docker Inc.\n-   [Docker Registry v2][distribution] - The Docker toolset to pack, ship, store, and deliver content\n- [Docket](https://github.com/netvarun/docket) :ice_cube: - Custom docker registry that allows for lightning fast deploys through bittorrent.\n- [Dragonfly](https://github.com/dragonflyoss/Dragonfly2) - Provide efficient, stable and secure file distribution and image acceleration based on p2p technology.\n-   [GCP Artifact Registry :yen:](https://cloud.google.com/artifact-registry/docs) Fast, private Docker image storage on Google Cloud Platform.\n- [Gitea Container Registry](https://docs.gitea.com/usage/packages/container) - Integrated Docker registry in Gitea, ideal for private, small-scale image hosting.\n- [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) - GitHub's solution for storing and managing Docker images, with tight integration into GitHub Actions.\n- [GitLab Container Registry](https://docs.gitlab.com/user/packages/container_registry/) - Registry focused on using its images in GitLab CI.\n-   [Harbor](https://github.com/goharbor/harbor) An open source trusted cloud native registry project that stores, signs, and scans content. Supports replication, user management, access control and activity auditing. By [CNCF](https://www.cncf.io) formerly [VMWare][vmware]\n- [JFrog Artifactory :yen:](https://jfrog.com/artifactory/) - Artifact Repository Manager, can be used as private Docker Registry as well.\n- [Kraken](https://github.com/uber/kraken) - Uber's Highly scalable P2P docker registry, capable of distributing TBs of data in seconds.\n- [nscr](https://github.com/jhstatewide/nscr) - A light-weight, self-contained container registry that's easy to run and maintain.\n- [Quay.io :yen:](https://quay.io/) - Secure hosting for private Docker repositories.\n- [Registryo](https://github.com/inmagik/registryo) - UI and token based authentication server for onpremise docker registry.\n- [RepoFlow](https://www.repoflow.io) - A simple and easy-to-use package management platform with Docker support alongside other formats like PyPI, Maven, npm, and Helm. Includes smart search, built-in Docker image scanning, and a great free option for both self-hosted and cloud use.\n- [Rescoyl](https://github.com/noteed/rescoyl) :ice_cube: - Private Docker registry (free and open source).\n- [Sonatype Nexus Repository](https://www.sonatype.com/products/sonatype-nexus-repository) - Manage binaries and build artifacts across your software supply chain.\n\n## Development with Docker\n\n### API Client\n\n- [ahab](https://github.com/instacart/ahab) :ice_cube: - Docker event handling with Python.\n- [contajners](https://github.com/lispyclouds/contajners) - An idiomatic, data-driven, REPL friendly Clojure client for OCI container engines. By [lispyclouds][lispyclouds].\n- [Docker Client for JVM](https://github.com/gesellix/docker-client) - A Docker remote api client library for the JVM, written in Groovy.\n- [Docker Client TypeScript](https://gitlab.com/masaeedu/docker-client) - Docker API client for JavaScript, automatically generated from Swagger API definition from moby repository. By [masaeedu](https://github.com/masaeedu).\n- [docker-controller-bot](https://github.com/dgongut/docker-controller-bot) - Telegram bot to control docker containers. By [dgongut](https://github.com/dgongut/).\n- [docker-it-scala](https://github.com/whisklabs/docker-it-scala) :ice_cube: - Docker integration testing kit with Scala.\n- [docker-java-api](https://github.com/amihaiemil/docker-java-api) :ice_cube: - Lightweight, truly object-oriented, Java client for Docker's API. By [amihaiemil](https://github.com/amihaiemil).\n- [docker-maven-plugin](https://github.com/fabric8io/docker-maven-plugin) - A Maven plugin for running and creating Docker images.\n- [Docker.DotNet](https://github.com/Microsoft/Docker.DotNet) - C#/.NET HTTP client for the Docker remote API.\n- [Docker.Registry.DotNet](https://github.com/ChangemakerStudios/Docker.Registry.DotNet) - .NET (C#) Client Library for interacting with a Docker Registry API (v2) [rquackenbush](https://github.com/rquackenbush).\n- [dockerode](https://github.com/apocas/dockerode) - Docker Remote API node.js module.\n- [DoMonit](https://github.com/eon01/DoMonit) :ice_cube: - A simple Docker Monitoring wrapper For Docker API.\n- [go-dockerclient](https://github.com/fsouza/go-dockerclient/) - Go HTTP client for the Docker remote API.\n- [Gradle Docker plugin](https://github.com/gesellix/gradle-docker-plugin) - A Docker remote api plugin for Gradle.\n- [Portainer stack utils](https://github.com/greenled/portainer-stack-utils) - Bash script to deploy/update/undeploy Docker stacks in a Portainer instance from a docker-compose yaml file. By [greenled](https://github.com/greenled).\n- [sbt-docker](https://github.com/marcuslonnberg/sbt-docker) - Create Docker images directly from sbt.\n\n### CI/CD\n\n- [Buddy :yen:](https://buddy.works) - The best of Git, build & deployment tools combined into one powerful tool that supercharged our development.\n- [Captain](https://github.com/harbur/captain) - Convert your Git workflow to Docker containers ready for Continuous Delivery.\n- [Cyclone](https://github.com/caicloud/cyclone) :ice_cube: - Powerful workflow engine and end-to-end pipeline solutions implemented with native Kubernetes resources.\n- [Defang](https://github.com/DefangLabs/defang) - Deploy Docker Compose to your favorite cloud in minutes.\n- [Depot :yen:](https://depot.dev) - Build Docker images fast, in the cloud. Blazing fast compute, automatic intelligent caching, and zero configuration. [Done in seconds](https://depot.dev/#benchmarks).\n- [Diun](https://github.com/crazy-max/diun) - Receive notifications when an image or repository is updated on a Docker registry by [crazy-max].\n- [dockcheck](https://github.com/mag37/dockcheck) - A script checking updates for docker images without pulling then auto-update selected/all containers. With notifications, pruning and more.\n- [Docker plugin for Jenkins](https://github.com/jenkinsci/docker-plugin/) - The aim of the docker plugin is to be able to use a docker host to dynamically provision a slave, run a single build, then tear-down that slave.\n- [Drone](https://github.com/drone/drone) - Continuous integration server built on Docker and configured using YAML files.\n- [Gantry](https://github.com/shizunge/gantry) - Automatically update selected Docker swarm services.\n- [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) - GitLab has integrated CI to test, build and deploy your code with the use of GitLab runners.\n- [Jaypore CI](https://github.com/theSage21/jaypore_ci) - Simple, very flexible, powerful CI / CD / automation system configured in Python. Offline and local first.\n- [Kraken CI](https://github.com/Kraken-CI/kraken) - Modern CI/CD, open-source, on-premise system that is highly scalable and focused on testing. One of its executors is Docker. Developed.\n- [Microservices Continuous Deployment](https://github.com/francescou/docker-continuous-deployment) :ice_cube: - Continuous deployment of a microservices application.\n- [mu](https://github.com/stelligent/mu) :ice_cube: - Tool to configure CI/CD of your container applications via AWS CodePipeline, CodeBuild and ECS [Stelligent](https://github.com/stelligent).\n- [Popper](https://github.com/systemslab/popper) :ice_cube: - Github actions workflow (HCL syntax) execution engine.\n- [Screwdriver :yen:](https://screwdriver.cd/) - Yahoo's OpenSource buildplatform designed for Continous Delivery.\n- [Skipper](https://github.com/Stratoscale/skipper) - Easily dockerize your Git repository.\n- [SwarmCI](https://github.com/ghostsquad/swarmci) :ice_cube: - Create a distributed, isolated task pipeline in your Docker Swarm.\n- [Tekton CD](https://tekton.dev/) - A cloud-native pipeline resource.\n\n### Development Environment\n\n- [Binci](https://github.com/binci/binci) :ice_cube: - Containerize your development workflow. (formerly DevLab by [TechnologyAdvice](https://github.com/TechnologyAdvice)).\n- [coder](https://github.com/coder/coder) - Remote development machines powered by Terraform or Docker.\n- [construi](https://github.com/lstephen/construi) :ice_cube: - Run your builds inside a Docker defined environment.\n- [dde](https://github.com/whatwedo/dde) - Local development environment toolset based on Docker. By [whatwedo](https://github.com/whatwedo).\n- [DIP](https://github.com/bibendi/dip) - CLI utility for straightforward provisioning and interacting with an application configured by docker-compose. By [bibendi](https://github.com/bibendi).\n- [dobi](https://github.com/dnephin/dobi) :ice_cube: - A build automation tool for Docker applications. By [dnephin](https://github.com/dnephin).\n- [Docker Missing Tools](https://github.com/nandoquintana/docker-missing-tools) :ice_cube: - A set of bash commands to shortcut typical docker dev-ops. An alternative to creating typical helper scripts like \"build.sh\" and \"deploy.sh\" inside code repositories. By [NandoQuintana](https://github.com/nandoquintana).\n- [Docker-Arch](https://github.com/Ph3nol/Docker-Arch) :ice_cube: - Generate Web/CLI projects Dockerized development environments, from 1 simple YAML file. By [Ph3nol](https://github.com/ph3nol).\n- [Docker-sync](https://github.com/EugenMayer/docker-sync) - Drastically improves performance ([50-70x](https://github.com/EugenMayer/docker-sync/wiki/4.-Performance)) when using Docker for development on Mac OS X/Windows and Linux while sharing code to the container. By [EugenMayer](https://github.com/EugenMayer).\n- [docker-vm](https://github.com/shyiko/docker-vm) :ice_cube: - Simple and transparent alternative to boot2docker (backed by Vagrant).\n- [DockerDL](https://github.com/matifali/dockerdl) - Deep Learning Docker Images. Don't waste time setting up a deep learning env when you can get a deep learning environment with everything pre-installed.\n- [Eclipse Che](https://github.com/eclipse/che) - Developer workspace server with Docker runtimes, cloud IDE, next-generation Eclipse IDE.\n- [EnvCLI](https://github.com/EnvCLI/EnvCLI) - Replace your local installation of Node, Go, ... with project-specific docker containers. By [EnvCLI](https://github.com/EnvCLI).\n- [ESP32 Linux - Docker builder](https://github.com/hpsaturn/esp32s3-linux) - Container solution to compile Linux and develop it for ESP32 microcontrollers - By [Hpsaturn](https://github.com/hpsaturn).\n- [Gebug](https://github.com/moshebe/gebug) - A tool that makes debugging of Dockerized Go applications super easy by enabling Debugger and Hot-Reload features, seamlessly.\n- [Kitt](https://github.com/senges/kitt) :ice_cube: - A portable and disposable Shell environment, based on Docker and Nix. By [senges](https://github.com/senges).\n- [Lando](https://github.com/lando/lando) - Lando is for developers who want to quickly specify and painlessly spin up the services and tools needed to develop their projects. By [Tandem](https://www.thinktandem.io/).\n- [Rust Universal Compiler](https://github.com/Peco602/rust-universal-compiler) :ice_cube: - Container solution to compile Rust projects for Linux, macOS and Windows. By [Peco602][peco602].\n- [uniget](https://github.com/uniget-org/cli) - Uni(versal)get, the installer and updater for container tools and beyond (formerly docker-setup). By [nicholasdille](https://github.com/nicholasdille).\n- [Vagga](https://github.com/tailhook/vagga) :ice_cube: - Vagga is a containerisation tool without daemons. It is a fully-userspace container engine inspired by Vagrant and Docker, specialized for development environments.\n- [Zsh-in-Docker](https://github.com/deluan/zsh-in-docker) - Install Zsh, Oh-My-Zsh and plugins inside a Docker container with one line! By [Deluan](https://www.deluan.com).\n\n### Garbage Collection\n\n- [caduc](https://github.com/tjamet/caduc) :ice_cube: - A docker garbage collector cleaning stuff you did not use recently.\n- [Docker Clean](https://github.com/ZZROTDesign/docker-clean) :ice_cube: - A script that cleans Docker containers, images and volumes.\n- [docker-custodian](https://github.com/Yelp/docker-custodian) - Keep docker hosts tidy. By [Yelp](https://github.com/Yelp).\n- [docker_gc](https://github.com/pdacity/docker_gc) :ice_cube: - Image for automatic removing unused Docker Swarm objects. Also works just as Docker Service.\n- [Docuum](https://github.com/stepchowfun/docuum) - Least recently used (LRU) eviction of Docker images.\n\n### Serverless\n\n- [Apache OpenWhisk](https://github.com/apache/openwhisk) - A serverless, open source cloud platform that executes functions in response to events at any scale. By [apache](https://github.com/apache).\n- [Funker](https://github.com/bfirsh/funker-example-voting-app) :ice_cube: - Functions as Docker containers example voting app. By [bfirsh](https://github.com/bfirsh).\n- [IronFunctions](https://github.com/iron-io/functions) :ice_cube: - The serverless microservices platform FaaS (Functions as a Service) which uses Docker containers to run Any language or AWS Lambda functions.\n- [Koyeb](https://www.koyeb.com/) - :yen: Koyeb is a developer-friendly serverless platform to deploy apps globally. Seamlessly run Docker containers, web apps, and APIs with git-based deployment, native autoscaling, a global edge network, and built-in service mesh and discovery.\n- [OpenFaaS](https://github.com/openfaas/faas) - A complete serverless functions framework for Docker and Kubernetes. By [OpenFaaS](https://github.com/openfaas).\n\n- [SCAR](https://github.com/grycap/scar) :ice_cube: - Serverless Container-aware Architectures (SCAR) is a serverless framework that allows easy deployment and execution of containers (e.g. Docker) in Serverless environments (e.g. Lambda).\n### Testing\n\n- [Container Structure Test](https://github.com/GoogleContainerTools/container-structure-test) - A framework to validate the structure of an image by checking the outputs of commands or the contents of the filesystem. By [GoogleContainerTools][googlecontainertools].\n- [dgoss](https://github.com/goss-org/goss/tree/master/extras/dgoss) - A fast YAML based tool for validating docker containers.\n- [DockerSpec](https://github.com/zuazo/dockerspec) :ice_cube: - A small Ruby Gem to run RSpec and Serverspec, Infrataster and Capybara tests against Dockerfiles or Docker images easily. By [zuazo](https://github.com/zuazo).\n- [EZDC](https://github.com/lynchborg/ezdc) :ice_cube: - Golang test harness for easily setting up tests that rely on services in a docker-compose.yml. By [byrnedo].\n-   [InSpec][inspec] - InSpec is an open-source testing framework for infrastructure with a human- and machine-readable language for specifying compliance, security and policy requirements. By [chef](https://github.com/chef)\n- [Kurtosis](https://github.com/kurtosis-tech/kurtosis) - A composable build system for multi-container test environments that provides developers with: a powerful Python-like SDK for environment configuration, a compile-time validator to verify environment behavior & setup, and a runtime for environment execution, monitoring, & debugging capabilities. By [Kurtosis](https://www.kurtosis.com/).\n- [Pull Dog](https://github.com/apps/pull-dog) - A GitHub app that automatically creates Docker-based test environments for your pull requests, from your docker-compose files. Not open source.\n- [Pumba](https://github.com/alexei-led/pumba) - Chaos testing tool for Docker. Can be deployed on kubernetes and CoreOS cluster. By [alexei-led](https://github.com/alexei-led).\n\n### Wrappers\n\n- [Ansible](https://docs.ansible.com/projects/ansible/latest/collections/community/general/docker_container_module.html) - Manage the life cycle of Docker containers. By RedHat.\n- [dexec](https://github.com/docker-exec/dexec) :ice_cube: - Command line interface written in Go for running code with Docker Exec images.\n- [dockerized](https://github.com/benzaita/dockerized-cli) :ice_cube: - Seamlessly execute commands in a container.\n- [Dray](https://github.com/CenturyLinkLabs/dray) :ice_cube: - An engine for managing the execution of container-based workflows.\n- [Hokusai](https://github.com/artsy/hokusai) - A Docker + Kubernetes CLI for application developers; used to containerize an application and to manage its lifecycle throughout development, testing, and release cycles. From [artsy](https://github.com/artsy).\n- [Preevy](https://github.com/livecycle/preevy) - Preview environments for Docker and Docker Compose projects. Test your changes and get feedback from devs and non-devs (Product/Design) by deploying pull requests to the your cloud provider as part of your CI pipeline.\n- [Shutit](https://github.com/ianmiell/shutit) :ice_cube: - Tool for building and maintaining complex Docker deployments.\n- [subuser](https://github.com/subuser-security/subuser) - Makes it easy to securely and portably run graphical desktop applications in Docker.\n- [Terraform cloud-init config](https://github.com/christippett/terraform-cloudinit-container-server) :ice_cube: - Terraform module for deploying a single Docker image or `docker-compose.yaml` file to any Cloud™ VM.\n- [Turbo](https://github.com/ramitsurana/turbo) :ice_cube: - Simple and Powerful utility for docker. By [ramitsurana][ramitsurana].\n- [udocker](https://github.com/indigo-dc/udocker) - A tool to execute simple docker containers in batch or interactive systems without root privileges.\n- [Vagrant - Docker provider](https://developer.hashicorp.com/vagrant/docs/providers/docker/basics) - Good starting point is [vagrant-docker-example](https://github.com/bubenkoff/vagrant-docker-example).\n\n## Services based on Docker (mostly :yen:)\n\n### CI Services\n\n- [CircleCI](https://circleci.com/) - :yen: Push or pull Docker images from your build environment, or build and run containers right on CircleCI.\n- [CodeFresh](https://codefresh.io) - :yen: Everything you need to build, test, and share your Docker applications. Provides automated end to end testing.\n- [CodeShip](https://www.cloudbees.com/blog/how-to-run-codeship-parallel-test-pipelines-efficiently-for-optimal-ci-parallelization) - :yen: Work with your established Docker workflows while automating your testing and deployment tasks with our hosted platform dedicated to speed and security.\n- [ConcourseCI](https://concourse-ci.org) - :yen: A CI SaaS platform for developers and DevOps teams pipeline oriented.\n-   [Semaphore CI](https://semaphore.io/) :yen: — A high-performance cloud solution that makes it easy to build, test and ship your containers to production.\n- [TravisCI](https://www.travis-ci.com/) - :yen: A Free github projects continuous integration Saas platform for developers and Devops.\n\n### CaaS\n\n- [Amazon ECS](https://aws.amazon.com/ecs/) - :yen: A management service on EC2 that supports Docker containers.\n- [Appfleet](https://appfleet.com/) - :yen: Edge platform to deploy and manage containerized services globally. The system will route the traffic to the closest location for lower latency.\n- [Azure AKS](https://azure.microsoft.com/en-us/products/kubernetes-service/) - :yen: Simplify Kubernetes management, deployment, and operations. Use a fully managed Kubernetes container orchestration service.\n- [Cloud 66](https://www.cloud66.com) - :yen: Full-stack hosted container management as a service.\n- [Giant Swarm](https://www.giantswarm.io/) - :yen: Simple microservice infrastructure. Deploy your containers in seconds.\n- [Google Container Engine](https://docs.cloud.google.com/kubernetes-engine/docs) - :yen: Docker containers on Google Cloud Computing powered by [Kubernetes][kubernetes].\n- [Mesosphere DC/OS Platform](https://d2iq.com/products/dcos) - :yen: Integrated platform for data and containers built on Apache Mesos.\n- [Red Hat OpenShift Dedicated](https://www.redhat.com/en/technologies/cloud-computing/openshift/dedicated) - :yen: Fully-managed Red Hat® OpenShift® service on Amazon Web Services and Google Cloud.\n- [Triton](https://www.joyent.com/) - :yen: Elastic container-native infrastructure by Joyent.\n\n### Monitoring Services\n\n- [AppDynamics](https://github.com/Appdynamics/docker-monitoring-extension) - Docker Monitoring extension gathers metrics from the Docker Remote API, either using Unix Socket or TCP.\n- [Better Stack](https://betterstack.com/community/guides/scaling-docker/) - :yen: A Docker-compatible observability stack that delivers robust log aggregation and uptime monitoring capabilities for various software application.\n- [Broadcom Docker Monitoring](https://www.broadcom.com/info/aiops/docker-monitoring) - :yen: Agile Operations solutions from Broadcom deliver the modern Docker monitoring businesses need to accelerate and optimize the performance of microservices and the dynamic Docker environments running them. Monitor both the Docker environment and apps that run inside them. (former CA Technologies).\n-   [Collecting docker logs and stats with Splunk](https://www.splunk.com/en_us/blog/tips-and-tricks/collecting-docker-logs-and-stats-with-splunk.html)\n- [Datadog](https://www.datadoghq.com/) - :yen: Datadog is a full-stack monitoring service for large-scale cloud environments that aggregates metrics/events from servers, databases, and applications. It includes support for Docker, Kubernetes, and Mesos.\n- [Prometheus](https://prometheus.io/) - :yen: Open-source service monitoring system and time series database.\n- [Site24x7](https://www.site24x7.com/docker-monitoring.html) - :yen: Docker Monitoring for DevOps and IT is a SaaS Pay per Host model.\n- [SPM for Docker](https://github.com/sematext/sematext-agent-docker) :ice_cube: - :yen: Monitoring of host and container metrics, Docker events and logs. Automatic log parser. Anomaly Detection and alerting for metrics and logs. [sematext](https://github.com/sematext).\n- [Sysdig Monitor](https://www.sysdig.com/products/monitor) - :yen: Sysdig Monitor can be used as either software or a SaaS service to monitor, alert, and troubleshoot containers using system calls. It has container-specific features for Docker and Kubernetes.\n\n# Useful Resources\n\n-   **[Valuable Docker Links](http://nane.kratzke.pages.mylab.th-luebeck.de/about/blog/2014/08/24/valuable-docker-links/)** High quality articles about docker! **MUST SEE**\n-   [Cloud Native Landscape](https://github.com/cncf/landscape)\n- [Docker Blog](https://www.docker.com/blog/) - Regular updates about Docker, the community and tools.\n-   [Docker Certification](https://intellipaat.com/docker-training-course/?US) :yen: will help you to will Learn Docker containerization, running Docker containers, Image creation, Dockerfile, Docker orchestration, security best practices, and more through hands-on projects and case studies and helps to clear Docker Certified Associate.\n\n- [Docker dev bookmarks](https://www.codever.dev/search?q=docker) - Use the tag [docker](https://www.codever.dev/bookmarks/t/docker).\n-   [Docker in Action, Second Edition](https://www.manning.com/books/docker-in-action-second-edition)\n-   [Docker in Practice, Second Edition](https://www.manning.com/books/docker-in-practice-second-edition)\n- [Docker packaging guide for Python](https://pythonspeed.com/docker/) - A series of detailed articles on the specifics of Docker packaging for Python.\n-   [Learn Docker in a Month of Lunches](https://www.manning.com/books/learn-docker-in-a-month-of-lunches)\n- [Learn Docker](https://coursesity.com/blog/best-docker-tutorials/) - Learn Docker - curated list of the top online docker tutorials and courses.\n-   [Programming Community Curated Resources for learning Docker](https://hackr.io/tutorials/learn-docker)\n\n## Awesome Lists\n\n- [Awesome CI/CD](https://github.com/cicdops/awesome-ciandcd) :ice_cube: - Not specific to docker but relevant.\n- [Awesome Compose](https://github.com/docker/awesome-compose) - Docker Compose samples.\n-   [Awesome Kubernetes](https://github.com/ramitsurana/awesome-kubernetes) by [ramitsurana][ramitsurana]\n-   [Awesome Linux Container](https://github.com/Friz-zy/awesome-linux-containers) more general about container than this repo, by [Friz-zy](https://github.com/Friz-zy).\n-   [Awesome Selfhosted](https://github.com/awesome-selfhosted/awesome-selfhosted) list of Free Software network services and web applications which can be hosted locally by running in a classical way (setup local web server and run applications from there) or in a Docker container. By [Kickball](https://github.com/Kickball)\n-   [Awesome Sysadmin](https://github.com/n1trux/awesome-sysadmin) by [n1trux](https://github.com/n1trux)\n-   [ToolsOfTheTrade](https://github.com/cjbarber/ToolsOfTheTrade) a list of SaaS and On premise applications by [cjbarber](https://github.com/cjbarber)\n\n## Demos and Examples\n\n-   [An Annotated Docker Config for Frontend Web Development](https://nystudio107.com/blog/an-annotated-docker-config-for-frontend-web-development) A local development environment with Docker allows you to shrink-wrap the devops your project needs as config, making onboarding frictionless.\n-   [Local Docker DB](https://github.com/alexmacarthur/local-docker-db) a list of docker-compose samples for a lot of databases by [alexmacarthur](https://github.com/alexmacarthur)\n-   [Webstack-micro](https://github.com/ferbs/webstack-micro) Demo web app showing how Docker Compose might be used to set up an API Gateway, centralized authentication, background workers, and WebSockets as containerized services.\n\n## Good Tips\n\n-   [Docker Caveats](http://docker-saigon.github.io/post/Docker-Caveats/) What You Should Know About Running Docker In Production (written 11 APRIL 2016) **MUST SEE**\n- [Docker Containers on the Desktop](https://blog.jessfraz.com/post/docker-containers-on-the-desktop/) - The **funniest way** to learn about docker by [jessfraz][jessfraz] who also gave a [presentation](https://www.youtube.com/watch?v=1qlLUf7KtAw) about it @ DockerCon 2015.\n-   [Docker vs. VMs? Combining Both for Cloud Portability Nirvana](https://www.flexera.com/blog/finops/)\n- [Dockerfile best practices](https://github.com/hexops/dockerfile) :ice_cube: - This repository has best-practices for writing Dockerfiles.\n-   [Don't Repeat Yourself with Anchors, Aliases and Extensions in Docker Compose Files](https://medium.com/@kinghuang/docker-compose-anchors-aliases-extensions-a1e4105d70bd) by [King Chung Huang](https://github.com/kinghuang)\n-   [GUI Apps with Docker](http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/) by [fgrehm][fgrehm]\n\n## Raspberry Pi & ARM\n\n-   [Docker Pirates ARMed with explosive stuff](https://blog.hypriot.com/) Huge resource on clustering, swarm, docker, pre-installed image for SD card on Raspberry Pi\n-   [Get Docker up and running on the RaspberryPi in three steps](https://github.com/umiddelb/armhf/wiki/Get-Docker-up-and-running-on-the-RaspberryPi-%28ARMv6%29-in-three-steps)\n-   [git push docker containers to linux devices](https://www.balena.io) Modern DevOps for IoT, leveraging git and Docker.\n-   [Installing, running, using Docker on armhf (ARMv7) devices](https://github.com/umiddelb/armhf/wiki/Installing,-running,-using-docker-on-armhf-%28ARMv7%29-devices)\n\n## Security\n\n-   [Bringing new security features to Docker](https://opensource.com/business/14/9/security-for-docker)\n-   [CVE Scanning Alpine images with Multi-stage builds in Docker 17.05](https://github.com/tomwillfixit/alpine-cvecheck) by [tomwillfixit](https://twitter.com/tomwillfixit)\n-   [Docker Secure Deployment Guidelines](https://github.com/AonCyberLabs/Docker-Secure-Deployment-Guidelines)\n-   [Docker Security - Quick Reference](https://binarymist.io/publication/docker-security/)\n-   [Docker Security: Are Your Containers Tightly Secured to the Ship? SlideShare](https://www.slideshare.net/slideshow/docker-security-are-your-containers-tightly-secured-to-the-ship/43834790)\n-   [How CVE's are handled on Offical Docker Images](https://github.com/docker-library/official-images/issues/1448)\n-   [Lynis is an open source security auditing tool including Docker auditing](https://cisofy.com/lynis/)\n-   [Security Best Practices for Building Docker Images](https://linux-audit.com/tags/docker/)\n-   [Software Engineering Radio interview of Docker Security Team Lead (Diogo Mónica)](https://www.se-radio.net/2017/05/se-radio-episode-290-diogo-monica-on-docker-security/)\n-   [Ten Docker Image Security Best Practices Cheat Sheet](https://snyk.io/blog/10-docker-image-security-best-practices/)\n-   [Top ten most popular docker images each contain at least 30 vulnerabilities](https://snyk.io/blog/top-ten-most-popular-docker-images-each-contain-at-least-30-vulnerabilities/)\n-   [Tuning Docker with the newest security enhancements](https://opensource.com/business/15/3/docker-security-tuning)\n-   [10 best practices to containerize Node.js web applications with Docker](https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/)\n\n## Videos\n\n-   [Contributing to Docker by Andrew \"Tianon\" Page (InfoSiftr)](https://www.youtube.com/watch?v=1jwo8-1HYYg) (34:31)\n-   [Deploying and scaling applications with Docker, Swarm, and a tiny bit of Python magic](https://www.youtube.com/watch?v=GpHMTR7P2Ms) (3:11:06) by [jpetazzo][jpetazzo]\n-   [Docker and SELinux by Daniel Walsh from Red Hat](https://www.youtube.com/watch?v=zWGFqMuEHdw) (40:23)\n-   [Docker Course](https://www.youtube.com/watch?v=UZpyvK6UGFo) (Spanish) by [pablokbs](https://github.com/pablokbs)\n-   [Docker for Developers](https://www.youtube.com/watch?v=FdkNAjjO5yQ) (54:26) by [jpetazzo][jpetazzo] <== Good introduction, context, demo\n-   [Docker from scratch](https://www.youtube.com/playlist?list=PLLhEJK7fQIxD-btrjrqdEfQHbkZnQrmqE) (1:22:01) on YouTube by Paris Nakita Kejser\n-   [Docker: How to Use Your Own Private Registry](https://www.youtube.com/watch?v=CAewZCBT4PI) (15:01)\n-   [Docker in Production](https://www.youtube.com/watch?v=Glk5d5WP6MI) by [jpetazzo][jpetazzo] (36:05)\n-   [Docker Primer to Docker Compose](https://www.youtube.com/watch?v=G-s2GXGAjTk) (1:56:45) on YouTube by LoginRadius\n-   [Docker Registry from scratch](https://www.youtube.com/playlist?list=PLLhEJK7fQIxAz3d4Fj3edq7UcxEhdTCBm) (44:40) on YouTube by Paris Nakita Kejser\n-   [Docker Swarm from scratch](https://www.youtube.com/playlist?list=PLLhEJK7fQIxAY4gZd1Wl-GsLvg-e9Ap1e) (1:41:28) on YouTube by Paris Nakita Kejser\n-   [Extending Docker with Plugins](https://vimeo.com/110835013) (15:21)\n-   [From Local Docker Development to Production Deployments](https://www.youtube.com/watch?v=7CZFpHUPqXw) by [jpetazzo][jpetazzo] @ AWS re:Invent 2015\n-   [Immutable Infrastructure with Docker and EC2 by Michael Bryzek (Gilt)](https://www.youtube.com/watch?v=GaHzdqFithc) (42:04)\n-   [Introduction to Docker and containers](https://www.youtube.com/watch?v=ZVaRK10HBjo) (3:09:00) by [jpetazzo][jpetazzo]\n-   [Logging on Docker: What You Need to Know](https://vimeo.com/123341629) (51:27)\n-   [Performance Analysis of Docker - Jeremy Eder](https://www.youtube.com/watch?v=6f2E6PKYb0w) (1:36:58)\n-   [Scalable Microservices with Kubernetes](https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615) Free Udacity course\n-   [State of containers: a debate with CoreOS, VMware and Google](https://www.youtube.com/watch?v=IiITP3yIRd8) (27:38)\n\n# Communities and Meetups\n\n## Brazilian\n\n-   [Docker BR on Telegram](https://telegram.me/dockerbr)\n\n## English\n\n-   [Docker Community](https://www.docker.com/community/)\n-   [Docker Events](https://www.docker.com/events/)\n-   [Docker Online Meetup](https://www.meetup.com/en-AU/Docker-Online-Meetup/)\n-   [Docker Reddit Community](https://www.reddit.com/r/docker/)\n\n## Russian\n\n-   [Docker Russian-speaking Community](https://t.me/docker_ru)\n\n## Spanish\n\n-   [Docker Tips](https://dockertips.com/)\n\n## Stargazers over time\n\n[![Stargazers over time](https://starchart.cc/veggiemonk/awesome-docker.svg?variant=adaptive)](https://starchart.cc/veggiemonk/awesome-docker)\n\n[contributing]: https://github.com/veggiemonk/awesome-docker/blob/master/.github/CONTRIBUTING.md\n[calico]: https://github.com/projectcalico/calico\n[containx]: https://github.com/ContainX\n[coreos]: https://github.com/coreos\n[deepfence]: https://github.com/deepfence\n[distribution]: https://github.com/docker/distribution\n[docker-flow]: https://github.com/docker-flow\n[docker-for-windows]: https://docs.docker.com/desktop/setup/install/windows-install/\n[docker]: https://github.com/docker\n[dozzle]: https://github.com/amir20/dozzle\n[editreadme]: https://github.com/veggiemonk/awesome-docker/edit/master/README.md\n[fgrehm]: https://github.com/fgrehm\n[gliderlabs]: https://github.com/gliderlabs\n[googlecontainertools]: https://github.com/GoogleContainerTools\n[inspec]: https://github.com/inspec/inspec\n[jessfraz]: https://github.com/jessfraz\n[jpetazzo]: https://github.com/jpetazzo\n[jwilder]: https://github.com/jwilder\n[kubernetes]: https://kubernetes.io\n[lispyclouds]: https://github.com/lispyclouds\n[nginxproxy]: https://github.com/nginx-proxy/nginx-proxy\n[openshift]: https://okd.io/\n[powerman]: https://github.com/powerman\n[progrium]: https://github.com/progrium\n[ramitsurana]: https://github.com/ramitsurana\n[sindresorhus]: https://github.com/sindresorhus/awesome\n[spotify]: https://github.com/spotify\n[vegasbrianc]: https://github.com/vegasbrianc\n[vmware]: https://github.com/vmware\n[byrnedo]: https://github.com/byrnedo\n[crazy-max]: https://github.com/crazy-max\n[skanehira]: https://github.com/skanehira\n[akito]: https://github.com/theAkito\n[peco602]: https://github.com/Peco602\n[weave]: https://github.com/weaveworks/weave\n"
  },
  {
    "path": "cmd/awesome-docker/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/veggiemonk/awesome-docker/internal/builder\"\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n\t\"github.com/veggiemonk/awesome-docker/internal/checker\"\n\t\"github.com/veggiemonk/awesome-docker/internal/linter\"\n\t\"github.com/veggiemonk/awesome-docker/internal/parser\"\n\t\"github.com/veggiemonk/awesome-docker/internal/scorer\"\n\t\"github.com/veggiemonk/awesome-docker/internal/tui\"\n)\n\nconst (\n\treadmePath      = \"README.md\"\n\texcludePath     = \"config/exclude.yaml\"\n\ttemplatePath    = \"config/website.tmpl.html\"\n\thealthCachePath = \"config/health_cache.yaml\"\n\twebsiteOutput   = \"website/index.html\"\n\tversion         = \"0.1.0\"\n)\n\ntype checkSummary struct {\n\tExternalTotal int\n\tGitHubTotal   int\n\tBroken        []checker.LinkResult\n\tRedirected    []checker.LinkResult\n\tGitHubErrors  []error\n\tGitHubSkipped bool\n}\n\nfunc main() {\n\troot := &cobra.Command{\n\t\tUse:   \"awesome-docker\",\n\t\tShort: \"Quality tooling for the awesome-docker curated list\",\n\t}\n\n\troot.AddCommand(\n\t\tversionCmd(),\n\t\tlintCmd(),\n\t\tcheckCmd(),\n\t\thealthCmd(),\n\t\tbuildCmd(),\n\t\treportCmd(),\n\t\tvalidateCmd(),\n\t\tciCmd(),\n\t\tbrowseCmd(),\n\t)\n\n\tif err := root.Execute(); err != nil {\n\t\tos.Exit(1)\n\t}\n}\n\nfunc versionCmd() *cobra.Command {\n\treturn &cobra.Command{\n\t\tUse:   \"version\",\n\t\tShort: \"Print version\",\n\t\tRun:   func(cmd *cobra.Command, args []string) { fmt.Printf(\"awesome-docker v%s\\n\", version) },\n\t}\n}\n\nfunc parseReadme() (parser.Document, error) {\n\tf, err := os.Open(readmePath)\n\tif err != nil {\n\t\treturn parser.Document{}, err\n\t}\n\tdefer f.Close()\n\treturn parser.Parse(f)\n}\n\nfunc collectURLs(sections []parser.Section, urls *[]string) {\n\tfor _, s := range sections {\n\t\tfor _, e := range s.Entries {\n\t\t\t*urls = append(*urls, e.URL)\n\t\t}\n\t\tcollectURLs(s.Children, urls)\n\t}\n}\n\ntype entryMeta struct {\n\tCategory    string\n\tDescription string\n}\n\nfunc collectEntriesWithCategory(sections []parser.Section, parentPath string, out map[string]entryMeta) {\n\tfor _, s := range sections {\n\t\tpath := s.Title\n\t\tif parentPath != \"\" {\n\t\t\tpath = parentPath + \" > \" + s.Title\n\t\t}\n\t\tfor _, e := range s.Entries {\n\t\t\tout[e.URL] = entryMeta{Category: path, Description: e.Description}\n\t\t}\n\t\tcollectEntriesWithCategory(s.Children, path, out)\n\t}\n}\n\nfunc runLinkChecks(prMode bool) (checkSummary, error) {\n\tdoc, err := parseReadme()\n\tif err != nil {\n\t\treturn checkSummary{}, fmt.Errorf(\"parse: %w\", err)\n\t}\n\n\tvar urls []string\n\tcollectURLs(doc.Sections, &urls)\n\n\texclude, err := cache.LoadExcludeList(excludePath)\n\tif err != nil {\n\t\treturn checkSummary{}, fmt.Errorf(\"load exclude list: %w\", err)\n\t}\n\n\tghURLs, extURLs := checker.PartitionLinks(urls)\n\n\tsummary := checkSummary{\n\t\tExternalTotal: len(extURLs),\n\t\tGitHubTotal:   len(ghURLs),\n\t}\n\n\tresults := checker.CheckLinks(extURLs, 10, exclude)\n\tfor _, r := range results {\n\t\tif !r.OK {\n\t\t\tsummary.Broken = append(summary.Broken, r)\n\t\t}\n\t\tif r.Redirected {\n\t\t\tsummary.Redirected = append(summary.Redirected, r)\n\t\t}\n\t}\n\n\tif prMode {\n\t\tsummary.GitHubSkipped = true\n\t\treturn summary, nil\n\t}\n\n\ttoken := os.Getenv(\"GITHUB_TOKEN\")\n\tif token == \"\" {\n\t\tsummary.GitHubSkipped = true\n\t\treturn summary, nil\n\t}\n\n\tgc := checker.NewGitHubChecker(token)\n\t_, errs := gc.CheckRepos(context.Background(), ghURLs, 50)\n\tsummary.GitHubErrors = errs\n\treturn summary, nil\n}\n\nfunc runHealth(ctx context.Context) error {\n\ttoken := os.Getenv(\"GITHUB_TOKEN\")\n\tif token == \"\" {\n\t\treturn fmt.Errorf(\"GITHUB_TOKEN environment variable is required\")\n\t}\n\n\tdoc, err := parseReadme()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse: %w\", err)\n\t}\n\n\tvar urls []string\n\tcollectURLs(doc.Sections, &urls)\n\tghURLs, _ := checker.PartitionLinks(urls)\n\n\tfmt.Printf(\"Scoring %d GitHub repositories...\\n\", len(ghURLs))\n\tgc := checker.NewGitHubChecker(token)\n\tinfos, errs := gc.CheckRepos(ctx, ghURLs, 50)\n\tfor _, e := range errs {\n\t\tfmt.Printf(\"  error: %v\\n\", e)\n\t}\n\tif len(infos) == 0 {\n\t\tif len(errs) > 0 {\n\t\t\treturn fmt.Errorf(\"failed to fetch GitHub metadata for all repositories (%d errors); check network/DNS and GITHUB_TOKEN\", len(errs))\n\t\t}\n\t\treturn fmt.Errorf(\"no GitHub repositories found in README\")\n\t}\n\n\tscored := scorer.ScoreAll(infos)\n\n\tmeta := make(map[string]entryMeta)\n\tcollectEntriesWithCategory(doc.Sections, \"\", meta)\n\tfor i := range scored {\n\t\tif m, ok := meta[scored[i].URL]; ok {\n\t\t\tscored[i].Category = m.Category\n\t\t\tscored[i].Description = m.Description\n\t\t}\n\t}\n\n\tcacheEntries := scorer.ToCacheEntries(scored)\n\n\thc, err := cache.LoadHealthCache(healthCachePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"load cache: %w\", err)\n\t}\n\thc.Merge(cacheEntries)\n\tif err := cache.SaveHealthCache(healthCachePath, hc); err != nil {\n\t\treturn fmt.Errorf(\"save cache: %w\", err)\n\t}\n\n\tfmt.Printf(\"Cache updated: %d entries in %s\\n\", len(hc.Entries), healthCachePath)\n\treturn nil\n}\n\nfunc scoredFromCache() ([]scorer.ScoredEntry, error) {\n\thc, err := cache.LoadHealthCache(healthCachePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"load cache: %w\", err)\n\t}\n\tif len(hc.Entries) == 0 {\n\t\treturn nil, fmt.Errorf(\"no cache data, run 'health' first\")\n\t}\n\n\tscored := make([]scorer.ScoredEntry, 0, len(hc.Entries))\n\tfor _, e := range hc.Entries {\n\t\tscored = append(scored, scorer.ScoredEntry{\n\t\t\tURL:         e.URL,\n\t\t\tName:        e.Name,\n\t\t\tStatus:      scorer.Status(e.Status),\n\t\t\tStars:       e.Stars,\n\t\t\tForks:       e.Forks,\n\t\t\tHasLicense:  e.HasLicense,\n\t\t\tLastPush:    e.LastPush,\n\t\t\tCategory:    e.Category,\n\t\t\tDescription: e.Description,\n\t\t})\n\t}\n\treturn scored, nil\n}\n\nfunc markdownReportFromCache() (string, error) {\n\tscored, err := scoredFromCache()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn scorer.GenerateReport(scored), nil\n}\n\nfunc writeGitHubOutput(path, key, value string) error {\n\tif path == \"\" {\n\t\treturn nil\n\t}\n\tf, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open github output file: %w\", err)\n\t}\n\tdefer f.Close()\n\tif _, err := fmt.Fprintf(f, \"%s=%s\\n\", key, value); err != nil {\n\t\treturn fmt.Errorf(\"write github output: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc sanitizeOutputValue(v string) string {\n\tv = strings.ReplaceAll(v, \"\\n\", \" \")\n\tv = strings.ReplaceAll(v, \"\\r\", \" \")\n\treturn strings.TrimSpace(v)\n}\n\nfunc buildBrokenLinksIssueBody(summary checkSummary, runErr error) string {\n\tvar b strings.Builder\n\tb.WriteString(\"# Broken Links Detected\\n\\n\")\n\n\tif runErr != nil {\n\t\tb.WriteString(\"The link checker failed to execute cleanly.\\n\\n\")\n\t\tb.WriteString(\"## Failure\\n\\n\")\n\t\tfmt.Fprintf(&b, \"- %s\\n\\n\", runErr)\n\t} else {\n\t\tfmt.Fprintf(&b, \"- Broken links: %d\\n\", len(summary.Broken))\n\t\tfmt.Fprintf(&b, \"- Redirected links: %d\\n\", len(summary.Redirected))\n\t\tfmt.Fprintf(&b, \"- GitHub API errors: %d\\n\\n\", len(summary.GitHubErrors))\n\n\t\tif len(summary.Broken) > 0 {\n\t\t\tb.WriteString(\"## Broken Links\\n\\n\")\n\t\t\tfor _, r := range summary.Broken {\n\t\t\t\tfmt.Fprintf(&b, \"- `%s` -> `%d %s`\\n\", r.URL, r.StatusCode, strings.TrimSpace(r.Error))\n\t\t\t}\n\t\t\tb.WriteString(\"\\n\")\n\t\t}\n\n\t\tif len(summary.GitHubErrors) > 0 {\n\t\t\tb.WriteString(\"## GitHub API Errors\\n\\n\")\n\t\t\tfor _, e := range summary.GitHubErrors {\n\t\t\t\tfmt.Fprintf(&b, \"- `%s`\\n\", e)\n\t\t\t}\n\t\t\tb.WriteString(\"\\n\")\n\t\t}\n\t}\n\n\tb.WriteString(\"## Action Required\\n\\n\")\n\tb.WriteString(\"- Update the URL if the resource moved\\n\")\n\tb.WriteString(\"- Remove the entry if permanently unavailable\\n\")\n\tb.WriteString(\"- Add to `config/exclude.yaml` if a known false positive\\n\")\n\tb.WriteString(\"- Investigate GitHub API/auth failures when present\\n\\n\")\n\tb.WriteString(\"---\\n\")\n\tb.WriteString(\"*Auto-generated by awesome-docker ci broken-links*\\n\")\n\treturn b.String()\n}\n\nfunc buildHealthReportIssueBody(report string, healthErr error) string {\n\tvar b strings.Builder\n\tif healthErr != nil {\n\t\tb.WriteString(\"WARNING: health refresh failed in this run; showing latest cached report.\\n\\n\")\n\t\tfmt.Fprintf(&b, \"Error: `%s`\\n\\n\", healthErr)\n\t}\n\tb.WriteString(report)\n\tif !strings.HasSuffix(report, \"\\n\") {\n\t\tb.WriteString(\"\\n\")\n\t}\n\tb.WriteString(\"\\n---\\n\")\n\tb.WriteString(\"*Auto-generated weekly by awesome-docker ci health-report*\\n\")\n\treturn b.String()\n}\n\nfunc lintCmd() *cobra.Command {\n\tvar fix bool\n\tcmd := &cobra.Command{\n\t\tUse:   \"lint\",\n\t\tShort: \"Validate README formatting\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tdoc, err := parseReadme()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"parse: %w\", err)\n\t\t\t}\n\n\t\t\tresult := linter.Lint(doc)\n\t\t\tfor _, issue := range result.Issues {\n\t\t\t\tfmt.Println(issue)\n\t\t\t}\n\n\t\t\tif result.Errors > 0 {\n\t\t\t\tfmt.Printf(\"\\n%d errors, %d warnings\\n\", result.Errors, result.Warnings)\n\t\t\t\tif !fix {\n\t\t\t\t\treturn fmt.Errorf(\"lint failed with %d errors\", result.Errors)\n\t\t\t\t}\n\t\t\t\tcount, err := linter.FixFile(readmePath)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"fix: %w\", err)\n\t\t\t\t}\n\t\t\t\tfmt.Printf(\"Fixed %d lines in %s\\n\", count, readmePath)\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\"OK: %d warnings\\n\", result.Warnings)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n\tcmd.Flags().BoolVar(&fix, \"fix\", false, \"Auto-fix formatting issues\")\n\treturn cmd\n}\n\nfunc checkCmd() *cobra.Command {\n\tvar prMode bool\n\tcmd := &cobra.Command{\n\t\tUse:   \"check\",\n\t\tShort: \"Check links for reachability\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tsummary, err := runLinkChecks(prMode)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Printf(\"Checking %d external links...\\n\", summary.ExternalTotal)\n\t\t\tif !prMode {\n\t\t\t\tif summary.GitHubSkipped {\n\t\t\t\t\tfmt.Println(\"GITHUB_TOKEN not set, skipping GitHub repo checks\")\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Printf(\"Checking %d GitHub repositories...\\n\", summary.GitHubTotal)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, e := range summary.GitHubErrors {\n\t\t\t\tfmt.Printf(\"  GitHub error: %v\\n\", e)\n\t\t\t}\n\n\t\t\tif len(summary.Redirected) > 0 {\n\t\t\t\tfmt.Printf(\"\\n%d redirected links (consider updating):\\n\", len(summary.Redirected))\n\t\t\t\tfor _, r := range summary.Redirected {\n\t\t\t\t\tfmt.Printf(\"  %s -> %s\\n\", r.URL, r.RedirectURL)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(summary.Broken) > 0 {\n\t\t\t\tfmt.Printf(\"\\n%d broken links:\\n\", len(summary.Broken))\n\t\t\t\tfor _, r := range summary.Broken {\n\t\t\t\t\tfmt.Printf(\"  %s -> %d %s\\n\", r.URL, r.StatusCode, r.Error)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(summary.Broken) > 0 && len(summary.GitHubErrors) > 0 {\n\t\t\t\treturn fmt.Errorf(\"found %d broken links and %d GitHub API errors\", len(summary.Broken), len(summary.GitHubErrors))\n\t\t\t}\n\t\t\tif len(summary.Broken) > 0 {\n\t\t\t\treturn fmt.Errorf(\"found %d broken links\", len(summary.Broken))\n\t\t\t}\n\t\t\tif len(summary.GitHubErrors) > 0 {\n\t\t\t\treturn fmt.Errorf(\"github checks failed with %d errors\", len(summary.GitHubErrors))\n\t\t\t}\n\n\t\t\tfmt.Println(\"All links OK\")\n\t\t\treturn nil\n\t\t},\n\t}\n\tcmd.Flags().BoolVar(&prMode, \"pr\", false, \"PR mode: skip GitHub API checks\")\n\treturn cmd\n}\n\nfunc healthCmd() *cobra.Command {\n\treturn &cobra.Command{\n\t\tUse:   \"health\",\n\t\tShort: \"Score repository health and update cache\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\treturn runHealth(context.Background())\n\t\t},\n\t}\n}\n\nfunc buildCmd() *cobra.Command {\n\treturn &cobra.Command{\n\t\tUse:   \"build\",\n\t\tShort: \"Generate website from README\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tif err := builder.Build(readmePath, templatePath, websiteOutput); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Website built: %s\\n\", websiteOutput)\n\t\t\treturn nil\n\t\t},\n\t}\n}\n\nfunc reportCmd() *cobra.Command {\n\tvar jsonOutput bool\n\tcmd := &cobra.Command{\n\t\tUse:   \"report\",\n\t\tShort: \"Generate health report from cache\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tscored, err := scoredFromCache()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif jsonOutput {\n\t\t\t\tpayload, err := scorer.GenerateJSONReport(scored)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"json report: %w\", err)\n\t\t\t\t}\n\t\t\t\tfmt.Println(string(payload))\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treport := scorer.GenerateReport(scored)\n\t\t\tfmt.Print(report)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tcmd.Flags().BoolVar(&jsonOutput, \"json\", false, \"Output full health report as JSON\")\n\treturn cmd\n}\n\nfunc validateCmd() *cobra.Command {\n\treturn &cobra.Command{\n\t\tUse:   \"validate\",\n\t\tShort: \"PR validation: lint + check --pr\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tfmt.Println(\"=== Linting ===\")\n\t\t\tdoc, err := parseReadme()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"parse: %w\", err)\n\t\t\t}\n\n\t\t\tresult := linter.Lint(doc)\n\t\t\tfor _, issue := range result.Issues {\n\t\t\t\tfmt.Println(issue)\n\t\t\t}\n\t\t\tif result.Errors > 0 {\n\t\t\t\tfmt.Printf(\"\\n%d errors, %d warnings\\n\", result.Errors, result.Warnings)\n\t\t\t\treturn fmt.Errorf(\"lint failed with %d errors\", result.Errors)\n\t\t\t}\n\t\t\tfmt.Printf(\"Lint OK: %d warnings\\n\", result.Warnings)\n\n\t\t\tfmt.Println(\"\\n=== Checking links (PR mode) ===\")\n\t\t\tsummary, err := runLinkChecks(true)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Checking %d external links...\\n\", summary.ExternalTotal)\n\t\t\tif len(summary.Broken) > 0 {\n\t\t\t\tfmt.Printf(\"\\n%d broken links:\\n\", len(summary.Broken))\n\t\t\t\tfor _, r := range summary.Broken {\n\t\t\t\t\tfmt.Printf(\"  %s -> %d %s\\n\", r.URL, r.StatusCode, r.Error)\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"found %d broken links\", len(summary.Broken))\n\t\t\t}\n\n\t\t\tfmt.Println(\"\\nValidation passed\")\n\t\t\treturn nil\n\t\t},\n\t}\n}\n\nfunc ciCmd() *cobra.Command {\n\tcmd := &cobra.Command{\n\t\tUse:   \"ci\",\n\t\tShort: \"CI-oriented helper commands\",\n\t}\n\tcmd.AddCommand(\n\t\tciBrokenLinksCmd(),\n\t\tciHealthReportCmd(),\n\t)\n\treturn cmd\n}\n\nfunc ciBrokenLinksCmd() *cobra.Command {\n\tvar issueFile string\n\tvar githubOutput string\n\tvar strict bool\n\n\tcmd := &cobra.Command{\n\t\tUse:   \"broken-links\",\n\t\tShort: \"Run link checks and emit CI outputs/artifacts\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tsummary, runErr := runLinkChecks(false)\n\n\t\t\thasErrors := runErr != nil || len(summary.Broken) > 0 || len(summary.GitHubErrors) > 0\n\t\t\texitCode := 0\n\t\t\tif hasErrors {\n\t\t\t\texitCode = 1\n\t\t\t}\n\t\t\tif runErr != nil {\n\t\t\t\texitCode = 2\n\t\t\t}\n\n\t\t\tif issueFile != \"\" && hasErrors {\n\t\t\t\tbody := buildBrokenLinksIssueBody(summary, runErr)\n\t\t\t\tif err := os.WriteFile(issueFile, []byte(body), 0o644); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"write issue file: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := writeGitHubOutput(githubOutput, \"has_errors\", strconv.FormatBool(hasErrors)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeGitHubOutput(githubOutput, \"check_exit_code\", strconv.Itoa(exitCode)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeGitHubOutput(githubOutput, \"broken_count\", strconv.Itoa(len(summary.Broken))); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeGitHubOutput(githubOutput, \"github_error_count\", strconv.Itoa(len(summary.GitHubErrors))); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif runErr != nil {\n\t\t\t\tif err := writeGitHubOutput(githubOutput, \"run_error\", sanitizeOutputValue(runErr.Error())); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif runErr != nil {\n\t\t\t\tfmt.Printf(\"CI broken-links run error: %v\\n\", runErr)\n\t\t\t}\n\t\t\tif hasErrors {\n\t\t\t\tfmt.Printf(\"CI broken-links found %d broken links and %d GitHub errors\\n\", len(summary.Broken), len(summary.GitHubErrors))\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"CI broken-links found no errors\")\n\t\t\t}\n\n\t\t\tif strict {\n\t\t\t\tif runErr != nil {\n\t\t\t\t\treturn runErr\n\t\t\t\t}\n\t\t\t\tif hasErrors {\n\t\t\t\t\treturn fmt.Errorf(\"found %d broken links and %d GitHub API errors\", len(summary.Broken), len(summary.GitHubErrors))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tcmd.Flags().StringVar(&issueFile, \"issue-file\", \"broken_links_issue.md\", \"Path to write issue markdown body\")\n\tcmd.Flags().StringVar(&githubOutput, \"github-output\", \"\", \"Path to GitHub output file (typically $GITHUB_OUTPUT)\")\n\tcmd.Flags().BoolVar(&strict, \"strict\", false, \"Return non-zero when errors are found\")\n\treturn cmd\n}\n\nfunc ciHealthReportCmd() *cobra.Command {\n\tvar issueFile string\n\tvar githubOutput string\n\tvar strict bool\n\n\tcmd := &cobra.Command{\n\t\tUse:   \"health-report\",\n\t\tShort: \"Refresh health cache, render report, and emit CI outputs/artifacts\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\thealthErr := runHealth(context.Background())\n\t\t\treport, reportErr := markdownReportFromCache()\n\n\t\t\thealthOK := healthErr == nil\n\t\t\treportOK := reportErr == nil\n\t\t\thasReport := reportOK && strings.TrimSpace(report) != \"\"\n\t\t\thasErrors := !healthOK || !reportOK\n\n\t\t\tif hasReport && issueFile != \"\" {\n\t\t\t\tbody := buildHealthReportIssueBody(report, healthErr)\n\t\t\t\tif err := os.WriteFile(issueFile, []byte(body), 0o644); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"write issue file: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := writeGitHubOutput(githubOutput, \"has_report\", strconv.FormatBool(hasReport)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeGitHubOutput(githubOutput, \"health_ok\", strconv.FormatBool(healthOK)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeGitHubOutput(githubOutput, \"report_ok\", strconv.FormatBool(reportOK)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeGitHubOutput(githubOutput, \"has_errors\", strconv.FormatBool(hasErrors)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif healthErr != nil {\n\t\t\t\tif err := writeGitHubOutput(githubOutput, \"health_error\", sanitizeOutputValue(healthErr.Error())); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif reportErr != nil {\n\t\t\t\tif err := writeGitHubOutput(githubOutput, \"report_error\", sanitizeOutputValue(reportErr.Error())); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif healthErr != nil {\n\t\t\t\tfmt.Printf(\"CI health-report health error: %v\\n\", healthErr)\n\t\t\t}\n\t\t\tif reportErr != nil {\n\t\t\t\tfmt.Printf(\"CI health-report report error: %v\\n\", reportErr)\n\t\t\t}\n\t\t\tif hasReport {\n\t\t\t\tfmt.Println(\"CI health-report generated report artifact\")\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"CI health-report has no report artifact\")\n\t\t\t}\n\n\t\t\tif strict {\n\t\t\t\tif healthErr != nil {\n\t\t\t\t\treturn healthErr\n\t\t\t\t}\n\t\t\t\tif reportErr != nil {\n\t\t\t\t\treturn reportErr\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tcmd.Flags().StringVar(&issueFile, \"issue-file\", \"health_report.txt\", \"Path to write health issue markdown body\")\n\tcmd.Flags().StringVar(&githubOutput, \"github-output\", \"\", \"Path to GitHub output file (typically $GITHUB_OUTPUT)\")\n\tcmd.Flags().BoolVar(&strict, \"strict\", false, \"Return non-zero when health/report fails\")\n\treturn cmd\n}\n\nfunc browseCmd() *cobra.Command {\n\tvar cachePath string\n\tcmd := &cobra.Command{\n\t\tUse:   \"browse\",\n\t\tShort: \"Interactive TUI browser for awesome-docker resources\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\thc, err := cache.LoadHealthCache(cachePath)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"load cache: %w\", err)\n\t\t\t}\n\t\t\tif len(hc.Entries) == 0 {\n\t\t\t\treturn fmt.Errorf(\"no cache data; run 'awesome-docker health' first\")\n\t\t\t}\n\t\t\treturn tui.Run(hc.Entries)\n\t\t},\n\t}\n\tcmd.Flags().StringVar(&cachePath, \"cache\", healthCachePath, \"Path to health cache YAML\")\n\treturn cmd\n}\n"
  },
  {
    "path": "config/exclude.yaml",
    "content": "# URLs or URL prefixes to skip during link checking.\n# These are known false positives or rate-limited domains.\ndomains:\n  - https://vimeo.com\n  - https://travis-ci.org/veggiemonk/awesome-docker.svg\n  - https://github.com/apps/\n  - https://twitter.com\n  - https://www.meetup.com/\n  - https://cycle.io/\n  - https://www.manning.com/\n  - https://deepfence.io\n  - https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg\n  - https://www.se-radio.net/2017/05/se-radio-episode-290-diogo-monica-on-docker-security\n  - https://www.reddit.com/r/docker/\n  - https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615\n  - https://www.youtube.com/playlist\n  - https://www.aquasec.com\n  - https://cloudsmith.com\n"
  },
  {
    "path": "config/health_cache.yaml",
    "content": "entries:\n    - url: https://github.com/byrnedo/capitan\n      name: byrnedo/capitan\n      status: stale\n      stars: 31\n      last_push: 2017-06-07T09:46:56Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: Composable docker orchestration with added scripting support by [byrnedo].\n    - url: https://github.com/magicmark/composerize\n      name: magicmark/composerize\n      status: healthy\n      stars: 3703\n      forks: 247\n      last_push: 2026-01-17T12:14:28Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: Convert docker run commands into docker-compose files.\n    - url: https://github.com/polonskiy/crowdr\n      name: polonskiy/crowdr\n      status: stale\n      stars: 98\n      forks: 9\n      last_push: 2020-10-09T07:57:52Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: Tool for managing multiple Docker containers (`docker-compose` alternative).\n    - url: https://github.com/ctk-hq/ctk\n      name: ctk-hq/ctk\n      status: healthy\n      stars: 298\n      forks: 27\n      last_push: 2026-02-15T22:53:00Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: Visual composer for container based workloads. By [corpulent](https://github.com/corpulent).\n    - url: https://github.com/sudo-bmitch/docker-config-update\n      name: sudo-bmitch/docker-config-update\n      status: stale\n      stars: 51\n      forks: 8\n      last_push: 2023-03-30T13:03:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: Utility to update docker configs and secrets for deploying in a compose file.\n    - url: https://github.com/cisco/elsy\n      name: cisco/elsy\n      status: stale\n      stars: 80\n      forks: 22\n      last_push: 2022-01-18T13:38:49Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: An opinionated, multi-language, build tool based on Docker and Docker Compose.\n    - url: https://github.com/cloud66-oss/habitus\n      name: cloud66-oss/habitus\n      status: stale\n      stars: 1392\n      forks: 81\n      last_push: 2020-02-05T17:10:30Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: A Build Flow Tool for Docker.\n    - url: https://github.com/kubernetes/kompose\n      name: kubernetes/kompose\n      status: healthy\n      stars: 10464\n      forks: 794\n      last_push: 2026-02-27T14:23:27Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: Go from Docker Compose to Kubernetes.\n    - url: https://github.com/av/harbor\n      name: av/harbor\n      status: healthy\n      stars: 2485\n      forks: 166\n      last_push: 2026-03-08T14:30:46Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: A CLI and companion app to effortlessly run LLM backends, APIs, frontends, and services with one command. By [av](https://github.com/av).\n    - url: https://github.com/ihucos/plash\n      name: ihucos/plash\n      status: healthy\n      stars: 387\n      forks: 15\n      last_push: 2025-03-20T15:47:21Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: A container run and build engine - runs inside docker.\n    - url: https://github.com/containers/podman-compose\n      name: containers/podman-compose\n      status: healthy\n      stars: 5990\n      forks: 577\n      last_push: 2026-03-05T16:25:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: A script to run docker-compose.yml using podman.\n    - url: https://github.com/alexaandrov/stitchocker\n      name: alexaandrov/stitchocker\n      status: inactive\n      stars: 30\n      forks: 2\n      last_push: 2024-03-14T13:50:30Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Container Composition\n      description: A lightweight and fast command line utility for conveniently grouping your docker-compose multiple container services. By [alexaandrov](https://github.com/alexaandrov).\n    - url: https://github.com/ethibox/awesome-stacks\n      name: ethibox/awesome-stacks\n      status: healthy\n      stars: 1250\n      forks: 162\n      last_push: 2026-03-08T14:40:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Deploy 150+ open-source web apps with one Docker command.\n    - url: https://github.com/newrelic/centurion\n      name: newrelic/centurion\n      status: archived\n      stars: 1757\n      forks: 112\n      last_push: 2025-09-11T20:47:50Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Centurion is a mass deployment tool for Docker fleets. It takes containers from a Docker registry and runs them on a fleet of hosts with the correct environment variables, host volume mappings, and port mappings. By [newrelic](https://github.com/newrelic).\n    - url: https://github.com/brooklyncentral/clocker\n      name: brooklyncentral/clocker\n      status: stale\n      stars: 429\n      forks: 64\n      last_push: 2018-10-24T15:29:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Clocker creates and manages a Docker cloud infrastructure. Clocker supports single-click deployments and runtime management of multi-node applications that run as containers distributed across multiple hosts, on both Docker and Marathon. It leverages [Calico][calico] and [Weave][weave] for networking and [Brooklyn](https://brooklyn.apache.org/) for application blueprints. By [brooklyncentral](https://github.com/brooklyncentral).\n    - url: https://github.com/ehazlett/conduit\n      name: ehazlett/conduit\n      status: stale\n      stars: 108\n      forks: 11\n      last_push: 2016-11-07T18:20:56Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Experimental deployment system for Docker.\n    - url: https://github.com/ContainX/depcon\n      name: ContainX/depcon\n      status: stale\n      stars: 93\n      forks: 15\n      last_push: 2018-06-05T04:40:23Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Depcon is written in Go and allows you to easily deploy Docker containers to Apache Mesos/Marathon, Amazon ECS and Kubernetes. By [ContainX][containx].\n    - url: https://github.com/deploystackio/docker-to-iac\n      name: deploystackio/docker-to-iac\n      status: healthy\n      stars: 23\n      last_push: 2026-03-02T06:11:33Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Translate docker run and commit into Infrastructure as Code templates for AWS, Render.com and DigitalOcean.\n    - url: https://github.com/hasura/gitkube\n      name: hasura/gitkube\n      status: stale\n      stars: 3850\n      forks: 203\n      last_push: 2023-08-31T07:48:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Gitkube is a tool for building and deploying docker images on Kubernetes using `git push`. By [Hasura](https://github.com/hasura/).\n    - url: https://github.com/grafeas/grafeas\n      name: grafeas/grafeas\n      status: healthy\n      stars: 1564\n      forks: 307\n      last_push: 2026-02-13T21:53:15Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: A common API for metadata about containers, from image and build details to security vulnerabilities. By [grafeas](https://github.com/grafeas).\n    - url: https://github.com/LombardiDaniel/swarm-ansible\n      name: LombardiDaniel/swarm-ansible\n      status: healthy\n      stars: 59\n      forks: 4\n      last_push: 2026-01-24T22:01:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n    - url: https://github.com/hansehe/SwarmManagement\n      name: hansehe/SwarmManagement\n      status: healthy\n      stars: 21\n      forks: 1\n      last_push: 2025-05-13T15:24:25Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Swarm Management is a python application, installed with pip. The application makes it easy to manage a Docker Swarm by configuring a single yaml file describing which stacks to deploy, and which networks, configs or secrets to create.\n    - url: https://github.com/werf/werf\n      name: werf/werf\n      status: healthy\n      stars: 4661\n      forks: 230\n      last_push: 2026-03-06T15:47:09Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Deployment and Infrastructure\n      description: Werf is a CI/CD tool for building Docker images efficiently and deploying them to Kubernetes using GitOps.\n    - url: https://github.com/willfarrell/docker-autoheal\n      name: willfarrell/docker-autoheal\n      status: healthy\n      stars: 1801\n      forks: 254\n      last_push: 2025-09-09T16:33:25Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Monitor and restart unhealthy docker containers automatically.\n    - url: https://github.com/google/cadvisor\n      name: google/cadvisor\n      status: healthy\n      stars: 18952\n      forks: 2461\n      last_push: 2026-03-02T18:35:32Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Analyzes resource usage and performance characteristics of running containers.\n    - url: https://github.com/bluewave-labs/checkmate\n      name: bluewave-labs/checkmate\n      status: healthy\n      stars: 9372\n      forks: 680\n      last_push: 2026-03-07T01:22:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Checkmate is an open-source, self-hosted tool designed to track and monitor server hardware, uptime, response times, and incidents in real-time with beautiful visualizations.\n    - url: https://github.com/zorak1103/dlia\n      name: zorak1103/dlia\n      status: healthy\n      stars: 3\n      last_push: 2026-03-07T04:03:52Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: DLIA is an AI-powered Docker log monitoring agent that uses Large Language Models (LLMs) to intelligently analyze container logs, detect anomalies, and provide contextual insights over time. By [zorak1103](https://github.com/zorak1103).\n    - url: https://github.com/deltaskelta/docker-alertd\n      name: deltaskelta/docker-alertd\n      status: stale\n      stars: 108\n      forks: 12\n      last_push: 2017-11-15T04:40:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Monitor and send alerts based on docker container resource usage/statistics.\n    - url: https://github.com/docker-flow/docker-flow-monitor\n      name: docker-flow/docker-flow-monitor\n      status: stale\n      stars: 88\n      forks: 38\n      last_push: 2021-03-17T14:33:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Reconfigures Prometheus when a new service is updated or deployed automatically.\n    - url: https://github.com/stefanprodan/dockprom\n      name: stefanprodan/dockprom\n      status: healthy\n      stars: 6488\n      forks: 1768\n      last_push: 2026-03-06T05:28:07Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Docker hosts and containers monitoring with Prometheus, Grafana, cAdvisor, NodeExporter and AlertManager.\n    - url: https://github.com/amerkurev/doku\n      name: amerkurev/doku\n      status: healthy\n      stars: 410\n      forks: 18\n      last_push: 2025-12-26T09:13:21Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Doku is a simple web-based application that allows you to monitor Docker disk usage. [amerkurev](https://github.com/amerkurev).\n    - url: https://github.com/nicolargo/glances\n      name: nicolargo/glances\n      status: healthy\n      stars: 31995\n      forks: 1695\n      last_push: 2026-03-07T15:24:35Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: A cross-platform curses-based system monitoring tool written in Python.\n    - url: https://github.com/dromara/hertzbeat\n      name: dromara/hertzbeat\n      status: healthy\n      stars: 7114\n      forks: 1255\n      last_push: 2026-03-08T12:09:09Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: An open-source real-time monitoring system with custom-monitor and agentless.\n    - url: https://github.com/vegasbrianc/docker-monitoring\n      name: vegasbrianc/docker-monitoring\n      status: stale\n      stars: 473\n      forks: 129\n      last_push: 2018-06-10T20:53:49Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: InfluxDB Time series DB in combination with Grafana and cAdvisor.\n    - url: https://github.com/gliderlabs/logspout\n      name: gliderlabs/logspout\n      status: stale\n      stars: 4701\n      forks: 668\n      last_push: 2023-07-11T20:36:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Log routing for Docker container logs.\n    - url: https://github.com/decryptus/monit-docker\n      name: decryptus/monit-docker\n      status: stale\n      stars: 34\n      forks: 5\n      last_push: 2023-01-16T11:31:14Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Monitor docker containers resources usage or status and execute docker commands or inside containers. [decryptus][decryptus].\n    - url: https://github.com/NexClipper/NexClipper\n      name: NexClipper/NexClipper\n      status: stale\n      stars: 565\n      forks: 72\n      last_push: 2023-05-05T02:21:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: NexClipper is the container monitoring and performance management solution specialized in Docker, Apache Mesos, Marathon, DC/OS, Mesosphere, Kubernetes.\n    - url: https://github.com/uschtwill/docker_monitoring_logging_alerting\n      name: uschtwill/docker_monitoring_logging_alerting\n      status: stale\n      stars: 539\n      forks: 119\n      last_push: 2018-09-13T07:36:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Docker host and container monitoring, logging and alerting out of the box using cAdvisor, Prometheus, Grafana for monitoring, Elasticsearch, Kibana and Logstash for logging and elastalert and Alertmanager for alerting. Set up in 5 Minutes. Secure mode for production use with built-in [Automated Nginx Reverse Proxy (jwilder's)][nginxproxy].\n    - url: https://github.com/runsidekick/sidekick\n      name: runsidekick/sidekick\n      status: stale\n      stars: 1611\n      forks: 67\n      last_push: 2023-06-29T12:18:38Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Open source live application debugger like Chrome DevTools for your backend. Collect traces and generate logs on-demand without stopping & redeploying your applications.\n    - url: https://github.com/gpulido/SwarmAlert\n      name: gpulido/SwarmAlert\n      status: stale\n      stars: 22\n      forks: 2\n      last_push: 2019-11-27T12:17:14Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Monitors a Docker Swarm and sends Pushover alerts when it finds a container with no healthy service task running.\n    - url: https://github.com/gomex/docker-zabbix\n      name: gomex/docker-zabbix\n      status: stale\n      stars: 53\n      forks: 12\n      last_push: 2017-07-28T14:29:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Monitor containers automatically using zabbix LLD feature.\n    - url: https://github.com/monitoringartist/Zabbix-Docker-Monitoring\n      name: monitoringartist/Zabbix-Docker-Monitoring\n      status: stale\n      stars: 1197\n      forks: 265\n      last_push: 2022-02-22T17:01:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Monitoring\n      description: Zabbix module that provides discovery of running containers, CPU/memory/blk IO/net container metrics. Systemd Docker and LXC execution driver is also supported. It's a dynamically linked shared object library, so its performance is (~10x) better, than any script solution.\n    - url: https://github.com/coreos/flannel\n      name: coreos/flannel\n      status: healthy\n      stars: 9410\n      forks: 2902\n      last_push: 2026-03-06T12:10:23Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n    - url: https://github.com/Microsoft/Freeflow\n      name: Microsoft/Freeflow\n      status: stale\n      stars: 632\n      forks: 96\n      last_push: 2023-06-12T19:30:22Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Networking\n      description: High performance container overlay networks on Linux. Enabling RDMA (on both InfiniBand and RoCE) and accelerating TCP to bare metal performance. By [Microsoft](https://github.com/Microsoft).\n    - url: https://github.com/jason5ng32/MyIP\n      name: jason5ng32/MyIP\n      status: healthy\n      stars: 9895\n      forks: 1072\n      last_push: 2026-02-10T07:38:47Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Networking\n      description: All in one IP Toolbox. Easy to check all your IPs, IP geolocation, check for DNS leaks, examine WebRTC connections, speed test, ping test, MTR test, check website availability, whois search and more. By [jason5ng32](https://github.com/jason5ng32).\n    - url: https://github.com/nicolaka/netshoot\n      name: nicolaka/netshoot\n      status: healthy\n      stars: 10445\n      forks: 1085\n      last_push: 2026-03-05T17:23:33Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Networking\n      description: The netshoot container has a powerful set of networking tools to help troubleshoot Docker networking issues.\n    - url: https://github.com/jpetazzo/pipework\n      name: jpetazzo/pipework\n      status: inactive\n      stars: 4252\n      forks: 727\n      last_push: 2024-11-04T17:31:57Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Networking\n      description: Software-Defined Networking for Linux Containers, Pipework works with \"plain\" LXC containers, and with the awesome Docker. By [jpetazzo][jpetazzo].\n    - url: https://github.com/Peco602/ansible-linux-docker\n      name: Peco602/ansible-linux-docker\n      status: stale\n      stars: 37\n      forks: 4\n      last_push: 2023-06-21T09:34:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Run Ansible from a Linux container. By [Peco602][peco602].\n    - url: https://github.com/athena-oss/athena\n      name: athena-oss/athena\n      status: stale\n      stars: 96\n      forks: 25\n      last_push: 2017-07-06T08:26:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: An automation platform with a plugin architecture that allows you to easily create and share services.\n    - url: https://github.com/CloudSlang/cloud-slang\n      name: CloudSlang/cloud-slang\n      status: healthy\n      stars: 240\n      forks: 83\n      last_push: 2026-03-04T10:56:48Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: CloudSlang is a workflow engine to create Docker process automation.\n    - url: https://github.com/clusterdock/clusterdock\n      name: clusterdock/clusterdock\n      status: stale\n      stars: 29\n      forks: 8\n      last_push: 2023-05-16T18:05:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Docker container orchestration to enable the testing of long-running cluster deployments.\n    - url: https://github.com/Dataman-Cloud/crane\n      name: Dataman-Cloud/crane\n      status: stale\n      stars: 748\n      forks: 164\n      last_push: 2023-08-31T09:46:38Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Control plane based on docker built-in swarm [Dataman-Cloud](https://github.com/Dataman-Cloud).\n    - url: https://github.com/docker-flow/docker-flow-swarm-listener\n      name: docker-flow/docker-flow-swarm-listener\n      status: stale\n      stars: 69\n      forks: 50\n      last_push: 2019-05-20T19:40:37Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Docker Flow Swarm Listener project is to listen to Docker Swarm events and send requests when a change occurs. By [docker-flow][docker-flow].\n    - url: https://github.com/Wowu/docker-rollout\n      name: Wowu/docker-rollout\n      status: healthy\n      stars: 3111\n      forks: 93\n      last_push: 2025-07-25T17:57:48Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Zero downtime deployment for Docker Compose services.\n    - url: https://github.com/codeabovelab/haven-platform\n      name: codeabovelab/haven-platform\n      status: stale\n      stars: 297\n      forks: 41\n      last_push: 2018-07-06T11:21:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Haven is a simplified container management platform that integrates container, application, cluster, image, and registry managements. By [codeabovelab](https://github.com/codeabovelab).\n    - url: https://github.com/kubernetes/kubernetes\n      name: kubernetes/kubernetes\n      status: healthy\n      stars: 120996\n      forks: 42620\n      last_push: 2026-03-07T08:41:59Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Open source orchestration system for Docker containers by Google.\n    - url: https://github.com/ManageIQ/manageiq\n      name: ManageIQ/manageiq\n      status: healthy\n      stars: 1392\n      forks: 922\n      last_push: 2026-03-05T20:13:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Discover, optimize and control your hybrid IT. By [ManageIQ](https://github.com/ManageIQ).\n    - url: https://github.com/apache/mesos\n      name: apache/mesos\n      status: inactive\n      stars: 5364\n      forks: 1669\n      last_push: 2024-08-23T18:59:16Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Resource/Job scheduler for containers, VM's and physical hosts [apache](https://mesos.apache.org/).\n    - url: https://github.com/hashicorp/nomad\n      name: hashicorp/nomad\n      status: healthy\n      stars: 16262\n      forks: 2059\n      last_push: 2026-03-08T09:06:18Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Easily deploy applications at any scale. A Distributed, Highly Available, Datacenter-Aware Scheduler.\n    - url: https://github.com/rancher/rancher\n      name: rancher/rancher\n      status: healthy\n      stars: 25400\n      forks: 3173\n      last_push: 2026-03-06T22:49:23Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: An open source project that provides a complete platform for operating Docker in production.\n    - url: https://github.com/redherd-project/redherd-framework\n      name: redherd-project/redherd-framework\n      status: stale\n      stars: 74\n      forks: 17\n      last_push: 2023-04-25T18:54:33Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: RedHerd is a collaborative and serverless framework for orchestrating a geographically distributed group of assets capable of simulating complex offensive cyberspace operations. By [RedHerdProject](https://github.com/redherd-project).\n    - url: https://github.com/crazy-max/swarm-cronjob\n      name: crazy-max/swarm-cronjob\n      status: healthy\n      stars: 861\n      forks: 74\n      last_push: 2026-03-06T07:02:33Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Orchestration\n      description: Create jobs on a time-based schedule on Swarm by [crazy-max].\n    - url: https://github.com/caprover/caprover\n      name: caprover/caprover\n      status: healthy\n      stars: 14892\n      forks: 966\n      last_push: 2026-01-31T15:42:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: '[Previously known as CaptainDuckDuck] Automated Scalable Webserver Package (automated Docker+nginx) - Heroku on Steroids.'\n    - url: https://github.com/convox/rack\n      name: convox/rack\n      status: healthy\n      stars: 1892\n      forks: 177\n      last_push: 2026-02-12T19:55:53Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: Convox Rack is open source PaaS built on top of expert infrastructure automation and devops best practices.\n    - url: https://github.com/pbertera/dcw\n      name: pbertera/dcw\n      status: stale\n      stars: 17\n      forks: 3\n      last_push: 2017-03-29T07:55:37Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: 'Docker-compose SSH wrapper: a very poor man PaaS, exposing the docker-compose and custom-container commands defined in container labels.'\n    - url: https://github.com/dokku/dokku\n      name: dokku/dokku\n      status: healthy\n      stars: 31896\n      forks: 2022\n      last_push: 2026-03-07T18:31:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: Docker powered mini-Heroku that helps you build and manage the lifecycle of applications (originally by [progrium][progrium]).\n    - url: https://github.com/remind101/empire\n      name: remind101/empire\n      status: stale\n      stars: 2681\n      forks: 156\n      last_push: 2023-11-25T17:16:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: A PaaS built on top of Amazon EC2 Container Service (ECS).\n    - url: https://github.com/exoframejs/exoframe\n      name: exoframejs/exoframe\n      status: healthy\n      stars: 1146\n      forks: 59\n      last_push: 2026-02-22T16:24:52Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: A self-hosted tool that allows simple one-command deployments using Docker.\n    - url: https://github.com/teamhephy/workflow\n      name: teamhephy/workflow\n      status: stale\n      stars: 419\n      forks: 36\n      last_push: 2023-09-27T17:30:49Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: Open source PaaS for Kubernetes that adds a developer-friendly layer to any Kubernetes cluster, making it easy to deploy and manage applications. Fork of [Deis Workflow](https://github.com/deis/workflow).\n    - url: https://github.com/krane/krane\n      name: krane/krane\n      status: stale\n      stars: 80\n      forks: 8\n      last_push: 2023-05-11T20:39:00Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: Toolset for managing container workloads on remote servers.\n    - url: https://github.com/nanobox-io/nanobox\n      name: nanobox-io/nanobox\n      status: stale\n      stars: 1625\n      forks: 90\n      last_push: 2019-10-21T20:03:10Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: An application development platform that creates local environments that can then be deployed and scaled in the cloud.\n    - url: https://github.com/tsuru/tsuru\n      name: tsuru/tsuru\n      status: healthy\n      stars: 5259\n      forks: 550\n      last_push: 2026-03-05T03:11:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > PaaS\n      description: Tsuru is an extensible and open source Platform as a Service software.\n    - url: https://github.com/bunkerity/bunkerweb\n      name: bunkerity/bunkerweb\n      status: healthy\n      stars: 10112\n      forks: 568\n      last_push: 2026-03-06T17:15:47Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Open-source and next-gen Web Application Firewall (WAF). By [Bunkerity](https://www.bunkerity.com).\n    - url: https://github.com/lucaslorentz/caddy-docker-proxy\n      name: lucaslorentz/caddy-docker-proxy\n      status: healthy\n      stars: 4315\n      forks: 211\n      last_push: 2026-03-08T07:04:18Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Caddy-based reverse proxy, configured with service or container labels. By [lucaslorentz](https://github.com/lucaslorentz).\n    - url: https://github.com/invzhi/caddy-docker-upstreams\n      name: invzhi/caddy-docker-upstreams\n      status: healthy\n      stars: 36\n      forks: 8\n      last_push: 2025-09-08T05:17:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Docker upstreams module for Caddy, configured with container labels. By [invzhi](https://github.com/invzhi).\n    - url: https://github.com/moonbuggy/docker-dnsmasq-updater\n      name: moonbuggy/docker-dnsmasq-updater\n      status: inactive\n      stars: 35\n      forks: 2\n      last_push: 2025-02-09T00:21:52Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Update a remote dnsmasq server with Docker container hostnames.\n    - url: https://github.com/docker-flow/docker-flow-proxy\n      name: docker-flow/docker-flow-proxy\n      status: healthy\n      stars: 320\n      forks: 189\n      last_push: 2025-12-05T02:29:16Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Reconfigures proxy every time a new service is deployed, or when a service is scaled. By [docker-flow][docker-flow].\n    - url: https://github.com/fabiolb/fabio\n      name: fabiolb/fabio\n      status: healthy\n      stars: 7333\n      forks: 624\n      last_push: 2026-02-23T02:48:11Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: A fast, modern, zero-conf load balancing HTTP(S) router for deploying microservices managed by consul. By [magiconair](https://github.com/magiconair) (Frank Schroeder).\n    - url: https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion\n      name: nginx-proxy/docker-letsencrypt-nginx-proxy-companion\n      status: healthy\n      stars: 7698\n      forks: 834\n      last_push: 2026-03-02T17:04:31Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: A lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. By [JrCs](https://github.com/JrCs).\n    - url: https://github.com/Yundera/mesh-router\n      name: Yundera/mesh-router\n      status: healthy\n      stars: 8\n      last_push: 2026-03-02T15:37:53Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Free domain(nsl.sh) provider for Docker containers with automatic HTTPS routing. Uses Wireguard VPN to securely route subdomain requests across networks. Ideal for self-hosted NAS and cloud deployments. By [Yundera](https://github.com/Yundera).\n    - url: https://github.com/jc21/nginx-proxy-manager\n      name: jc21/nginx-proxy-manager\n      status: healthy\n      stars: 32001\n      forks: 3639\n      last_push: 2026-03-06T14:15:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: A beautiful web interface for proxying web based services with SSL. By [jc21](https://github.com/jc21).\n    - url: https://github.com/Safe3/openresty-manager\n      name: Safe3/openresty-manager\n      status: healthy\n      stars: 1322\n      forks: 98\n      last_push: 2026-01-25T10:38:42Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: The easiest using, powerful and beautiful OpenResty Manager(Nginx Enhanced Version), open source alternative to OpenResty Edge. By [Safe3](https://github.com/Safe3/).\n    - url: https://github.com/flavioaiello/swarm-router\n      name: flavioaiello/swarm-router\n      status: healthy\n      stars: 73\n      forks: 12\n      last_push: 2025-09-15T06:12:30Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: A «zero config» service name based router for docker swarm mode with a fresh and more secure approach. By [flavioaiello](https://github.com/flavioaiello).\n    - url: https://github.com/containous/traefik\n      name: containous/traefik\n      status: healthy\n      stars: 62086\n      forks: 5865\n      last_push: 2026-03-06T16:16:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Reverse Proxy\n      description: Automated reverse proxy and load-balancer for Docker, Mesos, Consul, Etcd... By [EmileVauge](https://github.com/emilevauge).\n    - url: https://github.com/cri-o/cri-o\n      name: cri-o/cri-o\n      status: healthy\n      stars: 5588\n      forks: 1151\n      last_push: 2026-03-08T00:16:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Runtime\n      description: Open Container Initiative-based implementation of Kubernetes Container Runtime Interface by [cri-o](https://github.com/cri-o).\n    - url: https://github.com/lxc/lxc\n      name: lxc/lxc\n      status: healthy\n      stars: 5126\n      forks: 1162\n      last_push: 2026-03-02T14:26:30Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Runtime\n      description: LXC - Linux Containers.\n    - url: https://github.com/containers/libpod\n      name: containers/libpod\n      status: healthy\n      stars: 30937\n      forks: 3006\n      last_push: 2026-03-06T15:57:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Runtime\n      description: Libpod is a library used to create container pods. Home of Podman.\n    - url: https://github.com/brauner/rlxc\n      name: brauner/rlxc\n      status: stale\n      stars: 18\n      forks: 3\n      last_push: 2021-06-30T13:12:28Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Runtime\n      description: LXC binary written in Rust.\n    - url: https://github.com/opencontainers/runtime-tools\n      name: opencontainers/runtime-tools\n      status: healthy\n      stars: 473\n      forks: 159\n      last_push: 2025-12-05T00:49:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Runtime\n      description: Oci-runtime-tool is a collection of tools for working with the OCI runtime specification.\n    - url: https://github.com/SongStitch/anchor\n      name: SongStitch/anchor\n      status: inactive\n      stars: 24\n      last_push: 2025-01-15T23:09:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n    - url: https://github.com/genuinetools/bane\n      name: genuinetools/bane\n      status: stale\n      stars: 1224\n      forks: 91\n      last_push: 2020-09-17T20:10:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: AppArmor profile generator for Docker containers.\n    - url: https://github.com/dash14/buildcage\n      name: dash14/buildcage\n      status: healthy\n      stars: 4\n      last_push: 2026-03-08T16:59:17Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Restricts outbound network access during Docker builds to prevent supply chain attacks, working as a drop-in BuildKit remote driver for Docker Buildx, with ready-to-use GitHub Actions.\n    - url: https://github.com/hectorm/cetusguard\n      name: hectorm/cetusguard\n      status: healthy\n      stars: 82\n      forks: 2\n      last_push: 2026-03-01T11:42:56Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: CetusGuard is a tool that protects the Docker daemon socket by filtering calls to its API endpoints.\n    - url: https://github.com/bridgecrewio/checkov\n      name: bridgecrewio/checkov\n      status: healthy\n      stars: 8510\n      forks: 1307\n      last_push: 2026-03-08T07:40:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Static analysis for infrastructure as code manifests (Terraform, Kubernetes, Cloudformation, Helm, Dockerfile, Kustomize) find security misconfiguration and fix them. By [bridgecrew](https://github.com/bridgecrewio).\n    - url: https://github.com/dev-sec/cis-docker-benchmark\n      name: dev-sec/cis-docker-benchmark\n      status: stale\n      stars: 524\n      forks: 118\n      last_push: 2023-05-02T12:59:10Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: This [InSpec][inspec] compliance profile implement the CIS Docker 1.12.0 Benchmark in an automated way to provide security best-practice tests around Docker daemon and containers in a production environment. By [dev-sec](https://github.com/dev-sec).\n    - url: https://github.com/quay/clair\n      name: quay/clair\n      status: healthy\n      stars: 10940\n      forks: 1195\n      last_push: 2026-03-06T23:17:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Clair is an open source project for the static analysis of vulnerabilities in appc and docker containers. By [coreos][coreos].\n    - url: https://github.com/wolffcatskyy/crowdsec-blocklist-import\n      name: wolffcatskyy/crowdsec-blocklist-import\n      status: healthy\n      stars: 179\n      forks: 4\n      last_push: 2026-03-07T18:44:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Aggregates 36 free threat intelligence feeds into 120k+ malicious IPs for CrowdSec bouncers, providing 10-20x more blocks than default lists. By [wolffcatskyy](https://github.com/wolffcatskyy).\n    - url: https://github.com/eliasgranderubio/dagda\n      name: eliasgranderubio/dagda\n      status: stale\n      stars: 1220\n      forks: 169\n      last_push: 2023-05-23T02:03:43Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Dagda is a tool to perform static analysis of known vulnerabilities, trojans, viruses, malware & other malicious threats in docker images/containers and to monitor the docker daemon and running docker containers for detecting anomalous activities. By [eliasgranderubio](https://github.com/eliasgranderubio).\n    - url: https://github.com/deepfence/ThreatMapper\n      name: deepfence/ThreatMapper\n      status: healthy\n      stars: 5235\n      forks: 640\n      last_push: 2026-03-08T03:35:58Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Powerful runtime vulnerability scanner for kubernetes, virtual machines and serverless. By [deepfence][deepfence].\n    - url: https://github.com/docker/docker-bench-security\n      name: docker/docker-bench-security\n      status: inactive\n      stars: 9600\n      forks: 1038\n      last_push: 2024-10-21T07:26:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Script that checks for dozens of common best-practices around deploying Docker containers in production. By [docker][docker].\n    - url: https://github.com/google/docker-explorer\n      name: google/docker-explorer\n      status: inactive\n      stars: 553\n      forks: 45\n      last_push: 2024-10-04T07:44:31Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: A tool to help forensicate offline docker acquisitions.\n    - url: https://github.com/Peco602/dvwassl\n      name: Peco602/dvwassl\n      status: stale\n      stars: 6\n      forks: 4\n      last_push: 2023-04-30T17:03:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: SSL-enabled Damn Vulnerable Web App to test Web Application Firewalls. By [Peco602][peco602].\n    - url: https://github.com/checkmarx/kics\n      name: checkmarx/kics\n      status: healthy\n      stars: 2581\n      forks: 361\n      last_push: 2026-03-06T15:34:55Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: An infrastructure-as-code scanning tool, find security vulnerabilities, compliance issues, and infrastructure misconfigurations early in the development cycle. Can be extended for additional policies. By [Checkmarx](https://github.com/Checkmarx).\n    - url: https://github.com/theupdateframework/notary\n      name: theupdateframework/notary\n      status: archived\n      stars: 3287\n      forks: 520\n      last_push: 2024-08-07T19:02:32Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: A server and a client for running and interacting with trusted collections. By [TUF](https://github.com/theupdateframework).\n    - url: https://github.com/OpenSCAP/openscap\n      name: OpenSCAP/openscap\n      status: healthy\n      stars: 1676\n      forks: 424\n      last_push: 2026-02-27T12:44:50Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: OpenSCAP provides oscap-docker tool which is used to scan Docker containers and images. By [OpenSCAP](https://github.com/OpenSCAP).\n    - url: https://github.com/dormstern/segspec\n      name: dormstern/segspec\n      status: healthy\n      stars: 15\n      last_push: 2026-02-23T11:39:00Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Extracts network dependencies from Docker Compose, Kubernetes manifests, Helm charts, and other config files to generate Kubernetes NetworkPolicies with evidence tracing. By [dormstern](https://github.com/dormstern).\n    - url: https://github.com/anchore/syft\n      name: anchore/syft\n      status: healthy\n      stars: 8454\n      forks: 779\n      last_push: 2026-03-08T08:12:44Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: CLI tool and library for generating a Software Bill of Materials (SBOM) from container images and filesystems.\n    - url: https://github.com/falcosecurity/falco\n      name: falcosecurity/falco\n      status: healthy\n      stars: 8712\n      forks: 990\n      last_push: 2026-03-02T17:54:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Sysdig Falco is an open source container security monitor. It can monitor application, container, host, and network activity and alert on unauthorized activity.\n    - url: https://github.com/aquasecurity/trivy\n      name: aquasecurity/trivy\n      status: healthy\n      stars: 33020\n      forks: 76\n      last_push: 2026-03-06T06:42:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Security\n      description: Aqua Security's open source simple and comprehensive vulnerability scanner for containers (suitable for CI).\n    - url: https://github.com/bytesharky/docker-dns\n      name: bytesharky/docker-dns\n      status: healthy\n      stars: 3\n      forks: 1\n      last_push: 2025-12-26T02:44:43Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Service Discovery\n      description: Lightweight DNS forwarder for Docker containers, resolves container names with custom suffixes (e.g. `.docker`) on the host to simplify service discovery.\n    - url: https://github.com/etcd-io/etcd\n      name: etcd-io/etcd\n      status: healthy\n      stars: 51631\n      forks: 10336\n      last_push: 2026-03-06T20:11:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Service Discovery\n      description: Distributed reliable key-value store for the most critical data of a distributed system by [etcd-io](https://github.com/etcd-io) (former part of CoreOS).\n    - url: https://github.com/istio/istio\n      name: istio/istio\n      status: healthy\n      stars: 38089\n      forks: 8260\n      last_push: 2026-03-08T16:55:04Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Service Discovery\n      description: An open platform to connect, manage, and secure microservices.\n    - url: https://github.com/gliderlabs/registrator\n      name: gliderlabs/registrator\n      status: healthy\n      stars: 4675\n      forks: 909\n      last_push: 2025-05-22T04:16:52Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Service Discovery\n      description: Service registry bridge for Docker by [gliderlabs][gliderlabs] and [progrium][progrium].\n    - url: https://github.com/minio/minio\n      name: minio/minio\n      status: archived\n      stars: 60448\n      forks: 7197\n      last_push: 2026-02-12T20:18:51Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Volume Management / Data\n      description: S3 compatible object storage server in Docker containers.\n    - url: https://github.com/Storidge/quick-start\n      name: Storidge/quick-start\n      status: stale\n      stars: 1\n      forks: 1\n      last_push: 2019-09-09T21:42:15Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > Volume Management / Data\n      description: Software-defined Persistent Storage for Kubernetes and Docker Swarm.\n    - url: https://github.com/AbianS/docker-db-manager\n      name: AbianS/docker-db-manager\n      status: healthy\n      stars: 155\n      forks: 5\n      last_push: 2025-11-26T09:24:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Desktop\n      description: Desktop app for managing Docker database containers with visual interface and one-click operations.\n    - url: https://github.com/felixgborrego/simple-docker-ui\n      name: felixgborrego/simple-docker-ui\n      status: inactive\n      stars: 606\n      forks: 96\n      last_push: 2024-09-06T09:31:07Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Desktop\n      description: Built on Electron. By [felixgborrego](https://github.com/felixgborrego/).\n    - url: https://github.com/slonopotamus/stevedore\n      name: slonopotamus/stevedore\n      status: healthy\n      stars: 369\n      forks: 13\n      last_push: 2026-02-27T11:51:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Desktop\n      description: Good Docker Desktop replacement for Windows. Both Linux and Windows Containers are supported. [slonopotamus](https://github.com/slonopotamus).\n    - url: https://github.com/jr-k/d4s\n      name: jr-k/d4s\n      status: healthy\n      stars: 55\n      forks: 4\n      last_push: 2026-03-04T21:15:58Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: A fast, keyboard-driven terminal UI to manage Docker containers, Compose stacks, and Swarm services with the ergonomics of K9s.\n    - url: https://github.com/wagoodman/dive\n      name: wagoodman/dive\n      status: healthy\n      stars: 53505\n      forks: 1953\n      last_push: 2025-12-15T17:20:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: A tool for exploring each layer in a docker image. By [wagoodman](https://github.com/wagoodman).\n    - url: https://github.com/lirantal/dockly\n      name: lirantal/dockly\n      status: healthy\n      stars: 4014\n      forks: 164\n      last_push: 2026-02-01T19:31:17Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: An interactive shell UI for managing Docker containers.\n    - url: https://github.com/shubh-io/dockmate\n      name: shubh-io/dockmate\n      status: healthy\n      stars: 278\n      forks: 5\n      last_push: 2026-01-14T06:52:19Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: Lightweight terminal-based Docker and Podman manager with a text-based user interface,.\n    - url: https://github.com/GhostWriters/DockSTARTer\n      name: GhostWriters/DockSTARTer\n      status: healthy\n      stars: 2545\n      forks: 291\n      last_push: 2026-03-01T14:12:50Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: DockSTARTer helps you get started with home server apps running in Docker by [GhostWriters](https://github.com/GhostWriters).\n    - url: https://github.com/durableprogramming/dprs\n      name: durableprogramming/dprs\n      status: healthy\n      stars: 36\n      forks: 1\n      last_push: 2026-03-05T15:59:19Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: A developer-focused TUI for managing Docker containers with real-time log streaming and container management. Built with Rust. By [durableprogramming](https://github.com/durableprogramming).\n    - url: https://github.com/moncho/dry\n      name: moncho/dry\n      status: healthy\n      stars: 3227\n      forks: 103\n      last_push: 2026-03-08T10:25:15Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: An interactive CLI for Docker containers.\n    - url: https://github.com/ajayd-san/gomanagedocker\n      name: ajayd-san/gomanagedocker\n      status: inactive\n      stars: 632\n      forks: 26\n      last_push: 2024-12-28T07:44:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: TUI tool to view and manage your docker objects blazingly fast with sensible keybindings, also supports VIM navigation out of the box.\n    - url: https://github.com/jesseduffield/lazydocker\n      name: jesseduffield/lazydocker\n      status: healthy\n      stars: 50030\n      forks: 1578\n      last_push: 2026-01-17T06:16:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: The lazier way to manage everything docker. A simple terminal UI for both docker and docker-compose, written in Go with the gocui library. By [jesseduffield](https://github.com/jesseduffield).\n    - url: https://github.com/Lifailon/lazyjournal\n      name: Lifailon/lazyjournal\n      status: healthy\n      stars: 1175\n      forks: 28\n      last_push: 2026-03-06T14:14:51Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: A interface for reading and filtering the logs output of Docker and Podman containers like [Dozzle](dozzle) but for the terminal with support for fuzzy find, regex and output coloring.\n    - url: https://github.com/mrjackwills/oxker\n      name: mrjackwills/oxker\n      status: healthy\n      stars: 1552\n      forks: 43\n      last_push: 2026-02-23T15:18:34Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Terminal UI\n      description: A simple tui to view & control docker containers. Written in [Rust](https://rust-lang.org/), making heavy use of [ratatui](https://github.com/tui-rs-revival/ratatui) & [Bollard](https://github.com/fussybeaver/bollard),.\n    - url: https://github.com/jenssegers/captain\n      name: jenssegers/captain\n      status: stale\n      stars: 244\n      forks: 10\n      last_push: 2022-12-08T07:39:21Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Easily start and stop docker compose projects from any directory. By [jenssegers](https://github.com/jenssegers).\n    - url: https://github.com/Falldog/dcinja\n      name: Falldog/dcinja\n      status: healthy\n      stars: 13\n      forks: 3\n      last_push: 2025-06-26T12:33:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: The powerful and smallest binary size of template engine for docker command line environment. By [Falldog](https://github.com/Falldog).\n    - url: https://github.com/exdx/dcp\n      name: exdx/dcp\n      status: stale\n      stars: 114\n      forks: 3\n      last_push: 2023-07-24T01:09:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: A simple tool for copying files from container filesystems. By [exdx](https://github.com/exdx).\n    - url: https://github.com/FabienD/docker-stack\n      name: FabienD/docker-stack\n      status: healthy\n      stars: 22\n      forks: 2\n      last_push: 2026-03-01T10:58:51Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Dctl is a Cli tool that helps developers by allowing them to execute all docker compose commands anywhere in the terminal, and more. By [FabienD](https://github.com/FabienD).\n    - url: https://github.com/s0rg/decompose\n      name: s0rg/decompose\n      status: healthy\n      stars: 126\n      forks: 6\n      last_push: 2025-12-19T20:03:44Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Reverse-engineering tool for docker environments. By [s0rg](https://github.com/s0rg).\n    - url: https://github.com/christian-korneck/docker-pushrm\n      name: christian-korneck/docker-pushrm\n      status: inactive\n      stars: 148\n      forks: 3\n      last_push: 2024-06-10T21:42:09Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: A Docker CLI plugin that lets you push the README.md file from the current directory to Docker Hub. Also supports Quay and Harbor. By [christian-korneck](https://github.com/christian-korneck).\n    - url: https://github.com/lucabello/docker-captain\n      name: lucabello/docker-captain\n      status: healthy\n      stars: 2\n      last_push: 2026-03-07T00:13:26Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: A friendly CLI to manage multiple Docker Compose deployments with style — powered by Typer, Rich, questionary, and sh.\n    - url: https://github.com/mayflower/docker-ls\n      name: mayflower/docker-ls\n      status: archived\n      stars: 456\n      forks: 68\n      last_push: 2023-08-31T06:44:18Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: CLI tools for browsing and manipulating docker registries.\n    - url: https://github.com/howtowhale/dvm\n      name: howtowhale/dvm\n      status: stale\n      stars: 525\n      forks: 50\n      last_push: 2022-03-30T13:23:11Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Docker version manager.\n    - url: https://github.com/iamsoorena/goinside\n      name: iamsoorena/goinside\n      status: stale\n      stars: 30\n      forks: 2\n      last_push: 2020-10-17T20:31:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Get inside a running docker container easily.\n    - url: https://github.com/g31s/Pdocker\n      name: g31s/Pdocker\n      status: stale\n      stars: 7\n      forks: 2\n      last_push: 2021-02-27T06:42:13Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: A simple tool to manage and maintain Docker for personal projects.\n    - url: https://github.com/shiwaforce/poco\n      name: shiwaforce/poco\n      status: healthy\n      stars: 111\n      forks: 6\n      last_push: 2026-02-28T12:31:09Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Proco will help you to organise and manage Docker, Docker-Compose, Kubernetes projects of any complexity using simple YAML config files to shorten the route from finding your project to initialising it in your local environment.\n    - url: https://github.com/JonathonReinhart/scuba\n      name: JonathonReinhart/scuba\n      status: healthy\n      stars: 96\n      forks: 17\n      last_push: 2026-01-26T04:03:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Transparently use Docker containers to encapsulate software build environments,.\n    - url: https://github.com/containers/skopeo\n      name: containers/skopeo\n      status: healthy\n      stars: 10538\n      forks: 908\n      last_push: 2026-03-08T00:58:49Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Work with remote images registries - retrieving information, images, signing content.\n    - url: https://github.com/segersniels/supdock\n      name: segersniels/supdock\n      status: healthy\n      stars: 86\n      forks: 3\n      last_push: 2026-02-23T13:29:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Allows for slightly more visual usage of Docker with an interactive prompt. By [segersniels](https://github.com/segersniels).\n    - url: https://github.com/qazbnm456/tsaotun\n      name: qazbnm456/tsaotun\n      status: stale\n      stars: 59\n      forks: 3\n      last_push: 2022-10-04T06:53:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > CLI tools\n      description: Python based Assistance for Docker.\n    - url: https://github.com/vutran/dext-docker-registry-plugin\n      name: vutran/dext-docker-registry-plugin\n      status: stale\n      stars: 4\n      forks: 1\n      last_push: 2017-01-10T03:04:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Other\n      description: Search the Docker Registry with the Dext smart launcher. By [vutran](https://github.com/vutran).\n    - url: https://github.com/jeroenpeeters/docker-ssh\n      name: jeroenpeeters/docker-ssh\n      status: stale\n      stars: 659\n      forks: 89\n      last_push: 2018-04-11T20:24:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Other\n      description: SSH Server for Docker containers ~ Because every container should be accessible. By [jeroenpeeters](https://github.com/jeroenpeeters).\n    - url: https://github.com/marty90/multidocker\n      name: marty90/multidocker\n      status: stale\n      stars: 56\n      forks: 9\n      last_push: 2018-11-27T15:12:56Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Other\n      description: Create a secure multi-user Docker machine, where each user is segregated into an indepentent container.\n    - url: https://github.com/adrianmo/powerline-docker\n      name: adrianmo/powerline-docker\n      status: stale\n      stars: 61\n      forks: 6\n      last_push: 2017-06-30T09:11:44Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Terminal > Other\n      description: A Powerline segment for showing the status of Docker containers.\n    - url: https://github.com/knrdl/casa\n      name: knrdl/casa\n      status: healthy\n      stars: 84\n      forks: 5\n      last_push: 2026-03-02T14:26:48Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Outsource the administration of a handful of containers to your co-workers,.\n    - url: https://github.com/wrfly/container-web-tty\n      name: wrfly/container-web-tty\n      status: healthy\n      stars: 258\n      forks: 46\n      last_push: 2026-03-02T16:34:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Connect your containers via a web-tty [wrfly](https://github.com/wrfly).\n    - url: https://github.com/ProductiveOps/dokemon\n      name: ProductiveOps/dokemon\n      status: stale\n      stars: 759\n      forks: 36\n      last_push: 2024-02-21T10:51:14Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Docker Container Management GUI.\n    - url: https://github.com/klausmeyer/docker-registry-browser\n      name: klausmeyer/docker-registry-browser\n      status: healthy\n      stars: 675\n      forks: 61\n      last_push: 2026-02-21T09:06:10Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Web Interface for the Docker Registry HTTP API v2.\n    - url: https://github.com/mkuchin/docker-registry-web\n      name: mkuchin/docker-registry-web\n      status: stale\n      stars: 548\n      forks: 133\n      last_push: 2022-02-08T08:42:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Web UI, authentication service and event recorder for private docker registry v2.\n    - url: https://github.com/dockersamples/docker-swarm-visualizer\n      name: dockersamples/docker-swarm-visualizer\n      status: inactive\n      stars: 3348\n      forks: 596\n      last_push: 2024-10-26T07:12:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Visualizes Docker services on a Docker Swarm (for running demos).\n    - url: https://github.com/louislam/dockge\n      name: louislam/dockge\n      status: healthy\n      stars: 22365\n      forks: 707\n      last_push: 2026-01-21T10:51:44Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.\n    - url: https://github.com/mbecker20/komodo\n      name: mbecker20/komodo\n      status: healthy\n      stars: 10494\n      forks: 277\n      last_push: 2026-03-08T14:48:23Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: A tool to build and deploy software on many servers.\n    - url: https://github.com/kubevious/kubevious\n      name: kubevious/kubevious\n      status: stale\n      stars: 1692\n      forks: 95\n      last_push: 2024-01-15T18:42:38Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: A highly visual web UI for Kubernetes which renders configuration and state in an application centric way.\n    - url: https://github.com/hywax/mafl\n      name: hywax/mafl\n      status: healthy\n      stars: 675\n      forks: 52\n      last_push: 2025-10-26T02:26:26Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Minimalistic flexible homepage.\n    - url: https://github.com/netdata/netdata\n      name: netdata/netdata\n      status: healthy\n      stars: 77993\n      forks: 6360\n      last_push: 2026-03-08T10:17:43Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Real-time performance monitoring.\n    - url: https://github.com/OctoLinker/OctoLinker\n      name: OctoLinker/OctoLinker\n      status: stale\n      stars: 5352\n      forks: 283\n      last_push: 2023-10-02T12:33:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: A browser extension for GitHub that makes the image name in a `Dockerfile` clickable and redirect you to the related Docker Hub page.\n    - url: https://github.com/portainer/portainer\n      name: portainer/portainer\n      status: healthy\n      stars: 36781\n      forks: 2787\n      last_push: 2026-03-07T13:14:38Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: A lightweight management UI for managing your Docker hosts or Docker Swarm clusters.\n    - url: https://github.com/ozlerhakan/rapid\n      name: ozlerhakan/rapid\n      status: stale\n      stars: 147\n      forks: 24\n      last_push: 2021-09-21T08:44:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: A simple query dashboard to use Docker Remote API.\n    - url: https://github.com/tobegit3hub/seagull\n      name: tobegit3hub/seagull\n      status: stale\n      stars: 1939\n      forks: 268\n      last_push: 2017-11-22T02:11:23Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Friendly Web UI to monitor docker daemon.\n    - url: https://github.com/swarmpit/swarmpit\n      name: swarmpit/swarmpit\n      status: healthy\n      stars: 3410\n      forks: 312\n      last_push: 2026-03-04T00:04:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Swarmpit provides simple and easy to use interface for your Docker Swarm cluster. You can manage your stacks, services, secrets, volumes, networks etc.\n    - url: https://github.com/cuigh/swirl\n      name: cuigh/swirl\n      status: stale\n      stars: 668\n      forks: 83\n      last_push: 2023-05-16T02:47:48Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Swirl is a web management tool for Docker, focused on swarm cluster By [cuigh](https://github.com/cuigh/).\n    - url: https://github.com/eclipse-theia/theia\n      name: eclipse-theia/theia\n      status: healthy\n      stars: 21393\n      forks: 2801\n      last_push: 2026-03-07T09:12:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: Extensible platform to develop full-fledged multi-language Cloud & Desktop IDE-like products with state-of-the-art web technologies.\n    - url: https://github.com/fr4nsys/usulnet\n      name: fr4nsys/usulnet\n      status: healthy\n      stars: 77\n      forks: 3\n      last_push: 2026-02-23T23:00:19Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Container Operations > User Interface > Web\n      description: A complete and modern Docker management platform designed for sysadmin, devops with enterprise grade tools, cve scanner, ssh, rdp on web and much more. By [fr4nsys](https://github.com/fr4nsys).\n    - url: https://github.com/genuinetools/amicontained\n      name: genuinetools/amicontained\n      status: stale\n      stars: 1073\n      forks: 71\n      last_push: 2020-12-09T04:37:59Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Container introspection tool. Find out what container runtime is being used as well as features available.\n    - url: https://github.com/garywiz/chaperone\n      name: garywiz/chaperone\n      status: stale\n      stars: 179\n      forks: 31\n      last_push: 2020-07-16T21:30:27Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: A single PID1 process designed for docker containers. Does user management, log management, startup, zombie reaping, all in one small package.\n    - url: https://github.com/nicomt/ckron\n      name: nicomt/ckron\n      status: healthy\n      stars: 56\n      forks: 6\n      last_push: 2026-02-15T17:58:14Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: A cron-style job scheduler for docker,.\n    - url: https://github.com/GoogleContainerTools/distroless\n      name: GoogleContainerTools/distroless\n      status: healthy\n      stars: 22329\n      forks: 1360\n      last_push: 2026-03-06T14:09:42Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Language focused docker images, minus the operating system,.\n    - url: https://github.com/gliderlabs/docker-alpine\n      name: gliderlabs/docker-alpine\n      status: stale\n      stars: 5720\n      forks: 530\n      last_push: 2021-04-01T08:02:51Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: A super small Docker base image _(5MB)_ using Alpine Linux.\n    - url: https://github.com/jwilder/docker-gen\n      name: jwilder/docker-gen\n      status: healthy\n      stars: 4620\n      forks: 615\n      last_push: 2026-03-07T14:15:15Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Generate files from docker container meta-data.\n    - url: https://github.com/powerman/dockerize\n      name: powerman/dockerize\n      status: healthy\n      stars: 195\n      forks: 17\n      last_push: 2026-03-05T18:12:32Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Utility to simplify running applications in docker containers by [jwilder][jwilder], [powerman][powerman].\n    - url: https://github.com/tianon/gosu\n      name: tianon/gosu\n      status: healthy\n      stars: 4952\n      forks: 356\n      last_push: 2026-03-04T18:27:37Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Run this specific application as this specific user and get out of the pipeline (entrypoint script tool).\n    - url: https://github.com/sindresorhus/is-docker\n      name: sindresorhus/is-docker\n      status: healthy\n      stars: 233\n      forks: 16\n      last_push: 2025-09-15T21:04:10Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Check if the process is running inside a Docker container.\n    - url: https://github.com/ivanilves/lstags\n      name: ivanilves/lstags\n      status: stale\n      stars: 340\n      forks: 26\n      last_push: 2023-05-11T20:38:37Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Sync Docker images across registries.\n    - url: https://github.com/tarampampam/microcheck\n      name: tarampampam/microcheck\n      status: healthy\n      stars: 130\n      forks: 2\n      last_push: 2026-02-24T19:11:41Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Lightweight health check utilities for Docker containers (75 KB instead of 9.3 MB for httpcheck versus cURL) in pure C - http(s), port checks, and parallel execution are included.\n    - url: https://github.com/mcuadros/ofelia\n      name: mcuadros/ofelia\n      status: healthy\n      stars: 3742\n      forks: 204\n      last_push: 2026-03-08T01:55:37Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n    - url: https://github.com/beyondssl/sparkview-container\n      name: beyondssl/sparkview-container\n      status: healthy\n      stars: 20\n      forks: 2\n      last_push: 2025-09-22T06:59:43Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Access VMs, desktops, servers or applications anytime and from anywhere, without complex and costly client roll-outs or user management.\n    - url: https://github.com/ncopa/su-exec\n      name: ncopa/su-exec\n      status: healthy\n      stars: 1019\n      forks: 103\n      last_push: 2025-10-07T13:49:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: This is a simple tool that will simply execute a program with different privileges. The program will be executed directly and not run as a child, like su and sudo does, which avoids TTY and signal issues. Why reinvent gosu? This does more or less exactly the same thing as gosu but it is only 10kb instead of 1.8MB. By [ncopa](https://github.com/ncopa).\n    - url: https://github.com/theAkito/sue\n      name: theAkito/sue\n      status: stale\n      stars: 13\n      forks: 1\n      last_push: 2022-04-26T21:10:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Executes a program as a user different from the user running sue. This is a maintainable alternative to ncopa/su-exec, which is the better tianon/gosu. This one is far better (higher performance, smaller size), than the original gosu, however it is far easier to maintain, than su-exec, which is written in plain C. Made by [Akito][akito].\n    - url: https://github.com/aptible/supercronic\n      name: aptible/supercronic\n      status: healthy\n      stars: 2391\n      forks: 141\n      last_push: 2026-03-06T13:28:13Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: Crontab-compatible job runner, designed specifically to run in containers.\n    - url: https://github.com/vorakl/TrivialRC\n      name: vorakl/TrivialRC\n      status: stale\n      stars: 32\n      forks: 5\n      last_push: 2023-12-20T00:39:55Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Base Tools\n      description: A minimalistic Runtime Configuration system and process manager for containers [vorakl](https://github.com/vorakl).\n    - url: https://github.com/ansible-community/ansible-bender\n      name: ansible-community/ansible-bender\n      status: healthy\n      stars: 694\n      forks: 74\n      last_push: 2026-01-07T23:21:32Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A tool utilising `ansible` and `buildah`.\n    - url: https://github.com/containers/buildah\n      name: containers/buildah\n      status: healthy\n      stars: 8662\n      forks: 882\n      last_push: 2026-03-08T17:53:57Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A tool that facilitates building OCI images.\n    - url: https://github.com/moby/buildkit\n      name: moby/buildkit\n      status: healthy\n      stars: 9817\n      forks: 1379\n      last_push: 2026-03-06T22:37:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit.\n    - url: https://github.com/cekit/cekit\n      name: cekit/cekit\n      status: healthy\n      stars: 113\n      forks: 44\n      last_push: 2026-01-30T15:06:33Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A tool used by openshift to build base images using different build engines.\n    - url: https://github.com/mutable/container-factory\n      name: mutable/container-factory\n      status: stale\n      stars: 64\n      forks: 3\n      last_push: 2015-05-06T16:07:53Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Produces Docker images from tarballs of application source code.\n    - url: https://github.com/mdlavin/copy-docker-image\n      name: mdlavin/copy-docker-image\n      status: stale\n      stars: 38\n      forks: 16\n      last_push: 2018-08-29T08:27:20Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Copy a Docker image between registries without a full Docker installation.\n    - url: https://github.com/alibaba/derrick\n      name: alibaba/derrick\n      status: stale\n      stars: 693\n      forks: 109\n      last_push: 2023-03-06T22:40:17Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A tool help you to automate the generation of Dockerfile and dockerize application by scanning the code. By [alibaba](https://github.com/alibaba).\n    - url: https://github.com/orisano/dlayer\n      name: orisano/dlayer\n      status: healthy\n      stars: 445\n      forks: 12\n      last_push: 2026-03-02T09:11:34Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Docker layer analyzer.\n    - url: https://github.com/mudler/docker-companion\n      name: mudler/docker-companion\n      status: healthy\n      stars: 47\n      forks: 9\n      last_push: 2025-05-28T08:17:46Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A command line tool written in Golang to squash and unpack docker images.\n    - url: https://github.com/CtripCloud/docker-make\n      name: CtripCloud/docker-make\n      status: stale\n      stars: 99\n      forks: 20\n      last_push: 2019-11-22T08:32:26Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Build, tag,and push a bunch of related docker images via a single command.\n    - url: https://github.com/orf/docker-repack\n      name: orf/docker-repack\n      status: healthy\n      stars: 151\n      forks: 3\n      last_push: 2025-04-24T06:46:00Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Repacks a Docker image into a smaller, more efficient version that makes it significantly faster to pull. By [orf](https://github.com/orf).\n    - url: https://github.com/bcicen/docker-replay\n      name: bcicen/docker-replay\n      status: stale\n      stars: 203\n      forks: 13\n      last_push: 2018-10-13T13:09:28Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Generate `docker run`command and options from running containers. By [bcicen](https://github.com/bcicen).\n    - url: https://github.com/swipely/dockly\n      name: swipely/dockly\n      status: stale\n      stars: 228\n      forks: 10\n      last_push: 2023-02-15T15:26:17Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Dockly is a gem made to ease the pain of packaging an application in Docker.\n    - url: https://github.com/utensils/essex\n      name: utensils/essex\n      status: healthy\n      stars: 38\n      last_push: 2025-03-18T21:33:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: 'Boilerplate for Docker Based Projects: Essex is a CLI utility written in bash to quickly setup clean and consistent Docker projects with Makefile driven workflows. [jamesbrink](https://github.com/jamesbrink).'\n    - url: https://github.com/NVIDIA/hpc-container-maker\n      name: NVIDIA/hpc-container-maker\n      status: healthy\n      stars: 510\n      forks: 100\n      last_push: 2026-02-19T23:22:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Generates Dockerfiles from a high level Python recipe, including building blocks for High-Performance Computing components.\n    - url: https://github.com/genuinetools/img\n      name: genuinetools/img\n      status: inactive\n      stars: 3990\n      forks: 234\n      last_push: 2024-05-19T22:07:07Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Standalone, daemon-less, unprivileged Dockerfile and OCI compatible container image builder.\n    - url: https://github.com/duedil-ltd/portainer\n      name: duedil-ltd/portainer\n      status: stale\n      stars: 134\n      forks: 16\n      last_push: 2017-02-28T17:15:49Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Apache Mesos framework for building Docker images.\n    - url: https://github.com/cybersecsi/RAUDI\n      name: cybersecsi/RAUDI\n      status: healthy\n      stars: 560\n      forks: 34\n      last_push: 2026-03-05T01:57:28Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A tool to automatically update (and optionally push to Docker Hub) Docker Images for 3rd party software whenever theres is a new release/update/commit. By [SecSI](https://github.com/cybersecsi).\n    - url: https://github.com/lavie/runlike\n      name: lavie/runlike\n      status: healthy\n      stars: 2919\n      forks: 163\n      last_push: 2025-12-04T12:36:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Generate `docker run`command and options from running containers.\n    - url: https://github.com/theAkito/userdef\n      name: theAkito/userdef\n      status: stale\n      stars: 11\n      last_push: 2023-10-14T20:34:12Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: An advanced `adduser` for your Alpine based Docker images. Made by [Akito][akito].\n    - url: https://github.com/P3GLEG/Whaler\n      name: P3GLEG/Whaler\n      status: healthy\n      stars: 1185\n      forks: 101\n      last_push: 2025-09-17T03:56:52Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: Program to reverse Docker images into Dockerfiles.\n    - url: https://github.com/Gueils/whales\n      name: Gueils/whales\n      status: stale\n      stars: 391\n      forks: 20\n      last_push: 2019-05-27T13:20:14Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Builder\n      description: A tool to automatically dockerize your applications.\n    - url: https://github.com/garywiz/chaperone-docker\n      name: garywiz/chaperone-docker\n      status: stale\n      stars: 66\n      forks: 11\n      last_push: 2018-10-05T07:48:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Dockerfile\n      description: A set of images using the Chaperone process manager, including a lean Alpine image, LAMP, LEMP, and bare-bones base kits.\n    - url: https://github.com/patrickhoefler/dockerfilegraph\n      name: patrickhoefler/dockerfilegraph\n      status: healthy\n      stars: 255\n      forks: 17\n      last_push: 2026-03-08T00:49:58Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Dockerfile\n      description: Visualize your multi-stage Dockerfiles. By [PatrickHoefler](https://github.com/patrickhoefler).\n    - url: https://github.com/Dockershelf/dockershelf\n      name: Dockershelf/dockershelf\n      status: healthy\n      stars: 97\n      forks: 13\n      last_push: 2026-03-05T01:03:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Dockerfile\n      description: A repository that serves as a collector for docker recipes that are universal, efficient and slim. Images are updated, tested and published daily via a Travis cron job.\n    - url: https://github.com/deckrun/dockadvisor\n      name: deckrun/dockadvisor\n      status: healthy\n      stars: 186\n      forks: 6\n      last_push: 2026-01-12T09:26:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Linter\n      description: Lightweight Dockerfile linter with 60+ rules, quality scoring, and security checks.\n    - url: https://github.com/wemake-services/docker-image-size-limit\n      name: wemake-services/docker-image-size-limit\n      status: healthy\n      stars: 130\n      forks: 5\n      last_push: 2026-03-06T23:18:34Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Linter\n      description: A tool to keep an eye on your docker images size.\n    - url: https://github.com/buddy-works/dockerfile-linter\n      name: buddy-works/dockerfile-linter\n      status: stale\n      stars: 46\n      forks: 3\n      last_push: 2023-03-04T05:06:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Linter\n      description: The linter lets you verify Dockerfile syntax to make sure it follows the best practices for building efficient Docker images.\n    - url: https://github.com/replicatedhq/dockerfilelint\n      name: replicatedhq/dockerfilelint\n      status: stale\n      stars: 1029\n      forks: 83\n      last_push: 2023-09-27T20:58:01Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Linter\n      description: An opinionated Dockerfile linter.\n    - url: https://github.com/hadolint/hadolint\n      name: hadolint/hadolint\n      status: healthy\n      stars: 11985\n      forks: 487\n      last_push: 2026-03-02T08:58:07Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Linter\n      description: A Dockerfile linter that checks for best practices, common mistakes, and is also able to lint any bash written in `RUN` instructions;.\n    - url: https://github.com/RedCoolBeans/cargos-buildroot\n      name: RedCoolBeans/cargos-buildroot\n      status: stale\n      stars: 11\n      forks: 2\n      last_push: 2017-04-02T14:59:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: A bare essential OS for running the Docker Engine on bare metal or Cloud. By [RedCoolBeans](https://github.com/RedCoolBeans).\n    - url: https://github.com/hcguersoy/cleanreg\n      name: hcguersoy/cleanreg\n      status: stale\n      stars: 59\n      forks: 18\n      last_push: 2022-09-03T17:43:40Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: A small tool to delete image manifests from a Docker Registry implementing the API v2, dereferencing them for the GC.\n    - url: https://github.com/netvarun/docket\n      name: netvarun/docket\n      status: stale\n      stars: 709\n      forks: 33\n      last_push: 2020-09-02T02:35:17Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: Custom docker registry that allows for lightning fast deploys through bittorrent.\n    - url: https://github.com/dragonflyoss/Dragonfly2\n      name: dragonflyoss/Dragonfly2\n      status: healthy\n      stars: 3070\n      forks: 377\n      last_push: 2026-03-05T12:44:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: Provide efficient, stable and secure file distribution and image acceleration based on p2p technology.\n    - url: https://github.com/uber/kraken\n      name: uber/kraken\n      status: healthy\n      stars: 6659\n      forks: 468\n      last_push: 2026-03-05T13:24:04Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: Uber's Highly scalable P2P docker registry, capable of distributing TBs of data in seconds.\n    - url: https://github.com/jhstatewide/nscr\n      name: jhstatewide/nscr\n      status: healthy\n      stars: 1\n      last_push: 2025-10-27T14:37:18Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: A light-weight, self-contained container registry that's easy to run and maintain.\n    - url: https://github.com/inmagik/registryo\n      name: inmagik/registryo\n      status: healthy\n      stars: 15\n      last_push: 2025-12-17T10:20:47Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: UI and token based authentication server for onpremise docker registry.\n    - url: https://github.com/noteed/rescoyl\n      name: noteed/rescoyl\n      status: stale\n      stars: 18\n      forks: 4\n      last_push: 2017-04-08T19:17:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Docker Images > Registry\n      description: Private Docker registry (free and open source).\n    - url: https://github.com/instacart/ahab\n      name: instacart/ahab\n      status: stale\n      stars: 137\n      forks: 7\n      last_push: 2018-11-16T21:54:44Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Docker event handling with Python.\n    - url: https://github.com/lispyclouds/contajners\n      name: lispyclouds/contajners\n      status: healthy\n      stars: 145\n      forks: 8\n      last_push: 2026-02-20T09:07:36Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: An idiomatic, data-driven, REPL friendly Clojure client for OCI container engines. By [lispyclouds][lispyclouds].\n    - url: https://github.com/gesellix/docker-client\n      name: gesellix/docker-client\n      status: healthy\n      stars: 119\n      forks: 28\n      last_push: 2026-03-08T12:34:16Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: A Docker remote api client library for the JVM, written in Groovy.\n    - url: https://github.com/dgongut/docker-controller-bot\n      name: dgongut/docker-controller-bot\n      status: healthy\n      stars: 241\n      forks: 31\n      last_push: 2026-02-04T15:58:07Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Telegram bot to control docker containers. By [dgongut](https://github.com/dgongut/).\n    - url: https://github.com/whisklabs/docker-it-scala\n      name: whisklabs/docker-it-scala\n      status: stale\n      stars: 433\n      forks: 90\n      last_push: 2024-02-14T12:56:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Docker integration testing kit with Scala.\n    - url: https://github.com/amihaiemil/docker-java-api\n      name: amihaiemil/docker-java-api\n      status: stale\n      stars: 274\n      forks: 55\n      last_push: 2021-06-04T01:21:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Lightweight, truly object-oriented, Java client for Docker's API. By [amihaiemil](https://github.com/amihaiemil).\n    - url: https://github.com/fabric8io/docker-maven-plugin\n      name: fabric8io/docker-maven-plugin\n      status: healthy\n      stars: 1929\n      forks: 656\n      last_push: 2026-02-24T15:30:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: A Maven plugin for running and creating Docker images.\n    - url: https://github.com/Microsoft/Docker.DotNet\n      name: Microsoft/Docker.DotNet\n      status: healthy\n      stars: 2405\n      forks: 409\n      last_push: 2025-08-28T14:08:51Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: C#/.NET HTTP client for the Docker remote API.\n    - url: https://github.com/ChangemakerStudios/Docker.Registry.DotNet\n      name: ChangemakerStudios/Docker.Registry.DotNet\n      status: healthy\n      stars: 42\n      forks: 21\n      last_push: 2025-10-06T03:43:52Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: .NET (C#) Client Library for interacting with a Docker Registry API (v2) [rquackenbush](https://github.com/rquackenbush).\n    - url: https://github.com/apocas/dockerode\n      name: apocas/dockerode\n      status: healthy\n      stars: 4834\n      forks: 486\n      last_push: 2026-02-28T03:51:43Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Docker Remote API node.js module.\n    - url: https://github.com/eon01/DoMonit\n      name: eon01/DoMonit\n      status: stale\n      stars: 76\n      forks: 15\n      last_push: 2021-06-01T21:57:21Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: A simple Docker Monitoring wrapper For Docker API.\n    - url: https://github.com/fsouza/go-dockerclient\n      name: fsouza/go-dockerclient\n      status: healthy\n      stars: 2236\n      forks: 556\n      last_push: 2026-03-06T04:10:21Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n    - url: https://github.com/gesellix/gradle-docker-plugin\n      name: gesellix/gradle-docker-plugin\n      status: healthy\n      stars: 81\n      forks: 17\n      last_push: 2026-03-08T12:36:04Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: A Docker remote api plugin for Gradle.\n    - url: https://github.com/greenled/portainer-stack-utils\n      name: greenled/portainer-stack-utils\n      status: healthy\n      stars: 74\n      forks: 16\n      last_push: 2025-12-05T02:34:50Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Bash script to deploy/update/undeploy Docker stacks in a Portainer instance from a docker-compose yaml file. By [greenled](https://github.com/greenled).\n    - url: https://github.com/marcuslonnberg/sbt-docker\n      name: marcuslonnberg/sbt-docker\n      status: inactive\n      stars: 733\n      forks: 112\n      last_push: 2024-12-12T15:18:45Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > API Client\n      description: Create Docker images directly from sbt.\n    - url: https://github.com/harbur/captain\n      name: harbur/captain\n      status: healthy\n      stars: 776\n      forks: 48\n      last_push: 2025-05-25T00:09:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Convert your Git workflow to Docker containers ready for Continuous Delivery.\n    - url: https://github.com/caicloud/cyclone\n      name: caicloud/cyclone\n      status: stale\n      stars: 1073\n      forks: 171\n      last_push: 2023-10-24T12:08:27Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Powerful workflow engine and end-to-end pipeline solutions implemented with native Kubernetes resources.\n    - url: https://github.com/DefangLabs/defang\n      name: DefangLabs/defang\n      status: healthy\n      stars: 146\n      forks: 24\n      last_push: 2026-03-08T06:20:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Deploy Docker Compose to your favorite cloud in minutes.\n    - url: https://github.com/crazy-max/diun\n      name: crazy-max/diun\n      status: healthy\n      stars: 4457\n      forks: 143\n      last_push: 2026-03-08T17:42:13Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Receive notifications when an image or repository is updated on a Docker registry by [crazy-max].\n    - url: https://github.com/mag37/dockcheck\n      name: mag37/dockcheck\n      status: healthy\n      stars: 2237\n      forks: 80\n      last_push: 2026-03-05T18:27:54Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: A script checking updates for docker images without pulling then auto-update selected/all containers. With notifications, pruning and more.\n    - url: https://github.com/jenkinsci/docker-plugin\n      name: jenkinsci/docker-plugin\n      status: healthy\n      stars: 499\n      forks: 325\n      last_push: 2026-02-28T10:00:57Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n    - url: https://github.com/drone/drone\n      name: drone/drone\n      status: healthy\n      stars: 33861\n      forks: 2896\n      last_push: 2026-03-07T12:23:43Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Continuous integration server built on Docker and configured using YAML files.\n    - url: https://github.com/CodesWhat/drydock\n      name: CodesWhat/drydock\n      status: healthy\n      stars: 111\n      forks: 5\n      last_push: 2026-03-08T18:03:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Open-source container update monitoring with web dashboard, 15 registries, 16 notification triggers, and security scanning. Drop-in WUD replacement. By [CodesWhat](https://github.com/CodesWhat).\n    - url: https://github.com/shizunge/gantry\n      name: shizunge/gantry\n      status: healthy\n      stars: 84\n      forks: 4\n      last_push: 2026-03-06T03:39:21Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Automatically update selected Docker swarm services.\n    - url: https://github.com/theSage21/jaypore_ci\n      name: theSage21/jaypore_ci\n      status: healthy\n      stars: 38\n      forks: 4\n      last_push: 2026-03-07T17:18:09Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Simple, very flexible, powerful CI / CD / automation system configured in Python. Offline and local first.\n    - url: https://github.com/Kraken-CI/kraken\n      name: Kraken-CI/kraken\n      status: healthy\n      stars: 160\n      forks: 20\n      last_push: 2026-01-15T13:00:32Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Modern CI/CD, open-source, on-premise system that is highly scalable and focused on testing. One of its executors is Docker. Developed.\n    - url: https://github.com/francescou/docker-continuous-deployment\n      name: francescou/docker-continuous-deployment\n      status: stale\n      stars: 145\n      forks: 38\n      last_push: 2017-08-01T17:25:15Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Continuous deployment of a microservices application.\n    - url: https://github.com/stelligent/mu\n      name: stelligent/mu\n      status: stale\n      stars: 965\n      forks: 133\n      last_push: 2020-06-18T14:09:29Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Tool to configure CI/CD of your container applications via AWS CodePipeline, CodeBuild and ECS [Stelligent](https://github.com/stelligent).\n    - url: https://github.com/systemslab/popper\n      name: systemslab/popper\n      status: stale\n      stars: 307\n      forks: 62\n      last_push: 2022-03-29T22:02:27Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Github actions workflow (HCL syntax) execution engine.\n    - url: https://github.com/Stratoscale/skipper\n      name: Stratoscale/skipper\n      status: healthy\n      stars: 50\n      forks: 22\n      last_push: 2025-05-13T13:33:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Easily dockerize your Git repository.\n    - url: https://github.com/ghostsquad/swarmci\n      name: ghostsquad/swarmci\n      status: stale\n      stars: 58\n      forks: 6\n      last_push: 2017-02-24T02:14:18Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > CI/CD\n      description: Create a distributed, isolated task pipeline in your Docker Swarm.\n    - url: https://github.com/binci/binci\n      name: binci/binci\n      status: stale\n      stars: 673\n      forks: 24\n      last_push: 2022-12-06T20:24:40Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Containerize your development workflow. (formerly DevLab by [TechnologyAdvice](https://github.com/TechnologyAdvice)).\n    - url: https://github.com/coder/coder\n      name: coder/coder\n      status: healthy\n      stars: 12417\n      forks: 1194\n      last_push: 2026-03-08T17:58:52Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Remote development machines powered by Terraform or Docker.\n    - url: https://github.com/lstephen/construi\n      name: lstephen/construi\n      status: stale\n      stars: 24\n      forks: 5\n      last_push: 2022-12-08T06:36:04Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Run your builds inside a Docker defined environment.\n    - url: https://github.com/whatwedo/dde\n      name: whatwedo/dde\n      status: healthy\n      stars: 46\n      forks: 9\n      last_push: 2026-02-20T12:25:04Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Local development environment toolset based on Docker. By [whatwedo](https://github.com/whatwedo).\n    - url: https://github.com/bibendi/dip\n      name: bibendi/dip\n      status: inactive\n      stars: 1324\n      forks: 50\n      last_push: 2024-12-25T09:38:57Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: CLI utility for straightforward provisioning and interacting with an application configured by docker-compose. By [bibendi](https://github.com/bibendi).\n    - url: https://github.com/dnephin/dobi\n      name: dnephin/dobi\n      status: stale\n      stars: 315\n      forks: 34\n      last_push: 2023-11-10T06:32:19Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: A build automation tool for Docker applications. By [dnephin](https://github.com/dnephin).\n    - url: https://github.com/nandoquintana/docker-missing-tools\n      name: nandoquintana/docker-missing-tools\n      status: stale\n      stars: 30\n      forks: 6\n      last_push: 2018-05-01T13:10:10Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: A set of bash commands to shortcut typical docker dev-ops. An alternative to creating typical helper scripts like \"build.sh\" and \"deploy.sh\" inside code repositories. By [NandoQuintana](https://github.com/nandoquintana).\n    - url: https://github.com/Ph3nol/Docker-Arch\n      name: Ph3nol/Docker-Arch\n      status: stale\n      stars: 31\n      forks: 2\n      last_push: 2018-09-24T06:43:08Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Generate Web/CLI projects Dockerized development environments, from 1 simple YAML file. By [Ph3nol](https://github.com/ph3nol).\n    - url: https://github.com/EugenMayer/docker-sync\n      name: EugenMayer/docker-sync\n      status: healthy\n      stars: 3564\n      forks: 285\n      last_push: 2025-11-30T20:06:16Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Drastically improves performance ([50-70x](https://github.com/EugenMayer/docker-sync/wiki/4.-Performance)) when using Docker for development on Mac OS X/Windows and Linux while sharing code to the container. By [EugenMayer](https://github.com/EugenMayer).\n    - url: https://github.com/shyiko/docker-vm\n      name: shyiko/docker-vm\n      status: stale\n      stars: 43\n      forks: 8\n      last_push: 2016-09-24T17:45:47Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Simple and transparent alternative to boot2docker (backed by Vagrant).\n    - url: https://github.com/matifali/dockerdl\n      name: matifali/dockerdl\n      status: healthy\n      stars: 86\n      forks: 11\n      last_push: 2025-12-29T19:27:19Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Deep Learning Docker Images. Don't waste time setting up a deep learning env when you can get a deep learning environment with everything pre-installed.\n    - url: https://github.com/eclipse/che\n      name: eclipse/che\n      status: healthy\n      stars: 7129\n      forks: 1200\n      last_push: 2026-03-06T15:10:49Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Developer workspace server with Docker runtimes, cloud IDE, next-generation Eclipse IDE.\n    - url: https://github.com/EnvCLI/EnvCLI\n      name: EnvCLI/EnvCLI\n      status: healthy\n      stars: 116\n      forks: 4\n      last_push: 2025-06-16T20:36:16Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Replace your local installation of Node, Go, ... with project-specific docker containers. By [EnvCLI](https://github.com/EnvCLI).\n    - url: https://github.com/hpsaturn/esp32s3-linux\n      name: hpsaturn/esp32s3-linux\n      status: healthy\n      stars: 78\n      forks: 9\n      last_push: 2025-04-05T08:38:16Z\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Container solution to compile Linux and develop it for ESP32 microcontrollers - By [Hpsaturn](https://github.com/hpsaturn).\n    - url: https://github.com/moshebe/gebug\n      name: moshebe/gebug\n      status: healthy\n      stars: 634\n      forks: 17\n      last_push: 2026-03-06T21:42:46Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: A tool that makes debugging of Dockerized Go applications super easy by enabling Debugger and Hot-Reload features, seamlessly.\n    - url: https://github.com/senges/kitt\n      name: senges/kitt\n      status: stale\n      stars: 20\n      forks: 1\n      last_push: 2023-02-23T14:01:05Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: A portable and disposable Shell environment, based on Docker and Nix. By [senges](https://github.com/senges).\n    - url: https://github.com/lando/lando\n      name: lando/lando\n      status: healthy\n      stars: 4222\n      forks: 527\n      last_push: 2026-02-24T21:10:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Lando is for developers who want to quickly specify and painlessly spin up the services and tools needed to develop their projects. By [Tandem](https://www.thinktandem.io/).\n    - url: https://github.com/Peco602/rust-universal-compiler\n      name: Peco602/rust-universal-compiler\n      status: stale\n      stars: 33\n      forks: 2\n      last_push: 2023-04-30T17:04:02Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Container solution to compile Rust projects for Linux, macOS and Windows. By [Peco602][peco602].\n    - url: https://github.com/uniget-org/cli\n      name: uniget-org/cli\n      status: healthy\n      stars: 20\n      last_push: 2026-02-12T08:35:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Uni(versal)get, the installer and updater for container tools and beyond (formerly docker-setup). By [nicholasdille](https://github.com/nicholasdille).\n    - url: https://github.com/tailhook/vagga\n      name: tailhook/vagga\n      status: stale\n      stars: 1896\n      forks: 96\n      last_push: 2023-03-31T06:13:55Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Vagga is a containerisation tool without daemons. It is a fully-userspace container engine inspired by Vagrant and Docker, specialized for development environments.\n    - url: https://github.com/deluan/zsh-in-docker\n      name: deluan/zsh-in-docker\n      status: inactive\n      stars: 1096\n      forks: 119\n      last_push: 2024-09-30T19:07:49Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Development Environment\n      description: Install Zsh, Oh-My-Zsh and plugins inside a Docker container with one line! By [Deluan](https://www.deluan.com).\n    - url: https://github.com/tjamet/caduc\n      name: tjamet/caduc\n      status: stale\n      stars: 21\n      forks: 1\n      last_push: 2019-01-07T16:07:50Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Garbage Collection\n      description: A docker garbage collector cleaning stuff you did not use recently.\n    - url: https://github.com/ZZROTDesign/docker-clean\n      name: ZZROTDesign/docker-clean\n      status: stale\n      stars: 1304\n      forks: 90\n      last_push: 2018-01-16T16:29:41Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Garbage Collection\n      description: A script that cleans Docker containers, images and volumes.\n    - url: https://github.com/Yelp/docker-custodian\n      name: Yelp/docker-custodian\n      status: inactive\n      stars: 374\n      forks: 49\n      last_push: 2024-08-14T08:08:10Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Garbage Collection\n      description: Keep docker hosts tidy. By [Yelp](https://github.com/Yelp).\n    - url: https://github.com/pdacity/docker_gc\n      name: pdacity/docker_gc\n      status: stale\n      stars: 128\n      forks: 22\n      last_push: 2024-02-09T17:50:47Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Garbage Collection\n      description: Image for automatic removing unused Docker Swarm objects. Also works just as Docker Service.\n    - url: https://github.com/stepchowfun/docuum\n      name: stepchowfun/docuum\n      status: healthy\n      stars: 684\n      forks: 43\n      last_push: 2026-03-07T22:59:03Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Garbage Collection\n      description: Least recently used (LRU) eviction of Docker images.\n    - url: https://github.com/apache/openwhisk\n      name: apache/openwhisk\n      status: healthy\n      stars: 6757\n      forks: 1174\n      last_push: 2026-01-24T05:17:06Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Serverless\n      description: A serverless, open source cloud platform that executes functions in response to events at any scale. By [apache](https://github.com/apache).\n    - url: https://github.com/bfirsh/funker-example-voting-app\n      name: bfirsh/funker-example-voting-app\n      status: stale\n      stars: 26\n      forks: 8\n      last_push: 2016-11-29T11:51:39Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Serverless\n      description: Functions as Docker containers example voting app. By [bfirsh](https://github.com/bfirsh).\n    - url: https://github.com/iron-io/functions\n      name: iron-io/functions\n      status: stale\n      stars: 3220\n      forks: 224\n      last_push: 2023-09-15T01:37:58Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Serverless\n      description: The serverless microservices platform FaaS (Functions as a Service) which uses Docker containers to run Any language or AWS Lambda functions.\n    - url: https://github.com/openfaas/faas\n      name: openfaas/faas\n      status: healthy\n      stars: 26105\n      forks: 1970\n      last_push: 2026-02-22T08:49:51Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Serverless\n      description: A complete serverless functions framework for Docker and Kubernetes. By [OpenFaaS](https://github.com/openfaas).\n    - url: https://github.com/grycap/scar\n      name: grycap/scar\n      status: stale\n      stars: 599\n      forks: 47\n      last_push: 2023-05-22T11:01:11Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Serverless\n      description: Serverless Container-aware Architectures (SCAR) is a serverless framework that allows easy deployment and execution of containers (e.g. Docker) in Serverless environments (e.g. Lambda).\n    - url: https://github.com/GoogleContainerTools/container-structure-test\n      name: GoogleContainerTools/container-structure-test\n      status: healthy\n      stars: 2462\n      forks: 207\n      last_push: 2026-02-20T23:41:16Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Testing\n      description: A framework to validate the structure of an image by checking the outputs of commands or the contents of the filesystem. By [GoogleContainerTools][googlecontainertools].\n    - url: https://github.com/zuazo/dockerspec\n      name: zuazo/dockerspec\n      status: stale\n      stars: 181\n      forks: 8\n      last_push: 2017-08-30T20:40:57Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Testing\n      description: A small Ruby Gem to run RSpec and Serverspec, Infrataster and Capybara tests against Dockerfiles or Docker images easily. By [zuazo](https://github.com/zuazo).\n    - url: https://github.com/lynchborg/ezdc\n      name: lynchborg/ezdc\n      status: stale\n      stars: 12\n      last_push: 2024-02-12T08:42:24Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Testing\n      description: Golang test harness for easily setting up tests that rely on services in a docker-compose.yml. By [byrnedo].\n    - url: https://github.com/kurtosis-tech/kurtosis\n      name: kurtosis-tech/kurtosis\n      status: healthy\n      stars: 526\n      forks: 90\n      last_push: 2026-03-06T11:06:13Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Testing\n      description: 'A composable build system for multi-container test environments that provides developers with: a powerful Python-like SDK for environment configuration, a compile-time validator to verify environment behavior & setup, and a runtime for environment execution, monitoring, & debugging capabilities. By [Kurtosis](https://www.kurtosis.com/).'\n    - url: https://github.com/alexei-led/pumba\n      name: alexei-led/pumba\n      status: healthy\n      stars: 3000\n      forks: 201\n      last_push: 2026-03-01T21:26:21Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Testing\n      description: Chaos testing tool for Docker. Can be deployed on kubernetes and CoreOS cluster. By [alexei-led](https://github.com/alexei-led).\n    - url: https://github.com/docker-exec/dexec\n      name: docker-exec/dexec\n      status: stale\n      stars: 332\n      forks: 14\n      last_push: 2021-05-13T06:04:19Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Command line interface written in Go for running code with Docker Exec images.\n    - url: https://github.com/benzaita/dockerized-cli\n      name: benzaita/dockerized-cli\n      status: stale\n      stars: 65\n      forks: 5\n      last_push: 2024-02-27T13:49:38Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Seamlessly execute commands in a container.\n    - url: https://github.com/CenturyLinkLabs/dray\n      name: CenturyLinkLabs/dray\n      status: stale\n      stars: 386\n      forks: 37\n      last_push: 2020-01-24T17:34:58Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: An engine for managing the execution of container-based workflows.\n    - url: https://github.com/artsy/hokusai\n      name: artsy/hokusai\n      status: healthy\n      stars: 98\n      forks: 25\n      last_push: 2026-03-06T10:57:58Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: A Docker + Kubernetes CLI for application developers; used to containerize an application and to manage its lifecycle throughout development, testing, and release cycles. From [artsy](https://github.com/artsy).\n    - url: https://github.com/livecycle/preevy\n      name: livecycle/preevy\n      status: healthy\n      stars: 2191\n      forks: 87\n      last_push: 2026-02-06T07:38:46Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Preview environments for Docker and Docker Compose projects. Test your changes and get feedback from devs and non-devs (Product/Design) by deploying pull requests to the your cloud provider as part of your CI pipeline.\n    - url: https://github.com/ianmiell/shutit\n      name: ianmiell/shutit\n      status: stale\n      stars: 2144\n      forks: 110\n      last_push: 2022-08-14T14:43:18Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Tool for building and maintaining complex Docker deployments.\n    - url: https://github.com/subuser-security/subuser\n      name: subuser-security/subuser\n      status: inactive\n      stars: 894\n      forks: 63\n      last_push: 2025-02-23T11:31:31Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Makes it easy to securely and portably run graphical desktop applications in Docker.\n    - url: https://github.com/christippett/terraform-cloudinit-container-server\n      name: christippett/terraform-cloudinit-container-server\n      status: stale\n      stars: 120\n      forks: 30\n      last_push: 2022-08-19T06:41:50Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Terraform module for deploying a single Docker image or `docker-compose.yaml` file to any Cloud™ VM.\n    - url: https://github.com/ramitsurana/turbo\n      name: ramitsurana/turbo\n      status: stale\n      stars: 27\n      forks: 12\n      last_push: 2021-12-22T19:03:53Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: Simple and Powerful utility for docker. By [ramitsurana][ramitsurana].\n    - url: https://github.com/indigo-dc/udocker\n      name: indigo-dc/udocker\n      status: healthy\n      stars: 1709\n      forks: 164\n      last_push: 2025-08-13T17:21:57Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Development with Docker > Wrappers\n      description: A tool to execute simple docker containers in batch or interactive systems without root privileges.\n    - url: https://github.com/Appdynamics/docker-monitoring-extension\n      name: Appdynamics/docker-monitoring-extension\n      status: inactive\n      stars: 5\n      forks: 6\n      last_push: 2024-10-02T10:48:59Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Services based on Docker (mostly :heavy_dollar_sign:) > Monitoring Services\n      description: Docker Monitoring extension gathers metrics from the Docker Remote API, either using Unix Socket or TCP.\n    - url: https://github.com/sematext/sematext-agent-docker\n      name: sematext/sematext-agent-docker\n      status: stale\n      stars: 208\n      forks: 32\n      last_push: 2023-12-09T18:07:20Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Projects > Services based on Docker (mostly :heavy_dollar_sign:) > Monitoring Services\n      description: Monitoring of host and container metrics, Docker events and logs. Automatic log parser. Anomaly Detection and alerting for metrics and logs. [sematext](https://github.com/sematext).\n    - url: https://github.com/cicdops/awesome-ciandcd\n      name: cicdops/awesome-ciandcd\n      status: inactive\n      stars: 1987\n      forks: 225\n      last_push: 2024-04-01T18:08:23Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Useful Resources > Awesome Lists\n      description: Not specific to docker but relevant.\n    - url: https://github.com/docker/awesome-compose\n      name: docker/awesome-compose\n      status: healthy\n      stars: 44283\n      forks: 8070\n      last_push: 2026-03-05T09:59:09Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Useful Resources > Awesome Lists\n      description: Docker Compose samples.\n    - url: https://github.com/hexops/dockerfile\n      name: hexops/dockerfile\n      status: stale\n      stars: 4091\n      forks: 155\n      last_push: 2021-08-08T04:42:37Z\n      has_license: true\n      checked_at: 2026-03-08T18:26:00.233336Z\n      category: Useful Resources > Good Tips\n      description: This repository has best-practices for writing Dockerfiles.\n"
  },
  {
    "path": "config/website.tmpl.html",
    "content": "<!DOCTYPE html>\n<html class=\"no-js\" lang=\"en\">\n  <head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n    <meta http-equiv=\"Cache-control\" content=\"public\" />\n    <meta charset=\"UTF-8\" />\n    <title>Awesome-docker</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" media=\"(prefers-color-scheme: light)\" content=\"#0B77B7\" />\n    <meta name=\"theme-color\" media=\"(prefers-color-scheme: dark)\" content=\"#13344C\" />\n    <meta name=\"color-scheme\" content=\"light dark\" />\n    <meta\n      name=\"description\"\n      content=\"A curated list of Docker resources and projects.\"\n    />\n    <meta\n      name=\"keywords\"\n      content=\"free and open-source open source projects for docker moby kubernetes linux awesome awesome-list container tools dockerfile list moby docker-container docker-image docker-environment docker-deployment docker-swarm docker-api docker-monitoring docker-machine docker-security docker-registry\"\n    />\n    <meta\n      name=\"google-site-verification\"\n      content=\"_yiugvz0gCtfsBLyLl1LnkALXb6D4ofiwCyV1XOlYBM\"\n    />\n    <link rel=\"icon\" type=\"image/png\" href=\"favicon.png\" />\n    <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n    <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n    <link\n      href=\"https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;700;800&family=Sora:wght@600;700;800&display=swap\"\n      rel=\"stylesheet\"\n    />\n    <style>\n      :root {\n        --bg: #f3f8fb;\n        --bg-top: #eaf5fb;\n        --bg-bottom: #f6fbff;\n        --bg-spot-1: rgba(200, 232, 248, 1);\n        --bg-spot-2: rgba(213, 240, 255, 1);\n        --surface: #ffffff;\n        --surface-soft: #f7fbfe;\n        --text: #1f2d3d;\n        --muted: #4e6279;\n        --heading: #103a5c;\n        --link: #065f95;\n        --link-hover: #044971;\n        --border: #dbe7f0;\n        --marker: #2f77a8;\n        --hr: #d3e4f0;\n        --focus-ring: #0a67a5;\n        --focus-halo: rgba(10, 103, 165, 0.28);\n        --header-grad-start: #0d4d78;\n        --header-grad-mid: #0b77b7;\n        --header-grad-end: #43a8d8;\n        --header-orb-1: rgba(255, 255, 255, 0.3);\n        --header-orb-2: rgba(84, 195, 245, 0.5);\n        --code-bg: #edf4fa;\n        --code-border: #dce7f0;\n        --code-text: #1f2d3d;\n        --pre-bg: #0e2334;\n        --pre-border: #d8e3ed;\n        --pre-text: #e2edf5;\n        --table-bg: #ffffff;\n        --table-header-bg: #f0f7fc;\n        --toc-bg: linear-gradient(180deg, #f8fcff 0%, #f3f9fd 100%);\n        --toc-title: #214f72;\n        --toc-child-border: #c8deed;\n        --toc-link: #175886;\n        --toc-link-hover: #0f3f61;\n        --toc-link-hover-bg: #e6f2fa;\n        --toc-link-active: #0d3e61;\n        --toc-link-active-bg: #d9ebf8;\n        --toc-link-active-ring: #bcd8ec;\n        --shadow: 0 22px 50px -34px rgba(17, 57, 88, 0.42);\n      }\n\n      @media (prefers-color-scheme: dark) {\n        :root {\n          --bg: #0e1620;\n          --bg-top: #101a25;\n          --bg-bottom: #0d141d;\n          --bg-spot-1: rgba(23, 47, 68, 0.85);\n          --bg-spot-2: rgba(19, 61, 89, 0.62);\n          --surface: #121e2a;\n          --surface-soft: #162634;\n          --text: #d5e4f2;\n          --muted: #9fb7ce;\n          --heading: #f0f7ff;\n          --link: #7cc7f5;\n          --link-hover: #a1d8fb;\n          --border: #2b4257;\n          --marker: #78b6dd;\n          --hr: #284154;\n          --focus-ring: #84cbf8;\n          --focus-halo: rgba(132, 203, 248, 0.32);\n          --header-grad-start: #12344c;\n          --header-grad-mid: #185c86;\n          --header-grad-end: #23759f;\n          --header-orb-1: rgba(133, 198, 242, 0.24);\n          --header-orb-2: rgba(61, 141, 189, 0.36);\n          --code-bg: #1b2b3a;\n          --code-border: #2b4257;\n          --code-text: #d8e8f7;\n          --pre-bg: #0b1622;\n          --pre-border: #2b4257;\n          --pre-text: #dceaf7;\n          --table-bg: #121e2a;\n          --table-header-bg: #1a2b3a;\n          --toc-bg: linear-gradient(180deg, #162736 0%, #132432 100%);\n          --toc-title: #b6d6ee;\n          --toc-child-border: #335067;\n          --toc-link: #a9d4f2;\n          --toc-link-hover: #d7ecfc;\n          --toc-link-hover-bg: #20384b;\n          --toc-link-active: #e6f5ff;\n          --toc-link-active-bg: #294a62;\n          --toc-link-active-ring: #3e6482;\n          --shadow: 0 28px 60px -36px rgba(0, 0, 0, 0.78);\n        }\n      }\n\n      * {\n        box-sizing: border-box;\n      }\n\n      html {\n        -ms-text-size-adjust: 100%;\n        -webkit-text-size-adjust: 100%;\n        scroll-behavior: smooth;\n      }\n\n      body {\n        margin: 0;\n        min-height: 100vh;\n        font-family: \"Manrope\", \"Segoe UI\", \"Helvetica Neue\", Arial, sans-serif;\n        font-size: 16px;\n        line-height: 1.65;\n        color: var(--text);\n        background:\n          radial-gradient(circle at 12% 12%, var(--bg-spot-1) 0, transparent 40%),\n          radial-gradient(circle at 85% 2%, var(--bg-spot-2) 0, transparent 32%),\n          linear-gradient(180deg, var(--bg-top) 0%, var(--bg) 34%, var(--bg-bottom) 100%);\n      }\n\n      a {\n        color: var(--link);\n        text-decoration: none;\n        text-underline-offset: 0.16em;\n        transition: color 140ms ease, text-decoration-color 140ms ease;\n      }\n\n      a:hover {\n        color: var(--link-hover);\n        text-decoration: underline;\n      }\n\n      :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {\n        outline: 3px solid var(--focus-ring);\n        outline-offset: 3px;\n        box-shadow: 0 0 0 4px var(--focus-halo);\n        border-radius: 7px;\n      }\n\n      strong {\n        font-weight: 800;\n      }\n\n      p {\n        margin: 0;\n      }\n\n      img {\n        border: 0;\n        max-width: 100%;\n      }\n\n      svg:not(:root) {\n        overflow: hidden;\n      }\n\n      .btn {\n        display: inline-block;\n        padding: 0.72rem 1.15rem;\n        color: #ffffff;\n        font-weight: 700;\n        letter-spacing: 0.01em;\n        background: rgba(255, 255, 255, 0.18);\n        border: 1px solid rgba(255, 255, 255, 0.42);\n        border-radius: 10px;\n        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28);\n      }\n\n      .btn:hover {\n        color: #ffffff;\n        text-decoration: none;\n        background: rgba(255, 255, 255, 0.3);\n      }\n\n      .page-header {\n        position: relative;\n        overflow: hidden;\n        text-align: center;\n        color: #ffffff;\n        background-image: linear-gradient(128deg, var(--header-grad-start) 5%, var(--header-grad-mid) 57%, var(--header-grad-end) 100%);\n      }\n\n      .page-header::before,\n      .page-header::after {\n        content: \"\";\n        position: absolute;\n        border-radius: 999px;\n        pointer-events: none;\n      }\n\n      .page-header::before {\n        width: 30rem;\n        height: 30rem;\n        right: -7rem;\n        top: -19rem;\n        background: radial-gradient(circle, var(--header-orb-1) 0%, transparent 68%);\n      }\n\n      .page-header::after {\n        width: 28rem;\n        height: 28rem;\n        left: -10rem;\n        bottom: -20rem;\n        background: radial-gradient(circle, var(--header-orb-2) 0%, transparent 70%);\n      }\n\n      .page-header > * {\n        position: relative;\n        z-index: 1;\n      }\n\n      .project-name {\n        margin: 0 0 0.55rem;\n        font-family: \"Sora\", \"Avenir Next\", \"Segoe UI\", Arial, sans-serif;\n        font-size: clamp(2rem, 4.4vw, 3.4rem);\n        line-height: 1.05;\n        letter-spacing: -0.028em;\n      }\n\n      .project-tagline {\n        margin: 0 auto;\n        max-width: 46rem;\n        color: rgba(255, 255, 255, 0.92);\n        font-size: clamp(1.02rem, 1.8vw, 1.22rem);\n        line-height: 1.45;\n      }\n\n      .header-actions {\n        margin-top: 1.5rem;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        gap: 0.8rem;\n        flex-wrap: wrap;\n      }\n\n      .site-shell {\n        max-width: 76rem;\n        margin: -2.2rem auto 0;\n        padding: 0 1rem 2.5rem;\n      }\n\n      .main-content {\n        background: var(--surface);\n        border: 1px solid var(--border);\n        border-radius: 20px;\n        box-shadow: var(--shadow);\n        word-wrap: break-word;\n        overflow-wrap: anywhere;\n        max-width: 72rem;\n        margin: 0 auto;\n        padding: clamp(1.35rem, 1rem + 1.45vw, 2.6rem) clamp(1rem, 0.55rem + 2.15vw, 2.8rem);\n      }\n\n      .main-content > * {\n        max-width: 70ch;\n      }\n\n      .main-content > :first-child {\n        margin-top: 0;\n      }\n\n      .main-content h1,\n      .main-content h2,\n      .main-content h3,\n      .main-content h4,\n      .main-content h5 {\n        font-family: \"Sora\", \"Avenir Next\", \"Segoe UI\", Arial, sans-serif;\n        line-height: 1.2;\n        letter-spacing: -0.015em;\n        color: var(--heading);\n        scroll-margin-top: 1.1rem;\n        margin: 2rem 0 0.8rem;\n      }\n\n      .main-content h1 {\n        font-size: clamp(1.6rem, 2.5vw, 2.2rem);\n      }\n\n      .main-content h2 {\n        font-size: clamp(1.45rem, 2.2vw, 1.92rem);\n      }\n\n      .main-content h3 {\n        font-size: clamp(1.3rem, 2vw, 1.62rem);\n      }\n\n      .main-content h4,\n      .main-content h5 {\n        font-size: clamp(1.15rem, 1.85vw, 1.34rem);\n      }\n\n      .main-content p,\n      .main-content li {\n        color: var(--text);\n        line-height: 1.76;\n      }\n\n      .main-content p + p {\n        margin-top: 0.95rem;\n      }\n\n      .main-content ul,\n      .main-content ol {\n        padding-left: 1.4rem;\n        margin: 0.62rem 0 1.2rem;\n      }\n\n      .main-content li + li {\n        margin-top: 0.34rem;\n      }\n\n      .main-content ul li::marker {\n        color: var(--marker);\n      }\n\n      .main-content hr {\n        max-width: 100%;\n        border: 0;\n        height: 1px;\n        margin: 2.2rem 0;\n        background: linear-gradient(90deg, transparent, var(--hr) 18%, var(--hr) 82%, transparent);\n      }\n\n      .main-content blockquote {\n        margin: 1.3rem 0;\n        padding: 0.9rem 1.15rem;\n        border-left: 4px solid #68b0da;\n        border-radius: 0 12px 12px 0;\n        background: var(--surface-soft);\n        color: var(--muted);\n      }\n\n      .main-content blockquote > :first-child {\n        margin-top: 0;\n      }\n\n      .main-content blockquote > :last-child {\n        margin-bottom: 0;\n      }\n\n      .main-content code {\n        font-family: \"SFMono-Regular\", Menlo, Consolas, \"Liberation Mono\", monospace;\n        font-size: 0.88em;\n        background: var(--code-bg);\n        border: 1px solid var(--code-border);\n        border-radius: 6px;\n        padding: 0.08em 0.38em;\n        color: var(--code-text);\n      }\n\n      .main-content pre {\n        max-width: 100%;\n        overflow: auto;\n        border: 1px solid var(--pre-border);\n        border-radius: 12px;\n        background: var(--pre-bg);\n        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);\n        padding: 0.9rem 1rem;\n      }\n\n      .main-content pre code {\n        padding: 0;\n        border: 0;\n        background: transparent;\n        color: var(--pre-text);\n      }\n\n      .main-content table {\n        width: 100%;\n        max-width: 100%;\n        border-collapse: collapse;\n        border: 1px solid var(--border);\n        border-radius: 12px;\n        overflow: hidden;\n        background: var(--table-bg);\n        margin: 1.2rem 0 1.6rem;\n      }\n\n      .main-content th,\n      .main-content td {\n        border: 1px solid var(--border);\n        padding: 0.52rem 0.68rem;\n        text-align: left;\n      }\n\n      .main-content th {\n        background: var(--table-header-bg);\n        color: var(--heading);\n        font-weight: 700;\n      }\n\n      .main-content > ul:first-of-type {\n        list-style: none;\n        max-width: 100%;\n        padding: 0.95rem 1.05rem 1rem;\n        margin: 1rem 0 1.8rem;\n        border: 1px solid var(--border);\n        border-radius: 14px;\n        background: var(--toc-bg);\n      }\n\n      .main-content > ul:first-of-type::before {\n        content: \"Contents\";\n        display: block;\n        margin-bottom: 0.65rem;\n        font-family: \"Sora\", \"Avenir Next\", \"Segoe UI\", Arial, sans-serif;\n        font-size: 0.9rem;\n        font-weight: 700;\n        letter-spacing: 0.01em;\n        text-transform: uppercase;\n        color: var(--toc-title);\n      }\n\n      .main-content > ul:first-of-type li {\n        margin: 0.22rem 0;\n      }\n\n      .main-content > ul:first-of-type ul {\n        margin: 0.25rem 0 0.55rem 0.48rem;\n        padding-left: 0.58rem;\n        border-left: 1px solid var(--toc-child-border);\n      }\n\n      .main-content > ul:first-of-type a {\n        display: block;\n        padding: 0.2rem 0.46rem;\n        border-radius: 8px;\n        font-weight: 700;\n        color: var(--toc-link);\n        transition: color 170ms ease, background-color 180ms ease, box-shadow 180ms ease, transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);\n      }\n\n      .main-content > ul:first-of-type a:hover {\n        color: var(--toc-link-hover);\n        text-decoration: none;\n        background: var(--toc-link-hover-bg);\n        transform: translateX(2px);\n      }\n\n      .main-content > ul:first-of-type a.is-active {\n        color: var(--toc-link-active);\n        background: var(--toc-link-active-bg);\n        box-shadow: inset 0 0 0 1px var(--toc-link-active-ring);\n        transform: translateX(3px);\n      }\n\n      .main-content > ul:first-of-type li ul a {\n        font-weight: 600;\n        font-size: 0.92rem;\n      }\n\n      .main-content img {\n        word-wrap: break-word;\n        height: auto;\n      }\n\n      @keyframes hero-fade-in {\n        from {\n          opacity: 0;\n          transform: translateY(12px);\n        }\n        to {\n          opacity: 1;\n          transform: translateY(0);\n        }\n      }\n\n      @keyframes panel-rise-in {\n        from {\n          opacity: 0;\n          transform: translateY(14px);\n        }\n        to {\n          opacity: 1;\n          transform: translateY(0);\n        }\n      }\n\n      .page-header > * {\n        animation: hero-fade-in 540ms cubic-bezier(0.21, 0.76, 0.26, 1) both;\n      }\n\n      .project-tagline {\n        animation-delay: 90ms;\n      }\n\n      .header-actions {\n        animation-delay: 170ms;\n      }\n\n      .main-content {\n        animation: panel-rise-in 620ms cubic-bezier(0.18, 0.74, 0.24, 1) 130ms both;\n      }\n\n      @media screen and (min-width: 54em) {\n        .page-header {\n          padding: 4.65rem 2rem 5.05rem;\n        }\n\n        .main-content {\n          display: grid;\n          grid-template-columns: minmax(15rem, 19rem) minmax(0, 1fr);\n          column-gap: 2rem;\n          row-gap: 0;\n          align-items: start;\n        }\n\n        .main-content > * {\n          grid-column: 2;\n          width: min(100%, 70ch);\n          max-width: 100%;\n        }\n\n        .main-content > ul:first-of-type {\n          grid-column: 1;\n          grid-row: 1 / span 999;\n          width: 100%;\n          margin: 0;\n          position: sticky;\n          top: 1rem;\n          max-height: calc(100vh - 2rem);\n          overflow: auto;\n        }\n\n        .main-content > ul:first-of-type + * {\n          margin-top: 0;\n        }\n\n        .main-content > table,\n        .main-content > pre {\n          width: 100%;\n          max-width: 100%;\n        }\n      }\n\n      @media screen and (max-width: 54em) {\n        .page-header {\n          padding: 3.1rem 1rem 4.2rem;\n        }\n\n        .site-shell {\n          margin-top: -1.7rem;\n        }\n\n        .main-content > ul:first-of-type {\n          max-height: none;\n          position: static;\n        }\n\n        .header-actions {\n          gap: 0.65rem;\n        }\n      }\n\n      @media screen and (max-width: 34em) {\n        .btn {\n          width: 100%;\n        }\n\n        .main-content {\n          border-radius: 14px;\n          padding-top: 1.1rem;\n        }\n      }\n\n      @media (prefers-reduced-motion: reduce) {\n        * {\n          scroll-behavior: auto;\n          transition: none !important;\n          animation: none !important;\n        }\n      }\n    </style>\n  </head>\n\n  <body>\n    <section class=\"page-header\">\n      <h1 class=\"project-name\">Awesome-docker</h1>\n      <p class=\"project-tagline\">\n        A curated list of Docker resources and projects\n      </p>\n      <div class=\"header-actions\">\n        <a href=\"https://github.com/veggiemonk/awesome-docker\" class=\"btn\"\n          >View on GitHub</a\n        >\n        <a\n          class=\"github-button\"\n          href=\"https://github.com/veggiemonk/awesome-docker#readme\"\n          data-icon=\"octicon-star\"\n          data-size=\"large\"\n          data-count-href=\"/veggiemonk/awesome-docker/stargazers\"\n          data-show-count=\"true\"\n          data-count-aria-label=\"# stargazers on GitHub\"\n          aria-label=\"Star veggiemonk/awesome-docker on GitHub\"\n          >Star</a\n        >\n      </div>\n    </section>\n    <main class=\"site-shell\">\n      <section id=\"md\" class=\"main-content\"></section>\n    </main>\n    <script async defer src=\"https://buttons.github.io/buttons.js\"></script>\n    <script>\n      (function () {\n        var toc = document.querySelector(\"#md > ul:first-of-type\");\n        if (!toc) {\n          return;\n        }\n\n        var links = Array.prototype.slice.call(toc.querySelectorAll('a[href^=\"#\"]'));\n        if (links.length === 0) {\n          return;\n        }\n\n        var linkById = {};\n        links.forEach(function (link) {\n          var href = link.getAttribute(\"href\");\n          if (!href || href.length < 2) {\n            return;\n          }\n          var id = href.slice(1);\n          try {\n            id = decodeURIComponent(id);\n          } catch (_) {}\n          if (id) {\n            linkById[id] = link;\n          }\n        });\n\n        var headings = Array.prototype.filter.call(\n          document.querySelectorAll(\"#md h1[id], #md h2[id], #md h3[id], #md h4[id], #md h5[id]\"),\n          function (heading) {\n            return Boolean(linkById[heading.id]);\n          }\n        );\n        if (headings.length === 0) {\n          return;\n        }\n\n        function setActive(id) {\n          if (!id || !linkById[id]) {\n            return;\n          }\n          links.forEach(function (link) {\n            link.classList.remove(\"is-active\");\n            link.removeAttribute(\"aria-current\");\n          });\n          linkById[id].classList.add(\"is-active\");\n          linkById[id].setAttribute(\"aria-current\", \"true\");\n        }\n\n        function setActiveFromHash() {\n          if (!window.location.hash || window.location.hash.length < 2) {\n            return false;\n          }\n          var id = window.location.hash.slice(1);\n          try {\n            id = decodeURIComponent(id);\n          } catch (_) {}\n          if (linkById[id]) {\n            setActive(id);\n            return true;\n          }\n          return false;\n        }\n\n        function setActiveFromViewport() {\n          var current = headings[0];\n          for (var i = 0; i < headings.length; i += 1) {\n            if (headings[i].getBoundingClientRect().top <= 150) {\n              current = headings[i];\n            } else {\n              break;\n            }\n          }\n          setActive(current.id);\n        }\n\n        var ticking = false;\n        window.addEventListener(\n          \"scroll\",\n          function () {\n            if (ticking) {\n              return;\n            }\n            ticking = true;\n            window.requestAnimationFrame(function () {\n              setActiveFromViewport();\n              ticking = false;\n            });\n          },\n          { passive: true }\n        );\n\n        window.addEventListener(\"hashchange\", setActiveFromHash);\n        if (!setActiveFromHash()) {\n          setActiveFromViewport();\n        }\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/veggiemonk/awesome-docker\n\ngo 1.26.0\n\nrequire (\n\tcharm.land/bubbletea/v2 v2.0.2\n\tcharm.land/lipgloss/v2 v2.0.2\n\tgithub.com/shurcooL/githubv4 v0.0.0-20260209031235-2402fdf4a9ed\n\tgithub.com/spf13/cobra v1.10.2\n\tgithub.com/yuin/goldmark v1.7.16\n\tgolang.org/x/oauth2 v0.36.0\n\tgopkg.in/yaml.v3 v3.0.1\n)\n\nrequire (\n\tgithub.com/charmbracelet/colorprofile v0.4.3 // indirect\n\tgithub.com/charmbracelet/ultraviolet v0.0.0-20260309091805-903bfd0cf188 // indirect\n\tgithub.com/charmbracelet/x/ansi v0.11.6 // indirect\n\tgithub.com/charmbracelet/x/term v0.2.2 // indirect\n\tgithub.com/charmbracelet/x/termios v0.1.1 // indirect\n\tgithub.com/charmbracelet/x/windows v0.2.2 // indirect\n\tgithub.com/clipperhouse/displaywidth v0.11.0 // indirect\n\tgithub.com/clipperhouse/uax29/v2 v2.7.0 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/lucasb-eyer/go-colorful v1.3.0 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.21 // indirect\n\tgithub.com/muesli/cancelreader v0.2.2 // indirect\n\tgithub.com/rivo/uniseg v0.4.7 // indirect\n\tgithub.com/shurcooL/graphql v0.0.0-20240915155400-7ee5256398cf // indirect\n\tgithub.com/spf13/pflag v1.0.10 // indirect\n\tgithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/sys v0.42.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "charm.land/bubbletea/v2 v2.0.1 h1:B8e9zzK7x9JJ+XvHGF4xnYu9Xa0E0y0MyggY6dbaCfQ=\ncharm.land/bubbletea/v2 v2.0.1/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=\ncharm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0=\ncharm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=\ncharm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo=\ncharm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14=\ncharm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs=\ncharm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM=\ngithub.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM=\ngithub.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=\ngithub.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o=\ngithub.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=\ngithub.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=\ngithub.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=\ngithub.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=\ngithub.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=\ngithub.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=\ngithub.com/charmbracelet/ultraviolet v0.0.0-20260309091805-903bfd0cf188 h1:J8v4kWJYCaxv1SLhLunN74S+jMteZ1f7Dae99ioq4Bo=\ngithub.com/charmbracelet/ultraviolet v0.0.0-20260309091805-903bfd0cf188/go.mod h1:FzWNAbe1jEmI+GZljSnlaSA8wJjnNIZhWBLkTsAl6eg=\ngithub.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=\ngithub.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=\ngithub.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=\ngithub.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=\ngithub.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=\ngithub.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=\ngithub.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=\ngithub.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=\ngithub.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=\ngithub.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=\ngithub.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=\ngithub.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=\ngithub.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=\ngithub.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=\ngithub.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=\ngithub.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=\ngithub.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=\ngithub.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=\ngithub.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=\ngithub.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=\ngithub.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=\ngithub.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=\ngithub.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/githubv4 v0.0.0-20260209031235-2402fdf4a9ed h1:KT7hI8vYXgU0s2qaMkrfq9tCA1w/iEPgfredVP+4Tzw=\ngithub.com/shurcooL/githubv4 v0.0.0-20260209031235-2402fdf4a9ed/go.mod h1:zqMwyHmnN/eDOZOdiTohqIUKUrTFX62PNlu7IJdu0q8=\ngithub.com/shurcooL/graphql v0.0.0-20240915155400-7ee5256398cf h1:o1uxfymjZ7jZ4MsgCErcwWGtVKSiNAXtS59Lhs6uI/g=\ngithub.com/shurcooL/graphql v0.0.0-20240915155400-7ee5256398cf/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=\ngithub.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE=\ngithub.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngolang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=\ngolang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=\ngolang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=\ngolang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=\ngolang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=\ngolang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=\ngolang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=\ngolang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=\ngolang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n  <meta http-equiv=\"refresh\" content=\"0; url=website/\">\n  <title>Awesome-docker</title>\n</head>\n<body>\n<p><a href=\"website/\">Redirecting to the generated site.</a></p>\n</body>\n</html>\n"
  },
  {
    "path": "internal/builder/builder.go",
    "content": "package builder\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/yuin/goldmark\"\n\t\"github.com/yuin/goldmark/extension\"\n\t\"github.com/yuin/goldmark/parser\"\n\t\"github.com/yuin/goldmark/renderer/html\"\n)\n\n// Build converts a Markdown file to HTML using a template.\n// The template must contain a placeholder element that will be replaced with the rendered content.\nfunc Build(markdownPath, templatePath, outputPath string) error {\n\tmd, err := os.ReadFile(markdownPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read markdown: %w\", err)\n\t}\n\n\ttmpl, err := os.ReadFile(templatePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read template: %w\", err)\n\t}\n\n\t// Convert markdown to HTML\n\tgm := goldmark.New(\n\t\tgoldmark.WithExtensions(extension.GFM),\n\t\tgoldmark.WithParserOptions(parser.WithAutoHeadingID()),\n\t\tgoldmark.WithRendererOptions(html.WithUnsafe()),\n\t)\n\tvar buf bytes.Buffer\n\tif err := gm.Convert(md, &buf); err != nil {\n\t\treturn fmt.Errorf(\"convert markdown: %w\", err)\n\t}\n\n\t// Inject into template — support both placeholder formats\n\toutput := string(tmpl)\n\treplacements := []struct {\n\t\told string\n\t\tnew string\n\t}{\n\t\t{\n\t\t\told: `<div id=\"md\"></div>`,\n\t\t\tnew: `<div id=\"md\">` + buf.String() + `</div>`,\n\t\t},\n\t\t{\n\t\t\told: `<section id=\"md\" class=\"main-content\"></section>`,\n\t\t\tnew: `<section id=\"md\" class=\"main-content\">` + buf.String() + `</section>`,\n\t\t},\n\t}\n\n\treplaced := false\n\tfor _, r := range replacements {\n\t\tif strings.Contains(output, r.old) {\n\t\t\toutput = strings.Replace(output, r.old, r.new, 1)\n\t\t\treplaced = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !replaced {\n\t\treturn fmt.Errorf(\"template missing supported markdown placeholder\")\n\t}\n\n\tif err := os.WriteFile(outputPath, []byte(output), 0o644); err != nil {\n\t\treturn fmt.Errorf(\"write output: %w\", err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/builder/builder_test.go",
    "content": "package builder\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestBuild(t *testing.T) {\n\tdir := t.TempDir()\n\n\tmd := \"# Test List\\n\\n- [Example](https://example.com) - A test entry.\\n\"\n\tmdPath := filepath.Join(dir, \"README.md\")\n\tif err := os.WriteFile(mdPath, []byte(md), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttmpl := `<!DOCTYPE html>\n<html>\n<body>\n<div id=\"md\"></div>\n</body>\n</html>`\n\ttmplPath := filepath.Join(dir, \"template.html\")\n\tif err := os.WriteFile(tmplPath, []byte(tmpl), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\toutPath := filepath.Join(dir, \"index.html\")\n\tif err := Build(mdPath, tmplPath, outPath); err != nil {\n\t\tt.Fatalf(\"Build failed: %v\", err)\n\t}\n\n\tcontent, err := os.ReadFile(outPath)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\thtml := string(content)\n\tif !strings.Contains(html, \"Test List\") {\n\t\tt.Error(\"expected 'Test List' in output\")\n\t}\n\tif !strings.Contains(html, \"https://example.com\") {\n\t\tt.Error(\"expected link in output\")\n\t}\n}\n\nfunc TestBuildWithSectionPlaceholder(t *testing.T) {\n\tdir := t.TempDir()\n\n\tmd := \"# Hello\\n\\nWorld.\\n\"\n\tmdPath := filepath.Join(dir, \"README.md\")\n\tif err := os.WriteFile(mdPath, []byte(md), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// This matches the actual template format\n\ttmpl := `<!DOCTYPE html>\n<html>\n<body>\n<section id=\"md\" class=\"main-content\"></section>\n</body>\n</html>`\n\ttmplPath := filepath.Join(dir, \"template.html\")\n\tif err := os.WriteFile(tmplPath, []byte(tmpl), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\toutPath := filepath.Join(dir, \"index.html\")\n\tif err := Build(mdPath, tmplPath, outPath); err != nil {\n\t\tt.Fatalf(\"Build failed: %v\", err)\n\t}\n\n\tcontent, err := os.ReadFile(outPath)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif !strings.Contains(string(content), \"Hello\") {\n\t\tt.Error(\"expected 'Hello' in output\")\n\t}\n\tif !strings.Contains(string(content), `class=\"main-content\"`) {\n\t\tt.Error(\"expected section class preserved\")\n\t}\n}\n\nfunc TestBuildRealREADME(t *testing.T) {\n\tmdPath := \"../../README.md\"\n\ttmplPath := \"../../config/website.tmpl.html\"\n\tif _, err := os.Stat(mdPath); err != nil {\n\t\tt.Skip(\"README.md not found\")\n\t}\n\tif _, err := os.Stat(tmplPath); err != nil {\n\t\tt.Skip(\"website template not found\")\n\t}\n\n\tdir := t.TempDir()\n\toutPath := filepath.Join(dir, \"index.html\")\n\n\tif err := Build(mdPath, tmplPath, outPath); err != nil {\n\t\tt.Fatalf(\"Build failed: %v\", err)\n\t}\n\n\tinfo, err := os.Stat(outPath)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif info.Size() < 10000 {\n\t\tt.Errorf(\"output too small: %d bytes\", info.Size())\n\t}\n\tt.Logf(\"Generated %d bytes\", info.Size())\n}\n\nfunc TestBuildFailsWithoutPlaceholder(t *testing.T) {\n\tdir := t.TempDir()\n\n\tmdPath := filepath.Join(dir, \"README.md\")\n\tif err := os.WriteFile(mdPath, []byte(\"# Title\\n\"), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttmplPath := filepath.Join(dir, \"template.html\")\n\tif err := os.WriteFile(tmplPath, []byte(\"<html><body><main></main></body></html>\"), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\toutPath := filepath.Join(dir, \"index.html\")\n\terr := Build(mdPath, tmplPath, outPath)\n\tif err == nil {\n\t\tt.Fatal(\"expected Build to fail when template has no supported placeholder\")\n\t}\n}\n\nfunc TestBuildAddsHeadingIDs(t *testing.T) {\n\tdir := t.TempDir()\n\n\tmd := \"# Getting Started\\n\\n## Next Step\\n\"\n\tmdPath := filepath.Join(dir, \"README.md\")\n\tif err := os.WriteFile(mdPath, []byte(md), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttmpl := `<!DOCTYPE html>\n<html>\n<body>\n<section id=\"md\" class=\"main-content\"></section>\n</body>\n</html>`\n\ttmplPath := filepath.Join(dir, \"template.html\")\n\tif err := os.WriteFile(tmplPath, []byte(tmpl), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\toutPath := filepath.Join(dir, \"index.html\")\n\tif err := Build(mdPath, tmplPath, outPath); err != nil {\n\t\tt.Fatalf(\"Build failed: %v\", err)\n\t}\n\n\tcontent, err := os.ReadFile(outPath)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\thtml := string(content)\n\tif !strings.Contains(html, `id=\"getting-started\"`) {\n\t\tt.Error(\"expected auto-generated heading id for h1\")\n\t}\n\tif !strings.Contains(html, `id=\"next-step\"`) {\n\t\tt.Error(\"expected auto-generated heading id for h2\")\n\t}\n}\n"
  },
  {
    "path": "internal/cache/cache.go",
    "content": "package cache\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"gopkg.in/yaml.v3\"\n)\n\n// ExcludeList holds URL prefixes to skip during checking.\ntype ExcludeList struct {\n\tDomains []string `yaml:\"domains\"`\n}\n\n// IsExcluded returns true if the URL starts with any excluded prefix.\nfunc (e *ExcludeList) IsExcluded(url string) bool {\n\tfor _, d := range e.Domains {\n\t\tif strings.HasPrefix(url, d) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// LoadExcludeList reads an exclude.yaml file.\nfunc LoadExcludeList(path string) (*ExcludeList, error) {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar excl ExcludeList\n\tif err := yaml.Unmarshal(data, &excl); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &excl, nil\n}\n\n// HealthEntry stores metadata about a single entry.\ntype HealthEntry struct {\n\tURL        string    `yaml:\"url\"`\n\tName       string    `yaml:\"name\"`\n\tStatus     string    `yaml:\"status\"` // healthy, inactive, stale, archived, dead\n\tStars      int       `yaml:\"stars,omitempty\"`\n\tForks      int       `yaml:\"forks,omitempty\"`\n\tLastPush   time.Time `yaml:\"last_push,omitempty\"`\n\tHasLicense  bool      `yaml:\"has_license,omitempty\"`\n\tHasReadme   bool      `yaml:\"has_readme,omitempty\"`\n\tCheckedAt   time.Time `yaml:\"checked_at\"`\n\tCategory    string    `yaml:\"category,omitempty\"`\n\tDescription string    `yaml:\"description,omitempty\"`\n}\n\n// HealthCache is the full YAML cache file.\ntype HealthCache struct {\n\tEntries []HealthEntry `yaml:\"entries\"`\n}\n\n// LoadHealthCache reads a health_cache.yaml file. Returns empty cache if file doesn't exist.\nfunc LoadHealthCache(path string) (*HealthCache, error) {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn &HealthCache{}, nil\n\t\t}\n\t\treturn nil, err\n\t}\n\tvar hc HealthCache\n\tif err := yaml.Unmarshal(data, &hc); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &hc, nil\n}\n\n// SaveHealthCache writes the cache to a YAML file.\nfunc SaveHealthCache(path string, hc *HealthCache) error {\n\tdata, err := yaml.Marshal(hc)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn os.WriteFile(path, data, 0o644)\n}\n\n// Merge updates the cache with new entries, replacing existing ones by URL.\nfunc (hc *HealthCache) Merge(entries []HealthEntry) {\n\tindex := make(map[string]int)\n\tfor i, e := range hc.Entries {\n\t\tindex[e.URL] = i\n\t}\n\tfor _, e := range entries {\n\t\tif i, exists := index[e.URL]; exists {\n\t\t\thc.Entries[i] = e\n\t\t} else {\n\t\t\tindex[e.URL] = len(hc.Entries)\n\t\t\thc.Entries = append(hc.Entries, e)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/cache/cache_test.go",
    "content": "package cache\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestLoadExcludeList(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"exclude.yaml\")\n\tcontent := `domains:\n  - https://example.com\n  - https://test.org\n`\n\tif err := os.WriteFile(path, []byte(content), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\texcl, err := LoadExcludeList(path)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(excl.Domains) != 2 {\n\t\tt.Errorf(\"domains count = %d, want 2\", len(excl.Domains))\n\t}\n\tif !excl.IsExcluded(\"https://example.com/foo\") {\n\t\tt.Error(\"expected https://example.com/foo to be excluded\")\n\t}\n\tif excl.IsExcluded(\"https://other.com\") {\n\t\tt.Error(\"expected https://other.com to NOT be excluded\")\n\t}\n}\n\nfunc TestHealthCacheRoundTrip(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"health.yaml\")\n\n\toriginal := &HealthCache{\n\t\tEntries: []HealthEntry{\n\t\t\t{\n\t\t\t\tURL:        \"https://github.com/example/repo\",\n\t\t\t\tName:       \"Example\",\n\t\t\t\tStatus:     \"healthy\",\n\t\t\t\tStars:      42,\n\t\t\t\tLastPush:   time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC),\n\t\t\t\tHasLicense: true,\n\t\t\t\tHasReadme:  true,\n\t\t\t\tCheckedAt:  time.Date(2026, 2, 27, 9, 0, 0, 0, time.UTC),\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := SaveHealthCache(path, original); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tloaded, err := LoadHealthCache(path)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(loaded.Entries) != 1 {\n\t\tt.Fatalf(\"entries = %d, want 1\", len(loaded.Entries))\n\t}\n\tif loaded.Entries[0].Stars != 42 {\n\t\tt.Errorf(\"stars = %d, want 42\", loaded.Entries[0].Stars)\n\t}\n}\n\nfunc TestLoadHealthCacheMissing(t *testing.T) {\n\thc, err := LoadHealthCache(\"/nonexistent/path.yaml\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(hc.Entries) != 0 {\n\t\tt.Errorf(\"entries = %d, want 0 for missing file\", len(hc.Entries))\n\t}\n}\n\nfunc TestLoadHealthCacheInvalidYAML(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"health.yaml\")\n\tif err := os.WriteFile(path, []byte(\"entries:\\n  - url: [not yaml\"), 0o644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\thc, err := LoadHealthCache(path)\n\tif err == nil {\n\t\tt.Fatal(\"expected error for invalid YAML\")\n\t}\n\tif hc != nil {\n\t\tt.Fatal(\"expected nil cache on invalid YAML\")\n\t}\n}\n\nfunc TestMerge(t *testing.T) {\n\thc := &HealthCache{\n\t\tEntries: []HealthEntry{\n\t\t\t{URL: \"https://github.com/a/a\", Name: \"A\", Stars: 10},\n\t\t\t{URL: \"https://github.com/b/b\", Name: \"B\", Stars: 20},\n\t\t},\n\t}\n\n\thc.Merge([]HealthEntry{\n\t\t{URL: \"https://github.com/b/b\", Name: \"B\", Stars: 25}, // update\n\t\t{URL: \"https://github.com/c/c\", Name: \"C\", Stars: 30}, // new\n\t})\n\n\tif len(hc.Entries) != 3 {\n\t\tt.Fatalf(\"entries = %d, want 3\", len(hc.Entries))\n\t}\n\t// B should be updated\n\tif hc.Entries[1].Stars != 25 {\n\t\tt.Errorf(\"B stars = %d, want 25\", hc.Entries[1].Stars)\n\t}\n\t// C should be appended\n\tif hc.Entries[2].Name != \"C\" {\n\t\tt.Errorf(\"last entry = %q, want C\", hc.Entries[2].Name)\n\t}\n}\n\nfunc TestMergeDeduplicatesIncomingBatch(t *testing.T) {\n\thc := &HealthCache{}\n\n\thc.Merge([]HealthEntry{\n\t\t{URL: \"https://github.com/c/c\", Name: \"C\", Stars: 1},\n\t\t{URL: \"https://github.com/c/c\", Name: \"C\", Stars: 2},\n\t})\n\n\tif len(hc.Entries) != 1 {\n\t\tt.Fatalf(\"entries = %d, want 1\", len(hc.Entries))\n\t}\n\tif hc.Entries[0].Stars != 2 {\n\t\tt.Fatalf(\"stars = %d, want last value 2\", hc.Entries[0].Stars)\n\t}\n}\n"
  },
  {
    "path": "internal/checker/github.go",
    "content": "package checker\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/shurcooL/githubv4\"\n\t\"golang.org/x/oauth2\"\n)\n\n// RepoInfo holds metadata about a GitHub repository.\ntype RepoInfo struct {\n\tOwner      string\n\tName       string\n\tURL        string\n\tIsArchived bool\n\tIsDisabled bool\n\tIsPrivate  bool\n\tPushedAt   time.Time\n\tStars      int\n\tForks      int\n\tHasLicense bool\n}\n\n// ExtractGitHubRepo extracts owner/name from a GitHub URL.\n// Returns false for non-repo URLs (issues, wiki, apps, etc.).\nfunc ExtractGitHubRepo(rawURL string) (owner, name string, ok bool) {\n\tu, err := url.Parse(rawURL)\n\tif err != nil {\n\t\treturn \"\", \"\", false\n\t}\n\n\thost := strings.ToLower(u.Hostname())\n\tif host != \"github.com\" && host != \"www.github.com\" {\n\t\treturn \"\", \"\", false\n\t}\n\n\tpath := strings.Trim(u.Path, \"/\")\n\tparts := strings.Split(path, \"/\")\n\tif len(parts) != 2 || parts[0] == \"\" || parts[1] == \"\" {\n\t\treturn \"\", \"\", false\n\t}\n\n\t// Skip known non-repository top-level routes.\n\tswitch parts[0] {\n\tcase \"apps\", \"features\", \"topics\":\n\t\treturn \"\", \"\", false\n\t}\n\n\tname = strings.TrimSuffix(parts[1], \".git\")\n\tif name == \"\" {\n\t\treturn \"\", \"\", false\n\t}\n\n\treturn parts[0], name, true\n}\n\nfunc isHTTPURL(raw string) bool {\n\tu, err := url.Parse(raw)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn u.Scheme == \"http\" || u.Scheme == \"https\"\n}\n\nfunc isGitHubAuthError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\ts := strings.ToLower(err.Error())\n\treturn strings.Contains(s, \"401 unauthorized\") ||\n\t\tstrings.Contains(s, \"bad credentials\") ||\n\t\tstrings.Contains(s, \"resource not accessible by integration\")\n}\n\n// PartitionLinks separates URLs into GitHub repos and external HTTP(S) links.\nfunc PartitionLinks(urls []string) (github, external []string) {\n\tfor _, url := range urls {\n\t\tif _, _, ok := ExtractGitHubRepo(url); ok {\n\t\t\tgithub = append(github, url)\n\t\t} else if isHTTPURL(url) {\n\t\t\texternal = append(external, url)\n\t\t}\n\t}\n\treturn\n}\n\n// GitHubChecker uses the GitHub GraphQL API.\ntype GitHubChecker struct {\n\tclient *githubv4.Client\n}\n\n// NewGitHubChecker creates a checker with the given OAuth token.\nfunc NewGitHubChecker(token string) *GitHubChecker {\n\tsrc := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})\n\thttpClient := oauth2.NewClient(context.Background(), src)\n\treturn &GitHubChecker{client: githubv4.NewClient(httpClient)}\n}\n\n// CheckRepo queries a single GitHub repository.\nfunc (gc *GitHubChecker) CheckRepo(ctx context.Context, owner, name string) (RepoInfo, error) {\n\tvar query struct {\n\t\tRepository struct {\n\t\t\tIsArchived     bool\n\t\t\tIsDisabled     bool\n\t\t\tIsPrivate      bool\n\t\t\tPushedAt       time.Time\n\t\t\tStargazerCount int\n\t\t\tForkCount      int\n\t\t\tLicenseInfo    *struct {\n\t\t\t\tName string\n\t\t\t}\n\t\t} `graphql:\"repository(owner: $owner, name: $name)\"`\n\t}\n\n\tvars := map[string]interface{}{\n\t\t\"owner\": githubv4.String(owner),\n\t\t\"name\":  githubv4.String(name),\n\t}\n\n\tif err := gc.client.Query(ctx, &query, vars); err != nil {\n\t\treturn RepoInfo{}, fmt.Errorf(\"github query %s/%s: %w\", owner, name, err)\n\t}\n\n\tr := query.Repository\n\treturn RepoInfo{\n\t\tOwner:      owner,\n\t\tName:       name,\n\t\tURL:        fmt.Sprintf(\"https://github.com/%s/%s\", owner, name),\n\t\tIsArchived: r.IsArchived,\n\t\tIsDisabled: r.IsDisabled,\n\t\tIsPrivate:  r.IsPrivate,\n\t\tPushedAt:   r.PushedAt,\n\t\tStars:      r.StargazerCount,\n\t\tForks:      r.ForkCount,\n\t\tHasLicense: r.LicenseInfo != nil,\n\t}, nil\n}\n\n// CheckRepos queries multiple repos in sequence with rate limiting.\nfunc (gc *GitHubChecker) CheckRepos(ctx context.Context, urls []string, batchSize int) ([]RepoInfo, []error) {\n\tif batchSize <= 0 {\n\t\tbatchSize = 50\n\t}\n\n\tvar results []RepoInfo\n\tvar errs []error\n\n\tfor i, url := range urls {\n\t\towner, name, ok := ExtractGitHubRepo(url)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tinfo, err := gc.CheckRepo(ctx, owner, name)\n\t\tif err != nil {\n\t\t\terrs = append(errs, err)\n\t\t\tif isGitHubAuthError(err) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tresults = append(results, info)\n\n\t\tif (i+1)%batchSize == 0 {\n\t\t\ttime.Sleep(1 * time.Second)\n\t\t}\n\t}\n\n\treturn results, errs\n}\n"
  },
  {
    "path": "internal/checker/github_test.go",
    "content": "package checker\n\nimport (\n\t\"errors\"\n\t\"testing\"\n)\n\nfunc TestExtractGitHubRepo(t *testing.T) {\n\ttests := []struct {\n\t\turl   string\n\t\towner string\n\t\tname  string\n\t\tok    bool\n\t}{\n\t\t{\"https://github.com/docker/compose\", \"docker\", \"compose\", true},\n\t\t{\"https://github.com/moby/moby\", \"moby\", \"moby\", true},\n\t\t{\"https://github.com/user/repo/\", \"user\", \"repo\", true},\n\t\t{\"https://github.com/user/repo?tab=readme-ov-file\", \"user\", \"repo\", true},\n\t\t{\"https://github.com/user/repo#readme\", \"user\", \"repo\", true},\n\t\t{\"https://github.com/user/repo.git\", \"user\", \"repo\", true},\n\t\t{\"https://www.github.com/user/repo\", \"user\", \"repo\", true},\n\t\t{\"https://github.com/user/repo/issues\", \"\", \"\", false},\n\t\t{\"https://github.com/user/repo/wiki\", \"\", \"\", false},\n\t\t{\"https://github.com/apps/dependabot\", \"\", \"\", false},\n\t\t{\"https://example.com/not-github\", \"\", \"\", false},\n\t\t{\"https://github.com/user\", \"\", \"\", false},\n\t}\n\n\tfor _, tt := range tests {\n\t\towner, name, ok := ExtractGitHubRepo(tt.url)\n\t\tif ok != tt.ok {\n\t\t\tt.Errorf(\"ExtractGitHubRepo(%q): ok = %v, want %v\", tt.url, ok, tt.ok)\n\t\t\tcontinue\n\t\t}\n\t\tif ok {\n\t\t\tif owner != tt.owner || name != tt.name {\n\t\t\t\tt.Errorf(\"ExtractGitHubRepo(%q) = (%q, %q), want (%q, %q)\", tt.url, owner, name, tt.owner, tt.name)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestPartitionLinks(t *testing.T) {\n\turls := []string{\n\t\t\"https://github.com/docker/compose\",\n\t\t\"https://example.com/tool\",\n\t\t\"https://github.com/moby/moby\",\n\t\t\"https://github.com/user/repo/issues\",\n\t\t\"dozzle\",\n\t\t\"#projects\",\n\t}\n\tgh, ext := PartitionLinks(urls)\n\tif len(gh) != 2 {\n\t\tt.Errorf(\"github links = %d, want 2\", len(gh))\n\t}\n\tif len(ext) != 2 {\n\t\tt.Errorf(\"external links = %d, want 2\", len(ext))\n\t}\n}\n\nfunc TestIsGitHubAuthError(t *testing.T) {\n\ttests := []struct {\n\t\terr  error\n\t\twant bool\n\t}{\n\t\t{errors.New(\"non-200 OK status code: 401 Unauthorized body: \\\"Bad credentials\\\"\"), true},\n\t\t{errors.New(\"Resource not accessible by integration\"), true},\n\t\t{errors.New(\"dial tcp: lookup api.github.com: no such host\"), false},\n\t\t{errors.New(\"context deadline exceeded\"), false},\n\t}\n\n\tfor _, tt := range tests {\n\t\tgot := isGitHubAuthError(tt.err)\n\t\tif got != tt.want {\n\t\t\tt.Errorf(\"isGitHubAuthError(%q) = %v, want %v\", tt.err, got, tt.want)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/checker/http.go",
    "content": "package checker\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n)\n\nconst (\n\tdefaultTimeout     = 30 * time.Second\n\tdefaultConcurrency = 10\n\tuserAgent          = \"awesome-docker-checker/1.0\"\n)\n\n// LinkResult holds the result of checking a single URL.\ntype LinkResult struct {\n\tURL         string\n\tOK          bool\n\tStatusCode  int\n\tRedirected  bool\n\tRedirectURL string\n\tError       string\n}\n\nfunc shouldFallbackToGET(statusCode int) bool {\n\tswitch statusCode {\n\tcase http.StatusBadRequest, http.StatusForbidden, http.StatusMethodNotAllowed, http.StatusNotImplemented:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// CheckLink checks a single URL. Uses HEAD first, falls back to GET.\nfunc CheckLink(url string, client *http.Client) LinkResult {\n\tresult := LinkResult{URL: url}\n\n\tctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)\n\tdefer cancel()\n\n\t// Track redirects\n\tvar finalURL string\n\torigCheckRedirect := client.CheckRedirect\n\tclient.CheckRedirect = func(req *http.Request, via []*http.Request) error {\n\t\tfinalURL = req.URL.String()\n\t\tif len(via) >= 10 {\n\t\t\treturn http.ErrUseLastResponse\n\t\t}\n\t\treturn nil\n\t}\n\tdefer func() { client.CheckRedirect = origCheckRedirect }()\n\n\tdoRequest := func(method string) (*http.Response, error) {\n\t\treq, err := http.NewRequestWithContext(ctx, method, url, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treq.Header.Set(\"User-Agent\", userAgent)\n\t\treturn client.Do(req)\n\t}\n\n\tresp, err := doRequest(http.MethodHead)\n\tif err != nil {\n\t\tresp, err = doRequest(http.MethodGet)\n\t\tif err != nil {\n\t\t\tresult.Error = err.Error()\n\t\t\treturn result\n\t\t}\n\t} else if shouldFallbackToGET(resp.StatusCode) {\n\t\tresp.Body.Close()\n\t\tresp, err = doRequest(http.MethodGet)\n\t\tif err != nil {\n\t\t\tresult.Error = err.Error()\n\t\t\treturn result\n\t\t}\n\t}\n\tdefer resp.Body.Close()\n\n\tresult.StatusCode = resp.StatusCode\n\tresult.OK = resp.StatusCode >= 200 && resp.StatusCode < 400\n\n\tif finalURL != \"\" && finalURL != url {\n\t\tresult.Redirected = true\n\t\tresult.RedirectURL = finalURL\n\t}\n\n\treturn result\n}\n\n// CheckLinks checks multiple URLs concurrently.\nfunc CheckLinks(urls []string, concurrency int, exclude *cache.ExcludeList) []LinkResult {\n\tif concurrency <= 0 {\n\t\tconcurrency = defaultConcurrency\n\t}\n\n\tresults := make([]LinkResult, len(urls))\n\tsem := make(chan struct{}, concurrency)\n\tvar wg sync.WaitGroup\n\n\tfor i, url := range urls {\n\t\tif exclude != nil && exclude.IsExcluded(url) {\n\t\t\tresults[i] = LinkResult{URL: url, OK: true}\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(idx int, u string) {\n\t\t\tdefer wg.Done()\n\t\t\tsem <- struct{}{}\n\t\t\tdefer func() { <-sem }()\n\t\t\tclient := &http.Client{Timeout: defaultTimeout}\n\t\t\tresults[idx] = CheckLink(u, client)\n\t\t}(i, url)\n\t}\n\n\twg.Wait()\n\treturn results\n}\n"
  },
  {
    "path": "internal/checker/http_test.go",
    "content": "package checker\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n)\n\nfunc TestCheckLinkOK(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer server.Close()\n\n\tresult := CheckLink(server.URL, &http.Client{})\n\tif !result.OK {\n\t\tt.Errorf(\"expected OK, got status %d, error: %s\", result.StatusCode, result.Error)\n\t}\n}\n\nfunc TestCheckLink404(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t}))\n\tdefer server.Close()\n\n\tresult := CheckLink(server.URL, &http.Client{})\n\tif result.OK {\n\t\tt.Error(\"expected not OK for 404\")\n\t}\n\tif result.StatusCode != 404 {\n\t\tt.Errorf(\"status = %d, want 404\", result.StatusCode)\n\t}\n}\n\nfunc TestCheckLinkRedirect(t *testing.T) {\n\tfinal := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer final.Close()\n\n\tredir := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, final.URL, http.StatusMovedPermanently)\n\t}))\n\tdefer redir.Close()\n\n\tresult := CheckLink(redir.URL, &http.Client{})\n\tif !result.OK {\n\t\tt.Errorf(\"expected OK after following redirect, error: %s\", result.Error)\n\t}\n\tif !result.Redirected {\n\t\tt.Error(\"expected Redirected = true\")\n\t}\n}\n\nfunc TestCheckLinks(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/bad\" {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer server.Close()\n\n\turls := []string{server.URL + \"/good\", server.URL + \"/bad\", server.URL + \"/also-good\"}\n\tresults := CheckLinks(urls, 2, nil)\n\tif len(results) != 3 {\n\t\tt.Fatalf(\"results = %d, want 3\", len(results))\n\t}\n\n\tfor _, r := range results {\n\t\tif r.URL == server.URL+\"/bad\" && r.OK {\n\t\t\tt.Error(\"expected /bad to not be OK\")\n\t\t}\n\t\tif r.URL == server.URL+\"/good\" && !r.OK {\n\t\t\tt.Error(\"expected /good to be OK\")\n\t\t}\n\t}\n}\n\nfunc TestCheckLinkFallbackToGETOnMethodNotAllowed(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method == http.MethodHead {\n\t\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer server.Close()\n\n\tresult := CheckLink(server.URL, &http.Client{})\n\tif !result.OK {\n\t\tt.Errorf(\"expected OK after GET fallback, got status %d, error: %s\", result.StatusCode, result.Error)\n\t}\n\tif result.StatusCode != http.StatusOK {\n\t\tt.Errorf(\"status = %d, want 200\", result.StatusCode)\n\t}\n}\n\nfunc TestCheckLinkFallbackToGETOnForbiddenHead(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method == http.MethodHead {\n\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer server.Close()\n\n\tresult := CheckLink(server.URL, &http.Client{})\n\tif !result.OK {\n\t\tt.Errorf(\"expected OK after GET fallback, got status %d, error: %s\", result.StatusCode, result.Error)\n\t}\n\tif result.StatusCode != http.StatusOK {\n\t\tt.Errorf(\"status = %d, want 200\", result.StatusCode)\n\t}\n}\n"
  },
  {
    "path": "internal/linter/fixer.go",
    "content": "package linter\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/parser\"\n)\n\n// attributionRe matches trailing author attributions like:\n//\n//\tby [@author](url), by [@author][ref], by @author\n//\n// Also handles \"Created by\", \"Maintained by\" etc.\nvar attributionRe = regexp.MustCompile(`\\s+(?:(?:[Cc]reated|[Mm]aintained|[Bb]uilt)\\s+)?by\\s+\\[@[^\\]]+\\](?:\\([^)]*\\)|\\[[^\\]]*\\])\\.?$`)\n\n// bareAttributionRe matches: by @author at end of line (no link).\nvar bareAttributionRe = regexp.MustCompile(`\\s+by\\s+@\\w+\\.?$`)\n\n// sectionHeadingRe matches markdown headings.\nvar sectionHeadingRe = regexp.MustCompile(`^(#{1,6})\\s+(.+?)(?:\\s*<!--.*-->)?$`)\n\n// RemoveAttribution strips author attribution from a description string.\nfunc RemoveAttribution(desc string) string {\n\tdesc = attributionRe.ReplaceAllString(desc, \"\")\n\tdesc = bareAttributionRe.ReplaceAllString(desc, \"\")\n\treturn strings.TrimSpace(desc)\n}\n\n// FormatEntry reconstructs a markdown list line from a parsed Entry.\nfunc FormatEntry(e parser.Entry) string {\n\tdesc := e.Description\n\tvar markers []string\n\tfor _, m := range e.Markers {\n\t\tswitch m {\n\t\tcase parser.MarkerAbandoned:\n\t\t\tmarkers = append(markers, \":skull:\")\n\t\tcase parser.MarkerPaid:\n\t\t\tmarkers = append(markers, \":yen:\")\n\t\tcase parser.MarkerWIP:\n\t\t\tmarkers = append(markers, \":construction:\")\n\t\tcase parser.MarkerStale:\n\t\t\tmarkers = append(markers, \":ice_cube:\")\n\t\t}\n\t}\n\tif len(markers) > 0 {\n\t\tdesc = strings.Join(markers, \" \") + \" \" + desc\n\t}\n\treturn fmt.Sprintf(\"- [%s](%s) - %s\", e.Name, e.URL, desc)\n}\n\n// FixFile reads the README, fixes entries (capitalize, period, remove attribution,\n// sort), and writes the result back.\nfunc FixFile(path string) (int, error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer f.Close()\n\n\tvar lines []string\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tlines = append(lines, scanner.Text())\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\treturn 0, err\n\t}\n\n\tfixCount := 0\n\n\tvar headingLines []int\n\tfor i, line := range lines {\n\t\tif sectionHeadingRe.MatchString(line) {\n\t\t\theadingLines = append(headingLines, i)\n\t\t}\n\t}\n\n\t// Process each heading block independently to match linter sort scope.\n\tfor i, headingIdx := range headingLines {\n\t\tstart := headingIdx + 1\n\t\tend := len(lines)\n\t\tif i+1 < len(headingLines) {\n\t\t\tend = headingLines[i+1]\n\t\t}\n\n\t\tvar entryPositions []int\n\t\tvar entries []parser.Entry\n\t\tfor lineIdx := start; lineIdx < end; lineIdx++ {\n\t\t\tentry, err := parser.ParseEntry(lines[lineIdx], lineIdx+1)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tentryPositions = append(entryPositions, lineIdx)\n\t\t\tentries = append(entries, entry)\n\t\t}\n\t\tif len(entries) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar fixed []parser.Entry\n\t\tfor _, e := range entries {\n\t\t\tf := FixEntry(e)\n\t\t\tf.Description = RemoveAttribution(f.Description)\n\t\t\t// Re-apply period after removing attribution (it may have been stripped)\n\t\t\tif len(f.Description) > 0 && !strings.HasSuffix(f.Description, \".\") {\n\t\t\t\tf.Description += \".\"\n\t\t\t}\n\t\t\tfixed = append(fixed, f)\n\t\t}\n\n\t\tsorted := SortEntries(fixed)\n\t\tfor j, e := range sorted {\n\t\t\tnewLine := FormatEntry(e)\n\t\t\tlineIdx := entryPositions[j]\n\t\t\tif lines[lineIdx] != newLine {\n\t\t\t\tfixCount++\n\t\t\t\tlines[lineIdx] = newLine\n\t\t\t}\n\t\t}\n\t}\n\n\tif fixCount == 0 {\n\t\treturn 0, nil\n\t}\n\n\t// Write back\n\tout, err := os.Create(path)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer out.Close()\n\n\tw := bufio.NewWriter(out)\n\tfor i, line := range lines {\n\t\tw.WriteString(line)\n\t\tif i < len(lines)-1 {\n\t\t\tw.WriteString(\"\\n\")\n\t\t}\n\t}\n\t// Preserve trailing newline if original had one\n\tw.WriteString(\"\\n\")\n\treturn fixCount, w.Flush()\n}\n"
  },
  {
    "path": "internal/linter/fixer_test.go",
    "content": "package linter\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/parser\"\n)\n\nfunc TestRemoveAttribution(t *testing.T) {\n\ttests := []struct {\n\t\tinput string\n\t\twant  string\n\t}{\n\t\t{\n\t\t\t\"Tool for managing containers by [@author](https://github.com/author)\",\n\t\t\t\"Tool for managing containers\",\n\t\t},\n\t\t{\n\t\t\t\"Tool for managing containers by [@author][author]\",\n\t\t\t\"Tool for managing containers\",\n\t\t},\n\t\t{\n\t\t\t\"Tool for managing containers by @author\",\n\t\t\t\"Tool for managing containers\",\n\t\t},\n\t\t{\n\t\t\t\"Analyzes resource usage. Created by [@Google][google]\",\n\t\t\t\"Analyzes resource usage.\",\n\t\t},\n\t\t{\n\t\t\t\"A tool by [@someone](https://example.com).\",\n\t\t\t\"A tool\",\n\t\t},\n\t\t{\n\t\t\t\"step-by-step tutorial and more resources\",\n\t\t\t\"step-by-step tutorial and more resources\",\n\t\t},\n\t\t{\n\t\t\t\"No attribution here\",\n\t\t\t\"No attribution here\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tgot := RemoveAttribution(tt.input)\n\t\tif got != tt.want {\n\t\t\tt.Errorf(\"RemoveAttribution(%q) = %q, want %q\", tt.input, got, tt.want)\n\t\t}\n\t}\n}\n\nfunc TestFormatEntry(t *testing.T) {\n\te := parser.Entry{\n\t\tName:        \"Portainer\",\n\t\tURL:         \"https://github.com/portainer/portainer\",\n\t\tDescription: \"Management UI for Docker.\",\n\t}\n\tgot := FormatEntry(e)\n\twant := \"- [Portainer](https://github.com/portainer/portainer) - Management UI for Docker.\"\n\tif got != want {\n\t\tt.Errorf(\"FormatEntry = %q, want %q\", got, want)\n\t}\n}\n\nfunc TestFormatEntryWithMarkers(t *testing.T) {\n\te := parser.Entry{\n\t\tName:        \"OldTool\",\n\t\tURL:         \"https://github.com/old/tool\",\n\t\tDescription: \"A deprecated tool.\",\n\t\tMarkers:     []parser.Marker{parser.MarkerAbandoned},\n\t}\n\tgot := FormatEntry(e)\n\twant := \"- [OldTool](https://github.com/old/tool) - :skull: A deprecated tool.\"\n\tif got != want {\n\t\tt.Errorf(\"FormatEntry = %q, want %q\", got, want)\n\t}\n}\n\nfunc TestFixFile(t *testing.T) {\n\tcontent := `# Awesome Docker\n\n## Tools\n\n- [Zebra](https://example.com/zebra) - a tool by [@author](https://github.com/author)\n- [Alpha](https://example.com/alpha) - another tool\n\n## Other\n\nSome text here.\n`\n\ttmp, err := os.CreateTemp(\"\", \"readme-*.md\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer os.Remove(tmp.Name())\n\n\tif _, err := tmp.WriteString(content); err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttmp.Close()\n\n\tcount, err := FixFile(tmp.Name())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif count == 0 {\n\t\tt.Fatal(\"expected fixes, got 0\")\n\t}\n\n\tdata, err := os.ReadFile(tmp.Name())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tresult := string(data)\n\n\t// Check sorting: Alpha should come before Zebra\n\talphaIdx := strings.Index(result, \"[Alpha]\")\n\tzebraIdx := strings.Index(result, \"[Zebra]\")\n\tif alphaIdx > zebraIdx {\n\t\tt.Error(\"expected Alpha before Zebra after sort\")\n\t}\n\n\t// Check capitalization\n\tif !strings.Contains(result, \"- A tool.\") {\n\t\tt.Errorf(\"expected capitalized description, got:\\n%s\", result)\n\t}\n\n\t// Check attribution removed\n\tif strings.Contains(result, \"@author\") {\n\t\tt.Errorf(\"expected attribution removed, got:\\n%s\", result)\n\t}\n\n\t// Check period added\n\tif !strings.Contains(result, \"Another tool.\") {\n\t\tt.Errorf(\"expected period added, got:\\n%s\", result)\n\t}\n}\n\nfunc TestFixFileSortsAcrossBlankLinesAndIsIdempotent(t *testing.T) {\n\tcontent := `# Awesome Docker\n\n## Tools\n\n- [Zulu](https://example.com/zulu) - z tool\n\n- [Alpha](https://example.com/alpha) - a tool\n`\n\n\ttmp, err := os.CreateTemp(\"\", \"readme-*.md\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer os.Remove(tmp.Name())\n\n\tif _, err := tmp.WriteString(content); err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttmp.Close()\n\n\tfirstCount, err := FixFile(tmp.Name())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif firstCount == 0 {\n\t\tt.Fatal(\"expected first run to apply fixes\")\n\t}\n\n\tfirstData, err := os.ReadFile(tmp.Name())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfirstResult := string(firstData)\n\n\talphaIdx := strings.Index(firstResult, \"[Alpha]\")\n\tzuluIdx := strings.Index(firstResult, \"[Zulu]\")\n\tif alphaIdx == -1 || zuluIdx == -1 {\n\t\tt.Fatalf(\"expected both Alpha and Zulu in result:\\n%s\", firstResult)\n\t}\n\tif alphaIdx > zuluIdx {\n\t\tt.Fatalf(\"expected Alpha before Zulu after fix:\\n%s\", firstResult)\n\t}\n\n\tsecondCount, err := FixFile(tmp.Name())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif secondCount != 0 {\n\t\tt.Fatalf(\"expected second run to be idempotent, got %d changes\", secondCount)\n\t}\n}\n"
  },
  {
    "path": "internal/linter/linter.go",
    "content": "package linter\n\nimport (\n\t\"github.com/veggiemonk/awesome-docker/internal/parser\"\n)\n\n// Result holds all lint issues found.\ntype Result struct {\n\tIssues   []Issue\n\tErrors   int\n\tWarnings int\n}\n\n// Lint checks an entire parsed document for issues.\nfunc Lint(doc parser.Document) Result {\n\tvar result Result\n\n\t// Collect all entries for duplicate checking\n\tallEntries := collectEntries(doc.Sections)\n\tfor _, issue := range CheckDuplicates(allEntries) {\n\t\taddIssue(&result, issue)\n\t}\n\n\t// Check each section\n\tlintSections(doc.Sections, &result)\n\n\treturn result\n}\n\nfunc lintSections(sections []parser.Section, result *Result) {\n\tfor _, s := range sections {\n\t\tfor _, e := range s.Entries {\n\t\t\tfor _, issue := range CheckEntry(e) {\n\t\t\t\taddIssue(result, issue)\n\t\t\t}\n\t\t}\n\t\tfor _, issue := range CheckSorted(s.Entries) {\n\t\t\taddIssue(result, issue)\n\t\t}\n\t\tlintSections(s.Children, result)\n\t}\n}\n\nfunc collectEntries(sections []parser.Section) []parser.Entry {\n\tvar all []parser.Entry\n\tfor _, s := range sections {\n\t\tall = append(all, s.Entries...)\n\t\tall = append(all, collectEntries(s.Children)...)\n\t}\n\treturn all\n}\n\nfunc addIssue(result *Result, issue Issue) {\n\tresult.Issues = append(result.Issues, issue)\n\tif issue.Severity == SeverityError {\n\t\tresult.Errors++\n\t} else {\n\t\tresult.Warnings++\n\t}\n}\n"
  },
  {
    "path": "internal/linter/linter_test.go",
    "content": "package linter\n\nimport (\n\t\"testing\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/parser\"\n)\n\nfunc TestRuleDescriptionCapital(t *testing.T) {\n\tentry := parser.Entry{Name: \"Test\", URL: \"https://example.com\", Description: \"lowercase start.\", Line: 10}\n\tissues := CheckEntry(entry)\n\tfound := false\n\tfor _, issue := range issues {\n\t\tif issue.Rule == RuleDescriptionCapital {\n\t\t\tfound = true\n\t\t}\n\t}\n\tif !found {\n\t\tt.Error(\"expected RuleDescriptionCapital issue for lowercase description\")\n\t}\n}\n\nfunc TestRuleDescriptionPeriod(t *testing.T) {\n\tentry := parser.Entry{Name: \"Test\", URL: \"https://example.com\", Description: \"No period at end\", Line: 10}\n\tissues := CheckEntry(entry)\n\tfound := false\n\tfor _, issue := range issues {\n\t\tif issue.Rule == RuleDescriptionPeriod {\n\t\t\tfound = true\n\t\t}\n\t}\n\tif !found {\n\t\tt.Error(\"expected RuleDescriptionPeriod issue\")\n\t}\n}\n\nfunc TestRuleSorted(t *testing.T) {\n\tentries := []parser.Entry{\n\t\t{Name: \"Zebra\", URL: \"https://z.com\", Description: \"Z.\", Line: 1},\n\t\t{Name: \"Alpha\", URL: \"https://a.com\", Description: \"A.\", Line: 2},\n\t}\n\tissues := CheckSorted(entries)\n\tif len(issues) == 0 {\n\t\tt.Error(\"expected sorting issue\")\n\t}\n}\n\nfunc TestRuleSortedOK(t *testing.T) {\n\tentries := []parser.Entry{\n\t\t{Name: \"Alpha\", URL: \"https://a.com\", Description: \"A.\", Line: 1},\n\t\t{Name: \"Zebra\", URL: \"https://z.com\", Description: \"Z.\", Line: 2},\n\t}\n\tissues := CheckSorted(entries)\n\tif len(issues) != 0 {\n\t\tt.Errorf(\"expected no sorting issues, got %d\", len(issues))\n\t}\n}\n\nfunc TestRuleDuplicateURL(t *testing.T) {\n\tentries := []parser.Entry{\n\t\t{Name: \"A\", URL: \"https://example.com/a\", Description: \"A.\", Line: 1},\n\t\t{Name: \"B\", URL: \"https://example.com/a\", Description: \"B.\", Line: 5},\n\t}\n\tissues := CheckDuplicates(entries)\n\tif len(issues) == 0 {\n\t\tt.Error(\"expected duplicate URL issue\")\n\t}\n}\n\nfunc TestValidEntry(t *testing.T) {\n\tentry := parser.Entry{Name: \"Good\", URL: \"https://example.com\", Description: \"A good project.\", Line: 10}\n\tissues := CheckEntry(entry)\n\tif len(issues) != 0 {\n\t\tt.Errorf(\"expected no issues, got %v\", issues)\n\t}\n}\n\nfunc TestFixDescriptionCapital(t *testing.T) {\n\tentry := parser.Entry{Name: \"Test\", URL: \"https://example.com\", Description: \"lowercase.\", Line: 10}\n\tfixed := FixEntry(entry)\n\tif fixed.Description != \"Lowercase.\" {\n\t\tt.Errorf(\"description = %q, want %q\", fixed.Description, \"Lowercase.\")\n\t}\n}\n\nfunc TestFixDescriptionPeriod(t *testing.T) {\n\tentry := parser.Entry{Name: \"Test\", URL: \"https://example.com\", Description: \"No period\", Line: 10}\n\tfixed := FixEntry(entry)\n\tif fixed.Description != \"No period.\" {\n\t\tt.Errorf(\"description = %q, want %q\", fixed.Description, \"No period.\")\n\t}\n}\n\nfunc TestLintDocument(t *testing.T) {\n\tdoc := parser.Document{\n\t\tSections: []parser.Section{\n\t\t\t{\n\t\t\t\tTitle: \"Tools\",\n\t\t\t\tLevel: 2,\n\t\t\t\tEntries: []parser.Entry{\n\t\t\t\t\t{Name: \"Zebra\", URL: \"https://z.com\", Description: \"Z tool.\", Line: 1},\n\t\t\t\t\t{Name: \"Alpha\", URL: \"https://a.com\", Description: \"a tool\", Line: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tresult := Lint(doc)\n\tif result.Errors == 0 {\n\t\tt.Error(\"expected errors (unsorted, lowercase, no period)\")\n\t}\n}\n"
  },
  {
    "path": "internal/linter/rules.go",
    "content": "package linter\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/parser\"\n)\n\n// Rule identifies a linting rule.\ntype Rule string\n\nconst (\n\tRuleDescriptionCapital Rule = \"description-capital\"\n\tRuleDescriptionPeriod  Rule = \"description-period\"\n\tRuleSorted             Rule = \"sorted\"\n\tRuleDuplicateURL       Rule = \"duplicate-url\"\n)\n\n// Severity of a lint issue.\ntype Severity int\n\nconst (\n\tSeverityError Severity = iota\n\tSeverityWarning\n)\n\n// Issue is a single lint problem found.\ntype Issue struct {\n\tRule     Rule\n\tSeverity Severity\n\tLine     int\n\tMessage  string\n}\n\nfunc (i Issue) String() string {\n\tsev := \"ERROR\"\n\tif i.Severity == SeverityWarning {\n\t\tsev = \"WARN\"\n\t}\n\treturn fmt.Sprintf(\"[%s] line %d: %s (%s)\", sev, i.Line, i.Message, i.Rule)\n}\n\n// CheckEntry validates a single entry against formatting rules.\nfunc CheckEntry(e parser.Entry) []Issue {\n\tvar issues []Issue\n\n\tif first, ok := firstLetter(e.Description); ok && !unicode.IsUpper(first) {\n\t\tissues = append(issues, Issue{\n\t\t\tRule:     RuleDescriptionCapital,\n\t\t\tSeverity: SeverityError,\n\t\t\tLine:     e.Line,\n\t\t\tMessage:  fmt.Sprintf(\"%q: description should start with a capital letter\", e.Name),\n\t\t})\n\t}\n\n\tif len(e.Description) > 0 && !strings.HasSuffix(e.Description, \".\") {\n\t\tissues = append(issues, Issue{\n\t\t\tRule:     RuleDescriptionPeriod,\n\t\t\tSeverity: SeverityError,\n\t\t\tLine:     e.Line,\n\t\t\tMessage:  fmt.Sprintf(\"%q: description should end with a period\", e.Name),\n\t\t})\n\t}\n\n\treturn issues\n}\n\n// CheckSorted verifies entries are in alphabetical order (case-insensitive).\nfunc CheckSorted(entries []parser.Entry) []Issue {\n\tvar issues []Issue\n\tfor i := 1; i < len(entries); i++ {\n\t\tprev := strings.ToLower(entries[i-1].Name)\n\t\tcurr := strings.ToLower(entries[i].Name)\n\t\tif prev > curr {\n\t\t\tissues = append(issues, Issue{\n\t\t\t\tRule:     RuleSorted,\n\t\t\t\tSeverity: SeverityError,\n\t\t\t\tLine:     entries[i].Line,\n\t\t\t\tMessage:  fmt.Sprintf(\"%q should come before %q (alphabetical order)\", entries[i].Name, entries[i-1].Name),\n\t\t\t})\n\t\t}\n\t}\n\treturn issues\n}\n\n// CheckDuplicates finds entries with the same URL across the entire document.\nfunc CheckDuplicates(entries []parser.Entry) []Issue {\n\tvar issues []Issue\n\tseen := make(map[string]int) // URL -> first line number\n\tfor _, e := range entries {\n\t\turl := strings.TrimRight(e.URL, \"/\")\n\t\tif firstLine, exists := seen[url]; exists {\n\t\t\tissues = append(issues, Issue{\n\t\t\t\tRule:     RuleDuplicateURL,\n\t\t\t\tSeverity: SeverityError,\n\t\t\t\tLine:     e.Line,\n\t\t\t\tMessage:  fmt.Sprintf(\"duplicate URL %q (first seen at line %d)\", e.URL, firstLine),\n\t\t\t})\n\t\t} else {\n\t\t\tseen[url] = e.Line\n\t\t}\n\t}\n\treturn issues\n}\n\n// firstLetter returns the first unicode letter in s and true, or zero and false if none.\nfunc firstLetter(s string) (rune, bool) {\n\tfor _, r := range s {\n\t\tif unicode.IsLetter(r) {\n\t\t\treturn r, true\n\t\t}\n\t}\n\treturn 0, false\n}\n\n// FixEntry returns a copy of the entry with auto-fixable issues corrected.\nfunc FixEntry(e parser.Entry) parser.Entry {\n\tfixed := e\n\tif len(fixed.Description) > 0 {\n\t\t// Capitalize first letter (find it, may not be at index 0)\n\t\trunes := []rune(fixed.Description)\n\t\tfor i, r := range runes {\n\t\t\tif unicode.IsLetter(r) {\n\t\t\t\trunes[i] = unicode.ToUpper(r)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfixed.Description = string(runes)\n\n\t\t// Ensure period at end\n\t\tif !strings.HasSuffix(fixed.Description, \".\") {\n\t\t\tfixed.Description += \".\"\n\t\t}\n\t}\n\treturn fixed\n}\n\n// SortEntries returns a sorted copy of entries (case-insensitive by Name).\nfunc SortEntries(entries []parser.Entry) []parser.Entry {\n\tsorted := make([]parser.Entry, len(entries))\n\tcopy(sorted, entries)\n\tsort.Slice(sorted, func(i, j int) bool {\n\t\treturn strings.ToLower(sorted[i].Name) < strings.ToLower(sorted[j].Name)\n\t})\n\treturn sorted\n}\n"
  },
  {
    "path": "internal/parser/parser.go",
    "content": "package parser\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// entryRe matches: - [Name](URL) - Description\n// Also handles optional markers/text between URL and \" - \" separator, e.g.:\n//\n//   - [Name](URL) :skull: - Description\n//   - [Name](URL) (2) :skull: - Description\nvar entryRe = regexp.MustCompile(`^[-*]\\s+\\[([^\\]]+)\\]\\(([^)]+)\\)(.*?)\\s+-\\s+(.+)$`)\n\n// headingRe matches markdown headings: # Title, ## Title, etc.\nvar headingRe = regexp.MustCompile(`^(#{1,6})\\s+(.+?)(?:\\s*<!--.*-->)?$`)\n\nvar markerDefs = []struct {\n\ttext   string\n\tmarker Marker\n}{\n\t{text: \":skull:\", marker: MarkerAbandoned},\n\t{text: \":yen:\", marker: MarkerPaid},\n\t{text: \":construction:\", marker: MarkerWIP},\n\t{text: \":ice_cube:\", marker: MarkerStale},\n}\n\n// ParseEntry parses a single markdown list line into an Entry.\nfunc ParseEntry(line string, lineNum int) (Entry, error) {\n\tm := entryRe.FindStringSubmatch(strings.TrimSpace(line))\n\tif m == nil {\n\t\treturn Entry{}, fmt.Errorf(\"line %d: not a valid entry: %q\", lineNum, line)\n\t}\n\n\tmiddle := m[3] // text between URL closing paren and \" - \"\n\tdesc := m[4]\n\tvar markers []Marker\n\n\t// Extract markers from both the middle section and the description\n\tfor _, def := range markerDefs {\n\t\tif strings.Contains(middle, def.text) || strings.Contains(desc, def.text) {\n\t\t\tmarkers = append(markers, def.marker)\n\t\t\tmiddle = strings.ReplaceAll(middle, def.text, \"\")\n\t\t\tdesc = strings.ReplaceAll(desc, def.text, \"\")\n\t\t}\n\t}\n\tdesc = strings.TrimSpace(desc)\n\n\treturn Entry{\n\t\tName:        m[1],\n\t\tURL:         m[2],\n\t\tDescription: desc,\n\t\tMarkers:     markers,\n\t\tLine:        lineNum,\n\t\tRaw:         line,\n\t}, nil\n}\n\n// Parse reads a full README and returns a Document.\nfunc Parse(r io.Reader) (Document, error) {\n\tscanner := bufio.NewScanner(r)\n\tvar doc Document\n\tvar allSections []struct {\n\t\tsection Section\n\t\tlevel   int\n\t}\n\n\tlineNum := 0\n\tfor scanner.Scan() {\n\t\tlineNum++\n\t\tline := scanner.Text()\n\n\t\t// Check for heading\n\t\tif hm := headingRe.FindStringSubmatch(line); hm != nil {\n\t\t\tlevel := len(hm[1])\n\t\t\ttitle := strings.TrimSpace(hm[2])\n\t\t\tallSections = append(allSections, struct {\n\t\t\t\tsection Section\n\t\t\t\tlevel   int\n\t\t\t}{\n\t\t\t\tsection: Section{Title: title, Level: level, Line: lineNum},\n\t\t\t\tlevel:   level,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check for entry (list item with link)\n\t\tif entry, err := ParseEntry(line, lineNum); err == nil {\n\t\t\tif len(allSections) > 0 {\n\t\t\t\tallSections[len(allSections)-1].section.Entries = append(\n\t\t\t\t\tallSections[len(allSections)-1].section.Entries, entry)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Everything else: preamble if no sections yet\n\t\tif len(allSections) == 0 {\n\t\t\tdoc.Preamble = append(doc.Preamble, line)\n\t\t}\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn doc, err\n\t}\n\n\t// Build section tree by nesting based on heading level\n\tdoc.Sections = buildTree(allSections)\n\treturn doc, nil\n}\n\nfunc buildTree(flat []struct {\n\tsection Section\n\tlevel   int\n},\n) []Section {\n\tif len(flat) == 0 {\n\t\treturn nil\n\t}\n\n\tvar result []Section\n\tfor i := 0; i < len(flat); i++ {\n\t\tcurrent := flat[i].section\n\t\tcurrentLevel := flat[i].level\n\n\t\t// Collect children: everything after this heading at a deeper level\n\t\tj := i + 1\n\t\tfor j < len(flat) && flat[j].level > currentLevel {\n\t\t\tj++\n\t\t}\n\t\tif j > i+1 {\n\t\t\tcurrent.Children = buildTree(flat[i+1 : j])\n\t\t}\n\t\tresult = append(result, current)\n\t\ti = j - 1\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "internal/parser/parser_test.go",
    "content": "package parser\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestParseEntry(t *testing.T) {\n\tline := `- [Docker Desktop](https://www.docker.com/products/docker-desktop/) - Official native app. Only for Windows and MacOS.`\n\tentry, err := ParseEntry(line, 1)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t}\n\tif entry.Name != \"Docker Desktop\" {\n\t\tt.Errorf(\"name = %q, want %q\", entry.Name, \"Docker Desktop\")\n\t}\n\tif entry.URL != \"https://www.docker.com/products/docker-desktop/\" {\n\t\tt.Errorf(\"url = %q, want %q\", entry.URL, \"https://www.docker.com/products/docker-desktop/\")\n\t}\n\tif entry.Description != \"Official native app. Only for Windows and MacOS.\" {\n\t\tt.Errorf(\"description = %q, want %q\", entry.Description, \"Official native app. Only for Windows and MacOS.\")\n\t}\n\tif len(entry.Markers) != 0 {\n\t\tt.Errorf(\"markers = %v, want empty\", entry.Markers)\n\t}\n}\n\nfunc TestParseEntryWithMarkers(t *testing.T) {\n\tline := `- [Docker Swarm](https://github.com/docker/swarm) - Swarm clustering system. :skull:`\n\tentry, err := ParseEntry(line, 1)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t}\n\tif entry.Name != \"Docker Swarm\" {\n\t\tt.Errorf(\"name = %q, want %q\", entry.Name, \"Docker Swarm\")\n\t}\n\tif len(entry.Markers) != 1 || entry.Markers[0] != MarkerAbandoned {\n\t\tt.Errorf(\"markers = %v, want [MarkerAbandoned]\", entry.Markers)\n\t}\n\tif strings.Contains(entry.Description, \":skull:\") {\n\t\tt.Errorf(\"description should not contain marker text, got %q\", entry.Description)\n\t}\n}\n\nfunc TestParseEntryMultipleMarkers(t *testing.T) {\n\tline := `- [SomeProject](https://example.com) - A project. :yen: :construction:`\n\tentry, err := ParseEntry(line, 1)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t}\n\tif len(entry.Markers) != 2 {\n\t\tt.Fatalf(\"markers count = %d, want 2\", len(entry.Markers))\n\t}\n}\n\nfunc TestParseEntryMarkersCanonicalOrder(t *testing.T) {\n\tline := `- [SomeProject](https://example.com) - :construction: A project. :skull:`\n\tentry, err := ParseEntry(line, 1)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t}\n\tif len(entry.Markers) != 2 {\n\t\tt.Fatalf(\"markers count = %d, want 2\", len(entry.Markers))\n\t}\n\tif entry.Markers[0] != MarkerAbandoned || entry.Markers[1] != MarkerWIP {\n\t\tt.Fatalf(\"marker order = %v, want [MarkerAbandoned MarkerWIP]\", entry.Markers)\n\t}\n}\n\nfunc TestParseDocument(t *testing.T) {\n\tinput := `# Awesome Docker\n\n> A curated list\n\n# Contents\n\n- [Projects](#projects)\n\n# Legend\n\n- Abandoned :skull:\n\n# Projects\n\n## Tools\n\n- [ToolA](https://github.com/a/a) - Does A.\n- [ToolB](https://github.com/b/b) - Does B. :skull:\n\n## Services\n\n- [ServiceC](https://example.com/c) - Does C. :yen:\n`\n\tdoc, err := Parse(strings.NewReader(input))\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t}\n\tif len(doc.Sections) == 0 {\n\t\tt.Fatal(\"expected at least one section\")\n\t}\n\t// Find the \"Projects\" section\n\tvar projects *Section\n\tfor i := range doc.Sections {\n\t\tif doc.Sections[i].Title == \"Projects\" {\n\t\t\tprojects = &doc.Sections[i]\n\t\t\tbreak\n\t\t}\n\t}\n\tif projects == nil {\n\t\tt.Fatal(\"expected a Projects section\")\n\t}\n\tif len(projects.Children) != 2 {\n\t\tt.Errorf(\"projects children = %d, want 2\", len(projects.Children))\n\t}\n\tif projects.Children[0].Title != \"Tools\" {\n\t\tt.Errorf(\"first child = %q, want %q\", projects.Children[0].Title, \"Tools\")\n\t}\n\tif len(projects.Children[0].Entries) != 2 {\n\t\tt.Errorf(\"Tools entries = %d, want 2\", len(projects.Children[0].Entries))\n\t}\n}\n\nfunc TestParseNotAnEntry(t *testing.T) {\n\t_, err := ParseEntry(\"- Abandoned :skull:\", 1)\n\tif err == nil {\n\t\tt.Error(\"expected error for non-entry list item\")\n\t}\n}\n\nfunc TestParseRealREADME(t *testing.T) {\n\tf, err := os.Open(\"../../README.md\")\n\tif err != nil {\n\t\tt.Skip(\"README.md not found, skipping integration test\")\n\t}\n\tdefer f.Close()\n\n\tdoc, err := Parse(f)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to parse README: %v\", err)\n\t}\n\n\tif len(doc.Sections) == 0 {\n\t\tt.Error(\"expected sections\")\n\t}\n\n\ttotal := countEntries(doc.Sections)\n\tif total < 100 {\n\t\tt.Errorf(\"expected at least 100 entries, got %d\", total)\n\t}\n\tt.Logf(\"Parsed %d sections, %d total entries\", len(doc.Sections), total)\n}\n\nfunc countEntries(sections []Section) int {\n\tn := 0\n\tfor _, s := range sections {\n\t\tn += len(s.Entries)\n\t\tn += countEntries(s.Children)\n\t}\n\treturn n\n}\n"
  },
  {
    "path": "internal/parser/types.go",
    "content": "package parser\n\n// Marker represents a status emoji on an entry.\ntype Marker int\n\nconst (\n\tMarkerAbandoned Marker = iota // :skull:\n\tMarkerPaid                    // :yen:\n\tMarkerWIP                     // :construction:\n\tMarkerStale                   // :ice_cube:\n)\n\n// Entry is a single link entry in the README.\ntype Entry struct {\n\tName        string\n\tURL         string\n\tDescription string\n\tMarkers     []Marker\n\tLine        int    // 1-based line number in source\n\tRaw         string // original line text\n}\n\n// Section is a heading with optional entries and child sections.\ntype Section struct {\n\tTitle    string\n\tLevel    int // heading level: 1 = #, 2 = ##, etc.\n\tEntries  []Entry\n\tChildren []Section\n\tLine     int\n}\n\n// Document is the parsed representation of the full README.\ntype Document struct {\n\tPreamble []string // lines before the first section\n\tSections []Section\n}\n"
  },
  {
    "path": "internal/scorer/scorer.go",
    "content": "package scorer\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n\t\"github.com/veggiemonk/awesome-docker/internal/checker\"\n)\n\n// Status represents the health status of an entry.\ntype Status string\n\nconst (\n\tStatusHealthy  Status = \"healthy\"\n\tStatusInactive Status = \"inactive\" // 1-2 years since last push\n\tStatusStale    Status = \"stale\"    // 2+ years since last push\n\tStatusArchived Status = \"archived\"\n\tStatusDead     Status = \"dead\" // disabled or 404\n)\n\n// ScoredEntry is a repo with its computed health status.\ntype ScoredEntry struct {\n\tURL         string\n\tName        string\n\tStatus      Status\n\tStars       int\n\tForks       int\n\tHasLicense  bool\n\tLastPush    time.Time\n\tCategory    string\n\tDescription string\n}\n\n// ReportSummary contains grouped status counts.\ntype ReportSummary struct {\n\tHealthy  int `json:\"healthy\"`\n\tInactive int `json:\"inactive\"`\n\tStale    int `json:\"stale\"`\n\tArchived int `json:\"archived\"`\n\tDead     int `json:\"dead\"`\n}\n\n// ReportData is the full machine-readable report model.\ntype ReportData struct {\n\tGeneratedAt time.Time                `json:\"generated_at\"`\n\tTotal       int                      `json:\"total\"`\n\tSummary     ReportSummary            `json:\"summary\"`\n\tEntries     []ScoredEntry            `json:\"entries\"`\n\tByStatus    map[Status][]ScoredEntry `json:\"by_status\"`\n}\n\n// Score computes the health status of a GitHub repo.\nfunc Score(info checker.RepoInfo) Status {\n\tif info.IsDisabled {\n\t\treturn StatusDead\n\t}\n\tif info.IsArchived {\n\t\treturn StatusArchived\n\t}\n\n\ttwoYearsAgo := time.Now().AddDate(-2, 0, 0)\n\toneYearAgo := time.Now().AddDate(-1, 0, 0)\n\n\tif info.PushedAt.Before(twoYearsAgo) {\n\t\treturn StatusStale\n\t}\n\tif info.PushedAt.Before(oneYearAgo) {\n\t\treturn StatusInactive\n\t}\n\treturn StatusHealthy\n}\n\n// ScoreAll scores a batch of repo infos.\nfunc ScoreAll(infos []checker.RepoInfo) []ScoredEntry {\n\tresults := make([]ScoredEntry, len(infos))\n\tfor i, info := range infos {\n\t\tresults[i] = ScoredEntry{\n\t\t\tURL:        info.URL,\n\t\t\tName:       fmt.Sprintf(\"%s/%s\", info.Owner, info.Name),\n\t\t\tStatus:     Score(info),\n\t\t\tStars:      info.Stars,\n\t\t\tForks:      info.Forks,\n\t\t\tHasLicense: info.HasLicense,\n\t\t\tLastPush:   info.PushedAt,\n\t\t}\n\t}\n\treturn results\n}\n\n// ToCacheEntries converts scored entries to cache format.\nfunc ToCacheEntries(scored []ScoredEntry) []cache.HealthEntry {\n\tentries := make([]cache.HealthEntry, len(scored))\n\tnow := time.Now().UTC()\n\tfor i, s := range scored {\n\t\tentries[i] = cache.HealthEntry{\n\t\t\tURL:         s.URL,\n\t\t\tName:        s.Name,\n\t\t\tStatus:      string(s.Status),\n\t\t\tStars:       s.Stars,\n\t\t\tForks:       s.Forks,\n\t\t\tHasLicense:  s.HasLicense,\n\t\t\tLastPush:    s.LastPush,\n\t\t\tCheckedAt:   now,\n\t\t\tCategory:    s.Category,\n\t\t\tDescription: s.Description,\n\t\t}\n\t}\n\treturn entries\n}\n\n// GenerateReport produces a Markdown health report.\nfunc GenerateReport(scored []ScoredEntry) string {\n\tvar b strings.Builder\n\n\tdata := BuildReportData(scored)\n\tgroups := data.ByStatus\n\n\tfmt.Fprintf(&b, \"# Health Report\\n\\n\")\n\tfmt.Fprintf(&b, \"**Generated:** %s\\n\\n\", data.GeneratedAt.Format(time.RFC3339))\n\tfmt.Fprintf(&b, \"**Total:** %d repositories\\n\\n\", data.Total)\n\n\tfmt.Fprintf(&b, \"## Summary\\n\\n\")\n\tfmt.Fprintf(&b, \"- Healthy: %d\\n\", data.Summary.Healthy)\n\tfmt.Fprintf(&b, \"- Inactive (1-2 years): %d\\n\", data.Summary.Inactive)\n\tfmt.Fprintf(&b, \"- Stale (2+ years): %d\\n\", data.Summary.Stale)\n\tfmt.Fprintf(&b, \"- Archived: %d\\n\", data.Summary.Archived)\n\tfmt.Fprintf(&b, \"- Dead: %d\\n\\n\", data.Summary.Dead)\n\n\twriteSection := func(title string, status Status) {\n\t\tentries := groups[status]\n\t\tif len(entries) == 0 {\n\t\t\treturn\n\t\t}\n\t\tfmt.Fprintf(&b, \"## %s\\n\\n\", title)\n\t\tfor _, e := range entries {\n\t\t\tfmt.Fprintf(&b, \"- [%s](%s) - Stars: %d - Last push: %s\\n\",\n\t\t\t\te.Name, e.URL, e.Stars, e.LastPush.Format(\"2006-01-02\"))\n\t\t}\n\t\tb.WriteString(\"\\n\")\n\t}\n\n\twriteSection(\"Archived (should mark :skull:)\", StatusArchived)\n\twriteSection(\"Stale (2+ years inactive)\", StatusStale)\n\twriteSection(\"Inactive (1-2 years)\", StatusInactive)\n\n\treturn b.String()\n}\n\n// BuildReportData returns full report data for machine-readable and markdown rendering.\nfunc BuildReportData(scored []ScoredEntry) ReportData {\n\tgroups := map[Status][]ScoredEntry{}\n\tfor _, s := range scored {\n\t\tgroups[s.Status] = append(groups[s.Status], s)\n\t}\n\n\treturn ReportData{\n\t\tGeneratedAt: time.Now().UTC(),\n\t\tTotal:       len(scored),\n\t\tSummary: ReportSummary{\n\t\t\tHealthy:  len(groups[StatusHealthy]),\n\t\t\tInactive: len(groups[StatusInactive]),\n\t\t\tStale:    len(groups[StatusStale]),\n\t\t\tArchived: len(groups[StatusArchived]),\n\t\t\tDead:     len(groups[StatusDead]),\n\t\t},\n\t\tEntries:  scored,\n\t\tByStatus: groups,\n\t}\n}\n\n// GenerateJSONReport returns the full report as pretty-printed JSON.\nfunc GenerateJSONReport(scored []ScoredEntry) ([]byte, error) {\n\tdata := BuildReportData(scored)\n\treturn json.MarshalIndent(data, \"\", \"  \")\n}\n"
  },
  {
    "path": "internal/scorer/scorer_test.go",
    "content": "package scorer\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/checker\"\n)\n\nfunc TestScoreHealthy(t *testing.T) {\n\tinfo := checker.RepoInfo{\n\t\tPushedAt:   time.Now().AddDate(0, -3, 0),\n\t\tIsArchived: false,\n\t\tStars:      100,\n\t\tHasLicense: true,\n\t}\n\tstatus := Score(info)\n\tif status != StatusHealthy {\n\t\tt.Errorf(\"status = %q, want %q\", status, StatusHealthy)\n\t}\n}\n\nfunc TestScoreInactive(t *testing.T) {\n\tinfo := checker.RepoInfo{\n\t\tPushedAt:   time.Now().AddDate(-1, -6, 0),\n\t\tIsArchived: false,\n\t}\n\tstatus := Score(info)\n\tif status != StatusInactive {\n\t\tt.Errorf(\"status = %q, want %q\", status, StatusInactive)\n\t}\n}\n\nfunc TestScoreStale(t *testing.T) {\n\tinfo := checker.RepoInfo{\n\t\tPushedAt:   time.Now().AddDate(-3, 0, 0),\n\t\tIsArchived: false,\n\t}\n\tstatus := Score(info)\n\tif status != StatusStale {\n\t\tt.Errorf(\"status = %q, want %q\", status, StatusStale)\n\t}\n}\n\nfunc TestScoreArchived(t *testing.T) {\n\tinfo := checker.RepoInfo{\n\t\tPushedAt:   time.Now(),\n\t\tIsArchived: true,\n\t}\n\tstatus := Score(info)\n\tif status != StatusArchived {\n\t\tt.Errorf(\"status = %q, want %q\", status, StatusArchived)\n\t}\n}\n\nfunc TestScoreDisabled(t *testing.T) {\n\tinfo := checker.RepoInfo{\n\t\tIsDisabled: true,\n\t}\n\tstatus := Score(info)\n\tif status != StatusDead {\n\t\tt.Errorf(\"status = %q, want %q\", status, StatusDead)\n\t}\n}\n\nfunc TestGenerateReport(t *testing.T) {\n\tresults := []ScoredEntry{\n\t\t{URL: \"https://github.com/a/a\", Name: \"a/a\", Status: StatusHealthy, Stars: 100, LastPush: time.Now()},\n\t\t{URL: \"https://github.com/b/b\", Name: \"b/b\", Status: StatusArchived, Stars: 50, LastPush: time.Now()},\n\t\t{URL: \"https://github.com/c/c\", Name: \"c/c\", Status: StatusStale, Stars: 10, LastPush: time.Now().AddDate(-3, 0, 0)},\n\t}\n\treport := GenerateReport(results)\n\tif !strings.Contains(report, \"Healthy: 1\") {\n\t\tt.Error(\"report should contain 'Healthy: 1'\")\n\t}\n\tif !strings.Contains(report, \"Archived: 1\") {\n\t\tt.Error(\"report should contain 'Archived: 1'\")\n\t}\n\tif !strings.Contains(report, \"Stale\") {\n\t\tt.Error(\"report should contain 'Stale'\")\n\t}\n}\n\nfunc TestGenerateReportShowsAllEntries(t *testing.T) {\n\tvar results []ScoredEntry\n\tfor i := 0; i < 55; i++ {\n\t\tresults = append(results, ScoredEntry{\n\t\t\tURL:      fmt.Sprintf(\"https://github.com/stale/%d\", i),\n\t\t\tName:     fmt.Sprintf(\"stale/%d\", i),\n\t\t\tStatus:   StatusStale,\n\t\t\tStars:    i,\n\t\t\tLastPush: time.Now().AddDate(-3, 0, 0),\n\t\t})\n\t}\n\n\treport := GenerateReport(results)\n\tif strings.Contains(report, \"... and\") {\n\t\tt.Fatal(\"report should not be truncated\")\n\t}\n\tif !strings.Contains(report, \"stale/54\") {\n\t\tt.Fatal(\"report should contain all entries\")\n\t}\n}\n\nfunc TestGenerateJSONReport(t *testing.T) {\n\tresults := []ScoredEntry{\n\t\t{\n\t\t\tURL:      \"https://github.com/a/a\",\n\t\t\tName:     \"a/a\",\n\t\t\tStatus:   StatusHealthy,\n\t\t\tStars:    100,\n\t\t\tLastPush: time.Now(),\n\t\t},\n\t\t{\n\t\t\tURL:      \"https://github.com/b/b\",\n\t\t\tName:     \"b/b\",\n\t\t\tStatus:   StatusStale,\n\t\t\tStars:    50,\n\t\t\tLastPush: time.Now().AddDate(-3, 0, 0),\n\t\t},\n\t}\n\n\tdata, err := GenerateJSONReport(results)\n\tif err != nil {\n\t\tt.Fatalf(\"GenerateJSONReport() error = %v\", err)\n\t}\n\n\tvar report ReportData\n\tif err := json.Unmarshal(data, &report); err != nil {\n\t\tt.Fatalf(\"json.Unmarshal() error = %v\", err)\n\t}\n\tif report.Total != 2 {\n\t\tt.Fatalf(\"report.Total = %d, want 2\", report.Total)\n\t}\n\tif report.Summary.Healthy != 1 || report.Summary.Stale != 1 {\n\t\tt.Fatalf(\"summary = %+v, want healthy=1 stale=1\", report.Summary)\n\t}\n\tif len(report.Entries) != 2 {\n\t\tt.Fatalf(\"len(report.Entries) = %d, want 2\", len(report.Entries))\n\t}\n\tif len(report.ByStatus[StatusStale]) != 1 {\n\t\tt.Fatalf(\"len(report.ByStatus[stale]) = %d, want 1\", len(report.ByStatus[StatusStale]))\n\t}\n}\n\nfunc TestScoreAll(t *testing.T) {\n\tinfos := []checker.RepoInfo{\n\t\t{Owner: \"a\", Name: \"a\", PushedAt: time.Now(), Stars: 10},\n\t\t{Owner: \"b\", Name: \"b\", PushedAt: time.Now().AddDate(-3, 0, 0), Stars: 5},\n\t}\n\tscored := ScoreAll(infos)\n\tif len(scored) != 2 {\n\t\tt.Fatalf(\"scored = %d, want 2\", len(scored))\n\t}\n\tif scored[0].Status != StatusHealthy {\n\t\tt.Errorf(\"first = %q, want healthy\", scored[0].Status)\n\t}\n\tif scored[1].Status != StatusStale {\n\t\tt.Errorf(\"second = %q, want stale\", scored[1].Status)\n\t}\n}\n"
  },
  {
    "path": "internal/tui/model.go",
    "content": "package tui\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"runtime\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\ttea \"charm.land/bubbletea/v2\"\n\t\"charm.land/lipgloss/v2\"\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n)\n\ntype panel int\n\nconst (\n\tpanelTree panel = iota\n\tpanelList\n)\n\nconst entryHeight = 5 // lines rendered per entry in the list panel\nconst scrollOff = 4   // minimum lines/entries kept visible above and below cursor\n\n// Model is the top-level Bubbletea model.\ntype Model struct {\n\troots    []*TreeNode\n\tflatTree []FlatNode\n\n\tactivePanel    panel\n\ttreeCursor     int\n\ttreeOffset     int\n\tlistCursor     int\n\tlistOffset     int\n\tcurrentEntries []cache.HealthEntry\n\n\tfiltering  bool\n\tfilterText string\n\n\twidth, height int\n}\n\n// New creates a new Model from health cache entries.\nfunc New(entries []cache.HealthEntry) Model {\n\troots := BuildTree(entries)\n\t// Expand first root by default\n\tif len(roots) > 0 {\n\t\troots[0].Expanded = true\n\t}\n\tflat := FlattenVisible(roots)\n\n\tm := Model{\n\t\troots:    roots,\n\t\tflatTree: flat,\n\t}\n\tm.updateCurrentEntries()\n\treturn m\n}\n\n// Init returns an initial command.\nfunc (m Model) Init() tea.Cmd {\n\treturn nil\n}\n\n// Update handles messages.\nfunc (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {\n\tswitch msg := msg.(type) {\n\tcase tea.WindowSizeMsg:\n\t\tm.width = msg.Width\n\t\tm.height = msg.Height\n\t\treturn m, nil\n\n\tcase openURLMsg:\n\t\treturn m, nil\n\n\tcase tea.KeyPressMsg:\n\t\t// Filter mode input\n\t\tif m.filtering {\n\t\t\treturn m.handleFilterKey(msg)\n\t\t}\n\n\t\tswitch msg.String() {\n\t\tcase \"q\", \"ctrl+c\":\n\t\t\treturn m, tea.Quit\n\t\tcase \"tab\":\n\t\t\tif m.activePanel == panelTree {\n\t\t\t\tm.activePanel = panelList\n\t\t\t} else {\n\t\t\t\tm.activePanel = panelTree\n\t\t\t}\n\t\tcase \"/\":\n\t\t\tm.filtering = true\n\t\t\tm.filterText = \"\"\n\t\tdefault:\n\t\t\tif m.activePanel == panelTree {\n\t\t\t\treturn m.handleTreeKey(msg)\n\t\t\t}\n\t\t\treturn m.handleListKey(msg)\n\t\t}\n\t}\n\treturn m, nil\n}\n\nfunc (m Model) handleFilterKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {\n\tswitch msg.String() {\n\tcase \"esc\":\n\t\tm.filtering = false\n\t\tm.filterText = \"\"\n\t\tm.flatTree = FlattenVisible(m.roots)\n\t\tm.updateCurrentEntries()\n\tcase \"enter\":\n\t\tm.filtering = false\n\tcase \"backspace\":\n\t\tif len(m.filterText) > 0 {\n\t\t\tm.filterText = m.filterText[:len(m.filterText)-1]\n\t\t\tm.applyFilter()\n\t\t}\n\tdefault:\n\t\tr := msg.String()\n\t\tif utf8.RuneCountInString(r) == 1 {\n\t\t\tm.filterText += r\n\t\t\tm.applyFilter()\n\t\t}\n\t}\n\treturn m, nil\n}\n\nfunc (m *Model) applyFilter() {\n\tif m.filterText == \"\" {\n\t\tm.flatTree = FlattenVisible(m.roots)\n\t\tm.updateCurrentEntries()\n\t\treturn\n\t}\n\n\tquery := strings.ToLower(m.filterText)\n\tvar filtered []cache.HealthEntry\n\tfor _, root := range m.roots {\n\t\tfor _, e := range root.AllEntries() {\n\t\t\tif strings.Contains(strings.ToLower(e.Name), query) ||\n\t\t\t\tstrings.Contains(strings.ToLower(e.Description), query) ||\n\t\t\t\tstrings.Contains(strings.ToLower(e.Category), query) {\n\t\t\t\tfiltered = append(filtered, e)\n\t\t\t}\n\t\t}\n\t}\n\tm.currentEntries = filtered\n\tm.listCursor = 0\n\tm.listOffset = 0\n}\n\nfunc (m Model) handleTreeKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {\n\tswitch msg.String() {\n\tcase \"up\", \"k\":\n\t\tif m.treeCursor > 0 {\n\t\t\tm.treeCursor--\n\t\t\tm.adjustTreeScroll()\n\t\t\tm.updateCurrentEntries()\n\t\t}\n\tcase \"down\", \"j\":\n\t\tif m.treeCursor < len(m.flatTree)-1 {\n\t\t\tm.treeCursor++\n\t\t\tm.adjustTreeScroll()\n\t\t\tm.updateCurrentEntries()\n\t\t}\n\tcase \"enter\", \" \":\n\t\tif m.treeCursor < len(m.flatTree) {\n\t\t\tnode := m.flatTree[m.treeCursor].Node\n\t\t\tif node.HasChildren() {\n\t\t\t\tnode.Expanded = !node.Expanded\n\t\t\t\tm.flatTree = FlattenVisible(m.roots)\n\t\t\t\tif m.treeCursor >= len(m.flatTree) {\n\t\t\t\t\tm.treeCursor = len(m.flatTree) - 1\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.adjustTreeScroll()\n\t\t\tm.updateCurrentEntries()\n\t\t}\n\tcase \"ctrl+d\", \"pgdown\":\n\t\thalf := m.treePanelHeight() / 2\n\t\tif half < 1 {\n\t\t\thalf = 1\n\t\t}\n\t\tm.treeCursor += half\n\t\tif m.treeCursor >= len(m.flatTree) {\n\t\t\tm.treeCursor = len(m.flatTree) - 1\n\t\t}\n\t\tm.adjustTreeScroll()\n\t\tm.updateCurrentEntries()\n\tcase \"ctrl+u\", \"pgup\":\n\t\thalf := m.treePanelHeight() / 2\n\t\tif half < 1 {\n\t\t\thalf = 1\n\t\t}\n\t\tm.treeCursor -= half\n\t\tif m.treeCursor < 0 {\n\t\t\tm.treeCursor = 0\n\t\t}\n\t\tm.adjustTreeScroll()\n\t\tm.updateCurrentEntries()\n\tcase \"g\", \"home\":\n\t\tm.treeCursor = 0\n\t\tm.adjustTreeScroll()\n\t\tm.updateCurrentEntries()\n\tcase \"G\", \"end\":\n\t\tm.treeCursor = len(m.flatTree) - 1\n\t\tm.adjustTreeScroll()\n\t\tm.updateCurrentEntries()\n\tcase \"right\", \"l\":\n\t\tif m.treeCursor < len(m.flatTree) {\n\t\t\tnode := m.flatTree[m.treeCursor].Node\n\t\t\tif node.HasChildren() && !node.Expanded {\n\t\t\t\tnode.Expanded = true\n\t\t\t\tm.flatTree = FlattenVisible(m.roots)\n\t\t\t\tm.adjustTreeScroll()\n\t\t\t\tm.updateCurrentEntries()\n\t\t\t} else {\n\t\t\t\tm.activePanel = panelList\n\t\t\t}\n\t\t}\n\tcase \"left\", \"h\":\n\t\tif m.treeCursor < len(m.flatTree) {\n\t\t\tnode := m.flatTree[m.treeCursor].Node\n\t\t\tif node.HasChildren() && node.Expanded {\n\t\t\t\tnode.Expanded = false\n\t\t\t\tm.flatTree = FlattenVisible(m.roots)\n\t\t\t\tm.adjustTreeScroll()\n\t\t\t\tm.updateCurrentEntries()\n\t\t\t}\n\t\t}\n\t}\n\treturn m, nil\n}\n\nfunc (m *Model) adjustTreeScroll() {\n\tvisible := m.treePanelHeight()\n\toff := scrollOff\n\tif off > visible/2 {\n\t\toff = visible / 2\n\t}\n\tif m.treeCursor < m.treeOffset+off {\n\t\tm.treeOffset = m.treeCursor - off\n\t}\n\tif m.treeCursor >= m.treeOffset+visible-off {\n\t\tm.treeOffset = m.treeCursor - visible + off + 1\n\t}\n\tif m.treeOffset < 0 {\n\t\tm.treeOffset = 0\n\t}\n}\n\nfunc (m Model) treePanelHeight() int {\n\th := m.height - 6 // header, footer, borders, title\n\tif h < 1 {\n\t\th = 1\n\t}\n\treturn h\n}\n\nfunc (m Model) handleListKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {\n\tswitch msg.String() {\n\tcase \"up\", \"k\":\n\t\tif m.listCursor > 0 {\n\t\t\tm.listCursor--\n\t\t\tm.adjustListScroll()\n\t\t}\n\tcase \"down\", \"j\":\n\t\tif m.listCursor < len(m.currentEntries)-1 {\n\t\t\tm.listCursor++\n\t\t\tm.adjustListScroll()\n\t\t}\n\tcase \"ctrl+d\", \"pgdown\":\n\t\thalf := m.visibleListEntries() / 2\n\t\tif half < 1 {\n\t\t\thalf = 1\n\t\t}\n\t\tm.listCursor += half\n\t\tif m.listCursor >= len(m.currentEntries) {\n\t\t\tm.listCursor = len(m.currentEntries) - 1\n\t\t}\n\t\tm.adjustListScroll()\n\tcase \"ctrl+u\", \"pgup\":\n\t\thalf := m.visibleListEntries() / 2\n\t\tif half < 1 {\n\t\t\thalf = 1\n\t\t}\n\t\tm.listCursor -= half\n\t\tif m.listCursor < 0 {\n\t\t\tm.listCursor = 0\n\t\t}\n\t\tm.adjustListScroll()\n\tcase \"g\", \"home\":\n\t\tm.listCursor = 0\n\t\tm.adjustListScroll()\n\tcase \"G\", \"end\":\n\t\tm.listCursor = len(m.currentEntries) - 1\n\t\tm.adjustListScroll()\n\tcase \"enter\":\n\t\tif m.listCursor < len(m.currentEntries) {\n\t\t\treturn m, openURL(m.currentEntries[m.listCursor].URL)\n\t\t}\n\tcase \"left\", \"h\":\n\t\tm.activePanel = panelTree\n\t}\n\treturn m, nil\n}\n\nfunc (m *Model) updateCurrentEntries() {\n\tif len(m.flatTree) == 0 {\n\t\tm.currentEntries = nil\n\t\treturn\n\t}\n\tif m.treeCursor >= len(m.flatTree) {\n\t\tm.treeCursor = len(m.flatTree) - 1\n\t}\n\tnode := m.flatTree[m.treeCursor].Node\n\tm.currentEntries = node.AllEntries()\n\tm.listCursor = 0\n\tm.listOffset = 0\n}\n\nfunc (m Model) visibleListEntries() int {\n\tv := m.listPanelHeight() / entryHeight\n\tif v < 1 {\n\t\treturn 1\n\t}\n\treturn v\n}\n\nfunc (m *Model) adjustListScroll() {\n\tvisible := m.visibleListEntries()\n\toff := scrollOff\n\tif off > visible/2 {\n\t\toff = visible / 2\n\t}\n\tif m.listCursor < m.listOffset+off {\n\t\tm.listOffset = m.listCursor - off\n\t}\n\tif m.listCursor >= m.listOffset+visible-off {\n\t\tm.listOffset = m.listCursor - visible + off + 1\n\t}\n\tif m.listOffset < 0 {\n\t\tm.listOffset = 0\n\t}\n}\n\nfunc (m Model) listPanelHeight() int {\n\t// height minus header, footer, borders\n\th := m.height - 4\n\tif h < 1 {\n\t\th = 1\n\t}\n\treturn h\n}\n\n// View renders the UI.\nfunc (m Model) View() tea.View {\n\tif m.width == 0 || m.height == 0 {\n\t\treturn tea.NewView(\"Loading...\")\n\t}\n\n\ttreeWidth := m.width*3/10 - 2        // 30% minus borders\n\tlistWidth := m.width - treeWidth - 6 // remaining minus borders/gaps\n\tcontentHeight := m.height - 3        // minus footer\n\n\tif treeWidth < 10 {\n\t\ttreeWidth = 10\n\t}\n\tif listWidth < 20 {\n\t\tlistWidth = 20\n\t}\n\tif contentHeight < 3 {\n\t\tcontentHeight = 3\n\t}\n\n\ttree := m.renderTree(treeWidth, contentHeight)\n\tlist := m.renderList(listWidth, contentHeight)\n\n\t// Apply border styles\n\ttreeBorder := inactiveBorderStyle\n\tlistBorder := inactiveBorderStyle\n\tif m.activePanel == panelTree {\n\t\ttreeBorder = activeBorderStyle\n\t} else {\n\t\tlistBorder = activeBorderStyle\n\t}\n\n\ttreePanel := treeBorder.Width(treeWidth).Height(contentHeight).Render(tree)\n\tlistPanel := listBorder.Width(listWidth).Height(contentHeight).Render(list)\n\n\tbody := lipgloss.JoinHorizontal(lipgloss.Top, treePanel, listPanel)\n\n\tfooter := m.renderFooter()\n\n\tcontent := lipgloss.JoinVertical(lipgloss.Left, body, footer)\n\n\tv := tea.NewView(content)\n\tv.AltScreen = true\n\treturn v\n}\n\nfunc (m Model) renderTree(width, height int) string {\n\tvar b strings.Builder\n\n\ttitle := headerStyle.Render(\"Categories\")\n\tb.WriteString(title)\n\tb.WriteString(\"\\n\\n\")\n\n\tlinesUsed := 2\n\tend := m.treeOffset + height - 2\n\tif end > len(m.flatTree) {\n\t\tend = len(m.flatTree)\n\t}\n\tfor i := m.treeOffset; i < end; i++ {\n\t\tfn := m.flatTree[i]\n\t\tif linesUsed >= height {\n\t\t\tbreak\n\t\t}\n\n\t\tindent := strings.Repeat(\"  \", fn.Depth)\n\t\ticon := \"  \"\n\t\tif fn.Node.HasChildren() {\n\t\t\tif fn.Node.Expanded {\n\t\t\t\ticon = \"▼ \"\n\t\t\t} else {\n\t\t\t\ticon = \"▶ \"\n\t\t\t}\n\t\t}\n\n\t\tcount := fn.Node.TotalEntries()\n\t\tlabel := fmt.Sprintf(\"%s%s%s (%d)\", indent, icon, fn.Node.Name, count)\n\n\t\t// Truncate to width\n\t\tif len(label) > width {\n\t\t\tlabel = label[:width-1] + \"…\"\n\t\t}\n\n\t\tif i == m.treeCursor {\n\t\t\tlabel = treeSelectedStyle.Render(label)\n\t\t} else {\n\t\t\tlabel = treeNormalStyle.Render(label)\n\t\t}\n\n\t\tb.WriteString(label)\n\t\tb.WriteString(\"\\n\")\n\t\tlinesUsed++\n\t}\n\n\treturn b.String()\n}\n\nfunc (m Model) renderList(width, height int) string {\n\tvar b strings.Builder\n\n\t// Title\n\ttitle := \"Resources\"\n\tif m.filtering && m.filterText != \"\" {\n\t\ttitle = fmt.Sprintf(\"Resources (filter: %s)\", m.filterText)\n\t}\n\tb.WriteString(headerStyle.Render(title))\n\tb.WriteString(\"\\n\\n\")\n\n\tif len(m.currentEntries) == 0 {\n\t\tb.WriteString(entryDescStyle.Render(\"  No entries\"))\n\t\treturn b.String()\n\t}\n\n\tlinesUsed := 2\n\n\tvisible := (height - 2) / entryHeight\n\tif visible < 1 {\n\t\tvisible = 1\n\t}\n\n\tstart := m.listOffset\n\tend := start + visible\n\tif end > len(m.currentEntries) {\n\t\tend = len(m.currentEntries)\n\t}\n\n\tfor idx := start; idx < end; idx++ {\n\t\tif linesUsed+entryHeight > height {\n\t\t\tbreak\n\t\t}\n\n\t\te := m.currentEntries[idx]\n\t\tselected := idx == m.listCursor\n\n\t\t// Use a safe width that accounts for Unicode characters (★, ⑂)\n\t\t// that some terminals render as 2 columns but lipgloss counts as 1.\n\t\tsafeWidth := width - 2\n\n\t\t// Line 1: name + stars + forks\n\t\tstats := fmt.Sprintf(\"★ %d\", e.Stars)\n\t\tif e.Forks > 0 {\n\t\t\tstats += fmt.Sprintf(\"  ⑂ %d\", e.Forks)\n\t\t}\n\t\tname := e.Name\n\t\tstatsW := lipgloss.Width(stats)\n\t\tmaxName := safeWidth - statsW - 2 // 2 for minimum gap\n\t\tif maxName < 4 {\n\t\t\tmaxName = 4\n\t\t}\n\t\tif lipgloss.Width(name) > maxName {\n\t\t\tname = truncateToWidth(name, maxName-1) + \"…\"\n\t\t}\n\t\tnameStr := entryNameStyle.Render(name)\n\t\tstatsStr := entryDescStyle.Render(stats)\n\t\tpadding := safeWidth - lipgloss.Width(nameStr) - lipgloss.Width(statsStr)\n\t\tif padding < 1 {\n\t\t\tpadding = 1\n\t\t}\n\t\tline1 := nameStr + strings.Repeat(\" \", padding) + statsStr\n\n\t\t// Line 2: URL\n\t\turl := e.URL\n\t\tif lipgloss.Width(url) > safeWidth {\n\t\t\turl = truncateToWidth(url, safeWidth-1) + \"…\"\n\t\t}\n\t\tline2 := entryURLStyle.Render(url)\n\n\t\t// Line 3: description\n\t\tdesc := e.Description\n\t\tif lipgloss.Width(desc) > safeWidth {\n\t\t\tdesc = truncateToWidth(desc, safeWidth-3) + \"...\"\n\t\t}\n\t\tline3 := entryDescStyle.Render(desc)\n\n\t\t// Line 4: status + last push\n\t\tstatusStr := statusStyle(e.Status).Render(e.Status)\n\t\tlastPush := \"\"\n\t\tif !e.LastPush.IsZero() {\n\t\t\tlastPush = fmt.Sprintf(\"  Last push: %s\", e.LastPush.Format(\"2006-01-02\"))\n\t\t}\n\t\tline4 := statusStr + entryDescStyle.Render(lastPush)\n\n\t\t// Line 5: separator\n\t\tsepWidth := safeWidth\n\t\tif sepWidth < 1 {\n\t\t\tsepWidth = 1\n\t\t}\n\t\tline5 := entryDescStyle.Render(strings.Repeat(\"─\", sepWidth))\n\n\t\tentry := fmt.Sprintf(\"%s\\n%s\\n%s\\n%s\\n%s\", line1, line2, line3, line4, line5)\n\n\t\tif selected && m.activePanel == panelList {\n\t\t\tentry = entrySelectedStyle.Render(entry)\n\t\t}\n\n\t\tb.WriteString(entry)\n\t\tb.WriteString(\"\\n\")\n\t\tlinesUsed += entryHeight\n\t}\n\n\t// Scroll indicator\n\tif len(m.currentEntries) > visible {\n\t\tindicator := fmt.Sprintf(\" %d-%d of %d\", start+1, end, len(m.currentEntries))\n\t\tb.WriteString(footerStyle.Render(indicator))\n\t}\n\n\treturn b.String()\n}\n\nfunc (m Model) renderFooter() string {\n\tif m.filtering {\n\t\treturn filterPromptStyle.Render(\"/\") + entryDescStyle.Render(m.filterText+\"█\")\n\t}\n\thelp := \" Tab:switch  j/k:nav  PgDn/PgUp:page  g/G:top/bottom  Enter:expand/open  /:filter  q:quit\"\n\treturn footerStyle.Render(help)\n}\n\n// openURLMsg is sent after attempting to open a URL.\ntype openURLMsg struct{ err error }\n\nfunc openURL(url string) tea.Cmd {\n\treturn func() tea.Msg {\n\t\tvar cmd *exec.Cmd\n\t\tswitch runtime.GOOS {\n\t\tcase \"darwin\":\n\t\t\tcmd = exec.Command(\"open\", url)\n\t\tcase \"windows\":\n\t\t\tcmd = exec.Command(\"cmd\", \"/c\", \"start\", url)\n\t\tdefault:\n\t\t\tcmd = exec.Command(\"xdg-open\", url)\n\t\t}\n\t\treturn openURLMsg{err: cmd.Run()}\n\t}\n}\n\n// truncateToWidth truncates s to at most maxWidth visible columns.\nfunc truncateToWidth(s string, maxWidth int) string {\n\tif maxWidth <= 0 {\n\t\treturn \"\"\n\t}\n\tw := 0\n\tfor i, r := range s {\n\t\trw := lipgloss.Width(string(r))\n\t\tif w+rw > maxWidth {\n\t\t\treturn s[:i]\n\t\t}\n\t\tw += rw\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "internal/tui/styles.go",
    "content": "package tui\n\nimport \"charm.land/lipgloss/v2\"\n\nvar (\n\t// Panel borders\n\tactiveBorderStyle = lipgloss.NewStyle().\n\t\t\t\tBorder(lipgloss.RoundedBorder()).\n\t\t\t\tBorderForeground(lipgloss.Color(\"#7D56F4\"))\n\n\tinactiveBorderStyle = lipgloss.NewStyle().\n\t\t\t\tBorder(lipgloss.RoundedBorder()).\n\t\t\t\tBorderForeground(lipgloss.Color(\"#555555\"))\n\n\t// Tree styles\n\ttreeSelectedStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(\"#FF79C6\")).Background(lipgloss.Color(\"#3B2D50\"))\n\ttreeNormalStyle   = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#CCCCCC\"))\n\n\t// Entry styles\n\tentryNameStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(\"#50FA7B\"))\n\tentryURLStyle  = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#888888\")).Italic(true)\n\tentryDescStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#CCCCCC\"))\n\n\t// Status badge styles\n\tstatusHealthyStyle  = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#50FA7B\")).Bold(true)\n\tstatusInactiveStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#FFB86C\"))\n\tstatusStaleStyle    = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#F1FA8C\"))\n\tstatusArchivedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#FF5555\")).Bold(true)\n\tstatusDeadStyle     = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#666666\")).Strikethrough(true)\n\n\t// Selected entry\n\tentrySelectedStyle = lipgloss.NewStyle().Background(lipgloss.Color(\"#44475A\"))\n\n\t// Header\n\theaderStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(\"#BD93F9\")).Padding(0, 1)\n\n\t// Footer\n\tfooterStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#666666\"))\n\n\t// Filter\n\tfilterPromptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(\"#FF79C6\")).Bold(true)\n)\n\nfunc statusStyle(status string) lipgloss.Style {\n\tswitch status {\n\tcase \"healthy\":\n\t\treturn statusHealthyStyle\n\tcase \"inactive\":\n\t\treturn statusInactiveStyle\n\tcase \"stale\":\n\t\treturn statusStaleStyle\n\tcase \"archived\":\n\t\treturn statusArchivedStyle\n\tcase \"dead\":\n\t\treturn statusDeadStyle\n\tdefault:\n\t\treturn lipgloss.NewStyle()\n\t}\n}\n"
  },
  {
    "path": "internal/tui/tree.go",
    "content": "package tui\n\nimport (\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n)\n\n// TreeNode represents a node in the category tree.\ntype TreeNode struct {\n\tName     string       // display name (leaf segment, e.g. \"Networking\")\n\tPath     string       // full path (e.g. \"Container Operations > Networking\")\n\tChildren []*TreeNode\n\tExpanded bool\n\tEntries  []cache.HealthEntry\n}\n\n// FlatNode is a visible tree node with its indentation depth.\ntype FlatNode struct {\n\tNode  *TreeNode\n\tDepth int\n}\n\n// HasChildren returns true if this node has child categories.\nfunc (n *TreeNode) HasChildren() bool {\n\treturn len(n.Children) > 0\n}\n\n// TotalEntries returns the count of entries in this node and all descendants.\nfunc (n *TreeNode) TotalEntries() int {\n\tcount := len(n.Entries)\n\tfor _, c := range n.Children {\n\t\tcount += c.TotalEntries()\n\t}\n\treturn count\n}\n\n// AllEntries returns entries from this node and all descendants.\nfunc (n *TreeNode) AllEntries() []cache.HealthEntry {\n\tresult := make([]cache.HealthEntry, 0, n.TotalEntries())\n\tresult = append(result, n.Entries...)\n\tfor _, c := range n.Children {\n\t\tresult = append(result, c.AllEntries()...)\n\t}\n\treturn result\n}\n\n// BuildTree constructs a tree from flat HealthEntry slice, grouping by Category.\nfunc BuildTree(entries []cache.HealthEntry) []*TreeNode {\n\troot := &TreeNode{Name: \"root\"}\n\tnodeMap := map[string]*TreeNode{}\n\n\tfor _, e := range entries {\n\t\tcat := e.Category\n\t\tif cat == \"\" {\n\t\t\tcat = \"Uncategorized\"\n\t\t}\n\n\t\tnode := ensureNode(root, nodeMap, cat)\n\t\tnode.Entries = append(node.Entries, e)\n\t}\n\n\t// Sort children at every level\n\tsortTree(root)\n\treturn root.Children\n}\n\nfunc ensureNode(root *TreeNode, nodeMap map[string]*TreeNode, path string) *TreeNode {\n\tif n, ok := nodeMap[path]; ok {\n\t\treturn n\n\t}\n\n\tparts := strings.Split(path, \" > \")\n\tcurrent := root\n\tfor i, part := range parts {\n\t\tsubpath := strings.Join(parts[:i+1], \" > \")\n\t\tif n, ok := nodeMap[subpath]; ok {\n\t\t\tcurrent = n\n\t\t\tcontinue\n\t\t}\n\t\tchild := &TreeNode{\n\t\t\tName: part,\n\t\t\tPath: subpath,\n\t\t}\n\t\tcurrent.Children = append(current.Children, child)\n\t\tnodeMap[subpath] = child\n\t\tcurrent = child\n\t}\n\treturn current\n}\n\nfunc sortTree(node *TreeNode) {\n\tsort.Slice(node.Children, func(i, j int) bool {\n\t\treturn node.Children[i].Name < node.Children[j].Name\n\t})\n\tfor _, c := range node.Children {\n\t\tsortTree(c)\n\t}\n}\n\n// FlattenVisible returns visible nodes in depth-first order for rendering.\nfunc FlattenVisible(roots []*TreeNode) []FlatNode {\n\tvar result []FlatNode\n\tfor _, r := range roots {\n\t\tflattenNode(r, 0, &result)\n\t}\n\treturn result\n}\n\nfunc flattenNode(node *TreeNode, depth int, result *[]FlatNode) {\n\t*result = append(*result, FlatNode{Node: node, Depth: depth})\n\tif node.Expanded {\n\t\tfor _, c := range node.Children {\n\t\t\tflattenNode(c, depth+1, result)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/tui/tree_test.go",
    "content": "package tui\n\nimport (\n\t\"testing\"\n\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n)\n\nfunc TestBuildTree(t *testing.T) {\n\tentries := []cache.HealthEntry{\n\t\t{URL: \"https://github.com/a/b\", Name: \"a/b\", Category: \"Projects > Networking\", Description: \"desc1\"},\n\t\t{URL: \"https://github.com/c/d\", Name: \"c/d\", Category: \"Projects > Networking\", Description: \"desc2\"},\n\t\t{URL: \"https://github.com/e/f\", Name: \"e/f\", Category: \"Projects > Security\", Description: \"desc3\"},\n\t\t{URL: \"https://github.com/g/h\", Name: \"g/h\", Category: \"Docker Images > Base Tools\", Description: \"desc4\"},\n\t\t{URL: \"https://github.com/i/j\", Name: \"i/j\", Category: \"\", Description: \"no category\"},\n\t}\n\n\troots := BuildTree(entries)\n\n\t// Should have 3 roots: Docker Images, Projects, Uncategorized (sorted)\n\tif len(roots) != 3 {\n\t\tt.Fatalf(\"expected 3 roots, got %d\", len(roots))\n\t}\n\n\tif roots[0].Name != \"Docker Images\" {\n\t\tt.Errorf(\"expected first root 'Docker Images', got %q\", roots[0].Name)\n\t}\n\tif roots[1].Name != \"Projects\" {\n\t\tt.Errorf(\"expected second root 'Projects', got %q\", roots[1].Name)\n\t}\n\tif roots[2].Name != \"Uncategorized\" {\n\t\tt.Errorf(\"expected third root 'Uncategorized', got %q\", roots[2].Name)\n\t}\n\n\t// Projects > Networking should have 2 entries\n\tprojects := roots[1]\n\tif len(projects.Children) != 2 {\n\t\tt.Fatalf(\"expected 2 children under Projects, got %d\", len(projects.Children))\n\t}\n\tnetworking := projects.Children[0] // Networking < Security alphabetically\n\tif networking.Name != \"Networking\" {\n\t\tt.Errorf(\"expected 'Networking', got %q\", networking.Name)\n\t}\n\tif len(networking.Entries) != 2 {\n\t\tt.Errorf(\"expected 2 entries in Networking, got %d\", len(networking.Entries))\n\t}\n}\n\nfunc TestBuildTreeEmpty(t *testing.T) {\n\troots := BuildTree(nil)\n\tif len(roots) != 0 {\n\t\tt.Errorf(\"expected 0 roots for nil input, got %d\", len(roots))\n\t}\n}\n\nfunc TestTotalEntries(t *testing.T) {\n\tentries := []cache.HealthEntry{\n\t\t{URL: \"https://a\", Category: \"A > B\"},\n\t\t{URL: \"https://b\", Category: \"A > B\"},\n\t\t{URL: \"https://c\", Category: \"A > C\"},\n\t\t{URL: \"https://d\", Category: \"A\"},\n\t}\n\troots := BuildTree(entries)\n\tif len(roots) != 1 {\n\t\tt.Fatalf(\"expected 1 root, got %d\", len(roots))\n\t}\n\tif roots[0].TotalEntries() != 4 {\n\t\tt.Errorf(\"expected 4 total entries, got %d\", roots[0].TotalEntries())\n\t}\n}\n\nfunc TestFlattenVisible(t *testing.T) {\n\tentries := []cache.HealthEntry{\n\t\t{URL: \"https://a\", Category: \"A > B\"},\n\t\t{URL: \"https://b\", Category: \"A > C\"},\n\t}\n\troots := BuildTree(entries)\n\n\t// Initially not expanded, should see just root\n\tflat := FlattenVisible(roots)\n\tif len(flat) != 1 {\n\t\tt.Fatalf(\"expected 1 visible node (collapsed), got %d\", len(flat))\n\t}\n\tif flat[0].Depth != 0 {\n\t\tt.Errorf(\"expected depth 0, got %d\", flat[0].Depth)\n\t}\n\n\t// Expand root\n\troots[0].Expanded = true\n\tflat = FlattenVisible(roots)\n\tif len(flat) != 3 {\n\t\tt.Fatalf(\"expected 3 visible nodes (expanded), got %d\", len(flat))\n\t}\n\tif flat[1].Depth != 1 {\n\t\tt.Errorf(\"expected depth 1 for child, got %d\", flat[1].Depth)\n\t}\n}\n\nfunc TestAllEntries(t *testing.T) {\n\tentries := []cache.HealthEntry{\n\t\t{URL: \"https://a\", Category: \"A > B\"},\n\t\t{URL: \"https://b\", Category: \"A\"},\n\t}\n\troots := BuildTree(entries)\n\tall := roots[0].AllEntries()\n\tif len(all) != 2 {\n\t\tt.Errorf(\"expected 2 entries from AllEntries, got %d\", len(all))\n\t}\n}\n"
  },
  {
    "path": "internal/tui/tui.go",
    "content": "package tui\n\nimport (\n\ttea \"charm.land/bubbletea/v2\"\n\t\"github.com/veggiemonk/awesome-docker/internal/cache\"\n)\n\n// Run launches the TUI browser. It blocks until the user quits.\nfunc Run(entries []cache.HealthEntry) error {\n\tm := New(entries)\n\tp := tea.NewProgram(m)\n\t_, err := p.Run()\n\treturn err\n}\n"
  }
]