Ershu API
Ershu API is the HTTP backend for the Ershu web application and other HTTP clients. It is intended for people who operate Ershu and contributors working on its web boundary. The service handles account setup and login, project access, analysis run control, documents, search, chat, administration, browser sessions, and streamed responses.
Repository analysis runs in Ershu Worker. This service queues and controls that work, then serves the stored results. It does not import Worker or MCP code.
What the API owns
| Area | Responsibility |
|---|---|
| Authentication | Initial administrator setup, OPAQUE login, access and refresh tokens, session cookies, logout, and login rate limiting |
| Browser security | CORS, origin checks, CSRF protection, production HTTPS checks, and proxy header handling |
| Projects | Projects, repositories, members, groups, directory groups, grants, repository credentials, and access rules |
| Analysis runs | Create, list, cancel, retry, resume, and follow up on runs; read snapshots, usage, final results, and event streams |
| Documents and context | Document views, imports and exports, project context, code context, graph queries, and search |
| Chat | Private project chat sessions, streamed answers, and source citations |
| Administration | Users, audit logs, model channels, dependency sources, vault credentials, system settings, and maintenance operations |
| Repository triggers | Signed webhooks and a separate scheduled polling process |
The API can rebuild search entries from data already stored in Ershu and expose maintenance operations. Ershu Worker owns repository analysis and the generation of project documents, code facts, and knowledge relationships.
Where it fits
Frontend and HTTP clients
|
v
Ershu API --------------> PostgreSQL
| Redis
| Milvus
|
+---- queued runs ---> Ershu Worker
Ershu MCP uses shared Core services and storage. MCP traffic does not pass
through Ershu API.
| Component | Relationship to this repository |
|---|---|
ershu-core |
Required Python package for shared data models, permissions, queries, queue state, and database migrations |
ershu-worker |
Consumes queued runs and performs repository analysis and generation work |
ershu-mcp |
Publishes project context tools through shared Core services; it is not an API route |
frontend |
Uses the public HTTP, cookie, CSRF, and streaming contracts from this service |
ershu |
Deployment repository that pins compatible component versions and runs the complete system |
Each component is released independently. The deployment repository selects the exact set of component versions used together.
Install and commands
| Item | Value |
|---|---|
| Python distribution | ershu-api |
| Python requirement | Python 3.14 or newer |
| HTTP service | ershu-api |
| Scheduled repository poller | ershu-api-poller |
| Database migration command | ershu-db, provided by ershu-core |
| API prefix | /api/v1 |
Install the API as part of a tested component set through the
ershu installer package:
pip install "ershu[api]"
Projects that depend on the API package directly can pin the component with UV:
uv add "ershu-api==1.0.0.post20260812"
Requirements
Development requires:
- Python 3.14 or newer
- UV
- A compatible
ershu-corerelease
Running the service also requires PostgreSQL, Redis, and Milvus. PostgreSQL stores application state, Redis backs login rate limiting and the poller lease, and Milvus holds vectors used by semantic search.
Run from source
Install the locked runtime dependencies:
uv sync --locked
Copy .env.example to .env. Generate three independent values for SECRET_KEY, ENCRYPTION_KEY, and MCP_KEY_PEPPER:
uv run python -c "import secrets; print(*(secrets.token_urlsafe(48) for _ in range(3)), sep='\n')"
Use one output line for each setting. Do not reuse a value. The example placeholders are rejected at startup, and .env must not be committed.
Start PostgreSQL, Redis, and Milvus, then apply the database migrations:
uv run ershu-db upgrade head
Start the API:
uv run ershu-api
The development server listens on 127.0.0.1:8000 by default and reloads when source files change. OpenAPI pages are available only in development:
http://127.0.0.1:8000/docshttp://127.0.0.1:8000/redoc
Health checks
The root and versioned health endpoints report whether the HTTP process can respond:
curl -fsS http://127.0.0.1:8000/health
curl -fsS http://127.0.0.1:8000/api/v1/health
Both return {"status":"ok"}. Check PostgreSQL and Milvus separately:
curl -fsS http://127.0.0.1:8000/api/v1/health/dependencies
The dependency response is degraded when either check fails. It does not test Redis.
Configuration
The service reads .env from its working directory. .env.example lists the supported deployment settings.
| Group | Settings | Purpose |
|---|---|---|
| Runtime | ENVIRONMENT, LOG_LEVEL, HOST, PORT |
Runtime mode, logging, and listener address |
| Data services | DATABASE_URL, database pool settings, REDIS_URL, MILVUS_URI, MILVUS_TOKEN, MILVUS_DB_NAME |
Application state, rate limiting, polling lease, and vector search |
| Service secrets | SECRET_KEY, ENCRYPTION_KEY, MCP_KEY_PEPPER |
Sessions, encrypted stored credentials, and MCP key hashing |
| Browser sessions | token lifetimes, cookie names, SESSION_COOKIE_SECURE, SESSION_COOKIE_SAMESITE, CORS_ORIGINS |
Login state and browser request policy |
| Reverse proxy | PROXY_HEADERS, FORWARDED_ALLOW_IPS |
Forwarded scheme and client information from trusted proxies |
| Repository access | repository cache path, trusted local paths, Git host and protocol controls, provider tokens | Repository checkout and context access |
| Scheduled polling | POLLER_INTERVAL_SECONDS, POLLER_LEASE_SECONDS, POLLER_BATCH_SIZE |
Poll frequency, ownership lease, and batch size |
| Maintenance and search | run lease, retention count, and search batch size | Queue recovery, retained history, and index maintenance |
LLM, embedding, and reranker channels are managed through the administration endpoints. Their API keys are encrypted before storage and do not belong in .env.
Some non-secret operational settings can be overridden in the database through the system settings endpoints. Environment values remain the startup defaults.
OPAQUE server setup
Development can leave OPAQUE_SERVER_SETUP empty. On first startup, the API creates an OPAQUE server setup and stores it encrypted in PostgreSQL.
Production requires an explicit, stable value. Generate it once:
uv run python -c "import base64, opaque_ke_py; print(base64.urlsafe_b64encode(opaque_ke_py.server_setup().to_bytes()).decode('ascii').rstrip('='))"
Store the output in the deployment secret store. Changing this value prevents existing OPAQUE password records from being used.
Repository polling
Repositories with polling enabled need a separate long-running process:
uv run ershu-api-poller
Cron expressions use UTC. Poller instances coordinate through a renewable Redis lease, so more than one instance can run without processing the same schedule at once. A single cycle can be run manually:
uv run ershu-api-poller --once
The API and poller must use the same PostgreSQL database, Redis instance, and encryption settings. The poller detects revisions and queues refresh runs. A running Worker is still required to process them.
Repository webhooks
Repository webhooks use HMAC-SHA256 over this byte sequence:
timestamp + NUL + nonce + NUL + raw request body
Send the lowercase hexadecimal digest in X-Ershu-Webhook-Signature, the Unix timestamp in X-Ershu-Webhook-Timestamp, and a unique nonce in X-Ershu-Webhook-Nonce. The timestamp must be within five minutes of the server clock. The exact raw body used to compute the signature must be sent unchanged.
The webhook endpoint is under /api/v1/webhooks/repositories/{repository_id}. A valid webhook queues work; it does not run repository analysis inside the request.
Production checklist
- Set
ENVIRONMENT=productionandSESSION_COOKIE_SECURE=true. - Keep
SECRET_KEY,ENCRYPTION_KEY,MCP_KEY_PEPPER, andOPAQUE_SERVER_SETUPin a secret store. Use different, stable values. - Terminate TLS at the service or a trusted reverse proxy. Production API requests over plain HTTP are rejected.
- Limit
FORWARDED_ALLOW_IPSto the actual proxy addresses and pass the external host and scheme correctly. - Add only the real frontend origins to
CORS_ORIGINS. - Keep
ALLOW_DEV_OPEN_LOCAL_REPOSITORY_PATHS=false. - Route
/api/v1/to this service. Route/mcp/to Ershu MCP, not to Ershu API.
The API rejects weak or reused service secrets at startup. The development OpenAPI pages are disabled in production.
Development
Install the development dependencies:
uv sync --extra dev --locked
Run the repository checks:
uv run --extra dev pytest -q
uv run --extra dev ruff check src tests
uv run --extra dev ruff format --check src tests
uv build --wheel --out-dir dist
The test suite uses temporary SQLite databases and replaces external services, so it does not require live PostgreSQL, Redis, or Milvus instances.
Repository layout
| Path | Purpose |
|---|---|
src/ershu/api_main.py |
FastAPI application, middleware, lifecycle, and HTTP runner |
src/ershu/api/router.py |
Route registration under /api/v1 |
src/ershu/api/routes/ |
HTTP routes grouped by domain |
src/ershu/api/schemas/ |
API request and response models |
src/ershu/api/services/ |
API-specific orchestration |
src/ershu/api/runtime_settings.py |
API settings and runtime validation |
src/ershu/api/poller.py |
Scheduled repository polling process |
tests/ |
Route, permission, security, streaming, and maintenance tests |
Changes to HTTP requests, responses, errors, cookies, CSRF behavior, or stream
events can affect the frontend and other clients. Changes to shared data,
permissions, or query behavior belong in ershu-core; analysis and generation
changes belong in ershu-worker; MCP tool changes belong in ershu-mcp.
License
Ershu API is licensed under the Apache License 2.0.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ershu_api-1.0.0.post20260812.tar.gz.
File metadata
- Download URL: ershu_api-1.0.0.post20260812.tar.gz
- Upload date:
- Size: 126.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68cc534dcf6d460ced084a3622b2481c356ed5487c33eb098982e4077ef27aea
|
|
| MD5 |
3a6fdea6e60a66d0dcba06fa7b087dfa
|
|
| BLAKE2b-256 |
3fb56f2684300df99eaf6cfd0ee15f919078ec7cadb169e91eaca5804dea8ae9
|
File details
Details for the file ershu_api-1.0.0.post20260812-py3-none-any.whl.
File metadata
- Download URL: ershu_api-1.0.0.post20260812-py3-none-any.whl
- Upload date:
- Size: 176.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5f17d0fb830209b28f11c59e840608fc95c71b010dd7bad1ae77284727408a9
|
|
| MD5 |
abfd6fdf61813c9ad7f3e928339b8b69
|
|
| BLAKE2b-256 |
7a011249f3bfbd816acaafe213b3c0c8aaaa439c3d165d859566e1cc86337fb0
|