OpenLoom: a lightweight agent task harness — schedule, monitor, and verify AI coding tasks.
Project description
OpenLoom
Don't trust the agent's word — trust the file system.
OpenLoom is a webhook-driven task harness for OpenCode. It gives OpenCode a JSON task API, a session monitor, webhook fan-out, a web dashboard, and a file-inbox storage runner — so you can dispatch work from anywhere, even a phone.
OpenLoom does not replace OpenCode. It fills the gaps in its HTTP API.
Install
Requires Python 3.11+ and a running OpenCode server.
uv tool install openloom
That's it. Server deps, python-docx, requests — all bundled. No --with, no [extras].
Quick start
1. Start OpenCode
opencode serve
2. Configure (optional)
Defaults work out of the box with a local OpenCode on port 4096. For custom setups:
openloom init
This writes ~/.openloom/config.yaml. Edit it, or use env vars:
export OPENLOOM_OPENCODE_URL=http://127.0.0.1:4096
export OPENLOOM_OPENCODE_USERNAME=opencode
export OPENLOOM_OPENCODE_PASSWORD=your-password
3. Start OpenLoom
openloom serve
Web dashboard at http://127.0.0.1:8967. Verbose logging: openloom serve -v.
Webhook API
Dispatch a task from any HTTP client, CI pipeline, or messaging bot:
curl -X POST http://127.0.0.1:8967/api/tasks \
-H "Content-Type: application/json" \
-d '{"name": "fix-typo", "workspace": "/path/to/project", "goal": "Fix the typo in README.md"}'
Endpoints:
| Method | Path | Description |
|---|---|---|
POST |
/api/tasks |
Create and dispatch a task |
GET |
/api/tasks |
List all tasks |
GET |
/api/tasks/{id} |
Get task status |
POST |
/api/tasks/{id}/abort |
Abort a stuck session |
DELETE |
/api/tasks/{id} |
Delete a task |
GET |
/api/tasks/{id}/events |
SSE stream of task events |
Task payload
{
"name": "unique-task-name",
"workspace": "/absolute/path/to/project",
"goal": "Natural-language instruction for OpenCode"
}
Webhook notifications
OpenLoom fires webhooks on task lifecycle changes. Configure in config.yaml:
bus:
webhook_url: https://your-service.com/hooks/openloom
webhook_secret: "shared-secret"
Event payload:
{
"event": "TASK_UPDATED",
"task_name": "fix-typo",
"task_id": "abc123",
"status": "completed",
"timestamp": 1719676800,
"timestamp_iso": "2024-06-29T12:00:00+00:00",
"recent_activity": [...]
}
Storage Runner
Drop files into an inbox directory and OpenLoom dispatches them as tasks automatically.
Setup
Add a storage level to config.yaml:
levels:
storage:
path: ./inbox # directory to watch
poll_interval_s: 5 # check every 5 seconds
class: myapp.MyConnector # optional connector class
Supported formats
| Extension | Format |
|---|---|
.yaml / .yml |
Task spec (name, workspace, goal) |
.md |
Markdown — first heading as name, body as goal |
.txt |
Plain text |
.docx |
Word documents (auto-detected) |
Connectors
Storage connectors fetch task files from external sources. A connector is a Python class with a download(path) -> bytes | None method. Put it in ./connectors/:
# connectors/mysource.py
import requests
from openloom.levels.storage.base import Connector
class MyConnector(Connector):
def __init__(self):
self._session = requests.Session()
self._session.proxies = {"http": None, "https": None} # bypass system proxy
def download(self, path: str) -> bytes | None:
url = f"https://my-server/files/{path}"
r = self._session.get(url, timeout=30)
r.raise_for_status()
return r.content
Configure in config.yaml:
levels:
storage:
class: mysource.MyConnector
Dashboard
openloom serve serves a Svelte dashboard at http://127.0.0.1:8967:
- Dashboard — live task overview
- Tasks — create, browse, abort, delete tasks
- Activity — event stream with session messages
- Session drawer — inspect OpenCode sessions in real time
Configuration
Run openloom init for a starter ~/.openloom/config.yaml. Key sections:
opencode_url: "http://127.0.0.1:4096"
server:
port: 8967
bus:
webhook_url: ""
webhook_secret: ""
levels:
storage:
path: ./inbox
poll_interval_s: 5
Full reference: docs/configuration.md.
Requirements
- Python 3.11+
- OpenCode running with HTTP API enabled
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 openloom-0.17.0.tar.gz.
File metadata
- Download URL: openloom-0.17.0.tar.gz
- Upload date:
- Size: 678.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
465d26b08efb4c98b7b31a6f80ac88a0702085c0174b20370504af04f42a0521
|
|
| MD5 |
350daf404b5f74950406d6cf6f03fe38
|
|
| BLAKE2b-256 |
dbedf882d9e6c94dc5cac91903ccc20950642fb50929b3fe8adcdb037592a00b
|
Provenance
The following attestation bundles were made for openloom-0.17.0.tar.gz:
Publisher:
release.yml on atbeta/openloom
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openloom-0.17.0.tar.gz -
Subject digest:
465d26b08efb4c98b7b31a6f80ac88a0702085c0174b20370504af04f42a0521 - Sigstore transparency entry: 2128393568
- Sigstore integration time:
-
Permalink:
atbeta/openloom@1abf0a84835c1b1e4ee7f0fb99ed7e57568208a7 -
Branch / Tag:
refs/tags/v0.17.0 - Owner: https://github.com/atbeta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1abf0a84835c1b1e4ee7f0fb99ed7e57568208a7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file openloom-0.17.0-py3-none-any.whl.
File metadata
- Download URL: openloom-0.17.0-py3-none-any.whl
- Upload date:
- Size: 667.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cfe0a155d1fb5e3f43a339cc5244e3e860ef397d0cf49fc3f449cc47b7627a1f
|
|
| MD5 |
12d240416c62cf4aef9e1665edcdf5ff
|
|
| BLAKE2b-256 |
0462273cc8088736256b793efd2942cae99465b2eb1609fa51532b7bb5ff5d1c
|
Provenance
The following attestation bundles were made for openloom-0.17.0-py3-none-any.whl:
Publisher:
release.yml on atbeta/openloom
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openloom-0.17.0-py3-none-any.whl -
Subject digest:
cfe0a155d1fb5e3f43a339cc5244e3e860ef397d0cf49fc3f449cc47b7627a1f - Sigstore transparency entry: 2128393606
- Sigstore integration time:
-
Permalink:
atbeta/openloom@1abf0a84835c1b1e4ee7f0fb99ed7e57568208a7 -
Branch / Tag:
refs/tags/v0.17.0 - Owner: https://github.com/atbeta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1abf0a84835c1b1e4ee7f0fb99ed7e57568208a7 -
Trigger Event:
push
-
Statement type: