{
  "openapi": "3.0.3",
  "info": {
    "title": "Free2AITools API",
    "version": "2.0.0",
    "description": "Structured discovery, evidence, and identity layer for AI agents, powered by the Free2AITools Nexus Index (FNI). Returns FNI-ranked catalog data and evidence for the calling agent to reason over. Discovery layer only: does not perform compatibility analysis (hardware/framework fields are stored heuristics); does not execute, plan, or recommend workflows; does not select or decide on behalf of the caller; does not currently provide live semantic/ANN ranking.",
    "contact": {
      "name": "Free2AITools",
      "url": "https://free2aitools.com/developers"
    },
    "license": {
      "name": "MIT",
      "url": "https://github.com/mosesy5688-cell/ai-nexus/blob/main/LICENSE"
    }
  },
  "servers": [
    {
      "url": "https://free2aitools.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/v1/select": {
      "post": {
        "operationId": "selectModel",
        "summary": "Filter the catalog by declared metadata; returns FNI-ranked entries",
        "description": "Filter the Free2AITools catalog by declared metadata and return FNI-ranked entries. Constraints are metadata/heuristic filters, not verified compatibility analysis. The caller is responsible for final model selection. Each entry carries its FNI factor breakdown plus an optional factual `fni_summary` (evidence/factor facts, not a fit verdict).",
        "tags": [
          "Model Selection"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SelectRequest"
              },
              "example": {
                "task": "text-generation",
                "constraints": {
                  "max_vram_gb": 24,
                  "license": "commercial",
                  "ollama_compatible": true
                },
                "limit": 5,
                "explain": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "FNI-ranked catalog entries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SelectResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (missing task field or invalid JSON)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Rankings data not yet available — retry after next pipeline run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/search": {
      "get": {
        "operationId": "search",
        "summary": "Search AI models, tools, datasets, and papers",
        "description": "Full-text search across the Free2AITools catalog of 602,000+ AI models, tools, datasets, papers, and benchmarks, ranked by FNI score. Returns up to 20 results per request. Pagination is 1-based via `page` (default page is 1; offset = (page - 1) * limit); `total_count` in the response supports client-side page calculation. Results may change between requests as the dataset is refreshed; this endpoint does not provide cursor or snapshot consistency. Search may return a retryable transient 503 under cold-path or fallback budget limits; retry according to Retry-After.",
        "tags": [
          "Search"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Search query",
            "example": "text generation model for coding"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "model",
                "tool",
                "dataset",
                "paper",
                "benchmark"
              ]
            },
            "description": "Filter by entity type"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 5
            },
            "description": "Maximum results per request (capped at 20)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "1-based page; offset = (page-1)*limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Search results ranked by FNI",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "503": {
            "description": "Transient: a search tier (term-index, cold-shard hydration, or cluster fallback) exhausted its wall-clock/op budget. Retryable — honor the Retry-After header. Body is no-store and carries a machine-readable reason (term_index_timeout | cold_shard_timeout | cluster_fallback_budget | embedding_timeout | search_budget_exceeded). A 503 is NOT an empty result; do not treat it as 'no matches'.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait before retrying"
              }
            }
          }
        }
      }
    },
    "/api/v1/compare": {
      "get": {
        "operationId": "compareModels",
        "summary": "Compare 2-25 AI models side-by-side",
        "description": "Returns FNI factor decomposition, specs, and metadata for each model in parallel columns. Cold upper-range multi-paper requests may return a transient 503 (retry after the indicated delay).",
        "tags": [
          "Comparison"
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated model IDs (2-25)",
            "example": "meta-llama/Llama-3.1-8B,google/gemma-2-27b"
          }
        ],
        "responses": {
          "200": {
            "description": "Side-by-side comparison",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompareResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing ids parameter, fewer than 2, or more than 25",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Comparison inconclusive — transient/budget. Cold upper-range multi-paper requests may exhaust the cold-shard wall-clock budget or fan-out cap; the caller may retry (Retry-After header). Response body lists resolved vs pending ids.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/badge/{umid}": {
      "get": {
        "operationId": "getFniBadge",
        "summary": "FNI score badge (SVG)",
        "description": "Returns an SVG badge showing the entity's FNI score. Embeddable in READMEs and documentation.",
        "tags": [
          "Badge"
        ],
        "parameters": [
          {
            "name": "umid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Entity ID (slug format: author--name)",
            "example": "meta-llama--llama-3.3-70b-instruct"
          }
        ],
        "responses": {
          "200": {
            "description": "SVG badge image for an entity with a computed FNI score.",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Entity not found or has no FNI score. Response body is still an SVG placeholder ('FNI: not found') so README <img> embeds render gracefully, but the 404 status lets programmatic callers (Agents) distinguish missing entities from low-scoring ones.",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/entity/{id}": {
      "get": {
        "operationId": "getEntity",
        "summary": "Single-entity detail lookup",
        "description": "Returns full structured metadata for one entity. Closes the search -> detail chain so Agents don't have to scrape HTML. Tolerant of multiple ID forms: internal canonical (hf-model--author--name), HF-native (author/name), bare name, slug, or umid.",
        "tags": [
          "Entity"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Entity ID in any tolerated form",
            "example": "meta-llama/Llama-3.1-8B-Instruct"
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated optional sections. Currently supports: body (adds readme_html, up to 250KB)",
            "example": "body"
          }
        ],
        "responses": {
          "200": {
            "description": "Entity detail grouped into identity / classification / fni / specs / stats / links / relations",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EntityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing required path parameter: id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Entity not found (all probed shards returned 0 rows successfully)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "All probed shards errored — transient infrastructure issue, caller may retry. Interim: entity lookup may return transient 503 under cold-path probe budget; 404/503 contract under runtime diagnosis.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Runtime observability snapshot",
        "description": "Per-isolate VFS counters + Node runtime info. Cloudflare isolates have independent state, so each call returns metrics from the isolate that handled the request — useful for spot-checking during incidents, not global aggregation. `Cache-Control: no-store` (CDN does not cache).",
        "tags": [
          "Health"
        ],
        "responses": {
          "200": {
            "description": "Health snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/datasets": {
      "get": {
        "operationId": "listDatasets",
        "summary": "List open datasets (parquet format)",
        "description": "Returns JSON manifest of FNI-scored AI entity datasets. Pass `?file=<id>` to redirect (302) to the parquet download URL.",
        "tags": [
          "Datasets"
        ],
        "parameters": [
          {
            "name": "file",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Dataset ID — when present, server returns 302 redirect to CDN download URL",
            "example": "fni_lite_latest"
          }
        ],
        "responses": {
          "200": {
            "description": "Dataset manifest",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DatasetsResponse"
                }
              }
            }
          },
          "302": {
            "description": "Redirect to dataset download URL (only when ?file= is present and recognized)"
          },
          "404": {
            "description": "Unknown file ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/concepts": {
      "get": {
        "operationId": "listConcepts",
        "summary": "List knowledge articles (concepts)",
        "description": "Layer 0 endpoint. Returns a paginated list of published knowledge articles (concepts) from the anchor knowledge DB, ranked newest-first (published_at DESC, id ASC). Heavy content/highlights columns are excluded from the list payload; per-article detail goes through /api/v1/entity/<id>. Read-only, unauthenticated.",
        "tags": [
          "Concepts"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Max articles to return. Clamped to [1, 200]; non-numeric values fall back to 50.",
            "example": 50
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Number of articles to skip for pagination. Floored at 0; non-numeric values fall back to 0.",
            "example": 0
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[a-z][a-z0-9-]{0,40}$"
            },
            "description": "Optional category filter. Must match ^[a-z][a-z0-9-]{0,40}$ (lowercase, starts with a letter, ≤41 chars) or the request is rejected with 400.",
            "example": "machine-learning"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of published knowledge articles. `next_offset` is null when the final page has been reached; `category` echoes the applied filter (null when none).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConceptsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid category format (did not match ^[a-z][a-z0-9-]{0,40}$). Body is the structured concepts error envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConceptsError"
                }
              }
            }
          },
          "500": {
            "description": "Failed to load the knowledge index (upstream/DB error). Body is the structured concepts error envelope with code UPSTREAM_ERROR.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConceptsError"
                }
              }
            }
          }
        }
      },
      "options": {
        "operationId": "conceptsPreflight",
        "summary": "CORS preflight",
        "description": "CORS preflight. Returns 204 No Content with the CORS headers (Allow-Methods: GET, OPTIONS).",
        "tags": [
          "Concepts"
        ],
        "responses": {
          "204": {
            "description": "No Content — CORS preflight acknowledged."
          }
        }
      }
    },
    "/api/v1/trends/batch": {
      "get": {
        "operationId": "trendsBatch",
        "summary": "Batch 7-day FNI trend lookup",
        "description": "Layer 0 endpoint. Returns the 7-day FNI trend (scores, dates, 7-day change %, direction, and latest score) for up to 25 entities in a single call. Lookup is exact-match by entity id; ids with no trend data are returned in `missing` (never an error). Read-only, unauthenticated.",
        "tags": [
          "Trends"
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated entity IDs (1-25). Whitespace is trimmed and empty tokens are dropped before counting.",
            "example": "meta-llama/Llama-3.1-8B-Instruct,google/gemma-2-27b"
          }
        ],
        "responses": {
          "200": {
            "description": "Trend entries keyed by entity id. `missing` lists requested ids that had no trend data. When the trend index is unavailable, all requested ids appear in `missing` and `trends` is empty (still 200).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrendsBatchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing ids parameter, zero ids after trimming, or more than 25 ids. Body is the simple {error} envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error while loading or decoding the trend index. Body is the simple {error} envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "options": {
        "operationId": "trendsBatchPreflight",
        "summary": "CORS preflight",
        "description": "CORS preflight. Returns 204 No Content with the CORS headers (Allow-Methods: GET, OPTIONS).",
        "tags": [
          "Trends"
        ],
        "responses": {
          "204": {
            "description": "No Content — CORS preflight acknowledged."
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "mcpEndpoint",
        "summary": "MCP Server (JSON-RPC 2.0)",
        "description": "Model Context Protocol endpoint. Supports tools/list and tools/call for 5 tools: free2aitools_search, free2aitools_rank, free2aitools_explain, free2aitools_select_model, free2aitools_compare. Tool names MUST include the free2aitools_ prefix when invoking tools/call. **For the canonical tool catalog with full input schemas, fetch `/.well-known/mcp.json`** — that file is the canonical source. This OpenAPI entry intentionally does not duplicate it (DRY).",
        "tags": [
          "MCP"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "initialize",
                      "tools/list",
                      "tools/call"
                    ]
                  },
                  "id": {
                    "type": "integer"
                  },
                  "params": {
                    "type": "object"
                  }
                },
                "required": [
                  "jsonrpc",
                  "method",
                  "id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC 2.0 response"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SelectRequest": {
        "type": "object",
        "required": [
          "task"
        ],
        "properties": {
          "task": {
            "type": "string",
            "description": "Task name or natural language description",
            "example": "text-generation"
          },
          "constraints": {
            "type": "object",
            "properties": {
              "max_vram_gb": {
                "type": "number",
                "description": "Maximum VRAM in GB"
              },
              "max_params_b": {
                "type": "number",
                "description": "Maximum parameters in billions"
              },
              "license": {
                "type": "string",
                "description": "'commercial', 'apache-2.0', 'mit', or 'any'"
              },
              "min_context_length": {
                "type": "integer",
                "description": "Minimum context window tokens"
              },
              "ollama_compatible": {
                "type": "boolean",
                "description": "Only GGUF/Ollama-compatible models"
              },
              "can_run_local": {
                "type": "boolean",
                "description": "Locally runnable (≤13B + GGUF)"
              },
              "hosted_on": {
                "type": "string",
                "description": "Hosting provider: replicate, together, hf-inference"
              },
              "license_type": {
                "type": "string",
                "enum": [
                  "permissive",
                  "copyleft",
                  "non-commercial",
                  "any"
                ]
              }
            }
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "default": 5
          },
          "explain": {
            "type": "boolean",
            "default": true,
            "description": "Include per-entry fni_summary and caveats"
          }
        }
      },
      "SelectResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "fni_v2.0"
          },
          "task_interpreted": {
            "type": "string"
          },
          "total_candidates": {
            "type": "integer"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Entry"
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "elapsed_ms": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Entry": {
        "type": "object",
        "properties": {
          "rank": {
            "type": "integer"
          },
          "model_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "fni_score": {
            "type": "number"
          },
          "fni_factors": {
            "type": "object",
            "properties": {
              "semantic": {
                "type": "number",
                "nullable": true
              },
              "semantic_note": {
                "type": "string"
              },
              "authority": {
                "type": "number"
              },
              "popularity": {
                "type": "number"
              },
              "recency": {
                "type": "number"
              },
              "quality": {
                "type": "number"
              }
            }
          },
          "params_billions": {
            "type": "number",
            "nullable": true
          },
          "vram_estimate_gb": {
            "type": "number",
            "nullable": true
          },
          "context_length": {
            "type": "integer",
            "nullable": true
          },
          "license": {
            "type": "string",
            "nullable": true
          },
          "pipeline_tag": {
            "type": "string",
            "nullable": true
          },
          "ollama_compatible": {
            "type": "boolean"
          },
          "hosted_on": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "license_type": {
            "type": "string"
          },
          "can_run_local": {
            "type": "boolean"
          },
          "fni_summary": {
            "type": "string",
            "description": "Factual FNI factor/spec summary of this catalog entry — not a fit verdict"
          },
          "caveats": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "detail_url": {
            "type": "string",
            "format": "uri"
          },
          "badge_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "SearchResponse": {
        "type": "object",
        "description": "Public /api/v1/search 200 response. Fields are the internal SSR search row (DISPLAY_COLS) wrapped by the v1 versioner: `version` is prepended, `fni_s` is nulled (+ `fni_s_note`), and the internal `_dbSort`/`_score`/`_source` fields are stripped before serialization.",
        "required": [
          "version",
          "results",
          "total_count",
          "tier",
          "elapsed_ms"
        ],
        "properties": {
          "version": {
            "type": "string",
            "description": "API version tag added by the v1 wrapper (e.g. fni_v2.0). Always present on a 200."
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One catalog entity (SSR DISPLAY_COLS, v1-transformed). Non-measured numeric/string stats surface as JSON null (honest-contract), not 0 or empty.",
              "properties": {
                "id": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "description": "model | tool | dataset | paper | benchmark"
                },
                "author": {
                  "type": "string",
                  "nullable": true
                },
                "summary": {
                  "type": "string",
                  "nullable": true
                },
                "fni_score": {
                  "type": "number",
                  "nullable": true
                },
                "fni_s": {
                  "type": "number",
                  "nullable": true,
                  "description": "Always null in the v1 baseline: the Semantic pillar is a query-time baseline, not a per-entity measurement, and live semantic/ANN ranking is not currently provided. See fni_s_note."
                },
                "fni_s_note": {
                  "type": "string",
                  "description": "Present alongside fni_s: explains it is a query-time baseline, not a per-entity value."
                },
                "fni_a": {
                  "type": "number",
                  "nullable": true,
                  "description": "Authority factor."
                },
                "fni_p": {
                  "type": "number",
                  "nullable": true,
                  "description": "Popularity factor."
                },
                "fni_r": {
                  "type": "number",
                  "nullable": true,
                  "description": "Recency factor."
                },
                "fni_q": {
                  "type": "number",
                  "nullable": true,
                  "description": "Quality factor."
                },
                "stars": {
                  "type": "integer",
                  "nullable": true
                },
                "downloads": {
                  "type": "integer",
                  "nullable": true
                },
                "last_modified": {
                  "type": "string",
                  "nullable": true,
                  "format": "date-time"
                },
                "license": {
                  "type": "string",
                  "nullable": true
                },
                "pipeline_tag": {
                  "type": "string",
                  "nullable": true
                },
                "params_billions": {
                  "type": "number",
                  "nullable": true
                },
                "context_length": {
                  "type": "integer",
                  "nullable": true
                }
              }
            }
          },
          "total_count": {
            "type": "integer",
            "description": "Total matched results before the limit/page slice; supports client-side page calculation. Always present on a 200."
          },
          "tier": {
            "type": "string",
            "description": "Which search tier produced the results (e.g. inverted_index | cluster_fallback | browse | empty)."
          },
          "elapsed_ms": {
            "type": "integer"
          }
        }
      },
      "CompareResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "fni_v2.0"
          },
          "entities": {
            "type": "array",
            "description": "Per-ID result in request order. Unresolved IDs are returned as `{id, found: false}` placeholders — the overall response remains 200; the caller inspects `found` to detect partial misses.",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "description": "Resolved entity",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "author": {
                      "type": "string",
                      "nullable": true
                    },
                    "type": {
                      "type": "string"
                    },
                    "fni_score": {
                      "type": "number"
                    },
                    "fni_factors": {
                      "type": "object",
                      "properties": {
                        "semantic": {
                          "type": "number",
                          "nullable": true
                        },
                        "authority": {
                          "type": "number"
                        },
                        "popularity": {
                          "type": "number"
                        },
                        "recency": {
                          "type": "number"
                        },
                        "quality": {
                          "type": "number"
                        }
                      }
                    },
                    "specs": {
                      "type": "object",
                      "properties": {
                        "params_billions": {
                          "type": "number",
                          "nullable": true
                        },
                        "context_length": {
                          "type": "integer",
                          "nullable": true
                        },
                        "vram_estimate_gb": {
                          "type": "number",
                          "nullable": true
                        },
                        "license": {
                          "type": "string",
                          "nullable": true
                        },
                        "architecture": {
                          "type": "string",
                          "nullable": true
                        },
                        "pipeline_tag": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    },
                    "popularity": {
                      "type": "object",
                      "properties": {
                        "downloads": {
                          "type": "integer"
                        },
                        "stars": {
                          "type": "integer"
                        }
                      }
                    },
                    "last_modified": {
                      "type": "string",
                      "nullable": true,
                      "format": "date-time"
                    },
                    "detail_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "badge_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "found": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  }
                },
                {
                  "type": "object",
                  "description": "Unresolved ID — placeholder when the entity could not be located in any meta shard",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "found": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    }
                  },
                  "required": [
                    "id",
                    "found"
                  ]
                }
              ]
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "elapsed_ms": {
                "type": "integer"
              },
              "found": {
                "type": "integer",
                "description": "Count of entities with found: true"
              },
              "requested": {
                "type": "integer",
                "description": "Total IDs in the request"
              }
            }
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "fni_v2.0"
          },
          "status": {
            "type": "string",
            "example": "ok"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "vfs": {
            "type": "object",
            "description": "Per-isolate R2 VFS counters. Cache hit ratios are derived client-side: l0_hit_ratio = l0_hits / jread_total; l1_hit_ratio = l1_hits / (jread_total - l0_hits); short_read_rate = short_read_attempts / l2_fetches.",
            "properties": {
              "jread_total": {
                "type": "integer",
                "description": "Total VFS reads attempted since isolate boot"
              },
              "jread_errors": {
                "type": "integer"
              },
              "short_read_attempts": {
                "type": "integer"
              },
              "short_read_recovered": {
                "type": "integer"
              },
              "short_read_exhausted": {
                "type": "integer"
              },
              "l0_hits": {
                "type": "integer",
                "description": "Chunks served from in-memory L0 cache"
              },
              "l1_hits": {
                "type": "integer",
                "description": "Chunks served from Cloudflare Cache API"
              },
              "l2_fetches": {
                "type": "integer",
                "description": "Chunks fetched from R2 origin or CDN fallback"
              },
              "l0_size": {
                "type": "integer"
              },
              "l0_max": {
                "type": "integer"
              },
              "isolate_uptime_ms": {
                "type": "integer"
              },
              "error": {
                "type": "string",
                "description": "Present only when VFS module is not initialized in this isolate"
              }
            }
          },
          "runtime": {
            "type": "object",
            "properties": {
              "node_compat": {
                "type": "boolean"
              },
              "now_ms": {
                "type": "integer"
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "elapsed_ms": {
                "type": "integer"
              },
              "isolate_random_id": {
                "type": "string",
                "description": "8-char random ID — different per Cloudflare isolate, useful for grouping spot-check requests"
              }
            }
          }
        }
      },
      "DatasetsResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "fni_v2.0"
          },
          "description": {
            "type": "string"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "access"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "example": "fni_lite_latest"
                },
                "name": {
                  "type": "string"
                },
                "tier": {
                  "type": "string",
                  "enum": [
                    "free"
                  ],
                  "deprecated": true,
                  "description": "DEPRECATED legacy compatibility field. All Free2AITools datasets are open/public access; the only legal value is \"free\". Use `access` instead. Retained for backward compatibility; may be removed in a future major API version."
                },
                "access": {
                  "type": "string",
                  "enum": [
                    "public"
                  ],
                  "description": "Access class for the dataset. All current Free2AITools datasets are publicly downloadable with no auth; value is always \"public\"."
                },
                "fields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Schema field names available in the parquet file"
                },
                "download_url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Direct CDN URL for parquet file"
                },
                "api_url": {
                  "type": "string",
                  "description": "Relative API URL that returns 302 redirect to download_url"
                }
              }
            }
          }
        }
      },
      "EntityResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "fni_v2.0"
          },
          "entity": {
            "type": "object",
            "required": [
              "id",
              "canonical_id"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "Current canonical served identifier (lookup key). Reuse verbatim."
              },
              "canonical_id": {
                "type": "string",
                "description": "The same canonical identifier value as `id` (canonical_id == id). A separate derived UMID = SHA256(canonical_id)[:16] is not emitted at the top level of this response."
              },
              "slug": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "description": "model | dataset | paper | tool | benchmark | knowledge"
              },
              "name": {
                "type": "string"
              },
              "author": {
                "type": "string",
                "nullable": true
              },
              "source": {
                "type": "string",
                "nullable": true,
                "description": "huggingface | github | arxiv | replicate | etc."
              },
              "summary": {
                "type": "string",
                "nullable": true
              },
              "category": {
                "type": "string",
                "nullable": true
              },
              "tags": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "license": {
                "type": "string",
                "nullable": true
              },
              "license_type": {
                "type": "string",
                "nullable": true
              },
              "pipeline_tag": {
                "type": "string",
                "nullable": true
              },
              "task_categories": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "primary_language": {
                "type": "string",
                "nullable": true
              },
              "fni": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "number",
                    "nullable": true
                  },
                  "percentile": {
                    "type": "string",
                    "nullable": true
                  },
                  "factors": {
                    "type": "object",
                    "properties": {
                      "semantic": {
                        "type": "number",
                        "nullable": true,
                        "description": "Always null: the Semantic pillar is a query-time baseline scored live at search, not a measured per-entity value. See semantic_note."
                      },
                      "semantic_note": {
                        "type": "string",
                        "description": "Explains that semantic is a query-time baseline, not a per-entity score."
                      },
                      "authority": {
                        "type": "number",
                        "nullable": true
                      },
                      "popularity": {
                        "type": "number",
                        "nullable": true
                      },
                      "recency": {
                        "type": "number",
                        "nullable": true
                      },
                      "quality": {
                        "type": "number",
                        "nullable": true
                      }
                    }
                  },
                  "is_trending": {
                    "type": "boolean"
                  },
                  "trend_7d": {
                    "type": "string",
                    "nullable": true,
                    "description": "Comma-separated FNI scores for last 7 days, or null"
                  }
                }
              },
              "specs": {
                "type": "object",
                "properties": {
                  "params_billions": {
                    "type": "number",
                    "nullable": true
                  },
                  "context_length": {
                    "type": "integer",
                    "nullable": true
                  },
                  "architecture": {
                    "type": "string",
                    "nullable": true
                  },
                  "vocab_size": {
                    "type": "integer",
                    "nullable": true
                  },
                  "num_layers": {
                    "type": "integer",
                    "nullable": true
                  },
                  "hidden_size": {
                    "type": "integer",
                    "nullable": true
                  },
                  "vram": {
                    "type": "object",
                    "properties": {
                      "estimate_gb": {
                        "type": "number",
                        "nullable": true
                      },
                      "fp16_gb": {
                        "type": "number",
                        "nullable": true
                      },
                      "int8_gb": {
                        "type": "number",
                        "nullable": true
                      },
                      "int4_gb": {
                        "type": "number",
                        "nullable": true
                      }
                    }
                  },
                  "ollama_compatible": {
                    "type": "boolean",
                    "nullable": true
                  },
                  "can_run_local": {
                    "type": "boolean",
                    "nullable": true
                  },
                  "hosted_on": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "nullable": true
                  },
                  "runtime_hardware": {
                    "type": "string",
                    "nullable": true
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "downloads": {
                    "type": "integer",
                    "nullable": true
                  },
                  "stars": {
                    "type": "integer",
                    "nullable": true
                  },
                  "forks": {
                    "type": "integer",
                    "nullable": true
                  },
                  "citation_count": {
                    "type": "integer",
                    "nullable": true
                  },
                  "num_rows": {
                    "type": "integer",
                    "nullable": true
                  },
                  "last_modified": {
                    "type": "string",
                    "nullable": true,
                    "format": "date-time"
                  }
                }
              },
              "links": {
                "type": "object",
                "properties": {
                  "source_url": {
                    "type": "string",
                    "nullable": true,
                    "format": "uri"
                  },
                  "canonical_url": {
                    "type": "string",
                    "nullable": true,
                    "format": "uri"
                  },
                  "image_url": {
                    "type": "string",
                    "nullable": true,
                    "format": "uri"
                  },
                  "detail_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "badge_url": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              },
              "relations": {
                "type": "object",
                "properties": {
                  "datasets_used": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "benchmarks": {
                    "type": "object",
                    "nullable": true
                  },
                  "related": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              },
              "citation": {
                "type": "string",
                "nullable": true
              },
              "quick_start": {
                "type": "string",
                "nullable": true
              },
              "body": {
                "type": "object",
                "description": "Only present when ?include=body",
                "properties": {
                  "readme_html": {
                    "type": "string",
                    "nullable": true
                  },
                  "has_fulltext": {
                    "type": "boolean"
                  }
                }
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "elapsed_ms": {
                "type": "integer"
              },
              "etag": {
                "type": "string",
                "nullable": true
              },
              "candidates_tried": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Concept": {
        "type": "object",
        "description": "A single knowledge article (concept) list entry. Heavy content/highlights columns are excluded from the list payload.",
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "umid": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string"
          },
          "subtitle": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "author": {
            "type": "string",
            "nullable": true
          },
          "word_count": {
            "type": "integer",
            "description": "0 when not recorded."
          },
          "published_at": {
            "type": "string",
            "nullable": true
          },
          "updated_at": {
            "type": "string",
            "nullable": true
          },
          "canonical_url": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "slug",
          "title",
          "tags",
          "word_count"
        ]
      },
      "ConceptsResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "knowledge_v1"
          },
          "total_count": {
            "type": "integer",
            "description": "Total published articles matching the filter (before pagination)."
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "next_offset": {
            "type": "integer",
            "nullable": true,
            "description": "Offset for the next page, or null when the final page has been reached."
          },
          "category": {
            "type": "string",
            "nullable": true,
            "description": "Echoes the applied category filter; null when none was supplied."
          },
          "concepts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Concept"
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "elapsed_ms": {
                "type": "integer"
              },
              "etag": {
                "type": "string",
                "nullable": true
              }
            }
          }
        },
        "required": [
          "version",
          "total_count",
          "limit",
          "offset",
          "next_offset",
          "category",
          "concepts",
          "meta"
        ]
      },
      "ConceptsError": {
        "type": "object",
        "description": "Structured error envelope returned by /api/v1/concepts (distinct from the simple {error} envelope).",
        "properties": {
          "error": {
            "type": "boolean",
            "example": true
          },
          "code": {
            "type": "string",
            "example": "BAD_REQUEST"
          },
          "message": {
            "type": "string"
          },
          "endpoint": {
            "type": "string",
            "example": "/api/v1/concepts"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix epoch milliseconds."
          },
          "_gateway_trace": {
            "type": "string"
          }
        },
        "required": [
          "error",
          "code",
          "message",
          "endpoint",
          "timestamp"
        ]
      },
      "TrendEntry": {
        "type": "object",
        "description": "7-day FNI trend for one entity.",
        "properties": {
          "scores": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Up to 7 daily FNI scores, oldest-first."
          },
          "dates": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to 7 ISO dates aligned with scores."
          },
          "change7d": {
            "type": "number",
            "description": "7-day change percentage."
          },
          "direction": {
            "type": "string",
            "enum": [
              "up",
              "down",
              "stable"
            ]
          },
          "latest": {
            "type": "number",
            "description": "Most recent FNI score."
          }
        },
        "required": [
          "scores",
          "dates",
          "change7d",
          "direction",
          "latest"
        ]
      },
      "TrendsBatchResponse": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "fni_v2.0"
          },
          "trends": {
            "type": "object",
            "description": "Map of entity id → trend entry. Only ids with trend data are present.",
            "additionalProperties": {
              "$ref": "#/components/schemas/TrendEntry"
            }
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Requested ids that had no trend data."
          },
          "meta": {
            "type": "object",
            "properties": {
              "elapsed_ms": {
                "type": "integer"
              },
              "found": {
                "type": "integer",
                "description": "Count of ids resolved to a trend entry."
              },
              "requested": {
                "type": "integer",
                "description": "Count of ids requested."
              }
            }
          }
        },
        "required": [
          "version",
          "trends",
          "missing",
          "meta"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}