loopentx 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- loopentx-0.1.0/LICENSE +21 -0
- loopentx-0.1.0/PKG-INFO +555 -0
- loopentx-0.1.0/README.md +508 -0
- loopentx-0.1.0/loopentx/__init__.py +31 -0
- loopentx-0.1.0/loopentx/backends/__init__.py +11 -0
- loopentx-0.1.0/loopentx/backends/base.py +115 -0
- loopentx-0.1.0/loopentx/backends/memory.py +146 -0
- loopentx-0.1.0/loopentx/backends/redis_backend.py +196 -0
- loopentx-0.1.0/loopentx/cli/__init__.py +0 -0
- loopentx-0.1.0/loopentx/cli/main.py +398 -0
- loopentx-0.1.0/loopentx/core/__init__.py +28 -0
- loopentx-0.1.0/loopentx/core/config.py +67 -0
- loopentx-0.1.0/loopentx/core/context.py +362 -0
- loopentx-0.1.0/loopentx/core/events.py +35 -0
- loopentx-0.1.0/loopentx/core/exceptions.py +67 -0
- loopentx-0.1.0/loopentx/core/loop.py +240 -0
- loopentx-0.1.0/loopentx/core/memory.py +110 -0
- loopentx-0.1.0/loopentx/core/models.py +172 -0
- loopentx-0.1.0/loopentx/core/orchestrator.py +166 -0
- loopentx-0.1.0/loopentx/core/skill.py +159 -0
- loopentx-0.1.0/loopentx/llm/__init__.py +3 -0
- loopentx-0.1.0/loopentx/llm/caller.py +103 -0
- loopentx-0.1.0/loopentx/trust/__init__.py +4 -0
- loopentx-0.1.0/loopentx/trust/policy.py +185 -0
- loopentx-0.1.0/loopentx/trust/scorer.py +141 -0
- loopentx-0.1.0/loopentx.egg-info/PKG-INFO +555 -0
- loopentx-0.1.0/loopentx.egg-info/SOURCES.txt +32 -0
- loopentx-0.1.0/loopentx.egg-info/dependency_links.txt +1 -0
- loopentx-0.1.0/loopentx.egg-info/entry_points.txt +2 -0
- loopentx-0.1.0/loopentx.egg-info/requires.txt +29 -0
- loopentx-0.1.0/loopentx.egg-info/top_level.txt +1 -0
- loopentx-0.1.0/pyproject.toml +78 -0
- loopentx-0.1.0/setup.cfg +4 -0
- loopentx-0.1.0/tests/test_loopentx.py +548 -0
loopentx-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loopentx Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
loopentx-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: loopentx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Write the loop once. Step back. Loopentx runs it forever.
|
|
5
|
+
Author-email: Deepak Acharya <acharyadt260499@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/D1EE7P2U9/Loopentx-
|
|
8
|
+
Project-URL: Repository, https://github.com/D1EE7P2U9/Loopentx-
|
|
9
|
+
Project-URL: Issues, https://github.com/D1EE7P2U9/Loopentx-/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/D1EE7P2U9/Loopentx-/releases
|
|
11
|
+
Keywords: ai,agents,llm,loops,orchestration,agentic,autonomous
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: pydantic>=2.0
|
|
23
|
+
Requires-Dist: anyio>=4.0
|
|
24
|
+
Requires-Dist: httpx>=0.25
|
|
25
|
+
Requires-Dist: croniter>=2.0
|
|
26
|
+
Requires-Dist: click>=8.0
|
|
27
|
+
Requires-Dist: rich>=13.0
|
|
28
|
+
Requires-Dist: structlog>=24.0
|
|
29
|
+
Requires-Dist: python-ulid>=2.0
|
|
30
|
+
Provides-Extra: redis
|
|
31
|
+
Requires-Dist: redis[hiredis]>=5.0; extra == "redis"
|
|
32
|
+
Provides-Extra: postgres
|
|
33
|
+
Requires-Dist: asyncpg>=0.29; extra == "postgres"
|
|
34
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == "postgres"
|
|
35
|
+
Provides-Extra: openai
|
|
36
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
37
|
+
Provides-Extra: anthropic
|
|
38
|
+
Requires-Dist: anthropic>=0.25; extra == "anthropic"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
43
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
44
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
45
|
+
Requires-Dist: pre-commit>=3.7; extra == "dev"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
# Loopentx
|
|
49
|
+
|
|
50
|
+
> *Write the loop once. Step back. Loopentx runs it forever.*
|
|
51
|
+
|
|
52
|
+
[](https://badge.fury.io/py/loopentx)
|
|
53
|
+
[](https://www.python.org/downloads/)
|
|
54
|
+
[](https://opensource.org/licenses/MIT)
|
|
55
|
+
[](https://github.com/D1EE7P2U9/Loopentx-/actions)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
There's a shift happening in how developers work with AI.
|
|
60
|
+
|
|
61
|
+
- *"You shouldn't be prompting coding agents anymore. You should be designing loops that prompt your agents."* — [@steipete](https://x.com/steipete)
|
|
62
|
+
- *"I don't prompt Claude anymore. I write loops, the loops do the work."* — [@0xwhrrari](https://x.com/0xwhrrari)
|
|
63
|
+
- *"Remove yourself as the bottleneck. Arrange it once and hit go."* — [@karpathy](https://x.com/karpathy)
|
|
64
|
+
|
|
65
|
+
**Loopentx is the Python framework that makes this concrete.**
|
|
66
|
+
|
|
67
|
+
Not a prompt library. Not an agent wrapper. The infrastructure layer that lets you write a loop once — with durability, policy, trust, and memory built in — and trust it to run without you.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## The problem with existing frameworks
|
|
72
|
+
|
|
73
|
+
Every agent framework today still puts you in the loop by design.
|
|
74
|
+
|
|
75
|
+
LangGraph needs you to define the graph. CrewAI needs you to define agents and tasks. Inngest needs you to write the skills. These are excellent tools — but they all assume a human is nearby, watching, ready to intervene.
|
|
76
|
+
|
|
77
|
+
Loopentx is built around a different assumption: **you set it up once, then you're done.**
|
|
78
|
+
|
|
79
|
+
And it adds the layer every other framework is missing: **trust** — so when your loops run at 3am, you know they're doing the right thing, not just running.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Architecture
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
87
|
+
│ YOU (developer) │
|
|
88
|
+
│ Write the loop once. Step back. │
|
|
89
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
90
|
+
│
|
|
91
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
92
|
+
│ LOOPENTX FRAMEWORK │
|
|
93
|
+
│ │
|
|
94
|
+
│ ┌────────────────────────────────────────────────────────┐ │
|
|
95
|
+
│ │ LOOP LAYER │ │
|
|
96
|
+
│ │ @loop · cron/event · ctx.think() · memory · until= │ │
|
|
97
|
+
│ └───────────────────────────┬────────────────────────────┘ │
|
|
98
|
+
│ │ │
|
|
99
|
+
│ ┌───────────────────────────▼────────────────────────────┐ │
|
|
100
|
+
│ │ SKILL LAYER │ │
|
|
101
|
+
│ │ @skill · ctx.step() · retries · ctx.spawn() · hooks │ │
|
|
102
|
+
│ └───────────────────────────┬────────────────────────────┘ │
|
|
103
|
+
│ │ │
|
|
104
|
+
│ ┌───────────────────────────▼────────────────────────────┐ │
|
|
105
|
+
│ │ ORCHESTRATOR LAYER │ │
|
|
106
|
+
│ │ Scheduling · concurrency · history · hot-deploy │ │
|
|
107
|
+
│ └───────────────────────────┬────────────────────────────┘ │
|
|
108
|
+
│ │ │
|
|
109
|
+
│ ┌───────────────────────────▼────────────────────────────┐ │
|
|
110
|
+
│ │ TRUST + POLICY LAYER ✦ unique │ │
|
|
111
|
+
│ │ @policy · shadow mode · trust scoring · escalation │ │
|
|
112
|
+
│ └───────────────────────────┬────────────────────────────┘ │
|
|
113
|
+
└──────────────────────────────┼──────────────────────────────┘
|
|
114
|
+
│
|
|
115
|
+
┌────────────────────┼────────────────────┐
|
|
116
|
+
▼ ▼ ▼
|
|
117
|
+
LLM providers External tools Observability
|
|
118
|
+
OpenAI · Anthropic APIs · DBs · Slack Runs · traces
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Four layers. Most frameworks give you two. The trust layer is what makes the difference between a loop you watch and a loop you trust.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Quickstart
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pip install loopentx
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from loopentx import loop, skill, configure
|
|
133
|
+
from loopentx.trust import policy
|
|
134
|
+
from loopentx.backends import RedisBackend
|
|
135
|
+
|
|
136
|
+
configure(backend=RedisBackend("redis://localhost:6379"))
|
|
137
|
+
|
|
138
|
+
# A skill — durable, checkpointed, policy-scoped
|
|
139
|
+
@policy(can_read=["metrics_api"], can_write=["slack"], shadow_cycles=3)
|
|
140
|
+
@skill(retries=3, timeout=120)
|
|
141
|
+
async def triage_incident(ctx, services: list[str]):
|
|
142
|
+
metrics = await ctx.step("fetch", fetch_metrics, services)
|
|
143
|
+
analysis = await ctx.step("analyze", ctx.think, "What's the root cause?", context=metrics)
|
|
144
|
+
await ctx.step("notify", post_slack, analysis)
|
|
145
|
+
return analysis
|
|
146
|
+
|
|
147
|
+
# A loop — runs forever, decides what to do, invokes skills
|
|
148
|
+
@loop(every="30m", memory=True)
|
|
149
|
+
async def health_check(ctx):
|
|
150
|
+
health = await ctx.step("assess", check_health)
|
|
151
|
+
|
|
152
|
+
decision = await ctx.think(
|
|
153
|
+
"Is this health status worth waking someone up for?",
|
|
154
|
+
context=health,
|
|
155
|
+
choose_from=["act", "monitor", "skip"]
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
if decision == "act":
|
|
159
|
+
await ctx.invoke(triage_incident, services=health.affected)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
loopentx worker start --app myapp.loops
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
That's it. You're done. The loop runs every 30 minutes. If something's wrong, it triages it. If the process dies mid-execution, it resumes from the last checkpoint. If the skill misbehaves, the trust layer catches it.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Core primitives
|
|
171
|
+
|
|
172
|
+
### `@loop` — the entry point
|
|
173
|
+
|
|
174
|
+
A loop is the unit of autonomous work. It runs on a schedule or event, uses an LLM to decide what to do next, and invokes skills to do it.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
@loop(
|
|
178
|
+
every="1h", # interval: "30m", "2h", "1d"
|
|
179
|
+
cron="0 9 * * 1", # or cron expression
|
|
180
|
+
event="deploy.completed", # or event trigger
|
|
181
|
+
until=lambda ctx: ctx.memory.get("done"), # exit condition
|
|
182
|
+
max_iterations=100, # safety ceiling
|
|
183
|
+
memory=True, # persist state across runs
|
|
184
|
+
)
|
|
185
|
+
async def my_loop(ctx, **event_data):
|
|
186
|
+
...
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### `ctx.think()` — the LLM decision point
|
|
190
|
+
|
|
191
|
+
Every loop has a `think()` call. This is where the agent makes a decision. It's explicit and named — you always know where the LLM is in the loop.
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
decision = await ctx.think(
|
|
195
|
+
"Given what we know, what should we do next?",
|
|
196
|
+
context=ctx.memory.last(5),
|
|
197
|
+
choose_from=["continue", "escalate", "done"],
|
|
198
|
+
)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### `ctx.step()` — checkpointed execution
|
|
202
|
+
|
|
203
|
+
Every step is persisted. If the process restarts, completed steps are replayed from cache — not re-executed. LLM calls are never repeated. Tokens are never wasted.
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
result = await ctx.step("fetch-data", fetch_from_api, url)
|
|
207
|
+
summary = await ctx.step("summarize", call_llm, result)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### `ctx.memory` — loop-native persistence
|
|
211
|
+
|
|
212
|
+
Each loop has memory that persists across runs automatically.
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
ctx.memory.set("last_result", result)
|
|
216
|
+
ctx.memory.get("last_result")
|
|
217
|
+
ctx.memory.last(n=5) # last n run outputs
|
|
218
|
+
ctx.memory.append("log", item) # grow a list over time
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### `ctx.spawn()` — child loops
|
|
222
|
+
|
|
223
|
+
A loop can spawn another loop as a subtask. Loops supervising loops, natively.
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
# Fire and forget — parent continues immediately
|
|
227
|
+
await ctx.spawn(summarise_loop, data=chunk, wait=False)
|
|
228
|
+
|
|
229
|
+
# Wait for result — parent blocks until child completes
|
|
230
|
+
result = await ctx.spawn(deep_research_loop, topic=topic, wait=True)
|
|
231
|
+
|
|
232
|
+
# Gather multiple children in parallel
|
|
233
|
+
results = await ctx.gather([
|
|
234
|
+
ctx.spawn(worker_loop, task=t, wait=True) for t in tasks
|
|
235
|
+
])
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### `ctx.escalate()` — optional human checkpoint
|
|
239
|
+
|
|
240
|
+
Humans aren't in the loop by default. But the loop can decide to pull one in.
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
if decision == "uncertain":
|
|
244
|
+
response = await ctx.escalate(
|
|
245
|
+
"Loop hit an edge case — error rate 25% for 3 cycles. What should I do?",
|
|
246
|
+
timeout="2h", # if no response in 2h, use fallback
|
|
247
|
+
fallback="pause", # pause | continue | abort
|
|
248
|
+
)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### `@policy` — the trust layer
|
|
252
|
+
|
|
253
|
+
Declare what a skill is allowed to do. Enforced at runtime, not just documented.
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
@policy(
|
|
257
|
+
can_read=["db", "metrics_api"], # read access
|
|
258
|
+
can_write=["slack", "email"], # write/action access
|
|
259
|
+
blast_radius="medium", # low | medium | high | critical
|
|
260
|
+
shadow_cycles=5, # dry runs before going live
|
|
261
|
+
require_approval=False, # auto-approve if blast_radius=low
|
|
262
|
+
)
|
|
263
|
+
@skill(retries=3)
|
|
264
|
+
async def my_skill(ctx, ...):
|
|
265
|
+
...
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## The three loop patterns
|
|
271
|
+
|
|
272
|
+
Loopentx is designed around the three patterns that come up again and again in real agentic systems.
|
|
273
|
+
|
|
274
|
+
### Pattern 1 — The heartbeat loop
|
|
275
|
+
|
|
276
|
+
*Boris's model: "I write loops, the loops do the work."*
|
|
277
|
+
|
|
278
|
+
Runs on a schedule. Checks state. Acts if needed. Never needs prompting.
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
@loop(every="1h", memory=True)
|
|
282
|
+
async def monitor_loop(ctx):
|
|
283
|
+
state = await ctx.step("check", fetch_state)
|
|
284
|
+
decision = await ctx.think("Is action needed?", context=state,
|
|
285
|
+
choose_from=["act", "skip"])
|
|
286
|
+
if decision == "act":
|
|
287
|
+
await ctx.invoke(handle_anomaly, state=state)
|
|
288
|
+
ctx.memory.append("actions_taken", state)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Pattern 2 — The research loop
|
|
292
|
+
|
|
293
|
+
*Andrej's model: "Maximize token throughput. Remove yourself as the bottleneck."*
|
|
294
|
+
|
|
295
|
+
Runs until a goal is reached, not until a human says stop. Self-improving across iterations.
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
def confident_enough(ctx) -> bool:
|
|
299
|
+
return ctx.memory.get("confidence", 0) > 0.85
|
|
300
|
+
|
|
301
|
+
@loop(until=confident_enough, max_iterations=50, memory=True)
|
|
302
|
+
async def research_loop(ctx, topic: str):
|
|
303
|
+
prior = ctx.memory.get("findings", [])
|
|
304
|
+
findings = await ctx.step("search", search_and_read, topic, prior)
|
|
305
|
+
synthesis = await ctx.step("synthesize", ctx.think,
|
|
306
|
+
"How confident are we? What's missing?",
|
|
307
|
+
context=findings)
|
|
308
|
+
ctx.memory.set("confidence", synthesis.confidence)
|
|
309
|
+
ctx.memory.append("findings", synthesis.result)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Pattern 3 — The supervisor loop
|
|
313
|
+
|
|
314
|
+
*Steipete's model: "Design loops that prompt your agents."*
|
|
315
|
+
|
|
316
|
+
A parent loop breaks work into subtasks, spawns child loops, and collects results.
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
@loop(cron="0 9 * * 1") # Every Monday 9am
|
|
320
|
+
async def supervisor_loop(ctx):
|
|
321
|
+
tasks = await ctx.step("plan", decompose_goal, weekly_goal)
|
|
322
|
+
results = await ctx.gather([
|
|
323
|
+
ctx.spawn(worker_loop, task=t, wait=True) for t in tasks
|
|
324
|
+
])
|
|
325
|
+
report = await ctx.step("report", synthesize_results, results)
|
|
326
|
+
await ctx.step("send", email_report, report)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## What makes Loopentx different
|
|
332
|
+
|
|
333
|
+
| | LangGraph | CrewAI | Inngest | Agentex | **Loopentx** |
|
|
334
|
+
|----------------------------------------|-----------|--------|---------|---------|--------------|
|
|
335
|
+
| Core primitive | Graph | Agent crew | Function | Skill | **Loop** |
|
|
336
|
+
| Philosophy | You define the graph | You define agents | You define functions | You define policy | **You define the loop, then leave** |
|
|
337
|
+
| Step checkpointing | Partial | ❌ | ✅ | ✅ | **✅** |
|
|
338
|
+
| Loop memory | ❌ | ❌ | ❌ | ❌ | **✅** |
|
|
339
|
+
| Exit conditions | Manual | Manual | Manual | Manual | **Native primitive** |
|
|
340
|
+
| Child loops | ❌ | ❌ | ✅ | ✅ | **✅** |
|
|
341
|
+
| `ctx.think()` — explicit LLM decision | ❌ | ❌ | ❌ | ❌ | **✅** |
|
|
342
|
+
| Trust scoring | ❌ | ❌ | ❌ | ✅ | **✅** |
|
|
343
|
+
| Shadow mode | ❌ | ❌ | ❌ | ✅ | **✅** |
|
|
344
|
+
| Capability scoping | ❌ | ❌ | ❌ | ✅ | **✅** |
|
|
345
|
+
| Human escalation (opt-in) | ❌ | ⚠️ | ❌ | ⚠️ | **✅** |
|
|
346
|
+
| Python-first | ✅ | ✅ | ❌ | ✅ | **✅** |
|
|
347
|
+
|
|
348
|
+
The key distinction: every other framework puts a human in the design loop. Loopentx puts you in the *setup* loop and takes you out of the *execution* loop.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## How agents run on their own
|
|
353
|
+
|
|
354
|
+
This is the core question. Here's exactly what happens after you run `loopentx worker start`:
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
1. You wrote the loop. You started the worker. You're done.
|
|
358
|
+
|
|
359
|
+
2. Loopentx scheduler fires the loop at the configured time/event.
|
|
360
|
+
|
|
361
|
+
3. The loop runs ctx.think() → LLM evaluates state and decides what to do.
|
|
362
|
+
(You are not consulted. The LLM decides.)
|
|
363
|
+
|
|
364
|
+
4. The loop calls ctx.step() for each action.
|
|
365
|
+
Each step is checkpointed — if the process dies here, it resumes.
|
|
366
|
+
LLM calls inside steps are never repeated.
|
|
367
|
+
|
|
368
|
+
5. If a step fails → automatic retry with exponential backoff.
|
|
369
|
+
If all retries fail → on_failure hook fires, run is logged.
|
|
370
|
+
|
|
371
|
+
6. If the loop spawns a child → child runs with its own checkpointing.
|
|
372
|
+
Parent waits (if wait=True) or continues independently.
|
|
373
|
+
|
|
374
|
+
7. Exit condition is evaluated after each iteration.
|
|
375
|
+
If met → loop stops. Result is stored. Notification sent if configured.
|
|
376
|
+
If not met → loop sleeps until next scheduled time.
|
|
377
|
+
|
|
378
|
+
8. Trust layer runs in background:
|
|
379
|
+
- Tracks success/failure rate per skill
|
|
380
|
+
- Shadow mode intercepts write actions until cycles complete
|
|
381
|
+
- Trust score updates hourly
|
|
382
|
+
- Skills below threshold flagged for human review
|
|
383
|
+
|
|
384
|
+
9. You check the dashboard in the morning.
|
|
385
|
+
You see what ran, what succeeded, what failed, what the LLM decided.
|
|
386
|
+
You own the loop. You just don't have to watch it.
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## CLI reference
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
# Worker
|
|
395
|
+
loopentx worker start --app myapp.loops # start the execution worker
|
|
396
|
+
loopentx worker status # check worker health
|
|
397
|
+
|
|
398
|
+
# Deploy
|
|
399
|
+
loopentx deploy loop my_loop --app myapp.loops
|
|
400
|
+
loopentx deploy skill my_skill --app myapp.loops
|
|
401
|
+
|
|
402
|
+
# Inspect
|
|
403
|
+
loopentx inspect loop my_loop # status, memory, run history
|
|
404
|
+
loopentx inspect skill my_skill # trust score, policy, recent runs
|
|
405
|
+
|
|
406
|
+
# Runs
|
|
407
|
+
loopentx runs list --last 7d # recent runs
|
|
408
|
+
loopentx runs inspect <run-id> # full step trace
|
|
409
|
+
loopentx runs replay <run-id> # replay a failed run
|
|
410
|
+
|
|
411
|
+
# Trust
|
|
412
|
+
loopentx trust list # trust scores for all skills
|
|
413
|
+
loopentx trust approve my_skill # approve for live execution
|
|
414
|
+
loopentx trust reject my_skill # pause and reject
|
|
415
|
+
|
|
416
|
+
# Memory
|
|
417
|
+
loopentx memory show my_loop # view loop memory
|
|
418
|
+
loopentx memory clear my_loop # reset loop memory
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Integrations
|
|
424
|
+
|
|
425
|
+
Loopentx is designed to sit alongside your existing stack, not replace it.
|
|
426
|
+
|
|
427
|
+
**With LangGraph** — use LangGraph to define agent graph structure; use Loopentx to make each graph execution durable and policy-scoped:
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
@policy(can_write=["db"], blast_radius="medium")
|
|
431
|
+
@skill(retries=3)
|
|
432
|
+
async def run_langgraph_agent(ctx, state: dict):
|
|
433
|
+
result = await ctx.step("execute", my_lg_graph.invoke, state)
|
|
434
|
+
return result
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**With CrewAI** — use CrewAI for multi-agent conversation; use Loopentx to schedule and govern the crew execution:
|
|
438
|
+
|
|
439
|
+
```python
|
|
440
|
+
@loop(cron="0 8 * * *", memory=True)
|
|
441
|
+
async def run_daily_crew(ctx):
|
|
442
|
+
result = await ctx.step("crew", my_crew.kickoff, {"topic": ctx.memory.get("topic")})
|
|
443
|
+
ctx.memory.set("last_output", result)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**With OpenAI / Anthropic directly** — `ctx.think()` calls your configured LLM provider. Swap providers in config, loops stay unchanged.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Installation
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
# Core
|
|
454
|
+
pip install loopentx
|
|
455
|
+
|
|
456
|
+
# With Redis backend (production)
|
|
457
|
+
pip install loopentx[redis]
|
|
458
|
+
|
|
459
|
+
# With Postgres backend
|
|
460
|
+
pip install loopentx[postgres]
|
|
461
|
+
|
|
462
|
+
# With OpenAI
|
|
463
|
+
pip install loopentx[openai]
|
|
464
|
+
|
|
465
|
+
# With Anthropic
|
|
466
|
+
pip install loopentx[anthropic]
|
|
467
|
+
|
|
468
|
+
# Full dev install
|
|
469
|
+
pip install loopentx[dev]
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Examples
|
|
475
|
+
|
|
476
|
+
See [`examples/`](./examples/) for complete working code:
|
|
477
|
+
|
|
478
|
+
| Example | Pattern | Demonstrates |
|
|
479
|
+
|---------------------------|-----------------|-------------------------------------------|
|
|
480
|
+
| `examples/heartbeat/` | Heartbeat loop | Monitoring, cron, ctx.think() |
|
|
481
|
+
| `examples/research/` | Research loop | until=, memory, confidence scoring |
|
|
482
|
+
| `examples/supervisor/` | Supervisor loop | ctx.spawn(), ctx.gather(), child loops |
|
|
483
|
+
| `examples/health_monitor/`| Combined | All four layers, shadow mode, trust |
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Configuration
|
|
488
|
+
|
|
489
|
+
```python
|
|
490
|
+
# loopentx_config.py
|
|
491
|
+
from loopentx import configure
|
|
492
|
+
from loopentx.backends import RedisBackend
|
|
493
|
+
|
|
494
|
+
configure(
|
|
495
|
+
backend=RedisBackend(url="redis://localhost:6379"),
|
|
496
|
+
llm_provider="anthropic", # "openai" | "anthropic" | "custom"
|
|
497
|
+
llm_model="claude-sonnet-4-6",
|
|
498
|
+
llm_api_key="sk-ant-...", # or set ANTHROPIC_API_KEY env var
|
|
499
|
+
|
|
500
|
+
# Trust defaults
|
|
501
|
+
default_shadow_cycles=0,
|
|
502
|
+
auto_approve_low_blast=True,
|
|
503
|
+
|
|
504
|
+
# Worker
|
|
505
|
+
worker_concurrency=10,
|
|
506
|
+
worker_poll_interval=1.0,
|
|
507
|
+
)
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## Roadmap
|
|
513
|
+
|
|
514
|
+
- [x] `@loop` with cron, event, and interval triggers
|
|
515
|
+
- [x] `ctx.think()` — explicit LLM decision point
|
|
516
|
+
- [x] `ctx.step()` — step checkpointing
|
|
517
|
+
- [x] `ctx.memory` — loop-native persistence
|
|
518
|
+
- [x] `ctx.spawn()` — child loops and ctx.gather()
|
|
519
|
+
- [x] `ctx.escalate()` — optional human checkpoint
|
|
520
|
+
- [x] `@skill` with retries, timeout, on_failure
|
|
521
|
+
- [x] `@policy` — capability scoping, shadow mode, blast radius
|
|
522
|
+
- [x] Trust scoring — UNTRUSTED → AUTONOMOUS pipeline
|
|
523
|
+
- [x] Memory backend (in-memory + Redis)
|
|
524
|
+
- [x] CLI — deploy, inspect, runs, trust, worker
|
|
525
|
+
- [ ] Postgres backend
|
|
526
|
+
- [ ] Web dashboard (run history, trust scores, memory viewer)
|
|
527
|
+
- [ ] Temporal adapter
|
|
528
|
+
- [ ] Loop authoring agent (agent writes its own loops, trust pipeline validates)
|
|
529
|
+
- [ ] Evaluation suite integrations
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Contributing
|
|
534
|
+
|
|
535
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md). The project is young — issues, PRs, and ideas are all welcome.
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
git clone https://github.com/D1EE7P2U9/Loopentx-
|
|
539
|
+
cd Loopentx-
|
|
540
|
+
pip install -e ".[dev]"
|
|
541
|
+
pytest tests/
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## Why "Loopentx"?
|
|
547
|
+
|
|
548
|
+
Loop + agent + execution. The framework for loops that run without you.
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## License
|
|
553
|
+
|
|
554
|
+
MIT — see [LICENSE](./LICENSE)
|
|
555
|
+
|