Skip to main content
Aegra uses a JSON configuration file (aegra.json) to define graphs, authentication, HTTP settings, and the semantic store.

Config file resolution

Aegra resolves configuration files in this order:
  1. AEGRA_CONFIG environment variable — absolute or relative path
  2. aegra.json in the current working directory
  3. langgraph.json in the current working directory (compatibility fallback)
# Use a custom config file
AEGRA_CONFIG=production.json aegra dev

# Use default aegra.json
aegra dev

Complete example

{
  "dependencies": ["./shared"],
  "graphs": {
    "agent": "./src/react_agent/graph.py:graph",
    "agent_hitl": "./src/react_agent_hitl/graph.py:graph"
  },
  "auth": {
    "path": "./my_auth.py:auth",
    "disable_studio_auth": false
  },
  "http": {
    "app": "./custom_routes.py:app",
    "enable_custom_route_auth": false,
    "cors": {
      "allow_origins": ["https://example.com"],
      "allow_credentials": true
    }
  },
  "store": {
    "index": {
      "dims": 1536,
      "embed": "openai:text-embedding-3-small",
      "fields": ["$"]
    }
  }
}

dependencies

Add shared utility module paths to sys.path before graphs are loaded.
{
  "dependencies": ["./shared", "./libs/common"]
}
TypeDescription
list[str]List of directory paths to add to sys.path
  • Relative paths are resolved from the config file’s directory
  • Paths are added in order (first has highest import priority)
  • Non-existent paths generate a warning but don’t prevent startup
See dependencies guide for details.

graphs

Define your LangGraph agents.
{
  "graphs": {
    "agent": "./src/react_agent/graph.py:graph",
    "custom_agent": "./src/custom/graph.py:my_graph"
  }
}
FieldTypeDescription
KeystringGraph ID (used in API calls to identify the graph)
ValuestringImport path in format ./path/to/file.py:variable
The variable can be:
  • A compiled graph — result of builder.compile() (static, cached once at startup)
  • A 0-arg callable — called once at startup to produce the graph (e.g., for MCP adapter setup)
  • A factory function — called per-request with config and/or ServerRuntime to produce a graph customized for the current user or request context

Static graphs

builder = StateGraph(State)
# ... define nodes and edges
graph = builder.compile()  # Export as 'graph'

Factory graphs

Export a callable that accepts config (a RunnableConfig dict), runtime (a ServerRuntime), or both:
from langgraph_sdk.runtime import ServerRuntime

def graph(runtime: ServerRuntime):
    """Per-request factory — called with user context."""
    user = runtime.user
    store = runtime.store
    # Customize graph based on user/context
    builder = StateGraph(State)
    # ...
    return builder.compile()
Supported factory signatures:
  • def graph() — 0-arg, called once at startup
  • def graph(config: dict) — receives the RunnableConfig per-request
  • def graph(runtime: ServerRuntime) — receives runtime with user, store, and access context
  • def graph(config: dict, runtime: ServerRuntime) — receives both (any parameter order)
Async factories and factories returning async context managers are also supported.

Typed context with Runtime[T] (node-level)

When a run is created with a context dict, Aegra passes it to graph.astream(context=...). LangGraph core coerces it to a typed object and injects it into nodes via Runtime[T]. This works for both static and factory graphs:
from dataclasses import dataclass
from langgraph.graph import StateGraph
from langgraph.runtime import Runtime

@dataclass
class MyContext:
    model_name: str = "openai/gpt-4o-mini"
    temperature: float = 0.7

class State(TypedDict):
    messages: list

async def call_model(state: State, runtime: Runtime[MyContext]):
    """Node receives typed context via Runtime injection."""
    model = runtime.context.model_name      # str, typed
    temp = runtime.context.temperature      # float, typed
    ...

builder = StateGraph(State, context_schema=MyContext)
builder.add_node("call_model", call_model)
...
graph = builder.compile()
Pydantic BaseModel and dataclass types are both supported. Declare context_schema= on StateGraph and add a runtime: Runtime[T] parameter to any node that needs it.

Factory-level context with ServerRuntime[T]

For factory graphs, ServerRuntime[T] provides typed context at graph-build time — before execution starts. Use this for structural decisions that change the graph topology (adding/removing nodes, selecting tools, managing resource lifecycle):
from langgraph_sdk.runtime import ServerRuntime

@asynccontextmanager
async def graph(runtime: ServerRuntime[MyContext]):
    ert = runtime.execution_runtime
    ctx = ert.context if ert else MyContext()

    # Structural decision — changes graph topology
    tools = [search_tool] if ctx.enable_search else []
    compiled = build_graph(tools)
    yield compiled
Use runtime.execution_runtime to check whether the factory is being called for actual execution (returns the execution runtime with .context) or for introspection like schema extraction (returns None). When to use which:
NeedUseWorks with
Read context in node functionsRuntime[T] on node parameterStatic + factory graphs
Change graph structure per requestServerRuntime[T] in factoryFactory graphs only
Manage resource lifecycle (MCP, DB)ServerRuntime[T] + async context managerFactory graphs only
Filter tools by user permissionsServerRuntime (.user) in factoryFactory graphs only
For a complete example combining both layers, see examples/factory/.

auth

Configure authentication and authorization.
{
  "auth": {
    "path": "./my_auth.py:auth",
    "disable_studio_auth": false
  }
}
FieldTypeDefaultDescription
pathstringImport path to your auth handler (./file.py:variable)
disable_studio_authboolfalseDisable auth for LangGraph Studio connections
The path supports multiple formats:
  • ./auth.py:auth — Load from a file relative to the config
  • ./src/auth/jwt.py:auth — Nested path
  • mypackage.auth:auth — Load from an installed package
If auth is not configured, Aegra runs in no-auth mode where all requests are allowed. See authentication guide for details.

http

Configure custom routes and CORS.
{
  "http": {
    "app": "./custom_routes.py:app",
    "enable_custom_route_auth": false,
    "cors": {
      "allow_origins": ["https://example.com"],
      "allow_credentials": true
    }
  }
}
FieldTypeDefaultDescription
appstringNoneImport path to custom FastAPI app
enable_custom_route_authboolfalseApply Aegra auth to all custom routes
cors.allow_originslist[str]["*"]Allowed CORS origins
cors.allow_credentialsboolfalse when origins is ["*"], true otherwiseAllow credentials in CORS requests
See custom routes guide for details.

store

Configure semantic store with vector embeddings.
{
  "store": {
    "index": {
      "dims": 1536,
      "embed": "openai:text-embedding-3-small",
      "fields": ["$"]
    }
  }
}
FieldTypeRequiredDescription
index.dimsintegerYesEmbedding vector dimensions (must match your model)
index.embedstringYesEmbedding model in format provider:model-id
index.fieldslist[str]NoJSON fields to embed (default: ["$"] for entire document)
If store is not configured, Aegra operates in basic key-value mode. See semantic store guide for details.

Common configurations

Minimal

{
  "graphs": {
    "agent": "./src/agent/graph.py:graph"
  }
}

With authentication

{
  "graphs": {
    "agent": "./src/agent/graph.py:graph"
  },
  "auth": {
    "path": "./my_auth.py:auth"
  }
}

With custom routes

{
  "graphs": {
    "agent": "./src/agent/graph.py:graph"
  },
  "http": {
    "app": "./custom_routes.py:app"
  }
}

Production

{
  "graphs": {
    "agent": "./src/agent/graph.py:graph"
  },
  "auth": {
    "path": "./auth/production_auth.py:auth"
  },
  "http": {
    "app": "./custom_routes.py:app",
    "enable_custom_route_auth": true,
    "cors": {
      "allow_origins": ["https://myapp.com"],
      "allow_credentials": true
    }
  }
}