aegra

Deploys AI chatbots and agents to production with memory, security, and monitoring built in.

Installation
Run `npx skills add "https://docs.aegra.dev" --skill "aegra"` to install this skill, then follow its SKILL.md instructions for my next request.

Paste this into Claude Code, Cursor, or any agent that can run commands.

SKILL.mdShow the author's original SKILL.md
---
name: aegra
description: Use when deploying, configuring, or managing self-hosted LangGraph
  agent servers. Reach for this skill when building agent infrastructure,
  setting up authentication, managing threads and state, streaming agent
  responses, scheduling cron jobs, or deploying to Docker, PaaS, or Kubernetes.
metadata:
  mintlify-proj: aegra
  version: "1.0"
---

# Aegra Skill

## Product summary

Aegra is an open-source, self-hosted Agent Protocol server for running LangGraph agents on your own infrastructure. It's a drop-in replacement for LangSmith Deployments with the same SDK and APIs but full control over your data. Agents run in threads with persistent state, support streaming, human-in-the-loop interrupts, scheduled cron jobs, semantic storage, and custom authentication. Key files: `aegra.json` (configuration), `.env` (environment variables), `Dockerfile` (container image). CLI commands: `aegra init` (create project), `aegra dev` (local development), `aegra serve` (production), `aegra up` (Docker stack). Primary docs: https://docs.aegra.dev

## When to use

Use this skill when:
- **Setting up a new Aegra project** — initializing with templates, configuring graphs, environment variables
- **Configuring authentication** — adding JWT, OAuth, Firebase, or custom auth handlers
- **Managing agent execution** — creating threads, running agents, streaming responses, handling interrupts
- **Persisting state** — working with checkpoints, thread history, resuming from checkpoints
- **Scheduling tasks** — creating cron jobs with timezone support, managing recurring runs
- **Storing data** — using key-value store or semantic search with vector embeddings
- **Deploying to production** — Docker, PaaS (Railway, Render, Fly.io), Kubernetes, or bare metal
- **Observability** — configuring tracing to Langfuse, Phoenix, or OTLP backends
- **Troubleshooting** — debugging connection issues, migrations, health checks, worker crashes

## Quick reference

### CLI commands

| Command | Purpose | When to use |
|---------|---------|------------|
| `aegra init` | Create new project | Starting a new agent project |
| `aegra dev` | Local dev server | Development with hot reload |
| `aegra serve` | Production server | PaaS, containers, bare metal |
| `aegra up` | Docker stack | Self-hosted production with Docker |
| `aegra down` | Stop services | Stopping Docker containers |
| `aegra db upgrade` | Apply migrations | Multi-pod deployments before rolling |

### Configuration file (aegra.json)

```json
{
  "graphs": {
    "agent": "./src/agent/graph.py:graph"
  },
  "auth": {
    "path": "./auth.py:auth"
  },
  "http": {
    "app": "./routes.py:app",
    "cors": {
      "allow_origins": ["https://example.com"]
    }
  },
  "store": {
    "index": {
      "dims": 1536,
      "embed": "openai:text-embedding-3-small"
    }
  },
  "checkpointer": {
    "durability": "async"
  }
}
```

### Key environment variables

| Variable | Purpose | Example |
|----------|---------|---------|
| `DATABASE_URL` | PostgreSQL connection | `postgresql://user:pass@host/db` |
| `REDIS_BROKER_ENABLED` | Enable worker queue | `true` (production) or `false` (dev) |
| `REDIS_URL` | Redis connection | `redis://host:6379/0` |
| `OPENAI_API_KEY` | LLM API key | `sk-...` |
| `AEGRA_CONFIG` | Config file path | `production.json` |
| `CRON_ENABLED` | Enable scheduler | `true` (default) |
| `OTEL_TARGETS` | Tracing backends | `LANGFUSE,PHOENIX` |

### Core API patterns

**Create and stream a run:**
```python
async for chunk in client.runs.stream(
    thread_id=thread_id,
    assistant_id="agent",
    input={"messages": [{"type": "human", "content": "Hello"}]},
    stream_mode=["values"]
):
    print(chunk)
```

**Create a thread:**
```python
thread = await client.threads.create(
    metadata={"user_id": "alice"}
)
```

**Get thread state:**
```python
state = await client.threads.get_state(thread_id)
print(state["values"])  # Current state
print(state["next"])    # Next nodes to execute
```

**Resume from interrupt:**
```python
async for chunk in client.runs.stream(
    thread_id=thread_id,
    assistant_id="agent",
    command={"resume": [{"type": "accept"}]}
):
    print(chunk)
```

