Lár: The PyTorch for Agents. A 'define-by-run' agentic framework.
Project description
Lár: The Pytorch for Agents
Lár: The PyTorch for Agents
Lár (Irish for "core" or "center") is the open source standard for Deterministic, Auditable, and Air-Gap Capable AI agents.
It is a "define-by-run" framework that acts as a Flight Recorder for your agent, creating a complete audit trail for every single step.
[!NOTE] Lár is NOT a wrapper. It is a standalone, ground-up engine designed for reliability. It does not wrap LangChain, OpenAI Swarm, or any other library. It is pure, dependency-lite Python code optimized for "Code-as-Graph" execution.
The "Black Box" Problem
You are a developer launching a mission-critical AI agent. It works on your machine, but in production, it fails. You don't know why, where, or how much it cost. You just get a 100-line stack trace from a "magic" framework.
The "Glass Box" Solution
Lár removes the magic.
It is a simple engine that runs one node at a time, logging every single step to a forensic Flight Recorder.
This means you get:
- Instant Debugging: See the exact node and error that caused the crash.
- Free Auditing: A complete history of every decision and token cost, built-in by default.
- Total Control: Build deterministic "assembly lines," not chaotic chat rooms.
"This demonstrates that for a graph without randomness or external model variability, Lár executes deterministically and produces identical state traces."
Stop guessing. Start building agents you can trust.
Why Lár is Better: The "Glass Box" Advantage
| Feature | The "Black Box" (LangChain / CrewAI) | The "Glass Box" (Lár) |
|---|---|---|
| Debugging | A Nightmare. When an agent fails, you get a 100-line stack trace from inside the framework's "magic" AgentExecutor. You have to guess what went wrong. | Instant & Precise. Your history log is the debugger. You see the exact node that failed (e.g., ToolNode), You see the exact error (APIConnectionError), and the exact state that caused it. |
| Auditability | External & Paid. "What happened?" is a mystery. You need an external, paid tool like LangSmith to add a "flight recorder" to your "black box." | Built-in & Free. The "Flight Log" (history log) is the core, default, open-source output of the GraphExecutor. You built this from day one. |
| Multi-Agent Collaboration | Chaotic "Chat Room." Agents are put in a room to "talk" to each other. It's "magic," but it's uncontrollable. You can't be sure who will talk next or if they'll get stuck in a loop. | Deterministic "Assembly Line." You are the architect. You define the exact path of collaboration using RouterNode and ToolNode. |
| Deterministic Control | None. You can't guarantee execution order. The "Tweeter" agent might run before the "Researcher" agent is finished. | Full Control. The "Tweeter" (LLMNode) cannot run until the "RAG Agent" (ToolNode) has successfully finished and saved its result to the state. |
| Data Flow | Implicit & Messy. Agents pass data by "chatting." The ToolNode's output might be polluted by another agent's "thoughts." |
Explicit & Hard-Coded. The data flow is defined by you: RAG Output -> Tweet Input. The "Tweeter" only sees the data it's supposed to. |
| Resilience & Cost | Wasteful & Brittle. If the RAG agent fails, the Tweeter agent might still run with no data, wasting API calls and money. A loop of 5 agents all chatting can hit rate limits fast. | Efficient & Resilient. If the RAG agent fails, the Tweeter never runs. Your graph stops, saving you money and preventing a bad output. Your LLMNode's built-in retry handles transient errors silently. |
| Core Philosophy | Sells "Magic." | Sells "Trust." |
The Game Changer: Hybrid Cognitive Architecture
Most frameworks are "All LLM." This doesn't scale. You cannot run 1,000 agents if every step costs $0.05 and takes 3 seconds.
1. The "Construction Site" Metaphor
-
The Old Way (Standard Agents): Imagine a construction site where every single worker is a high-paid Architect. To hammer a nail, they stop, "think" about the nail, write a poem about the nail, and charge you $5. It takes forever and costs a fortune.
-
The Lár Way (Hybrid Swarm): Imagine One Architect and 1,000 Robots.
- The Architect (Orchestrator Node): Looks at the blueprint ONCE. Yells: "Build the Skyscraper!"
- The Robots (Swarm): They hear the order. They don't "think." They don't charge $5. They just execute thousands of steps instantly.
2. The Numbers Don't Lie
We prove this in examples/9_corporate_swarm.py.
| Feature | Standard "Agent Builder" (LangChain/CrewAI) | Lár "Hybrid" Architecture |
|---|---|---|
| Logic | 100% LLM Nodes. Every step is a prompt. | 1% LLM (Orchestrator) + 99% Code (Swarm) |
| Cost | $$$ (60 LLM calls). | $ (1 LLM call). |
| Speed | Slow (60s+ latency). | Instant (0.08s for 64 steps). |
| Reliability | Low. "Telephone Game" effect. | High. Deterministic execution. |
3. Case Study: The "Smoking Gun" Proof
We built the generic "Corporate Swarm" in massive-scale LangChain/LangGraph (examples/comparisons/langchain_swarm_fail.py) to compare.
It crashed at Step 25.
-> Step 24
💥 CRASH CONFIRMED: Recursion limit of 25 reached without hitting a stop condition.
LangGraph Engine stopped execution due to Recursion Limit.
Why this matters:
- The "Recursion Limit" Crash: Standard executors treat agents as loops. They cap at 25 steps to prevent infinite loops. Real work (like a 60-step swarm) triggers this safety switch.
- The "Token Burn": Standard frameworks use an LLM to route every step ($0.60/run). Lár uses code ($0.00/run).
- The "Telephone Game": Passing data through 60 LLM layers corrupts context. Lár passes explicit state objects.
"Lár turns Agents from 'Chatbot Prototyping' into 'High-Performance Software'."
A Simple Self-Correcting Loop
graph TD
A[Start] --> B[Step 0: PlannerNode - Writer]
B --> C1[Step 1: ToolNode - Tester]
C1 --> D{Step 2: RouteNode - Judge}
%% Success path
subgraph Success_Path
direction TB
G[Step 5: AddValueNode - Finalize]
end
%% Correction loop
subgraph Correction_Loop
direction TB
E[Step 3: LLMNode - Corrector]
F[Step 4: ClearErrorNode - Cleanup]
end
D -- Success --> G
D -- Failure --> E
E --> F
F --> C1
G --> H[End]
classDef default stroke:#8FA3B0, color:#FFFFFF, fill:#1E293B;
classDef decision stroke:#8FA3B0, color:#FFFFFF, fill:#1E293B;
classDef startend stroke:#8FA3B0, color:#FFFFFF, fill:#1E293B;
class A,H startend;
class B,C1,E,F,G default;
class D decision;
The Lár Architecture: Core Primitives
You can build any agent with four core components:
-
GraphState: A simple, unified object that holds the "memory" of the agent. It is passed to every node, allowing one node to write data (state.set(...)) and the next to read it (state.get(...)). -
BaseNode: The abstract class (the "contract") for all executable units. It enforces a single method:execute(self, state). Theexecutemethod's sole responsibility is to perform its logic and return the nextBaseNodeto run, orNoneto terminate the graph. -
GraphExecutor: The "engine" that runs the graph. It is a Python generator that runs one node, yields the execution log for that step, and then pauses, waiting for the next call. -
Node Implementations: The "building blocks" of your agent.
LLMNode: The "Thinker." Calls any major LLM API (e.g., Gemini, GPT-4, Claude) to generate text... to generate text, modify plans, or correct code. Now supportsgeneration_configfor controlling creativity (temperature, top_p).ToolNode: The "Actor." Executes any deterministic Python function (e.g., run code, search a database, call an API). It supports separate routing forsuccessanderror.RouterNode: The "Choice." Executes a simple Python function to inspect the state and returns a string key, which deterministically routes execution to the next node. This is your "if/else" statement.ClearErrorNode: A utility node that cleans up state (e.g., removeslast_error) to prevent infinite loops.
Example "Glass Box" Audit Trail
You don't need to guess why an agent failed. lar is a "glass box" that provides a complete, auditable log for every run, especially failures.
This is a real execution log from a lar-built agent. The agent's job was to run a "Planner" and then a "Synthesizer" (both LLMNodes). The GraphExecutor caught a fatal error, gracefully stopped the agent, and produced this perfect audit trail.
Execution Summary (Run ID: a1b2c3d4-...)
| Step | Node | Outcome | Key Changes |
|---|---|---|---|
| 0 | LLMNode |
success |
+ ADDED: 'search_query' |
| 1 | ToolNode |
success |
+ ADDED: 'retrieved_context' |
| 2 | LLMNode |
success |
+ ADDED: 'draft_answer' |
| 3 | LLMNode |
error |
+ ADDED: 'error': "APIConnectionError" |
This is the lar difference. You know the exact node (LLMNode), the exact step (3), and the exact reason (APIConnectionError) for the failure. You can't debug a "black box," but you can always fix a "glass box."
Installation
This project is managed with Poetry.
-
Clone the repository:
git clone https://github.com/snath-ai/lar.git cd lar
-
Set Up Environment Variables Lár uses the unified LiteLLM adapter under the hood. This means if a model is supported by LiteLLM (100+ providers including Azure, Bedrock, VertexAI), it is supported by Lár.
Create a .env file:
# Required for running Gemini models:
GEMINI_API_KEY="YOUR_GEMINI_KEY_HERE"
# Required for running OpenAI models (e.g., gpt-4o):
OPENAI_API_KEY="YOUR_OPENAI_KEY_HERE"
# Required for running Anthropic models (e.g., Claude):
ANTHROPIC_API_KEY="YOUR_ANTHROPIC_KEY_HERE"
-
Install dependencies: This command creates a virtual environment and installs all packages from
pyproject.toml.poetry install
Ready to build with Lár? (Agentic IDEs)
Lár is designed for Agentic IDEs (Cursor, Windsurf, Antigravity) and strict code generation.
We provide a 2-Step Workflow directly in the repo to make your IDE an expert Lár Architect.
1. The Strategy: "Reference, Don't Copy"
Instead of pasting massive prompts, simply reference the master files in the lar/ directory.
2. The Workflow
- Context (The Brain): In your IDE chat, reference
@lar/IDE_MASTER_PROMPT.md. This loads the strict typing rules and "Code-as-Graph" philosophy. - Scaffold (The Ask): Open
@lar/IDE_PROMPT_TEMPLATE.md, fill in your agent's goal, and ask the IDE to "Implement this."
Example Prompt to Cursor/Windsurf:
"Using the rules in @lar/IDE_MASTER_PROMPT.md, implement the agent described in @lar/IDE_PROMPT_TEMPLATE.md."
2. Learn by Example
We have provided 8 robust patterns in the examples/ directory:
| Level | Pattern | Concept |
|---|---|---|
| 🟢 | 1_simple_triage.py |
Classification & Linear Routing |
| 🟢 | 2_rag_researcher.py |
RAG (ToolNode) & State Merging |
| 🟡 | 3_self_correction.py |
"Judge" Pattern & Error Loops |
| 🟡 | 4_human_in_the_loop.py |
User Approval & Interrupts |
| 🟡 | 5_parallel_execution.py |
Fan-Out / Fan-In Aggregation |
| 🔴 | 6_structured_output.py |
Strict JSON Enforcement |
| 🔴 | 7_multi_agent_handoff.py |
Multi-Agent Collaboration (Writer <-> Editor) |
| 🟣 | 8_meta_prompt_optimizer.py |
Self-Modifying Agents (Meta-Reasoning) |
| ⚫ | 9_corporate_swarm.py |
Stress Test: 60+ Node Graph (Programmatic Generation) |
| 🛡️ | 10_security_firewall.py |
Architecture Security: Blocking Jailbreaks with Code ($0 Cost) |
Example: Multi-Agent Orchestration (A Customer Support Agent)
The real power of lar is not just loops, but multi-agent orchestration.
Other frameworks use a "chaotic chat room" model, where agents talk to each other and you hope for a good result. lar is a deterministic "assembly line." You are the architect. You build a "glass box" graph that routes a task to specialized agents, guaranteeing order and auditing every step.
1. The "Glass Box" Flowchart
This is the simple, powerful "Customer Support" agent we'll build. It's a "Master Agent" that routes tasks to specialists.
graph TD
A[Start] --> B(LLMNode<br/>'Agent 1: Triage');
B --> C(LLMNode<br/>'Agent 2: Planner');
C --> D(ToolNode<br/>'Retriever');
%% This is the "hub" node
D --> E{RouterNode<br/>'Manager: Route By Category'};
%% Define the three parallel paths
E -- "BILLING_AGENT" --> F;
E -- "TECH_AGENT" --> G;
E -- "GENERAL_AGENT" --> H;
%% Define what's INSIDE the subgraphs
subgraph "Finance Department"
F(LLMNode<br/>'Agent 3: Finance Specialist');
end
subgraph "Tech Support Department"
G(LLMNode<br/>'Agent 4: Tech Specialist');
end
subgraph "General"
H(LLMNode<br/>'Agent 5: Generalist');
end
%% Define the "join" point
F --> I[AddValueNode<br/>'Final Answer'];
G --> I;
H --> I;
I --> J[END];
Lár Engine Architecture: The Multi-Agent Assembly Line
The core of this application is a Multi-Agent Orchestration Graph. Lár forces you to define the assembly line, which guarantees predictable, auditable results.
1. Graph Flow (Execution Sequence)
The agent executes in a fixed, 6-step sequence. The graph is defined backwards in the code, but the execution runs forwards:
| Step | Node Name | Lár Primitive | Action | State Output |
|---|---|---|---|---|
| 0 (Start) | triage_node | LLMNode | Classifies the user's input ({task}) into a service category (BILLING, TECH, etc.). |
category |
| 1 | planner_node | LLMNode | Converts the task into a concise, high-quality search query. | search_query |
| 2 | retrieve_node | ToolNode | Executes the local FAISS vector search and retrieves the relevant context. | retrieved_context |
| 3 | specialist_router | RouterNode | Decision point. Reads the category and routes the flow to the appropriate specialist. | (No change; routing) |
| 4 | billing/tech_agent | LLMNode | The chosen specialist synthesizes the final answer using the retrieved context. | agent_answer |
| 5 (End) | final_node | AddValueNode | Saves the synthesized answer as final_response and terminates the graph. |
final_response |
2. Architectural Primitives Used
This demo relies on the core Lár primitives to function:
-
LLMNode: Used 5 times (Triage, Plan, and the 3 Specialists) for all reasoning and synthesis steps. -
RouterNode: Used once (specialist_router) for the deterministic if/else branching logic. -
ToolNode: Used once (retrieve_node) to securely execute the local RAG database lookup. -
GraphExecutor: The engine that runs this entire sequence and produces the complete audit log
This is the full logic from support_app.py. It's just a clean, explicit Python script.
'''
====================================================================
ARCHITECTURE NOTE: Defining the Graph Backwards
The Lár Engine uses a "define-by-run" philosophy. Because a node
references the *next_node* object (e.g., next_node=planner_node),
the nodes MUST be defined in Python in the REVERSE order of execution
to ensure the next object already exists in memory.
Execution runs: START (Triage) -> END (Final)
Definition runs: END (Final) -> START (Triage)
====================================================================
'''
from lar import *
from lar.utils import compute_state_diff # (Used by executor)
# 1. Define the "choice" logic for our Router
def triage_router_function(state: GraphState) -> str:
"""Reads the 'category' from the state and returns a route key."""
category = state.get("category", "GENERAL").strip().upper()
if "BILLING" in category:
return "BILLING_AGENT"
elif "TECH_SUPPORT" in category:
return "TECH_AGENT"
else:
return "GENERAL_AGENT"
# 2. Define the agent's nodes (the "bricks")
# We build from the end to the start.
# --- The End Nodes (the destinations) ---
final_node = AddValueNode(key="final_response", value="{agent_answer}", next_node=None)
critical_fail_node = AddValueNode(key="final_status", value="CRITICAL_FAILURE", next_node=None)
# --- The "Specialist" Agents ---
billing_agent = LLMNode(
model_name="gemini-1.5-pro",
prompt_template="You are a BILLING expert. Answer '{task}' using ONLY this context: {retrieved_context}",
output_key="agent_answer",
next_node=final_node
)
tech_agent = LLMNode(
model_name="gemini-1.5-pro",
prompt_template="You are a TECH SUPPORT expert. Answer '{task}' using ONLY this context: {retrieved_context}",
output_key="agent_answer",
next_node=final_node
)
general_agent = LLMNode(
model_name="gemini-1.5-pro",
prompt_template="You are a GENERAL assistant. Answer '{task}' using ONLY this context: {retrieved_context}",
output_key="agent_answer",
next_node=final_node
)
# --- The "Manager" (Router) ---
specialist_router = RouterNode(
decision_function=triage_router_function,
path_map={
"BILLING_AGENT": billing_agent,
"TECH_AGENT": tech_agent,
"GENERAL_AGENT": general_agent
},
default_node=general_agent
)
# --- The "Retriever" (Tool) ---
retrieve_node = ToolNode(
tool_function=retrieve_relevant_chunks, # This is our local FAISS search
input_keys=["search_query"],
output_key="retrieved_context",
next_node=specialist_router,
error_node=critical_fail_node
)
# --- The "Planner" (LLM) ---
planner_node = LLMNode(
model_name="gemini-1.5-pro",
prompt_template="You are a search query machine. Convert this task to a search query: {task}. Respond with ONLY the query.",
output_key="search_query",
next_node=retrieve_node
)
# --- The "Triage" Node (The *real* start) ---
triage_node = LLMNode(
model_name="gemini-1.5-pro",
prompt_template="You are a triage bot. Classify this task: \"{task}\". Respond ONLY with: BILLING, TECH_SUPPORT, or GENERAL.",
output_key="category",
next_node=planner_node
)
# 3. Run the Agent
executor = GraphExecutor()
initial_state = {"task": "How do I reset my password?"}
result_log = list(executor.run_step_by_step(
start_node=triage_node,
initial_state=initial_state
))
# 4. The "Deploy Anywhere" Feature
# Serialize your entire graph logic to a portable JSON schema.
# This file can be versioned in git or imported into Snath Cloud.
executor.save_to_file("support_agent_v1.json")
print("Agent serialized successfully. Ready for deployment.")
'''
The "glass box" log for Step 0 will show:
"state_diff": {"added": {"category": "TECH_SUPPORT"}}
The log for Step 1 will show:
"Routing to LLMNode" (the tech_support_agent)
'''
Ready to Build a Real Agent?
We have built two "killer demos" that prove this "glass box" model. You can clone, build, and run them today.
-
snath-ai/rag-demo: A complete, self-correcting RAG agent that uses a local vector database.
-
snath-ai/support-demo:The Customer Support agent described above.
Show Your Agents are Auditable
-
If you build an agent using the Lár Engine, you are building a dependable, verifiable system. Help us spread the philosophy of the "Glass Box" by displaying the badge below in your project's README.
-
By adopting this badge, you signal to users and collaborators that your agent is built for production reliability and auditability.
Show an Auditable Badge to your project:
Badge Markdown:
[](https://docs.snath.ai)
Author
Lár was created by Aadithya Vishnu Sajeev.
Support the Project
Lár is an open-source agent framework built to be clear, debuggable, and developer-friendly. If this project helps you, consider supporting its development through GitHub Sponsors.
Become a sponsor → Sponsor on GitHub
Your support helps me continue improving the framework and building new tools for the community.
Contributing
We welcome contributions to Lár.
To get started, please read our Contribution Guidelines on how to report bugs, submit pull requests, and propose new features.
License
Làr is licensed under the Apache License 2.0
This means:
- You are free to use Làr in personal, academic, or commercial projects.
- You may modify and distribute the code.
- You MUST retain the
LICENSEand theNOTICEfile. - If you distribute a modified version, you must document what you changed.
- You receive a patent license for contributions made to the project.
Apache 2.0 protects the original author (Aadithya Vishnu Sajeev) from liability while allowing you to use this in commercial software.
For developers building on Làr:
Please ensure that the LICENSE and NOTICE files remain intact
to preserve full legal compatibility with the Apache 2.0 terms.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lar_engine-0.9.0.tar.gz.
File metadata
- Download URL: lar_engine-0.9.0.tar.gz
- Upload date:
- Size: 38.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
442a7df59b680c40e976f2a857de75de1f8b14c34650cfc7988d4550a48af3de
|
|
| MD5 |
5670b11663b89e8bc30dda7d71e58905
|
|
| BLAKE2b-256 |
9ea3e9abfac94fce8d40bb5ad59e519bfecaa0209eb000a7433268f7edd58851
|
Provenance
The following attestation bundles were made for lar_engine-0.9.0.tar.gz:
Publisher:
publish.yml on snath-ai/lar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lar_engine-0.9.0.tar.gz -
Subject digest:
442a7df59b680c40e976f2a857de75de1f8b14c34650cfc7988d4550a48af3de - Sigstore transparency entry: 773799440
- Sigstore integration time:
-
Permalink:
snath-ai/lar@5921a30bb4e507c47482b90bf7b5b66dfb5490e5 -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/snath-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5921a30bb4e507c47482b90bf7b5b66dfb5490e5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file lar_engine-0.9.0-py3-none-any.whl.
File metadata
- Download URL: lar_engine-0.9.0-py3-none-any.whl
- Upload date:
- Size: 33.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2117f49cee939d09a713a3283a6a418dafdc76a557d97464c82f7a28775251d
|
|
| MD5 |
c250aa6a2bd1f80659ed59d7bb67a67f
|
|
| BLAKE2b-256 |
f10c45fac287df46a17722902fa3f55e41ec9c926bdc688596043a1eef5b2938
|
Provenance
The following attestation bundles were made for lar_engine-0.9.0-py3-none-any.whl:
Publisher:
publish.yml on snath-ai/lar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lar_engine-0.9.0-py3-none-any.whl -
Subject digest:
a2117f49cee939d09a713a3283a6a418dafdc76a557d97464c82f7a28775251d - Sigstore transparency entry: 773799446
- Sigstore integration time:
-
Permalink:
snath-ai/lar@5921a30bb4e507c47482b90bf7b5b66dfb5490e5 -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/snath-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5921a30bb4e507c47482b90bf7b5b66dfb5490e5 -
Trigger Event:
release
-
Statement type: