The package manager for NurOS
  • C 90%
  • Meson 3.9%
  • Python 3%
  • Shell 2.1%
  • Nix 1%
Find a file
2026-07-22 18:01:56 +05:00
.github Большой апдейт 2025-12-27 18:57:33 +05:00
completions feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
man feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
scripts feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
src feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
subprojects feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
test feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
.clang-format feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
.gitignore feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
CODE_OF_CONDUCT.md Большой апдейт 2025-12-27 18:57:33 +05:00
flake.nix feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
LICENSE Initial commit 2024-10-09 01:41:40 +03:00
meson.build feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
meson_options.txt feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00
README.md docs: rephrase repository mirror note in README 2026-07-22 18:01:56 +05:00
ROADMAP.md feat: implement tulpar 0.1.0 2026-07-22 17:52:40 +05:00

tulpar

CLI package manager frontend for NurOS.

Note

Repository Mirrors

  • git.nuros.org (core/tulpar): primary, self-hosted Forgejo instance, accounts restricted to the core team.
  • GitHub (NurOS-Linux/tulpar): mirror for external contributors. Issues and Pull Requests opened here are welcome and are reviewed and processed by the core team.

About

tulpar is the command-line package manager for NurOS. It resolves, downloads, installs, removes, and upgrades packages, backed by libapg for local package database and transaction handling, and by a Tulpar Server instance for remote repository operations over HTTP.

libapg has no networking and no logging of its own; everything network-related, repository-related, configuration, caching, and logging is tulpar's responsibility, built on top of libapg's package, database, transaction, dependency graph, signature, and journal APIs.

Dependencies

Dependency Description
Meson Build system
Ninja Build tool
pkg-config Helper tool for compiling
libapg Packaging backend library, pulled in as a meson subproject
libcurl HTTP(S) client used for all Tulpar Server communication
yyjson JSON library, same one libapg uses internally

Everything else (terminal color output, progress bars, argument parsing) is hand-written with no external dependency.

The libapg dependency

tulpar consumes libapg as a meson subproject, wired up through subprojects/libapg.wrap, a wrap-git pointing at https://git.nuros.org/core/libapg.git, pinned to a specific commit. Meson fetches and builds it automatically as part of a normal meson setup.

Manual mirror override: if git.nuros.org is unreachable from your network, libapg is also mirrored read-only at github.com/nuros-linux/libapg.git. meson's .wrap format does not support a fallback URL list in a single file, so this is a manual override, not something the wrap file itself encodes: edit subprojects/libapg.wrap and change the url to the GitHub mirror before running meson setup, or drop a working checkout directly at subprojects/libapg/ (meson prefers an existing directory over fetching the wrap).

The pinned revision is only the latest one known when this wrap was written; it does not track main automatically and will be bumped by the maintainer as libapg evolves.

Signing backends

libapg builds in both signing backends side by side and lets the caller choose at runtime; tulpar exposes that choice as its own sign_backend setting:

  • sodium (the default): libsodium, Ed25519 signing. Calls libapg's unsuffixed sign_verify / keyring_load / ... functions.
  • gpgme: OpenPGP signing via GnuPG. Calls libapg's _gpgme suffixed sign_verify_gpgme / keyring_load_gpgme / ... functions.

Set sign_backend = sodium or sign_backend = gpgme in tulpar.conf, or pass --sign-backend sodium|gpgme on the command line for a single invocation. require_signature defaults to false, matching Tulpar Server's own default; when a package's signature is missing or fails verification, tulpar always prints a loud warning before proceeding, regardless of require_signature. Set require_signature = true (or pass --require-signature) to reject unsigned or unverifiable packages outright instead of just warning.

Install-script sandbox

Lifecycle scripts (pre-install, post-install, pre-remove, post-remove) are executed by libapg's run_script(), isolated using the strongest primitive available on the host:

  • Linux: unshare() with isolated network, mount, UTS, and IPC namespaces.
  • FreeBSD: chroot() into the alternate install root, when one is given (via --dest).
  • Other POSIX platforms: no sandbox primitive is available; scripts run without isolation.

tulpar does not reimplement any of this. It only resolves where the package database lives under --dest, makes sure the target root's directory structure exists before committing, and passes the resolved root path into trans_commit(), which threads it through to every script invocation libapg triggers internally.

Building

meson setup build --buildtype=release
meson compile -C build

Running tests

meson test -C build

Installing

sudo meson install -C build

Configuration

tulpar.conf

Global settings are read from two locations, in order, with later values overriding earlier ones:

  1. /etc/apg/tulpar.conf (system-wide)
  2. ~/.config/apg/tulpar.conf (per-user override)

The format is plain key = value lines; # starts a comment; there are no sections. See tulpar.conf(5) for the full list of keys (cache_dir, db_dir, log_file, repodata_ttl, max_parallel_downloads, require_signature, sign_backend, color_theme, verbose, quiet, journald).

Repositories

The repository list is a plain text file, one URL per line, # for comments, no key/value syntax, no sections:

  • /etc/apg/repos (system-wide)
  • ~/.config/apg/repos (per-user addition, for managing personal repositories without root)

Manage it with tulpar repo add|remove|list|update rather than editing it by hand if you'd rather not deal with the raw format.

Cache

  • /var/cache/apg/pkgs/: downloaded .apg archives.
  • /var/cache/apg/repodata/: cached repodata.json per configured repository, refreshed automatically once repodata_ttl (default 900 seconds) has elapsed, or on demand with tulpar repo update.

Logging

Plain syslog-style text lines, one per event, written to /var/log/tulpar.log by default. Override the path with log_file in tulpar.conf or a CLI flag. --verbose and --quiet control both log and terminal output verbosity. On Linux, log lines can additionally be mirrored to syslog/journald by setting journald = true.

Command reference

Every command has a full name, a single-letter short alias usable as the first word, and the same letter usable as a leading flag: tulpar install pkg, tulpar i pkg, and tulpar -i pkg are identical.

Command Alias Description
install i Install one or more packages
remove, uninstall r Remove an installed package
upgrade u Upgrade one named package, or all installed packages
search s Search the local database and remote repository indexes
list l List installed packages
info, show n Show full metadata for a package
verify v Verify installed package files
orphans, autoremove o List and remove orphaned packages
hold g Block a package from upgrade or removal
unhold x Release a held package
history, audit, log a Show past install/remove operations
repo add|remove|list|update e Manage configured repositories
download w Fetch a package without installing it
key add|list k Manage the trusted signing keyring

-h/-V/-y/-j/-d/-q are reserved globally for help, version, --yes, --json, --dest, and --quiet, so no command alias reuses those letters; see tulpar(1) for the full rationale behind each letter choice.

Every install/remove/upgrade-family command accepts --dest <path> to operate against an alternate filesystem root instead of the live system. The package database then lives under <dest>/var/lib/apg/db, dependency resolution runs against that database, and root privileges are not required (the destination may be user-owned). Without --dest, tulpar operates on the live root and requires geteuid() == 0 before any write operation.

Full documentation for every command is available as a man page: tulpar(1), tulpar-install(1), tulpar-remove(1), tulpar-upgrade(1), tulpar-search(1), tulpar-list(1), tulpar-info(1), tulpar-verify(1), tulpar-orphans(1), tulpar-hold(1), tulpar-unhold(1), tulpar-history(1), tulpar-repo(1), tulpar-download(1), tulpar-key(1), and tulpar.conf(5).

License

This project is licensed under the GNU General Public License v3.0 (GPL-3.0).

See the LICENSE file for details.