{
  "openapi": "3.1.0",
  "info": {
    "title": "Stratigos Security page finder",
    "version": "2.0.0",
    "summary": "Describe what you are looking for on stratigossecurity.com and get the pages most likely to answer it.",
    "description": "This is not a general-purpose API. Its one read action returns the two to four pages on stratigossecurity.com most likely to answer what you describe, chosen by plain keyword rules rather than a model. An optional reader role picks the pages written for that reader. What is sent is kept with the ordinary request log (User-Agent, signature headers, network origin) so the site can be improved around what visitors come for; secondarily, the optional model and developer parameters are compared with that log for a small research project on how agents read the web. Nothing here asks for, or should receive, anything that identifies a person or organization: no names, employers, email addresses, credentials, or quoted prompts. Anything resembling contact details is removed before storage. What is recorded and why: https://stratigossecurity.com/agents/#what-we-record",
    "contact": {
      "name": "Stratigos Security",
      "url": "https://stratigossecurity.com/contact/"
    },
    "x-purpose": "page-finder",
    "x-via": "openapi"
  },
  "servers": [
    {
      "url": "https://stratigossecurity.com"
    }
  ],
  "paths": {
    "/api/agent/find": {
      "get": {
        "operationId": "findPages",
        "summary": "Find the pages most likely to answer what you describe",
        "description": "One GET. Records the query, the pages returned, and the optional fields alongside the request log, and returns the pages with a note of what was stored. A later call with only session and found says whether the pages helped. Queries sent with GET appear in the URL; POST the same fields as JSON for a detailed project description. Every call is recorded.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "What you are looking for, in plain words. Required unless you are only answering found.",
            "schema": {
              "type": "string",
              "maxLength": 1000
            }
          },
          {
            "name": "role",
            "in": "query",
            "required": false,
            "description": "Who the reader is. Picks the pages written for that role.",
            "schema": {
              "type": "string",
              "enum": [
                "regulatory",
                "engineering",
                "quality",
                "clinical",
                "executive",
                "security",
                "research",
                "press",
                "other"
              ]
            }
          },
          {
            "name": "found",
            "in": "query",
            "required": false,
            "description": "On a later call with the same session: whether the suggested pages answered it.",
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "partly",
                "no"
              ]
            }
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "Optional. Model name and version, compared with the request headers.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "developer",
            "in": "query",
            "required": false,
            "description": "Optional. The organization that trained the model.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "harness",
            "in": "query",
            "required": false,
            "description": "Optional. The product or harness the agent runs inside.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "task_category",
            "in": "query",
            "required": false,
            "description": "Optional. The kind of task that brought you here. A category only.",
            "schema": {
              "type": "string",
              "enum": [
                "answering-question",
                "research-company",
                "indexing",
                "testing",
                "security",
                "sales-marketing",
                "browsing",
                "other"
              ]
            }
          },
          {
            "name": "discovery",
            "in": "query",
            "required": false,
            "description": "Optional. How you found this finder.",
            "schema": {
              "type": "string",
              "enum": [
                "llms-txt",
                "robots-txt",
                "link-rel",
                "link-header",
                "footer",
                "agent-card",
                "openapi",
                "api",
                "search",
                "person",
                "other"
              ]
            }
          },
          {
            "name": "session",
            "in": "query",
            "required": false,
            "description": "Optional. The session identifier from GET /api/agent or an earlier find call, so calls join up.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "via",
            "in": "query",
            "required": false,
            "description": "Optional. The via tag from the link you followed.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "verbose",
            "in": "query",
            "required": false,
            "description": "Set to '1' to add what the request itself indicated, the agreement check, and which index the answer came from.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pages, plus what was recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindResponse"
                }
              }
            }
          },
          "400": {
            "description": "Neither q nor a follow-up was given. The body still lists the general pages and says what is missing."
          },
          "503": {
            "description": "The collection service is not running. Nothing was recorded."
          }
        }
      },
      "post": {
        "operationId": "findPagesPost",
        "summary": "The same finder, with the parameters in a JSON or form body. Preferred for detailed project descriptions, which then stay out of the URL.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FindRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pages, plus what was recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindResponse"
                }
              }
            }
          },
          "400": {
            "description": "Neither q nor a follow-up was given."
          }
        }
      }
    },
    "/api/agent": {
      "get": {
        "operationId": "describeFinder",
        "summary": "Describe the finder and return a session identifier",
        "description": "Returns a JSON description of the finder's parameters, the optional self-report, and a session identifier to include in later calls so they join the request that fetched this description.",
        "responses": {
          "200": {
            "description": "Description of the finder",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FinderDescription"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/report": {
      "post": {
        "operationId": "introduceYourself",
        "summary": "Optional: a fuller self-description",
        "description": "Optional. Submit a short self-description as the agent, not as its user. Accepts JSON or an HTML form body. Returns a receipt, the comparison between what you said and what the request itself indicated, and suggested reading for the goal.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Introduction"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Introduction"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "303": {
            "description": "HTML form submissions are redirected to the receipt page at /agents/thanks/"
          },
          "400": {
            "description": "Missing or invalid fields. The body says which."
          },
          "503": {
            "description": "The collection service is not running. Nothing was recorded."
          }
        }
      }
    },
    "/api/agent/find/{words}": {
      "get": {
        "operationId": "findPagesByPath",
        "summary": "The finder with the words in the path, for fetchers that drop query strings",
        "description": "Identical to GET /api/agent/find?q=... with the query taken from the path segment. Hyphens, underscores, and plus signs read as spaces; percent-encoding is accepted. Other parameters may still be given in the query string when the fetcher keeps it.",
        "parameters": [
          {
            "name": "words",
            "in": "path",
            "required": true,
            "description": "What you are looking for, hyphen-separated or URL-encoded.",
            "schema": {
              "type": "string",
              "maxLength": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pages, plus what was recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/find/found/{session}/{answer}": {
      "get": {
        "operationId": "findFollowUp",
        "summary": "Say whether the suggested pages answered it",
        "description": "The follow-up in path form (the follow_up URLs in every finder response use it). Attaches the answer to the session's latest query.",
        "parameters": [
          {
            "name": "session",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "answer",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "partly",
                "no"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recorded; the same pages again for reference",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindResponse"
                }
              }
            }
          },
          "400": {
            "description": "No earlier query in that session"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "FindRequest": {
        "type": "object",
        "properties": {
          "q": {
            "type": "string",
            "maxLength": 1000,
            "description": "What you are looking for."
          },
          "role": {
            "type": "string",
            "enum": [
              "regulatory",
              "engineering",
              "quality",
              "clinical",
              "executive",
              "security",
              "research",
              "press",
              "other"
            ]
          },
          "found": {
            "type": "string",
            "enum": [
              "yes",
              "partly",
              "no"
            ]
          },
          "model": {
            "type": "string",
            "maxLength": 200
          },
          "developer": {
            "type": "string",
            "maxLength": 200
          },
          "harness": {
            "type": "string",
            "maxLength": 200
          },
          "task_category": {
            "type": "string",
            "enum": [
              "answering-question",
              "research-company",
              "indexing",
              "testing",
              "security",
              "sales-marketing",
              "browsing",
              "other"
            ]
          },
          "discovery": {
            "type": "string",
            "enum": [
              "llms-txt",
              "robots-txt",
              "link-rel",
              "link-header",
              "footer",
              "agent-card",
              "openapi",
              "api",
              "search",
              "person",
              "other"
            ]
          },
          "session": {
            "type": "string",
            "maxLength": 64
          },
          "via": {
            "type": "string",
            "maxLength": 64
          },
          "verbose": {
            "type": "string",
            "enum": [
              "1"
            ]
          }
        }
      },
      "FindResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "description": "Up to four pages, best match first.",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "why": {
                  "type": "string"
                },
                "answers": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "The page's own 'questions answered' entries that share terms with the query."
                }
              }
            }
          },
          "matched": {
            "type": "boolean",
            "description": "True when a keyword rule matched your words; false when the list came from the role or the general fallback."
          },
          "role": {
            "type": "string",
            "enum": [
              "regulatory",
              "engineering",
              "quality",
              "clinical",
              "executive",
              "security",
              "research",
              "press",
              "other"
            ]
          },
          "recorded": {
            "type": "object",
            "description": "What was stored, after length limits and the contact-details scrub. stored is false only when the database write itself failed; the call is answered either way."
          },
          "observed": {
            "type": "object",
            "description": "Present when a model or developer was given, or with verbose=1: what the request itself indicated."
          },
          "agreement": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "agrees",
              "disagrees",
              "unclear",
              "no-headers",
              null
            ],
            "description": "Present when a model or developer was given, or with verbose=1: whether the self-description matches the request-level evidence."
          },
          "follow_up": {
            "type": [
              "object",
              "null"
            ],
            "description": "Path-form URLs to say whether the pages helped: yes, partly, no. Null once answered or when the call was not stored.",
            "properties": {
              "question": {
                "type": "string"
              },
              "yes": {
                "type": "string"
              },
              "partly": {
                "type": "string"
              },
              "no": {
                "type": "string"
              }
            }
          },
          "receipt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier for this call. Contains no personal data."
          },
          "session": {
            "type": "string"
          },
          "about": {
            "type": "string",
            "description": "What was recorded and where a person can reach us."
          },
          "matched_terms": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Display forms of the terms that matched the top result."
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Things the site does not publish that the query asked about, said plainly: pricing, client names, sample reports."
          },
          "index": {
            "type": "object",
            "description": "With verbose=1: how many pages the answer was scored against, whether the index came from the origin or the bundled snapshot, and when it was generated."
          }
        }
      },
      "Introduction": {
        "type": "object",
        "required": [
          "model",
          "developer",
          "task_category",
          "discovery"
        ],
        "properties": {
          "model": {
            "type": "string",
            "maxLength": 200,
            "description": "Model name and version, for example 'Claude Opus 5' or 'GPT-5'."
          },
          "developer": {
            "type": "string",
            "maxLength": 200,
            "description": "The organization that trained the model."
          },
          "harness": {
            "type": "string",
            "maxLength": 200,
            "description": "Optional. The product or harness you run inside."
          },
          "task_category": {
            "type": "string",
            "enum": [
              "answering-question",
              "research-company",
              "indexing",
              "testing",
              "security",
              "sales-marketing",
              "browsing",
              "other"
            ],
            "description": "The kind of task that brought you here. A category only, never the task itself."
          },
          "discovery": {
            "type": "string",
            "enum": [
              "llms-txt",
              "robots-txt",
              "link-rel",
              "link-header",
              "footer",
              "agent-card",
              "openapi",
              "api",
              "search",
              "person",
              "other"
            ],
            "description": "How you found this."
          },
          "goal": {
            "type": "string",
            "maxLength": 1000,
            "description": "Optional. What the reader is trying to accomplish, in general terms. Used to choose the suggested reading."
          },
          "audience": {
            "type": "string",
            "maxLength": 500,
            "description": "Optional. Who the reader is, in general terms: a role and kind of organization. No names, employers, or contact details."
          },
          "wanted": {
            "type": "string",
            "maxLength": 1000,
            "description": "Optional. What information would have helped most, or what you looked for and did not find."
          },
          "outcome": {
            "type": "string",
            "enum": [
              "yes",
              "partly",
              "no",
              "not-looking",
              "other"
            ],
            "description": "Optional. Did you find what you needed?"
          },
          "notes": {
            "type": "string",
            "maxLength": 2000,
            "description": "Optional free text. Nothing that identifies a person or organization."
          },
          "session": {
            "type": "string",
            "maxLength": 64,
            "description": "Optional. The session identifier from GET /api/agent, so the submission joins the request that fetched it."
          },
          "via": {
            "type": "string",
            "maxLength": 64,
            "description": "Optional. The via tag from the link you followed."
          }
        }
      },
      "Receipt": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "receipt": {
            "type": "string",
            "description": "Identifier for this submission. Contains no personal data."
          },
          "recorded": {
            "type": "object",
            "description": "The fields as stored, after length limits."
          },
          "observed": {
            "type": "object",
            "description": "What the request itself indicated: User-Agent classification, signature status, network match."
          },
          "agreement": {
            "type": "string",
            "enum": [
              "agrees",
              "disagrees",
              "unclear",
              "no-headers"
            ],
            "description": "Whether the self-description matches the request-level evidence."
          },
          "suggested_reading": {
            "type": "array",
            "description": "Pages most likely to help with the described goal. Chosen by plain keyword rules, not by a model.",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "why": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "FinderDescription": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "session": {
            "type": "string"
          },
          "actions": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "recorded": {
            "type": "string"
          },
          "do_not_include": {
            "type": "string"
          },
          "what_we_record": {
            "type": "string"
          }
        }
      }
    }
  }
}
