The context layer for your GitHub org
One API turns your whole GitHub organization into structured, LLM-ready context — ownership, dependency graph, contributor expertise, PR & review context, semantic retrieval, and activity. Call it directly, or connect the official MCP server and any agent gets it as native tools.
Overview
Every endpoint is scoped to your organization, derived from your API key and GitHub App install — you never pass an org id. Read endpoints return pre-computed, relationship-aware context; webhooks push updates to you in real time.
| Value | |
|---|---|
| Base URL | https://eos.dev/api/v1 |
| Auth | Bearer API key (eos_…) |
| Format | JSON · { data, meta } |
| Versioning | X-EOS-API-Version: 1 (additive only) |
Quickstart
Three steps from zero to your first context call:
1. Install the EOS GitHub App on the repos you want context for — every surface is scoped to what the App can see. 2. Create an API key in Settings → API (pick the scopes you need). 3. Call the API:
curl "https://eos.dev/api/v1/context/ownership?repo=acme/app&path=services/auth" \
-H "Authorization: Bearer eos_your_key_here"Or with the TypeScript SDK:
import { EosClient } from "@eos-ai/sdk";
const eos = new EosClient({ apiKey: process.env.EOS_API_KEY });
const { data } = await eos.context.ownership({ repo: "acme/app", path: "services/auth" });
console.log(data[0].handle, data[0].score); // "alex.kim" 912.4Authentication & scopes
Pass your key as a Bearer token on every request. Any org member can create a key from Settings → API in the console; manage, rotate and revoke them there. A key is scoped to the organization it was minted for and only grants the scopes you select — pick the least it needs.
Keys & the GitHub App. Context is only available for repositories the EOS GitHub App can see. A key inherits that install’s scope — it can read context for those repos and nothing else. Install or adjust repository access from the console at any time.
Authorization: Bearer eos_xxxxxxxxxxxxxxxxxxxxxxxx| Scope | Grants |
|---|---|
| read:context | All context surfaces: ownership & expertise, architecture & dependency graph, contributors, PR & review context, and activity/hotspots. |
| read:search | Retrieval over your org's own history (POST /context/search) — LLM-ready chunks with citations. |
| read:sql | Read-only SQL over your workspace's own data (POST /context/query) — the curated api.* views. |
The console authenticates by session cookie instead of a key; both resolve to the same org-scoped access.
Limits & usage
The unit is one context request (one API call or one MCP tool call). Every plan gets the full API surface — tiers gate volume, not endpoints. Two limits apply in parallel: a short-window rate limit (hour + day) that protects the service, and a monthly quota. Every response carries both, so a client (or an agent) can pace itself:
X-RateLimit-Limit: 100 # daily request cap for your plan
X-RateLimit-Remaining: 98
X-RateLimit-Reset: 34200 # seconds until the daily window resets (midnight UTC)
X-EOS-Quota-Limit: 5000 # monthly context-request quota
X-EOS-Quota-Used: 1287
X-EOS-Quota-Remaining: 3713
X-EOS-Quota-Warning: 80 # only present at 80% / 100% of the monthly quotaRequests allowed per plan:
| Plan | Per hour | Per day | Per month |
|---|---|---|---|
| Free | 60 | 100 | 5,000 |
| Starter | 200 | 1,000 | Unlimited |
| Pro | 2,000 | 10,000 | Unlimited |
| Enterprise | Unlimited | Unlimited | Unlimited |
The Free tier includes the full API surface and the MCP server. Semantic retrieval and synthesis are powered internally by Claude — folded into pricing, never a separate credit SKU. Exceeding a limit returns 429 with a Retry-After header; the daily limit resets at midnight UTC and the hourly at the top of the hour.
Responses & errors
Successful responses use a { data, meta } envelope. data is the surface’s result (an array for list surfaces, an object for the graph); meta carries result counts, timestamps, and per-surface context. For data freshness, call /context/freshness.
{
"data": [ /* … the surface's result … */ ],
"meta": { "total": 2, "generated_at": "2026-07-30T12:00:00Z" }
}Errors return { error, code }. Branch on code (stable), not the message:
| code | Meaning |
|---|---|
| invalid_request | A query/body parameter failed validation (HTTP 400). |
| unauthorized | Missing or invalid API key (HTTP 401). |
| forbidden_scope | The key lacks the scope the endpoint requires (HTTP 403). |
| plan_upgrade_required | The endpoint requires a higher plan than the key's workspace has (HTTP 403). |
| rate_limited | Rate limit or monthly quota exceeded — see Retry-After (HTTP 429). |
| not_found | The requested resource doesn't exist (HTTP 404). |
| internal | Unexpected server error (HTTP 500). |
Ownership & expertise
Who owns or knows any file, module, or system — computed from real contribution history, not CODEOWNERS. The answer to “who should review this?” and “who knows auth?”
GET /api/v1/context/ownership?repo=acme/app&path=services/auth
{
"data": [
{ "handle": "alex.kim", "score": 912.4, "commits": 312, "recent_commits": 41,
"files_touched": 18, "lines_changed": 8730, "last_committed": "2026-07-28T09:12:00Z" },
{ "handle": "ren.park", "score": 104.2, "commits": 47, "recent_commits": 3,
"files_touched": 9, "lines_changed": 1210, "last_committed": "2026-05-02T14:03:00Z" }
],
"meta": {
"repo": "acme/app", "path": "services/auth", "total": 2, "weighting": "recency_churn",
"knowledge_concentration": { "top_owner": "alex.kim", "top_owner_share": 0.898, "single_owner_risk": true }
}
}Architecture & dependency graph
A structural map of the org — repos, modules, inter-file dependencies, and coupling (files that change together). The same graph your agents retrieve and the console visualizes.
GET /api/v1/context/graph?repo=acme/app
{
"data": {
"nodes": [
{ "id": "services/auth", "commits": 210, "file_count": 34 },
{ "id": "lib/db", "commits": 168, "file_count": 22 }
],
"edges": [
{ "source": "services/auth", "target": "lib/db", "shared_commits": 41 }
]
},
"meta": { "plan": "pro", "repo": "acme/app", "node_count": 2, "edge_count": 1,
"module_total": 2, "truncated": false, "generated_at": "2026-07-30T12:00:00Z" }
}Contributor context
Per-person expertise areas, activity footprint, and review history — so an agent can route work to the right human.
GET /api/v1/context/contributors/alex.kim
{
"data": {
"handle": "alex.kim",
"period_days": 180, "merged_prs": 63, "open_prs": 2,
"avg_cycle_time_hours": 18.4, "lines_changed": 24100,
"expertise": [
{ "repo": "acme/api", "commits": 312 },
{ "repo": "acme/app", "commits": 96 }
],
"recent_prs": [
{ "title": "Rotate refresh tokens", "repo": "acme/api", "merged_at": "2026-07-27T14:03:00Z" }
]
}
}PR & review context
The review graph: who reviews what, turnaround, and related past PRs — plus scored reviewer suggestions with citations.
GET /api/v1/context/pulls/482/reviewers?repo=acme/api
{
"data": {
"pr": { "repo": "acme/api", "number": 482, "title": "Add rate limiting", "author": "dan" },
"suggested_reviewers": [
{ "github_handle": "sam.lee", "display_name": "Sam Lee", "score": 0.82,
"reason": "5 PRs merged in this repo, no open PRs, 4 merged in the last 30d",
"signals": { "repo_prs": 5, "wip": 0, "merged_30d": 4 } }
],
"primary": "sam.lee"
},
"meta": { "plan": "pro", "count": 1 }
}Org retrieval
Natural-language retrieval over your organization's own history — the decisions, pull requests and people behind the code, with citations. Retrieval that models the organization, not the source tree.
Not code search. Finding the function that does X is served better by tools built for it, and EOS is the context layer those tools read from rather than a competitor to them.
POST /api/v1/context/search
{ "query": "how does auth refresh work", "limit": 5 }
{
"data": {
"query": "how does auth refresh work",
"results": [
{ "id": "node_8f2…", "node_type": "file", "score": 0.91,
"content": "Refresh-token rotation in session.ts …",
"related_repos": ["acme/api"], "related_developers": ["alex.kim"],
"created_at": "2026-07-20T10:00:00Z" }
],
"conversations": [],
"citations": [
{ "ref": "code:file:acme/api:services/auth/session.ts", "type": "file",
"id": "node_8f2…", "kind": "file", "repos": ["acme/api"], "score": 0.91 }
],
"total": 1
},
"meta": { "request_id": "req_a1b2", "took_ms": 142, "cached": false }
}Activity & hotspots
Where change is concentrated right now — hotspots, churn, and what's moving across the org.
GET /api/v1/context/activity?repo=acme/app&days=7
{
"data": [
{ "path": "services/auth/session.ts", "file": "session.ts", "module": "services/auth",
"commits": 23, "author_count": 4, "intensity": "high",
"summary": "session.ts changed 23× by 4 authors in the last 7d" }
],
"meta": { "plan": "pro", "repo": "acme/app", "period_days": 7, "count": 1,
"file_count": 991, "truncated": false, "generated_at": "2026-07-30T12:00:00Z" }
}SQL query
Run read-only SQL over your own workspace data — pull requests, commits, repos, developers, Linear issues, and CI runs — when the fixed endpoints don't match the exact shape you need. Every view is already scoped to your workspace; there's no workspace_id to pass or filter on. Pro plan and up.
Only a single SELECT (or WITH … SELECT) is allowed. Results are capped at limit rows (default 1000) and queries time out at ~8s. Call GET /context/query/schema for the exact views and columns. Pass "format": "csv" to get a CSV download instead of JSON (row count and truncation are returned in the X-EOS-Row-Count / X-EOS-Truncated headers). Hit the row cap? Page with keyset in your SQL — e.g. … where id > $last order by id limit 1000.
POST /api/v1/context/query
{ "sql": "select repo, count(*) as prs from pull_requests where state = 'merged' group by 1 order by 2 desc", "limit": 100 }
{
"data": [
{ "repo": "acme/api", "prs": 128 },
{ "repo": "acme/web", "prs": 74 }
],
"meta": { "plan": "pro", "row_count": 2, "truncated": false, "limit": 100,
"generated_at": "2026-08-03T12:00:00Z" }
}Webhooks
Subscribe an https endpoint and EOS pushes events as they happen — so your agents always call fresh context without polling. Manage subscriptions in Settings → API (Pro+). The signing secret is shown once.
| Event | Fires when |
|---|---|
| context.updated | Any context surface for a path was recomputed after a change. |
| ownership.changed | The owner or backup owner of a file or module changed. |
| graph.changed | Dependencies or coupling for a module changed. |
| contributor.updated | A contributor's expertise or activity footprint shifted. |
| pull.reviewed / pull.merged | A pull request was reviewed or merged. |
| reindex.completed | A repository finished (re)indexing — its context is now fresh. |
Each delivery is a signed POST. Verify X-EOS-Signature (HMAC-SHA256 of the raw body) before trusting it:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(header), b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Payloads carry a stable id (the idempotency key), api_version, and are retried up to 3× with backoff.
SDK
The TypeScript SDK wraps every context surface with types. Install @eos-ai/sdk:
import { EosClient } from "@eos-ai/sdk";
const eos = new EosClient({ apiKey: process.env.EOS_API_KEY });
await eos.context.ownership({ repo: "acme/api", path: "services/auth" });
await eos.context.graph({ repo: "acme/api" });
await eos.context.contributor("alex.kim");
await eos.context.reviewers(482, { repo: "acme/api" });
await eos.context.search({ query: "how does auth refresh work" });MCP — for AI agents
Run the official EOS MCP server so any MCP-compatible agent (Claude Desktop, Cursor, Windsurf) gets your org as native tools — zero glue code. It exposes get_ownership, get_graph, get_contributors, suggest_reviewers, search_context and more.
{
"mcpServers": {
"eos": {
"command": "npx",
"args": ["-y", "@eos-ai/mcp-server"],
"env": { "EOS_API_KEY": "eos_your_key_here" }
}
}
}Looking for the raw machine-readable spec? The full OpenAPI document is at /api/docs.