10xgraph.json reference
In shortEvery 10xgraph.json key the server and CLI read, with types, defaults and examples, the rate_limit sub-keys, and the environment variables the API server uses.
- 8 min read
- 8 sections
- Updated
- v0.9.2
- Markdown
10xgraph.json tells the 10xGraph API server which graph to serve and how to secure it. Only agent is required. The file is plain JSON, and the server also reads settings from environment variables, listed at the end of this page. Edit it by hand or with 10xgraph config.
Which keys does it accept?
| Key | Type | Default | Purpose |
|---|---|---|---|
agent |
string | required | Compiled graph as module:attribute, for example graph.agent:app |
env |
string | none | Dotenv file to load before the graph starts, for example .env |
auth |
string, object or null | null |
Authentication: "jwt", or {"method": "custom", "path": "module:Class"} |
authorization |
string, object or null | by MODE |
Access control backend |
injectq |
string or null | none | Import path of an InjectQ container |
store |
string or null | none | Import path of a BaseStore for long-term memory |
checkpointer |
string or null | none | Not applied by the API server. Pass the checkpointer to compile() |
thread_name_generator |
string or null | none | Import path of a thread name generator |
redis |
string or null | none | Redis URL for the shared ownership cache. Falls back to REDIS_URL |
remote_tools |
array | [] |
Schemas of tools that run in the client |
rate_limit |
object | absent (off) | Request rate limiting |
websocket |
object | built-in caps | WebSocket connection limits |
ag_ui |
object | disabled | AG-UI protocol endpoint |
observability |
object | absent | Logfire and LangSmith tracing |
test |
object | absent | Defaults for 10xgraph test |
evaluation |
object | absent | Defaults for 10xgraph eval |
Import paths use module:attribute. Unknown top-level keys are kept in the file but ignored.
auth
| Value | Meaning |
|---|---|
null or absent |
No authentication. Every request runs as anonymous, and the server logs a warning |
"jwt" |
Verify bearer JWTs. Needs JWT_SECRET_KEY and JWT_ALGORITHM |
{"method": "custom", "path": "auth.agent_auth:AgentAuth"} |
Load a BaseAuth subclass. Both method and path are required |
authorization
| Value | Meaning |
|---|---|
"ownership" |
A thread is accessible only to the user who owns it |
"allow_all", "default", "none" |
Any authenticated user may do anything |
"module:attribute" |
Custom AuthorizationBackend |
{"backend": "rbac", ...} |
Role-based scopes plus owner isolation |
| absent | ownership when MODE=production, otherwise allow-all |
RBAC object keys:
| Key | Type | Default | Purpose |
|---|---|---|---|
backend |
string | required | rbac, role_based or roles (type is also accepted) |
roles |
object | {} |
Role name to a list of scopes. "*" grants every scope. role_scopes is also accepted |
default_scopes |
array | [] |
Scopes granted to everyone |
isolation |
string | owner |
owner or none: whether storage is scoped per user |
Scopes are checkpointer:read|write|delete, config:read, files:read|upload, graph:fix|invoke|read|setup|stop|stream and store:read|write|delete.
rate_limit
Rate limiting applies to REST requests. /ping is always excluded. Set "enabled": false to keep the block without enforcing it.
| Key | Type | Default | Purpose |
|---|---|---|---|
enabled |
boolean | true |
Turn limiting on or off |
backend |
string | memory |
memory, redis or custom (bind a BaseRateLimitBackend in InjectQ) |
requests |
integer | 100 |
Requests allowed per window. Must be above 0 |
window |
integer | 60 |
Window length in seconds. Must be above 0 |
by |
string | ip |
Count per ip, user or global |
exclude_paths |
array | [] |
Extra paths to skip |
redis |
object or string | none | {"url": "...", "prefix": "..."} or a URL string. $VAR and ${VAR} are expanded |
redis.prefix |
string | agentflow:rate-limit |
Redis key prefix |
fail_open |
boolean | true |
Allow requests when the backend errors. false denies them |
trusted_proxy_headers |
boolean | false |
Honour X-Forwarded-For. Only behind a proxy you control |
trusted_proxy_hops |
integer | 1 |
Proxies you control, counted from the right of X-Forwarded-For. At least 1 |
trusted_proxies |
array | [] |
IPs or CIDR ranges your proxies connect from. Others cannot spoof the header |
The memory backend counts per process, so with N workers the real limit is requests times N and it resets on restart. Use redis for any multi-worker deployment.
websocket, ag_ui and observability
| Key | Type | Default | Purpose |
|---|---|---|---|
websocket.max_connections |
integer or null | 1000 |
Concurrent connections per process. 0 or null means unlimited |
websocket.max_connections_per_user |
integer or null | 10 |
Per verified user. 0 or null means unlimited |
websocket.realtime_models |
array of strings | [] |
Models a /v1/graph/live client may request |
ag_ui.enabled |
boolean | false |
Mounts POST /v1/ag-ui. Needs the ag-ui extra |
ag_ui.allow_client_tools |
boolean | true |
Offer tools sent by the AG-UI client to the model |
observability.level |
string | standard |
spans, standard or full (full may record PII) |
observability.logfire |
object | none | Keys include enabled, service_name, send_to_logfire, console |
observability.langsmith |
object | none | Keys include enabled, project, endpoint |
Tokens stay in the environment: LOGFIRE_TOKEN and LANGSMITH_API_KEY are never read from the file.
remote_tools
Each entry declares a tool the model can call that runs in the client. Unknown fields are rejected and tool names must be unique.
| Key | Type | Required | Purpose |
|---|---|---|---|
node |
string | yes | Graph node the tool belongs to |
name |
string | yes | Tool name |
description |
string | yes | Description shown to the model |
parameters |
object | no | JSON Schema with type: "object". Defaults to no properties |
test and evaluation
| Key | Type | Default | Purpose |
|---|---|---|---|
test.path |
string | pytest discovery | Test directory or file |
test.coverage |
boolean | false |
Run with coverage |
test.coverage_threshold |
integer | none | Fail below this percentage |
evaluation.directory |
string | evals |
Where eval files live |
evaluation.output_dir |
string | eval_reports |
Report directory |
evaluation.threshold |
number | none | Minimum pass rate, 0 to 1 |
evaluation.parallel |
boolean | false |
Run cases concurrently |
evaluation.max_concurrency |
integer | 4 |
Concurrent cases when parallel |
Which environment variables does the server read?
Set these in the process environment or in the file named by env.
| Variable | Default | Purpose |
|---|---|---|
MODE |
development |
production disables the local telemetry store and the docs pages, and defaults authorization to ownership |
IS_DEBUG |
true |
Set false in production |
LOG_LEVEL |
INFO |
Logging level |
LOGGER_NAME |
agentflow-cli |
Logger name |
APP_NAME, APP_VERSION, SUMMARY |
MyApp, 0.1.0, Agentflow Backend |
Application metadata |
ORIGINS |
* |
Comma-separated CORS origins. Wildcard with credentials is refused in production |
ALLOWED_HOST |
* |
Allowed hosts. * warns in production |
CORS_ALLOW_CREDENTIALS |
true |
Allow credentialed cross-origin requests |
ROOT_PATH, DOCS_PATH, REDOCS_PATH |
/, /docs, /redocs |
URL paths. The docs paths are empty in production unless set |
MAX_REQUEST_SIZE |
10485760 |
Maximum request body in bytes |
REDIS_URL |
none | Redis for the ownership cache when redis is not set |
JWT_SECRET_KEY |
none | Signing secret. 32 bytes or more for HS* algorithms |
JWT_ALGORITHM |
HS256 |
Signing algorithm. Must be set for auth: "jwt" |
JWT_ISSUER, JWT_AUDIENCE |
none | When set, tokens must carry matching iss or aud |
SENTRY_DSN |
none | Enables Sentry in production, staging or development modes |
SENTRY_TRACES_SAMPLE_RATE, SENTRY_PROFILES_SAMPLE_RATE |
0.1, 0.0 |
Sampling rates from 0 to 1 |
OTEL_ENABLED |
false |
Enable OpenTelemetry |
OTEL_SERVICE_NAME |
agentflow-api |
Service name |
OTEL_EXPORTER_OTLP_ENDPOINT |
none | OTLP endpoint |
OTEL_LEVEL |
standard |
spans, standard or full |
SECURITY_HEADERS_ENABLED |
true |
Add security headers |
HSTS_ENABLED, HSTS_MAX_AGE, HSTS_INCLUDE_SUBDOMAINS, HSTS_PRELOAD |
true, 31536000, true, false |
Strict-Transport-Security |
FRAME_OPTIONS, CONTENT_TYPE_OPTIONS, XSS_PROTECTION, REFERRER_POLICY |
DENY, nosniff, 1; mode=block, strict-origin-when-cross-origin |
Other security headers |
PERMISSIONS_POLICY, CSP_POLICY |
none | Header values. Built-in defaults apply when unset |
GRAPH_PATH |
10xgraph.json |
Config file path used by the server. 10xgraph api sets it for you |
WEB_CONCURRENCY |
2 in generated Dockerfile |
Gunicorn worker count |
AGENTFLOW_NO_FULLSCREEN |
unset | Set to 1 to disable the full-screen CLI |
Media upload settings:
| Variable | Default | Purpose |
|---|---|---|
MEDIA_STORAGE_TYPE |
local |
memory, local or cloud |
MEDIA_STORAGE_PATH |
./uploads |
Local storage directory |
MEDIA_MAX_SIZE_MB |
25.0 |
Maximum upload size |
MEDIA_ALLOWED_CONTENT_TYPES |
empty (all) | Comma-separated allowlist, for example image/*,application/pdf |
MEDIA_REQUIRE_OWNER |
false |
Deny files with no recorded owner |
DOCUMENT_HANDLING |
extract_text |
extract_text, pass_raw or skip |
MEDIA_CLOUD_PROVIDER, MEDIA_CLOUD_BUCKET, MEDIA_CLOUD_REGION, MEDIA_CLOUD_PREFIX |
aws, empty, us-east-1, 10xgraph-media |
Used when storage is cloud |
Snowflake ID generation reads SNOWFLAKE_EPOCH (1723323246031), SNOWFLAKE_TOTAL_BITS (64), SNOWFLAKE_TIME_BITS (39), SNOWFLAKE_NODE_BITS (7), SNOWFLAKE_NODE_ID (0), SNOWFLAKE_WORKER_ID (0) and SNOWFLAKE_WORKER_BITS (5). Give each instance a unique node and worker id in distributed deployments.
What does a complete config look like?
{
"agent": "graph.agent:app",
"env": ".env",
"auth": "jwt",
"authorization": "ownership",
"injectq": "graph.agent:container",
"store": null,
"redis": "redis://localhost:6379/0",
"thread_name_generator": "graph.thread_name_generator:MyNameGenerator",
"rate_limit": {
"enabled": true,
"backend": "redis",
"requests": 100,
"window": 60,
"by": "user",
"trusted_proxy_headers": true,
"trusted_proxy_hops": 1,
"exclude_paths": ["/docs"],
"redis": { "url": "${REDIS_URL}", "prefix": "myapp:rate-limit" },
"fail_open": true
},
"websocket": { "max_connections": 500, "max_connections_per_user": 5 },
"ag_ui": { "enabled": false },
"observability": { "level": "standard", "logfire": { "enabled": false } },
"test": { "path": "tests", "coverage": true, "coverage_threshold": 80 },
"evaluation": { "directory": "evals", "output_dir": "eval_reports", "threshold": 0.75 }
}Frequently asked questions
- Which key is required in 10xgraph.json?
- Only agent, a string in module:attribute form that points at your compiled graph. Every other key is optional.
- Where does the CLI look for the config file?
- It searches the working directory and its parents for the path you pass with --config (default 10xgraph.json). Without a path, test and eval also try .10xgraph.json and agentflow.config.json.