GitHub - ramayac/GoPOSIX: A Go-native, single-binary POSIX userland with 100+ tools. Runs as a persistent JSON-RPC daemon or multicall CLI, backed by >98% Busybox test compatibility.

5 min read Original article ↗

A Go-native, single-binary POSIX userland with 115 tools. Runs as a persistent JSON-RPC daemon or multicall CLI, a typed Go SDK and ~98.2% BusyBox test compatibility (878 of 919 tests pass).

CI Go Reference Go Report Card codecov Go Version License Docker

Why?

Well, I wanted to do an experiment on Harsness Engineering, and improve my "agentic development" skills, prompts, instructions and all that. I did LFS in my early 20's and I had this weird itch of "do your own thing" but left it alone for my own sanity. Still the POSIX concepts remained in the back of my head. Last year (2025) I started to learn Go-lang, and then LLMs got really good in December 2025. Good enough that I've been using it at work non stop since then.

During that time I got this notion that AI waste time formating output, so I started doing --json output in a lot of my work scripts and tools (to save some time for my robot friends). Eventually all of these random ideas boiled to the conclusion that I should make a complete implementation of POSIX utilities in Go, with a JSON output and a Go SDK, and then benchmark it against BusyBox. It's the "natural conclusion" ... right?

Also deepseek-v4-pro had an very agressive 75% discount!, and I wanted to try pi.dev instead of Antigravity/ClaudeCode (I ended up using agy for some auditing).

All things kind of aligned in the last month so here we are now.

I'm not the first to start something like this, there is cugo and go-posix, but sadly they seem to be abandoned, and no wonder! A project like this is a huge undertaking, its probably a year of solid work for 1 human, that being said, took about 3 weeks to do with AI, with the proper "harness" and "agentic development" approach, that's really something.

Anyway the project got into a point that I'm happy with the results, that's enough for me ☑️.

Honest and Obvious Recognitions

I want to be very clear about this:

The only reason this works is that there's a brutally thorough, existing corpus of tests to validate against. The AI iterated until it passed. Without BusyBox's tests, this project is just random hallucinated code. The test suite is the real hero.

Finally: let's not kid ourselves, this project is 90% wiring the AI to do the heavy lifting, 10% is steering it in the right direction, the fact that I was able to "solo dev" this with an LLM, reproducing close to 99% of BusyBox's behavior in a completely different language shows that POSIX utilities are, at their core, text transformers with very well-defined contracts (do one thing and do it well).

Does it work?

Yes! yes it does! see how GoPOSIX replaces BusyBox in Alpine here: docker/Dockerfile (target: alpine-mvp).

Quickstart

See wiki/sdk.md for the full Go SDK guide and wiki/usage.md for CLI usage and Docker recipes.

CLI (secondary)

docker pull ghcr.io/ramayac/goposix:cli
docker run --rm ghcr.io/ramayac/goposix:cli ls --json /

Build & Test

make all          # vet + test + build
make test         # unit tests
make testsuite    # BusyBox integration tests (gates every commit)
make ci           # full pipeline (test + testsuite + coverage + docker)

Environment Variables

Daemon & CLI Configuration

Variable Default Description
GOPOSIX_SOCKET /var/run/goposix.sock Daemon UNIX socket path for CLI forwarding and client SDK connections
GOPOSIX_DEBUG (empty) Set to 1 to enable verbose JSON-RPC request/response debug logging to stderr
GOPOSIX_SHELL_TIMEOUT 30s Shell execution timeout (Go duration format, e.g. 60s, 5m)
GOPOSIX_MAX_REQUEST_SIZE 1048576 (1MB) Max JSON-RPC request size in bytes
GOPOSIX_RATE_LIMIT 100 Max JSON-RPC requests/sec per connection
GOPOSIX_SHUTDOWN_TIMEOUT 5s Graceful shutdown drain timeout
GOPOSIX_LS_CACHE_TTL 30s Time-to-Live for ls owner/group name string translation caching (Go duration format, e.g., 30s, 1m)

Standard POSIX Environment Variables

Variable Description
TZ Standard timezone rule parsed dynamically by date and tar to format and project timestamps
LOGNAME Current login username retrieved by logname
PWD Logical working directory used by readlink to resolve symlinks component-by-component

Daemon Stdin

The JSON-RPC daemon accepts a stdin field in request params, enabling stdin-consuming utilities (grep, sed, sort, wc, tr, head, tail, cut, tee, uniq, and 30+ others) to receive input directly through the Go SDK without temp files.

// Pass stdin through the daemon
c.Grep(ctx, []string{"foo"}, client.WithStdin("line1\nline2\nfoo\n"))
c.Wc(ctx, []string{"-l"}, client.WithStdin("line1\nline2\nline3\n"))

Performance

Metric GoPOSIX BusyBox
Per-call latency (Go SDK, persistent) ~60µs ~680µs (fork+exec)
Large-file grep significantly faster baseline
Binary size ~10 MB ~800 KB
Cold start ~7ms <1ms

Numbers above are approximate. For reproducible benchmarks with scale factors and full methodology, see wiki/performance.md.

Documentation

Quick Project Principles

  • Multicall Binary: Single binary dispatched via symlink or subcommand (goposix ls).
  • Daemon-First: The default image starts the persistent JSON-RPC daemon. Use the Go SDK for programmatic access. CLI is available as a secondary interface (goposix:cli).
  • No CGO: Static compilation for FROM scratch containers (CGO_ENABLED=0).
  • Little Dependencies: Only 3 external Go modules: mvdan.cc/sh/v3 (shell interpreter), golang.org/x/sys (cross-platform syscalls), golang.org/x/term (terminal detection). No external libraries for flag parsing, output, or utility logic.
  • --json Only: Structured output via --json long flag only — no short-form (-j) collision with POSIX flags.
  • POSIX Flag Parsing: Custom parser in pkg/common/flags.go with escape hatches for free-form utilities (echo, printf, expr).