0.5.2 · work in progress

Write a task once.
Run it anywhere.

Every team rewrites the same ten pipelines. Build, tag, push, deploy — the same work, copied between projects and companies, then translated again into each CI's YAML. Oren turns each step into a contract: inputs, outputs and dependencies declared, with interchangeable implementations — running identically on your laptop, on GitLab, on GitHub or on Cloud Build.

The problem

Reusing a pipeline today means copy and paste

"Analyse commits and decide the next version" is the same task in every repository in the world. Yet every team rewrites it from scratch, tied to their CI's primitives, with no way to say what it takes in and what it gives back.

With no contract there is no substitution: swapping the implementation means rewriting the pipeline. There is no comparison either — two solutions to the same problem are not comparable if they do not even describe the same problem. And there is no reuse between organisations, because there is nothing to reuse beyond a YAML file.

Portability

The pipeline does not belong to your CI

A pipeline written in GitLab CI only runs on GitLab. Reproducing it on your machine means guessing what the runner does, and moving platform means rewriting everything. In Oren the pipeline is a single file, and where it runs is a separate decision.

# on your machine, the same thing that runs in production
oren run dev

# or generate your platform's native configuration
oren generate gitlab     > .gitlab-ci.yml
oren generate github     > .github/workflows/ci.yml
oren generate cloudbuild > cloudbuild.yaml

Both paths run exactly the same containers, with the same contracts.

A two-step pipeline: build and publish. The publish implementation cycles through publish-gcp, publish-azure and publish-aws, pointing at GCP, Azure and AWS, while the contract stays the same. The view then zooms out and shows the same pipeline running on a laptop, on GitLab CI and on GitHub Actions. Laptop GitLab CI GitHub Actions build docker-build-kaniko publish publish-gcp publish-azure publish-aws GCP Azure AWS
The contract does not change. Switching cloud means switching one step’s implementation; switching CI means changing nothing.

Local first

Run the whole pipeline before committing. No test push, no waiting in a runner queue to find out about a typo.

Native when you want it

Generation produces one job per step, making use of the platform's parallelism, cache and interface — without you writing its YAML.

No lock-in

Moving from GitLab to GitHub, or between clouds, does not rewrite the pipeline. Only the generation target changes.

This works because dependencies are typed. The generator knows that a secret/gcp-service-account becomes a protected variable on GitLab, a secret on GitHub Actions or a Secret Manager reference on Cloud Build. A bare file path would tell nobody any of that.

The idea

A task is a contract. A worker is one way of fulfilling it.

The contract declares what goes in, what comes out and which resources of the environment the task needs — and nothing about how the work gets done. That is each implementation's choice, and it is why they can be swapped without the pipeline changing a line.

# the contract — published once
apiVersion: oren.sh/v1
kind: Task
metadata:
  name: analyze-commits
  namespace: oren
  version: 1.0.0
spec:
  inputs:
    properties:
      defaultChange:
        type: string
        enum: [major, minor, patch, none]
  outputs:
    properties:
      change: { type: string }
      minor:  { type: boolean }
  dependencies:
    source:
      type: git-repository

The contract mentions no language, no image and no path.

# the pipeline, in your repository
steps:
  - id: analyze
    task: techlite/analyze-commits@^1.0.0
    inputs:
      defaultChange: minor
    dependencies:
      source: "."

  - id: build
    task: techlite/build-docker-image@^1.0.0
    inputs:
      imageName: acme/api
      incrementMinor: ${outputs['analyze'].minor}
    dependencies:
      source: "."

One task's output is the next one's input, with types checked.

Execution

A worker is an image that reads one file and writes another

There is no mandatory SDK, no preferred language and no API to implement. The CLI mounts the dependencies, writes the inputs to disk and reads the output. That is the whole protocol:

# a complete worker, in shell
. /oren/oren.sh

IMAGE=$(oren_input .imageName)
docker build -t "$IMAGE" /source
oren_output image "$IMAGE"

The first line loads the SDK, a shell file copied into the image — nothing is injected. stdout and stderr stay free for logging: they carry no data.

Isolated

Everything runs in a container, orchestrated by Dagger. Nothing is installed on the machine that runs it.

Reproducible

An oren.lock pins the contract, the implementation and the image digest. The same pipeline today and a year from now.

Verified

Inputs and outputs are validated against the contract. An output outside the declared format fails the step, even with exit code zero.

Dependencies

What a task asks of your environment is explicit

Folders, credentials and access to Docker are not configuration details — they are the cost of running that worker on your machine. Every dependency is declared and typed, and the CLI grants exactly what was declared. Nothing more.

TypePrivilege
git-repositorylowa directory, read only
secret/git-tokenmediumrepository access token
secret/gcp-service-accounthighservice account key
engine/dockercriticalthe daemon socket — equivalent to root on the host

This makes two implementations of the same contract genuinely comparable. If both build the same image and one requires the Docker socket while the other uses kaniko, the difference stops being invisible — and the choice becomes an informed one.

Credentials do not need to be registered anywhere. If your organisation already uses Vault or Secret Manager, fetching the secret is just one more task at the start of the pipeline. Values marked as sensitive never appear in logs, never reach the lockfile and never touch the machine's disk.

Portal

An open catalogue between organisations

Contracts published by one organisation can be implemented by any other. That is what stops the original problem from coming back at another scale: if every company had to write its own contract, we would be back to ten versions of the same thing.

  • Discover

    Find the task that does what you need and compare the available implementations side by side.

  • Add

    oren add techlite/build-docker-image writes the step, resolves the implementation and points at what is left to configure.

  • Or implement

    oren init worker scaffolds a whole task — contract, worker, implementation and an example pipeline — in shell or Node.

Published versions are immutable and never disappear; they are only deprecated. Private implementations remain possible for whoever has an internal process to protect, while the contract stays public — and with it, comparability.

Get started

Three commands

# the CLI
npm install -g @oren-sh/cli

# a project, and a task from the catalogue
oren init
oren add techlite/analyze-commits

# runs on your machine, from the same file that runs in CI
oren run dev

To publish your own, oren login and oren publish. The example workers live under techlite/*. Whoever publishes a contract does not choose who implements it — any organisation can, and that is what gives consumers an alternative.

How to use it

Two ways, and the CLI is the same

The oren.yaml does not change between them. What changes is where the catalogue lives — and the oren.lock guarantees that, once resolved, running depends on no catalogue at all.

On your infrastructure

on-premise · free

A jar and a Postgres. Your catalogue, your accounts, your data — nothing leaves your network, and private tasks stay private because the server is yours.

It is the same software, not a cut-down edition. Available now.

Hosted by us

managed · free for public tasks

No server to maintain. Publish to the open catalogue and use what other organisations have published — a contract can be implemented by any of them, and that is what gives consumers an alternative.

Not up yet.

You can also use it with no catalogue at all: tasks coming from a directory in your own repository, resolved by path. It is how a worker is written before it is published.

Who uses it

In production today

Techlite. Maintains and publishes the reference workers under techlite/* — analysing commits, building and pushing images, Terraform, Cloud Deploy — and runs delivery pipelines built from them: version derived from conventional commits, two images published to Artifact Registry, and a release created through Cloud Deploy, from the same file that runs on a laptop.

This is version 0.5.2. Published versions are already immutable, but the document format may still change before 1.0.