From 90be03a8e96d8aa53b554da31b8550b6faa267f3 Mon Sep 17 00:00:00 2001 From: vratprem-art Date: Mon, 15 Jun 2026 20:51:32 +0530 Subject: [PATCH] Add files via upload --- docs/index.html | 21 + docs/openapi.json | 832 ++++++++++++++++++++++++++++++++++++ docs/openapi.yaml | 570 ++++++++++++++++++++++++ scripts/generate_openapi.py | 145 +++++++ 4 files changed, 1568 insertions(+) create mode 100644 docs/index.html create mode 100644 docs/openapi.json create mode 100644 docs/openapi.yaml create mode 100644 scripts/generate_openapi.py diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..58f3e332 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,21 @@ + + + + Engram Miner API Documentation + + + + + + + + + + + + diff --git a/docs/openapi.json b/docs/openapi.json new file mode 100644 index 00000000..18b57555 --- /dev/null +++ b/docs/openapi.json @@ -0,0 +1,832 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Engram Miner API", + "description": "Auto-generated OpenAPI specification for Engram Miner HTTP endpoints.", + "version": "1.0.0" + }, + "components": { + "securitySchemes": { + "sr25519_auth": { + "type": "apiKey", + "in": "header", + "name": "Authorization", + "description": "Request body must be signed. Validation depends on Bittensor SS58 hotkeys and sr25519 signatures." + } + } + }, + "paths": { + "/IngestSynapse": { + "post": { + "summary": "", + "description": "", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/QuerySynapse": { + "post": { + "summary": "", + "description": "", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/ChallengeSynapse": { + "post": { + "summary": "", + "description": "", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/namespace": { + "post": { + "summary": "Namespace management \u2014 create, delete, rotate key. Localhost only.", + "description": "Namespace management \u2014 create, delete, rotate key. Localhost only.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/AttestNamespace": { + "post": { + "summary": "Attest a namespace to a Bittensor hotkey.", + "description": "POST /AttestNamespace\nBody: {\n \"namespace\": str,\n \"owner_hotkey\": str (SS58),\n \"signature\": str (hex sr25519),\n \"timestamp_ms\": int\n}\n\nAnyone can call this \u2014 but only the hotkey owner can produce a valid\nsignature, and the on-chain stake of that hotkey determines trust tier.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/attestation/{namespace}": { + "get": { + "summary": "return trust info for a namespace.", + "description": "GET /attestation/{namespace} \u2014 return trust info for a namespace.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, + "/chat-history/{user_id}": { + "get": { + "summary": "GET /chat-history/{user_id}?conv_id=X \u2014 load a user's chat history.", + "description": "GET /chat-history/{user_id}?conv_id=X \u2014 load a user's chat history.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "user_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, + "/chat-history": { + "post": { + "summary": "save a user's chat history.", + "description": "POST /chat-history \u2014 save a user's chat history.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/conversations/{user_id}": { + "get": { + "summary": "list all conversations for a user.", + "description": "GET /conversations/{user_id} \u2014 list all conversations for a user.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "user_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, + "/conversations": { + "post": { + "summary": "create a new conversation.", + "description": "POST /conversations \u2014 create a new conversation.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/conversations/{conv_id}": { + "patch": { + "summary": "rename a conversation.", + "description": "PATCH /conversations/{conv_id} \u2014 rename a conversation.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "conv_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + }, + "delete": { + "summary": "DELETE /conversations/{conv_id}?user_id=X \u2014 delete a conversation.", + "description": "DELETE /conversations/{conv_id}?user_id=X \u2014 delete a conversation.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "conv_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, + "/retrieve/{cid}": { + "get": { + "summary": "return stored metadata for a CID.", + "description": "Public memories are freely readable. Private namespace memories return\n404 regardless of whether the CID exists \u2014 callers must use an\nauthenticated query to access their own private data.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "cid", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + }, + "delete": { + "summary": "permanently remove a stored memory.", + "description": "Public memories require network auth (validator/miner hotkey via\nverify_request). Private namespace memories additionally require the\ncaller to prove namespace ownership via namespace_hotkey + namespace_sig\n+ namespace_timestamp_ms in the JSON body.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "cid", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, + "/RepairSynapse": { + "post": { + "summary": "return full embedding for a CID so the validator", + "description": "can copy it to under-replicated miners. Requires network auth.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/KeyShareSynapse": { + "post": { + "summary": "store a Shamir key share for a namespace.", + "description": "Caller must prove namespace ownership via namespace_sig. The miner\nstores one share per namespace and cannot reconstruct the full key alone.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/KeyShareRetrieve": { + "post": { + "summary": "return this miner's share for a namespace.", + "description": "Caller must prove namespace ownership via namespace_sig. Returns the\nsingle share stored here; the client must collect K shares to reconstruct.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/list": { + "post": { + "summary": "paginate and filter stored memories.", + "description": "Body (all optional):\n filter dict[str, str] metadata key/value pairs (AND match)\n limit int max results (default 50, max 200)\n offset int skip N records (default 0)\n namespace str namespace to list (default public)\n namespace_hotkey str required for private namespaces\n namespace_sig str sr25519 ownership signature\n namespace_timestamp_ms int Unix ms timestamp for replay prevention", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + }, + "/health": { + "get": { + "summary": "", + "description": "", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/stats": { + "get": { + "summary": "Public stats endpoint \u2014 rich counters for the dashboard.", + "description": "Public stats endpoint \u2014 rich counters for the dashboard.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/metagraph": { + "get": { + "summary": "Public metagraph snapshot \u2014 returns all registered neurons for the leaderboard.", + "description": "Public metagraph snapshot \u2014 returns all registered neurons for the leaderboard.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/metrics": { + "get": { + "summary": "Prometheus metrics \u2014 localhost only to avoid leaking operational data.", + "description": "Prometheus metrics \u2014 localhost only to avoid leaking operational data.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/wallet-stats": { + "get": { + "summary": "", + "description": "", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/wallet-stats/{hotkey}": { + "get": { + "summary": "", + "description": "", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "parameters": [ + { + "name": "hotkey", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, + "/commitment": { + "get": { + "summary": "returns the Merkle root of this miner's full memory corpus.", + "description": "AI agents and validators can use this root to verify that a specific\nmemory (cid, embedding_hash) is genuinely stored here without downloading\nthe full index. The root changes whenever a memory is added or removed.", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/prove-memory": { + "post": { + "summary": "return a Merkle inclusion proof for one CID.", + "description": "Body: {\"cid\": \"v1::...\", \"embedding_hash\": \"<64-char hex>\"}\n\nAI agents use this to verify a specific memory is intact without\nfetching the entire store. Returns the proof as a JSON object that\ncan be verified offline with engram_core.verify_inclusion().", + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "sr25519_auth": [] + } + ] + } + } + } +} \ No newline at end of file diff --git a/docs/openapi.yaml b/docs/openapi.yaml new file mode 100644 index 00000000..ff1d4469 --- /dev/null +++ b/docs/openapi.yaml @@ -0,0 +1,570 @@ +openapi: 3.0.3 +info: + title: Engram Miner API + description: Auto-generated OpenAPI specification for Engram Miner HTTP endpoints. + version: 1.0.0 +components: + securitySchemes: + sr25519_auth: + type: apiKey + in: header + name: Authorization + description: Request body must be signed. Validation depends on Bittensor SS58 + hotkeys and sr25519 signatures. +paths: + /IngestSynapse: + post: + summary: '' + description: '' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /QuerySynapse: + post: + summary: '' + description: '' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /ChallengeSynapse: + post: + summary: '' + description: '' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /namespace: + post: + summary: "Namespace management \u2014 create, delete, rotate key. Localhost\ + \ only." + description: "Namespace management \u2014 create, delete, rotate key. Localhost\ + \ only." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /AttestNamespace: + post: + summary: Attest a namespace to a Bittensor hotkey. + description: "POST /AttestNamespace\nBody: {\n \"namespace\": str,\n \"\ + owner_hotkey\": str (SS58),\n \"signature\": str (hex sr25519),\n \"\ + timestamp_ms\": int\n}\n\nAnyone can call this \u2014 but only the hotkey\ + \ owner can produce a valid\nsignature, and the on-chain stake of that hotkey\ + \ determines trust tier." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /attestation/{namespace}: + get: + summary: return trust info for a namespace. + description: "GET /attestation/{namespace} \u2014 return trust info for a namespace." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: namespace + in: path + required: true + schema: + type: string + /chat-history/{user_id}: + get: + summary: "GET /chat-history/{user_id}?conv_id=X \u2014 load a user's chat history." + description: "GET /chat-history/{user_id}?conv_id=X \u2014 load a user's chat\ + \ history." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: user_id + in: path + required: true + schema: + type: string + /chat-history: + post: + summary: save a user's chat history. + description: "POST /chat-history \u2014 save a user's chat history." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /conversations/{user_id}: + get: + summary: list all conversations for a user. + description: "GET /conversations/{user_id} \u2014 list all conversations for\ + \ a user." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: user_id + in: path + required: true + schema: + type: string + /conversations: + post: + summary: create a new conversation. + description: "POST /conversations \u2014 create a new conversation." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /conversations/{conv_id}: + patch: + summary: rename a conversation. + description: "PATCH /conversations/{conv_id} \u2014 rename a conversation." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: conv_id + in: path + required: true + schema: + type: string + delete: + summary: "DELETE /conversations/{conv_id}?user_id=X \u2014 delete a conversation." + description: "DELETE /conversations/{conv_id}?user_id=X \u2014 delete a conversation." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: conv_id + in: path + required: true + schema: + type: string + /retrieve/{cid}: + get: + summary: return stored metadata for a CID. + description: "Public memories are freely readable. Private namespace memories\ + \ return\n404 regardless of whether the CID exists \u2014 callers must use\ + \ an\nauthenticated query to access their own private data." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: cid + in: path + required: true + schema: + type: string + delete: + summary: permanently remove a stored memory. + description: 'Public memories require network auth (validator/miner hotkey via + + verify_request). Private namespace memories additionally require the + + caller to prove namespace ownership via namespace_hotkey + namespace_sig + + + namespace_timestamp_ms in the JSON body.' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: cid + in: path + required: true + schema: + type: string + /RepairSynapse: + post: + summary: return full embedding for a CID so the validator + description: can copy it to under-replicated miners. Requires network auth. + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /KeyShareSynapse: + post: + summary: store a Shamir key share for a namespace. + description: 'Caller must prove namespace ownership via namespace_sig. The + miner + + stores one share per namespace and cannot reconstruct the full key alone.' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /KeyShareRetrieve: + post: + summary: return this miner's share for a namespace. + description: 'Caller must prove namespace ownership via namespace_sig. Returns + the + + single share stored here; the client must collect K shares to reconstruct.' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /list: + post: + summary: paginate and filter stored memories. + description: "Body (all optional):\n filter dict[str, str]\ + \ metadata key/value pairs (AND match)\n limit int \ + \ max results (default 50, max 200)\n offset int\ + \ skip N records (default 0)\n namespace str \ + \ namespace to list (default public)\n namespace_hotkey \ + \ str required for private namespaces\n namespace_sig \ + \ str sr25519 ownership signature\n namespace_timestamp_ms\ + \ int Unix ms timestamp for replay prevention" + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] + /health: + get: + summary: '' + description: '' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + /stats: + get: + summary: "Public stats endpoint \u2014 rich counters for the dashboard." + description: "Public stats endpoint \u2014 rich counters for the dashboard." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + /metagraph: + get: + summary: "Public metagraph snapshot \u2014 returns all registered neurons for\ + \ the leaderboard." + description: "Public metagraph snapshot \u2014 returns all registered neurons\ + \ for the leaderboard." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + /metrics: + get: + summary: "Prometheus metrics \u2014 localhost only to avoid leaking operational\ + \ data." + description: "Prometheus metrics \u2014 localhost only to avoid leaking operational\ + \ data." + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + /wallet-stats: + get: + summary: '' + description: '' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + /wallet-stats/{hotkey}: + get: + summary: '' + description: '' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + parameters: + - name: hotkey + in: path + required: true + schema: + type: string + /commitment: + get: + summary: returns the Merkle root of this miner's full memory corpus. + description: 'AI agents and validators can use this root to verify that a specific + + memory (cid, embedding_hash) is genuinely stored here without downloading + + the full index. The root changes whenever a memory is added or removed.' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + /prove-memory: + post: + summary: return a Merkle inclusion proof for one CID. + description: 'Body: {"cid": "v1::...", "embedding_hash": "<64-char hex>"} + + + AI agents use this to verify a specific memory is intact without + + fetching the entire store. Returns the proof as a JSON object that + + can be verified offline with engram_core.verify_inclusion().' + responses: + '200': + description: Successful operation + '400': + description: Bad Request + '401': + description: Unauthorized - Auth signature invalid + '403': + description: Forbidden - Missing or invalid namespace signature + '404': + description: Not Found + '500': + description: Internal Server Error + security: + - sr25519_auth: [] diff --git a/scripts/generate_openapi.py b/scripts/generate_openapi.py new file mode 100644 index 00000000..0e0a14ff --- /dev/null +++ b/scripts/generate_openapi.py @@ -0,0 +1,145 @@ +import ast +import json +import os +import yaml +from pathlib import Path + +def parse_miner_routes(filepath): + with open(filepath, "r", encoding="utf-8") as f: + source = f.read() + + tree = ast.parse(source) + + # 1. Find all async handlers and their docstrings + handlers = {} + for node in ast.walk(tree): + if isinstance(node, ast.AsyncFunctionDef): + docstring = ast.get_docstring(node) + handlers[node.name] = docstring or "" + + # 2. Find route registrations: app.router.add_("path", handler) + routes = [] + for node in ast.walk(tree): + if isinstance(node, ast.Call): + # Look for app.router.add_xxx(...) + if isinstance(node.func, ast.Attribute) and node.func.attr.startswith("add_"): + if isinstance(node.func.value, ast.Attribute) and node.func.value.attr == "router": + method = node.func.attr.replace("add_", "").lower() + if len(node.args) >= 2: + path_node = node.args[0] + handler_node = node.args[1] + + if isinstance(path_node, ast.Constant): + path = path_node.value + handler_name = handler_node.id if isinstance(handler_node, ast.Name) else None + + docstring = handlers.get(handler_name, "") if handler_name else "" + routes.append({ + "method": method, + "path": path, + "handler": handler_name, + "docstring": docstring + }) + return routes + +def generate_openapi(): + base_dir = Path(__file__).parent.parent + miner_file = base_dir / "neurons" / "miner.py" + + routes = parse_miner_routes(miner_file) + + openapi = { + "openapi": "3.0.3", + "info": { + "title": "Engram Miner API", + "description": "Auto-generated OpenAPI specification for Engram Miner HTTP endpoints.", + "version": "1.0.0" + }, + "components": { + "securitySchemes": { + "sr25519_auth": { + "type": "apiKey", + "in": "header", + "name": "Authorization", + "description": "Request body must be signed. Validation depends on Bittensor SS58 hotkeys and sr25519 signatures." + } + } + }, + "paths": {} + } + + for route in routes: + path = route["path"] + method = route["method"] + docstring = route["docstring"] + + # Parse docstring for summary and description + lines = docstring.strip().split("\n") + summary = lines[0] if lines else f"{method.upper()} {path}" + description = "\n".join(lines[1:]).strip() if len(lines) > 1 else summary + + if path not in openapi["paths"]: + openapi["paths"][path] = {} + + operation = { + "summary": summary.replace(f"{method.upper()} {path} — ", "").replace(f"POST {path} — ", "").strip(), + "description": description, + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized - Auth signature invalid" + }, + "403": { + "description": "Forbidden - Missing or invalid namespace signature" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + + # Add auth requirement to most POST endpoints + if method == "post" and path not in ["/health"]: + operation["security"] = [{"sr25519_auth": []}] + + # Parse path parameters + if "{" in path and "}" in path: + param_name = path.split("{")[1].split("}")[0] + operation["parameters"] = [ + { + "name": param_name, + "in": "path", + "required": True, + "schema": { + "type": "string" + } + } + ] + + openapi["paths"][path][method] = operation + + return openapi + +if __name__ == "__main__": + openapi_spec = generate_openapi() + + docs_dir = Path(__file__).parent.parent / "docs" + docs_dir.mkdir(exist_ok=True) + + json_path = docs_dir / "openapi.json" + with open(json_path, "w", encoding="utf-8") as f: + json.dump(openapi_spec, f, indent=2) + + yaml_path = docs_dir / "openapi.yaml" + with open(yaml_path, "w", encoding="utf-8") as f: + yaml.dump(openapi_spec, f, sort_keys=False) + + print(f"Generated {json_path} and {yaml_path}")