{
    "openapi": "3.1.0",
    "info": {
        "title": "FOSSHunter Public Agent Discovery API",
        "description": "Read-only, unauthenticated, citation-first access to the FOSSHunter open-source tool catalog. Repository metrics are point-in-time GitHub observations as of each tool's `synced_at`. Cite `canonical_url` for every tool presented and include `synced_at` plus `catalog_revision` when quoting metrics.",
        "version": "1.0.0",
        "license": {
            "name": "Public agent access terms",
            "url": "https://fosshunter.com/about#agent-access"
        }
    },
    "servers": [
        {
            "url": "https://fosshunter.com"
        }
    ],
    "externalDocs": {
        "description": "Full agent rulebook (interpretation, errors, caching)",
        "url": "https://fosshunter.com/llms-full.txt"
    },
    "paths": {
        "/api/public/v1/ai/discovery": {
            "get": {
                "summary": "Agent discovery entrypoint",
                "operationId": "getDiscovery",
                "responses": {
                    "200": {
                        "description": "Discovery document listing endpoints, formats, and rate limits.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Discovery"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/v1/catalog/stats": {
            "get": {
                "summary": "Catalog statistics",
                "operationId": "getCatalogStats",
                "responses": {
                    "200": {
                        "description": "Catalog counts and freshness signals.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CatalogStatistics"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/v1/tools": {
            "get": {
                "summary": "Search published tools",
                "operationId": "listTools",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "description": "Match against tool name and tagline.",
                        "schema": {
                            "type": "string",
                            "maxLength": 100
                        }
                    },
                    {
                        "name": "category",
                        "in": "query",
                        "description": "Active category slug.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "tags",
                        "in": "query",
                        "description": "Comma-separated tag slugs (max 8).",
                        "schema": {
                            "type": "string"
                        },
                        "example": "security,monitoring"
                    },
                    {
                        "name": "stacks",
                        "in": "query",
                        "description": "Comma-separated tech stack slugs (max 8).",
                        "schema": {
                            "type": "string"
                        },
                        "example": "php,laravel"
                    },
                    {
                        "name": "is_open_source",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "is_self_hosted",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "is_verified",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "is_featured",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "license",
                        "in": "query",
                        "description": "Exact SPDX identifier (e.g. MIT).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "relevance",
                                "stars",
                                "forks",
                                "last_commit"
                            ],
                            "default": "relevance"
                        }
                    },
                    {
                        "name": "dir",
                        "in": "query",
                        "description": "Sort direction for metric sorts.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ],
                            "default": "desc"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 50,
                            "default": 20
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "default": 1
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated tool summaries matching the filters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ToolCollection"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/v1/tools/{slug}": {
            "get": {
                "summary": "Tool detail",
                "operationId": "getTool",
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "pattern": "^[a-z0-9-]+$"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Full tool payload with repository metrics, features, links, and alternatives.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ToolDetail"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/v1/tools/{slug}/alternatives": {
            "get": {
                "summary": "Tool alternatives",
                "operationId": "getToolAlternatives",
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "pattern": "^[a-z0-9-]+$"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Curated and external alternatives for the tool.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AlternativeCollection"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/v1/compare": {
            "get": {
                "summary": "Compare tools by repository metrics",
                "description": "Compares 2-5 published tools. Returns `status: \"insufficient_data\"` (HTTP 200) when fewer than two tools resolve or lack repository metrics.",
                "operationId": "compareTools",
                "parameters": [
                    {
                        "name": "slugs",
                        "in": "query",
                        "required": true,
                        "description": "Comma-separated tool slugs.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "tool-a,tool-b"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Comparison payload or an insufficient_data envelope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Comparison"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/v1/categories": {
            "get": {
                "summary": "Active categories",
                "operationId": "listCategories",
                "responses": {
                    "200": {
                        "description": "Active categories with published tool counts.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryCollection"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error envelope with code `not_found`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "405": {
                        "description": "Error envelope with code `method_not_allowed`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Error envelope with code `invalid_input`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Error envelope with code `rate_limited`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Error envelope with code `temporarily_unavailable`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "Meta": {
                "type": "object",
                "required": [
                    "canonical_url",
                    "generated_at",
                    "catalog_revision",
                    "terms_url"
                ],
                "properties": {
                    "canonical_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "generated_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "catalog_revision": {
                        "type": "integer"
                    },
                    "terms_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "pagination": {
                        "$ref": "#/components/schemas/Pagination"
                    },
                    "filters": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "unresolved_slugs": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "excluded_tools": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            },
            "Pagination": {
                "type": "object",
                "required": [
                    "current_page",
                    "last_page",
                    "per_page",
                    "total"
                ],
                "properties": {
                    "current_page": {
                        "type": "integer"
                    },
                    "last_page": {
                        "type": "integer"
                    },
                    "per_page": {
                        "type": "integer"
                    },
                    "total": {
                        "type": "integer"
                    }
                }
            },
            "ErrorObject": {
                "type": "object",
                "required": [
                    "code",
                    "message"
                ],
                "properties": {
                    "code": {
                        "type": "string"
                    },
                    "message": {
                        "type": "string"
                    },
                    "details": {
                        "type": "object",
                        "additionalProperties": true
                    }
                }
            },
            "Error": {
                "type": "object",
                "required": [
                    "data",
                    "error",
                    "meta"
                ],
                "properties": {
                    "data": {
                        "type": "null"
                    },
                    "error": {
                        "$ref": "#/components/schemas/ErrorObject"
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "Discovery": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "CatalogStatistics": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "published_tools": {
                                "type": "integer"
                            },
                            "featured_tools": {
                                "type": "integer"
                            },
                            "verified_tools": {
                                "type": "integer"
                            },
                            "active_categories": {
                                "type": "integer"
                            },
                            "tags": {
                                "type": "integer"
                            },
                            "active_tech_stacks": {
                                "type": "integer"
                            },
                            "tools_with_repository_metrics": {
                                "type": "integer"
                            },
                            "newest_published_at": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time"
                            },
                            "last_repository_sync_at": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time"
                            }
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "ToolSummary": {
                "type": "object",
                "required": [
                    "slug",
                    "name"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "tagline": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "website_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "is_open_source": {
                        "type": "boolean"
                    },
                    "is_self_hosted": {
                        "type": [
                            "boolean",
                            "null"
                        ]
                    },
                    "is_featured": {
                        "type": "boolean"
                    },
                    "is_verified": {
                        "type": "boolean"
                    },
                    "category": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "additionalProperties": true
                    },
                    "tags": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "tech_stacks": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "repository": {
                        "$ref": "#/components/schemas/RepositoryMetrics"
                    },
                    "published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "canonical_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "links": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "string",
                            "format": "uri"
                        }
                    }
                }
            },
            "ToolDetailData": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/ToolSummary"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "description": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "features": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "additionalProperties": true
                                }
                            },
                            "external_links": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "additionalProperties": true
                                }
                            },
                            "alternatives": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Alternative"
                                }
                            }
                        }
                    }
                ]
            },
            "RepositoryMetrics": {
                "type": [
                    "object",
                    "null"
                ],
                "required": [
                    "provider",
                    "repo_url",
                    "stars_count",
                    "forks_count",
                    "open_issues_count",
                    "synced_at"
                ],
                "properties": {
                    "provider": {
                        "type": "string",
                        "enum": [
                            "github"
                        ]
                    },
                    "repo_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "owner": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "stars_count": {
                        "type": "integer"
                    },
                    "forks_count": {
                        "type": "integer"
                    },
                    "open_issues_count": {
                        "type": "integer"
                    },
                    "license_spdx": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "last_pushed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "synced_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "Point-in-time observation timestamp; REQUIRED in metric citations."
                    },
                    "is_archived": {
                        "type": "boolean"
                    }
                }
            },
            "Alternative": {
                "type": "object",
                "properties": {
                    "source_type": {
                        "type": "string",
                        "enum": [
                            "internal",
                            "external"
                        ]
                    },
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "website_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "is_open_source": {
                        "type": [
                            "boolean",
                            "null"
                        ]
                    },
                    "reason": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "canonical_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    }
                }
            },
            "ToolCollection": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ToolSummary"
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "ToolDetail": {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/ToolDetailData"
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "AlternativeCollection": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "Comparison": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": [
                            "object",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "insufficient_data"
                        ]
                    },
                    "error": {
                        "$ref": "#/components/schemas/ErrorObject",
                        "description": "Present on insufficient_data responses."
                    },
                    "abstention_reason": {
                        "type": "string"
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "CategoryCollection": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Category"
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Meta"
                    }
                }
            },
            "Category": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": "string"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "published_tools_count": {
                        "type": "integer"
                    }
                }
            }
        }
    }
}
