CLI · Docker · C Language

FORGE

Lightweight Deployment CLI

Deploy containerized applications from any Git repository with a single command. No YAML. No bloat. Written in C from scratch to understand deployment pipelines from the ground up.

forge deploy https://github.com/user/app.git
1
Command to deploy
0
Config files needed
100%
Pure C code
POSIX
Compatible

Built Different

Most deployment tools are optimised for teams managing production infrastructure. FORGE is optimised for understanding. It exposes the raw mechanics of cloning, building, and running containers — and wraps them in a C program small enough to read in an afternoon.

01 — CLI
CLI First

One subcommand to clone, build, and start a container. No dashboards, no GUIs, no abstraction hiding what's actually happening.

02 — Docker
Docker Native

FORGE shells out to your existing Docker daemon. It doesn't reinvent container management — it just automates the repetitive commands you already know.

03 — Zero config
Zero Config

Pass a Git URL. FORGE infers the image name, build context, and container name from the repository. Sensible defaults you can always override with flags.

04 — C
Written in C

Pure ANSI C with POSIX extensions. No dependencies outside libc. The entire source compiles in under a second and fits in a single translation unit.

05 — Learning
Pedagogical

Every design decision prioritises clarity. Reading the source is the documentation. FORGE exists to be understood, not just used.

06 — Lean
Minimal Footprint

The compiled binary is a few dozen kilobytes. FORGE adds no runtime overhead; all the work is done by git and docker which you already have installed.

Zero to Running

Three steps: install prerequisites, compile FORGE, deploy a repo. No package manager, no runtime, no configuration file.

Step 1 — Prerequisites

You need git, docker, and a C compiler available on your PATH. That's it.

Verify prerequisites
$ git --version
git version 2.43.0
$ docker --version
Docker version 25.0.3, build 4debf41
$ gcc --version
gcc (Ubuntu 13.2.0) 13.2.0

Step 2 — Build FORGE

Build from source
$ git clone https://github.com/gauranga18/forge.git
$ cd forge
$ make
✓  forge compiled successfully (18 KB)

Step 3 — Deploy

Your first deploy
$ forge deploy https://github.com/user/my-app.git
  Cloning  https://github.com/user/my-app.git ...
  Building my-app:latest ...
  Starting container my-app ...
✓  my-app is running on port 8080
Add the compiled forge binary to a directory on your PATH (e.g. /usr/local/bin) so you can run it from anywhere.

Install FORGE

FORGE ships as source. You compile it once on your machine and get a standalone native binary with no runtime dependencies.

Linux / macOS

Linux & macOS install
# Clone and compile
$ git clone https://github.com/gauranga18/forge.git ~/forge
$ cd ~/forge && make

# Optional: install system-wide
$ sudo cp forge /usr/local/bin/forge
$ forge --version
forge v1.0

Windows (WSL2)

WSL2 install
# Inside a WSL2 Ubuntu shell
$ sudo apt-get install -y gcc make git docker.io
$ git clone https://github.com/gauranga18/forge.git
$ cd forge && make
✓  forge compiled successfully

Manual Compile (no Make)

Direct gcc compile
$ gcc -O2 -Wall -Wextra -pedantic \
      src/forge.c \
      -o forge
Docker Engine must be running before you invoke forge. On macOS and Windows use Docker Desktop; on Linux start the daemon with sudo systemctl start docker.

Commands

All FORGE functionality lives under a single binary. The first positional argument is always the subcommand. Additional positional arguments and flags follow.

Syntax

Usage pattern
forge <subcommand> [arguments] [flags]

Subcommand Reference

Command Argument Description
deploy <git-url> required Clone the repository, build a Docker image from its Dockerfile, and start a container. All three steps in one command.
build <git-url> required Clone and build the Docker image only. Does not start a container. Useful for verifying a Dockerfile before deploying.
run <image> required Start a container from a locally available image. Skips the clone and build steps.
stop <name> required Stop a running container by name.
rm <name> required Remove a stopped container. Use --force to remove a running container.
logs <name> required Stream stdout/stderr logs from a running or stopped container.
status <name> optional Show the status of a named container, or list all containers managed by FORGE if no name is given.
version Print the FORGE version string and exit.
help [subcommand] optional Show help for FORGE or for a specific subcommand.

Flags & Options

Flags are optional and always follow the subcommand and its required arguments. Unrecognised flags cause FORGE to exit with a non-zero status and print usage.

Global flags

--version bool
Print version and exit.
--help, -h bool
Show help text. Pass a subcommand name for per-command help.
--verbose, -v bool
Print every shell command FORGE executes before running it. Useful for debugging and learning.
--dry-run bool
Print what FORGE would do without executing any commands. Implies --verbose.

deploy / build flags

--name <str> string
Override the auto-derived container and image name.
Default: last path segment of the git URL, stripped of .git
--tag <str> string
Docker image tag to use when building.
Default: latest
--port <int> integer
Host port to bind to the container's exposed port.
Default: 8080
--branch <str> string
Git branch, tag, or commit SHA to check out.
Default: repository default branch
--dir <path> string
Directory to clone into. Created if it does not exist.
Default: /tmp/forge-<name>
--detach, -d bool
Run the container in the background. FORGE prints the container ID and exits.
Default: attached (foreground)
--force bool
Stop and remove a container with the same name before starting a new one.
--env KEY=VAL string (repeatable)
Pass an environment variable to the container. May be repeated for multiple variables.

