Files
worldmonitor/public/.well-known/agent-skills/fetch-country-brief/SKILL.md
Elie Habib def94733a8 feat(agent-readiness): Agent Skills discovery index (#3310) (#3355)
* feat(agent-readiness): Agent Skills discovery index (#3310)

Closes #3310. Ships the Agent Skills Discovery v0.2.0 manifest at
/.well-known/agent-skills/index.json plus two real, useful skills.

Skills are grounded in real sebuf proto RPCs:
- fetch-country-brief → GetCountryIntelBrief (public).
- fetch-resilience-score → GetResilienceScore (Pro / API key).

Each SKILL.md documents endpoint, auth, parameters, response shape,
worked curl, errors, and when not to use the skill.

scripts/build-agent-skills-index.mjs walks every
public/.well-known/agent-skills/<name>/SKILL.md, sha256s the bytes,
and emits index.json. Wired into prebuild + every variant build so a
deploy can never ship an index whose digests disagree with served files.

tests/agent-skills-index.test.mjs asserts the index is up-to-date
via the script's --check mode and recomputes every sha256 against
the on-disk SKILL.md bytes.

Discovery wiring:
- public/.well-known/api-catalog: new anchor entry with the
  agent-skills-index rel per RFC 9727 linkset shape.
- vercel.json: adds agent-skills-index rel to the homepage +
  /index.html Link headers; deploy-config required-rels list updated.

Canonical URLs use the apex (worldmonitor.app) since #3322 fixed
the apex redirect that previously hid .well-known paths.

* fix(agent-readiness): correct auth header + harden frontmatter parser (#3310)

Addresses review findings on #3310.

## P1 — auth header was wrong in both SKILL.md files

The published skills documented `Authorization: Bearer wm_live_...`,
but WorldMonitor API keys must be sent in `X-WorldMonitor-Key`.
`Authorization: Bearer` is for MCP/OAuth or Clerk JWTs — not raw
`wm_live_...` keys. Agents that followed the SKILL.md verbatim would
have gotten 401s despite holding valid keys.

fetch-country-brief also incorrectly claimed the endpoint was
"public"; server-to-server callers without a trusted browser origin
are rejected by `validateApiKey`, so agents do need a key there too.
Fixed both SKILL.md files to document `X-WorldMonitor-Key` and
cross-link docs/usage-auth as the canonical auth matrix.

## P2 — frontmatter parser brittleness

The hand-rolled parser used `indexOf('\n---', 4)` as the closing
fence, which matched any body line that happened to start with `---`.
Swapped for a regex that anchors the fence to its own line, and
delegated value parsing to js-yaml (already a project dep) so future
catalog growth (quoted colons, typed values, arrays) does not trip
new edge cases.

Added parser-contract tests that lock in the new semantics:
body `---` does not terminate the block, values with colons survive
intact, non-mapping frontmatter throws, and no-frontmatter files
return an empty mapping.

Index.json rebuilt against the updated SKILL.md bytes.
2026-04-23 22:21:25 +04:00

2.9 KiB

name, version, description
name version description
fetch-country-brief 1 Retrieve the current AI-generated strategic intelligence brief for a country, keyed by ISO 3166-1 alpha-2 code.

fetch-country-brief

Use this skill when the user asks for a summary of the current geopolitical, economic, or security situation in a specific country. The endpoint returns a fresh AI-generated brief composed from the latest news, market, conflict, and infrastructure signals World Monitor tracks for that country.

Authentication

Server-to-server callers (agents, scripts, SDKs) MUST present an API key in the X-WorldMonitor-Key header. Authorization: Bearer … is for MCP/OAuth or Clerk JWTs — not raw API keys.

X-WorldMonitor-Key: wm_live_...

Browser requests from worldmonitor.app get a free pass via CORS Origin trust, but agents will never hit that path. Issue a key at https://www.worldmonitor.app/pro.

Endpoint

GET https://api.worldmonitor.app/api/intelligence/v1/get-country-intel-brief

Parameters

Name In Required Shape Notes
country_code query yes ISO 3166-1 alpha-2, uppercase (e.g. US, IR, KE) Case-sensitive server-side. Lowercase is rejected with 400.
framework query no free text, ≤ 2000 chars Optional analytical framing appended to the system prompt (e.g. "focus on energy security").

Response shape

{
  "countryCode": "IR",
  "countryName": "Iran",
  "brief": "Multi-paragraph AI-generated brief …",
  "model": "gpt-4o-mini",
  "generatedAt": 1745421600000
}

generatedAt is Unix epoch milliseconds. model identifies which LLM produced the text.

Worked example

curl -s -H "X-WorldMonitor-Key: $WM_API_KEY" \
  'https://api.worldmonitor.app/api/intelligence/v1/get-country-intel-brief?country_code=IR' \
  | jq -r '.brief'

With an analytical framework:

curl -s --get -H "X-WorldMonitor-Key: $WM_API_KEY" \
  'https://api.worldmonitor.app/api/intelligence/v1/get-country-intel-brief' \
  --data-urlencode 'country_code=TR' \
  --data-urlencode 'framework=focus on energy corridors and Black Sea shipping'

Errors

  • 400country_code missing, not 2 letters, or not uppercase.
  • 401 — missing X-WorldMonitor-Key (server-to-server callers).
  • 429 — rate limited; retry with backoff.
  • 5xx — transient upstream model failure; retry once after 2s.

When NOT to use

  • For rankings or comparisons across countries, use fetch-resilience-score per country and aggregate client-side, or call the GetResilienceRanking RPC directly.
  • For raw news events rather than synthesized narrative, use SearchGdeltDocuments (/api/intelligence/v1/search-gdelt-documents).

References