{
  "openapi": "3.0.3",
  "info": {
    "title": "KnowledgeChain API",
    "description": "KnowledgeChain REST API — 让 AI Agent 有记忆，做过的事不重复，踩过的坑不再踩。",
    "version": "0.1.0",
    "contact": {
      "name": "KnowledgeChain",
      "url": "https://github.com/knowledge-chain/kc"
    }
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "Current server"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/search": {
      "post": {
        "operationId": "searchExperience",
        "summary": "Search experiences",
        "description": "Semantic search over the experience store. Returns ranked matches with optional summary or full detail.",
        "tags": ["experience"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              },
              "example": {
                "query": "how to handle HTTP errors in Go",
                "limit": 5,
                "detail": "summary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Matching experiences",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/record": {
      "post": {
        "operationId": "recordExperience",
        "summary": "Record a new experience",
        "description": "Saves a completed task as an experience. The engine extracts embeddings, computes quality score, and deduplicates.",
        "tags": ["experience"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordRequest"
              },
              "example": {
                "task_description": "deploy Go service with Docker",
                "approach": ["write Dockerfile", "build image", "run container"],
                "outcome": "success",
                "tags": ["go", "docker", "deployment"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Experience created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/query": {
      "post": {
        "operationId": "queryKnowledge",
        "summary": "Query the knowledge graph",
        "description": "Natural language Q&A over the knowledge graph powered by LightRAG.",
        "tags": ["knowledge"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryRequest"
              },
              "example": {
                "question": "What is the best way to use Redis for caching?",
                "mode": "hybrid"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Knowledge graph answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueryResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/compare": {
      "post": {
        "operationId": "compareApproaches",
        "summary": "Compare multiple approaches",
        "description": "Multi-signal reasoning layer — retrieves evidence for each candidate approach and ranks them by reliability.",
        "tags": ["reasoning"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompareRequest"
              },
              "example": {
                "problem": "how to implement rate limiting in Go",
                "candidates": ["token bucket", "leaky bucket", "sliding window"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked candidates with evidence",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompareResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/expand": {
      "post": {
        "operationId": "expandExperience",
        "summary": "Expand experience details",
        "description": "Given a list of experience IDs (e.g. from a summary search), returns the full approach, anti_patterns, and metrics for each.",
        "tags": ["experience"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExpandRequest"
              },
              "example": {
                "ids": ["exp-001", "exp-002"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Full experience details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExpandResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key as Bearer token. Omit in dev mode (API_KEYS env var empty)."
      }
    },
    "schemas": {
      "SearchRequest": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": {
            "type": "string",
            "description": "Natural language query"
          },
          "limit": {
            "type": "integer",
            "default": 5,
            "minimum": 1,
            "maximum": 20,
            "description": "Max number of results"
          },
          "detail": {
            "type": "string",
            "enum": ["summary", "full"],
            "default": "summary",
            "description": "summary saves ~80% tokens; use expand to fetch full details"
          },
          "tags": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Optional tag filters"
          }
        }
      },
      "SearchResponse": {
        "type": "object",
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MatchResult"
            }
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "MatchResult": {
        "type": "object",
        "properties": {
          "experience_id": {"type": "string"},
          "task_description": {"type": "string"},
          "match_score": {"type": "number", "format": "float"},
          "semantic_score": {"type": "number", "format": "float"},
          "source": {"type": "string"},
          "reflection": {
            "type": "string",
            "enum": ["accept", "warn", "refine"],
            "description": "Self-RAG style signal — accept: use as-is; warn: use with caution; refine: consider re-querying"
          },
          "tags": {
            "type": "array",
            "items": {"type": "string"}
          },
          "quality_score": {"type": "number", "format": "float"},
          "status": {"type": "string"}
        }
      },
      "RecordRequest": {
        "type": "object",
        "required": ["task_description", "approach"],
        "properties": {
          "task_description": {
            "type": "string",
            "description": "What the agent was trying to do"
          },
          "approach": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Ordered steps taken"
          },
          "outcome": {
            "type": "string",
            "enum": ["success", "failure", "partial"],
            "default": "success"
          },
          "tags": {
            "type": "array",
            "items": {"type": "string"}
          },
          "anti_patterns": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Pitfalls to avoid next time"
          },
          "referenced_experience_id": {
            "type": "string",
            "description": "ID of an experience this builds on (provenance chain)"
          }
        }
      },
      "RecordResponse": {
        "type": "object",
        "properties": {
          "experience_id": {"type": "string"},
          "status": {"type": "string"},
          "quality_score": {"type": "number", "format": "float"},
          "duplicate_of": {
            "type": "string",
            "description": "Set if this experience was merged into an existing one"
          }
        }
      },
      "QueryRequest": {
        "type": "object",
        "required": ["question"],
        "properties": {
          "question": {
            "type": "string",
            "description": "Natural language question"
          },
          "mode": {
            "type": "string",
            "enum": ["naive", "local", "global", "hybrid"],
            "default": "hybrid",
            "description": "LightRAG retrieval mode"
          }
        }
      },
      "QueryResponse": {
        "type": "object",
        "properties": {
          "answer": {"type": "string"},
          "confidence": {"type": "number", "format": "float"},
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {"type": "string"},
                "content": {"type": "string"},
                "score": {"type": "number", "format": "float"}
              }
            }
          }
        }
      },
      "CompareRequest": {
        "type": "object",
        "required": ["problem"],
        "properties": {
          "problem": {
            "type": "string",
            "description": "The problem or decision to compare approaches for"
          },
          "candidates": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Approach names to compare. If omitted, the engine retrieves candidates from the experience store."
          }
        }
      },
      "CompareResponse": {
        "type": "object",
        "properties": {
          "candidates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "approach": {"type": "string"},
                "score": {"type": "number", "format": "float"},
                "evidence_count": {"type": "integer"},
                "summary": {"type": "string"}
              }
            }
          },
          "recommendation": {"type": "string"}
        }
      },
      "ExpandRequest": {
        "type": "object",
        "required": ["ids"],
        "properties": {
          "ids": {
            "type": "array",
            "items": {"type": "string"},
            "minItems": 1,
            "description": "Experience IDs to expand (from a previous search_experience call)"
          }
        }
      },
      "ExpandResponse": {
        "type": "object",
        "properties": {
          "experiences": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExperienceFull"
            }
          }
        }
      },
      "ExperienceFull": {
        "type": "object",
        "properties": {
          "id": {"type": "string"},
          "task_description": {"type": "string"},
          "approach": {
            "type": "array",
            "items": {"type": "string"}
          },
          "outcome": {"type": "string"},
          "anti_patterns": {
            "type": "array",
            "items": {"type": "string"}
          },
          "tags": {
            "type": "array",
            "items": {"type": "string"}
          },
          "quality_score": {"type": "number", "format": "float"},
          "confidence": {"type": "number", "format": "float"},
          "reuse_count": {"type": "integer"},
          "status": {"type": "string"},
          "created_at": {"type": "string", "format": "date-time"},
          "updated_at": {"type": "string", "format": "date-time"}
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {"type": "string"}
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": {
          "application/json": {
            "schema": {"$ref": "#/components/schemas/ErrorResponse"}
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {"$ref": "#/components/schemas/ErrorResponse"}
          }
        }
      }
    }
  }
}