Getting an AI agent to work is the easy part now. A model, a few tools and a loop, and you have a demo in an afternoon.
Then someone asks you to put it in front of customers, and the questions change:
None of these are about the agent. They are about the backend around it, and most teams end up building that backend by hand before the feature can ship.
That backend is what 10xGraph is, and today it reaches 1.0.
10xGraph is open-source, self-hosted infrastructure for AI applications. You write the agents, tools and tasks. 10xGraph runs them behind an API server with authentication, role-based access, tenant isolation, durable state in Postgres and Redis, background jobs, metrics and tracing, and it generates the Docker and Kubernetes files to deploy it. It is MIT licensed and made by 10xScale. (It used to be called Agentflow.)
It ships as three packages, released together:
10xgraph: the Python framework (graphs, agents, tools, memory, storage)10xgraph-api: the API server and the 10xgraph-client: a typed TypeScript client
The quickest way to show what that means is to start one.
You need Python 3.12 or newer and a key for Google, OpenAI or Anthropic. No code to write.
pip install 10xgraph-api
mkdir support-agent && cd support-agent
10xgraph init --mode full --name support-agent --provider google --yes
pip install -e .
cp .env.example .env # set GOOGLE_API_KEY and JWT_SECRET_KEY
10xgraph dev
That's it. Your agent is ready, and it is not a toy. The Full setup turns on what a real deployment needs:
The server listens on port 8000 with invoke, streaming, threads and message history. 10xgraph dev also opens a playground in the browser where you can chat with the agent and inspect its threads.
Auth is already on, so a request without a token is refused:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/v1/threads
With a valid token, a user sees only their own data. Another user's thread answers 404, the same as a thread that does not exist, so nobody can even learn that it is there. You wrote no access-control code for this.
Need durable storage? Add --storage postgres to init and you get Postgres for threads with Redis as the cache store. Set DATABASE_URL and REDIS_URL in .env.
The same CLI takes the project the rest of the way:
10xgraph test # run the generated test suite
10xgraph eval # run the agent evals and open the report
10xgraph config # review auth, rate limits, CORS and the rest
10xgraph build --docker-compose --k8s # write the deploy files
build writes a Dockerfile (multi-stage, non-root), a docker-compose.yml and a k8s.yaml with liveness and readiness probes. Frontends talk to the server through the typed TypeScript client, npm install 10xgraph-client.
Here is what the Full setup is standing on.
Access control on every endpoint. One auth object configures JWT or your own auth class, plus roles. Each role has permissions (graph:invoke, threads:delete, ...) and a reach: own, tenant or all. The server refuses to boot if any non-public route is missing a permission guard.
Tenant isolation in storage, not just in the API. PgCheckpointer (threads) and PgVectorStore (long-term memory) filter every query by tenant columns you declare, filled from the verified identity, never from client input. Postgres row-level security is available as an extra layer.
One database. Conversation state lives in Postgres with Redis as a hot cache. Long-term memory and RAG use pgvector in the same Postgres, with similarity, full-text or hybrid search. One database to back up and secure.
Correct when things fail. Finished tool calls are recorded, so when a run resumes after a crash, a tool that already ran is not called again. On SIGTERM the server stops taking traffic, finishes or saves active runs, and shuts down cleanly. A cancelled or crashed run leaves a usable thread. (The honest limit: a crash before a tool returns can repeat it, so anything that moves money should get an idempotency key.)
Calling services as the user. UserCredential lets a tool or an MCP server call downstream APIs with the end user's credential, and that credential never reaches traces or logs.
Background jobs, metrics and an audit log. A thin TaskIQ layer (10xgraph worker, 10xgraph scheduler) that runs jobs under the same auth. Prometheus or OTLP metrics for the API and the worker. A metadata-only audit log you ship to your own storage.
Tracing. Spans follow the OpenTelemetry GenAI conventions and go to any OTLP backend, Phoenix, Logfire or LangSmith.
Any model. OpenAI, Google Gemini (including Vertex AI), Anthropic (direct, Vertex AI or Bedrock) and OpenAI-compatible endpoints like vLLM or Ollama. Changing the model string does not change your graph or tools. MCP tools work out of the box.
Graph orchestration, a tool-calling loop, streaming and MCP are in there too, but every serious framework has those. The list above is the reason to pick this one.
The breaking changes are done. From 1.0 on:
major.minor, so What counts as "public" in each package is written down in the stability and deprecation policy. Coming from 0.x, read the upgrade guide first. The old agentflow names keep working with a deprecation warning until 2.0.
Better you hear it here than find out later:
--mode full template turns it on, but the Quick setup and a bare server start open.refund, user B may not" is not built in yet.
pip install -U 10xgraph 10xgraph-api
npm install 10xgraph-client
If you are shipping AI to your own customers and the backend questions at the top of this post sound familiar, give it a try and tell us where it falls short. And if it saves you some work, a star on the repo helps other people find it.