A monorepo management tool for the agentic ages

Unpac CLI Workflow#

Overview#

Unpac is a vendoring tool that lets you maintain local patches to dependencies while tracking upstream changes. This document describes the ideal CLI workflow.

Quick Start#

# Initialize a new unpac workspace
unpac init myworkspace
cd myworkspace

# Configure an opam repository
unpac opam repo add opam-repository /path/to/opam-repository

# Create a project
unpac project new myapp

# Add a dependency (looks up dev-repo in opam repository)
unpac opam add cmdliner

# Edit the vendored package (opens patches worktree)
unpac opam edit cmdliner
# ... make changes, e.g., port to dune ...
cd opam/patches/cmdliner
git add -A && git commit -m "Port cmdliner to dune"
cd ../../..

# Add the patched package to your project
unpac opam merge cmdliner myapp

# Build your project
cd project/myapp
dune build

Commands#

Initialization#

unpac init <path>#

Initialize a new unpac workspace at the given path.

unpac init myworkspace

Creates:

  • git/ - bare git repository (shared object store)
  • main/ - metadata branch with unpac.toml

Project Management#

unpac project new <name>#

Create a new project branch.

unpac project new myapp

Creates an orphan branch project/<name> with:

  • dune-project with dune lang 3.20
  • dune with (vendored_dirs vendor)
  • vendor/opam/ directory structure

unpac project list#

List all projects in the workspace.

unpac project list

Opam Repository Management#

unpac opam repo add <name> <path-or-url>#

Add an opam repository for package lookups.

# Local repository
unpac opam repo add opam-repository /workspace/opam/opam-repository

# Remote repository (planned)
unpac opam repo add opam-repository https://github.com/ocaml/opam-repository

unpac opam repo list#

List configured opam repositories.

unpac opam repo list

unpac opam repo remove <name>#

Remove an opam repository.

unpac opam repo remove opam-repository

Package Vendoring#

unpac opam add <package-or-url> [--name <name>] [--version <version>]#

Vendor a package. Can specify either:

  • A package name (looks up dev-repo in configured repositories)
  • A git URL directly
# By package name (recommended)
unpac opam add cmdliner
unpac opam add cmdliner --version 1.3.0

# By URL (for packages not in a repository)
unpac opam add https://github.com/dbuenzli/cmdliner.git --name cmdliner

This creates three branches:

  • opam/upstream/<pkg> - pristine upstream code
  • opam/vendor/<pkg> - code with vendor/opam/<pkg>/ path prefix
  • opam/patches/<pkg> - your local modifications (initially same as vendor)

unpac opam list#

List all vendored packages.

unpac opam list

unpac opam edit <package>#

Open the patches worktree for editing a package.

unpac opam edit cmdliner

Creates/checks out opam/patches/cmdliner/ worktree. Make your changes there, then commit:

cd opam/patches/cmdliner
# ... edit files ...
git add -A
git commit -m "Port to dune build system"

unpac opam done <package>#

Close the patches worktree (cleanup after editing).

unpac opam done cmdliner

unpac opam update <package>#

Update a package from upstream.

unpac opam update cmdliner

This:

  1. Fetches latest from upstream
  2. Updates opam/upstream/<pkg> and opam/vendor/<pkg>
  3. Prints instructions for rebasing patches if needed

unpac opam rebase <package>#

Rebase your patches onto the updated vendor branch.

unpac opam rebase cmdliner

Opens the patches worktree for conflict resolution if needed.

unpac opam merge <package> <project>#

Merge a vendored package into a project.

unpac opam merge cmdliner myapp

Merges opam/patches/<pkg> into project/<name>, placing files under vendor/opam/<pkg>/.

unpac opam remove <package>#

Remove a vendored package.

unpac opam remove cmdliner

Package Information#

unpac opam info <package>#

Show information about a vendored package.

unpac opam info cmdliner

Shows:

  • Upstream URL
  • Current upstream SHA
  • Current patches SHA
  • Number of local commits
  • Projects using this package

unpac opam diff <package>#

Show the diff between vendor and patches (your local changes).

unpac opam diff cmdliner

Workflow Examples#

Porting a Package to Dune#

# Setup
unpac init myworkspace && cd myworkspace
unpac opam repo add opam-repository /workspace/opam/opam-repository
unpac project new myapp

# Vendor and patch
unpac opam add cmdliner
unpac opam edit cmdliner

cd opam/patches/cmdliner
# Add dune files, remove _tags, etc.
git add -A
git commit -m "Port cmdliner to dune"
cd ../../..

unpac opam done cmdliner

# Use in project
unpac opam merge cmdliner myapp
cd project/myapp
dune build

Updating a Patched Package#

# Update from upstream
unpac opam update cmdliner

# Rebase your patches
unpac opam rebase cmdliner

# If conflicts, resolve them:
cd opam/patches/cmdliner
# ... resolve conflicts ...
git add -A
git rebase --continue
cd ../../..

unpac opam done cmdliner

# Re-merge into project
unpac opam merge cmdliner myapp

Adding Multiple Dependencies#

unpac opam add fmt
unpac opam add logs
unpac opam add cmdliner

# Merge all into project
unpac opam merge fmt myapp
unpac opam merge logs myapp
unpac opam merge cmdliner myapp

Directory Structure#

After setup, your workspace looks like:

myworkspace/
├── git/                      # Bare git repo (shared objects)
├── main/                     # Metadata worktree
│   └── unpac.toml           # Configuration
├── project/
│   └── myapp/               # Project worktree
│       ├── dune-project
│       ├── dune
│       └── vendor/
│           └── opam/
│               ├── cmdliner/  # Merged vendor code
│               └── fmt/
└── opam/                     # Package worktrees (on-demand)
    └── patches/
        └── cmdliner/        # When editing

Configuration (unpac.toml)#

[opam]
repositories = [
  { name = "opam-repository", path = "/workspace/opam/opam-repository" }
]
# compiler = "5.4.0"  # Optional: pin compiler version

[projects]
myapp = {}