**Create a cron job:**
```python
cron = await client.crons.create(
    assistant_id="agent",
    schedule="0 9 * * *",  # 09:00 UTC daily
    input={"messages": [{"role": "user", "content": "Report"}]},
    timezone="America/New_York"
)
```

**Store data:**
```python
await client.store.put_item(
    namespace=["users", "alice", "prefs"],
    key="theme",
    value={"color": "dark"}
)
```

## Decision guidance

### When to use each deployment command

| Scenario | Command | Why |
|----------|---------|-----|
| Local development | `aegra dev` | Hot reload, managed PostgreSQL, no Redis needed |
| Self-hosted Docker | `aegra up` | Full stack (PostgreSQL + Redis + app) in containers |
| PaaS (Railway, Render) | `aegra serve` | Bring your own database, no Docker management |
| Kubernetes | `aegra serve` in pod spec | Stateless, works with managed databases |
| Single-instance production | `aegra serve` + `REDIS_BROKER_ENABLED=false` | Simpler, in-process asyncio tasks |
| Multi-instance production | `aegra serve` + `REDIS_BROKER_ENABLED=true` | Shared Redis for job queue and SSE |

### When to use each stream mode

| Mode | Use when |
|------|----------|
| `values` | You need full state snapshots after each node |
| `updates` | You only want state deltas (smaller payloads) |
| `messages` | You're building a chat UI (token-by-token output) |
| `custom` | You emit custom data from inside graph nodes |
| `events` | You need fine-grained LangGraph internal events |

### When to use checkpoint durability

| Mode | Use when |
|------|----------|
| `sync` | You need guaranteed recovery from the last completed step |
| `async` (default) | You want background checkpointing while execution continues |
| `exit` | You have high-volume runs that never use time travel or mid-run recovery |

### When to use stateless vs thread-bound crons

| Type | Use when |
|------|----------|
| Stateless cron | Each run is independent (daily reports, batch jobs) |
| Thread-bound cron | Runs continue the same conversation (weekly digests, recurring tasks) |

## Workflow

### 1. Set up a new Aegra project

1. Install CLI: `pip install aegra-cli`
2. Create project: `aegra init` (choose template: `simple-chatbot` or `react-agent`)
3. Navigate to project: `cd <project-name>`
4. Copy env file: `cp .env.example .env`
5. Add API keys to `.env` (e.g., `OPENAI_API_KEY`)
6. Start dev server: `uv sync && uv run aegra dev`
7. Visit `http://localhost:2026/docs` to explore API

### 2. Create and run an agent

1. Define your graph in Python (LangGraph StateGraph)
2. Register in `aegra.json` under `graphs`
3. Aegra auto-creates a default assistant for each graph
4. Create a thread: `thread = await client.threads.create()`
5. Stream a run: `async for chunk in client.runs.stream(thread_id=..., assistant_id="agent", input=...)`
6. Check thread state: `state = await client.threads.get_state(thread_id)`

### 3. Add human-in-the-loop approval

1. In your graph, call `interrupt()` at decision points with a payload
2. Client receives interrupt and thread status becomes `"interrupted"`
3. User reviews the payload and decides (approve, edit, respond, ignore)
4. Resume with `command={"resume": [{"type": "accept"}]}` or other action
5. Run continues from the interrupt point

### 4. Set up authentication

1. Create auth handler file (e.g., `auth.py`) with `@auth.on` decorators
2. Register in `aegra.json`: `"auth": {"path": "./auth.py:auth"}`
3. Handlers intercept requests and can filter/deny based on user identity
4. Threads and store data are automatically scoped to authenticated user
5. Restart server to apply changes

### 5. Deploy to production

1. **Docker:** Run `aegra up` (generates docker-compose.yml with PostgreSQL + Redis)
2. **PaaS:** Create PostgreSQL and Redis addons, set `DATABASE_URL` and `REDIS_URL`, run `aegra serve`
3. **Kubernetes:** Use `aegra serve` as container command, provide managed PostgreSQL and Redis
4. Set `REDIS_BROKER_ENABLED=true` for multi-instance deployments
5. Run migrations: `aegra db upgrade` (or auto on startup with `RUN_MIGRATIONS_ON_STARTUP=true`)
6. Configure health checks: `/health`, `/ready`, `/live`

### 6. Schedule a cron job

1. Create cron: `await client.crons.create(assistant_id="agent", schedule="0 9 * * *", input={...})`
2. Use standard 5-field cron format or 6-field for seconds
3. Set timezone if needed: `timezone="America/New_York"`
4. For thread-bound crons: `await client.crons.create_for_thread(thread_id=..., ...)`
5. Update: `await client.crons.update(cron_id=..., schedule="0 10 * * *")`
6. Disable without deleting: `await client.crons.update(cron_id=..., enabled=False)`

