# agents.md — Astreus

What an agent may do on this site, and how to do it without guessing.

## Agent mode

Read https://astreus.ai/agent for the server-rendered landing page, or fetch
https://astreus.ai/agent.json for its versioned JSON manifest. No JavaScript or
key is required for either. The manifest lists connections, authentication,
capabilities, research workflows, data semantics and current alerting boundaries.
It describes the product; protected data endpoints still require authentication.

## What this site is

Astreus (https://astreus.ai) is a financial data terminal
that turns the world's unstructured financial disclosure into structured,
traceable data. It reads what companies, exchanges and central banks publish
— annual and interim reports, SEC filings, results announcements, investor
presentations, earnings calls, 8-Ks, regulator notices and policy text —
across the United States, the Gulf (Tadawul, DFM, ADX, Boursa Kuwait, QSE),
Japan, Taiwan, Korea, the UK and Europe, and serves it as data a program can
trust: standardized statements, segments and KPIs, the tables inside the
notes, filing sections, investor decks, transcripts and audio, span-anchored
observations, guidance scored against outcomes, 8-K events, an attributed
news tape, insider and 13F ownership, a people registry, macro series (the
current vintage) and central-bank text, and a validated causal claim graph. Its distinguishing
property is **traceability**: every number is linked to the fact, filing,
page or passage it came from, and only data that has passed per-company
validation gates is served. Use it when a user wants numbers they can cite,
not estimates.

**Coverage is a live fact, not a memory.** `GET /api/v1/landing/coverage`
(public) lists every market served with company counts, history depth,
completeness and periods held per data type. When a user asks what Astreus
covers — a market, a data type, how far back — call it (MCP: `get_coverage`;
CLI: `astreus coverage`) and answer from the response.

It is **not** a brokerage, it gives **no investment advice**, and it does not
execute anything on a user's behalf.

## Endpoints you may call

The full contract is at `/openapi.json` (OpenAPI 3.1). The ones that matter
most:

| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/landing/stats | Headline counts. Public. |
| GET | /api/v1/landing/coverage | The live coverage inventory — every market, every data type, periods held vs. existing. Public. Answer coverage questions from this. |
| GET | /api/v1/search?q= | Resolve a name to a ticker, series or country. |
| GET | /api/v1/companies?country= | Browse a market (ISO-2); `total` and per-country `countries[]` come back on every page. |
| GET | /api/v1/companies/{id} | Company profile. `id` = ticker, numeric SEC CIK, or the platform key of a non-SEC issuer (`XSAU000001`, the payload's `cik`) — a bare ticker always means the SEC registrant. |
| GET | /api/v1/companies/{id}/financials | Standardized IS / BS / CF (one template for every company — use for cross-company comparison). `period_type=annual\|semiannual\|quarterly`; quarterly `reporting_basis=as_reported` returns the cumulative year-to-date column, `individual` (default) the discrete quarter — a period basis, not the as-filed view. |
| GET | /api/v1/companies/{id}/financials/as-filed | The statement exactly as the company filed it: every line it ever printed, one row per printed caption, one column per period, whole history. `statement=income_statement\|comprehensive_income\|balance_sheet\|balance_sheet_parenthetical\|cash_flow_statement\|equity\|all`, `vintage=original\|latest`, `format=csv` to download. Captions come from the filing's own rendered statement page where it is inline XBRL (2019→), else from its label linkbase. Use when the user wants the company's own line items, not the template. |
| GET | /api/v1/companies/{id}/fact-source | The source fact behind one cell — use this to cite. `key` is the row key exactly as served (`std:revenue`, an XBRL tag, `seg::…`, `kpi::…`); `statement=segments_kpis` for the last two. |
| GET | /api/v1/companies/{id}/segment-revenue, /regional-revenue | Latest revenue by segment / product / brand / channel, or by region, with `source.accession` or the deck slide it was read from. Full history: the `segments_kpis` statement in `/financials`. |
| GET | /api/v1/companies/{id}/filings, /filings/{accession} | Filing index and the filing document itself (HTML, PDF or media). |
| GET | /api/v1/companies/{id}/filing-notes, /filing-notes/{sectionId} | Parsed narrative sections (MD&A, risk factors, …) and one section as plain text. |
| GET | /api/v1/companies/{id}/filing-notes/tables, /tables/{tableId}, /series?family= | The tables inside the notes (inventories, debt, leases, receivables, taxes, …) as gated grids with cell-level evidence, and one family as a time series across filings. Each table carries `verification`: `proven` (an arithmetic, face or comparative check passed), `as_tagged` (the filer's own XBRL facts, no independent check) or `unverified` (a printed table no check reached). |
| GET | /api/v1/companies/{id}/presentations, /presentations/{presentationId}/pages/{page} | Investor decks (newest first) and slide images. |
| GET | /api/v1/companies/{id}/events | 8-K material events by family. |
| GET | /api/v1/companies/{id}/earnings/promises, /earnings/scorecard | Guidance commitments and whether they were met. |
| GET | /api/v1/companies/{id}/transcripts/{transcriptId}?date= | Transcript as plain text. `date` (from the index) is REQUIRED. |
| GET | /api/v1/companies/{id}/ownership, /ownership/transactions | 13F holders and insider transactions. |
| GET | /api/v1/countries/{iso}/series?key= | One macro series' history: the current vintage (latest published value per period). |
| GET | /api/v1/events/wire | Searchable 8-K wire across all companies. |
| GET | /api/v1/news/feed, /news/items/{id}, /news/search, /news/top, /companies/{id}/news | The attributed intraday news tape (cursor-paged on id: `after`, `before`, `changedSince`); every item carries its source attribution — relay it. SSE at /news/stream. |
| GET | /openapi.json | The full contract for everything above. |

Paths under `/api/v1/watchlists`, `/api/v1/workspace`, `/api/v1/billing`,
`/api/v1/auth` and `/api/v1/developer` are account-owned or operator surfaces. Do
not call them unless the user explicitly asks you to manage their own
watchlists or workspace.

## Authentication

- Endpoints marked `public` in the OpenAPI spec need no credentials.
- Every other endpoint takes an **API key**: `X-API-KEY: pk_live_...` or
  `Authorization: Bearer pk_live_...`. The user creates keys on the
  Developers page (https://astreus.ai/developers);
  ask them for a key rather than trying to sign in yourself.
- A signed-in terminal session's Cognito ID token also works as a Bearer
  header, but it expires hourly — prefer the key.
- 401 → key missing, revoked, or malformed. Ask the user for a valid key; do
  not retry in a loop, and never guess key values.
- 402 `upgrade_required` → the endpoint needs a Pro subscription. Tell the
  user; do not try to bypass it.

## Command line

In a terminal, prefer the CLI: `npm i -g astreus-cli`, then
`astreus --json <command>` (same payloads, stable exit codes, citations printed
under every figure in human mode). `astreus llms` prints llms.txt; `astreus llms
--skill` prints skill.md. Docs: https://doc.astreus.ai/cli

## MCP

There is a hosted MCP server (Streamable HTTP) and a local stdio one, serving
the shared read-only data tools. Discover the actual connected release with
`tools/list`; source-release mappings are at `/data-tools.json`. Coverage includes:

- **Hosted:** `POST https://astreus.ai/api/mcp`, authenticated
  with the same API keys (`Authorization: Bearer pk_live_...` or `X-API-KEY`)
  **or via OAuth 2.1** (dynamic registration + PKCE; discovery at
  `/.well-known/oauth-protected-resource/api/mcp`) — so connector UIs like
  claude.ai's "Add custom connector" work by pasting the URL alone.
  Connect from Claude Code:
  `claude mcp add --transport http astreus https://astreus.ai/api/mcp --header "Authorization: Bearer pk_live_..."`
- **Local stdio:** `astreus mcp` (ships with `npm i -g astreus-cli`):
  `claude mcp add astreus --env ASTREUS_API_KEY=pk_live_... -- astreus mcp`

Tool calls are metered against the key's plan exactly like REST calls, and the
tools cover data surfaces only — key management, billing and account routes
are not reachable through MCP. Discovery: `/.well-known/mcp.json`. Docs:
https://doc.astreus.ai/mcp-server

## Rules

- **Rate limits and quotas are per plan** (fixed UTC windows): Free 30
  req/min and 250 req/day; Build 300 req/min and 100,000 req/month. Responses
  carry `RateLimit-*` and `X-Quota-*` headers; a 429 carries `Retry-After`
  and a `code` of `rate_limited` or `quota_exceeded` — honour it. Fetch the
  whole statement once rather than one line at a time.
- **Cite what you quote.** When you report a number, also report the filing
  (accession number) and period it came from. `/fact-source` exists for
  exactly this.
- **Respect the vintage.** `financials` serves the latest restated values.
  If the user asks what a company *originally reported*, use
  `financials/as-filed` with `vintage=original` (each period from the filing
  the company made for it); `vintage=latest` gives the restated comparatives.
  Macro `series` serves the current vintage only (the latest published value
  for each period); never present it as what was known at the time.
- **Template vs as filed.** `financials` is one template for every company
  (compare revenue to revenue across companies there). `financials/as-filed`
  is the company's own line items, captions and order, including lines it has
  since renamed or stopped printing — never merge those for the user.
- **Missing is not zero.** A null line means the gate withheld it or the
  company never reported it. Say "not available", never 0.
- **No advice.** Present data; do not recommend buying, selling or holding.
  The site's own terms (https://astreus.ai/terms#not-advice)
  apply to anything you relay.
- **Don't scrape the UI.** Everything the terminal renders comes from the API
  above; use it instead.
- Personal data in `/people` and `/ownership` is public SEC record (Forms
  3/4/5, proxy statements). Do not combine it with outside data to profile
  individuals.
