Graph-backed, human-verified legal intelligence for Indian contracts.
This project is built with FastAPI, LangChain, LangGraph, LangSmith, Gemini, TigerData-backed Postgres, Neo4j, and Graphiti. It is not a generic agent sandbox. It is a stateful legal reasoning system designed around resumability, memory discipline, human review, and deterministic execution.
AI Agents should never be replacing Humans. They should be your devoted digital companions, ever-ready to absorb the soul-crushing repetition and mindless grunt work that slowly poisons the very profession you once chased with youthful fire.
Neither should you use AI Agents to do the job for you completely end-to-end. Instead, you should be doing AI-assisted work that feels like a genuinely ergonomic work chair: removing avoidable strain, reducing dread-filled procrastination, cutting down existential second-guessing, and lowering the quiet terror of "what if I chose wrong?".
If your agents free time that would otherwise be wasted on repetitive cognitive drag, that time should go back to being more human, lifting invisible weight off your shoulders instead of turning your hair white early.
This is a graph-backed, human-verified legal intelligence platform for Indian contracts.
A distributed, resumable, schema-driven cognitive workflow engine with controlled reasoning surfaces. It has three layers:
The real architecture:
The deepest insight: if your system cannot deterministically replay a run, you do not control your agent.
Final mental model:
Plan -> deterministic execution -> validated output -> persisted state
Not:
LLM -> decide -> act -> hope it works
The orchestration model is deliberate.
Main agent plans -> delegates to workers -> synthesizes.
That maps cleanly to the actual requirements:
LegalAgentState, workers read and write through controlled surfacesDo not initialize models or compile agents inside LangGraph nodes. That is the fast path to slow requests, memory churn, noisy traces, and production pain.
Bad pattern:
def research_node(state):
model = init_chat_model("gpt-4o")
agent = create_agent(model, tools)
return agent.invoke(state)
Why it hurts:
Correct pattern:
research_agent = create_agent(
init_chat_model("gpt-4o"),
tools=[search_caselaw],
)
def research_node(state):
return research_agent.invoke(state)
Compile models, tools, and agents once at startup. Then pass compiled callables into graph nodes. Node functions should execute workflow logic, not rebuild the runtime.
The intended node strategy:
create_agent(...) outside the graph.graph.add_node(...).app.state.The expected result is lower latency, stable memory, reusable traces, and a graph that behaves like infrastructure instead of improvisation.
This is not about shallow "time-saving".
Legal work has a strange cruelty to it: the most expensive human judgment often sits behind a wall of repetitive reading, clause sorting, calendar math, template comparison, and anxious second-guessing. The people who need clarity most are usually the least able to buy it continuously: founders signing vendor terms, families reading settlement papers, policyholders facing claim language, and small businesses trying not to discover a liability clause after the damage is done.
Agent Saul exists to reduce that information asymmetry. Not by pretending to be a lawyer, and not by turning legal judgment into autocomplete, but by making the repetitive surface area small enough that humans can spend their attention on the parts that actually require judgment.
The actual pain in India is different:
High-volume work worth automating:
Time is a symptom. Risk and uncertainty are the disease.
The same pattern shows up across domains:
pgvector, pgvectorscale, and pg_textsearchThe architecture notes that drive this repo live in tests/performance/Saul_agent_Arch.md.
pgvector, pgvectorscale, pg_textsearchWhy humans are required:
What humans do:
What gets stored:
This becomes training data and audit data, not just UI feedback.
In Indian legal work, judgment interpretation is not optional context. The system has to preserve judgment context, surface conflicting rulings, and distinguish what binds a District Court, a High Court, and the Supreme Court of India.
Agents do not only spend tokens on user prompts. The context window fills from several sources:
system prompt 2K-5K tokens
bootstrap files varies, often large
memory files grows over time
skills and instructions per selected skill
conversation history primary recurring cost
tool output history silent killer, can reach huge character counts
compaction summaries usually 1K-3K tokens
The system should treat context as an operating budget, not a junk drawer.
Practical rules:
3.12+uvrufftygit clone https://github.com/Harmeet10000/langchain-fastapi-production.git
cd langchain-fastapi-production
uv venv
source .venv/bin/activate
uv sync
uv sync --extra dev
uv run uvicorn src.app.main:app --reload --reload-dir src --host 0.0.0.0 --port 5000 --no-access-log
uv run python src/app/server.py
uv run pre-commit run --all-files
uv run alembic revision --autogenerate -m "Add user table"
uv run alembic upgrade head
uv run alembic downgrade -1
uv run alembic current
uv run alembic history --verbose
uv run ruff check --fix
uv run ruff format
uv run pytest -x
uv run celery -A celery_config worker --loglevel=info
.
├── README.md
├── docs/
│ ├── README.md
│ ├── CAP for AI Agents.md
│ └── LANGGRAPH_COMPLETE_GUIDE.md
├── tests/
│ ├── performance/
│ │ ├── Saul_agent_Arch.md
│ │ ├── agent_saul_full_architecture.svg
│ │ └── python_memory_optimization_cheatsheet.md
│ ├── integration/
│ ├── e2e/
│ └── unit/
├── src/
│ ├── app/
│ │ ├── api/
│ │ ├── config/
│ │ ├── connections/
│ │ ├── features/
│ │ │ ├── agent_saul/
│ │ │ ├── ingestion/
│ │ │ ├── knowledge_base/
│ │ │ ├── search/
│ │ │ └── web_scraping/
│ │ ├── lifecycle/
│ │ ├── middleware/
│ │ ├── shared/
│ │ │ ├── agents/
│ │ │ ├── document_processing/
│ │ │ ├── langchain_layer/
│ │ │ ├── langgraph_layer/
│ │ │ │ └── agent_saul/
│ │ │ ├── mcp/
│ │ │ ├── rag/
│ │ │ │ └── graphiti/
│ │ │ └── vectorstore/
│ │ └── utils/
│ ├── database/
│ │ ├── schemas/
│ │ └── seeders/
│ └── tasks/
├── infra/
│ └── gcp/
├── docker/
├── caddy/
├── pyproject.toml
└── uv.lock
$ claude mcp add AgentNexus-LangChain-FastAPI \
-- python -m otcore.mcp_server <graph>