framework

Gloo Framework

Fluent shell pipes for Go. Gloo expresses the Unix pipeline model as type-safe, composable Go values. A command is a value — you assign it, pass it around, and compose it — and the pipeline you build reads like a shell one-liner while staying fully typed, concurrent, and testable without ever touching real I/O.

gloo.Run(
    gloo.SliceSource([]string{"error: a", "info: b", "error: c"}),
    gloo.WriteTo(os.Stdout),
    grep("error"),          // a Command[string, string]
    patterns.Head[string](1),
)
// error: a

That’s the whole idea: a source of data, a chain of commands that transform it, and a sink that consumes it — connected by a stream that behaves exactly like a shell pipe, down to the SIGPIPE-style teardown when a downstream stage stops early.

Built on rill for stream plumbing and afero for filesystem abstraction.

Modulegithub.com/gloo-foo/framework
Packagegloo (+ subpackage gloo-foo/framework/patterns)
API referencepkg.go.dev/github.com/gloo-foo/framework

The one mental model

Everything in gloo is this shape:

 Source ──▶ Command ──▶ Command ──▶ … ──▶ Sink
        Stream[A]    Stream[B]      Stream[Y]

Hold that picture and the rest of the framework falls into place. The four types are defined in framework.go; they’re explored in depth on The Pipeline Model.


Which reader are you?

Gloo has two audiences. Pick your track — they share the vocabulary above but touch different parts of the API.

🧑‍🍳 Command Users — compose and run

You take prebuilt commands and wire them into pipelines. You never see rill, never write a FuncCommand, never touch a raw stream. This is the product; everything else exists to make it pleasant.

For Command Users

🔧 Command Authors — build the commands

You write the commands Users compose. You pick a pattern and supply only your algorithm — the pattern owns all stream wiring, channels, and cancellation.

For Command Authors

Whichever you are, read Concurrency & Lifecycle once. It’s short, it’s the framework’s most carefully engineered guarantee, and it explains why a gloo pipeline tears down cleanly the way a shell pipe does — with no way to leak a goroutine.


Sixty-second start

package main

import (
    "os"
    "strings"

    gloo "github.com/gloo-foo/framework"
    "github.com/gloo-foo/framework/patterns"
)

func main() {
    // A command is just a value built from a pattern.
    shout := patterns.Map(func(line string) (string, error) {
        return strings.ToUpper(line), nil
    })

    // Compose a source, a sink, and commands; run once.
    gloo.Run(
        gloo.SliceSource([]string{"hello", "world"}),
        gloo.WriteTo(os.Stdout),
        shout,
    )
    // HELLO
    // WORLD
}

To run a pipeline as a real Unix filter (stdin → stdout), use Pump.


Map of the wiki

PageWhat it coversFor
The Pipeline ModelThe four core types, how data flows, lazy vs. eager wiring, values vs. buildersEveryone
For Command UsersRun, Chain, Compose, Pipe, Pump; the error modelUsers
For Command AuthorsThe pattern catalog + decision matrix; building commands; FuncCommand for exotic casesAuthors
Concurrency & LifecycleThe teardown contract, Discard, silent stop vs. surfaced cancellation, what’s safe to shareEveryone
Errors & TestingSentinel errors, how errors flow, testing commands with in-memory streamsEveryone

Resources