Getting Started
Build your first command in 5 minutes.
Install the framework
shell
go get github.com/gloo-foo/framework Zero transitive dependencies beyond rill for concurrent streams and afero for testable filesystem access.
Choose a pattern
Every command maps to one of 7 patterns. For your first command, use Map — the simplest. One in, one out.
| I want to… | Pattern |
|---|---|
| Transform each item | Map |
| Filter items | Filter |
| Collect and reorder | Accumulate |
| Reduce to summary | Aggregate |
| Split into many | Expand |
See all 7 patterns →
Implement a command
Build uppercase — converts each line to upper case:
go
func Uppercase(opts ...any) gloo.Command[[]byte, []byte] { return patterns.Map(func(line []byte) ([]byte, error) { return bytes.ToUpper(line), nil }) } One function, one pattern, zero boilerplate.
Write tests
Test without touching the filesystem:
go
func TestUppercase(t \*testing.T) { source := gloo.SliceSource([][]byte{ []byte("hello"), []byte("world"), })
results, _ := gloo.Chain(source).
To(Uppercase()).
Collect()
// results.([][]byte) == {[]byte("HELLO"), []byte("WORLD")}
} No files, no I/O, no mocks. Pure in-memory streams.
Compose into a pipeline
Import command aliases and compose with Run or Chain:
go
// Run: source, sink, then commands gloo.Run(source, gloo.ByteWriteTo(os.Stdout), grep.Grep("error", grep.IgnoreCase), sort.Sort(sort.Reverse), uniq.Uniq(uniq.Count), )
// Chain: fluent builder gloo.Chain(source). To(grep.Grep("error", grep.IgnoreCase)). To(sort.Sort(sort.Reverse)). To(uniq.Uniq(uniq.Count)). Sink(gloo.ByteWriteTo(os.Stdout)) Commands are values. Pipelines are composition.
Next steps
You’ve built a command, tested it without I/O, and composed it into a pipeline. Now explore:
- All 7 patterns → — understand the full pattern system
- 44 commands → — see every reimplemented Unix tool
- Pipeline recipes → — real-world examples