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).
-
+
+No projects match these filters. Try removing a filter or clear all filters.
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=