GibilGibil

Architecture

Design decisions and technical implementation

Gibil is a thin orchestration layer between you and Hetzner Cloud. There's no custom infrastructure, no proprietary runtime, no vendor lock-in. It's a CLI that makes the right API calls in the right order.

Design decisions

Raw fetch over Hetzner SDK

Zero extra dependencies, full control over the HTTP layer, easy to mock in tests. The entire Hetzner integration is one file with a private request<T>() method.

CloudProvider interface

The CloudProvider interface is the abstraction boundary. Today it wraps Hetzner. Tomorrow it can wrap Fly.io, DigitalOcean, or AWS — implement the same interface, swap the provider.

Cloud-init over SSH provisioning

The server configures itself on boot. Gibil generates a cloud-init script with your runtime, services, and tasks — then hands it to Hetzner. No SSH connection needed during setup, no fragile multi-step provisioning over the network.

Auth is optional

The CLI works with just a Hetzner token. Gibil's auth layer (Supabase + Stripe) adds metering and billing for the managed service, but it's entirely optional. BYOH users never touch it.

InstanceStore with dependency injection

Instance metadata is stored as JSON files in ~/.gibil/instances/. The store accepts a baseDir parameter — production uses ~/.gibil, tests use a temp directory. No global state, no singletons.

Tech stack

ComponentTechnologyWhy
CLI frameworkCommander.jsStandard, well-documented
BuildtsupFast, zero-config ESM bundling
LanguageTypeScript (strict)Type safety without ceremony
SSHssh2Native Node.js SSH, no shelling out
ConfigYAML (.gibil.yml)Human-readable, version-controllable
TestsVitestFast, ESM-native, good DX
CloudHetzner Cloud APICheapest full VMs, clean API
Auth/billingSupabase + StripeOptional, no extra hosting needed

Project structure

src/
  cli/
    commands/       # One file per command (create, ssh, run, destroy, ...)
    index.ts        # Entry point — registers all commands with Commander
  providers/        # CloudProvider implementations (Hetzner)
  config/           # YAML parser + cloud-init script generator
  ssh/              # Key generation + remote command execution
  types/            # Shared TypeScript types (index.ts)
  utils/            # Logger, store, auth, paths, validate, random

Each command is a single file with a registerXCommand(program) function. The provider is injected, not imported directly. Utilities are small and single-purpose.

Next steps

On this page