Examples

Real-world invocation patterns covering the most common workflows.

Deploy with custom port

Deploy on port 3000
$ forge deploy https://github.com/user/api.git \
    --port 3000 \
    --detach

Deploy a specific branch

Branch deploy
$ forge deploy https://github.com/user/app.git \
    --branch staging \
    --name   app-staging

Passing environment variables

Environment variables
$ forge deploy https://github.com/user/web.git \
    --env NODE_ENV=production \
    --env DATABASE_URL=postgres://localhost/mydb

Dry run to inspect actions

Dry run output
$ forge deploy https://github.com/user/app.git --dry-run
  [dry-run] git clone https://github.com/user/app.git /tmp/forge-app
  [dry-run] docker build -t app:latest /tmp/forge-app
  [dry-run] docker run -p 8080:8080 --name app app:latest
✓  dry run complete — no changes made

View logs and stop

Container management
# Stream logs
$ forge logs app

# Stop the container
$ forge stop app

# Remove it
$ forge rm app

Redeploy (force replace)

Force redeploy
# Stop/remove existing container and redeploy
$ forge deploy https://github.com/user/app.git --force
  Stopping existing container app ...
  Removing  container app ...
  Cloning   https://github.com/user/app.git ...
  Building  app:latest ...
  Starting  container app ...
✓  app is running on port 8080

Architecture

FORGE follows a deliberately simple pipeline. Each subcommand maps to a small C function that constructs a shell command string and hands it to execvp() (or popen() where output capture is needed). There is no intermediate representation, no plugin system, no async runtime.

Deploy Pipeline

1
Argument Parsing

A hand-written parse_args() function walks argv and populates a ForgeConfig struct. Unknown flags abort early with a usage message and exit code 1.

2
Name Derivation

If --name was not provided, FORGE extracts the last path segment of the git URL, strips a trailing .git, and uses that as both image name and container name.

3
Git Clone

FORGE calls git clone [--branch <b>] <url> <dir> via execvp(). The parent process waits for the child with waitpid() and checks the exit code.

4
Docker Build

Calls docker build -t <name>:<tag> <dir>. Build output is piped to FORGE's stdout so you can see layers being processed in real time.

5
Docker Run

Assembles a docker run command string from the parsed flags (--port, --env, --detach) and executes it. The container name is tracked in a local state file under ~/.forge/.

6
State File

A newline-delimited text file at ~/.forge/containers records each container name managed by FORGE. The status and rm subcommands read this file to enumerate containers.

Because FORGE simply shells out to git and docker, it inherits all their capabilities and limitations. Any valid Dockerfile works; any git transport protocol supported by your git installation works.

Source Layout

The entire implementation lives in a single C source file. The project is structured so you can read it top-to-bottom as a tutorial.

forge/ — project tree
forge/
├── src/
│   └── forge.c           # entire implementation (~600 lines)
├── Makefile             # default target: compile with -O2 -Wall
├── README.md
└── LICENSE

# Runtime paths (created on first use)
~/.forge/
└── containers           # plain-text container registry

Key C Functions

Function Signature Responsibility
main int main(int argc, char **argv) Entry point. Routes to the correct subcommand handler.
parse_args ForgeConfig parse_args(int, char**) Walks argv and fills a ForgeConfig struct. Prints usage on error.
derive_name char *derive_name(const char *url) Extracts repo name from git URL. Strips trailing .git.
run_cmd int run_cmd(char *const argv[]) Fork-exec wrapper. Waits for child and returns exit code.
cmd_deploy int cmd_deploy(ForgeConfig *) Orchestrates clone → build → run pipeline.
state_add void state_add(const char *name) Appends a container name to ~/.forge/containers.

Who Uses FORGE

FORGE targets developers who want to understand what deployment tools actually do — not just use them as black boxes.

Learning

Trace every line of C source to understand how a deployment CLI actually invokes git and Docker under the hood.

Quick deploys

Spin up personal projects and prototypes from any git URL without creating config files or memorising docker run options.

DevOps practice

Learn infrastructure automation patterns — clone, build, run, log, stop, remove — with a tiny, auditable codebase.

Local testing

Reproduce a cloud deployment locally. FORGE's --dry-run flag lets you inspect the exact commands before touching anything.

FORGE is not designed for production infrastructure. It has no secrets management, no rollback, and no health-check loop. Use Kubernetes, Nomad, or Docker Swarm for production workloads. FORGE is for learning and personal projects.

Tech Stack

FORGE has exactly zero library dependencies beyond what ships with your operating system. The only tools required to build it are a C compiler and Make.

C (ANSI + POSIX) GCC / Clang Make Docker CLI Git fork(2) execvp(3) waitpid(2) popen(3)

Frequently Asked

Ready to forge?

Clone the repo, compile, and have your first container running in under two minutes.