Source of Truth

· 6 min read

The Scattered Truth

Here’s a typical project:

myapp/
├── main.go              # the actual code
├── go.mod               # Go dependencies
├── package.json         # JS tooling deps
├── Dockerfile           # how to containerize
├── docker-compose.yml   # how to orchestrate
├── Makefile             # how to build
├── .github/workflows/   # how to CI/CD
├── terraform/           # infrastructure
├── k8s/                 # deployment manifests
└── README.md            # "please read this first"

Ten places where “truth” lives. Ten places that can drift out of sync.

Did you update the Dockerfile when you added that dependency? Did the README mention that new system library? Does the Makefile still work after you renamed that directory?

Every config file is a liability. Each one is a potential source of drift, confusion, and “works on my machine.”

The Koru Thesis

Your source code should be the single source of truth.

Not just for logic. For everything.

myapp/
└── main.kz              # THE source of truth

One file that contains:

  • The code
  • What system libraries it needs
  • What packages it imports
  • How to build it
  • What containers it runs in
  • (soon) How to deploy it

The compiler reads one file and knows everything.

The Evolution

We’ve been building toward this systematically.

Chapter 1: Import = Install

~import "$koru/sqlite3"

~koru.sqlite3:open(path: ":memory:")
| db d |> ...

No package.json. The import IS the dependency declaration. Remove the import, the dependency vanishes from everywhere.

Read more →

Chapter 2: The Compiler Runs Brew

~import "$std/deps"

~std.deps:requires.system {
    "name": "sqlite3",
    "check": "pkg-config --modversion sqlite3",
    "brew": "sqlite3",
    "apt": "libsqlite3-dev"
}

System dependencies declared in source. Run koruc main.kz deps install and the compiler installs libsqlite3 for you.

Read more →

Chapter 3: Build Configuration

~import "$std/build"

~std.build:requires {
    exe.linkSystemLibrary("sqlite3");
    exe.linkLibC();
}

No separate build.zig to maintain. The source code tells the compiler how to link it.

Chapter 4: Infrastructure

This is new. And it’s wild.

~import "$koru/docker"

~koru.docker:image(tag: "myapp:latest") {
    FROM alpine:3.18
    COPY zig-out/bin/main /usr/local/bin/myapp
    CMD ["myapp"]
}

That’s a Dockerfile. Inside your source code.

Koru compiles to a native binary via Zig - no runtime needed. So your container is just Alpine + your binary. Tiny. Fast.

$ koruc main.kz                    # compile to native binary
$ koruc main.kz docker build       # build the container

Building 1 Docker image(s)...

  [1/1] Building myapp:latest...
    ✓ built myapp:latest

No separate Dockerfile to maintain. The infrastructure IS the source code.

Multiple Services? Same File.

~import "$koru/docker"

// API server
~koru.docker:image(tag: "api:v1") {
    FROM alpine:3.18
    RUN apk add --no-cache sqlite-libs
    COPY zig-out/bin/api /usr/local/bin/api
    EXPOSE 8080
    CMD ["api"]
}

// Background worker
~koru.docker:image(tag: "worker:v1") {
    FROM alpine:3.18
    COPY zig-out/bin/worker /usr/local/bin/worker
    CMD ["worker"]
}

// CLI tool (for migrations, admin tasks)
~koru.docker:image(tag: "cli:v1") {
    FROM alpine:3.18
    RUN apk add --no-cache sqlite-libs
    COPY zig-out/bin/cli /usr/local/bin/cli
    ENTRYPOINT ["cli"]
}

Three images. One source file. All native binaries on minimal Alpine containers.

$ koruc main.kz docker build

Building 3 Docker image(s)...

  [1/3] Building api:v1...
    ✓ built api:v1
  [2/3] Building worker:v1...
    ✓ built worker:v1
  [3/3] Building cli:v1...
    ✓ built cli:v1

Each image is maybe 10-15MB. No Go runtime. No Node runtime. No Python interpreter. Just your code.

The Full Picture

Here’s what a complete Koru application looks like:

~import "$std/deps"
~import "$std/build"
~import "$koru/docker"
~import "$koru/sqlite3"

// System dependencies - the compiler runs brew/apt for you
~std.deps:requires.system {
    "name": "sqlite3",
    "check": "pkg-config --modversion sqlite3",
    "brew": "sqlite3",
    "apt": "libsqlite3-dev"
}

// Build configuration - how to link the binary
~std.build:requires {
    exe.linkSystemLibrary("sqlite3");
}

// The infrastructure - containerization
~koru.docker:image(tag: "myapp:latest") {
    FROM alpine:3.18
    RUN apk add --no-cache sqlite-libs
    COPY zig-out/bin/main /usr/local/bin/myapp
    CMD ["myapp"]
}

// The actual code
~koru.sqlite3:open(path: "/data/app.db")
| db d |>
    koru.sqlite3:exec(conn: d.conn, sql: "SELECT * FROM users")
    | rows r |> process_users(r)
    | err e |> log_error(e)
| err e |> fatal(e)

Everything in one place:

  • What system libraries to install (sqlite3 via brew/apt)
  • How to build the binary (link libsqlite3)
  • How to containerize it (Alpine + binary + sqlite-libs)
  • What the application does (open db, query, process)

No drift. No “did you update X when you changed Y?” No archaeology across config files.

Why This Matters

Onboarding

Old way:

1. Read README
2. Install prerequisites (hope it's up to date)
3. Figure out build system
4. Debug why it doesn't work
5. Ask someone who knows

Koru way:

git clone ...
koruc main.kz deps install
koruc main.kz docker build

Done. The source code contains everything the compiler needs.

Refactoring

Old way: Change a dependency, then remember to update Dockerfile, docker-compose, CI config, README…

Koru way: Change the source. Everything else follows automatically.

Code Review

Old way: Review code changes, then separately review Dockerfile changes, then check if they’re consistent…

Koru way: One diff. All the truth in one place.

The Philosophy

Configuration files are a necessary evil that we’ve normalized. “Of course you need a Dockerfile separate from your code.” “Of course you need package.json.” “Of course you need terraform files.”

Why?

Your source code already describes what the application does. Why can’t it also describe what it needs, how to build it, and how to run it?

Source code as source of truth.

Not “source code plus a constellation of config files that hopefully agree with each other.”

Just source.

~import "$koru/docker"

~koru.docker:image(tag: "myapp:latest") {
    FROM alpine:3.18
    COPY zig-out/bin/main /usr/local/bin/myapp
    CMD ["myapp"]
}

That’s your Dockerfile. It lives with your code. It IS your code.

A native binary on a 5MB base image. No runtime. No interpreter. No dependency hell inside the container.

One file. One truth.