Installation & setup
Get the context-forge binary onto a Linux machine, make shell completion actually work, register the background service and (optionally) plug in a local Ollama model.
Requirements
- Linux, x86_64, with a systemd user session (
systemctl --usermust work: the server is a user unit, not a system one). - Runtime libraries:
libconfig++(sonamelibconfig++.so.15, i.e. a recent libconfig), OpenSSL 3, zlib, brotli, libstdc++. Fedora 44 provides all of them via thelibconfigpackage; on other distributions check thatlibconfig++.so.15is available, otherwise build from source against your own libconfig. bashandcurlon thePATH(used bysetup,statusandinstall-ollama).- Optional: Ollama reachable over HTTP (default
localhost:11434) for the LLM pass.
Packages ship the binary and the shell completions only. The rule plugins (trigger_default.so, pre-rule_ansi.so, rule_*.so) are not packaged in v1.0.0: without them the server loads no rules and only the LLM pass can run. To use rules, build the plugins from source once and point setup --plugins at the resulting plugins/ folder (or write your own).
Install from packages
Signed .rpm and .deb packages are published on the project's GitHub Pages. Two channels exist: context-forge (stable, built from vX.Y.Z tags) and context-forge-pre (pre-release, built from vX.Y.Z-something tags). They conflict with each other, so install one or the other.
The repository is laid out as fedora/$releasever/$basearch; Fedora 44 / x86_64 is what CI currently publishes.
sudo curl -fsSL -o /etc/yum.repos.d/context-forge.repo \
https://tsukini22.github.io/context-forge/context-forge.repo
sudo rpm --import https://tsukini22.github.io/context-forge/RPM-GPG-KEY-tsukini
sudo dnf install context-forge # or: context-forge-pre
sudo dnf install libconfig # runtime dependency, if not already present
The .repo file it downloads is simply:
[context-forge]
name=context-forge repository
baseurl=https://tsukini22.github.io/context-forge/fedora/$releasever/$basearch
enabled=1
gpgcheck=1
gpgkey=https://tsukini22.github.io/context-forge/RPM-GPG-KEY-tsukini
If dnf complains about an invalid hash after a new release, clear its cache: sudo dnf clean all && sudo dnf makecache.
The APT repository serves stable main for amd64 and is signed with the same key.
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://tsukini22.github.io/context-forge/RPM-GPG-KEY-tsukini \
| gpg --dearmor | sudo tee /etc/apt/keyrings/context-forge.gpg > /dev/null
sudo chmod a+r /etc/apt/keyrings/context-forge.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/context-forge.gpg] \
https://tsukini22.github.io/context-forge/debian stable main" \
| sudo tee /etc/apt/sources.list.d/context-forge.list > /dev/null
sudo apt-get update
sudo apt-get install context-forge # or: context-forge-pre
The .deb is produced by the same Fedora-based CI container as the .rpm and declares no dependencies. It expects libconfig++.so.15 and a recent glibc/libstdc++; if context-forge -h fails with a missing shared library on your Debian/Ubuntu release, build from source instead.
You can also fetch a package file directly and install it with your package manager. The naming pattern is context-forge[-pre]-<version>-Linux.<rpm|deb>.
# RPM
curl -fLO https://tsukini22.github.io/context-forge/fedora/44/x86_64/context-forge-1.0.0-Linux.rpm
sudo dnf install ./context-forge-1.0.0-Linux.rpm
# DEB
curl -fLO https://tsukini22.github.io/context-forge/debian/pool/main/context-forge-1.0.0-Linux.deb
sudo apt-get install ./context-forge-1.0.0-Linux.deb
Browse the index at tsukini22.github.io/context-forge (the gh-pages branch of the repository).
Build from source
Building from source is required to get the plugins, and is the only way to install on distributions without a package. The build is CMake ≥ 3.20 and forces clang++ (set in CMakeLists.txt), C++20.
Build dependencies
| Dependency | Purpose | Fedora | Debian / Ubuntu |
|---|---|---|---|
clang, cmake, make, pkg-config | toolchain | clang cmake make pkgconf-pkg-config | clang cmake make pkg-config |
| libutils ≥ 2.13.22 | author's utility library (argument parser, process/pipe/shared-memory wrappers, exceptions, observer) | see below — installed from the author's own package repository | |
| cpp-httplib | HTTP client to Ollama | cpp-httplib-devel | libcpp-httplib-dev |
| libconfig++ | parses .cfg rule files | libconfig-devel | libconfig++-dev |
| nlohmann/json | Ollama request/response bodies | json-devel | nlohmann-json3-dev |
| Python 3 | generates include/exception/generated_external_exception_header.hpp at configure time | python3 | python3 |
| GoogleTest (tests only) | -DBUILD_TESTS=ON | gtest-devel | libgtest-dev |
| ccache (optional) | picked up automatically if present | ccache | ccache |
libutils is published the same way as context-forge. Its setup.sh registers the repository for your distribution; then install the headers/CMake config (libutils-dev) and the optimized library (libutils-op) — or just the meta-package:
curl -fsSL https://raw.githubusercontent.com/TsukiNi22/libutils/main/setup.sh | bash -s
sudo dnf install libutils # Fedora (pre-release channel: libutils-pre)
sudo apt-get install libutils # Debian (pre-release channel: libutils-pre)
CMake asks for utils 2.13.22 or newer. At the time of writing that version only exists on the -pre channel, so use libutils-pre if the stable package is older. You can also build libutils from its repository (cmake --build build --target install) into /usr/local.
Build
git clone https://github.com/TsukiNi22/context-forge.git
cd context-forge
make # = cmake -S . -B build && cmake --build build --parallel
Outputs land in the source tree, not in build/:
context-forge/
├── context-forge ← the executable
└── plugins/
├── triggers/trigger_default.so
├── pre-rules/pre-rule_ansi.so
└── rules/rule_ln.so rule_drop.so rule_dup.so rule_insert.so rule_replace.so
Other useful targets:
| Command | Effect |
|---|---|
cmake --build build --target release | Reconfigure with -DCMAKE_BUILD_TYPE=Optimized (-O3 -march=native …) and rebuild. |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Asan | AddressSanitizer build. |
cmake --build build --target plugins | Build only the seven shared objects. |
cmake -S . -B build -DBUILD_TESTS=ON && cmake --build build && (cd build && ctest --output-on-failure) | Build and run the GoogleTest suite (./unit_tests). |
cmake --build build --target package_release | Produce .rpm/.deb in build/ with CPack. |
make re / make fclean | Full rebuild / remove build/. |
Install the binary and completions
sudo cmake --install build # prefix /usr/local
This installs /usr/local/bin/context-forge, /usr/local/share/zsh/site-functions/_context-forge and /usr/local/share/bash-completion/completions/context-forge. Plugins are not installed by this step — keep the plugins/ folder around or let setup --copy clone it (next sections).
context-forge setup writes the absolute path of the binary into the systemd unit and only looks in /usr/local/bin and /usr/bin. Running setup straight from the build directory without installing fails with Missing binary. Either install, or symlink: sudo ln -s "$PWD/context-forge" /usr/local/bin/context-forge.
What gets installed where
| File | Package (/usr) | cmake --install (/usr/local) |
|---|---|---|
| binary | /usr/bin/context-forge | /usr/local/bin/context-forge |
| zsh completion | /usr/share/zsh/site-functions/_context-forge | /usr/local/share/zsh/site-functions/_context-forge |
| bash completion | /usr/share/bash-completion/completions/context-forge | /usr/local/share/bash-completion/completions/context-forge |
systemd unit (created by setup) | ~/.config/systemd/user/context-forge.service | |
cloned resources (created by setup --copy) | ~/.config/context-forge/plugins/, ~/.config/context-forge/rules/, ~/.config/context-forge/system-prompt | |
Shell completion
Both completion scripts are installed for you, but neither shell picks them up automatically in every configuration. Here is what to check for each shell.
zsh only loads a completion file if (1) its directory is in $fpath before compinit runs and (2) compinit is actually called. Frameworks such as oh-my-zsh call compinit for you; a bare ~/.zshrc usually does not.
- Check whether the directory is already in
$fpathprint -l $fpath | grep -n 'site-functions' which _context-forge # after compinit: prints the file path if it is picked upDistribution zsh builds normally include
/usr/share/zsh/site-functions(the package location) and often/usr/local/share/zsh/site-functions(thecmake --installlocation) — but if you setfpath=(…)yourself in.zshrcwithout$fpathat the end, those defaults are gone. - Add the directory and initialise completionPut this in
~/.zshrc, before any existingcompinitline:# pick the one matching how you installed: fpath=(/usr/share/zsh/site-functions $fpath) # package fpath=(/usr/local/share/zsh/site-functions $fpath) # cmake --install autoload -Uz compinit && compinit - Reload without opening a new shell
unfunction _context-forge 2>/dev/null rm -f ~/.zcompdump* # zsh caches the list of completion files exec zshThen type
context-forgeand press Tab: you should see the sub-commands (exec,setup,server, …).context-forge exec -Tab lists the flags, and-vTab offersnone basic advanced debug.
Per-user alternative (no root, survives package removal), as suggested in the script header:
mkdir -p ~/.zsh/completions
cp /usr/share/zsh/site-functions/_context-forge ~/.zsh/completions/ # or from the repo: cmake/completions/zsh/_context-forge
# in ~/.zshrc, before compinit:
fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit && compinit
"zsh compinit: insecure directories" warning? zsh refuses group/world-writable directories in $fpath. Fix the permissions (compaudit lists the culprits; chmod go-w them) rather than using compinit -u.
The script is written for the bash-completion framework (≥ 2.x), which lazy-loads completions/context-forge the first time you press Tab after the command name. It searches $XDG_DATA_DIRS (default /usr/local/share:/usr/share), so both install locations are covered — provided the framework is installed and sourced.
- Make sure bash-completion is installed and loaded
sudo dnf install bash-completion # Fedora sudo apt-get install bash-completion # Debian / Ubuntu type _init_completion # "is a function" → framework is loaded in this shellInteractive login shells source it through
/etc/profile.d/bash_completion.sh. If_init_completionis missing, add to~/.bashrc:[ -r /usr/share/bash-completion/bash_completion ] && . /usr/share/bash-completion/bash_completion - Or source the script directly (works without the framework, thanks to its built-in fallback):
. /usr/share/bash-completion/completions/context-forge # package # . /usr/local/share/bash-completion/completions/context-forge # cmake --install - Reload and check
complete -r context-forge 2>/dev/null # drop a stale registration source ~/.bashrc complete -p context-forge # → complete -F _context_forge_completions context-forge
Per-user copy: mkdir -p ~/.local/share/bash-completion/completions && cp /usr/share/bash-completion/completions/context-forge ~/.local/share/bash-completion/completions/ — new shells pick it up automatically.
The scripts live in the repository under cmake/completions/; you can use them from a clone without installing anything system-wide:
# zsh (current shell only)
fpath+=("$PWD/cmake/completions/zsh"); autoload -Uz compinit && compinit
# bash (current shell only)
source cmake/completions/bash/context-forge
Other shells (fish, nushell…) are not provided in v1.0.0.
Register the daemon
context-forge is split in two: exec (the client you call from your shell) and server (a long-lived process that holds the loaded plugins, rules and Ollama session). setup generates and enables a systemd user unit for the server. Run it as your normal user — not with sudo.
context-forge setup --copy --recursive \
--plugins ~/src/context-forge/plugins \
--rules ~/forge/rules \
--system-prompt ~/forge/system-prompt # omit to disable the LLM pass
What setup does, step by step:
- Locates the binary (
/usr/local/binthen/usr/bin). - With
--copy: clones*.sofrom the plugins directory into~/.config/context-forge/plugins/,*.cfginto~/.config/context-forge/rules/(recursively if--recursive) and the system prompt to~/.config/context-forge/system-prompt. Without--copythe unit references your directories directly, so edits are picked up on the next restart. - Writes
~/.config/systemd/user/context-forge.service:[Unit] Description=context-forge daemon After=network.target [Service] Type=simple Restart=always RestartSec=2 ExecStart=/usr/bin/context-forge server --recursive --plugins /home/you/.config/context-forge/plugins --rules /home/you/.config/context-forge/rules --system-prompt /home/you/.config/context-forge/system-prompt [Install] WantedBy=default.target - Runs
systemctl --user daemon-reload,enableandrestarton the unit.
Every server option can be passed to setup and is baked into ExecStart: --ip, --port, --model, --verbose LEVEL. Re-run setup whenever you want to change them; it overwrites the unit.
Dry-run before you commit. context-forge check local --plugins … --rules … -v debug loads everything exactly like the server would and prints each plugin and rule file as it is accepted or rejected, then exits. After a setup --copy, context-forge check dist validates the cloned copies.
To start the daemon on boot without an open session (headless machines), enable lingering once: sudo loginctl enable-linger "$USER".
Ollama (optional)
The LLM pass rewrites the (already rule-formatted) output with a model served by Ollama, guided by a system prompt file you provide. It is enabled only when the server was given --system-prompt and the model can be reached at start-up; failures are logged and the pass is skipped until the next restart.
- Install Ollama — either from ollama.com or through the wrapper (it runs the official install script and therefore needs root):
sudo context-forge install-ollama - Pull a model — the default is
qwen2.5-coder:1.5b:context-forge pull qwen2.5-coder:1.5b ollama serve & # if Ollama is not already running as a service - Write a system prompt — a plain text file. The server sends your prompt as
systemand, as the user message, the wrapped command name and its output wrapped in<binary>…</binary>and<output>…</output>tags. Design the prompt around that:You receive the output of a shell command inside <output> tags and the program name inside <binary>. Return the same information, shortened: keep errors and warnings verbatim, collapse repetitive lines, never add commentary. Output plain text only. - Point the server at it (
--system-prompt, plus--model/--ip/--portif not default) and restart:context-forge setup --copy --recursive --plugins … --rules … --system-prompt ~/forge/system-prompt --model qwen2.5-coder:1.5b context-forge status
The server keeps the model loaded by pinging Ollama with keep_alive: 10m on a schedule while it runs, so the first wrapped command after a restart is the only slow one.
Verify the installation
context-forge status
server: running
ollama: installed / running
Then wrap something:
context-forge exec -v advanced -c ls -la
With -v advanced the client prints the raw and formatted blocks around the command output, which is the quickest way to see rules taking effect. If you see [FALLBACK] context-forge: server is unavailable… the command still ran, untouched; check journalctl --user -u context-forge.
Uninstall
context-forge remove # stops + disables the unit, deletes it and ~/.config/context-forge
sudo dnf remove context-forge # or: sudo apt-get remove context-forge
# from-source install: remove the three files listed in "What gets installed where"