{
  "openapi": "3.1.0",
  "info": {
    "title": "Darlington Public API",
    "version": "1.0.0",
    "description": "Read-only public portfolio data and a human-reviewed contact endpoint for Michael Darlington. Private Personal OS data is deliberately excluded.",
    "contact": {
      "name": "Darlington",
      "url": "https://www.darlington.dev/contact",
      "email": "access@darlington.dev"
    },
    "x-deprecation-policy": {
      "currentVersion": "2026-08-01",
      "status": "active",
      "minimumNoticeDays": 90,
      "documentation": "https://www.darlington.dev/api-policy.md",
      "activeResponseLinkRelation": "deprecation",
      "responseHeadersWhenDeprecated": ["Deprecation", "Sunset"],
      "standards": ["RFC 9745", "RFC 8594"]
    },
    "x-onboarding": {
      "authentication": "none",
      "firstRequest": "GET https://www.darlington.dev/api/profile",
      "sandboxRequired": false,
      "note": "Public reads expose deliberately public data and may be called directly in production. POST /api/contact sends a real message and remains human-confirmed."
    },
    "x-rate-limit-policy": {
      "applicationQuotaEnforced": false,
      "documentation": "https://www.darlington.dev/api-policy.md#rate-limits-and-retries",
      "note": "No fixed application quota exists, so the API does not publish fabricated RateLimit values."
    },
    "x-async-jobs": {
      "supported": false,
      "note": "Every public operation completes synchronously; no job or status resources exist."
    },
    "x-client-tooling": {
      "officialSdk": false,
      "officialCli": false,
      "recommended": ["HTTPS", "OpenAPI", "MCP"],
      "note": "Published Cortex packages target the separate Cortex product, not this portfolio API."
    },
    "license": {
      "name": "Public data; source-specific rights retained",
      "url": "https://www.darlington.dev/privacy"
    }
  },
  "externalDocs": {
    "description": "Onboarding, lifecycle, retry and client-tooling policy",
    "url": "https://www.darlington.dev/api-policy.md"
  },
  "servers": [
    {
      "url": "https://www.darlington.dev",
      "description": "Production"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Portfolio",
      "description": "Public identity, career, systems and writing"
    },
    {
      "name": "Activity",
      "description": "Public development and ship-log activity"
    },
    {
      "name": "Contact",
      "description": "Human-reviewed contact action"
    }
  ],
  "paths": {
    "/api/profile": {
      "parameters": [{ "$ref": "#/components/parameters/ApiVersion" }],
      "get": {
        "operationId": "getPublicProfile",
        "summary": "Get the public Darlington portfolio",
        "description": "Returns structured public career, systems, writing and link data. No authentication is required. Private Personal OS data is never returned.",
        "tags": ["Portfolio"],
        "responses": {
          "200": {
            "description": "Public portfolio data",
            "headers": {
              "Cache-Control": {
                "schema": { "type": "string" },
                "description": "Shared-cache policy"
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PublicProfile" }
              }
            }
          },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      },
      "options": {
        "operationId": "getPublicProfileCorsOptions",
        "summary": "Discover allowed cross-origin methods",
        "tags": ["Portfolio"],
        "responses": {
          "204": { "description": "CORS preflight accepted" }
        }
      }
    },
    "/api/ship-log": {
      "parameters": [{ "$ref": "#/components/parameters/ApiVersion" }],
      "get": {
        "operationId": "listPublicShipLogs",
        "summary": "List public ship-log entries",
        "description": "Returns published development summaries ordered newest first. Use the date of the final entry as the before cursor for the next page.",
        "tags": ["Activity"],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum entries to return; capped at 100",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Pagination cursor returned by a previous request",
            "schema": { "type": "string", "minLength": 1, "maxLength": 200 }
          }
        ],
        "responses": {
          "200": {
            "description": "Public ship-log entries",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ShipLogList" }
              }
            }
          }
        }
      }
    },
    "/api/github/activity": {
      "parameters": [{ "$ref": "#/components/parameters/ApiVersion" }],
      "get": {
        "operationId": "listPublicGithubActivity",
        "summary": "List recent public GitHub activity",
        "description": "Returns Michael Darlington's recent public personal and agency GitHub events.",
        "tags": ["Activity"],
        "responses": {
          "200": {
            "description": "Recent public activity",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ActivityList" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/api/github/contributions": {
      "parameters": [{ "$ref": "#/components/parameters/ApiVersion" }],
      "get": {
        "operationId": "getPublicGithubContributionCount",
        "summary": "Get the current public GitHub contribution count",
        "description": "Returns the aggregate public contribution total. A zero total with an error string indicates temporarily degraded upstream data.",
        "tags": ["Activity"],
        "responses": {
          "200": {
            "description": "Contribution count",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ContributionCount" }
              }
            }
          }
        }
      }
    },
    "/api/contact": {
      "parameters": [{ "$ref": "#/components/parameters/ApiVersion" }],
      "post": {
        "operationId": "submitContactMessage",
        "summary": "Send a contact message",
        "description": "Sends a real email to Michael Darlington. Agents should call this only after explicit user authorization; the website leaves final submission to the user. Supply Idempotency-Key to make retries safe: the same key and payload replay the successful result without sending another email for 24 hours; reusing the key with a different payload returns 409. After 24 hours the key is treated as new.",
        "tags": ["Contact"],
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ContactMessage" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ContactAccepted" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "409": {
            "description": "The idempotency key is already processing or was previously used with a different request payload",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying a concurrent request with the same key; present only for an in-progress request",
                "schema": { "type": "integer", "minimum": 1 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Problem" }
              }
            }
          },
          "415": {
            "description": "The request body must use application/json",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Problem" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/ServerError" },
          "503": { "$ref": "#/components/responses/ServerError" }
        }
      }
    }
  },
  "components": {
    "headers": {
      "ApiVersion": {
        "description": "The stable public API contract version used for this response.",
        "schema": { "type": "string", "const": "2026-08-01" }
      },
      "LifecyclePolicy": {
        "description": "RFC 8288 Link field containing an RFC 9745 deprecation-policy relation. Its presence does not mean the active version is deprecated.",
        "schema": { "type": "string" },
        "example": "<https://www.darlington.dev/api-policy.md>; rel=\"deprecation\"; type=\"text/markdown\""
      },
      "Deprecation": {
        "description": "RFC 9745 field emitted only after a resource or version is scheduled for deprecation.",
        "schema": { "type": "string" }
      },
      "Sunset": {
        "description": "RFC 8594 HTTP-date emitted only when a resource or version has a planned shutdown date.",
        "schema": { "type": "string" }
      }
    },
    "parameters": {
      "ApiVersion": {
        "name": "API-Version",
        "in": "header",
        "required": false,
        "description": "Public API contract version. Omit to use the current stable version.",
        "schema": {
          "type": "string",
          "enum": ["2026-08-01"],
          "default": "2026-08-01"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Unique key for this contact-message intent. Recommended for every request. Retrying the same payload with the same key within 24 hours returns success without sending another email. Reusing it with a different payload returns 409; after 24 hours it may create a new send.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 256
        }
      }
    },
    "schemas": {
      "PublicProfile": {
        "type": "object",
        "required": [
          "schemaVersion",
          "person",
          "career",
          "systems",
          "writing",
          "links",
          "privacyBoundary"
        ],
        "properties": {
          "schemaVersion": { "type": "string", "const": "1.0" },
          "person": { "$ref": "#/components/schemas/Person" },
          "career": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/CareerEntry" }
          },
          "systems": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SystemEntry" }
          },
          "personalOsModules": {
            "type": "array",
            "items": { "type": "string" }
          },
          "liveSites": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/LiveSite" }
          },
          "sourceRepositories": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SourceRepository" }
          },
          "writing": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/WritingEntry" }
          },
          "links": {
            "type": "object",
            "additionalProperties": { "type": "string", "format": "uri" }
          },
          "privacyBoundary": { "type": "string" }
        },
        "additionalProperties": false
      },
      "Person": {
        "type": "object",
        "required": [
          "name",
          "publicName",
          "location",
          "role",
          "summary",
          "specialties"
        ],
        "properties": {
          "name": { "type": "string" },
          "publicName": { "type": "string" },
          "location": { "type": "string" },
          "role": { "type": "string" },
          "summary": { "type": "string" },
          "specialties": { "type": "array", "items": { "type": "string" } }
        },
        "additionalProperties": false
      },
      "CareerEntry": {
        "type": "object",
        "required": ["year", "role", "company", "desc", "current"],
        "properties": {
          "year": { "type": "string" },
          "role": { "type": "string" },
          "company": { "type": "string" },
          "href": { "type": "string", "format": "uri" },
          "desc": { "type": "string" },
          "current": { "type": "boolean" }
        },
        "additionalProperties": false
      },
      "SystemEntry": {
        "type": "object",
        "required": ["icon", "name", "desc", "stack"],
        "properties": {
          "icon": { "type": "string" },
          "name": { "type": "string" },
          "desc": { "type": "string" },
          "stack": { "type": "array", "items": { "type": "string" } },
          "href": { "type": "string" },
          "award": { "type": "string" },
          "artifacts": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SystemArtifact" }
          }
        },
        "additionalProperties": false
      },
      "SystemArtifact": {
        "type": "object",
        "required": ["name", "kind", "ecosystem", "href", "install"],
        "properties": {
          "name": { "type": "string" },
          "kind": { "type": "string", "enum": ["SDK", "MCP bridge"] },
          "ecosystem": {
            "type": "string",
            "enum": ["npm", "PyPI", "crates.io", "Go"]
          },
          "href": { "type": "string", "format": "uri" },
          "install": { "type": "string" }
        },
        "additionalProperties": false
      },
      "WritingEntry": {
        "type": "object",
        "required": ["title", "tag", "href"],
        "properties": {
          "title": { "type": "string" },
          "tag": { "type": "string" },
          "href": { "type": "string", "format": "uri" }
        },
        "additionalProperties": false
      },
      "LiveSite": {
        "type": "object",
        "required": ["name", "tech", "href", "image"],
        "properties": {
          "name": { "type": "string" },
          "tech": { "type": "array", "items": { "type": "string" } },
          "href": { "type": "string", "format": "uri" },
          "image": { "type": "string" }
        },
        "additionalProperties": false
      },
      "SourceRepository": {
        "type": "object",
        "required": ["name", "lang", "href"],
        "properties": {
          "name": { "type": "string" },
          "lang": { "type": "string" },
          "href": { "type": "string", "format": "uri" }
        },
        "additionalProperties": false
      },
      "ShipLogCommit": {
        "type": "object",
        "required": ["sha", "message", "author", "timestamp"],
        "properties": {
          "sha": { "type": "string" },
          "message": { "type": "string" },
          "author": { "type": "string" },
          "timestamp": { "type": "string", "format": "date-time" }
        },
        "additionalProperties": false
      },
      "ShipLogPullRequest": {
        "type": "object",
        "required": ["number", "title", "merged_at", "url"],
        "properties": {
          "number": { "type": "integer", "minimum": 1 },
          "title": { "type": "string" },
          "merged_at": { "type": "string", "format": "date-time" },
          "url": { "type": "string", "format": "uri" }
        },
        "additionalProperties": false
      },
      "ShipLogProject": {
        "type": "object",
        "required": ["name", "repo", "summary", "commits", "prs"],
        "properties": {
          "name": { "type": "string" },
          "repo": { "type": "string" },
          "summary": { "type": "string" },
          "commits": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ShipLogCommit" }
          },
          "prs": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ShipLogPullRequest" }
          }
        },
        "additionalProperties": false
      },
      "ShipLogStats": {
        "type": "object",
        "required": ["total_commits", "prs_merged", "repos_active"],
        "properties": {
          "total_commits": { "type": "integer", "minimum": 0 },
          "prs_merged": { "type": "integer", "minimum": 0 },
          "repos_active": { "type": "integer", "minimum": 0 }
        },
        "additionalProperties": false
      },
      "ShipLogEntry": {
        "type": "object",
        "required": ["id", "date", "narrative", "projects", "stats"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "date": { "type": "string", "format": "date" },
          "narrative": { "type": "string" },
          "projects": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ShipLogProject" }
          },
          "stats": { "$ref": "#/components/schemas/ShipLogStats" }
        },
        "additionalProperties": false
      },
      "ShipLogList": {
        "type": "array",
        "items": { "$ref": "#/components/schemas/ShipLogEntry" }
      },
      "ActivityEntry": {
        "type": "object",
        "required": ["time", "msg", "org"],
        "properties": {
          "time": { "type": "string", "format": "date-time" },
          "msg": { "type": "string" },
          "org": { "type": "string", "enum": ["personal", "agency"] }
        },
        "additionalProperties": false
      },
      "ActivityList": {
        "type": "array",
        "items": { "$ref": "#/components/schemas/ActivityEntry" }
      },
      "ContributionCount": {
        "type": "object",
        "required": ["total"],
        "properties": {
          "total": { "type": "integer", "minimum": 0 },
          "error": { "type": "string" }
        },
        "additionalProperties": false
      },
      "ContactMessage": {
        "type": "object",
        "required": ["name", "email", "message"],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 120 },
          "email": { "type": "string", "format": "email", "maxLength": 320 },
          "message": { "type": "string", "minLength": 1, "maxLength": 5000 }
        },
        "additionalProperties": false
      },
      "ContactAccepted": {
        "type": "object",
        "required": ["success"],
        "properties": { "success": { "type": "boolean", "const": true } },
        "additionalProperties": false
      },
      "Problem": {
        "type": "object",
        "required": ["error"],
        "properties": { "error": { "type": "string" } },
        "additionalProperties": true
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request was invalid",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Problem" }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "The HTTP method is not supported",
        "content": {
          "application/json": {
            "schema": { "type": "object", "additionalProperties": true }
          }
        }
      },
      "ServerError": {
        "description": "The operation could not be completed",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Problem" }
          }
        }
      }
    }
  }
}
