{
  "openapi": "3.1.0",
  "info": {
    "title": "Trigvale Agent API",
    "version": "1.0.0",
    "summary": "Synchronous evaluation surface for agent clients (Cursor, Claude Code, Codex, Claude Desktop, custom agents).",
    "description": "Trigvale's REST API for AI agents that need to validate startup ideas before scaffolding code. The official MCP server `@trigvale/mcp` wraps this endpoint as a stdio MCP tool — see https://www.npmjs.com/package/@trigvale/mcp. Agents that prefer plain HTTP can call this surface directly with the same auth + request/response shape.\n\nAuth is via long-lived agent tokens issued from https://trigvale.com/settings (Integrate plan, $99/mo). The token is a bearer credential; tokens are gated to the operator plan at issuance time AND re-checked on every call (downgrades take effect immediately).",
    "contact": { "name": "Trigvale support", "url": "https://trigvale.com/contact" },
    "license": { "name": "Proprietary — see https://trigvale.com/terms" }
  },
  "servers": [
    { "url": "https://api.trigvale.com", "description": "Production" },
    { "url": "https://api-dev.trigvale.com", "description": "Development (internal)" }
  ],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/agent/v1/evaluate": {
      "post": {
        "operationId": "evaluateIdea",
        "summary": "Validate a startup idea",
        "description": "Runs the full Trigvale pipeline on a raw idea string: Haiku normalization → Opus scoring (10-dimension rubric, deterministic VRS computed in code) → live evidence pull (Reddit / GitHub / HN / Stack Overflow / dev.to, archetype-partitioned) → archetype classification → founder-fit calibration (if a skill graph is on file). The verdict (kill / pivot / test / build) is decided deterministically from the scorecard + evidence — same inputs always yield the same verdict. By default the brief is persisted to the user's vault at /ideas/{ideaId}; pass `save=false` for ephemeral checks.\n\nIntended UX: build agents call this BEFORE writing project scaffolding. A `kill` or `pivot` verdict surfaces the load-bearing weakness; the agent can show the user and ask whether to proceed anyway. A `test` verdict means a specific assumption needs real-world validation first; the agent can suggest the validation sprint Trigvale recommends.",
        "tags": ["agents"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EvaluateRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Brief generated successfully.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EvaluateResponse" }
              }
            }
          },
          "401": {
            "description": "Missing or invalid agent token.",
            "$ref": "#/components/responses/ErrorResponse"
          },
          "402": {
            "description": "Agent tokens require the Integrate plan. Upgrade at /pricing.",
            "$ref": "#/components/responses/ErrorResponse"
          },
          "422": {
            "description": "Request body failed validation (e.g. rawIdea too short / too long).",
            "$ref": "#/components/responses/ErrorResponse"
          },
          "429": {
            "description": "Monthly evaluation quota exceeded for this account.",
            "$ref": "#/components/responses/ErrorResponse"
          },
          "500": {
            "description": "Internal error — pipeline failed mid-run.",
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Trigvale agent token (`tvk_…`) issued at https://trigvale.com/settings"
      }
    },
    "responses": {
      "ErrorResponse": {
        "description": "Error envelope.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    },
    "schemas": {
      "EvaluateRequest": {
        "type": "object",
        "required": ["rawIdea"],
        "properties": {
          "rawIdea": {
            "type": "string",
            "minLength": 5,
            "maxLength": 4000,
            "description": "Free-form idea description from the founder. Mess is fine — Trigvale normalizes it. Be specific about who has the pain, who pays, and why now."
          },
          "save": {
            "type": "boolean",
            "default": true,
            "description": "When true, persist the brief to the user's vault at /ideas/{ideaId}. Set false for ephemeral checks (no DDB write, no quota burn for sharpens, no archetype aggregate update)."
          }
        }
      },
      "EvaluateResponse": {
        "type": "object",
        "required": ["ideaObject", "scorecard", "evidence", "verdict"],
        "properties": {
          "ideaObject": { "$ref": "#/components/schemas/IdeaObject" },
          "scorecard": { "$ref": "#/components/schemas/Scorecard" },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/EvidenceItem" }
          },
          "verdict": { "$ref": "#/components/schemas/Verdict" },
          "founderAdjustments": {
            "type": "array",
            "description": "Per-dimension calibration deltas applied from the user's declared founder skill graph. Empty array if no profile is on file. Bounded ±15 points per dimension.",
            "items": {
              "type": "object",
              "required": ["dimension", "delta", "reason"],
              "properties": {
                "dimension": { "type": "string" },
                "delta": { "type": "integer", "minimum": -15, "maximum": 15 },
                "reason": { "type": "string" }
              }
            }
          },
          "archetypeAssignments": {
            "type": "array",
            "description": "1–3 archetype clusters this idea matches (from the 16-archetype catalog at /archetypes).",
            "items": {
              "type": "object",
              "required": ["archetype", "confidence", "rationale"],
              "properties": {
                "archetype": {
                  "type": "string",
                  "description": "Catalog id, e.g. 'vertical-ai-saas'."
                },
                "confidence": { "type": "string", "enum": ["high", "medium", "low"] },
                "rationale": { "type": "string" }
              }
            }
          },
          "saved": {
            "type": ["object", "null"],
            "description": "Present + non-null when `save=true` was requested AND persistence succeeded.",
            "properties": {
              "ideaId": {
                "type": "string",
                "description": "Open at https://trigvale.com/ideas/{ideaId}"
              },
              "versionId": { "type": "string" },
              "versionN": { "type": "integer" }
            }
          }
        }
      },
      "IdeaObject": {
        "type": "object",
        "description": "The normalized form of the founder's pitch — what the LLM scores against.",
        "required": [
          "title",
          "problem",
          "targetCustomer",
          "buyer",
          "currentAlternatives",
          "solution",
          "monetizationHypothesis",
          "distributionHypothesis",
          "constraints",
          "founderAssumptions",
          "missingInfo"
        ],
        "properties": {
          "title": { "type": "string" },
          "problem": { "type": "string" },
          "targetCustomer": { "type": "string" },
          "buyer": { "type": "string" },
          "currentAlternatives": { "type": "array", "items": { "type": "string" } },
          "solution": { "type": "string" },
          "monetizationHypothesis": { "type": "string" },
          "distributionHypothesis": { "type": "string" },
          "constraints": { "type": "array", "items": { "type": "string" } },
          "founderAssumptions": { "type": "array", "items": { "type": "string" } },
          "missingInfo": { "type": "array", "items": { "type": "string" } }
        }
      },
      "Scorecard": {
        "type": "object",
        "required": ["vrs", "confidence", "breakdown", "weakestAssumptions"],
        "properties": {
          "vrs": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Venture Readiness Score, computed deterministically in code from the per-dimension breakdown. The LLM does NOT pick this number — it scores individual dimensions against published anchors and code derives the VRS."
          },
          "confidence": { "type": "string", "enum": ["low", "medium", "high"] },
          "breakdown": {
            "type": "array",
            "description": "10 dimensions: painIntensity, buyerUrgency, reachability, marketSize, competition, differentiation, monetization, executionComplexity, founderFit, evidenceQuality.",
            "items": {
              "type": "object",
              "required": ["dimension", "score", "anchor", "rationale"],
              "properties": {
                "dimension": { "type": "string" },
                "score": { "type": "integer", "minimum": 0, "maximum": 100 },
                "anchor": {
                  "type": "string",
                  "description": "Calibrated anchor label the score corresponds to (0/25/50/75/100)."
                },
                "rationale": { "type": "string" }
              }
            }
          },
          "weakestAssumptions": {
            "type": "array",
            "items": { "type": "string" },
            "description": "3–5 short bullets naming the load-bearing assumptions that, if wrong, kill the verdict."
          },
          "modelUsed": {
            "type": "string",
            "description": "The LLM provider+model that produced this scorecard."
          }
        }
      },
      "EvidenceItem": {
        "type": "object",
        "required": ["sourceKind"],
        "properties": {
          "sourceKind": {
            "type": "string",
            "enum": ["observed", "inferred", "missing", "ai", "user-claim"],
            "description": "Trigvale never blends sources — every item declares whether it's grounded (observed), reasoned-about (inferred), conspicuously absent (missing), AI-generated context (ai), or the founder's own claim."
          },
          "claim": { "type": "string" },
          "url": { "type": ["string", "null"], "format": "uri" },
          "id": { "type": "string" },
          "capturedAt": { "type": "string", "format": "date-time" }
        }
      },
      "Verdict": {
        "type": "object",
        "required": ["verdict", "reasons"],
        "properties": {
          "verdict": {
            "type": "string",
            "enum": ["kill", "pivot", "test", "build"],
            "description": "Decided deterministically from the scorecard + evidence. Build is rare by construction — gated on a conjunction of strong pain + clear buyer + reachable channel + founder fit + evidence quality."
          },
          "reasons": {
            "type": "array",
            "items": { "type": "string" },
            "description": "One-line summaries of the gates that decided the verdict."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string" }
        }
      }
    }
  }
}
