{"components":{"schemas":{"Certificate":{"description":"A professional certification.","properties":{"credential_url":{"type":["string","null"],"description":"Public credential verification page.","format":"uri"},"description":{"type":["string","null"],"description":"What the certification covers."},"issued_at":{"description":"Issue date (ISO 8601).","type":["string","null"]},"title":{"description":"Certification name.","type":"string"}},"required":["title"],"type":"object"},"Error":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"},"Post":{"description":"A blog post including its full content as Markdown.","properties":{"categories":{"description":"Category titles the post is filed under.","items":{"type":"string"},"type":"array"},"description":{"type":["string","null"],"description":"Post intro/summary."},"markdown_url":{"description":"The post as raw Markdown (append .md to the post URL).","format":"uri","type":"string"},"published_at":{"description":"Publication date (ISO 8601).","type":["string","null"]},"slug":{"description":"URL slug of the post.","type":"string"},"title":{"description":"Post title.","type":"string"},"updated_at":{"description":"Last modification timestamp (ISO 8601).","type":"string"},"url":{"description":"Canonical HTML page.","format":"uri","type":"string"},"content_markdown":{"description":"Full post content rendered as Markdown.","type":"string"}},"required":["markdown_url","slug","title","updated_at","url","content_markdown"],"type":"object"},"PostSummary":{"description":"A blog post as listed on /blog.","properties":{"categories":{"description":"Category titles the post is filed under.","items":{"type":"string"},"type":"array"},"description":{"type":["string","null"],"description":"Post intro/summary."},"markdown_url":{"description":"The post as raw Markdown (append .md to the post URL).","format":"uri","type":"string"},"published_at":{"description":"Publication date (ISO 8601).","type":["string","null"]},"slug":{"description":"URL slug of the post.","type":"string"},"title":{"description":"Post title.","type":"string"},"updated_at":{"description":"Last modification timestamp (ISO 8601).","type":"string"},"url":{"description":"Canonical HTML page.","format":"uri","type":"string"}},"required":["markdown_url","slug","title","updated_at","url"],"type":"object"},"Program":{"description":"A developer or community program joined.","properties":{"description":{"type":["string","null"],"description":"What the program is."},"joined_at":{"description":"Join date (ISO 8601).","type":["string","null"]},"organization":{"type":["string","null"],"description":"Organization running the program."},"title":{"description":"Program name.","type":"string"},"url":{"type":["string","null"],"description":"Program page.","format":"uri"}},"required":["title"],"type":"object"},"ShowcaseProject":{"description":"A project from the showcase.","properties":{"created_at":{"description":"Project date (ISO 8601).","type":["string","null"]},"description":{"type":["string","null"],"description":"Short project description."},"slug":{"description":"URL slug of the project.","type":"string"},"title":{"description":"Project title.","type":"string"},"updated_at":{"description":"Last modification timestamp (ISO 8601).","type":"string"},"url":{"description":"Canonical HTML page.","format":"uri","type":"string"}},"required":["slug","title","updated_at","url"],"type":"object"},"SiteProfile":{"description":"Site and profile metadata with discovery links.","properties":{"contact":{"description":"How to reach the person behind the site.","properties":{"email":{"description":"Preferred contact email.","format":"email","type":"string"},"social":{"description":"Public social profiles.","items":{"description":"A public social profile.","properties":{"title":{"description":"Network or profile name.","type":"string"},"url":{"description":"Profile URL.","format":"uri","type":"string"}},"required":["title","url"],"type":"object"},"type":"array"},"url":{"description":"Contact page.","format":"uri","type":"string"}},"required":["email","social","url"],"type":"object"},"description":{"description":"One-line professional summary.","type":"string"},"focus":{"description":"Engineering focus areas.","items":{"type":"string"},"type":"array"},"handle":{"description":"Public handle used across the web.","type":"string"},"links":{"description":"Canonical HTML pages of the site.","properties":{"about":{"description":"Profile, experience, and education.","format":"uri","type":"string"},"achievements":{"description":"Certifications and programs.","format":"uri","type":"string"},"blog":{"description":"Writing on engineering and tooling.","format":"uri","type":"string"},"developers":{"description":"Developer portal and API docs.","format":"uri","type":"string"},"home":{"description":"Homepage.","format":"uri","type":"string"},"machine_view":{"description":"Plain-text machine view of the site.","format":"uri","type":"string"},"privacy":{"description":"Privacy policy.","format":"uri","type":"string"},"showcase":{"description":"Selected projects and works.","format":"uri","type":"string"}},"required":["about","achievements","blog","developers","home","machine_view","privacy","showcase"],"type":"object"},"location":{"description":"Where the person is based.","type":"string"},"machine_readable":{"description":"Machine-readable discovery surfaces.","properties":{"agent_skills":{"description":"Agent skills discovery index.","format":"uri","type":"string"},"agents_md":{"description":"Agent-ready profile in Markdown.","format":"uri","type":"string"},"api_catalog":{"description":"RFC 9727 API catalog linkset.","format":"uri","type":"string"},"llms_txt":{"description":"Complete site context as Markdown.","format":"uri","type":"string"},"openapi":{"description":"This OpenAPI 3.1 specification.","format":"uri","type":"string"},"sitemap_markdown":{"description":"Semantic sitemap in Markdown.","format":"uri","type":"string"},"sitemap_xml":{"description":"XML sitemap for search engines.","format":"uri","type":"string"}},"required":["agent_skills","agents_md","api_catalog","llms_txt","openapi","sitemap_markdown","sitemap_xml"],"type":"object"},"name":{"description":"Full legal name.","type":"string"},"role":{"description":"Professional role.","type":"string"}},"required":["contact","description","focus","handle","links","location","machine_readable","name","role"],"type":"object"}}},"info":{"contact":{"email":"hello@pungrumpy.com","name":"Noppakorn Kaewsalabnil (PunGrumpy)","url":"https://www.pungrumpy.com/contact"},"description":"Public, read-only JSON API for pungrumpy.com — the portfolio of Noppakorn Kaewsalabnil (PunGrumpy). No authentication or API key is required. Use it to fetch the site profile, blog posts (with full Markdown content), showcase projects, and achievements. Markdown surfaces for LLMs are documented at /developers, /llms.txt, and /agents.md. Versioning: the major version is pinned in the URL path (/api/v1); breaking changes ship as a new version, and a version slated for removal announces it with Deprecation (RFC 9745) and Sunset (RFC 8594) response headers at least 6 months in advance — v1 has no planned sunset. Rate limits: every response carries advisory RateLimit headers describing the fair-use envelope, and a throttled request receives HTTP 429 with Retry-After.","summary":"Read-only content API for the PunGrumpy portfolio.","title":"PunGrumpy Content API","version":"1.1.0","x-deprecation-policy":"https://www.pungrumpy.com/developers#versioning","x-rate-limit-policy":"https://www.pungrumpy.com/developers#fair-use"},"openapi":"3.1.0","paths":{"/api/v1":{"get":{"description":"Lists every available endpoint with its method, path, and purpose, plus the versioning, deprecation, and rate limit policies. Use this to orient before calling anything else.","operationId":"getApiIndex","responses":{"200":{"content":{"application/json":{"schema":{"description":"Index of the API: every endpoint plus service policies.","properties":{"description":{"description":"What the API offers.","type":"string"},"documentation_url":{"description":"Human-readable API documentation.","format":"uri","type":"string"},"endpoints":{"description":"Every available endpoint.","items":{"properties":{"description":{"description":"What the endpoint returns.","type":"string"},"method":{"description":"HTTP method.","type":"string"},"path":{"description":"URL path template.","type":"string"},"url":{"description":"Absolute endpoint URL.","format":"uri","type":"string"}},"required":["description","method","path","url"],"type":"object"},"type":"array"},"name":{"description":"API display name.","type":"string"},"openapi_url":{"description":"This OpenAPI 3.1 specification.","format":"uri","type":"string"},"rate_limit":{"properties":{"documentation_url":{"description":"Where the policy is documented.","format":"uri","type":"string"},"summary":{"description":"The policy in one sentence.","type":"string"}},"required":["documentation_url","summary"],"type":"object","description":"Rate limit policy."},"version":{"description":"Current API version.","type":"string"},"version_status":{"description":"Lifecycle status of this version.","enum":["current","deprecated","sunset"],"type":"string"},"versioning":{"description":"Versioning and deprecation policy.","properties":{"deprecation_policy":{"description":"Deprecation policy documentation.","format":"uri","type":"string"},"scheme":{"description":"How versions are selected.","enum":["url-path"],"type":"string"},"summary":{"description":"The versioning contract in one sentence.","type":"string"}},"required":["deprecation_policy","scheme","summary"],"type":"object"}},"required":["description","documentation_url","endpoints","name","openapi_url","version"],"type":"object"}}},"description":"Index of the API.","headers":{"RateLimit":{"description":"Current service limit per draft-ietf-httpapi-ratelimit-headers, e.g. remaining quota (r) and seconds until reset (t). Advisory: describes the fair-use envelope, not a live counter.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Quota policy per draft-ietf-httpapi-ratelimit-headers: q requests per w-second window.","schema":{"type":"string"}}}},"429":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Rate limited. Back off for the number of seconds given in Retry-After, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"default":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Structured JSON error."}},"summary":"API index","tags":["site"]}},"/api/v1/achievements":{"get":{"description":"Returns professional certifications (with credential verification links) and developer programs joined, newest first.","operationId":"listAchievements","responses":{"200":{"content":{"application/json":{"schema":{"description":"Certifications and programs.","properties":{"certificates":{"description":"Professional certifications, newest first.","items":{"description":"A professional certification.","properties":{"credential_url":{"type":["string","null"],"description":"Public credential verification page.","format":"uri"},"description":{"type":["string","null"],"description":"What the certification covers."},"issued_at":{"description":"Issue date (ISO 8601).","type":["string","null"]},"title":{"description":"Certification name.","type":"string"}},"required":["title"],"type":"object"},"type":"array"},"programs":{"description":"Developer programs joined, newest first.","items":{"description":"A developer or community program joined.","properties":{"description":{"type":["string","null"],"description":"What the program is."},"joined_at":{"description":"Join date (ISO 8601).","type":["string","null"]},"organization":{"type":["string","null"],"description":"Organization running the program."},"title":{"description":"Program name.","type":"string"},"url":{"type":["string","null"],"description":"Program page.","format":"uri"}},"required":["title"],"type":"object"},"type":"array"}},"required":["certificates","programs"],"type":"object"}}},"description":"Certifications and programs.","headers":{"RateLimit":{"description":"Current service limit per draft-ietf-httpapi-ratelimit-headers, e.g. remaining quota (r) and seconds until reset (t). Advisory: describes the fair-use envelope, not a live counter.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Quota policy per draft-ietf-httpapi-ratelimit-headers: q requests per w-second window.","schema":{"type":"string"}}}},"429":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Rate limited. Back off for the number of seconds given in Retry-After, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"default":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Structured JSON error."}},"summary":"List certifications and programs","tags":["achievements"]}},"/api/v1/posts":{"get":{"description":"Returns every published blog post, newest first, with title, summary, categories, dates, and canonical HTML plus raw Markdown URLs.","operationId":"listPosts","responses":{"200":{"content":{"application/json":{"schema":{"description":"All published posts.","properties":{"count":{"description":"Number of posts returned.","type":"integer"},"posts":{"description":"Every published post, newest first.","items":{"description":"A blog post as listed on /blog.","properties":{"categories":{"description":"Category titles the post is filed under.","items":{"type":"string"},"type":"array"},"description":{"type":["string","null"],"description":"Post intro/summary."},"markdown_url":{"description":"The post as raw Markdown (append .md to the post URL).","format":"uri","type":"string"},"published_at":{"description":"Publication date (ISO 8601).","type":["string","null"]},"slug":{"description":"URL slug of the post.","type":"string"},"title":{"description":"Post title.","type":"string"},"updated_at":{"description":"Last modification timestamp (ISO 8601).","type":"string"},"url":{"description":"Canonical HTML page.","format":"uri","type":"string"}},"required":["markdown_url","slug","title","updated_at","url"],"type":"object"},"type":"array"}},"required":["count","posts"],"type":"object"}}},"description":"All published posts.","headers":{"RateLimit":{"description":"Current service limit per draft-ietf-httpapi-ratelimit-headers, e.g. remaining quota (r) and seconds until reset (t). Advisory: describes the fair-use envelope, not a live counter.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Quota policy per draft-ietf-httpapi-ratelimit-headers: q requests per w-second window.","schema":{"type":"string"}}}},"429":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Rate limited. Back off for the number of seconds given in Retry-After, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"default":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Structured JSON error."}},"summary":"List blog posts","tags":["posts"]}},"/api/v1/posts/{slug}":{"get":{"description":"Returns a single blog post by its URL slug, including the full content rendered as Markdown. Slugs come from the listPosts operation.","operationId":"getPostBySlug","parameters":[{"description":"URL slug of the post, e.g. from /api/v1/posts.","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"A blog post including its full content as Markdown.","properties":{"categories":{"description":"Category titles the post is filed under.","items":{"type":"string"},"type":"array"},"description":{"type":["string","null"],"description":"Post intro/summary."},"markdown_url":{"description":"The post as raw Markdown (append .md to the post URL).","format":"uri","type":"string"},"published_at":{"description":"Publication date (ISO 8601).","type":["string","null"]},"slug":{"description":"URL slug of the post.","type":"string"},"title":{"description":"Post title.","type":"string"},"updated_at":{"description":"Last modification timestamp (ISO 8601).","type":"string"},"url":{"description":"Canonical HTML page.","format":"uri","type":"string"},"content_markdown":{"description":"Full post content rendered as Markdown.","type":"string"}},"required":["markdown_url","slug","title","updated_at","url","content_markdown"],"type":"object"}}},"description":"The requested post.","headers":{"RateLimit":{"description":"Current service limit per draft-ietf-httpapi-ratelimit-headers, e.g. remaining quota (r) and seconds until reset (t). Advisory: describes the fair-use envelope, not a live counter.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Quota policy per draft-ietf-httpapi-ratelimit-headers: q requests per w-second window.","schema":{"type":"string"}}}},"404":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"No post exists with that slug."},"429":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Rate limited. Back off for the number of seconds given in Retry-After, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"default":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Structured JSON error."}},"summary":"Get a blog post","tags":["posts"]}},"/api/v1/showcase":{"get":{"description":"Returns every showcase project, newest first, with title, description, dates, and canonical URL.","operationId":"listShowcaseProjects","responses":{"200":{"content":{"application/json":{"schema":{"description":"All showcase projects.","properties":{"count":{"description":"Number of projects returned.","type":"integer"},"projects":{"description":"Every showcase project, newest first.","items":{"description":"A project from the showcase.","properties":{"created_at":{"description":"Project date (ISO 8601).","type":["string","null"]},"description":{"type":["string","null"],"description":"Short project description."},"slug":{"description":"URL slug of the project.","type":"string"},"title":{"description":"Project title.","type":"string"},"updated_at":{"description":"Last modification timestamp (ISO 8601).","type":"string"},"url":{"description":"Canonical HTML page.","format":"uri","type":"string"}},"required":["slug","title","updated_at","url"],"type":"object"},"type":"array"}},"required":["count","projects"],"type":"object"}}},"description":"All showcase projects.","headers":{"RateLimit":{"description":"Current service limit per draft-ietf-httpapi-ratelimit-headers, e.g. remaining quota (r) and seconds until reset (t). Advisory: describes the fair-use envelope, not a live counter.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Quota policy per draft-ietf-httpapi-ratelimit-headers: q requests per w-second window.","schema":{"type":"string"}}}},"429":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Rate limited. Back off for the number of seconds given in Retry-After, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"default":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Structured JSON error."}},"summary":"List showcase projects","tags":["showcase"]}},"/api/v1/site":{"get":{"description":"Returns the profile of the person behind the site — name, role, focus areas, location, contact channels — plus links to every page and machine-readable surface.","operationId":"getSiteProfile","responses":{"200":{"content":{"application/json":{"schema":{"description":"Site and profile metadata with discovery links.","properties":{"contact":{"description":"How to reach the person behind the site.","properties":{"email":{"description":"Preferred contact email.","format":"email","type":"string"},"social":{"description":"Public social profiles.","items":{"description":"A public social profile.","properties":{"title":{"description":"Network or profile name.","type":"string"},"url":{"description":"Profile URL.","format":"uri","type":"string"}},"required":["title","url"],"type":"object"},"type":"array"},"url":{"description":"Contact page.","format":"uri","type":"string"}},"required":["email","social","url"],"type":"object"},"description":{"description":"One-line professional summary.","type":"string"},"focus":{"description":"Engineering focus areas.","items":{"type":"string"},"type":"array"},"handle":{"description":"Public handle used across the web.","type":"string"},"links":{"description":"Canonical HTML pages of the site.","properties":{"about":{"description":"Profile, experience, and education.","format":"uri","type":"string"},"achievements":{"description":"Certifications and programs.","format":"uri","type":"string"},"blog":{"description":"Writing on engineering and tooling.","format":"uri","type":"string"},"developers":{"description":"Developer portal and API docs.","format":"uri","type":"string"},"home":{"description":"Homepage.","format":"uri","type":"string"},"machine_view":{"description":"Plain-text machine view of the site.","format":"uri","type":"string"},"privacy":{"description":"Privacy policy.","format":"uri","type":"string"},"showcase":{"description":"Selected projects and works.","format":"uri","type":"string"}},"required":["about","achievements","blog","developers","home","machine_view","privacy","showcase"],"type":"object"},"location":{"description":"Where the person is based.","type":"string"},"machine_readable":{"description":"Machine-readable discovery surfaces.","properties":{"agent_skills":{"description":"Agent skills discovery index.","format":"uri","type":"string"},"agents_md":{"description":"Agent-ready profile in Markdown.","format":"uri","type":"string"},"api_catalog":{"description":"RFC 9727 API catalog linkset.","format":"uri","type":"string"},"llms_txt":{"description":"Complete site context as Markdown.","format":"uri","type":"string"},"openapi":{"description":"This OpenAPI 3.1 specification.","format":"uri","type":"string"},"sitemap_markdown":{"description":"Semantic sitemap in Markdown.","format":"uri","type":"string"},"sitemap_xml":{"description":"XML sitemap for search engines.","format":"uri","type":"string"}},"required":["agent_skills","agents_md","api_catalog","llms_txt","openapi","sitemap_markdown","sitemap_xml"],"type":"object"},"name":{"description":"Full legal name.","type":"string"},"role":{"description":"Professional role.","type":"string"}},"required":["contact","description","focus","handle","links","location","machine_readable","name","role"],"type":"object"}}},"description":"Site profile.","headers":{"RateLimit":{"description":"Current service limit per draft-ietf-httpapi-ratelimit-headers, e.g. remaining quota (r) and seconds until reset (t). Advisory: describes the fair-use envelope, not a live counter.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Quota policy per draft-ietf-httpapi-ratelimit-headers: q requests per w-second window.","schema":{"type":"string"}}}},"429":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Rate limited. Back off for the number of seconds given in Retry-After, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"default":{"content":{"application/json":{"schema":{"description":"Structured error envelope returned by every non-2xx API response.","properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","examples":["not_found"],"type":"string"},"documentation_url":{"description":"Where the API is documented.","format":"uri","type":"string"},"hint":{"description":"What an agent should try next to recover.","type":"string"},"message":{"description":"Human-readable description of the failure.","type":"string"},"status":{"description":"HTTP status code, mirrored in the body.","type":"integer"}},"required":["code","documentation_url","hint","message","status"],"type":"object"}},"required":["error"],"type":"object"}}},"description":"Structured JSON error."}},"summary":"Get the site profile","tags":["site"]}}},"servers":[{"description":"Production","url":"https://www.pungrumpy.com"}],"tags":[{"description":"Site profile and API discovery.","name":"site"},{"description":"Blog posts, including raw Markdown.","name":"posts"},{"description":"Showcase projects.","name":"showcase"},{"description":"Certifications and developer programs.","name":"achievements"}]}