### 7. Use semantic search in the store

1. Configure in `aegra.json`: `"store": {"index": {"dims": 1536, "embed": "openai:text-embedding-3-small"}}`
2. Store items: `await client.store.put_item(namespace=[...], key="...", value={...})`
3. Search by meaning: `await client.store.search_items(namespace_prefix=[...], query="...", limit=5)`
4. Items are auto-embedded; search returns results ranked by semantic similarity

## Common gotchas

- **Don't install `aegra` package** — install `aegra-cli` directly. The `aegra` meta-package doesn't support version pinning.
- **Store values must be JSON objects** — primitives (strings, numbers) are rejected. Wrap them: `{"value": "text"}`.
- **Thread IDs and assistant IDs are limited to 255 characters** — longer values are rejected with 422 before hitting database limits.
- **Cron delivery is at-least-once** — under a crash between firing and advancing, a run can fire twice. Make scheduled work idempotent.
- **Scheduled runs skip per-request auth handlers** — put per-run authorization logic in the graph itself if it must apply to crons.
- **Checkpoint durability `exit` mode loses mid-run history** — you cannot inspect or fork from steps inside the run. Use `sync` or `async` if you need time travel.
- **Stateless crons delete their threads by default** — set `on_run_completed="keep"` if you want to inspect results. Clean up manually or use thread TTL.
- **Multi-pod deployments can race on migrations** — set `RUN_MIGRATIONS_ON_STARTUP=false` and run `aegra db upgrade` once per release from a Job or init container.
- **Liveness probes can timeout during startup** — increase `terminationGracePeriodSeconds` above `WORKER_DRAIN_TIMEOUT` (default 30s) in Kubernetes.
- **Redis is required for multi-instance deployments** — without it, runs execute as in-process asyncio tasks and cannot be shared across pods.
- **Namespace scoping is automatic** — user-scoped store data is buried under `["users", <user_id>, ...]` even if you omit the prefix. Configured scopes follow the same rule.
- **Graph factories are called per-request** — use `ServerRuntime.execution_runtime` to detect introspection (schema extraction) vs actual execution.
- **Subgraph streaming is opt-in** — set `stream_subgraphs=True` to receive events from nested subgraphs.
- **SSE keepalive prevents idle proxy timeouts** — the server sends heartbeat comments every 5 seconds to keep connections alive through proxies with 60s idle timeouts.

## Verification checklist

Before submitting work with Aegra:

- [ ] **Configuration is valid** — `aegra.json` parses without errors; all graph imports resolve
- [ ] **Environment variables are set** — `.env` includes required keys (API keys, database URL, Redis URL if needed)
- [ ] **Database is reachable** — `aegra dev` or `aegra serve` connects without "connection refused" errors
- [ ] **Migrations applied** — server starts without "relation does not exist" errors
- [ ] **Graphs load** — server startup logs show graphs registered (e.g., "Loaded graph: agent")
- [ ] **API is accessible** — `GET http://localhost:2026/docs` returns Swagger UI
- [ ] **Health checks pass** — `GET /health`, `GET /ready`, `GET /live` return 200
- [ ] **Threads can be created** — `POST /threads` succeeds and returns a thread object
- [ ] **Runs execute** — `POST /threads/{id}/runs/stream` produces events without errors
- [ ] **State persists** — `GET /threads/{id}/state` returns expected values after a run
- [ ] **Auth is enforced** (if configured) — requests without valid credentials return 401/403
- [ ] **Crons fire on schedule** — check `next_run_date` and verify runs are created at expected times
- [ ] **Store operations work** — `PUT /store/items` and `POST /store/items/search` succeed
- [ ] **Tracing is configured** (if needed) — traces appear in Langfuse/Phoenix/OTLP backend
- [ ] **Deployment target is ready** — database, Redis, and any external services are running and accessible

## Resources

- **Full documentation:** https://docs.aegra.dev/llms.txt (comprehensive page-by-page navigation for agents)
- **Configuration reference:** https://docs.aegra.dev/reference/configuration
- **CLI reference:** https://docs.aegra.dev/reference/cli
- **Deployment guide:** https://docs.aegra.dev/guides/deployment

---

> For additional documentation and navigation, see: https://docs.aegra.dev/llms.txt

Mirrored from the author's public source. Install counts from the open skills registry.

The systems behind these skills get built for partners every week.

Partner with us