LIPAS — write ordinary Python agents with replay, auditing, supervision, and durable handoffs.
Project description
LIPAS
LIPAS lets you write ordinary Python agents with an explicit record of what they decided, spent, and did. It is a small Python reference implementation of a claim-based execution model for reliable AI agents.
Start with one assistant. Add only the reliability boundary the application actually needs.
Agent = one assistant that thinks and uses tools
@tool = an explicit capability with a declared side effect
Team = a durable handoff between named assistants or functions
0.9.8 public beta. Ollama, injected-client Anthropic, and OpenAI Responses adapters are available, along with durable SQLite sessions, safe replay, supervision, and at-least-once Team handoffs.
The one idea underneath
LIPAS does not ask you to write a graph or a special workflow language. You
write ordinary Python; an Agent calls a model and ordinary @tool functions.
The runtime records the reliability-relevant parts of that work as immutable
Claims.
A fold accepts each stable claim once, validates it, and updates small
derived views of the same record: history answers what happened, capability
enforces spend limits, and effects record intent → result | rejection.
ordinary Python Agent / Tool / Team
│
▼
append-only Claims
├── history: decisions and handoffs
├── capability: budgets and spend
└── effect: intent, result, lineage
That one record is why the pieces fit together rather than becoming unrelated features: guards and budgets decide before a call; replay substitutes a recorded result; supervision records its recommendation; a Team handoff has a stable causal id; an external write can be reconciled against its recorded intent. Your code remains natural Python because the runtime records the boundary around it instead of replacing its control flow.
For the precise guarantees and limits, read the short Execution model.
Start here
pip install 'lipas[ollama]'
ollama pull gemma4:12b
from lipas import Agent, tool
@tool(side_effect="read_only")
def lookup_customer(customer_id: str) -> str:
"""Look up a customer without changing external state."""
return f"customer={customer_id}"
with Agent.ollama(
tools=[lookup_customer],
instructions="Use tools when useful; answer concisely.",
session="runs/support.db", # omit for in-memory use
) as agent:
result = agent.ask("Find customer C-42")
print(result.text)
agent.ask(...) is the normal-script API. In an async application, use
await agent.run(...). The first runnable example is
examples/01_first_agent.py. The numbered
example course then builds from ordinary assistants to
replay, supervision, durable handoffs, and external-operation recovery.
When to add more
Keep one Agent when one coherent goal shares one conversation, tool set, budget, and answer. Multiple steps or multiple tools do not require a Team.
Add a Team only when work needs a separate owner or recovery boundary: an
independently restartable task, a different authority/budget, a separately
audited result, or a human/external-operation handoff. A Team member is usually
an Agent, but can be a plain async function. In a normal script:
from lipas import Team
async def researcher(prompt):
return {"finding": f"researched: {prompt}"}
with Team.open("runs/team.db") as team:
team.add("research", researcher)
finding = team.ask_sync("research", "check release risks")
Reliability, only when you ask for it
| Add | LIPAS provides |
|---|---|
@tool(side_effect="read_only") |
explicit replay and retry safety class |
session="runs/app.db" |
durable trace of intent, result, spend, and decisions |
budgets={...} |
pre-flight rejection before a known limit is exceeded |
tool_guards=[...] |
recorded policy denial before a live call |
OperationJournal |
idempotency-key persistence and reconciliation state for an external write |
Team |
durable, at-least-once handoff with leases and acknowledgement |
The record is not a magic memory system and LIPAS is not a graph/workflow DSL. Your application still owns its domain data, business rules, and user-facing workflow.
The high-level Agent API returns a final result. Lower-level
LLMHarness.stream(...) supports normalized stream events for integrations
that need them, but LIPAS does not yet offer token streaming from Agent.
Reusable Skills
A Skill is a portable SKILL.md instruction file: it captures how an Agent
should approach recurring work without granting it any new authority. Tools
remain the only executable capability. Start by copying one of the ready-made
example skills, then point an Agent at its directory:
from lipas import Agent
from my_app.tools import search_papers
agent = Agent.ollama(
tools=[search_papers],
skills="skills/research-brief",
)
The research, support-triage, daily-brief, and safe-external-actions Skills are deliberately small templates: edit them for your own standards rather than treating prompt text as a permission system.
Try and inspect
The optional CLI is for trying an ordinary Python Agent and inspecting its session; it is not a second configuration language.
pip install 'lipas[ollama,cli]'
lipas init support-demo --model gemma4:12b
cd support-demo
lipas chat --factory agent:build_agent
lipas trace runs/chat.db
lipas effects runs/chat.db
From a source checkout before installation, use python -m lipas.cli instead.
The session file is created automatically. Ollama is local but accessed through
its local HTTP service; a timeout means the local daemon/model did not answer
in time, not that LIPAS contacted the internet.
Read only what you need
- Getting started — build a small Agent, then add replay, a Team handoff, and supervision.
- Execution model — the exact semantics and limits of claims, effects, replay, external operations, and Teams.
- Examples — focused, runnable scenarios from the high level API down to the lower-level harnesses.
- Changelog — release history.
License
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 lipas-0.9.8.tar.gz.
File metadata
- Download URL: lipas-0.9.8.tar.gz
- Upload date:
- Size: 188.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86e6c682eb9134a31c4187f868c44142cfd62e34320d52f1a65a3c0686ff7e2b
|
|
| MD5 |
826d4dfbeb26da69412d4a285e685ac7
|
|
| BLAKE2b-256 |
b48ffa00280af3c062fd0792ba383cbb898e1785348ddafa551294d125723c62
|
File details
Details for the file lipas-0.9.8-py3-none-any.whl.
File metadata
- Download URL: lipas-0.9.8-py3-none-any.whl
- Upload date:
- Size: 148.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9c0b7902c796ee0bd858a66e5060802bb3a64fa9c39b47fcaf0e6a8186b1dad
|
|
| MD5 |
f3e4714ff053f6a2b10286185df76431
|
|
| BLAKE2b-256 |
2e3821b93ed2858fb8ecc9026340e1ce8c1ee03be2ffbec0f6c8eb75829c3f00
|