diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 64b1ec0..32bdd81 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,3 +11,5 @@ - [ ] Descriptions are original, factual and free of marketing claims - [ ] Recipe changes: test status updated honestly (`tested` only with a passing smoke test) - [ ] Added an entry under *Unreleased* in `CHANGELOG.md` +- [ ] Facts come from upstream sources (LICENSE file, repo, release); no unverified claims +- [ ] `python -m pytest -q tests` passes; browser tests pass if `docs/catalog.md` or `docs/javascripts/` changed diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed67379..c2c3e2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ jobs: - run: pip install -r requirements.txt - name: Schema, duplicates, licences, evidence, no submodules run: python scripts/validate.py + - name: Unit tests (collector, validator, build) + run: python -m pytest -q tests - name: Generated files match catalog (and generation is deterministic) run: | python scripts/build.py && git diff --exit-code @@ -33,6 +35,30 @@ jobs: with: args: --offline --no-progress --index-files index.html --root-dir ${{ github.workspace }}/_check --remap 'https://codesbyfebin.github.io/Open-Source-Ai file://${{ github.workspace }}/_check/Open-Source-Ai' --exclude-path _check/Open-Source-Ai/404.html '_check/**/*.html' fail: true + browser: + name: Browser tests (Playwright, desktop + iPhone 13 emulation) + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: {python-version: '3.12'} + - uses: actions/setup-node@v4 + with: {node-version: '20'} + - run: pip install -r requirements.txt + - run: mkdocs build --strict -d _site/Open-Source-Ai + - working-directory: tests/browser + run: npm ci && npx playwright install --with-deps chromium webkit + - working-directory: tests/browser + run: npx playwright test + - if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-results + if-no-files-found: ignore + path: | + tests/browser/results.json + tests/browser/test-results upstream-links: name: Upstream links (non-blocking) runs-on: ubuntu-latest @@ -54,5 +80,3 @@ jobs: docker compose -f recipes/local-chat/docker-compose.yml config --quiet docker compose -f recipes/agent-memory-eval/docker-compose.yml config --quiet - run: ./recipes/local-chat/smoke.sh - - if: always() - run: docker compose -f recipes/local-chat/docker-compose.yml down -v diff --git a/.github/workflows/recipe-agent-memory.yml b/.github/workflows/recipe-agent-memory.yml new file mode 100644 index 0000000..f725ce0 --- /dev/null +++ b/.github/workflows/recipe-agent-memory.yml @@ -0,0 +1,24 @@ +name: Recipe – agent-memory-eval +# Heavier end-to-end recipe (~1.3 GB of models). Runs only when the recipe changes, weekly, or on demand. +# Not a required check. +on: + push: + branches: [main] + paths: ['recipes/agent-memory-eval/**', '.github/workflows/recipe-agent-memory.yml'] + pull_request: + paths: ['recipes/agent-memory-eval/**', '.github/workflows/recipe-agent-memory.yml'] + schedule: [{cron: '0 4 * * 1'}] + workflow_dispatch: +permissions: {contents: read} +jobs: + e2e: + runs-on: ubuntu-latest + timeout-minutes: 40 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: {python-version: '3.12'} + - uses: actions/setup-node@v4 + with: {node-version: '22'} + - run: pip install -r recipes/agent-memory-eval/requirements.txt + - run: ./recipes/agent-memory-eval/smoke.sh diff --git a/.github/workflows/refresh.yml b/.github/workflows/refresh.yml index c2bc38d..85d881c 100644 --- a/.github/workflows/refresh.yml +++ b/.github/workflows/refresh.yml @@ -3,6 +3,7 @@ on: schedule: [{cron: '0 3 * * 1'}] # weekly, Monday 03:00 UTC workflow_dispatch: concurrency: {group: refresh, cancel-in-progress: false} +permissions: {} # job-level only jobs: refresh: runs-on: ubuntu-latest @@ -10,6 +11,7 @@ jobs: permissions: {contents: write, pull-requests: write} steps: - uses: actions/checkout@v4 + with: {persist-credentials: false} - uses: actions/setup-python@v5 with: {python-version: '3.12'} - run: pip install -r requirements.txt @@ -18,17 +20,29 @@ jobs: path: .cache/etags.json key: etags-${{ github.run_id }} restore-keys: etags- - - name: Collect evidence from GitHub API - env: {GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'} + - name: Collect evidence from GitHub API (read-only token) + id: collect + env: {GITHUB_TOKEN: '${{ github.token }}'} run: python scripts/collect.py - - name: Regenerate docs and validate - run: python scripts/build.py && python scripts/validate.py + - name: Regenerate docs, test and validate + run: python scripts/build.py && python -m pytest -q tests && python scripts/validate.py + # Optional GitHub App token: PRs opened with it trigger CI automatically. + # Configure repo variable OSA_APP_ID and secret OSA_APP_PRIVATE_KEY (see CONTRIBUTING.md). + - name: Mint GitHub App token (optional) + id: app + if: ${{ vars.OSA_APP_ID != '' }} + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.OSA_APP_ID }} + private-key: ${{ secrets.OSA_APP_PRIVATE_KEY }} - uses: peter-evans/create-pull-request@v7 with: + token: ${{ steps.app.outputs.token || github.token }} branch: bot/evidence-refresh + base: main delete-branch: true commit-message: "catalog: refresh evidence" - title: "catalog: weekly evidence refresh" + title: "catalog: weekly evidence refresh${{ steps.collect.outputs.failed != '0' && format(' ({0} lookups failed)', steps.collect.outputs.failed) || '' }}" body-path: .cache/summary.md labels: evidence-refresh add-paths: | @@ -36,3 +50,4 @@ jobs: docs README.md CREDITS.md + mkdocs.yml diff --git a/.gitignore b/.gitignore index 32ba010..f576193 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ site/ __pycache__/ .venv/ _check/ +_site/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d30c50..7768a97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ Catalog changes are recorded here. Evidence refreshes are listed by their pull r ## Unreleased +- Licences: 15 projects now `needs-review`, each with a recorded `review_reason` (adds Phoenix, Trylon Gateway, llamafile and three AgentDomains repos: source-available or undetected). OpenMemory and PR-Agent re-verified as MIT from their LICENSE files. +- Collector: failed / rate-limited lookups are reported as failed and keep previous evidence; records `moved` and `fetch_status`. Validator: moved repo and GitHub licence mismatch are errors; zone-aware date checks. +- Unit tests (collector, validator, build) and Playwright browser tests (Chromium + WebKit, desktop and iPhone 13 emulation, axe-core). +- Search page: URL state (reload/back/forward), clear button, no-results message, archived badge, focus styles. +- Recipes: pinned images; local-chat smoke test now proves the reply came from the model; agent-memory-eval end-to-end CI workflow. +- Refresh workflow: optional GitHub App token, minimal permissions. + - Merged first evidence refresh (PR #1): 70 projects collected, 2 archived upstream (Flowise, Text Generation Inference). - Corrected licences from upstream LICENSE files: OpenMemory Apache-2.0 → MIT, PR-Agent AGPL-3.0 → MIT. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9367da5..3bad217 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,3 +32,47 @@ Upstream licences are authoritative. Use an SPDX id with `state: declared` only ## Evidence refresh `.github/workflows/refresh.yml` runs weekly (Monday 03:00 UTC) and on demand. It only updates `catalog/evidence/` and regenerated pages, and always opens a pull request for review – it never pushes to `main`. Pull requests opened by the bot do not trigger CI automatically; a maintainer should run `python scripts/validate.py` on the branch (or re-run CI) before merging. + +## Verifying facts + +- **Licence:** open the upstream LICENSE file (not just GitHub's badge). Use `state: declared` only for a single standard SPDX licence; otherwise `state: needs-review` with a `review_reason` explaining why (custom terms, multiple licences, source-available, undetected). +- **Repository state:** comes only from `catalog/evidence/`. If validation reports `repo moved`, update `repo:` in `projects.yaml` to the canonical URL. +- **Archived projects** stay in the catalog and are labelled; don't delete them without a CHANGELOG entry. +- **Recipes:** `tested` only when a smoke test passes in CI; say what was tested, versions and environment. + +## Tests + +```bash +python -m pytest -q tests # unit tests +mkdocs build --strict -d _site/Open-Source-Ai +cd tests/browser && npm ci && npx playwright install chromium webkit && npx playwright test +./recipes/local-chat/smoke.sh # needs Docker +``` + +## Maintainer one-time setup (not done automatically) + +These settings are documented here and must be applied by a repository admin. + +### Branch protection for `main` + +Settings → Branches → Add rule for `main`: + +- Require a pull request before merging (1 approval) +- Require status checks: `Catalog integrity`, `Docs build + internal links`, `Browser tests (Playwright, desktop + iPhone 13 emulation)`, `Recipe smoke test – local-chat` +- Do **not** require `Upstream links (non-blocking)` or `Recipe – agent-memory-eval` (network-dependent / heavier) +- Do not allow bypass for the bot + +### Evidence refresh PRs and CI + +PRs created with the default `GITHUB_TOKEN` **do not trigger** other workflows (a GitHub safety rule), so CI will not start on `bot/evidence-refresh` by itself. + +**Option A – GitHub App (recommended):** + +1. Settings → Developer settings → GitHub Apps → New. Permissions: *Contents: read & write*, *Pull requests: read & write*. No webhook. +2. Install it on this repository only. +3. Add repository variable `OSA_APP_ID` (the App ID) and secret `OSA_APP_PRIVATE_KEY` (the generated private key). +4. The refresh workflow then uses `actions/create-github-app-token` and CI starts automatically on its PRs. + +**Option B – manual fallback (no setup):** open the PR, then either close and reopen it, or run *CI* via *Actions → CI → Run workflow* on the `bot/evidence-refresh` branch. Merge only when blocking checks are green. + +The refresh job never pushes to `main`, uses no `pull_request_target`, and the collection step runs before any write token is minted. diff --git a/CREDITS.md b/CREDITS.md index 043ec6e..0829a03 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -8,7 +8,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | FreeLLMAPI | https://github.com/tashfeenahmed/freellmapi | MIT | declared | 2026-10-20 | | OpenCode Free Router | https://github.com/0xgetz/opencode-free-9router | MIT | declared | 2026-10-20 | | Bifrost | https://github.com/maximhq/bifrost | Apache-2.0 | declared | 2026-10-20 | -| Trylon Gateway | https://github.com/trylonai/gateway | BUSL-1.1 | declared | 2026-10-20 | +| Trylon Gateway | https://github.com/trylonai/gateway | BUSL-1.1 | needs-review | 2026-10-20 | | LiteLLM | https://github.com/BerriAI/litellm | MIT (enterprise/ dir separate) | needs-review | 2026-10-20 | | Portkey Gateway | https://github.com/Portkey-AI/gateway | MIT | declared | 2026-10-20 | | Open WebUI | https://github.com/open-webui/open-webui | Open WebUI License (BSD-3 + branding clause) | needs-review | 2026-10-20 | @@ -18,7 +18,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | GPT4All | https://github.com/nomic-ai/gpt4all | MIT | declared | 2026-10-20 | | Ollama | https://github.com/ollama/ollama | MIT | declared | 2026-10-20 | | llama.cpp | https://github.com/ggml-org/llama.cpp | MIT | declared | 2026-10-20 | -| llamafile | https://github.com/mozilla-ai/llamafile | Apache-2.0 | declared | 2026-10-20 | +| llamafile | https://github.com/mozilla-ai/llamafile | Apache-2.0 | needs-review | 2026-10-20 | | LocalAI | https://github.com/mudler/LocalAI | MIT | declared | 2026-10-20 | | Text Generation WebUI | https://github.com/oobabooga/textgen | AGPL-3.0 | declared | 2026-10-20 | | vLLM | https://github.com/vllm-project/vllm | Apache-2.0 | declared | 2026-10-20 | @@ -26,7 +26,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | Text Generation Inference | https://github.com/huggingface/text-generation-inference | Apache-2.0 | declared | 2026-10-20 | | Triton Inference Server | https://github.com/triton-inference-server/server | BSD-3-Clause | declared | 2026-10-20 | | Mem0 | https://github.com/mem0ai/mem0 | Apache-2.0 | declared | 2026-10-20 | -| OpenMemory | https://github.com/mem0ai/openmemory | MIT | declared | 2026-10-20 | +| OpenMemory | https://github.com/mem0ai/openmemory | MIT | declared | 2026-10-21 | | Letta | https://github.com/letta-ai/letta | Apache-2.0 | declared | 2026-10-20 | | Graphiti | https://github.com/getzep/graphiti | Apache-2.0 | declared | 2026-10-20 | | LangChain | https://github.com/langchain-ai/langchain | MIT | declared | 2026-10-20 | @@ -42,7 +42,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | OpenCode | https://github.com/anomalyco/opencode | MIT | declared | 2026-10-20 | | Cline | https://github.com/cline/cline | Apache-2.0 | declared | 2026-10-20 | | Open Code Review | https://github.com/alibaba/open-code-review | Apache-2.0 | declared | 2026-10-20 | -| PR-Agent | https://github.com/The-PR-Agent/pr-agent | MIT | declared | 2026-10-20 | +| PR-Agent | https://github.com/The-PR-Agent/pr-agent | MIT | declared | 2026-10-21 | | Dify | https://github.com/langgenius/dify | Dify Open Source License (Apache-2.0 + conditions) | needs-review | 2026-10-20 | | Flowise | https://github.com/FlowiseAI/Flowise | Apache-2.0 (enterprise dir separate) | needs-review | 2026-10-20 | | Langflow | https://github.com/langflow-ai/langflow | MIT | declared | 2026-10-20 | @@ -55,7 +55,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | Milvus | https://github.com/milvus-io/milvus | Apache-2.0 | declared | 2026-10-20 | | Weaviate | https://github.com/weaviate/weaviate | BSD-3-Clause (core) | needs-review | 2026-10-20 | | Langfuse | https://github.com/langfuse/langfuse | MIT (ee/ dirs separate) | needs-review | 2026-10-20 | -| Phoenix | https://github.com/Arize-ai/phoenix | Elastic-2.0 | declared | 2026-10-20 | +| Phoenix | https://github.com/Arize-ai/phoenix | Elastic-2.0 | needs-review | 2026-10-20 | | promptfoo | https://github.com/promptfoo/promptfoo | MIT | declared | 2026-10-20 | | DeepEval | https://github.com/confident-ai/deepeval | Apache-2.0 | declared | 2026-10-20 | | Butterbase | https://github.com/butterbase-ai/butterbase | Apache-2.0 | declared | 2026-10-20 | @@ -65,9 +65,9 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | One Person Company | https://github.com/tashfeenahmed/OnePersonCompany | MIT | declared | 2026-10-20 | | Kinetic | https://github.com/tashfeenahmed/kinetic | MIT | declared | 2026-10-20 | | CircleChat | https://github.com/tashfeenahmed/circlechat | MIT | declared | 2026-10-20 | -| AgentDomains | https://github.com/tashfeenahmed/AgentDomains | FSL-1.1-Apache-2.0 | declared | 2026-10-20 | -| AgentDomains MCP | https://github.com/tashfeenahmed/AgentDomains-mcp | FSL-1.1-Apache-2.0 | declared | 2026-10-20 | -| AgentDomains Skill | https://github.com/tashfeenahmed/AgentDomains-skill | FSL-1.1-Apache-2.0 | declared | 2026-10-20 | +| AgentDomains | https://github.com/tashfeenahmed/AgentDomains | FSL-1.1-Apache-2.0 | needs-review | 2026-10-20 | +| AgentDomains MCP | https://github.com/tashfeenahmed/AgentDomains-mcp | FSL-1.1-Apache-2.0 | needs-review | 2026-10-20 | +| AgentDomains Skill | https://github.com/tashfeenahmed/AgentDomains-skill | FSL-1.1-Apache-2.0 | needs-review | 2026-10-20 | | ScallopBot | https://github.com/tashfeenahmed/scallopbot | MIT | declared | 2026-10-20 | | Cashmaxx | https://github.com/tashfeenahmed/cashmaxx | MIT | declared | 2026-10-20 | | Jev Deep Research | https://github.com/tashfeenahmed/jev-deepresearch | MIT | declared | 2026-10-20 | diff --git a/catalog/evidence/agentdomains-mcp.json b/catalog/evidence/agentdomains-mcp.json index 062f880..b1ee272 100644 --- a/catalog/evidence/agentdomains-mcp.json +++ b/catalog/evidence/agentdomains-mcp.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/AgentDomains-mcp", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "agentdomains-mcp", "last_commit": "2026-09-30T13:17:04Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/AgentDomains-mcp/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-09-30T13:17:04Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/AgentDomains-mcp", "stars": 2, "state": "active" diff --git a/catalog/evidence/agentdomains-skill.json b/catalog/evidence/agentdomains-skill.json index e34e60f..e796c81 100644 --- a/catalog/evidence/agentdomains-skill.json +++ b/catalog/evidence/agentdomains-skill.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/AgentDomains-skill", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "agentdomains-skill", "last_commit": "2026-10-17T20:25:20Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/AgentDomains-skill/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-10-17T20:25:23Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/AgentDomains-skill", "stars": 10, "state": "active" diff --git a/catalog/evidence/agentdomains.json b/catalog/evidence/agentdomains.json index 4821f19..b256bde 100644 --- a/catalog/evidence/agentdomains.json +++ b/catalog/evidence/agentdomains.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/AgentDomains", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "agentdomains", "last_commit": "2026-10-17T19:16:41Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/AgentDomains/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-10-17T20:24:07Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/AgentDomains", "stars": 39, "state": "active" diff --git a/catalog/evidence/agno.json b/catalog/evidence/agno.json index b2a37ae..adb32cd 100644 --- a/catalog/evidence/agno.json +++ b/catalog/evidence/agno.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/agno-agi/agno", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "agno", "last_commit": "2026-10-20T16:30:55Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/agno-agi/agno/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T16:31:36Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/agno-agi/agno", "stars": 42836, "state": "active" diff --git a/catalog/evidence/aider.json b/catalog/evidence/aider.json index 8d1290a..91d2fe6 100644 --- a/catalog/evidence/aider.json +++ b/catalog/evidence/aider.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/Aider-AI/aider", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "aider", "last_commit": "2026-05-22T14:02:20Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/Aider-AI/aider/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-05-22T14:02:20Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/Aider-AI/aider", "stars": 49663, "state": "active" diff --git a/catalog/evidence/autogen.json b/catalog/evidence/autogen.json index 9e05c54..4f80131 100644 --- a/catalog/evidence/autogen.json +++ b/catalog/evidence/autogen.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/microsoft/autogen", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "autogen", "last_commit": "2026-10-16T16:14:36Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/microsoft/autogen/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-16T16:14:37Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/microsoft/autogen", "stars": 61497, "state": "active" diff --git a/catalog/evidence/awesome-llm-apps.json b/catalog/evidence/awesome-llm-apps.json index 872651a..fa0c3c8 100644 --- a/catalog/evidence/awesome-llm-apps.json +++ b/catalog/evidence/awesome-llm-apps.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/Shubhamsaboo/awesome-llm-apps", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "awesome-llm-apps", "last_commit": "2026-10-18T16:28:46Z", "latest_release": null, @@ -9,9 +13,10 @@ "source": "https://api.github.com/repos/Shubhamsaboo/awesome-llm-apps/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-18T16:28:46Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/Shubhamsaboo/awesome-llm-apps", - "stars": 142403, + "stars": 142406, "state": "active" } diff --git a/catalog/evidence/bifrost.json b/catalog/evidence/bifrost.json index ed3dd4e..996b712 100644 --- a/catalog/evidence/bifrost.json +++ b/catalog/evidence/bifrost.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/maximhq/bifrost", "default_branch": "dev", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "bifrost", "last_commit": "2026-10-19T12:11:40Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/maximhq/bifrost/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T18:52:39Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/maximhq/bifrost", - "stars": 8965, + "stars": 8966, "state": "active" } diff --git a/catalog/evidence/butterbase.json b/catalog/evidence/butterbase.json index 1b87f10..6f592a8 100644 --- a/catalog/evidence/butterbase.json +++ b/catalog/evidence/butterbase.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/butterbase-ai/butterbase", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "butterbase", "last_commit": "2026-10-20T04:36:50Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/butterbase-ai/butterbase/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T04:36:50Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/butterbase-ai/butterbase", "stars": 3112, "state": "active" diff --git a/catalog/evidence/cashmaxx.json b/catalog/evidence/cashmaxx.json index 0d14430..6ee705d 100644 --- a/catalog/evidence/cashmaxx.json +++ b/catalog/evidence/cashmaxx.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/cashmaxx", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "cashmaxx", "last_commit": "2026-10-04T18:36:50Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/cashmaxx/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-04T18:36:51Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/cashmaxx", "stars": 2, "state": "active" diff --git a/catalog/evidence/chatbot-ui.json b/catalog/evidence/chatbot-ui.json index 14cecd9..6cff22d 100644 --- a/catalog/evidence/chatbot-ui.json +++ b/catalog/evidence/chatbot-ui.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/mckaywrigley/chatbot-ui", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "chatbot-ui", "last_commit": "2024-06-22T17:14:46Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/mckaywrigley/chatbot-ui/license", "state": "detected" }, + "moved": false, "pushed_at": "2024-08-03T00:38:07Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/mckaywrigley/chatbot-ui", "stars": 33323, "state": "active" diff --git a/catalog/evidence/chroma.json b/catalog/evidence/chroma.json index 71c714d..29e0049 100644 --- a/catalog/evidence/chroma.json +++ b/catalog/evidence/chroma.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/chroma-core/chroma", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "chroma", "last_commit": "2026-10-17T21:37:30Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/chroma-core/chroma/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T03:43:25Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/chroma-core/chroma", "stars": 29540, "state": "active" diff --git a/catalog/evidence/circlechat.json b/catalog/evidence/circlechat.json index 3b4a4b7..7a52a61 100644 --- a/catalog/evidence/circlechat.json +++ b/catalog/evidence/circlechat.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/circlechat", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "circlechat", "last_commit": "2026-09-30T13:10:04Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/circlechat/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-19T03:34:06Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/circlechat", "stars": 81, "state": "active" diff --git a/catalog/evidence/cline.json b/catalog/evidence/cline.json index ccbe225..b2b5e79 100644 --- a/catalog/evidence/cline.json +++ b/catalog/evidence/cline.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/cline/cline", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "cline", "last_commit": "2026-10-20T12:01:16Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/cline/cline/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:46:30Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:51:36Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/cline/cline", - "stars": 70847, + "stars": 70722, "state": "active" } diff --git a/catalog/evidence/continue.json b/catalog/evidence/continue.json index 552523d..8247e0e 100644 --- a/catalog/evidence/continue.json +++ b/catalog/evidence/continue.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/continuedev/continue", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "continue", "last_commit": "2026-07-21T04:00:09Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/continuedev/continue/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T14:30:21Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/continuedev/continue", "stars": 36273, "state": "active" diff --git a/catalog/evidence/crewai.json b/catalog/evidence/crewai.json index 06ff8cc..bab8342 100644 --- a/catalog/evidence/crewai.json +++ b/catalog/evidence/crewai.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/crewAIInc/crewAI", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "crewai", "last_commit": "2026-10-20T18:27:26Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/crewAIInc/crewAI/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T18:27:29Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/crewAIInc/crewAI", - "stars": 59921, + "stars": 59922, "state": "active" } diff --git a/catalog/evidence/deepeval.json b/catalog/evidence/deepeval.json index dad8beb..571fc7e 100644 --- a/catalog/evidence/deepeval.json +++ b/catalog/evidence/deepeval.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/confident-ai/deepeval", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "deepeval", "last_commit": "2026-10-19T06:25:00Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/confident-ai/deepeval/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-19T06:25:04Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/confident-ai/deepeval", "stars": 18991, "state": "active" diff --git a/catalog/evidence/dify.json b/catalog/evidence/dify.json index b487072..a3d4a7d 100644 --- a/catalog/evidence/dify.json +++ b/catalog/evidence/dify.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/langgenius/dify", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "dify", "last_commit": "2026-10-20T14:44:34Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/langgenius/dify/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-10-20T16:10:29Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/langgenius/dify", - "stars": 159045, + "stars": 159048, "state": "active" } diff --git a/catalog/evidence/emotion-state.json b/catalog/evidence/emotion-state.json index 1336726..0548f76 100644 --- a/catalog/evidence/emotion-state.json +++ b/catalog/evidence/emotion-state.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/emotion-state", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "emotion-state", "last_commit": "2026-02-05T11:01:42Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/emotion-state/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-02-05T11:01:48Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/emotion-state", "stars": 0, "state": "active" diff --git a/catalog/evidence/flowise.json b/catalog/evidence/flowise.json index 8c70989..6458f96 100644 --- a/catalog/evidence/flowise.json +++ b/catalog/evidence/flowise.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/FlowiseAI/Flowise", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "flowise", "last_commit": "2026-08-13T12:38:19Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/FlowiseAI/Flowise/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-08-13T12:38:19Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/FlowiseAI/Flowise", "stars": 55510, "state": "archived" diff --git a/catalog/evidence/freellmapi.json b/catalog/evidence/freellmapi.json index 087c55d..76c4a39 100644 --- a/catalog/evidence/freellmapi.json +++ b/catalog/evidence/freellmapi.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/freellmapi", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "freellmapi", "last_commit": "2026-10-20T12:53:36Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/tashfeenahmed/freellmapi/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T17:51:09Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/freellmapi", - "stars": 38195, + "stars": 38219, "state": "active" } diff --git a/catalog/evidence/gpt4all.json b/catalog/evidence/gpt4all.json index 0858758..4624e13 100644 --- a/catalog/evidence/gpt4all.json +++ b/catalog/evidence/gpt4all.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/nomic-ai/gpt4all", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "gpt4all", "last_commit": "2025-05-27T19:46:52Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/nomic-ai/gpt4all/license", "state": "detected" }, + "moved": false, "pushed_at": "2025-05-27T20:05:19Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/nomic-ai/gpt4all", "stars": 77350, "state": "active" diff --git a/catalog/evidence/graphiti.json b/catalog/evidence/graphiti.json index 66aa89c..e4ce97a 100644 --- a/catalog/evidence/graphiti.json +++ b/catalog/evidence/graphiti.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/getzep/graphiti", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "graphiti", "last_commit": "2026-10-20T18:21:34Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/getzep/graphiti/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T18:21:36Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/getzep/graphiti", "stars": 32084, "state": "active" diff --git a/catalog/evidence/haystack.json b/catalog/evidence/haystack.json index 5c388d2..5492fe4 100644 --- a/catalog/evidence/haystack.json +++ b/catalog/evidence/haystack.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/deepset-ai/haystack", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "haystack", "last_commit": "2026-10-20T14:21:50Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/deepset-ai/haystack/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T14:22:40Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/deepset-ai/haystack", "stars": 26792, "state": "active" diff --git a/catalog/evidence/html-email-template.json b/catalog/evidence/html-email-template.json index 69b5803..84d2a5d 100644 --- a/catalog/evidence/html-email-template.json +++ b/catalog/evidence/html-email-template.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/html-email-template", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "html-email-template", "last_commit": "2021-09-19T14:40:46Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/html-email-template/license", "state": "detected" }, + "moved": false, "pushed_at": "2021-09-19T14:40:46Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/html-email-template", "stars": 1, "state": "active" diff --git a/catalog/evidence/jev-deepresearch.json b/catalog/evidence/jev-deepresearch.json index cd6682d..6f7d90b 100644 --- a/catalog/evidence/jev-deepresearch.json +++ b/catalog/evidence/jev-deepresearch.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/jev-deepresearch", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "jev-deepresearch", "last_commit": "2026-09-22T10:35:28Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/jev-deepresearch/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-09-22T10:35:33Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/jev-deepresearch", "stars": 2, "state": "active" diff --git a/catalog/evidence/kinetic.json b/catalog/evidence/kinetic.json index 0d3049b..115cb37 100644 --- a/catalog/evidence/kinetic.json +++ b/catalog/evidence/kinetic.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/kinetic", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "kinetic", "last_commit": "2026-10-15T07:29:12Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/kinetic/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-19T16:18:55Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/kinetic", "stars": 7, "state": "active" diff --git a/catalog/evidence/langchain.json b/catalog/evidence/langchain.json index 274d672..b9f5ad4 100644 --- a/catalog/evidence/langchain.json +++ b/catalog/evidence/langchain.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/langchain-ai/langchain", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "langchain", "last_commit": "2026-10-20T15:51:22Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/langchain-ai/langchain/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T18:35:35Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/langchain-ai/langchain", - "stars": 148141, + "stars": 148143, "state": "active" } diff --git a/catalog/evidence/langflow.json b/catalog/evidence/langflow.json index 15a1d69..a7aa06d 100644 --- a/catalog/evidence/langflow.json +++ b/catalog/evidence/langflow.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/langflow-ai/langflow", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "langflow", "last_commit": "2026-10-16T02:13:02Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/langflow-ai/langflow/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:52:04Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:47:30Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/langflow-ai/langflow", - "stars": 155879, + "stars": 155872, "state": "active" } diff --git a/catalog/evidence/langfuse.json b/catalog/evidence/langfuse.json index 01de025..c0888e0 100644 --- a/catalog/evidence/langfuse.json +++ b/catalog/evidence/langfuse.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/langfuse/langfuse", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "langfuse", "last_commit": "2026-10-20T18:26:33Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/langfuse/langfuse/license", "state": "needs-review" }, - "pushed_at": "2026-10-20T18:37:59Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:29:47Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/langfuse/langfuse", - "stars": 36093, + "stars": 36095, "state": "active" } diff --git a/catalog/evidence/langgraph.json b/catalog/evidence/langgraph.json index d99b0c6..dbd2044 100644 --- a/catalog/evidence/langgraph.json +++ b/catalog/evidence/langgraph.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/langchain-ai/langgraph", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "langgraph", "last_commit": "2026-10-20T10:09:26Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/langchain-ai/langgraph/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T10:09:29Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/langchain-ai/langgraph", - "stars": 43590, + "stars": 43592, "state": "active" } diff --git a/catalog/evidence/letta.json b/catalog/evidence/letta.json index 2da6672..5c96059 100644 --- a/catalog/evidence/letta.json +++ b/catalog/evidence/letta.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/letta-ai/letta", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "letta", "last_commit": "2026-10-18T22:28:01Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/letta-ai/letta/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-18T22:28:04Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/letta-ai/letta", "stars": 25206, "state": "active" diff --git a/catalog/evidence/librechat.json b/catalog/evidence/librechat.json index ce92482..b2372b1 100644 --- a/catalog/evidence/librechat.json +++ b/catalog/evidence/librechat.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/LibreChat-AI/LibreChat", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "librechat", "last_commit": "2026-10-17T04:30:44Z", "latest_release": null, @@ -9,9 +13,10 @@ "source": "https://api.github.com/repos/LibreChat-AI/LibreChat/license", "state": "detected" }, - "pushed_at": "2026-10-20T17:22:59Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:42:39Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/LibreChat-AI/LibreChat", - "stars": 46072, + "stars": 46075, "state": "active" } diff --git a/catalog/evidence/litellm.json b/catalog/evidence/litellm.json index fe27bb6..a2ad2c8 100644 --- a/catalog/evidence/litellm.json +++ b/catalog/evidence/litellm.json @@ -1,20 +1,25 @@ { "canonical_repo": "https://github.com/BerriAI/litellm", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "litellm", - "last_commit": "2026-10-20T18:46:17Z", + "last_commit": "2026-10-20T19:49:58Z", "latest_release": { - "published_at": "2026-10-18T05:53:32Z", - "tag": "v1.106.0" + "published_at": "2026-10-20T18:58:28Z", + "tag": "v1.106.1" }, "license": { "github_spdx": "NOASSERTION", "source": "https://api.github.com/repos/BerriAI/litellm/license", "state": "needs-review" }, - "pushed_at": "2026-10-20T18:51:47Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:50:12Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/BerriAI/litellm", - "stars": 61665, + "stars": 61667, "state": "active" } diff --git a/catalog/evidence/llama-index.json b/catalog/evidence/llama-index.json index a8dc58c..3cf0738 100644 --- a/catalog/evidence/llama-index.json +++ b/catalog/evidence/llama-index.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/run-llama/llama_index", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "llama-index", "last_commit": "2026-10-14T15:29:28Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/run-llama/llama_index/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T07:12:17Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/run-llama/llama_index", "stars": 52582, "state": "active" diff --git a/catalog/evidence/llama.cpp.json b/catalog/evidence/llama.cpp.json index de9f539..3e0128b 100644 --- a/catalog/evidence/llama.cpp.json +++ b/catalog/evidence/llama.cpp.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/ggml-org/llama.cpp", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "llama.cpp", - "last_commit": "2026-10-20T17:36:14Z", + "last_commit": "2026-10-20T19:09:56Z", "latest_release": { "published_at": "2026-10-15T17:13:19Z", "tag": "v0.7.0" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/ggml-org/llama.cpp/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:32:20Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:09:57Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/ggml-org/llama.cpp", - "stars": 131831, + "stars": 131832, "state": "active" } diff --git a/catalog/evidence/llamafile.json b/catalog/evidence/llamafile.json index 4a58023..84d779b 100644 --- a/catalog/evidence/llamafile.json +++ b/catalog/evidence/llamafile.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/mozilla-ai/llamafile", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "llamafile", "last_commit": "2026-10-08T19:53:38Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/mozilla-ai/llamafile/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-10-12T00:26:41Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/mozilla-ai/llamafile", - "stars": 26446, + "stars": 26442, "state": "active" } diff --git a/catalog/evidence/lobe-chat.json b/catalog/evidence/lobe-chat.json index 31d86e6..318799e 100644 --- a/catalog/evidence/lobe-chat.json +++ b/catalog/evidence/lobe-chat.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/lobehub/lobehub", "default_branch": "canary", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "lobe-chat", - "last_commit": "2026-10-20T18:14:50Z", + "last_commit": "2026-10-20T19:25:33Z", "latest_release": { "published_at": "2026-10-18T03:18:40Z", "tag": "v2.2.20" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/lobehub/lobehub/license", "state": "needs-review" }, - "pushed_at": "2026-10-20T18:44:38Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:45:58Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/lobehub/lobehub", - "stars": 83357, + "stars": 83359, "state": "active" } diff --git a/catalog/evidence/localai.json b/catalog/evidence/localai.json index fcadaba..2b51c65 100644 --- a/catalog/evidence/localai.json +++ b/catalog/evidence/localai.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/mudler/LocalAI", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "localai", "last_commit": "2026-10-20T16:09:02Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/mudler/LocalAI/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T17:23:06Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/mudler/LocalAI", - "stars": 49788, + "stars": 49791, "state": "active" } diff --git a/catalog/evidence/magictap.json b/catalog/evidence/magictap.json index fa7e61d..bd4fb47 100644 --- a/catalog/evidence/magictap.json +++ b/catalog/evidence/magictap.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/magictap", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "magictap", "last_commit": "2026-10-14T11:06:50Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/magictap/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-14T11:06:51Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/magictap", "stars": 1, "state": "active" diff --git a/catalog/evidence/mem0.json b/catalog/evidence/mem0.json index 9f1cbc4..b623e4a 100644 --- a/catalog/evidence/mem0.json +++ b/catalog/evidence/mem0.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/mem0ai/mem0", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "mem0", "last_commit": "2026-10-14T15:39:50Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/mem0ai/mem0/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T01:47:59Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/mem0ai/mem0", - "stars": 67527, + "stars": 67529, "state": "active" } diff --git a/catalog/evidence/milvus.json b/catalog/evidence/milvus.json index 5ecc658..a807aeb 100644 --- a/catalog/evidence/milvus.json +++ b/catalog/evidence/milvus.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/milvus-io/milvus", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "milvus", "last_commit": "2026-10-20T17:51:51Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/milvus-io/milvus/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T17:51:51Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/milvus-io/milvus", "stars": 46447, "state": "active" diff --git a/catalog/evidence/n8n.json b/catalog/evidence/n8n.json index c27b1df..7ff057c 100644 --- a/catalog/evidence/n8n.json +++ b/catalog/evidence/n8n.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/n8n-io/n8n", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "n8n", "last_commit": "2026-10-20T18:18:00Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/n8n-io/n8n/license", "state": "needs-review" }, - "pushed_at": "2026-10-20T18:41:01Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:50:32Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/n8n-io/n8n", - "stars": 208141, + "stars": 208143, "state": "active" } diff --git a/catalog/evidence/ollama.json b/catalog/evidence/ollama.json index 5b14a2c..f5bc1a5 100644 --- a/catalog/evidence/ollama.json +++ b/catalog/evidence/ollama.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/ollama/ollama", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "ollama", - "last_commit": "2026-10-20T16:56:18Z", + "last_commit": "2026-10-20T19:19:18Z", "latest_release": { "published_at": "2026-10-16T22:00:46Z", "tag": "v0.40.6" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/ollama/ollama/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:14:17Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:19:18Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/ollama/ollama", - "stars": 184138, + "stars": 184065, "state": "active" } diff --git a/catalog/evidence/one-person-company.json b/catalog/evidence/one-person-company.json index 6266c73..fa0f288 100644 --- a/catalog/evidence/one-person-company.json +++ b/catalog/evidence/one-person-company.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/OnePersonCompany", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "one-person-company", "last_commit": "2026-10-06T16:28:26Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/OnePersonCompany/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-19T20:22:56Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/OnePersonCompany", "stars": 40, "state": "active" diff --git a/catalog/evidence/open-code-review.json b/catalog/evidence/open-code-review.json index a618196..e9d467c 100644 --- a/catalog/evidence/open-code-review.json +++ b/catalog/evidence/open-code-review.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/alibaba/open-code-review", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "open-code-review", "last_commit": "2026-10-20T09:50:03Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/alibaba/open-code-review/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T09:50:03Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/alibaba/open-code-review", "stars": 47720, "state": "active" diff --git a/catalog/evidence/open-webui.json b/catalog/evidence/open-webui.json index cacea53..342a352 100644 --- a/catalog/evidence/open-webui.json +++ b/catalog/evidence/open-webui.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/open-webui/open-webui", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "open-webui", "last_commit": "2026-10-16T11:46:08Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/open-webui/open-webui/license", "state": "needs-review" }, - "pushed_at": "2026-10-20T18:44:44Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:46:36Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/open-webui/open-webui", - "stars": 156277, + "stars": 156280, "state": "active" } diff --git a/catalog/evidence/opencode-free-9router.json b/catalog/evidence/opencode-free-9router.json index 17f9907..24113f5 100644 --- a/catalog/evidence/opencode-free-9router.json +++ b/catalog/evidence/opencode-free-9router.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/0xgetz/opencode-free-9router", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "opencode-free-9router", "last_commit": "2026-10-17T13:49:38Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/0xgetz/opencode-free-9router/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-17T13:49:39Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/0xgetz/opencode-free-9router", "stars": 45, "state": "active" diff --git a/catalog/evidence/opencode.json b/catalog/evidence/opencode.json index f59b8d7..3074881 100644 --- a/catalog/evidence/opencode.json +++ b/catalog/evidence/opencode.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/anomalyco/opencode", "default_branch": "dev", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "opencode", - "last_commit": "2026-10-20T18:19:00Z", + "last_commit": "2026-10-20T19:04:31Z", "latest_release": { "published_at": "2026-10-16T12:31:52Z", "tag": "v1.19.3" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/anomalyco/opencode/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:49:02Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:52:23Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/anomalyco/opencode", - "stars": 218703, + "stars": 218736, "state": "active" } diff --git a/catalog/evidence/openhands.json b/catalog/evidence/openhands.json index b73c4d7..ed6462b 100644 --- a/catalog/evidence/openhands.json +++ b/catalog/evidence/openhands.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/OpenHands/OpenHands", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "openhands", - "last_commit": "2026-10-20T18:27:33Z", + "last_commit": "2026-10-20T19:37:27Z", "latest_release": { "published_at": "2026-10-19T17:09:42Z", "tag": "v1.28.1" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/OpenHands/OpenHands/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:45:14Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:49:18Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/OpenHands/OpenHands", - "stars": 91398, + "stars": 91402, "state": "active" } diff --git a/catalog/evidence/openhuman.json b/catalog/evidence/openhuman.json index 7cd3c99..88a5fb4 100644 --- a/catalog/evidence/openhuman.json +++ b/catalog/evidence/openhuman.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tinyhumansai/openhuman", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "openhuman", "last_commit": "2026-10-20T17:27:42Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/tinyhumansai/openhuman/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T17:27:42Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tinyhumansai/openhuman", - "stars": 42189, + "stars": 42190, "state": "active" } diff --git a/catalog/evidence/openmemory.json b/catalog/evidence/openmemory.json index 994cb66..b4a4114 100644 --- a/catalog/evidence/openmemory.json +++ b/catalog/evidence/openmemory.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/mem0ai/openmemory", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "openmemory", "last_commit": "2026-07-29T09:40:39Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/mem0ai/openmemory/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-07-29T09:40:39Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/mem0ai/openmemory", "stars": 98, "state": "active" diff --git a/catalog/evidence/phoenix.json b/catalog/evidence/phoenix.json index 633b4ba..473e840 100644 --- a/catalog/evidence/phoenix.json +++ b/catalog/evidence/phoenix.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/Arize-ai/phoenix", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "phoenix", - "last_commit": "2026-10-20T17:52:16Z", + "last_commit": "2026-10-20T19:54:26Z", "latest_release": { "published_at": "2026-10-19T16:42:17Z", "tag": "arize-phoenix-sqlean-v0.2.1" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/Arize-ai/phoenix/license", "state": "needs-review" }, - "pushed_at": "2026-10-20T18:43:03Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:54:29Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/Arize-ai/phoenix", - "stars": 11925, + "stars": 11926, "state": "active" } diff --git a/catalog/evidence/pocketbase.json b/catalog/evidence/pocketbase.json index 6dc35bf..35777f8 100644 --- a/catalog/evidence/pocketbase.json +++ b/catalog/evidence/pocketbase.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/pocketbase/pocketbase", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "pocketbase", "last_commit": "2026-10-08T16:21:49Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/pocketbase/pocketbase/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-14T18:45:14Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/pocketbase/pocketbase", - "stars": 61510, + "stars": 61511, "state": "active" } diff --git a/catalog/evidence/portkey-gateway.json b/catalog/evidence/portkey-gateway.json index 466552c..a8ad57c 100644 --- a/catalog/evidence/portkey-gateway.json +++ b/catalog/evidence/portkey-gateway.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/Portkey-AI/gateway", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "portkey-gateway", "last_commit": "2026-05-25T13:54:51Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/Portkey-AI/gateway/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-05-25T13:54:51Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/Portkey-AI/gateway", - "stars": 13233, + "stars": 13232, "state": "active" } diff --git a/catalog/evidence/pr-agent.json b/catalog/evidence/pr-agent.json index 412c9e6..f4dc86f 100644 --- a/catalog/evidence/pr-agent.json +++ b/catalog/evidence/pr-agent.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/The-PR-Agent/pr-agent", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "pr-agent", "last_commit": "2026-10-20T12:31:35Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/The-PR-Agent/pr-agent/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T12:31:35Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/The-PR-Agent/pr-agent", - "stars": 13502, + "stars": 13505, "state": "active" } diff --git a/catalog/evidence/promptfoo.json b/catalog/evidence/promptfoo.json index 434915d..303122d 100644 --- a/catalog/evidence/promptfoo.json +++ b/catalog/evidence/promptfoo.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/promptfoo/promptfoo", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "promptfoo", "last_commit": "2026-10-20T15:41:20Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/promptfoo/promptfoo/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T17:04:08Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/promptfoo/promptfoo", - "stars": 26191, + "stars": 26192, "state": "active" } diff --git a/catalog/evidence/pyreality.json b/catalog/evidence/pyreality.json index c469aef..abbb24f 100644 --- a/catalog/evidence/pyreality.json +++ b/catalog/evidence/pyreality.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/pyreality", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "pyreality", "last_commit": "2021-07-31T19:25:13Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/pyreality/license", "state": "detected" }, + "moved": false, "pushed_at": "2021-07-31T19:25:13Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/pyreality", "stars": 1, "state": "active" diff --git a/catalog/evidence/qdrant.json b/catalog/evidence/qdrant.json index 6416474..1963972 100644 --- a/catalog/evidence/qdrant.json +++ b/catalog/evidence/qdrant.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/qdrant/qdrant", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "qdrant", "last_commit": "2026-10-05T10:03:16Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/qdrant/qdrant/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T16:36:27Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/qdrant/qdrant", - "stars": 35158, + "stars": 35159, "state": "active" } diff --git a/catalog/evidence/ragflow.json b/catalog/evidence/ragflow.json index 58f9f6c..c4652cb 100644 --- a/catalog/evidence/ragflow.json +++ b/catalog/evidence/ragflow.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/infiniflow/ragflow", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "ragflow", "last_commit": "2026-10-20T11:43:57Z", "latest_release": { @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/infiniflow/ragflow/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-20T13:15:28Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/infiniflow/ragflow", - "stars": 92544, + "stars": 92545, "state": "active" } diff --git a/catalog/evidence/scallopbot.json b/catalog/evidence/scallopbot.json index 6f0bb58..21f3ab9 100644 --- a/catalog/evidence/scallopbot.json +++ b/catalog/evidence/scallopbot.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/tashfeenahmed/scallopbot", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "scallopbot", "last_commit": "2026-10-16T20:14:28Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/tashfeenahmed/scallopbot/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-16T20:14:32Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/tashfeenahmed/scallopbot", "stars": 50, "state": "active" diff --git a/catalog/evidence/sglang.json b/catalog/evidence/sglang.json index 6f4f2e0..bc5ad6d 100644 --- a/catalog/evidence/sglang.json +++ b/catalog/evidence/sglang.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/sgl-project/sglang", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "sglang", - "last_commit": "2026-10-20T18:49:05Z", + "last_commit": "2026-10-20T19:05:14Z", "latest_release": { "published_at": "2026-10-19T02:55:19Z", "tag": "v0.5.22" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/sgl-project/sglang/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:49:05Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:05:14Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/sgl-project/sglang", - "stars": 37506, + "stars": 37510, "state": "active" } diff --git a/catalog/evidence/smolagents.json b/catalog/evidence/smolagents.json index a3986ef..f4d299a 100644 --- a/catalog/evidence/smolagents.json +++ b/catalog/evidence/smolagents.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/huggingface/smolagents", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "smolagents", "last_commit": "2026-10-06T09:38:53Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/huggingface/smolagents/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-06T18:35:07Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/huggingface/smolagents", "stars": 29949, "state": "active" diff --git a/catalog/evidence/supabase.json b/catalog/evidence/supabase.json index b3a2b2e..54483cf 100644 --- a/catalog/evidence/supabase.json +++ b/catalog/evidence/supabase.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/supabase/supabase", "default_branch": "master", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "supabase", - "last_commit": "2026-10-20T18:52:57Z", + "last_commit": "2026-10-20T19:31:12Z", "latest_release": { "published_at": "2026-08-07T13:57:57Z", "tag": "v1.26.08" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/supabase/supabase/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:53:01Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:31:15Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/supabase/supabase", - "stars": 112360, + "stars": 112377, "state": "active" } diff --git a/catalog/evidence/text-generation-inference.json b/catalog/evidence/text-generation-inference.json index 552de6b..b969b81 100644 --- a/catalog/evidence/text-generation-inference.json +++ b/catalog/evidence/text-generation-inference.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/huggingface/text-generation-inference", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "text-generation-inference", "last_commit": "2026-03-21T11:34:22Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/huggingface/text-generation-inference/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-03-21T11:34:22Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/huggingface/text-generation-inference", "stars": 10880, "state": "archived" diff --git a/catalog/evidence/text-generation-webui.json b/catalog/evidence/text-generation-webui.json index 5419162..db2dab3 100644 --- a/catalog/evidence/text-generation-webui.json +++ b/catalog/evidence/text-generation-webui.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/oobabooga/textgen", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "text-generation-webui", "last_commit": "2026-08-17T17:38:15Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/oobabooga/textgen/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-08-17T17:38:16Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/oobabooga/textgen", "stars": 47737, "state": "active" diff --git a/catalog/evidence/triton-server.json b/catalog/evidence/triton-server.json index 365f045..f25d415 100644 --- a/catalog/evidence/triton-server.json +++ b/catalog/evidence/triton-server.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/triton-inference-server/server", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "triton-server", "last_commit": "2026-10-15T11:04:01Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/triton-inference-server/server/license", "state": "detected" }, + "moved": false, "pushed_at": "2026-10-19T18:43:09Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/triton-inference-server/server", "stars": 11099, "state": "active" diff --git a/catalog/evidence/trylon-gateway.json b/catalog/evidence/trylon-gateway.json index d55ddf6..232198f 100644 --- a/catalog/evidence/trylon-gateway.json +++ b/catalog/evidence/trylon-gateway.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/trylonai/gateway", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "trylon-gateway", "last_commit": "2025-06-25T10:01:42Z", "latest_release": null, @@ -9,8 +13,9 @@ "source": "https://api.github.com/repos/trylonai/gateway/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2025-06-25T10:01:46Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/trylonai/gateway", "stars": 179, "state": "active" diff --git a/catalog/evidence/vllm.json b/catalog/evidence/vllm.json index f3455e6..32a4a47 100644 --- a/catalog/evidence/vllm.json +++ b/catalog/evidence/vllm.json @@ -1,8 +1,12 @@ { "canonical_repo": "https://github.com/vllm-project/vllm", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "vllm", - "last_commit": "2026-10-20T18:29:35Z", + "last_commit": "2026-10-20T19:48:27Z", "latest_release": { "published_at": "2026-10-18T06:50:48Z", "tag": "v0.32.0" @@ -12,9 +16,10 @@ "source": "https://api.github.com/repos/vllm-project/vllm/license", "state": "detected" }, - "pushed_at": "2026-10-20T18:47:33Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "moved": false, + "pushed_at": "2026-10-20T19:48:28Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/vllm-project/vllm", - "stars": 94371, + "stars": 94384, "state": "active" } diff --git a/catalog/evidence/weaviate.json b/catalog/evidence/weaviate.json index c4b60f5..d261637 100644 --- a/catalog/evidence/weaviate.json +++ b/catalog/evidence/weaviate.json @@ -1,6 +1,10 @@ { "canonical_repo": "https://github.com/weaviate/weaviate", "default_branch": "main", + "fetch_status": { + "at": "2026-10-20T19:54:06Z", + "result": "ok" + }, "id": "weaviate", "last_commit": "2026-10-16T08:22:16Z", "latest_release": { @@ -12,8 +16,9 @@ "source": "https://api.github.com/repos/weaviate/weaviate/license", "state": "needs-review" }, + "moved": false, "pushed_at": "2026-10-20T14:33:33Z", - "retrieved_at": "2026-10-20T18:52:53Z", + "retrieved_at": "2026-10-20T19:54:06Z", "source": "https://api.github.com/repos/weaviate/weaviate", "stars": 16893, "state": "active" diff --git a/catalog/projects.yaml b/catalog/projects.yaml index efcdb00..abf16c9 100644 --- a/catalog/projects.yaml +++ b/catalog/projects.yaml @@ -75,9 +75,10 @@ projects: license: spdx: BUSL-1.1 label: BUSL-1.1 - state: declared + state: needs-review evidence_url: https://github.com/trylonai/gateway/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Source-available, not OSI: Business Source License 1.1 with a use limitation (upstream LICENSE).' setup_url: https://github.com/trylonai/gateway#readme editorial: highlight: Guardrails / security @@ -98,6 +99,7 @@ projects: state: needs-review evidence_url: https://github.com/BerriAI/litellm/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Multiple licences: MIT for most code, separate licence for the enterprise/ directory (stated at top of upstream LICENSE).' setup_url: https://github.com/BerriAI/litellm#readme editorial: highlight: Broadest provider coverage @@ -141,6 +143,7 @@ projects: state: needs-review evidence_url: https://github.com/open-webui/open-webui/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Custom licence: BSD-3-style terms plus a clause forbidding removal or alteration of Open WebUI branding (upstream LICENSE).' setup_url: https://github.com/open-webui/open-webui#readme editorial: highlight: RAG, multi-user, plugins @@ -161,6 +164,7 @@ projects: state: needs-review evidence_url: https://github.com/lobehub/lobehub/blob/canary/LICENSE checked: '2026-10-20' + review_reason: 'Custom licence: LobeHub Community License, Apache-2.0 based with additional commercial-use conditions (upstream LICENSE).' setup_url: https://github.com/lobehub/lobehub#readme editorial: highlight: Agents marketplace @@ -280,9 +284,10 @@ projects: license: spdx: Apache-2.0 label: Apache-2.0 - state: declared + state: needs-review evidence_url: https://github.com/mozilla-ai/llamafile/blob/main/LICENSE checked: '2026-10-20' + review_reason: LICENSE text is Apache-2.0 but GitHub's detector returns NOASSERTION; vendored third-party components not reviewed. setup_url: https://github.com/mozilla-ai/llamafile#readme editorial: highlight: Zero-install distribution @@ -448,7 +453,8 @@ projects: label: MIT state: declared evidence_url: https://github.com/mem0ai/openmemory/blob/main/LICENSE - checked: '2026-10-20' + checked: '2026-10-21' + verified_note: 'Upstream LICENSE file read 2026-10-21: standard MIT License text.' setup_url: https://github.com/mem0ai/openmemory#readme editorial: highlight: MCP memory server @@ -571,6 +577,7 @@ projects: state: needs-review evidence_url: https://github.com/microsoft/autogen/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Multiple licences: LICENSE is CC-BY-4.0 (docs) and LICENSE-CODE is MIT (code); GitHub reports only CC-BY-4.0.' setup_url: https://github.com/microsoft/autogen#readme editorial: highlight: Agent conversations @@ -774,7 +781,8 @@ projects: label: MIT state: declared evidence_url: https://github.com/The-PR-Agent/pr-agent/blob/main/LICENSE - checked: '2026-10-20' + checked: '2026-10-21' + verified_note: 'Upstream LICENSE file read 2026-10-21: standard MIT License text.' setup_url: https://github.com/The-PR-Agent/pr-agent#readme editorial: highlight: GitHub Action / app @@ -798,6 +806,7 @@ projects: state: needs-review evidence_url: https://github.com/langgenius/dify/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Custom licence: modified Apache-2.0 with additional conditions (upstream LICENSE).' setup_url: https://github.com/langgenius/dify#readme editorial: highlight: Multi-tenant SaaS restricted @@ -818,6 +827,7 @@ projects: state: needs-review evidence_url: https://github.com/FlowiseAI/Flowise/blob/main/LICENSE.md checked: '2026-10-20' + review_reason: 'Multiple licences: Apache-2.0 except the enterprise directory, which has separate terms (upstream LICENSE.md).' setup_url: https://github.com/FlowiseAI/Flowise#readme editorial: highlight: Core Apache-2.0 @@ -858,6 +868,7 @@ projects: state: needs-review evidence_url: https://github.com/n8n-io/n8n/blob/master/LICENSE.md checked: '2026-10-20' + review_reason: 'Source-available, not OSI: Sustainable Use License (fair-code) with portions under an enterprise licence (upstream LICENSE.md).' setup_url: https://github.com/n8n-io/n8n#readme editorial: highlight: Source-available @@ -1002,6 +1013,7 @@ projects: state: needs-review evidence_url: https://github.com/weaviate/weaviate/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Multiple licences: source is variously BSD-3-Clause or the Weaviate License (upstream LICENSE).' setup_url: https://github.com/weaviate/weaviate#readme editorial: highlight: Vector DB (hybrid) @@ -1026,6 +1038,7 @@ projects: state: needs-review evidence_url: https://github.com/langfuse/langfuse/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Multiple licences: MIT except ee/ directories, which have separate terms (upstream LICENSE).' setup_url: https://github.com/langfuse/langfuse#readme editorial: highlight: Tracing platform @@ -1043,9 +1056,10 @@ projects: license: spdx: Elastic-2.0 label: Elastic-2.0 - state: declared + state: needs-review evidence_url: https://github.com/Arize-ai/phoenix/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Source-available, not OSI: Elastic License 2.0 (upstream LICENSE).' setup_url: https://github.com/Arize-ai/phoenix#readme editorial: highlight: Notebook + server @@ -1249,9 +1263,10 @@ projects: license: spdx: FSL-1.1-Apache-2.0 label: FSL-1.1-Apache-2.0 - state: declared + state: needs-review evidence_url: https://github.com/tashfeenahmed/AgentDomains/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION.' setup_url: https://github.com/tashfeenahmed/AgentDomains#readme editorial: highlight: CLI @@ -1269,9 +1284,10 @@ projects: license: spdx: FSL-1.1-Apache-2.0 label: FSL-1.1-Apache-2.0 - state: declared + state: needs-review evidence_url: https://github.com/tashfeenahmed/AgentDomains-mcp/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION.' setup_url: https://github.com/tashfeenahmed/AgentDomains-mcp#readme editorial: highlight: MCP server @@ -1289,9 +1305,10 @@ projects: license: spdx: FSL-1.1-Apache-2.0 label: FSL-1.1-Apache-2.0 - state: declared + state: needs-review evidence_url: https://github.com/tashfeenahmed/AgentDomains-skill/blob/main/LICENSE checked: '2026-10-20' + review_reason: 'Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION.' setup_url: https://github.com/tashfeenahmed/AgentDomains-skill#readme editorial: highlight: Agent skill diff --git a/catalog/schema.json b/catalog/schema.json index adeeb16..78dc180 100644 --- a/catalog/schema.json +++ b/catalog/schema.json @@ -2,7 +2,9 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Open Source Ai catalog", "type": "object", - "required": ["projects"], + "required": [ + "projects" + ], "additionalProperties": false, "properties": { "projects": { @@ -10,31 +12,168 @@ "items": { "type": "object", "additionalProperties": false, - "required": ["id","name","repo","category","description","tasks","deployment","hardware","languages","license","setup_url","last_checked"], + "required": [ + "id", + "name", + "repo", + "category", + "description", + "tasks", + "deployment", + "hardware", + "languages", + "license", + "setup_url", + "last_checked" + ], "properties": { - "id": {"type": "string", "pattern": "^[a-z0-9][a-z0-9.-]*$"}, - "name": {"type": "string", "minLength": 1}, - "repo": {"type": "string", "pattern": "^https://github\\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"}, - "category": {"type": "string"}, - "description": {"type": "string", "minLength": 10, "maxLength": 200}, - "tasks": {"type": "array", "minItems": 1, "items": {"enum": ["routing","api-gateway","chat","local-inference","serving","memory","agents","coding","code-review","workflows","no-code","rag","evaluation","tracing","backend","examples","experiments"]}}, - "deployment": {"type": "array", "minItems": 1, "items": {"enum": ["local","self-hosted","library","ci","examples","cloud","unknown"]}}, - "hardware": {"enum": ["cpu-ok","gpu-recommended","gpu-required","not-applicable","unknown"]}, - "languages": {"type": "array", "minItems": 1, "items": {"type": "string"}}, + "id": { + "type": "string", + "pattern": "^[a-z0-9][a-z0-9.-]*$" + }, + "name": { + "type": "string", + "minLength": 1 + }, + "repo": { + "type": "string", + "pattern": "^https://github\\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" + }, + "category": { + "type": "string" + }, + "description": { + "type": "string", + "minLength": 10, + "maxLength": 200 + }, + "tasks": { + "type": "array", + "minItems": 1, + "items": { + "enum": [ + "routing", + "api-gateway", + "chat", + "local-inference", + "serving", + "memory", + "agents", + "coding", + "code-review", + "workflows", + "no-code", + "rag", + "evaluation", + "tracing", + "backend", + "examples", + "experiments" + ] + } + }, + "deployment": { + "type": "array", + "minItems": 1, + "items": { + "enum": [ + "local", + "self-hosted", + "library", + "ci", + "examples", + "cloud", + "unknown" + ] + } + }, + "hardware": { + "enum": [ + "cpu-ok", + "gpu-recommended", + "gpu-required", + "not-applicable", + "unknown" + ] + }, + "languages": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, "license": { - "type": "object", "additionalProperties": false, - "required": ["spdx","label","state","evidence_url","checked"], + "type": "object", + "additionalProperties": false, + "required": [ + "spdx", + "label", + "state", + "evidence_url", + "checked" + ], "properties": { - "spdx": {"type": ["string","null"]}, - "label": {"type": "string"}, - "state": {"enum": ["declared","needs-review","none"]}, - "evidence_url": {"type": "string", "pattern": "^https://"}, - "checked": {"type": "string", "pattern": "^20[0-9]{2}-[01][0-9]-[0-3][0-9]$"} - } + "spdx": { + "type": [ + "string", + "null" + ] + }, + "label": { + "type": "string" + }, + "state": { + "enum": [ + "declared", + "needs-review", + "none" + ] + }, + "evidence_url": { + "type": "string", + "pattern": "^https://" + }, + "checked": { + "type": "string", + "pattern": "^20[0-9]{2}-[01][0-9]-[0-3][0-9]$" + }, + "review_reason": { + "type": "string", + "minLength": 20 + }, + "verified_note": { + "type": "string" + } + }, + "allOf": [ + { + "if": { + "properties": { + "state": { + "const": "needs-review" + } + } + }, + "then": { + "required": [ + "review_reason" + ] + } + } + ] + }, + "setup_url": { + "type": "string", + "pattern": "^https://" + }, + "editorial": { + "type": "object" }, - "setup_url": {"type": "string", "pattern": "^https://"}, - "editorial": {"type": "object"}, - "last_checked": {"type": "string", "pattern": "^20[0-9]{2}-[01][0-9]-[0-3][0-9]$"} + "last_checked": { + "type": "string", + "pattern": "^20[0-9]{2}-[01][0-9]-[0-3][0-9]$" + } } } } diff --git a/docs/assets/catalog.json b/docs/assets/catalog.json index d4de212..fddcb88 100644 --- a/docs/assets/catalog.json +++ b/docs/assets/catalog.json @@ -71,6 +71,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "FreeLLMAPI", "repo": "https://github.com/tashfeenahmed/freellmapi", @@ -93,6 +94,7 @@ ], "last_commit": "2026-10-17", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "OpenCode Free Router", "repo": "https://github.com/0xgetz/opencode-free-9router", @@ -115,6 +117,7 @@ ], "last_commit": "2026-10-19", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Bifrost", "repo": "https://github.com/maximhq/bifrost", @@ -137,7 +140,8 @@ ], "last_commit": "2025-06-25", "license": "BUSL-1.1", - "license_state": "declared", + "license_reason": "Source-available, not OSI: Business Source License 1.1 with a use limitation (upstream LICENSE).", + "license_state": "needs-review", "name": "Trylon Gateway", "repo": "https://github.com/trylonai/gateway", "status": "active", @@ -159,6 +163,7 @@ ], "last_commit": "2026-10-20", "license": "MIT (enterprise/ dir separate)", + "license_reason": "Multiple licences: MIT for most code, separate licence for the enterprise/ directory (stated at top of upstream LICENSE).", "license_state": "needs-review", "name": "LiteLLM", "repo": "https://github.com/BerriAI/litellm", @@ -181,6 +186,7 @@ ], "last_commit": "2026-05-25", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Portkey Gateway", "repo": "https://github.com/Portkey-AI/gateway", @@ -204,6 +210,7 @@ ], "last_commit": "2026-10-16", "license": "Open WebUI License (BSD-3 + branding clause)", + "license_reason": "Custom licence: BSD-3-style terms plus a clause forbidding removal or alteration of Open WebUI branding (upstream LICENSE).", "license_state": "needs-review", "name": "Open WebUI", "repo": "https://github.com/open-webui/open-webui", @@ -225,6 +232,7 @@ ], "last_commit": "2026-10-20", "license": "LobeHub Community License (Apache-2.0 based)", + "license_reason": "Custom licence: LobeHub Community License, Apache-2.0 based with additional commercial-use conditions (upstream LICENSE).", "license_state": "needs-review", "name": "Lobe Chat", "repo": "https://github.com/lobehub/lobehub", @@ -246,6 +254,7 @@ ], "last_commit": "2026-10-17", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "LibreChat", "repo": "https://github.com/LibreChat-AI/LibreChat", @@ -267,6 +276,7 @@ ], "last_commit": "2024-06-22", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Chatbot UI", "repo": "https://github.com/mckaywrigley/chatbot-ui", @@ -288,6 +298,7 @@ ], "last_commit": "2025-05-27", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "GPT4All", "repo": "https://github.com/nomic-ai/gpt4all", @@ -309,6 +320,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Ollama", "repo": "https://github.com/ollama/ollama", @@ -330,6 +342,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "llama.cpp", "repo": "https://github.com/ggml-org/llama.cpp", @@ -351,7 +364,8 @@ ], "last_commit": "2026-10-08", "license": "Apache-2.0", - "license_state": "declared", + "license_reason": "LICENSE text is Apache-2.0 but GitHub's detector returns NOASSERTION; vendored third-party components not reviewed.", + "license_state": "needs-review", "name": "llamafile", "repo": "https://github.com/mozilla-ai/llamafile", "status": "active", @@ -372,6 +386,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "LocalAI", "repo": "https://github.com/mudler/LocalAI", @@ -393,6 +408,7 @@ ], "last_commit": "2026-08-17", "license": "AGPL-3.0", + "license_reason": "", "license_state": "declared", "name": "Text Generation WebUI", "repo": "https://github.com/oobabooga/textgen", @@ -414,6 +430,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "vLLM", "repo": "https://github.com/vllm-project/vllm", @@ -435,6 +452,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "SGLang", "repo": "https://github.com/sgl-project/sglang", @@ -457,6 +475,7 @@ ], "last_commit": "2026-03-21", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Text Generation Inference", "repo": "https://github.com/huggingface/text-generation-inference", @@ -478,6 +497,7 @@ ], "last_commit": "2026-10-15", "license": "BSD-3-Clause", + "license_reason": "", "license_state": "declared", "name": "Triton Inference Server", "repo": "https://github.com/triton-inference-server/server", @@ -500,6 +520,7 @@ ], "last_commit": "2026-10-14", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Mem0", "repo": "https://github.com/mem0ai/mem0", @@ -522,6 +543,7 @@ ], "last_commit": "2026-07-29", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "OpenMemory", "repo": "https://github.com/mem0ai/openmemory", @@ -544,6 +566,7 @@ ], "last_commit": "2026-10-18", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Letta", "repo": "https://github.com/letta-ai/letta", @@ -566,6 +589,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Graphiti", "repo": "https://github.com/getzep/graphiti", @@ -587,6 +611,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "LangChain", "repo": "https://github.com/langchain-ai/langchain", @@ -608,6 +633,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "LangGraph", "repo": "https://github.com/langchain-ai/langgraph", @@ -629,6 +655,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "CrewAI", "repo": "https://github.com/crewAIInc/crewAI", @@ -650,6 +677,7 @@ ], "last_commit": "2026-10-16", "license": "CC-BY-4.0 (docs) / MIT (code)", + "license_reason": "Multiple licences: LICENSE is CC-BY-4.0 (docs) and LICENSE-CODE is MIT (code); GitHub reports only CC-BY-4.0.", "license_state": "needs-review", "name": "AutoGen", "repo": "https://github.com/microsoft/autogen", @@ -671,6 +699,7 @@ ], "last_commit": "2026-10-06", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "smolagents", "repo": "https://github.com/huggingface/smolagents", @@ -692,6 +721,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Agno", "repo": "https://github.com/agno-agi/agno", @@ -713,6 +743,7 @@ ], "last_commit": "2026-10-20", "license": "GPL-3.0", + "license_reason": "", "license_state": "declared", "name": "OpenHuman", "repo": "https://github.com/tinyhumansai/openhuman", @@ -734,6 +765,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "OpenHands", "repo": "https://github.com/OpenHands/OpenHands", @@ -755,6 +787,7 @@ ], "last_commit": "2026-07-21", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Continue", "repo": "https://github.com/continuedev/continue", @@ -776,6 +809,7 @@ ], "last_commit": "2026-05-22", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Aider", "repo": "https://github.com/Aider-AI/aider", @@ -797,6 +831,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "OpenCode", "repo": "https://github.com/anomalyco/opencode", @@ -818,6 +853,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Cline", "repo": "https://github.com/cline/cline", @@ -839,6 +875,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Open Code Review", "repo": "https://github.com/alibaba/open-code-review", @@ -860,6 +897,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "PR-Agent", "repo": "https://github.com/The-PR-Agent/pr-agent", @@ -881,6 +919,7 @@ ], "last_commit": "2026-10-20", "license": "Dify Open Source License (Apache-2.0 + conditions)", + "license_reason": "Custom licence: modified Apache-2.0 with additional conditions (upstream LICENSE).", "license_state": "needs-review", "name": "Dify", "repo": "https://github.com/langgenius/dify", @@ -903,6 +942,7 @@ ], "last_commit": "2026-08-13", "license": "Apache-2.0 (enterprise dir separate)", + "license_reason": "Multiple licences: Apache-2.0 except the enterprise directory, which has separate terms (upstream LICENSE.md).", "license_state": "needs-review", "name": "Flowise", "repo": "https://github.com/FlowiseAI/Flowise", @@ -925,6 +965,7 @@ ], "last_commit": "2026-10-16", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Langflow", "repo": "https://github.com/langflow-ai/langflow", @@ -947,6 +988,7 @@ ], "last_commit": "2026-10-20", "license": "Sustainable Use License (fair-code)", + "license_reason": "Source-available, not OSI: Sustainable Use License (fair-code) with portions under an enterprise licence (upstream LICENSE.md).", "license_state": "needs-review", "name": "n8n", "repo": "https://github.com/n8n-io/n8n", @@ -970,6 +1012,7 @@ ], "last_commit": "2026-10-14", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "LlamaIndex", "repo": "https://github.com/run-llama/llama_index", @@ -992,6 +1035,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Haystack", "repo": "https://github.com/deepset-ai/haystack", @@ -1014,6 +1058,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "RAGFlow", "repo": "https://github.com/infiniflow/ragflow", @@ -1036,6 +1081,7 @@ ], "last_commit": "2026-10-05", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Qdrant", "repo": "https://github.com/qdrant/qdrant", @@ -1059,6 +1105,7 @@ ], "last_commit": "2026-10-17", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Chroma", "repo": "https://github.com/chroma-core/chroma", @@ -1081,6 +1128,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Milvus", "repo": "https://github.com/milvus-io/milvus", @@ -1103,6 +1151,7 @@ ], "last_commit": "2026-10-16", "license": "BSD-3-Clause (core)", + "license_reason": "Multiple licences: source is variously BSD-3-Clause or the Weaviate License (upstream LICENSE).", "license_state": "needs-review", "name": "Weaviate", "repo": "https://github.com/weaviate/weaviate", @@ -1125,6 +1174,7 @@ ], "last_commit": "2026-10-20", "license": "MIT (ee/ dirs separate)", + "license_reason": "Multiple licences: MIT except ee/ directories, which have separate terms (upstream LICENSE).", "license_state": "needs-review", "name": "Langfuse", "repo": "https://github.com/langfuse/langfuse", @@ -1148,7 +1198,8 @@ ], "last_commit": "2026-10-20", "license": "Elastic-2.0", - "license_state": "declared", + "license_reason": "Source-available, not OSI: Elastic License 2.0 (upstream LICENSE).", + "license_state": "needs-review", "name": "Phoenix", "repo": "https://github.com/Arize-ai/phoenix", "status": "active", @@ -1171,6 +1222,7 @@ ], "last_commit": "2026-10-20", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "promptfoo", "repo": "https://github.com/promptfoo/promptfoo", @@ -1194,6 +1246,7 @@ ], "last_commit": "2026-10-19", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "DeepEval", "repo": "https://github.com/confident-ai/deepeval", @@ -1216,6 +1269,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Butterbase", "repo": "https://github.com/butterbase-ai/butterbase", @@ -1237,6 +1291,7 @@ ], "last_commit": "2026-10-20", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Supabase", "repo": "https://github.com/supabase/supabase", @@ -1258,6 +1313,7 @@ ], "last_commit": "2026-10-08", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "PocketBase", "repo": "https://github.com/pocketbase/pocketbase", @@ -1279,6 +1335,7 @@ ], "last_commit": "2026-10-18", "license": "Apache-2.0", + "license_reason": "", "license_state": "declared", "name": "Awesome LLM Apps", "repo": "https://github.com/Shubhamsaboo/awesome-llm-apps", @@ -1300,6 +1357,7 @@ ], "last_commit": "2026-10-06", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "One Person Company", "repo": "https://github.com/tashfeenahmed/OnePersonCompany", @@ -1321,6 +1379,7 @@ ], "last_commit": "2026-10-15", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Kinetic", "repo": "https://github.com/tashfeenahmed/kinetic", @@ -1342,6 +1401,7 @@ ], "last_commit": "2026-09-30", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "CircleChat", "repo": "https://github.com/tashfeenahmed/circlechat", @@ -1363,7 +1423,8 @@ ], "last_commit": "2026-10-17", "license": "FSL-1.1-Apache-2.0", - "license_state": "declared", + "license_reason": "Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION.", + "license_state": "needs-review", "name": "AgentDomains", "repo": "https://github.com/tashfeenahmed/AgentDomains", "status": "active", @@ -1384,7 +1445,8 @@ ], "last_commit": "2026-09-30", "license": "FSL-1.1-Apache-2.0", - "license_state": "declared", + "license_reason": "Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION.", + "license_state": "needs-review", "name": "AgentDomains MCP", "repo": "https://github.com/tashfeenahmed/AgentDomains-mcp", "status": "active", @@ -1405,7 +1467,8 @@ ], "last_commit": "2026-10-17", "license": "FSL-1.1-Apache-2.0", - "license_state": "declared", + "license_reason": "Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION.", + "license_state": "needs-review", "name": "AgentDomains Skill", "repo": "https://github.com/tashfeenahmed/AgentDomains-skill", "status": "active", @@ -1426,6 +1489,7 @@ ], "last_commit": "2026-10-16", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "ScallopBot", "repo": "https://github.com/tashfeenahmed/scallopbot", @@ -1447,6 +1511,7 @@ ], "last_commit": "2026-10-04", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Cashmaxx", "repo": "https://github.com/tashfeenahmed/cashmaxx", @@ -1468,6 +1533,7 @@ ], "last_commit": "2026-09-22", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Jev Deep Research", "repo": "https://github.com/tashfeenahmed/jev-deepresearch", @@ -1489,6 +1555,7 @@ ], "last_commit": "2026-02-05", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "Emotion State", "repo": "https://github.com/tashfeenahmed/emotion-state", @@ -1510,6 +1577,7 @@ ], "last_commit": "2026-10-14", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "MagicTap", "repo": "https://github.com/tashfeenahmed/magictap", @@ -1531,6 +1599,7 @@ ], "last_commit": "2021-07-31", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "PyReality", "repo": "https://github.com/tashfeenahmed/pyreality", @@ -1552,6 +1621,7 @@ ], "last_commit": "2021-09-19", "license": "MIT", + "license_reason": "", "license_state": "declared", "name": "HTML Email Template", "repo": "https://github.com/tashfeenahmed/html-email-template", diff --git a/docs/catalog.md b/docs/catalog.md index 13613a5..2d153d9 100644 --- a/docs/catalog.md +++ b/docs/catalog.md @@ -7,7 +7,7 @@ description: Filter open-source AI agent and LLM projects by task, deployment, h Filter by your constraints. Results are not ranked recommendations; they are listed alphabetically. Status and last commit come from the [weekly evidence refresh](freshness.md). -

+

+
diff --git a/docs/credits.md b/docs/credits.md index 043ec6e..0829a03 100644 --- a/docs/credits.md +++ b/docs/credits.md @@ -8,7 +8,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | FreeLLMAPI | https://github.com/tashfeenahmed/freellmapi | MIT | declared | 2026-10-20 | | OpenCode Free Router | https://github.com/0xgetz/opencode-free-9router | MIT | declared | 2026-10-20 | | Bifrost | https://github.com/maximhq/bifrost | Apache-2.0 | declared | 2026-10-20 | -| Trylon Gateway | https://github.com/trylonai/gateway | BUSL-1.1 | declared | 2026-10-20 | +| Trylon Gateway | https://github.com/trylonai/gateway | BUSL-1.1 | needs-review | 2026-10-20 | | LiteLLM | https://github.com/BerriAI/litellm | MIT (enterprise/ dir separate) | needs-review | 2026-10-20 | | Portkey Gateway | https://github.com/Portkey-AI/gateway | MIT | declared | 2026-10-20 | | Open WebUI | https://github.com/open-webui/open-webui | Open WebUI License (BSD-3 + branding clause) | needs-review | 2026-10-20 | @@ -18,7 +18,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | GPT4All | https://github.com/nomic-ai/gpt4all | MIT | declared | 2026-10-20 | | Ollama | https://github.com/ollama/ollama | MIT | declared | 2026-10-20 | | llama.cpp | https://github.com/ggml-org/llama.cpp | MIT | declared | 2026-10-20 | -| llamafile | https://github.com/mozilla-ai/llamafile | Apache-2.0 | declared | 2026-10-20 | +| llamafile | https://github.com/mozilla-ai/llamafile | Apache-2.0 | needs-review | 2026-10-20 | | LocalAI | https://github.com/mudler/LocalAI | MIT | declared | 2026-10-20 | | Text Generation WebUI | https://github.com/oobabooga/textgen | AGPL-3.0 | declared | 2026-10-20 | | vLLM | https://github.com/vllm-project/vllm | Apache-2.0 | declared | 2026-10-20 | @@ -26,7 +26,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | Text Generation Inference | https://github.com/huggingface/text-generation-inference | Apache-2.0 | declared | 2026-10-20 | | Triton Inference Server | https://github.com/triton-inference-server/server | BSD-3-Clause | declared | 2026-10-20 | | Mem0 | https://github.com/mem0ai/mem0 | Apache-2.0 | declared | 2026-10-20 | -| OpenMemory | https://github.com/mem0ai/openmemory | MIT | declared | 2026-10-20 | +| OpenMemory | https://github.com/mem0ai/openmemory | MIT | declared | 2026-10-21 | | Letta | https://github.com/letta-ai/letta | Apache-2.0 | declared | 2026-10-20 | | Graphiti | https://github.com/getzep/graphiti | Apache-2.0 | declared | 2026-10-20 | | LangChain | https://github.com/langchain-ai/langchain | MIT | declared | 2026-10-20 | @@ -42,7 +42,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | OpenCode | https://github.com/anomalyco/opencode | MIT | declared | 2026-10-20 | | Cline | https://github.com/cline/cline | Apache-2.0 | declared | 2026-10-20 | | Open Code Review | https://github.com/alibaba/open-code-review | Apache-2.0 | declared | 2026-10-20 | -| PR-Agent | https://github.com/The-PR-Agent/pr-agent | MIT | declared | 2026-10-20 | +| PR-Agent | https://github.com/The-PR-Agent/pr-agent | MIT | declared | 2026-10-21 | | Dify | https://github.com/langgenius/dify | Dify Open Source License (Apache-2.0 + conditions) | needs-review | 2026-10-20 | | Flowise | https://github.com/FlowiseAI/Flowise | Apache-2.0 (enterprise dir separate) | needs-review | 2026-10-20 | | Langflow | https://github.com/langflow-ai/langflow | MIT | declared | 2026-10-20 | @@ -55,7 +55,7 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | Milvus | https://github.com/milvus-io/milvus | Apache-2.0 | declared | 2026-10-20 | | Weaviate | https://github.com/weaviate/weaviate | BSD-3-Clause (core) | needs-review | 2026-10-20 | | Langfuse | https://github.com/langfuse/langfuse | MIT (ee/ dirs separate) | needs-review | 2026-10-20 | -| Phoenix | https://github.com/Arize-ai/phoenix | Elastic-2.0 | declared | 2026-10-20 | +| Phoenix | https://github.com/Arize-ai/phoenix | Elastic-2.0 | needs-review | 2026-10-20 | | promptfoo | https://github.com/promptfoo/promptfoo | MIT | declared | 2026-10-20 | | DeepEval | https://github.com/confident-ai/deepeval | Apache-2.0 | declared | 2026-10-20 | | Butterbase | https://github.com/butterbase-ai/butterbase | Apache-2.0 | declared | 2026-10-20 | @@ -65,9 +65,9 @@ Open Source Ai's own content is MIT-licensed © CodesbyFebin. Catalogued project | One Person Company | https://github.com/tashfeenahmed/OnePersonCompany | MIT | declared | 2026-10-20 | | Kinetic | https://github.com/tashfeenahmed/kinetic | MIT | declared | 2026-10-20 | | CircleChat | https://github.com/tashfeenahmed/circlechat | MIT | declared | 2026-10-20 | -| AgentDomains | https://github.com/tashfeenahmed/AgentDomains | FSL-1.1-Apache-2.0 | declared | 2026-10-20 | -| AgentDomains MCP | https://github.com/tashfeenahmed/AgentDomains-mcp | FSL-1.1-Apache-2.0 | declared | 2026-10-20 | -| AgentDomains Skill | https://github.com/tashfeenahmed/AgentDomains-skill | FSL-1.1-Apache-2.0 | declared | 2026-10-20 | +| AgentDomains | https://github.com/tashfeenahmed/AgentDomains | FSL-1.1-Apache-2.0 | needs-review | 2026-10-20 | +| AgentDomains MCP | https://github.com/tashfeenahmed/AgentDomains-mcp | FSL-1.1-Apache-2.0 | needs-review | 2026-10-20 | +| AgentDomains Skill | https://github.com/tashfeenahmed/AgentDomains-skill | FSL-1.1-Apache-2.0 | needs-review | 2026-10-20 | | ScallopBot | https://github.com/tashfeenahmed/scallopbot | MIT | declared | 2026-10-20 | | Cashmaxx | https://github.com/tashfeenahmed/cashmaxx | MIT | declared | 2026-10-20 | | Jev Deep Research | https://github.com/tashfeenahmed/jev-deepresearch | MIT | declared | 2026-10-20 | diff --git a/docs/freshness.md b/docs/freshness.md index ec766a9..0b1da73 100644 --- a/docs/freshness.md +++ b/docs/freshness.md @@ -8,6 +8,13 @@ description: Weekly evidence for every catalogued project – repository state, Evidence is collected from the public GitHub REST API by a **weekly** scheduled workflow (Mondays 03:00 UTC, also runnable manually). Changes arrive as a pull request for human review; nothing is rewritten on `main` automatically. This is not real-time monitoring. +**How to read this page** + +- *State* and dates are collected facts with a source URL and retrieval time in `catalog/evidence/.json`. +- *Declared licence* is curated by humans in `catalog/projects.yaml`; *needs review* entries list a reason on their project page. +- *Flags*: `archived` (upstream archived, kept and labelled), `moved` (canonical URL changed), `licence review`, `lookup: …` (last request failed – previous evidence kept, treat as possibly stale). +- To correct anything, edit `catalog/projects.yaml` (never this generated page) – see CONTRIBUTING.md. + **Summary:** 68 active · 2 archived · 0 unknown/not collected · 70 total. "Declared licence" is the curated value; "GitHub detected" is GitHub's automatic detection (`NOASSERTION` means GitHub could not identify a single licence). A failed request never marks a project deleted. @@ -18,7 +25,7 @@ Evidence is collected from the public GitHub REST API by a **weekly** scheduled | [OpenCode Free Router](stacks/gateways-routing.md#opencode-free-9router) | active | 2026-10-17 | – | MIT | MIT | 2026-10-20 | – | | [Bifrost](stacks/gateways-routing.md#bifrost) | active | 2026-10-19 | ent-v2.3.1-base | Apache-2.0 | Apache-2.0 | 2026-10-20 | – | | [Trylon Gateway](stacks/gateways-routing.md#trylon-gateway) | active | 2025-06-25 | – | BUSL-1.1 | NOASSERTION | 2026-10-20 | licence review | -| [LiteLLM](stacks/gateways-routing.md#litellm) | active | 2026-10-20 | v1.106.0 | MIT (enterprise/ dir separate) | NOASSERTION | 2026-10-20 | licence review | +| [LiteLLM](stacks/gateways-routing.md#litellm) | active | 2026-10-20 | v1.106.1 | MIT (enterprise/ dir separate) | NOASSERTION | 2026-10-20 | licence review | | [Portkey Gateway](stacks/gateways-routing.md#portkey-gateway) | active | 2026-05-25 | v1.15.2 | MIT | MIT | 2026-10-20 | – | | [Open WebUI](stacks/chat-ui.md#open-webui) | active | 2026-10-16 | v0.12.3 | Open WebUI License (BSD-3 + branding clause) | NOASSERTION | 2026-10-20 | licence review | | [Lobe Chat](stacks/chat-ui.md#lobe-chat) | active | 2026-10-20 | v2.2.20 | LobeHub Community License (Apache-2.0 based) | NOASSERTION | 2026-10-20 | licence review | @@ -32,7 +39,7 @@ Evidence is collected from the public GitHub REST API by a **weekly** scheduled | [Text Generation WebUI](stacks/local-models.md#text-generation-webui) | active | 2026-08-17 | v4.9 | AGPL-3.0 | AGPL-3.0 | 2026-10-20 | – | | [vLLM](stacks/inference-serving.md#vllm) | active | 2026-10-20 | v0.32.0 | Apache-2.0 | Apache-2.0 | 2026-10-20 | – | | [SGLang](stacks/inference-serving.md#sglang) | active | 2026-10-20 | v0.5.22 | Apache-2.0 | Apache-2.0 | 2026-10-20 | – | -| [Text Generation Inference](stacks/inference-serving.md#text-generation-inference) | archived | 2026-03-21 | v3.3.7 | Apache-2.0 | Apache-2.0 | 2026-10-20 | archived | +| [Text Generation Inference](stacks/inference-serving.md#text-generation-inference) | ⚠ **archived upstream** | 2026-03-21 | v3.3.7 | Apache-2.0 | Apache-2.0 | 2026-10-20 | archived | | [Triton Inference Server](stacks/inference-serving.md#triton-server) | active | 2026-10-15 | v2.73.0 | BSD-3-Clause | BSD-3-Clause | 2026-10-20 | – | | [Mem0](stacks/memory.md#mem0) | active | 2026-10-14 | ts-v3.3.1 | Apache-2.0 | Apache-2.0 | 2026-10-20 | – | | [OpenMemory](stacks/memory.md#openmemory) | active | 2026-07-29 | – | MIT | MIT | 2026-10-20 | – | @@ -53,7 +60,7 @@ Evidence is collected from the public GitHub REST API by a **weekly** scheduled | [Open Code Review](stacks/code-review.md#open-code-review) | active | 2026-10-20 | v1.13.2 | Apache-2.0 | Apache-2.0 | 2026-10-20 | – | | [PR-Agent](stacks/code-review.md#pr-agent) | active | 2026-10-20 | v0.48.0 | MIT | MIT | 2026-10-20 | – | | [Dify](stacks/app-builders.md#dify) | active | 2026-10-20 | 1.17.1 | Dify Open Source License (Apache-2.0 + conditions) | NOASSERTION | 2026-10-20 | licence review | -| [Flowise](stacks/app-builders.md#flowise) | archived | 2026-08-13 | flowise@3.1.4 | Apache-2.0 (enterprise dir separate) | NOASSERTION | 2026-10-20 | archived, licence review | +| [Flowise](stacks/app-builders.md#flowise) | ⚠ **archived upstream** | 2026-08-13 | flowise@3.1.4 | Apache-2.0 (enterprise dir separate) | NOASSERTION | 2026-10-20 | archived, licence review | | [Langflow](stacks/app-builders.md#langflow) | active | 2026-10-16 | v1.12.6 | MIT | MIT | 2026-10-20 | – | | [n8n](stacks/app-builders.md#n8n) | active | 2026-10-20 | n8n@2.44.4 | Sustainable Use License (fair-code) | NOASSERTION | 2026-10-20 | licence review | | [LlamaIndex](stacks/rag-vector-db.md#llama-index) | active | 2026-10-14 | v0.14.25 | MIT | MIT | 2026-10-20 | – | diff --git a/docs/javascripts/a11y.js b/docs/javascripts/a11y.js new file mode 100644 index 0000000..51efbca --- /dev/null +++ b/docs/javascripts/a11y.js @@ -0,0 +1,8 @@ +// Make horizontally scrollable code blocks and tables keyboard-focusable (WCAG 2.1.1). +function osaFocusable() { + document.querySelectorAll("pre > code, .osa-table-wrap").forEach(function (e) { + if (!e.hasAttribute("tabindex")) e.setAttribute("tabindex", "0"); + }); +} +if (window.document$) window.document$.subscribe(function () { setTimeout(osaFocusable, 0); }); +window.addEventListener("load", osaFocusable); diff --git a/docs/javascripts/catalog.js b/docs/javascripts/catalog.js index 59192f5..f7acc74 100644 --- a/docs/javascripts/catalog.js +++ b/docs/javascripts/catalog.js @@ -2,14 +2,29 @@ var form = document.getElementById("osa-filters"); if (!form) return; var base = document.querySelector('script[src*="javascripts/catalog.js"]').src.replace(/javascripts\/catalog\.js.*$/, ""); - fetch(base + "assets/catalog.json").then(function (r) { return r.json(); }).then(init); + var FIELDS = ["q", "category", "task", "deployment", "hardware", "license", "status"]; + function $(id) { return document.getElementById(id); } function el(t, txt) { var e = document.createElement(t); if (txt != null) e.textContent = txt; return e; } function fill(id, values, labels) { - var s = document.getElementById(id); + var s = $(id); values.forEach(function (v) { var o = el("option", labels ? labels[v] : v); o.value = v; s.appendChild(o); }); } function uniq(a) { return Array.from(new Set(a)).sort(); } - function init(data) { + function fromURL() { + var u = new URLSearchParams(location.search); + FIELDS.forEach(function (f) { + var e = $("f-" + f), v = u.get(f) || ""; + if (e.tagName === "SELECT" && v && !Array.prototype.some.call(e.options, function (o) { return o.value === v; })) v = ""; + e.value = v; + }); + } + function toURL(push) { + var u = new URLSearchParams(); + FIELDS.forEach(function (f) { var v = $("f-" + f).value; if (v) u.set(f, v); }); + var qs = u.toString(), url = location.pathname + (qs ? "?" + qs : ""); + if (url !== location.pathname + location.search) history[push ? "pushState" : "replaceState"](null, "", url); + } + fetch(base + "assets/catalog.json").then(function (r) { return r.json(); }).then(function (data) { var P = data.projects, cat = {}; data.categories.forEach(function (c) { cat[c.id] = c.title; }); fill("f-category", data.categories.map(function (c) { return c.id; }), cat); @@ -18,18 +33,18 @@ fill("f-hardware", uniq(P.map(function (p) { return p.hardware; }))); fill("f-license", uniq(P.map(function (p) { return p.license_state; }))); var cutoff = new Date(Date.now() - 90 * 864e5).toISOString().slice(0, 10); - function v(id) { return document.getElementById(id).value; } + function v(id) { return $("f-" + id).value; } function render() { - var q = v("f-q").toLowerCase(), tb = document.querySelector("#osa-results tbody"); + var q = v("q").trim().toLowerCase(), tb = document.querySelector("#osa-results tbody"); var rows = P.filter(function (p) { if (q && (p.name + " " + p.description).toLowerCase().indexOf(q) < 0) return false; - if (v("f-category") && p.category !== v("f-category")) return false; - if (v("f-task") && p.tasks.indexOf(v("f-task")) < 0) return false; - if (v("f-deployment") && p.deployment.indexOf(v("f-deployment")) < 0) return false; - if (v("f-hardware") && p.hardware !== v("f-hardware")) return false; - if (v("f-license") && p.license_state !== v("f-license")) return false; - var s = v("f-status"); - if (s === "recent" && !(p.last_commit >= cutoff && p.last_commit !== "–")) return false; + if (v("category") && p.category !== v("category")) return false; + if (v("task") && p.tasks.indexOf(v("task")) < 0) return false; + if (v("deployment") && p.deployment.indexOf(v("deployment")) < 0) return false; + if (v("hardware") && p.hardware !== v("hardware")) return false; + if (v("license") && p.license_state !== v("license")) return false; + var s = v("status"); + if (s === "recent" && !(p.last_commit !== "–" && p.last_commit >= cutoff)) return false; if (s === "active" && p.status === "archived") return false; if (s === "archived" && p.status !== "archived") return false; return true; @@ -38,14 +53,30 @@ rows.forEach(function (p) { var tr = el("tr"), td = el("td"), a = el("a", p.name); a.href = base + "stacks/" + p.category + "/#" + p.id.replace(/\./g, ""); - a.setAttribute("aria-label", p.name + " details"); td.appendChild(a); tr.appendChild(td); - [p.description, p.deployment.join(", "), p.hardware, p.license + (p.license_state === "declared" ? "" : " (needs review)"), p.status, p.last_commit] - .forEach(function (t) { tr.appendChild(el("td", t)); }); + [p.description, p.deployment.join(", "), p.hardware].forEach(function (t) { tr.appendChild(el("td", t)); }); + var lt = el("td", p.license + (p.license_state === "declared" ? "" : " (needs review)")); + if (p.license_reason) lt.title = p.license_reason; + tr.appendChild(lt); + var st = el("td"); + if (p.status === "archived") { var b = el("strong", "⚠ archived"); b.className = "osa-archived"; st.appendChild(b); } + else st.textContent = p.status; + tr.appendChild(st); tr.appendChild(el("td", p.last_commit)); tb.appendChild(tr); }); - document.getElementById("osa-count").textContent = rows.length + " of " + P.length + " projects match"; + $("osa-count").textContent = rows.length + " of " + P.length + " projects match"; + $("osa-empty").hidden = rows.length > 0; + document.getElementById("osa-results").hidden = rows.length === 0; } - form.addEventListener("input", render); form.addEventListener("change", render); render(); - } + function clear(e) { if (e) e.preventDefault(); FIELDS.forEach(function (f) { $("f-" + f).value = ""; }); toURL(true); render(); $("f-q").focus(); } + var t; + form.addEventListener("input", function (e) { if (e.target.id === "f-q") { clearTimeout(t); t = setTimeout(function () { toURL(false); }, 300); render(); } }); + form.addEventListener("change", function (e) { if (e.target.tagName === "SELECT") { toURL(true); render(); } }); + $("f-q").addEventListener("change", function () { toURL(true); }); + $("f-clear").addEventListener("click", clear); + $("f-clear-link").addEventListener("click", clear); + window.addEventListener("popstate", function () { fromURL(); render(); }); + fromURL(); render(); + form.setAttribute("data-ready", "true"); + }); })(); diff --git a/docs/recipes/agent-memory-eval.md b/docs/recipes/agent-memory-eval.md index 86cf219..b95b48e 100644 --- a/docs/recipes/agent-memory-eval.md +++ b/docs/recipes/agent-memory-eval.md @@ -4,31 +4,49 @@ description: A small Python agent uses a local model via Ollama, stores long-ter --- -!!! warning "Test status: unverified" - Not yet run end-to-end. Missing evidence: a successful run of agent.py with Mem0's Ollama provider and a passing promptfoo eval. Treat the commands as a starting point. +!!! success "Test status: tested" + Workflow `Recipe – agent-memory-eval` (run 39490869588, 2026-10-20 UTC, GitHub-hosted ubuntu-latest, 4 vCPU, 16 GB, no GPU, ~156 s) ran smoke.sh: stored two facts, restarted Qdrant, recalled 'Rust' from a new process, and promptfoo passed 2/2 assertions (answers contained 'rust' and 'lisbon', words absent from the questions). Pinned: Ollama 0.40.6, Qdrant v1.19.2, mem0ai 2.2.1, promptfoo 0.124.1, qwen2.5:1.5b, nomic-embed-text:v1.5. Runs on recipe changes, weekly and on demand; not a required check. Not tested: Mem0 LLM fact extraction (infer=True), tool use, multi-user isolation. # Agent with persistent memory and evaluation: Ollama + Mem0 + Qdrant + promptfoo -**Data flow:** `agent.py` → Mem0 (extracts facts) → Qdrant (vectors) · `agent.py` → Ollama (chat + embeddings) · promptfoo runs `agent.py` and asserts on answers. +**Data flow:** `agent.py remember` → Mem0 → Ollama embeddings → Qdrant · `agent.py ask` → Mem0 search (Qdrant) → Ollama chat with retrieved facts · promptfoo runs `agent.py ask` and asserts on the answers. + +## Pinned versions + +| Component | Version | +|---|---| +| Ollama | `ollama/ollama:0.40.6` | +| Qdrant | `qdrant/qdrant:v1.19.2` | +| Mem0 | `mem0ai==2.2.1` (see `requirements.txt`) | +| promptfoo | `promptfoo@0.124.1` | +| Models | `qwen2.5:1.5b` (~1 GB), `nomic-embed-text:v1.5` (~0.3 GB) | ## Requirements -- Docker 24+ with Compose v2, Python 3.10+, Node.js 18+ (for promptfoo) -- 8 GB RAM, ~6 GB disk; CPU is enough for the 1.5B model +- Docker 24+ with Compose v2, Python 3.10+, Node.js 22.22+ (promptfoo 0.124 requirement) +- 4 vCPU, 8 GB RAM, ~6 GB disk; no GPU needed. Cold start ~3–5 minutes (image + model pulls). ## Run ```bash cd Open-Source-Ai/recipes/agent-memory-eval -docker compose up -d -docker compose exec ollama ollama pull qwen2.5:1.5b -docker compose exec ollama ollama pull nomic-embed-text -python -m venv .venv && . .venv/bin/activate && pip install mem0ai openai -python agent.py "Hi, my favourite language is Python." -python agent.py "What is my favourite language?" -npx promptfoo@latest eval +python -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt +./smoke.sh # full end-to-end test (cleans up on exit; KEEP=1 to keep containers) ``` +Or step by step: + +```bash +docker compose up -d && docker compose wait model-pull +python agent.py remember "My favourite programming language is Rust." +docker compose restart qdrant # memory survives the restart +python agent.py recall "favourite language" +python agent.py ask "Which programming language does the user prefer?" +npx promptfoo@0.124.1 eval +``` + +`remember` stores facts verbatim (`infer=False`) so the test is deterministic; set `INFER=1` to let the LLM extract facts (less reliable with small models). + ## Clean up ```bash @@ -37,5 +55,5 @@ docker compose down -v && rm -rf .venv ## Known limitations -- **Unverified:** this recipe has not been run end-to-end yet; Mem0 config keys may differ between versions. -- Small models extract memories unreliably; use 7B+ for meaningful results. +- Tests memory storage, persistence across a Qdrant restart and a new process, and that answers use stored facts. Does not test Mem0's LLM-based fact extraction, multi-user isolation or tool use. +- Small models can phrase answers unexpectedly; assertions only check for the key word. diff --git a/docs/recipes/index.md b/docs/recipes/index.md index 849a69a..1f21e4e 100644 --- a/docs/recipes/index.md +++ b/docs/recipes/index.md @@ -5,5 +5,5 @@ Recipes compose a few catalogued projects into a working stack. Each states exac | Recipe | What you get | Test status | |---|---|---| -| [Agent with persistent memory and evaluation](agent-memory-eval.md) | A small Python agent uses a local model via Ollama, stores long-term memory with Mem0 (Qdrant backend), and is regression-tested with promptfoo. | **unverified** | +| [Agent with persistent memory and evaluation](agent-memory-eval.md) | A small Python agent uses a local model via Ollama, stores long-term memory with Mem0 (Qdrant backend), and is regression-tested with promptfoo. | **tested** | | [Local private chat (model + gateway + chat UI)](local-chat.md) | Ollama serves a small local model, LiteLLM exposes it as an OpenAI-compatible gateway, Open WebUI provides the chat interface. | **tested** | diff --git a/docs/recipes/local-chat.md b/docs/recipes/local-chat.md index 2417829..0c2cd5d 100644 --- a/docs/recipes/local-chat.md +++ b/docs/recipes/local-chat.md @@ -5,7 +5,7 @@ description: Ollama serves a small local model, LiteLLM exposes it as an OpenAI- !!! success "Test status: tested" - CI job `recipe-local-chat` runs recipes/local-chat/smoke.sh on GitHub-hosted ubuntu-latest (4 vCPU, 16 GB, no GPU) on every push to main: compose validation, model pull (qwen2.5:0.5b), a chat completion through the gateway and the Open WebUI health endpoint. Image digests are printed in the job log. Not tested: GPUs, larger models, the browser UI flow. + CI job `recipe-local-chat` runs recipes/local-chat/smoke.sh on GitHub-hosted ubuntu-latest (4 vCPU, 16 GB RAM, no GPU) on every push and PR. It validates the compose file, pulls qwen2.5:0.5b, asks the gateway 17+25 and asserts the reply contains 42 with non-zero completion tokens, checks `ollama ps` shows the model loaded and Ollama's log shows the chat request, and checks the Open WebUI health endpoint. Pinned: Ollama 0.40.6, LiteLLM v1.106.1, Open WebUI v0.12.3. Not tested: GPUs, larger models, the browser chat flow in Open WebUI. # Local private chat: Ollama + LiteLLM + Open WebUI @@ -22,6 +22,17 @@ description: Ollama serves a small local model, LiteLLM exposes it as an OpenAI- No accounts or paid API keys are needed. +## Pinned versions + +| Component | Version | +|---|---| +| Ollama | `ollama/ollama:0.40.6` | +| LiteLLM | `ghcr.io/berriai/litellm:v1.106.1` | +| Open WebUI | `ghcr.io/open-webui/open-webui:v0.12.3` | +| Model | `qwen2.5:0.5b` (~0.4 GB) | + +Typical cold start on a 4-vCPU CI runner: about 2 minutes (image pulls dominate). + ## Run ```bash @@ -37,7 +48,8 @@ Environment variables: `LITELLM_MASTER_KEY` (gateway key, default is a placehold ## Verify ```bash -./smoke.sh # same test CI runs +./smoke.sh # same test CI runs; asks 17+25 and checks the model answers 42, + # token usage is reported, and Ollama's own log shows the request # or manually curl -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H 'Content-Type: application/json' \ http://localhost:4000/v1/chat/completions \ @@ -56,4 +68,4 @@ docker compose down -v # also delete models and chats ## Known limitations - `qwen2.5:0.5b` is a tiny model chosen so CI can run on CPU; answers are low quality. Use a 3B–8B model for real use. -- Images use moving tags (`latest`, `main`, `main-stable`); the exact digests tested are in the CI log. +- Ollama model tags are not immutable; the digest actually pulled is printed by `ollama list` in the CI log. diff --git a/docs/stacks/agent-frameworks.md b/docs/stacks/agent-frameworks.md index 4a361bf..b816aaa 100644 --- a/docs/stacks/agent-frameworks.md +++ b/docs/stacks/agent-frameworks.md @@ -43,6 +43,8 @@ Composable LLM application framework | Licence | MIT · [licence evidence](https://github.com/langchain-ai/langchain/blob/master/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | langchain-core==1.6.12 (2026-10-16) | | Deployment | library | @@ -61,6 +63,8 @@ Graph-based stateful agent orchestration | Licence | MIT · [licence evidence](https://github.com/langchain-ai/langgraph/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | cli==0.4.37 (2026-10-19) | | Deployment | library | @@ -79,6 +83,8 @@ Role-based multi-agent crews | Licence | MIT · [licence evidence](https://github.com/crewAIInc/crewAI/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | 1.15.28 (2026-10-14) | | Deployment | library | @@ -97,6 +103,8 @@ Conversational multi-agent framework | Licence | CC-BY-4.0 (docs) / MIT (code) ⚠ needs review · [licence evidence](https://github.com/microsoft/autogen/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | CC-BY-4.0 | | Repository state | active | +| Licence review reason | Multiple licences: LICENSE is CC-BY-4.0 (docs) and LICENSE-CODE is MIT (code); GitHub reports only CC-BY-4.0. | +| Last lookup | ok | | Last commit | 2026-10-16 | | Latest release | python-v0.7.5 (2025-09-30) | | Deployment | library | @@ -115,6 +123,8 @@ Minimal code-writing agents | Licence | Apache-2.0 · [licence evidence](https://github.com/huggingface/smolagents/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-06 | | Latest release | v1.26.0 (2026-05-29) | | Deployment | library | @@ -133,6 +143,8 @@ Fast agent framework with memory and tools | Licence | Apache-2.0 · [licence evidence](https://github.com/agno-agi/agno/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v3.1.7 (2026-10-20) | | Deployment | library | @@ -151,6 +163,8 @@ Lightweight agent harness that runs hundreds of agents on a small VPS | Licence | GPL-3.0 · [licence evidence](https://github.com/tinyhumansai/openhuman/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | GPL-3.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.64.15 (2026-10-09) | | Deployment | library | diff --git a/docs/stacks/app-builders.md b/docs/stacks/app-builders.md index dc57a8f..3d74e0b 100644 --- a/docs/stacks/app-builders.md +++ b/docs/stacks/app-builders.md @@ -15,7 +15,7 @@ Visual builders for LLM apps, agents and workflows. | Project | What it does | Highlight (editorial) | Deployment | Hardware | Licence | Status | |---|---|---|---|---|---|---| | [Dify](#dify) | LLM app and agentic workflow platform | Multi-tenant SaaS restricted | self-hosted | cpu-ok | Dify Open Source License (Apache-2.0 + conditions) ⚠ needs review | active | -| [Flowise](#flowise) | Drag-and-drop agent builder | Core Apache-2.0 | self-hosted | cpu-ok | Apache-2.0 (enterprise dir separate) ⚠ needs review | archived | +| [Flowise](#flowise) | Drag-and-drop agent builder | Core Apache-2.0 | self-hosted | cpu-ok | Apache-2.0 (enterprise dir separate) ⚠ needs review | ⚠ **archived upstream** | | [Langflow](#langflow) | Visual flow builder for agents and RAG | Permissive | self-hosted | cpu-ok | MIT | active | | [n8n](#n8n) | Workflow automation with AI nodes | Source-available | self-hosted | cpu-ok | Sustainable Use License (fair-code) ⚠ needs review | active | @@ -40,6 +40,8 @@ LLM app and agentic workflow platform | Licence | Dify Open Source License (Apache-2.0 + conditions) ⚠ needs review · [licence evidence](https://github.com/langgenius/dify/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Custom licence: modified Apache-2.0 with additional conditions (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | 1.17.1 (2026-09-10) | | Deployment | self-hosted | @@ -57,7 +59,9 @@ Drag-and-drop agent builder | Setup docs | [Flowise setup guide](https://github.com/FlowiseAI/Flowise#readme) | | Licence | Apache-2.0 (enterprise dir separate) ⚠ needs review · [licence evidence](https://github.com/FlowiseAI/Flowise/blob/main/LICENSE.md) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | -| Repository state | archived | +| Repository state | ⚠ **archived upstream** | +| Licence review reason | Multiple licences: Apache-2.0 except the enterprise directory, which has separate terms (upstream LICENSE.md). | +| Last lookup | ok | | Last commit | 2026-08-13 | | Latest release | flowise@3.1.4 (2026-07-29) | | Deployment | self-hosted | @@ -76,6 +80,8 @@ Visual flow builder for agents and RAG | Licence | MIT · [licence evidence](https://github.com/langflow-ai/langflow/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-16 | | Latest release | v1.12.6 (2026-10-13) | | Deployment | self-hosted | @@ -94,6 +100,8 @@ Workflow automation with AI nodes | Licence | Sustainable Use License (fair-code) ⚠ needs review · [licence evidence](https://github.com/n8n-io/n8n/blob/master/LICENSE.md) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Source-available, not OSI: Sustainable Use License (fair-code) with portions under an enterprise licence (upstream LICENSE.md). | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | n8n@2.44.4 (2026-10-19) | | Deployment | self-hosted | diff --git a/docs/stacks/app-templates.md b/docs/stacks/app-templates.md index 333badd..9b91a6b 100644 --- a/docs/stacks/app-templates.md +++ b/docs/stacks/app-templates.md @@ -33,6 +33,8 @@ Browse the upstream examples repository, clone only the example you need, instal | Licence | Apache-2.0 · [licence evidence](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-18 | | Latest release | none detected | | Deployment | examples | diff --git a/docs/stacks/backend-infra.md b/docs/stacks/backend-infra.md index 46e7dfa..fd6d458 100644 --- a/docs/stacks/backend-infra.md +++ b/docs/stacks/backend-infra.md @@ -39,6 +39,8 @@ Open-source backend-as-a-service: Postgres, auth, storage, functions, AI gateway | Licence | Apache-2.0 · [licence evidence](https://github.com/butterbase-ai/butterbase/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | none detected | | Deployment | self-hosted | @@ -57,6 +59,8 @@ Postgres platform with auth, storage, pgvector | Licence | Apache-2.0 · [licence evidence](https://github.com/supabase/supabase/blob/master/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v1.26.08 (2026-08-07) | | Deployment | self-hosted | @@ -75,6 +79,8 @@ Single-file backend with realtime DB | Licence | MIT · [licence evidence](https://github.com/pocketbase/pocketbase/blob/master/LICENSE.md) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-08 | | Latest release | v0.40.5 (2026-10-08) | | Deployment | self-hosted | diff --git a/docs/stacks/chat-ui.md b/docs/stacks/chat-ui.md index c4a532d..31f1e7d 100644 --- a/docs/stacks/chat-ui.md +++ b/docs/stacks/chat-ui.md @@ -39,6 +39,8 @@ Feature-rich web UI for Ollama and OpenAI-compatible APIs | Licence | Open WebUI License (BSD-3 + branding clause) ⚠ needs review · [licence evidence](https://github.com/open-webui/open-webui/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Custom licence: BSD-3-style terms plus a clause forbidding removal or alteration of Open WebUI branding (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-16 | | Latest release | v0.12.3 (2026-10-16) | | Deployment | self-hosted | @@ -57,6 +59,8 @@ Modern multi-provider chat and agent workspace | Licence | LobeHub Community License (Apache-2.0 based) ⚠ needs review · [licence evidence](https://github.com/lobehub/lobehub/blob/canary/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Custom licence: LobeHub Community License, Apache-2.0 based with additional commercial-use conditions (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v2.2.20 (2026-10-18) | | Deployment | self-hosted | @@ -75,6 +79,8 @@ Multi-provider chat with agents, auth and plugins | Licence | MIT · [licence evidence](https://github.com/LibreChat-AI/LibreChat/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-17 | | Latest release | none detected | | Deployment | self-hosted | @@ -93,6 +99,8 @@ Minimal open-source chat front end | Licence | MIT · [licence evidence](https://github.com/mckaywrigley/chatbot-ui/blob/main/license) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2024-06-22 | | Latest release | none detected | | Deployment | self-hosted | diff --git a/docs/stacks/code-review.md b/docs/stacks/code-review.md index 2adcb31..1910024 100644 --- a/docs/stacks/code-review.md +++ b/docs/stacks/code-review.md @@ -34,6 +34,8 @@ Hybrid deterministic + LLM agent code reviewer with line-level comments | Licence | Apache-2.0 · [licence evidence](https://github.com/alibaba/open-code-review/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v1.13.2 (2026-10-20) | | Deployment | ci | @@ -49,9 +51,11 @@ PR review, describe and improve commands |---|---| | Upstream repository | [PR-Agent on GitHub](https://github.com/The-PR-Agent/pr-agent) | | Setup docs | [PR-Agent setup guide](https://github.com/The-PR-Agent/pr-agent#readme) | -| Licence | MIT · [licence evidence](https://github.com/The-PR-Agent/pr-agent/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | MIT · [licence evidence](https://github.com/The-PR-Agent/pr-agent/blob/main/LICENSE) · checked 2026-10-21 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.48.0 (2026-10-16) | | Deployment | ci | diff --git a/docs/stacks/codesbyfebin-collection.md b/docs/stacks/codesbyfebin-collection.md index 7b4cea3..a45841e 100644 --- a/docs/stacks/codesbyfebin-collection.md +++ b/docs/stacks/codesbyfebin-collection.md @@ -17,9 +17,9 @@ Hand-picked agent tools, MCP servers and experiments. | [One Person Company](#one-person-company) | Operations dashboard for solo founders | Dashboard | unknown | unknown | MIT | active | | [Kinetic](#kinetic) | GTM enrichment tables plus cold-email outreach | Sales app | unknown | unknown | MIT | active | | [CircleChat](#circlechat) | Team chat where humans and agents are members | Chat + agent runtime | unknown | unknown | MIT | active | -| [AgentDomains](#agentdomains) | CLI to claim free subdomains and DNS for agents | CLI | unknown | unknown | FSL-1.1-Apache-2.0 | active | -| [AgentDomains MCP](#agentdomains-mcp) | MCP server for subdomain/DNS management | MCP server | unknown | unknown | FSL-1.1-Apache-2.0 | active | -| [AgentDomains Skill](#agentdomains-skill) | Coding-agent skill for subdomain/DNS | Agent skill | unknown | unknown | FSL-1.1-Apache-2.0 | active | +| [AgentDomains](#agentdomains) | CLI to claim free subdomains and DNS for agents | CLI | unknown | unknown | FSL-1.1-Apache-2.0 ⚠ needs review | active | +| [AgentDomains MCP](#agentdomains-mcp) | MCP server for subdomain/DNS management | MCP server | unknown | unknown | FSL-1.1-Apache-2.0 ⚠ needs review | active | +| [AgentDomains Skill](#agentdomains-skill) | Coding-agent skill for subdomain/DNS | Agent skill | unknown | unknown | FSL-1.1-Apache-2.0 ⚠ needs review | active | | [ScallopBot](#scallopbot) | Self-hosted assistant with MCP-native memory | Assistant | unknown | unknown | MIT | active | | [Cashmaxx](#cashmaxx) | Autonomous agent with guarded crypto wallet | Agent | unknown | unknown | MIT | active | | [Jev Deep Research](#jev-deepresearch) | Deep-research crawler with planner LLM | Research agent | unknown | unknown | MIT | active | @@ -45,6 +45,8 @@ Operations dashboard for solo founders | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/OnePersonCompany/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-06 | | Latest release | none detected | | Deployment | unknown | @@ -63,6 +65,8 @@ GTM enrichment tables plus cold-email outreach | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/kinetic/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-15 | | Latest release | none detected | | Deployment | unknown | @@ -81,6 +85,8 @@ Team chat where humans and agents are members | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/circlechat/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-09-30 | | Latest release | none detected | | Deployment | unknown | @@ -96,9 +102,11 @@ CLI to claim free subdomains and DNS for agents |---|---| | Upstream repository | [AgentDomains on GitHub](https://github.com/tashfeenahmed/AgentDomains) | | Setup docs | [AgentDomains setup guide](https://github.com/tashfeenahmed/AgentDomains#readme) | -| Licence | FSL-1.1-Apache-2.0 · [licence evidence](https://github.com/tashfeenahmed/AgentDomains/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | FSL-1.1-Apache-2.0 ⚠ needs review · [licence evidence](https://github.com/tashfeenahmed/AgentDomains/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION. | +| Last lookup | ok | | Last commit | 2026-10-17 | | Latest release | v0.1.8 (2026-10-17) | | Deployment | unknown | @@ -114,9 +122,11 @@ MCP server for subdomain/DNS management |---|---| | Upstream repository | [AgentDomains MCP on GitHub](https://github.com/tashfeenahmed/AgentDomains-mcp) | | Setup docs | [AgentDomains MCP setup guide](https://github.com/tashfeenahmed/AgentDomains-mcp#readme) | -| Licence | FSL-1.1-Apache-2.0 · [licence evidence](https://github.com/tashfeenahmed/AgentDomains-mcp/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | FSL-1.1-Apache-2.0 ⚠ needs review · [licence evidence](https://github.com/tashfeenahmed/AgentDomains-mcp/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION. | +| Last lookup | ok | | Last commit | 2026-09-30 | | Latest release | none detected | | Deployment | unknown | @@ -132,9 +142,11 @@ Coding-agent skill for subdomain/DNS |---|---| | Upstream repository | [AgentDomains Skill on GitHub](https://github.com/tashfeenahmed/AgentDomains-skill) | | Setup docs | [AgentDomains Skill setup guide](https://github.com/tashfeenahmed/AgentDomains-skill#readme) | -| Licence | FSL-1.1-Apache-2.0 · [licence evidence](https://github.com/tashfeenahmed/AgentDomains-skill/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | FSL-1.1-Apache-2.0 ⚠ needs review · [licence evidence](https://github.com/tashfeenahmed/AgentDomains-skill/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Source-available, not OSI: Functional Source License 1.1 (Apache-2.0 future licence); GitHub returns NOASSERTION. | +| Last lookup | ok | | Last commit | 2026-10-17 | | Latest release | none detected | | Deployment | unknown | @@ -153,6 +165,8 @@ Self-hosted assistant with MCP-native memory | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/scallopbot/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-16 | | Latest release | v0.1.0 (2026-02-03) | | Deployment | unknown | @@ -171,6 +185,8 @@ Autonomous agent with guarded crypto wallet | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/cashmaxx/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-04 | | Latest release | none detected | | Deployment | unknown | @@ -189,6 +205,8 @@ Deep-research crawler with planner LLM | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/jev-deepresearch/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-09-22 | | Latest release | v0.1.0 (2026-09-22) | | Deployment | unknown | @@ -207,6 +225,8 @@ Emotion state classification for agents | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/emotion-state/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-02-05 | | Latest release | none detected | | Deployment | unknown | @@ -225,6 +245,8 @@ Gaze + sound touch input for laptops | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/magictap/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-14 | | Latest release | none detected | | Deployment | unknown | @@ -243,6 +265,8 @@ Mixed-reality visualisations in notebooks | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/pyreality/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2021-07-31 | | Latest release | none detected | | Deployment | unknown | @@ -261,6 +285,8 @@ Reusable HTML email template | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/html-email-template/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2021-09-19 | | Latest release | none detected | | Deployment | unknown | diff --git a/docs/stacks/coding-agents.md b/docs/stacks/coding-agents.md index c6f7e61..46d2105 100644 --- a/docs/stacks/coding-agents.md +++ b/docs/stacks/coding-agents.md @@ -40,6 +40,8 @@ Autonomous software-engineering agent | Licence | MIT · [licence evidence](https://github.com/OpenHands/OpenHands/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v1.28.1 (2026-10-19) | | Deployment | local | @@ -58,6 +60,8 @@ IDE assistant for VS Code and JetBrains | Licence | Apache-2.0 · [licence evidence](https://github.com/continuedev/continue/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-07-21 | | Latest release | v2.0.0-vscode (2026-06-19) | | Deployment | local | @@ -76,6 +80,8 @@ Terminal pair programmer working on git repos | Licence | Apache-2.0 · [licence evidence](https://github.com/Aider-AI/aider/blob/main/LICENSE.txt) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-05-22 | | Latest release | v0.86.0 (2025-08-09) | | Deployment | local | @@ -94,6 +100,8 @@ Terminal coding agent | Licence | MIT · [licence evidence](https://github.com/anomalyco/opencode/blob/dev/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v1.19.3 (2026-10-16) | | Deployment | local | @@ -112,6 +120,8 @@ Autonomous coding agent in VS Code | Licence | Apache-2.0 · [licence evidence](https://github.com/cline/cline/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | desktop-v0.0.48 (2026-10-17) | | Deployment | local | diff --git a/docs/stacks/eval-observability.md b/docs/stacks/eval-observability.md index dc3cb0b..463aa51 100644 --- a/docs/stacks/eval-observability.md +++ b/docs/stacks/eval-observability.md @@ -15,7 +15,7 @@ Tracing, evaluations and prompt management. | Project | What it does | Highlight (editorial) | Deployment | Hardware | Licence | Status | |---|---|---|---|---|---|---| | [Langfuse](#langfuse) | LLM tracing, evals and prompt management | Tracing platform | library, self-hosted | cpu-ok | MIT (ee/ dirs separate) ⚠ needs review | active | -| [Phoenix](#phoenix) | AI observability and evaluation | Notebook + server | library, self-hosted | cpu-ok | Elastic-2.0 | active | +| [Phoenix](#phoenix) | AI observability and evaluation | Notebook + server | library, self-hosted | cpu-ok | Elastic-2.0 ⚠ needs review | active | | [promptfoo](#promptfoo) | Prompt testing and red-teaming CLI | CI evals | library, self-hosted | cpu-ok | MIT | active | | [DeepEval](#deepeval) | Unit-test style LLM evaluation | pytest-style | library, self-hosted | cpu-ok | Apache-2.0 | active | @@ -40,6 +40,8 @@ LLM tracing, evals and prompt management | Licence | MIT (ee/ dirs separate) ⚠ needs review · [licence evidence](https://github.com/langfuse/langfuse/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Multiple licences: MIT except ee/ directories, which have separate terms (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v4.66.0 (2026-10-20) | | Deployment | library, self-hosted | @@ -55,9 +57,11 @@ AI observability and evaluation |---|---| | Upstream repository | [Phoenix on GitHub](https://github.com/Arize-ai/phoenix) | | Setup docs | [Phoenix setup guide](https://github.com/Arize-ai/phoenix#readme) | -| Licence | Elastic-2.0 · [licence evidence](https://github.com/Arize-ai/phoenix/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | Elastic-2.0 ⚠ needs review · [licence evidence](https://github.com/Arize-ai/phoenix/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Source-available, not OSI: Elastic License 2.0 (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | arize-phoenix-sqlean-v0.2.1 (2026-10-19) | | Deployment | library, self-hosted | @@ -76,6 +80,8 @@ Prompt testing and red-teaming CLI | Licence | MIT · [licence evidence](https://github.com/promptfoo/promptfoo/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | code-scan-action-0.2.2 (2026-10-08) | | Deployment | library, self-hosted | @@ -94,6 +100,8 @@ Unit-test style LLM evaluation | Licence | Apache-2.0 · [licence evidence](https://github.com/confident-ai/deepeval/blob/main/LICENSE.md) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-19 | | Latest release | python-v4.2.4 (2026-09-22) | | Deployment | library, self-hosted | diff --git a/docs/stacks/gateways-routing.md b/docs/stacks/gateways-routing.md index e97b818..d862ce9 100644 --- a/docs/stacks/gateways-routing.md +++ b/docs/stacks/gateways-routing.md @@ -17,7 +17,7 @@ OpenAI-compatible gateways, routers, guardrail firewalls and free-LLM aggregator | [FreeLLMAPI](#freellmapi) | Aggregates free LLM providers behind one /v1 endpoint with failover | Free-tier aggregation | self-hosted | cpu-ok | MIT | active | | [OpenCode Free Router](#opencode-free-9router) | Routes coding-agent traffic to free model endpoints | Free routing for coding agents | self-hosted | cpu-ok | MIT | active | | [Bifrost](#bifrost) | High-performance AI gateway with load balancing and fallbacks | Low-latency gateway | self-hosted | cpu-ok | Apache-2.0 | active | -| [Trylon Gateway](#trylon-gateway) | Self-hosted LLM firewall with guardrails | Guardrails / security | self-hosted | cpu-ok | BUSL-1.1 | active | +| [Trylon Gateway](#trylon-gateway) | Self-hosted LLM firewall with guardrails | Guardrails / security | self-hosted | cpu-ok | BUSL-1.1 ⚠ needs review | active | | [LiteLLM](#litellm) | Proxy + SDK for 100+ LLM APIs in OpenAI format, cost tracking | Broadest provider coverage | self-hosted | cpu-ok | MIT (enterprise/ dir separate) ⚠ needs review | active | | [Portkey Gateway](#portkey-gateway) | Fast AI gateway with routing, retries and caching | Edge-friendly gateway | self-hosted | cpu-ok | MIT | active | @@ -43,6 +43,8 @@ Aggregates free LLM providers behind one /v1 endpoint with failover | Licence | MIT · [licence evidence](https://github.com/tashfeenahmed/freellmapi/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.16.6 (2026-10-20) | | Deployment | self-hosted | @@ -61,6 +63,8 @@ Routes coding-agent traffic to free model endpoints | Licence | MIT · [licence evidence](https://github.com/0xgetz/opencode-free-9router/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-17 | | Latest release | none detected | | Deployment | self-hosted | @@ -79,6 +83,8 @@ High-performance AI gateway with load balancing and fallbacks | Licence | Apache-2.0 · [licence evidence](https://github.com/maximhq/bifrost/blob/dev/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-19 | | Latest release | ent-v2.3.1-base (2026-10-19) | | Deployment | self-hosted | @@ -94,9 +100,11 @@ Self-hosted LLM firewall with guardrails |---|---| | Upstream repository | [Trylon Gateway on GitHub](https://github.com/trylonai/gateway) | | Setup docs | [Trylon Gateway setup guide](https://github.com/trylonai/gateway#readme) | -| Licence | BUSL-1.1 · [licence evidence](https://github.com/trylonai/gateway/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | BUSL-1.1 ⚠ needs review · [licence evidence](https://github.com/trylonai/gateway/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Source-available, not OSI: Business Source License 1.1 with a use limitation (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2025-06-25 | | Latest release | none detected | | Deployment | self-hosted | @@ -115,8 +123,10 @@ Proxy + SDK for 100+ LLM APIs in OpenAI format, cost tracking | Licence | MIT (enterprise/ dir separate) ⚠ needs review · [licence evidence](https://github.com/BerriAI/litellm/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Multiple licences: MIT for most code, separate licence for the enterprise/ directory (stated at top of upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-20 | -| Latest release | v1.106.0 (2026-10-18) | +| Latest release | v1.106.1 (2026-10-20) | | Deployment | self-hosted | | Hardware | cpu-ok | | Languages | Python | @@ -133,6 +143,8 @@ Fast AI gateway with routing, retries and caching | Licence | MIT · [licence evidence](https://github.com/Portkey-AI/gateway/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-05-25 | | Latest release | v1.15.2 (2026-01-12) | | Deployment | self-hosted | diff --git a/docs/stacks/inference-serving.md b/docs/stacks/inference-serving.md index de4c3cb..2ad56d2 100644 --- a/docs/stacks/inference-serving.md +++ b/docs/stacks/inference-serving.md @@ -16,7 +16,7 @@ High-throughput production model serving on GPUs. |---|---|---|---|---|---|---| | [vLLM](#vllm) | PagedAttention-based high-throughput server | Throughput | self-hosted | gpu-required | Apache-2.0 | active | | [SGLang](#sglang) | Fast serving with structured generation | Structured outputs | self-hosted | gpu-required | Apache-2.0 | active | -| [Text Generation Inference](#text-generation-inference) | Production LLM server | HF Hub integration | self-hosted | gpu-required | Apache-2.0 | archived | +| [Text Generation Inference](#text-generation-inference) | Production LLM server | HF Hub integration | self-hosted | gpu-required | Apache-2.0 | ⚠ **archived upstream** | | [Triton Inference Server](#triton-server) | Multi-framework model server | Mixed model fleets | self-hosted | gpu-required | BSD-3-Clause | active | ## Quick start @@ -40,6 +40,8 @@ PagedAttention-based high-throughput server | Licence | Apache-2.0 · [licence evidence](https://github.com/vllm-project/vllm/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.32.0 (2026-10-18) | | Deployment | self-hosted | @@ -58,6 +60,8 @@ Fast serving with structured generation | Licence | Apache-2.0 · [licence evidence](https://github.com/sgl-project/sglang/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.5.22 (2026-10-19) | | Deployment | self-hosted | @@ -75,7 +79,9 @@ Production LLM server | Setup docs | [Text Generation Inference setup guide](https://github.com/huggingface/text-generation-inference#readme) | | Licence | Apache-2.0 · [licence evidence](https://github.com/huggingface/text-generation-inference/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | -| Repository state | archived | +| Repository state | ⚠ **archived upstream** | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-03-21 | | Latest release | v3.3.7 (2025-12-19) | | Deployment | self-hosted | @@ -94,6 +100,8 @@ Multi-framework model server | Licence | BSD-3-Clause · [licence evidence](https://github.com/triton-inference-server/server/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | BSD-3-Clause | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-15 | | Latest release | v2.73.0 (2026-09-30) | | Deployment | self-hosted | diff --git a/docs/stacks/local-models.md b/docs/stacks/local-models.md index d6b8e63..0538699 100644 --- a/docs/stacks/local-models.md +++ b/docs/stacks/local-models.md @@ -17,7 +17,7 @@ Run LLMs on your own laptop or server. | [GPT4All](#gpt4all) | Desktop app for private local LLM chat | Non-technical desktop users | local | cpu-ok | MIT | active | | [Ollama](#ollama) | One-command local model runner with OpenAI-compatible API | Easiest local API | local | cpu-ok | MIT | active | | [llama.cpp](#llamacpp) | Portable C/C++ inference for GGUF models | CPU / Apple Silicon | local | cpu-ok | MIT | active | -| [llamafile](#llamafile) | Single-file executable LLMs | Zero-install distribution | local | cpu-ok | Apache-2.0 | active | +| [llamafile](#llamafile) | Single-file executable LLMs | Zero-install distribution | local | cpu-ok | Apache-2.0 ⚠ needs review | active | | [LocalAI](#localai) | Drop-in OpenAI API replacement for local models | Multi-modal local API | local | cpu-ok | MIT | active | | [Text Generation WebUI](#text-generation-webui) | Gradio UI supporting many backends | Experimenting with backends | local | cpu-ok | AGPL-3.0 | active | @@ -42,6 +42,8 @@ Desktop app for private local LLM chat | Licence | MIT · [licence evidence](https://github.com/nomic-ai/gpt4all/blob/main/LICENSE.txt) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2025-05-27 | | Latest release | v3.10.0 (2025-02-25) | | Deployment | local | @@ -60,6 +62,8 @@ One-command local model runner with OpenAI-compatible API | Licence | MIT · [licence evidence](https://github.com/ollama/ollama/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.40.6 (2026-10-16) | | Deployment | local | @@ -78,6 +82,8 @@ Portable C/C++ inference for GGUF models | Licence | MIT · [licence evidence](https://github.com/ggml-org/llama.cpp/blob/master/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.7.0 (2026-10-15) | | Deployment | local | @@ -93,9 +99,11 @@ Single-file executable LLMs |---|---| | Upstream repository | [llamafile on GitHub](https://github.com/mozilla-ai/llamafile) | | Setup docs | [llamafile setup guide](https://github.com/mozilla-ai/llamafile#readme) | -| Licence | Apache-2.0 · [licence evidence](https://github.com/mozilla-ai/llamafile/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | Apache-2.0 ⚠ needs review · [licence evidence](https://github.com/mozilla-ai/llamafile/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | LICENSE text is Apache-2.0 but GitHub's detector returns NOASSERTION; vendored third-party components not reviewed. | +| Last lookup | ok | | Last commit | 2026-10-08 | | Latest release | 0.10.6 (2026-09-15) | | Deployment | local | @@ -114,6 +122,8 @@ Drop-in OpenAI API replacement for local models | Licence | MIT · [licence evidence](https://github.com/mudler/LocalAI/blob/master/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v4.11.0 (2026-10-02) | | Deployment | local | @@ -132,6 +142,8 @@ Gradio UI supporting many backends | Licence | AGPL-3.0 · [licence evidence](https://github.com/oobabooga/textgen/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | AGPL-3.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-08-17 | | Latest release | v4.9 (2026-05-20) | | Deployment | local | diff --git a/docs/stacks/memory.md b/docs/stacks/memory.md index 98f7fa2..ab64563 100644 --- a/docs/stacks/memory.md +++ b/docs/stacks/memory.md @@ -40,6 +40,8 @@ Universal memory layer for AI agents | Licence | Apache-2.0 · [licence evidence](https://github.com/mem0ai/mem0/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-14 | | Latest release | ts-v3.3.1 (2026-09-25) | | Deployment | library, self-hosted | @@ -55,9 +57,11 @@ Local-first memory server (MCP) for AI tools |---|---| | Upstream repository | [OpenMemory on GitHub](https://github.com/mem0ai/openmemory) | | Setup docs | [OpenMemory setup guide](https://github.com/mem0ai/openmemory#readme) | -| Licence | MIT · [licence evidence](https://github.com/mem0ai/openmemory/blob/main/LICENSE) · checked 2026-10-20 | +| Licence | MIT · [licence evidence](https://github.com/mem0ai/openmemory/blob/main/LICENSE) · checked 2026-10-21 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-07-29 | | Latest release | none detected | | Deployment | library, self-hosted | @@ -76,6 +80,8 @@ Stateful agents with self-editing memory | Licence | Apache-2.0 · [licence evidence](https://github.com/letta-ai/letta/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-18 | | Latest release | 0.16.8 (2026-05-14) | | Deployment | library, self-hosted | @@ -94,6 +100,8 @@ Temporal knowledge-graph memory | Licence | Apache-2.0 · [licence evidence](https://github.com/getzep/graphiti/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v0.31.2 (2026-10-20) | | Deployment | library, self-hosted | diff --git a/docs/stacks/rag-vector-db.md b/docs/stacks/rag-vector-db.md index b03c03e..87e634e 100644 --- a/docs/stacks/rag-vector-db.md +++ b/docs/stacks/rag-vector-db.md @@ -43,6 +43,8 @@ Data framework for RAG | Licence | MIT · [licence evidence](https://github.com/run-llama/llama_index/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | MIT | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-14 | | Latest release | v0.14.25 (2026-09-21) | | Deployment | library, self-hosted | @@ -61,6 +63,8 @@ Production RAG pipelines | Licence | Apache-2.0 · [licence evidence](https://github.com/deepset-ai/haystack/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v3.4.0 (2026-10-15) | | Deployment | library, self-hosted | @@ -79,6 +83,8 @@ Deep-document-understanding RAG engine | Licence | Apache-2.0 · [licence evidence](https://github.com/infiniflow/ragflow/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v1.0.0-rc2 (2026-10-16) | | Deployment | library, self-hosted | @@ -97,6 +103,8 @@ Vector search engine | Licence | Apache-2.0 · [licence evidence](https://github.com/qdrant/qdrant/blob/master/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-05 | | Latest release | v1.19.2 (2026-10-05) | | Deployment | library, self-hosted | @@ -115,6 +123,8 @@ Embedding database | Licence | Apache-2.0 · [licence evidence](https://github.com/chroma-core/chroma/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-17 | | Latest release | 1.5.9 (2026-05-05) | | Deployment | library, self-hosted | @@ -133,6 +143,8 @@ Cloud-native vector database | Licence | Apache-2.0 · [licence evidence](https://github.com/milvus-io/milvus/blob/master/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | Apache-2.0 | | Repository state | active | +| Licence review reason | – | +| Last lookup | ok | | Last commit | 2026-10-20 | | Latest release | v3.0.3 (2026-10-14) | | Deployment | library, self-hosted | @@ -151,6 +163,8 @@ Vector DB with hybrid search | Licence | BSD-3-Clause (core) ⚠ needs review · [licence evidence](https://github.com/weaviate/weaviate/blob/main/LICENSE) · checked 2026-10-20 | | Licence detected by GitHub | NOASSERTION | | Repository state | active | +| Licence review reason | Multiple licences: source is variously BSD-3-Clause or the Weaviate License (upstream LICENSE). | +| Last lookup | ok | | Last commit | 2026-10-16 | | Latest release | v1.40.1 (2026-10-13) | | Deployment | library, self-hosted | diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index b8ec997..32a165a 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -4,3 +4,8 @@ .osa-filters input:focus,.osa-filters select:focus{outline:3px solid var(--md-accent-fg-color);outline-offset:1px} .osa-table-wrap{overflow-x:auto} #osa-results caption{text-align:left;font-weight:600} +.osa-archived{color:#9a3412} +[data-md-color-scheme="slate"] .osa-archived{color:#fdba74} +#f-clear{align-self:end;margin:0;padding:.35rem .8rem;font-size:.75rem} +a:focus-visible,button:focus-visible,summary:focus-visible{outline:3px solid var(--md-accent-fg-color);outline-offset:2px} +.md-copyright,.md-copyright__highlight{color:#e5e7eb} diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md new file mode 100644 index 0000000..f42ff89 --- /dev/null +++ b/docs/wiki/Home.md @@ -0,0 +1,35 @@ +> **Unpublished draft.** The GitHub wiki for this repository has not been initialised (its git remote returns "not found"). To publish: open the repo's **Wiki** tab, click *Create the first page*, paste everything below the line, and save as **Home**. + +--- + +# Open Source Ai – Wiki + +**Purpose.** Open Source Ai by CodesbyFebin is a curated, evidence-backed catalog of open-source and source-available projects for building AI agents and LLM apps. It contains metadata, comparisons and recipes – not upstream source code. + +- **Search & filter:** https://codesbyfebin.github.io/Open-Source-Ai/catalog/ +- **Docs site:** https://codesbyfebin.github.io/Open-Source-Ai/ + +## Selection criteria + +Projects must have a licence file, be maintained or widely used, be self-hostable or usable as a library, and fit a catalog category. Full criteria: https://codesbyfebin.github.io/Open-Source-Ai/selection-criteria/ + +## Recipes + +| Recipe | Status | +|---|---| +| Local private chat (Ollama + LiteLLM + Open WebUI) | tested in CI on every push | +| Agent with memory and evaluation (Ollama + Mem0 + Qdrant + promptfoo) | tested in CI (non-required workflow; runs on recipe changes and weekly) | + +## Contributing + +1. Edit `catalog/projects.yaml` (never generated pages). +2. Run `python scripts/build.py && python scripts/validate.py && python -m pytest -q tests`. +3. Open a pull request and complete the checklist. Details: `CONTRIBUTING.md`. + +## Licence caveat + +The MIT licence covers only this repository's curation, docs and code. Every catalogued project is governed by its own upstream licence. Entries marked **needs review** have custom, multiple, source-available or undetected licences – read the upstream terms before use. + +## Freshness + +A workflow collects repository state, last commit, latest release and licence detection from the GitHub API every Monday 03:00 UTC and opens a pull request for human review. It is not real-time monitoring. Report: https://codesbyfebin.github.io/Open-Source-Ai/freshness/ diff --git a/mkdocs.yml b/mkdocs.yml index dc608cb..8629292 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,7 +23,7 @@ extra: - icon: fontawesome/brands/github link: https://github.com/CodesbyFebin plugins: [search] -extra_javascript: [javascripts/catalog.js] +extra_javascript: [javascripts/a11y.js, javascripts/catalog.js] extra_css: [stylesheets/extra.css] markdown_extensions: [attr_list, admonition, tables, toc, pymdownx.superfences, pymdownx.highlight] nav: @@ -54,3 +54,6 @@ nav: - Freshness Report: freshness.md - Selection Criteria: selection-criteria.md - Credits & Licences: credits.md + +exclude_docs: | + wiki/ diff --git a/recipes/agent-memory-eval/README.md b/recipes/agent-memory-eval/README.md index e8d5200..f4ecf9f 100644 --- a/recipes/agent-memory-eval/README.md +++ b/recipes/agent-memory-eval/README.md @@ -1,25 +1,43 @@ # Agent with persistent memory and evaluation: Ollama + Mem0 + Qdrant + promptfoo -**Data flow:** `agent.py` → Mem0 (extracts facts) → Qdrant (vectors) · `agent.py` → Ollama (chat + embeddings) · promptfoo runs `agent.py` and asserts on answers. +**Data flow:** `agent.py remember` → Mem0 → Ollama embeddings → Qdrant · `agent.py ask` → Mem0 search (Qdrant) → Ollama chat with retrieved facts · promptfoo runs `agent.py ask` and asserts on the answers. + +## Pinned versions + +| Component | Version | +|---|---| +| Ollama | `ollama/ollama:0.40.6` | +| Qdrant | `qdrant/qdrant:v1.19.2` | +| Mem0 | `mem0ai==2.2.1` (see `requirements.txt`) | +| promptfoo | `promptfoo@0.124.1` | +| Models | `qwen2.5:1.5b` (~1 GB), `nomic-embed-text:v1.5` (~0.3 GB) | ## Requirements -- Docker 24+ with Compose v2, Python 3.10+, Node.js 18+ (for promptfoo) -- 8 GB RAM, ~6 GB disk; CPU is enough for the 1.5B model +- Docker 24+ with Compose v2, Python 3.10+, Node.js 22.22+ (promptfoo 0.124 requirement) +- 4 vCPU, 8 GB RAM, ~6 GB disk; no GPU needed. Cold start ~3–5 minutes (image + model pulls). ## Run ```bash cd Open-Source-Ai/recipes/agent-memory-eval -docker compose up -d -docker compose exec ollama ollama pull qwen2.5:1.5b -docker compose exec ollama ollama pull nomic-embed-text -python -m venv .venv && . .venv/bin/activate && pip install mem0ai openai -python agent.py "Hi, my favourite language is Python." -python agent.py "What is my favourite language?" -npx promptfoo@latest eval +python -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt +./smoke.sh # full end-to-end test (cleans up on exit; KEEP=1 to keep containers) ``` +Or step by step: + +```bash +docker compose up -d && docker compose wait model-pull +python agent.py remember "My favourite programming language is Rust." +docker compose restart qdrant # memory survives the restart +python agent.py recall "favourite language" +python agent.py ask "Which programming language does the user prefer?" +npx promptfoo@0.124.1 eval +``` + +`remember` stores facts verbatim (`infer=False`) so the test is deterministic; set `INFER=1` to let the LLM extract facts (less reliable with small models). + ## Clean up ```bash @@ -28,5 +46,5 @@ docker compose down -v && rm -rf .venv ## Known limitations -- **Unverified:** this recipe has not been run end-to-end yet; Mem0 config keys may differ between versions. -- Small models extract memories unreliably; use 7B+ for meaningful results. +- Tests memory storage, persistence across a Qdrant restart and a new process, and that answers use stored facts. Does not test Mem0's LLM-based fact extraction, multi-user isolation or tool use. +- Small models can phrase answers unexpectedly; assertions only check for the key word. diff --git a/recipes/agent-memory-eval/agent.py b/recipes/agent-memory-eval/agent.py index 710dea1..029d1e4 100644 --- a/recipes/agent-memory-eval/agent.py +++ b/recipes/agent-memory-eval/agent.py @@ -1,23 +1,46 @@ -"""Minimal agent with long-term memory. Untested recipe – see README.""" -import sys +"""Minimal agent with long-term memory (Mem0 + Qdrant) on a local Ollama model. + +Usage: + python agent.py remember "" # store a fact for user 'demo' + python agent.py recall "" # print stored memories matching the query + python agent.py ask "" # answer using retrieved memories +""" +import os, sys +os.environ.setdefault("MEM0_TELEMETRY", "False") from mem0 import Memory from openai import OpenAI -MODEL = "qwen2.5:1.5b" +CHAT = os.environ.get("CHAT_MODEL", "qwen2.5:1.5b") +EMBED = os.environ.get("EMBED_MODEL", "nomic-embed-text:v1.5") +OLLAMA = os.environ.get("OLLAMA_URL", "http://localhost:11434") +USER = "demo" + memory = Memory.from_config({ - "llm": {"provider": "ollama", "config": {"model": MODEL, "ollama_base_url": "http://localhost:11434"}}, - "embedder": {"provider": "ollama", "config": {"model": "nomic-embed-text", "ollama_base_url": "http://localhost:11434"}}, - "vector_store": {"provider": "qdrant", "config": {"host": "localhost", "port": 6333, "embedding_model_dims": 768}}, + "llm": {"provider": "ollama", "config": {"model": CHAT, "ollama_base_url": OLLAMA, "temperature": 0}}, + "embedder": {"provider": "ollama", "config": {"model": EMBED, "ollama_base_url": OLLAMA}}, + "vector_store": {"provider": "qdrant", "config": {"host": "localhost", "port": 6333, "collection_name": "osa_demo", "embedding_model_dims": 768}}, }) -llm = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama") -def chat(user_id: str, text: str) -> str: - facts = "\n".join(m["memory"] for m in memory.search(text, user_id=user_id).get("results", [])) - reply = llm.chat.completions.create(model=MODEL, messages=[ - {"role": "system", "content": f"Known facts about the user:\n{facts or 'none'}"}, - {"role": "user", "content": text}]).choices[0].message.content - memory.add([{"role": "user", "content": text}, {"role": "assistant", "content": reply}], user_id=user_id) - return reply + +def hits(q): + r = memory.search(q, filters={"user_id": USER}) # mem0 2.x API + return [m["memory"] for m in (r.get("results", r) if isinstance(r, dict) else r)] + + +def ask(q): + facts = "\n".join(hits(q)) or "none" + llm = OpenAI(base_url=OLLAMA + "/v1", api_key="ollama") + return llm.chat.completions.create(model=CHAT, temperature=0, messages=[ + {"role": "system", "content": "Answer in one short sentence using only these facts about the user:\n" + facts}, + {"role": "user", "content": q}]).choices[0].message.content + if __name__ == "__main__": - print(chat("demo", " ".join(sys.argv[1:]) or "Hi, my favourite language is Python.")) + cmd, text = sys.argv[1], " ".join(sys.argv[2:]) + if cmd == "remember": + # infer=False stores the fact verbatim (deterministic); infer=True lets the LLM extract facts + print(memory.add([{"role": "user", "content": text}], user_id=USER, infer=os.environ.get("INFER", "0") == "1")) + elif cmd == "recall": + print("\n".join(hits(text))) + elif cmd == "ask": + print(ask(text)) diff --git a/recipes/agent-memory-eval/docker-compose.yml b/recipes/agent-memory-eval/docker-compose.yml index 129c6ef..b6d7154 100644 --- a/recipes/agent-memory-eval/docker-compose.yml +++ b/recipes/agent-memory-eval/docker-compose.yml @@ -1,10 +1,17 @@ services: ollama: - image: ollama/ollama:latest + image: ollama/ollama:0.40.6 ports: ["11434:11434"] volumes: [ollama:/root/.ollama] + healthcheck: {test: ["CMD", "ollama", "list"], interval: 10s, retries: 12} + model-pull: + image: ollama/ollama:0.40.6 + depends_on: {ollama: {condition: service_healthy}} + environment: {OLLAMA_HOST: "http://ollama:11434"} + entrypoint: ["sh", "-c", "ollama pull ${CHAT_MODEL:-qwen2.5:1.5b} && ollama pull ${EMBED_MODEL:-nomic-embed-text:v1.5}"] + restart: "no" qdrant: - image: qdrant/qdrant:latest + image: qdrant/qdrant:v1.19.2 ports: ["6333:6333"] volumes: [qdrant:/qdrant/storage] volumes: {ollama: {}, qdrant: {}} diff --git a/recipes/agent-memory-eval/promptfooconfig.yaml b/recipes/agent-memory-eval/promptfooconfig.yaml index 257f381..4ae70d1 100644 --- a/recipes/agent-memory-eval/promptfooconfig.yaml +++ b/recipes/agent-memory-eval/promptfooconfig.yaml @@ -1,9 +1,13 @@ -description: Memory recall regression test (untested recipe) +description: Agent answers from long-term memory stored in a previous session +prompts: ["{{question}}"] providers: - - id: exec:python agent.py + - id: "exec: python agent.py ask" tests: - - vars: {prompt: "What is my favourite language?"} + - vars: {question: "Which programming language does the user prefer?"} assert: - type: icontains - value: python -prompts: ["{{prompt}}"] + value: rust + - vars: {question: "What city does the user live in?"} + assert: + - type: icontains + value: lisbon diff --git a/recipes/agent-memory-eval/recipe.yaml b/recipes/agent-memory-eval/recipe.yaml index c7d5195..aaf81ae 100644 --- a/recipes/agent-memory-eval/recipe.yaml +++ b/recipes/agent-memory-eval/recipe.yaml @@ -2,5 +2,5 @@ title: Agent with persistent memory and evaluation summary: A small Python agent uses a local model via Ollama, stores long-term memory with Mem0 (Qdrant backend), and is regression-tested with promptfoo. components: [ollama, mem0, qdrant, promptfoo] test: - status: unverified - details: "Not yet run end-to-end. Missing evidence: a successful run of agent.py with Mem0's Ollama provider and a passing promptfoo eval. Treat the commands as a starting point." + status: tested + details: "Workflow `Recipe – agent-memory-eval` (run 39490869588, 2026-10-20 UTC, GitHub-hosted ubuntu-latest, 4 vCPU, 16 GB, no GPU, ~156 s) ran smoke.sh: stored two facts, restarted Qdrant, recalled 'Rust' from a new process, and promptfoo passed 2/2 assertions (answers contained 'rust' and 'lisbon', words absent from the questions). Pinned: Ollama 0.40.6, Qdrant v1.19.2, mem0ai 2.2.1, promptfoo 0.124.1, qwen2.5:1.5b, nomic-embed-text:v1.5. Runs on recipe changes, weekly and on demand; not a required check. Not tested: Mem0 LLM fact extraction (infer=True), tool use, multi-user isolation." diff --git a/recipes/agent-memory-eval/requirements.txt b/recipes/agent-memory-eval/requirements.txt new file mode 100644 index 0000000..622bf48 --- /dev/null +++ b/recipes/agent-memory-eval/requirements.txt @@ -0,0 +1,4 @@ +mem0ai==2.2.1 +ollama==0.6.3 +openai==3.35.1 +qdrant-client==1.19.1 diff --git a/recipes/agent-memory-eval/smoke.sh b/recipes/agent-memory-eval/smoke.sh new file mode 100755 index 0000000..dac8289 --- /dev/null +++ b/recipes/agent-memory-eval/smoke.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# End-to-end: services up -> store memories (session 1) -> restart Qdrant -> new process +# recalls them (session 2) -> promptfoo asserts the agent's answers use the memories. +set -euo pipefail +cd "$(dirname "$0")" +cleanup() { status=$?; [ $status -ne 0 ] && docker compose logs --tail 60 || true; [ "${KEEP:-0}" = 1 ] || docker compose down -v >/dev/null 2>&1 || true; exit $status; } +trap cleanup EXIT +start=$(date +%s) +docker compose config --quiet +docker compose up -d +docker compose wait model-pull +for i in $(seq 1 30); do curl -fsS http://localhost:6333/readyz >/dev/null 2>&1 && break; sleep 2; done +python agent.py remember "My favourite programming language is Rust." +python agent.py remember "I live in Lisbon, Portugal." +echo "--- restarting qdrant to prove persistence" +docker compose restart qdrant +for i in $(seq 1 30); do curl -fsS http://localhost:6333/readyz >/dev/null 2>&1 && break; sleep 2; done +out=$(python agent.py recall "favourite programming language") +echo "session 2 recall: $out" +echo "$out" | grep -qi rust || { echo "memory not recalled after restart"; exit 1; } +npx --yes promptfoo@0.124.1 eval --no-cache --no-progress-bar -o /tmp/promptfoo.json +python3 -c 'import json;r=json.load(open("/tmp/promptfoo.json"))["results"]["stats"];print("promptfoo", r);assert r["failures"]==0 and r["successes"]>=2' +docker compose images +echo "elapsed $(( $(date +%s) - start ))s" +echo "SMOKE TEST PASSED" diff --git a/recipes/local-chat/README.md b/recipes/local-chat/README.md index 8bddb13..3bfa1d4 100644 --- a/recipes/local-chat/README.md +++ b/recipes/local-chat/README.md @@ -13,6 +13,17 @@ No accounts or paid API keys are needed. +## Pinned versions + +| Component | Version | +|---|---| +| Ollama | `ollama/ollama:0.40.6` | +| LiteLLM | `ghcr.io/berriai/litellm:v1.106.1` | +| Open WebUI | `ghcr.io/open-webui/open-webui:v0.12.3` | +| Model | `qwen2.5:0.5b` (~0.4 GB) | + +Typical cold start on a 4-vCPU CI runner: about 2 minutes (image pulls dominate). + ## Run ```bash @@ -28,7 +39,8 @@ Environment variables: `LITELLM_MASTER_KEY` (gateway key, default is a placehold ## Verify ```bash -./smoke.sh # same test CI runs +./smoke.sh # same test CI runs; asks 17+25 and checks the model answers 42, + # token usage is reported, and Ollama's own log shows the request # or manually curl -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H 'Content-Type: application/json' \ http://localhost:4000/v1/chat/completions \ @@ -47,4 +59,4 @@ docker compose down -v # also delete models and chats ## Known limitations - `qwen2.5:0.5b` is a tiny model chosen so CI can run on CPU; answers are low quality. Use a 3B–8B model for real use. -- Images use moving tags (`latest`, `main`, `main-stable`); the exact digests tested are in the CI log. +- Ollama model tags are not immutable; the digest actually pulled is printed by `ollama list` in the CI log. diff --git a/recipes/local-chat/docker-compose.yml b/recipes/local-chat/docker-compose.yml index 644caa7..b5d5380 100644 --- a/recipes/local-chat/docker-compose.yml +++ b/recipes/local-chat/docker-compose.yml @@ -1,7 +1,7 @@ # Open Source Ai – local full stack: Ollama (models) -> LiteLLM (gateway) -> Open WebUI (chat) services: ollama: - image: ollama/ollama:latest + image: ollama/ollama:0.40.6 volumes: [ollama:/root/.ollama] ports: ["11434:11434"] healthcheck: @@ -9,20 +9,20 @@ services: interval: 10s retries: 12 model-pull: - image: ollama/ollama:latest + image: ollama/ollama:0.40.6 depends_on: {ollama: {condition: service_healthy}} environment: {OLLAMA_HOST: "http://ollama:11434"} entrypoint: ["ollama", "pull", "${MODEL:-qwen2.5:0.5b}"] restart: "no" litellm: - image: ghcr.io/berriai/litellm:main-stable + image: ghcr.io/berriai/litellm:v1.106.1 command: ["--config", "/app/config.yaml", "--port", "4000"] volumes: ["./litellm-config.yaml:/app/config.yaml:ro"] environment: {LITELLM_MASTER_KEY: "${LITELLM_MASTER_KEY:-sk-local-change-me}"} ports: ["4000:4000"] depends_on: [ollama] open-webui: - image: ghcr.io/open-webui/open-webui:main + image: ghcr.io/open-webui/open-webui:v0.12.3 environment: OPENAI_API_BASE_URL: "http://litellm:4000/v1" OPENAI_API_KEY: "${LITELLM_MASTER_KEY:-sk-local-change-me}" diff --git a/recipes/local-chat/recipe.yaml b/recipes/local-chat/recipe.yaml index d597910..df58417 100644 --- a/recipes/local-chat/recipe.yaml +++ b/recipes/local-chat/recipe.yaml @@ -3,4 +3,4 @@ summary: Ollama serves a small local model, LiteLLM exposes it as an OpenAI-comp components: [ollama, litellm, open-webui] test: status: tested - details: "CI job `recipe-local-chat` runs recipes/local-chat/smoke.sh on GitHub-hosted ubuntu-latest (4 vCPU, 16 GB, no GPU) on every push to main: compose validation, model pull (qwen2.5:0.5b), a chat completion through the gateway and the Open WebUI health endpoint. Image digests are printed in the job log. Not tested: GPUs, larger models, the browser UI flow." + details: "CI job `recipe-local-chat` runs recipes/local-chat/smoke.sh on GitHub-hosted ubuntu-latest (4 vCPU, 16 GB RAM, no GPU) on every push and PR. It validates the compose file, pulls qwen2.5:0.5b, asks the gateway 17+25 and asserts the reply contains 42 with non-zero completion tokens, checks `ollama ps` shows the model loaded and Ollama's log shows the chat request, and checks the Open WebUI health endpoint. Pinned: Ollama 0.40.6, LiteLLM v1.106.1, Open WebUI v0.12.3. Not tested: GPUs, larger models, the browser chat flow in Open WebUI." diff --git a/recipes/local-chat/smoke.sh b/recipes/local-chat/smoke.sh index ef31ecd..559c30f 100755 --- a/recipes/local-chat/smoke.sh +++ b/recipes/local-chat/smoke.sh @@ -1,17 +1,33 @@ #!/usr/bin/env bash -# Smoke test: model -> gateway -> chat UI. Safe for CI (~0.4 GB model, CPU only, no paid APIs). +# Smoke test: model -> gateway -> chat UI. CPU only, ~0.4 GB model, no paid APIs. +# Proves the reply came from the local model: arithmetic answer, token usage, model +# reported by the gateway, and Ollama's own log/ps showing the request and loaded model. set -euo pipefail cd "$(dirname "$0")" -export LITELLM_MASTER_KEY="${LITELLM_MASTER_KEY:-sk-ci-$(date +%s)}" +export LITELLM_MASTER_KEY="${LITELLM_MASTER_KEY:-sk-ci-$RANDOM$RANDOM}" +cleanup() { status=$?; [ $status -ne 0 ] && docker compose logs --tail 80 || true; [ "${KEEP:-0}" = 1 ] || docker compose down -v >/dev/null 2>&1 || true; exit $status; } +trap cleanup EXIT +start=$(date +%s) docker compose config --quiet docker compose up -d -trap 'docker compose logs --tail 50 || true' ERR -echo "waiting for model pull"; docker compose wait model-pull +docker compose wait model-pull for i in $(seq 1 60); do curl -fsS http://localhost:4000/health/liveliness >/dev/null 2>&1 && break; sleep 5; done resp=$(curl -fsS http://localhost:4000/v1/chat/completions -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H 'Content-Type: application/json' \ - -d '{"model":"local-llama","messages":[{"role":"user","content":"Reply with the word ok"}],"max_tokens":10}') -echo "$resp" | python3 -c 'import json,sys; c=json.load(sys.stdin)["choices"][0]["message"]["content"]; assert c.strip(), "empty"; print("gateway reply:", c)' + -d '{"model":"local-llama","temperature":0,"messages":[{"role":"user","content":"What is 17 plus 25? Answer with the number only."}],"max_tokens":20}') +echo "$resp" | python3 -c ' +import json,sys +r=json.load(sys.stdin); c=r["choices"][0]["message"]["content"]; u=r.get("usage") or {} +print("gateway model:", r.get("model"), "| reply:", repr(c), "| usage:", u) +assert "42" in c, "model did not answer 17+25" +assert u.get("completion_tokens",0)>0, "no completion tokens reported" +assert "qwen2.5" in (r.get("model") or "") or r.get("model")=="local-llama", "unexpected model"' +docker compose exec -T ollama ollama ps | tee /tmp/ollama-ps.txt +grep -q "qwen2.5:0.5b" /tmp/ollama-ps.txt || { echo "model not loaded in Ollama"; exit 1; } +docker compose logs ollama 2>&1 | grep -E 'POST +"/api/chat"|POST +"/v1/chat/completions"|POST +"/api/generate"' | tail -2 | tee /tmp/ollama-req.txt +[ -s /tmp/ollama-req.txt ] || { echo "no chat request in Ollama logs"; exit 1; } for i in $(seq 1 60); do curl -fsS http://localhost:3000/health >/dev/null 2>&1 && break; sleep 5; done curl -fsS http://localhost:3000/health && echo " open-webui healthy" docker compose images +docker compose exec -T ollama ollama list +echo "elapsed $(( $(date +%s) - start ))s" echo "SMOKE TEST PASSED" diff --git a/requirements.txt b/requirements.txt index 8eb51d0..5d5eff8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ jsonschema==4.26.0 mkdocs==1.6.1 mkdocs-material==9.7.7 PyYAML==6.0.3 +pytest==9.1.1 diff --git a/scripts/build.py b/scripts/build.py index 4998b37..6822cd4 100644 --- a/scripts/build.py +++ b/scripts/build.py @@ -20,6 +20,9 @@ def status(p): e = ev.get(p["id"]) if not e: return "not yet collected" return e.get("state", "unknown") +def badge(p): + s = status(p) + return {"archived": "⚠ **archived upstream**", "unknown": "❓ unknown (lookup failed)"}.get(s, s) def lic(p): l = p["license"] return l["label"] + ("" if l["state"] == "declared" else " ⚠ needs review") @@ -31,7 +34,7 @@ def w(path, text): # ---- category pages for c in cats: ps = by_cat[c["id"]] - rows = "\n".join(f"| [{p['name']}](#{p['id'].replace('.', '')}) | {p['description']} | {p['editorial'].get('highlight','–')} | {', '.join(p['deployment'])} | {p['hardware']} | {lic(p)} | {status(p)} |" for p in ps) + rows = "\n".join(f"| [{p['name']}](#{p['id'].replace('.', '')}) | {p['description']} | {p['editorial'].get('highlight','–')} | {', '.join(p['deployment'])} | {p['hardware']} | {lic(p)} | {badge(p)} |" for p in ps) det = [] for p in ps: e = ev.get(p["id"], {}) @@ -46,7 +49,9 @@ def w(path, text): | Setup docs | [{p['name']} setup guide]({p['setup_url']}) | | Licence | {lic(p)} · [licence evidence]({p['license']['evidence_url']}) · checked {p['license']['checked']} | | Licence detected by GitHub | {e.get('license', {}).get('github_spdx') or 'not detected'} | -| Repository state | {status(p)} | +| Repository state | {badge(p)} | +| Licence review reason | {p['license'].get('review_reason', '–')} | +| Last lookup | {(e.get('fetch_status') or {}).get('result', '–')} | | Last commit | {d(e.get('last_commit'))} | | Latest release | {rel.get('tag') or 'none detected'} {('(' + d(rel.get('published_at')) + ')') if rel else ''} | | Deployment | {', '.join(p['deployment'])} | @@ -85,7 +90,7 @@ def w(path, text): e = ev.get(p["id"], {}) data.append({"id": p["id"], "name": p["name"], "category": p["category"], "description": p["description"], "tasks": p["tasks"], "deployment": p["deployment"], "hardware": p["hardware"], "languages": p["languages"], - "license": p["license"]["label"], "license_state": p["license"]["state"], "repo": p["repo"], + "license": p["license"]["label"], "license_state": p["license"]["state"], "license_reason": p["license"].get("review_reason", ""), "repo": p["repo"], "status": status(p), "last_commit": d(e.get("last_commit"))}) w("docs/assets/catalog.json", json.dumps({"categories": [{"id": c["id"], "title": c["title"]} for c in cats], "projects": data}, indent=1, sort_keys=True) + "\n") @@ -99,8 +104,9 @@ def w(path, text): if status(p) == "archived": flags.append("archived") if e.get("canonical_repo") and e["canonical_repo"].lower() != p["repo"].lower(): flags.append("moved") if p["license"]["state"] != "declared" or gl in ("NOASSERTION", "not detected"): flags.append("licence review") - if e.get("last_attempt"): flags.append("last fetch failed") - fr.append(f"| [{p['name']}](stacks/{p['category']}.md#{p['id'].replace('.', '')}) | {status(p)} | {d(e.get('last_commit'))} | {rel} | {p['license']['label']} | {gl} | {d(e.get('retrieved_at'))} | {', '.join(flags) or '–'} |") + fs = (e.get("fetch_status") or {}).get("result", "ok") + if fs != "ok": flags.append(f"lookup: {fs}") + fr.append(f"| [{p['name']}](stacks/{p['category']}.md#{p['id'].replace('.', '')}) | {badge(p)} | {d(e.get('last_commit'))} | {rel} | {p['license']['label']} | {gl} | {d(e.get('retrieved_at'))} | {', '.join(flags) or '–'} |") st = [status(p) for p in projects] w("docs/freshness.md", f"""--- title: Freshness Report – Open Source Ai @@ -111,6 +117,13 @@ def w(path, text): Evidence is collected from the public GitHub REST API by a **weekly** scheduled workflow (Mondays 03:00 UTC, also runnable manually). Changes arrive as a pull request for human review; nothing is rewritten on `main` automatically. This is not real-time monitoring. +**How to read this page** + +- *State* and dates are collected facts with a source URL and retrieval time in `catalog/evidence/.json`. +- *Declared licence* is curated by humans in `catalog/projects.yaml`; *needs review* entries list a reason on their project page. +- *Flags*: `archived` (upstream archived, kept and labelled), `moved` (canonical URL changed), `licence review`, `lookup: …` (last request failed – previous evidence kept, treat as possibly stale). +- To correct anything, edit `catalog/projects.yaml` (never this generated page) – see CONTRIBUTING.md. + **Summary:** {st.count('active')} active · {st.count('archived')} archived · {sum(1 for s in st if s not in ('active','archived'))} unknown/not collected · {total} total. "Declared licence" is the curated value; "GitHub detected" is GitHub's automatic detection (`NOASSERTION` means GitHub could not identify a single licence). A failed request never marks a project deleted. @@ -180,6 +193,7 @@ def w(path, text): m = open("mkdocs.yml").read().split("nav:")[0] nav = "\n".join(f" - {c['title']}: stacks/{c['id']}.md" for c in cats) recipes = "\n".join(f" - {yaml.safe_load(open(f))['title']}: recipes/{os.path.basename(os.path.dirname(f))}.md" for f in sorted(glob.glob("recipes/*/recipe.yaml"))) +tail = "\nexclude_docs: |\n wiki/\n" w("mkdocs.yml", m + f"""nav: - Home: index.md - Search & Filter: catalog.md @@ -194,7 +208,7 @@ def w(path, text): - Freshness Report: freshness.md - Selection Criteria: selection-criteria.md - Credits & Licences: credits.md -""") +""" + tail) # ---- recipe pages rows = [] diff --git a/scripts/collect.py b/scripts/collect.py index 93fef17..a9110f8 100644 --- a/scripts/collect.py +++ b/scripts/collect.py @@ -1,95 +1,124 @@ """Refresh evidence for every catalog project from the GitHub REST API. -Writes catalog/evidence/.json. Only collected facts live there; human-authored -fields in projects.yaml are never touched. Uses ETag conditional requests cached in -.cache/etags.json, bounded concurrency, timeouts, retries with backoff and rate-limit -awareness. A failed request never marks a project deleted or unlicensed: previous -evidence is kept and the failure is reported. +Writes catalog/evidence/.json (collected facts only; projects.yaml is never touched). +- ETag conditional requests cached in .cache/etags.json +- bounded concurrency (4), 20 s timeouts, retries with exponential backoff +- rate-limit aware: waits up to 5 min for reset, otherwise reports "rate-limited" +- a failed lookup is NEVER reported as success and never marks a project deleted: + previous facts are kept and `fetch_status` records the failure. +Exit code 1 if every lookup failed (nothing trustworthy to propose). """ import json, os, sys, time, datetime, urllib.request, urllib.error, concurrent.futures as cf -import yaml API = "https://api.github.com" -TOKEN = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") -CACHE = ".cache/etags.json" -os.makedirs(".cache", exist_ok=True); os.makedirs("catalog/evidence", exist_ok=True) -etags = json.load(open(CACHE)) if os.path.exists(CACHE) else {} -NOW = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z") +VOLATILE = ("retrieved_at", "stars", "fetch_status") -def get(path): - url = API + path - for attempt in range(4): - req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "open-source-ai-collector"}) - if TOKEN: req.add_header("Authorization", f"Bearer {TOKEN}") - if url in etags: req.add_header("If-None-Match", etags[url]["etag"]) - try: - with urllib.request.urlopen(req, timeout=20) as r: - body = json.loads(r.read() or b"null") - if r.headers.get("ETag"): etags[url] = {"etag": r.headers["ETag"], "body": body} - return 200, body - except urllib.error.HTTPError as e: - if e.code == 304: return 200, etags[url]["body"] - if e.code in (403, 429) and e.headers.get("X-RateLimit-Remaining") == "0": - wait = max(1, int(e.headers.get("X-RateLimit-Reset", time.time() + 60)) - int(time.time())) - if wait > 300: return e.code, None - time.sleep(wait); continue - if e.code in (404, 451): return e.code, None - if e.code >= 500: time.sleep(2 ** attempt); continue - return e.code, None - except Exception: - time.sleep(2 ** attempt) - return -1, None -def collect(p): +def now_utc(): + return datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z") + + +class Client: + def __init__(self, token=None, etags=None, sleep=time.sleep, opener=urllib.request.urlopen, max_wait=300): + self.token, self.etags, self.sleep, self.open, self.max_wait = token, etags if etags is not None else {}, sleep, opener, max_wait + + def get(self, path): + """Return (status, body). status: 200, 404, 451, 'rate-limited', or 'error:'.""" + url = API + path + last = "error:unknown" + for attempt in range(4): + req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "open-source-ai-collector"}) + if self.token: req.add_header("Authorization", f"Bearer {self.token}") + if url in self.etags: req.add_header("If-None-Match", self.etags[url]["etag"]) + try: + with self.open(req, timeout=20) as r: + body = json.loads(r.read() or b"null") + if r.headers.get("ETag"): self.etags[url] = {"etag": r.headers["ETag"], "body": body} + return 200, body + except urllib.error.HTTPError as e: + if e.code == 304 and url in self.etags: return 200, self.etags[url]["body"] + if e.code in (403, 429) and (e.headers.get("X-RateLimit-Remaining") == "0" or e.headers.get("Retry-After")): + reset = e.headers.get("Retry-After") + wait = int(reset) if reset else int(e.headers.get("X-RateLimit-Reset", 0)) - int(time.time()) + if wait > self.max_wait: return "rate-limited", None + self.sleep(max(1, wait)); last = "rate-limited"; continue + if e.code in (404, 451): return e.code, None + last = f"error:{e.code}" + if e.code >= 500: self.sleep(2 ** attempt); continue + return last, None + except Exception as e: # timeouts, DNS, bad JSON + last = f"error:{type(e).__name__}"; self.sleep(2 ** attempt) + return last, None + + +def collect(client, p, old, ts): + """Return (status, evidence). status in new|updated|unchanged|failed|not-found.""" owner_repo = p["repo"].split("github.com/")[1] - path = f"catalog/evidence/{p['id']}.json" - old = json.load(open(path)) if os.path.exists(path) else None - code, repo = get(f"/repos/{owner_repo}") - if code != 200 or not repo: - status = "unavailable" if code in (404, 451) and old is None else "fetch-failed" - if old: # keep previous facts, record the failure separately - old["last_attempt"] = {"at": NOW, "http_status": code} - return p["id"], "failed", old - return p["id"], status, {"id": p["id"], "source": f"{API}/repos/{owner_repo}", "retrieved_at": NOW, "state": "unknown", "last_attempt": {"at": NOW, "http_status": code}} - _, commits = get(f"/repos/{owner_repo}/commits?per_page=1") - _, rel = get(f"/repos/{owner_repo}/releases/latest") + src = f"{API}/repos/{owner_repo}" + code, repo = client.get(f"/repos/{owner_repo}") + if code != 200 or not isinstance(repo, dict): + status = "not-found" if code in (404, 451) else "failed" + attempt = {"at": ts, "result": str(code)} + if old: + ev = dict(old); ev["fetch_status"] = attempt + return status, ev + return status, {"id": p["id"], "source": src, "retrieved_at": ts, "state": "unknown", "fetch_status": attempt} + c_code, commits = client.get(f"/repos/{owner_repo}/commits?per_page=1") + r_code, rel = client.get(f"/repos/{owner_repo}/releases/latest") lic = repo.get("license") or {} spdx = lic.get("spdx_id") + canonical = repo.get("html_url") ev = { - "id": p["id"], - "source": f"{API}/repos/{owner_repo}", - "retrieved_at": NOW, - "canonical_repo": repo.get("html_url"), + "id": p["id"], "source": src, "retrieved_at": ts, + "canonical_repo": canonical, + "moved": bool(canonical) and canonical.lower() != p["repo"].lower(), "state": "archived" if repo.get("archived") else "active", "default_branch": repo.get("default_branch"), - "last_commit": (commits[0]["commit"]["committer"]["date"] if isinstance(commits, list) and commits else None), + "last_commit": commits[0]["commit"]["committer"]["date"] if c_code == 200 and isinstance(commits, list) and commits else None, "pushed_at": repo.get("pushed_at"), - "latest_release": ({"tag": rel.get("tag_name"), "published_at": rel.get("published_at")} if isinstance(rel, dict) and rel.get("tag_name") else None), - "license": { - "github_spdx": spdx, - "state": "not-detected" if not spdx else ("needs-review" if spdx == "NOASSERTION" else "detected"), - "source": f"{API}/repos/{owner_repo}/license", - }, + "latest_release": {"tag": rel.get("tag_name"), "published_at": rel.get("published_at")} if r_code == 200 and isinstance(rel, dict) and rel.get("tag_name") else None, + "license": {"github_spdx": spdx, + "state": "not-detected" if not spdx else ("needs-review" if spdx == "NOASSERTION" else "detected"), + "source": f"{src}/license"}, "stars": repo.get("stargazers_count"), + "fetch_status": {"at": ts, "result": "ok" if c_code == 200 else f"partial (commits: {c_code})"}, } - if old: - same = {k: v for k, v in old.items() if k not in ("retrieved_at", "last_attempt", "stars")} == {k: v for k, v in ev.items() if k not in ("retrieved_at", "stars")} - if same: - return p["id"], "unchanged", old - return p["id"], ("updated" if old else "new"), ev + if old and {k: v for k, v in old.items() if k not in VOLATILE} == {k: v for k, v in ev.items() if k not in VOLATILE}: + return "unchanged", old + return ("updated" if old else "new"), ev + + +def main(): + import yaml + os.makedirs(".cache", exist_ok=True); os.makedirs("catalog/evidence", exist_ok=True) + cache = ".cache/etags.json" + client = Client(os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN"), json.load(open(cache)) if os.path.exists(cache) else {}) + ts = now_utc() + projects = yaml.safe_load(open("catalog/projects.yaml"))["projects"] + def one(p): + path = f"catalog/evidence/{p['id']}.json" + old = json.load(open(path)) if os.path.exists(path) else None + return p["id"], path, old, *collect(client, p, old, ts) + S = {k: [] for k in ("new", "updated", "unchanged", "failed", "not-found", "archived", "moved", "license-needs-review")} + with cf.ThreadPoolExecutor(max_workers=4) as ex: + for pid, path, old, status, ev in ex.map(one, projects): + S[status].append(pid) + if ev is not old: + with open(path, "w") as f: json.dump(ev, f, indent=2, sort_keys=True); f.write("\n") + if ev.get("state") == "archived": S["archived"].append(pid) + if ev.get("moved"): S["moved"].append(pid) + if (ev.get("license") or {}).get("state") in ("needs-review", "not-detected"): S["license-needs-review"].append(pid) + json.dump(client.etags, open(cache, "w")) + bad = len(S["failed"]) + len(S["not-found"]) + out = "\n".join([f"## Catalog evidence refresh – {ts}", "", + f"**{bad} of {len(projects)} lookups failed or not found** – those projects keep their previous evidence and are flagged; review before merging." if bad else "All lookups succeeded.", ""] + + [f"- **{k}** ({len(v)}): {', '.join(sorted(v)) or '–'}" for k, v in S.items()]) + "\n" + print(out) + if os.environ.get("GITHUB_STEP_SUMMARY"): open(os.environ["GITHUB_STEP_SUMMARY"], "a").write(out) + open(".cache/summary.md", "w").write(out) + if os.environ.get("GITHUB_OUTPUT"): open(os.environ["GITHUB_OUTPUT"], "a").write(f"failed={bad}\n") + return 1 if bad == len(projects) else 0 + -projects = yaml.safe_load(open("catalog/projects.yaml"))["projects"] -summary = {"new": [], "updated": [], "unchanged": [], "failed": [], "unavailable": [], "fetch-failed": [], "archived": [], "license-needs-review": []} -with cf.ThreadPoolExecutor(max_workers=4) as ex: - for pid, status, ev in ex.map(collect, projects): - summary[status].append(pid) - if status != "unchanged": - json.dump(ev, open(f"catalog/evidence/{pid}.json", "w"), indent=2, sort_keys=True); open(f"catalog/evidence/{pid}.json", "a").write("\n") - if ev.get("state") == "archived": summary["archived"].append(pid) - if ev.get("license", {}).get("state") in ("needs-review", "not-detected"): summary["license-needs-review"].append(pid) -json.dump(etags, open(CACHE, "w")) -lines = ["## Catalog evidence refresh", f"Run at {NOW}", ""] + [f"- **{k}** ({len(v)}): {', '.join(sorted(v)) or '–'}" for k, v in summary.items()] -out = "\n".join(lines) + "\n" -print(out) -if os.environ.get("GITHUB_STEP_SUMMARY"): open(os.environ["GITHUB_STEP_SUMMARY"], "a").write(out) -open(".cache/summary.md", "w").write(out) +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/validate.py b/scripts/validate.py index cab4140..0854b41 100644 --- a/scripts/validate.py +++ b/scripts/validate.py @@ -1,54 +1,85 @@ -"""Validate catalog/ data. Exit 1 on any error. Warnings are printed but do not fail.""" -import json, glob, os, sys, subprocess, datetime, collections, yaml, jsonschema +"""Validate catalog/ data. Exit 1 on any error; warnings do not fail.""" +import json, glob, os, sys, subprocess, datetime, collections SPDX = {"MIT", "Apache-2.0", "AGPL-3.0", "GPL-3.0", "GPL-2.0", "LGPL-3.0", "BSD-2-Clause", "BSD-3-Clause", "MPL-2.0", "BUSL-1.1", "Elastic-2.0", "FSL-1.1-Apache-2.0", "FSL-1.1-MIT", "CC-BY-4.0", "ISC", "Unlicense"} -err, warn = [], [] -cats = [c["id"] for c in yaml.safe_load(open("catalog/categories.yaml"))["categories"]] -doc = yaml.safe_load(open("catalog/projects.yaml")) -try: - jsonschema.validate(doc, json.load(open("catalog/schema.json"))) -except jsonschema.ValidationError as e: - err.append(f"schema: {e.message} at {list(e.absolute_path)}") -P = doc["projects"] -for key in ("id", "repo"): - for v, n in collections.Counter(p[key].lower() for p in P).items(): - if n > 1: err.append(f"duplicate {key}: {v}") -for c, n in collections.Counter(cats).items(): - if n > 1: err.append(f"duplicate category {c}") -today = datetime.date.today().isoformat() -ev_files = {os.path.basename(f)[:-5] for f in glob.glob("catalog/evidence/*.json")} -bootstrap = not ev_files -if bootstrap: warn.append("no evidence collected yet (bootstrap) – run the refresh workflow") -for p in P: - i = p["id"] - if p["category"] not in cats: err.append(f"{i}: unknown category {p['category']}") - if not any(p["category"] == c for c in cats): pass - l = p["license"] - if l["state"] == "declared" and l["spdx"] not in SPDX: err.append(f"{i}: declared licence '{l['spdx']}' is not a known SPDX id; use state needs-review") - if l["state"] != "declared" and l["spdx"] == "NOASSERTION": err.append(f"{i}: NOASSERTION is not a licence") - for k in (l["checked"], p["last_checked"]): - if not ("2024-01-01" <= k <= today): err.append(f"{i}: implausible date {k}") - if not bootstrap: - if i not in ev_files: err.append(f"{i}: missing evidence file catalog/evidence/{i}.json") - else: - e = json.load(open(f"catalog/evidence/{i}.json")) - if not e.get("source", "").startswith("https://api.github.com/") or not e.get("retrieved_at"): err.append(f"{i}: evidence lacks source/retrieved_at") - elif e["retrieved_at"][:10] > today: err.append(f"{i}: evidence from the future") - if e.get("canonical_repo") and e["canonical_repo"].lower() != p["repo"].lower(): warn.append(f"{i}: repo moved to {e['canonical_repo']}") - if e.get("state") == "archived": warn.append(f"{i}: upstream archived") - gs = (e.get("license") or {}).get("github_spdx") - if l["state"] == "declared" and gs and gs not in ("NOASSERTION", l["spdx"]): warn.append(f"{i}: declared {l['spdx']} but GitHub detects {gs}") -for f in ev_files - {p["id"] for p in P}: err.append(f"orphan evidence file {f}.json") -if os.path.exists(".gitmodules"): err.append(".gitmodules must not exist (catalog-first repo)") -links = [l for l in subprocess.run(["git", "ls-files", "-s"], capture_output=True, text=True).stdout.splitlines() if l.startswith("160000")] -if links: err.append(f"{len(links)} gitlinks present") -for f in glob.glob("recipes/*/recipe.yaml"): - r = yaml.safe_load(open(f)) - if r["test"]["status"] not in ("tested", "unverified"): err.append(f"{f}: bad test status") - for c in r["components"]: - if c not in {p["id"] for p in P}: err.append(f"{f}: component {c} not in catalog") -for w_ in warn: print("WARN", w_) -for e_ in err: print("ERROR", e_) -print(f"{len(P)} projects, {len(cats)} categories, {len(ev_files)} evidence files: {'FAIL' if err else 'OK'}") -sys.exit(1 if err else 0) + + +def parse_date(s): + """Accept YYYY-MM-DD or ISO-8601 UTC timestamp ending in Z. Return date or None.""" + try: + if len(s) == 10: return datetime.date.fromisoformat(s) + if not s.endswith("Z"): return None + return datetime.datetime.fromisoformat(s[:-1] + "+00:00").date() + except (ValueError, TypeError): + return None + + +def check(doc, cats, evidence, today, schema=None, gitlinks=0, has_gitmodules=False, recipes=()): + err, warn = [], [] + if schema is not None: + import jsonschema + for e in jsonschema.Draft202012Validator(schema).iter_errors(doc): + err.append(f"schema: {e.message} at {list(e.absolute_path)}") + if err: return err, warn + P = doc["projects"]; ids = {p["id"] for p in P} + for key in ("id", "repo"): + for v, n in collections.Counter(p[key].lower().rstrip("/") for p in P).items(): + if n > 1: err.append(f"duplicate {key}: {v}") + for c, n in collections.Counter(cats).items(): + if n > 1: err.append(f"duplicate category {c}") + lo = datetime.date(2024, 1, 1) + hi = today + datetime.timedelta(days=1) # curators may write dates in UTC+14 .. UTC-12 + bootstrap = not evidence + if bootstrap: warn.append("no evidence collected yet (bootstrap)") + for p in P: + i, l = p["id"], p["license"] + if p["category"] not in cats: err.append(f"{i}: unknown category {p['category']}") + if l["state"] == "declared" and l["spdx"] not in SPDX: err.append(f"{i}: declared licence '{l['spdx']}' is not a known SPDX id; use needs-review") + if l["spdx"] == "NOASSERTION": err.append(f"{i}: NOASSERTION is not a licence") + if l["state"] == "needs-review" and not l.get("review_reason"): err.append(f"{i}: needs-review without review_reason") + for k in (l["checked"], p["last_checked"]): + d = parse_date(k) + if d is None or not (lo <= d <= hi): err.append(f"{i}: invalid or implausible date {k!r}") + if bootstrap: continue + e = evidence.get(i) + if e is None: err.append(f"{i}: missing evidence file"); continue + if not str(e.get("source", "")).startswith("https://api.github.com/repos/"): err.append(f"{i}: evidence source missing/invalid") + d = parse_date(e.get("retrieved_at") or "") + if d is None: err.append(f"{i}: evidence retrieved_at missing/invalid") + elif not (lo <= d <= hi): err.append(f"{i}: evidence date out of range {e['retrieved_at']}") + if e.get("state") not in ("active", "archived", "unknown"): err.append(f"{i}: evidence state invalid {e.get('state')!r}") + fs = (e.get("fetch_status") or {}).get("result", "ok") + if fs != "ok" and not fs.startswith("partial"): warn.append(f"{i}: last lookup failed ({fs}); evidence may be stale") + if e.get("state") == "unknown": warn.append(f"{i}: upstream state unknown") + if e.get("canonical_repo") and e["canonical_repo"].lower() != p["repo"].lower(): err.append(f"{i}: repo moved to {e['canonical_repo']} – update projects.yaml") + if e.get("state") == "archived": warn.append(f"{i}: upstream archived (labelled, kept)") + gs = (e.get("license") or {}).get("github_spdx") + if l["state"] == "declared" and gs and gs not in ("NOASSERTION", l["spdx"]): err.append(f"{i}: declared {l['spdx']} but GitHub detects {gs} – verify LICENSE") + for f in sorted(set(evidence) - ids): err.append(f"orphan evidence {f}") + if has_gitmodules: err.append(".gitmodules must not exist") + if gitlinks: err.append(f"{gitlinks} gitlinks present") + for name, r in recipes: + if r["test"]["status"] not in ("tested", "unverified"): err.append(f"{name}: bad test status") + for c in r["components"]: + if c not in ids: err.append(f"{name}: component {c} not in catalog") + return err, warn + + +def main(): + import yaml + doc = yaml.safe_load(open("catalog/projects.yaml")) + cats = [c["id"] for c in yaml.safe_load(open("catalog/categories.yaml"))["categories"]] + ev = {os.path.basename(f)[:-5]: json.load(open(f)) for f in sorted(glob.glob("catalog/evidence/*.json"))} + links = sum(1 for l in subprocess.run(["git", "ls-files", "-s"], capture_output=True, text=True).stdout.splitlines() if l.startswith("160000")) + recipes = [(f, yaml.safe_load(open(f))) for f in sorted(glob.glob("recipes/*/recipe.yaml"))] + today = datetime.datetime.now(datetime.timezone.utc).date() + err, warn = check(doc, cats, ev, today, json.load(open("catalog/schema.json")), links, os.path.exists(".gitmodules"), recipes) + for w in warn: print("WARN", w) + for e in err: print("ERROR", e) + print(f"{len(doc['projects'])} projects, {len(cats)} categories, {len(ev)} evidence files, {len(warn)} warnings, {len(err)} errors: {'FAIL' if err else 'OK'}") + return 1 if err else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/browser/.gitignore b/tests/browser/.gitignore new file mode 100644 index 0000000..eaefc11 --- /dev/null +++ b/tests/browser/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +test-results/ +results.json +playwright-report/ diff --git a/tests/browser/catalog.spec.js b/tests/browser/catalog.spec.js new file mode 100644 index 0000000..9216f79 --- /dev/null +++ b/tests/browser/catalog.spec.js @@ -0,0 +1,109 @@ +const { test, expect } = require("@playwright/test"); +const AxeBuilder = require("@axe-core/playwright").default; + +const count = (page) => page.locator("#osa-count"); +async function open(page, qs = "") { + await page.goto("catalog/" + qs); + await expect(page.locator("#osa-filters[data-ready=true]")).toBeAttached(); +} +async function total(page) { return Number((await count(page).textContent()).split(" of ")[1].split(" ")[0]); } + +test("loads all projects", async ({ page }) => { + await open(page); + await expect(count(page)).toHaveText(/^(\d+) of \1 projects match$/); + expect(await total(page)).toBeGreaterThan(50); +}); + +test("text search narrows results and updates the URL", async ({ page }) => { + await open(page); + await page.getByLabel("Search projects", { exact: true }).fill("ollama"); + await expect(page.locator("#osa-results tbody tr").first()).toContainText("Ollama"); + await expect(count(page)).not.toHaveText(/^(\d+) of \1 /); + await expect(page).toHaveURL(/[?&]q=ollama/); +}); + +test("filters combine, clear resets, no-results message", async ({ page }) => { + await open(page); + const all = await total(page); + await page.getByLabel("Category").selectOption("local-models"); + await expect(page).toHaveURL(/category=local-models/); + const rows = page.locator("#osa-results tbody tr"); + const n = await rows.count(); + expect(n).toBeGreaterThan(0); expect(n).toBeLessThan(all); + await page.getByLabel("Search projects", { exact: true }).fill("zzzz-no-such-project"); + await expect(page.locator("#osa-empty")).toBeVisible(); + await expect(count(page)).toHaveText(`0 of ${all} projects match`); + await page.getByRole("button", { name: "Clear filters" }).click(); + await expect(count(page)).toHaveText(`${all} of ${all} projects match`); + await expect(page.locator("#osa-empty")).toBeHidden(); + await expect(page).toHaveURL(/catalog\/$/); +}); + +test("archived projects are labelled", async ({ page }) => { + await open(page, "?status=archived"); + const rows = page.locator("#osa-results tbody tr"); + expect(await rows.count()).toBeGreaterThan(0); + for (const r of await rows.all()) await expect(r.locator(".osa-archived")).toHaveText("⚠ archived"); +}); + +test("state survives reload and back/forward", async ({ page }) => { + await open(page); + await page.getByLabel("Category").selectOption("memory"); + await page.getByLabel("Licence state").selectOption("declared"); + await page.reload(); + await expect(page.locator("#osa-filters[data-ready=true]")).toBeAttached(); + await expect(page.getByLabel("Category")).toHaveValue("memory"); + await expect(page.getByLabel("Licence state")).toHaveValue("declared"); + await page.goBack(); + await expect(page.getByLabel("Licence state")).toHaveValue(""); + await expect(page.getByLabel("Category")).toHaveValue("memory"); + await page.goForward(); + await expect(page.getByLabel("Licence state")).toHaveValue("declared"); +}); + +test("invalid URL values are ignored", async ({ page }) => { + await open(page, "?category=