# forge — Documentation (v0.1.0)

forge documentation: manifest format, operations reference, build strategies, variable interpolation, build cache, OS detection, package mapping, and CLI commands.

## Contents

1. [Getting started](#getting-started)
2. [Manifest format](#manifest)
3. [Operations reference](#operations)
4. [Build strategies](#strategies)
5. [Variable interpolation](#interpolation)
6. [Build cache](#cache)
7. [OS detection & package mapping](#os-detection)
8. [CLI commands](#commands)
9. [Architecture](#architecture)

<a id="getting-started"></a>

## 1. Getting started

forge ships as a single static Go binary. Prebuilt binaries are on the GitHub releases page, or build from source:

```sh
# Linux x86_64
curl -LO https://github.com/supanadit/forge/releases/latest/download/forge-linux-amd64
mv forge-linux-amd64 forge
chmod +x forge

# or build from the repo root
go build -o forge ./app
```

### Your first manifest

A manifest is a `[[components]]` list. Each component carries an ordered `ops` list — the order **is** the build lifecycle:

```toml
[project]
name = "myapp"

[vars]
VERSION = "1.0"

[[components]]
name = "base"
ops = [
  { packages = ["curl", "ca-certificates"] },
  { mkdir = [{ path = "/opt/app", mode = "0755" }] },
]

[[components]]
name = "app"
ops = [
  { source_install = { type = "archive",
                       url = "https://example.com/app-${VERSION}.tar.gz",
                       strategy = "configure",
                       prefix = "/usr/local/app" } },
  { verify = [{ file = "/usr/local/app/bin/app" }] },
]
```

```sh
forge build forge.toml
```

That is the whole model: **one TOML file, ordered ops, automatic DAG execution.** The rest of this page is a reference for everything the manifest can declare.

<a id="manifest"></a>

## 2. Manifest format

A forge manifest is a TOML file with a `[project]` header, optional `[vars]`, and one or more `[[components]]`. Each component has a `name` and an `ops` list.

| Section | Purpose |
| --- | --- |
| [project] | Project metadata: name, description. |
| [vars] | Named variables for interpolation. Overridable via env or --var. |
| [[components]] | A build unit with a name and ordered ops list. |
| ops | Ordered list of operations — the build lifecycle. |

The order of ops within a component **is** the execution order. Components are ordered by their dependencies (declared implicitly via variable references or explicitly).

<a id="operations"></a>

## 3. Operations reference

Every operation is a single-key table in the `ops` list. The key names the operation type.

| Operation | Purpose |
| --- | --- |
| packages | Install packages via the detected OS package manager. |
| source_install | Fetch source (archive/git) and build/install it. |
| binary_install | Download an archive and copy a prebuilt binary into place. |
| user | Create a system/user account. |
| mkdir | Create directories with mode and owner. |
| chown | Change ownership of a path. |
| chmod | Change permissions of a path. |
| copy | Copy a file, with optional mode. |
| touch | Create an empty file. |
| generate | Generate code (e.g. protoc-c). |
| verify | Check files/dirs exist. |
| raw | Run an arbitrary shell command (last resort). |

### packages

Installs software through the detected OS package manager. Supports build/runtime/remove/conditional categories.

```toml
{ packages = ["curl", "git"] }

{ packages = { build    = ["build-essential", "pkg-config"],
               runtime  = ["curl", "ca-certificates"],
               remove   = ["vim-tiny", "nano"],
               conditional = [{ category = "build",
                                when = { var = "POSTGRESQL_VERSION", gte = "17" },
                                packages = ["bison", "flex"] }] } }
```

- **build** — installed, then removed after all components finish.
- **runtime** — installed and kept (spared by the cleanup).
- **remove** — explicitly stripped once after all components finish.
- **conditional** — gate packages behind a structured version condition.

### source_install

Fetches source (archive or git) and builds/installs it. Supports before/after hooks.

```toml
{ source_install = { type = "archive",
                     url = "https://example.com/app-${VERSION}.tar.gz",
                     ref = "",
                     strategy = "configure",
                     prefix = "/usr/local/app",
                     flags = ["--with-ssl"],
                     jobs = 4,
                     before = [{ raw = "echo preparing" }],
                     after  = [{ verify = [{ file = "/usr/local/app/bin/app" }] }] } }
```

### binary_install

Downloads an archive and copies prebuilt binaries into place.

```toml
{ binary_install = { url = "https://example.com/tools.tar.gz",
                     copy = [{ from = "tool", to = "/usr/local/bin/tool",
                               mode = "0755" }] } }
```

<a id="strategies"></a>

## 4. Build strategies

The `strategy` field in `source_install` selects the build system:

| Strategy | What it runs |
| --- | --- |
| configure | ./configure && make |
| autogen | autoreconf -fi && ./configure && make |
| cmake | cmake && make |
| meson | meson setup && ninja |
| make | make && make install |
| detect | Auto-select from the source tree |

<a id="interpolation"></a>

## 5. Variable interpolation

`${VAR}` and `${VAR:-default}` resolve from `[vars]`, the environment, and `--var` overrides.

Precedence: vars < env < overrides.

```toml
[vars]
VERSION = "1.0"

[[components]]
name = "app"
ops = [
  { source_install = { url = "https://example.com/app-${VERSION}.tar.gz",
                       strategy = "configure" } },
]
```

<a id="cache"></a>

## 6. Build cache

Caching is fully automatic. A component's cache key hashes its ops, the vars it references, and its dependencies' keys.

- A cache hit is trusted only if the step's output files still exist.
- On a hit whose files vanished (e.g. a Docker layer rebuild), forge restores from an artifact archive.
- With BuildKit, mount the cache dir: `RUN --mount=type=cache,target=/var/cache/forge ... --cache-dir /var/cache/forge`.
- CI cache export (`--cache-to type=gha,mode=max`) persists artifacts too.

> **Cache directory** — The default cache directory is OS-specific. Override with --cache-dir or FORGE_CACHE_DIR.

<a id="os-detection"></a>

## 7. OS detection & package mapping

forge detects the OS package manager automatically:

- 1. `--pkg-manager` flag, then `FORGE_PKG_MANAGER` env var.
- 2. `/etc/os-release` — `ID`, then `ID_LIKE` (e.g. `rhel fedora`).
- 3. Binary lookup on PATH: `apt-get`, `dnf`, `yum`, `apk`.
- 4. Otherwise an error naming the supported managers.

### Package name mapping

Package names differ across distros. forge maps the most common ones automatically:

| Logical name | apt | dnf/yum | apk |
| --- | --- | --- | --- |
| build-essential | build-essential | gcc gcc-c++ make | build-base |
| pkg-config | pkg-config | pkgconf-pkg-config | pkgconf |
| libfoo-dev | libfoo-dev | libfoo-devel | libfoo-dev |

Unknown names pass through unchanged with a warning.

<a id="commands"></a>

## 8. CLI commands

| Command | Purpose |
| --- | --- |
| forge init [dir] | Scaffold a new forge.toml. |
| forge validate <manifest.toml> | Validate without executing. |
| forge build <manifest.toml> | Build from a manifest. |

### Build flags

| Flag | Purpose |
| --- | --- |
| --parallel N | Max concurrent steps (0 = auto). |
| --dry-run | Print the execution plan without running. |
| --fail-fast=false | Continue past failed steps. |
| -v, --verbose | Stream live command output. |
| --var KEY=VALUE | Override a manifest var (repeatable). |
| --no-cache | Disable the build cache. |
| --cache-dir DIR | Override the cache directory. |
| --pkg-manager PM | Override OS package manager. |

<a id="architecture"></a>

## 9. Architecture

forge follows clean architecture conventions. The codebase is organized into domain, service, repository, and CLI layers.

Repository: <https://github.com/supanadit/forge>

