A factory for producing artifacts under governance — provenance, ownership, authorization, and an append-only audit trail on every output.
Project description
open-refinery
An open factory to shine light into the dark.
A self-hosted dark factory that adds auditability to make it open. Work ships through customizable processes; every output carries its provenance, an owner, and an audit trail; every production is authorized before it runs and logged as it happens.
Status: 0.3.0 — in development. Server, token auth (developer / platform / admin), repositories, processes (steps + feedback loops), work items with a governed transition loop, oversight levels (L0–L4) with approvals, and an audit trail are working and tested. OAuth, the web dashboard, metrics, and policy governance are on the roadmap.
Quickstart
Requires Python 3.11+. SQLite ships with Python — there is no separate database to install.
pip install open-refinery # or: uv pip install open-refinery
open-refinery serve # server + dashboard on port 8000
Open http://your-host:8000 — on a fresh instance the dashboard walks you
through creating the first admin (no CLI needed), then signs you in. From there,
manage repos, processes, work, oversight, and the audit trail. The UI (React +
shadcn/ui, light/dark/auto themes) is bundled in the package — no Node to run.
Prefer the CLI to seed the admin? open-refinery create-admin --email you@x.dev
still works.
Background it on a VPS however you like — &, nohup, screen, tmux, or
your process manager:
open-refinery serve --port 9000 & # or: PORT=9000 open-refinery serve
curl localhost:9000/health # {"status": "ok"}
Using the API
Authenticate every request with the admin token from create-admin:
TOKEN=<paste the token>
H="Authorization: Bearer $TOKEN"
# register a repository (a repo = a project, whatever the code architecture)
curl -s -H "$H" localhost:9000/repositories \
-d '{"name":"my-app","git_url":"git@github.com:me/my-app.git"}'
# define a process: steps + oversight (dark = lights-out; assisted needs approval)
curl -s -H "$H" localhost:9000/processes \
-d '{"name":"remediate","archetype":"doctrine",
"stages":["detect","triage","patch","verify","close"],
"transitions":[["detect","triage"],["triage","patch"],["patch","verify"],
["verify","close"],["verify","patch"]],
"oversight":"supervised","gates":["close"]}'
# ship work through it, then move it a step (approve=true when a gate needs sign-off)
curl -s -H "$H" localhost:9000/work-items \
-d '{"repo_id":"<repo>","process_id":"<proc>","title":"CVE-1234"}'
curl -s -H "$H" localhost:9000/work-items/<item>/transition -d '{"to":"triage"}'
# read the audit trail — every move, owned and attributed
curl -s -H "$H" "localhost:9000/events?subject=<item>"
Config is env-only, all optional: PORT (or --port), DATABASE_URL
(sqlite:///open-refinery.db default), LOG_LEVEL.
Sign in with GitHub (optional)
Set these and the dashboard shows a "Sign in with GitHub" button:
export GITHUB_CLIENT_ID=... # from your GitHub OAuth App
export GITHUB_CLIENT_SECRET=...
export APP_BASE_URL=https://or.example.com # optional; used to build the callback
Register the OAuth App's callback as <APP_BASE_URL>/auth/github/callback.
A GitHub login is accepted only when its verified primary email matches an
existing user — provision accounts first (an admin creates them in the UI);
unknown emails are denied. The OAuth client id/secret are the one bit of config
that must be env (they're needed before anyone can log in). API/CI accounts keep
using tokens.
Library
open-refinery is also an embeddable core — the same governed-production loop without the server:
from open_refinery import Factory
factory = Factory()
@factory.recipe("upper")
def upper(text: str) -> str:
return text.upper()
artifact, record = factory.produce("upper", actor="ian", text="hello")
open-refinery demo prints one such record.
Pillars
| Pillar | Where it lives |
|---|---|
| Authorization | Authorizer (AllowAll, AllowList) — checked before produce |
| Provenance | Record — recipe, actor, timestamp, input/output digests |
| Ownership | owner on every record (defaults to the actor) |
| Auditability | AuditSink (MemorySink, JsonlSink) — append-only trail |
| Logging | stdlib logging, logger name open_refinery |
| Oversight | Per-process autonomy levels L0–L4; gated steps need recorded approvals |
| Observability | GET /metrics — WIP, event counts, per-actor activity, lead times over the audit trail |
| Governance | (roadmap) policy layer that constrains what may be produced |
Durable audit trail
from open_refinery import Factory, JsonlSink
factory = Factory(audit=JsonlSink("audit.jsonl"))
Each production appends one JSON line — a replayable record of who produced what, from which inputs, and when.
Development
make install # backend: uv sync --extra dev
make test # uv run pytest
make serve # run the server locally
make help # list all tasks
open-refinery seed # populate a fresh DB with sample data + login tokens (dev)
Frontend (dashboard) lives in frontend/ — React + TypeScript + Vite + Tailwind
- shadcn/ui, built with bun:
make ui-dev # Vite dev server (proxies API to :8000)
make ui # build the SPA into the package
make dist # build UI + wheel (the wheel bundles the SPA)
The build step is release-time only; end users never need bun/node.
See PLAN.md, CONTRIBUTING.md, and docs/ARCHITECTURE.md.
License
MIT © Ian Johnson
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 open_refinery-0.3.0.tar.gz.
File metadata
- Download URL: open_refinery-0.3.0.tar.gz
- Upload date:
- Size: 336.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0390b574c4074202bc397a802dbb0ead454f84b10193e6b47506eee5ec1a186
|
|
| MD5 |
efb99d830afd13954b8bd8884fdc5e55
|
|
| BLAKE2b-256 |
19d4bc8272a8142d1fa721c746556c379b786a1316b474961f055f7e6b5e1a4c
|
File details
Details for the file open_refinery-0.3.0-py3-none-any.whl.
File metadata
- Download URL: open_refinery-0.3.0-py3-none-any.whl
- Upload date:
- Size: 251.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62c61c25daa29c22889659345d71992e769fe6e0aeeeca1ad19806f21b6d7f29
|
|
| MD5 |
a3fdd61d5667453ccb4a2c7232123a7f
|
|
| BLAKE2b-256 |
f866f2d34c64d2a1513446769e8ef3926fc86c5e06993c6c1787d5f98ae2ab95
|