A standalone Gentoo-style
emergepackage manager for Arch Linux. Installs from official repos, the AUR and ABS; scans PKGBUILDs for supply-chain attack patterns before building; runs untrusted build steps inside abwrapsandbox.
Packages are tracked in a world file - install once, track forever.
Sections: Installation · Usage examples · Configuration · Working with packages · Repositories · Security · Flags (at the end)
paru -S aura-emerge # via an AUR helperor with plain makepkg:
git clone https://aur.archlinux.org/aura-emerge.git
cd aura-emerge
makepkg -sigit clone https://github.com/Undercat037/aura-emerge.git
cd aura-emerge
make install # or by hand:cargo build --release
sudo install -Dm755 -o root -g root target/release/aura-emerge /usr/bin/emerge
sudo ln -sf /usr/bin/emerge /usr/bin/portageq
sudo ln -sf /usr/bin/emerge /usr/bin/eselect
emerge --gen-completions bash | sudo tee /usr/share/bash-completion/completions/emerge
emerge --gen-completions zsh | sudo tee /usr/share/zsh/site-functions/_emerge
emerge --gen-completions fish | sudo tee /usr/share/fish/vendor_completions.d/emerge.fish
emerge --gen-manpage | sudo tee /usr/share/man/man1/emerge.1 >/dev/null
sudo install -Dm644 misc/eselect.bash-completion /usr/share/bash-completion/completions/eselect
sudo install -Dm644 misc/_eselect /usr/share/zsh/site-functions/_eselect
sudo install -Dm644 misc/eselect.fish /usr/share/fish/vendor_completions.d/eselect.fishDependencies: git, sudo, bubblewrap (AUR/ABS build sandbox), pacman (libalpm, makepkg), gnupg (key import for the built-in pacman-key implementation and for --autopgp with ABS).
Optional: devtools (--abs support).
# Installing
emerge neovim # official repos, falling back to the AUR
emerge neovim --nodeps # install the package without its dependencies
emerge neovim-git --aur # AUR only (AUR-only dependencies are built recursively)
emerge neovim --repos # official repos only
emerge neovim --abs # build from ABS (pkgctl) in the sandbox
emerge aur/neovim-git abs/nano cachyos-extra-v3/neovim # per-package source via a prefix
emerge -pt neovim # dry run, plan as a tree
emerge -a neovim # ask before acting
emerge -1 htop # as a dependency (does not go into world)
emerge -at aur/setrixtui abs/nano @fonts --jobs=7 --jobsa=2 # several packages at once: 7 at a time from repos, 2 AUR/ABS builds at a time
# Removing
emerge -C neovim # remove a package (--unmerge)
emerge -c # remove orphans (--depclean)
emerge -cp --show-protected # orphans, plus those kept back by world, package.protect or the selected profile
emerge --prune # remove everything that is not in world
# Updating
emerge --sync # refresh package databases
emerge -u # full upgrade (repos + AUR)
emerge -u --devel # ...and rebuild -git/-hg/-svn/-bzr packages with a newer upstream
emerge -u --exclude linux --keep-going # exclude the `linux` package from the upgrade
# World and sets
emerge @world # install everything from world that is missing
emerge @desktop neovim # a custom set + a regular package
emerge --select neovim # add to world without installing
emerge --deselect neovim # remove from world without uninstalling
# Search and info
emerge -s neovim # search: repos => ABS => AUR
emerge -S neovim # search by description
emerge -sv neovim # verbose
emerge -s abs/nano # ABS only (aur/ and <repo>/ work too)
emerge --info # system information
emerge --news # Arch Linux news
# Security
emerge neovim-git --aur --pkgbuild-view # show/diff the PKGBUILD before building
emerge neovim-git --aur --edit # edit the PKGBUILD first
emerge --scan neovim-git --aur # audit only, no build
emerge --usepkgbuild ~/src/my-pkg # local PKGBUILD through the scanner and sandbox
emerge --usepkg ./foo-1.0-1-x86_64.pkg.tar.zst # prebuilt archive (pin + audit)
# Without installing
emerge -B neovim --aur # only build the archives
emerge -f neovim --aur --outdistfiles ~/ae-out # only download the whole tree into the chosen directory
emerge --usepkg ~/ae-out # install all archives from a directory in one transaction
# Recovery
emerge --resume # resume an interrupted transaction
emerge --undo # undo the last install/removal/depclean
emerge --revdep-rebuild # fix binaries with broken .so links
emerge --aelist # files left behind by AE ForceThe full flag table is at the end of the page.
Everything is configured under /etc/portage/. The config is system-wide only and owned by root.
| Path | Purpose |
|---|---|
make.conf |
Main config: default flags, colours, build flags, FEATURES |
package.mask, package.unmask |
What is never installed / exceptions |
package.protect, package.freeze |
What must not be removed / what must not be upgraded |
package.env, env/ |
Per-package build flags |
make.profile |
Profile (a symlink) |
world, sets/ |
Explicitly installed packages and custom sets |
repos.conf, ae-repos.conf |
Repository list (FEATURES="repos") and ae-* sections for pacman.conf |
hooks/ |
Custom alpm hooks |
resume.state, lastaction.state |
State for --resume and --undo |
Elsewhere: /var/lib/aura-emerge/repos/ — local repositories, /var/log/emerge.log — operation log, ~/.cache/aura-emerge/ — caches (PKGBUILD view, devel, news, builds), /var/db/repos/portage/profiles/ — profile database.
# Default flags. Spliced in before whatever you type (the command line always wins).
# Disable for one run: --ignore-default-opts.
EMERGE_DEFAULT_OPTS="--jobs=8 --tree --deep"
# Status-line colours (roles: ok, warn, error, info, special).
COLORS="ok=#FFB3AE warn=#E7BDB9 error=#FDB1AC info=#E7BDB9 special=#cba6f7"
# Build flags (see below)
CFLAGS="-march=native -O2 -pipe"
CXXFLAGS="$CFLAGS"
RUSTFLAGS="-C target-cpu=native"
MAKEFLAGS="-j$(nproc)"
NINJAFLAGS="-j$(nproc)"
OPTIONS=(strip docs !debug lto)
BUILDENV=(!distcc color check !sign)
# Switches for aura-emerge only
FEATURES="localrepo"Syntax is bash-like: KEY="...", KEY='...' (literal, no expansion) or KEY=(a b c). $(nproc) and $CFLAGS work in double quotes and unquoted. The file is opened with O_NOFOLLOW: a symlink is rejected.
| Key | Purpose |
|---|---|
EMERGE_DEFAULT_OPTS |
Flags spliced into every run |
COLORS |
Palette for status output |
FEATURES |
aura-emerge switches |
EMERGE_FREEZE |
Same as package.freeze, on one line |
CFLAGS CXXFLAGS CPPFLAGS LDFLAGS RUSTFLAGS MAKEFLAGS NINJAFLAGS BUILDENV OPTIONS |
AUR/ABS build flags |
EMERGE_DEFAULT_OPTS accepts modifier flags only (--ask, --verbose, --devel, --tree, --deep, --jobs=N, --jobsa=N, --searchdesc, --exclude=<atom>, etc.), so you cannot turn every run into --unmerge. Conflicting pairs are rejected when both are set: --aur/--abs, --aur/--repos, --no-sandbox/--unshare-net-build, --skippgp/--autopgp, --select/--deselect. A config value that conflicts with the command line is dropped. --abs and --repos do not conflict with each other.
COLORS — role=colour tokens; a colour is #RRGGBB or a name (red, bright-cyan, …). The last mention of a role wins; unknown roles and colours are skipped with a warning.
FEATURES — for aura-emerge only, never translated into makepkg (set ccache, check, strip in BUILDENV / OPTIONS). -name turns a token off, the last mention wins. Tokens:
| Token | What it enables |
|---|---|
localrepo |
local repositories ae-aur / ae-abs / ae-local (details) |
repos |
Portage-style repos.conf (details) |
Unknown tokens are read and shown in --info but do nothing. emerge --info prints the effective FEATURES and the values that override makepkg. => make.conf example
Gentoo (make.conf) |
aura-emerge (make.conf) |
|---|---|
CFLAGS, CXXFLAGS, RUSTFLAGS |
the same |
MAKEOPTS="-j$(nproc)" |
MAKEFLAGS="-j$(nproc)" |
USE="lto" |
OPTIONS=(... lto) |
FEATURES="ccache" |
BUILDENV=(... ccache) |
FEATURES (Portage functions) |
FEATURES for AE only: localrepo, repos |
Arch has no USE flags, so OPTIONS partly plays their role. Reference: GCC optimization options, rustc codegen options.
Build flags are set only in make.conf (and per package in package.env). There is no need to edit /etc/makepkg.conf for aura-emerge.
Before every AUR/ABS build, emerge generates a temporary makepkg.conf itself: it first sources the system one, then overrides it with the keys from make.conf, and that file is passed to makepkg via --config. Hence:
- the system
/etc/makepkg.confis only a base for keys thatmake.confdoes not have (PKGEXT, compression,DLAGENTS, etc.); on a key clashmake.confalways wins; - if
make.confhas no build keys at all, makepkg is left untouched; - inside the sandbox the user's
~/.config/pacman/makepkg.confhas no effect ($HOMEis empty); without the sandbox (--no-sandbox) makepkg sources it after the generated one, and a clashing key beats make.conf — emerge warns about it.
On security: values are escaped during generation (", `, \; a single-quoted value is never expanded), only tokens made of letters, digits and !_-+. are allowed in BUILDENV / OPTIONS (otherwise a warning, and the key stays as in the system file). The generated file lives in a private (0700) scratch directory outside the build tree so that prepare() / build() cannot rewrite it, and is deleted after the build.
Per-package build flags. An entry is an atom plus one or more env files from /etc/portage/env/. /etc/portage/package.env is a file or a directory.
# /etc/portage/package.env/neovim
abs/neovim lto.conf # repo prefix and '*' work as in package.mask
aur/*-git no-lto fast # several envs are applied in the given order
# /etc/portage/env/lto.conf (make.conf syntax; only build keys are honoured)
CFLAGS="-march=znver3 -O2 -pipe"
MAKEFLAGS="-j16"
OPTIONS="strip docs !debug lto"- Layering:
make.conf=> matchingpackage.enventries => each env file in order. The layer that set the key last wins; a key is replaced as a whole, not merged. The build reports which layer won. - Matching: by pkgbase or any pkgname.
- Scope: AUR/ABS builds only.
EMERGE_DEFAULT_OPTSin an env file is ignored with a warning. - Errors: a symlink, a malformed entry or a missing env file is skipped with a warning (file and line); the rest is applied.
package.mask lists packages this machine must never install. The check fires on every path: a request by name, a transitive AUR dependency, world provisioning, --select/-R/-u. A masked package is a hard stop, with no prompt and no flag to bypass it; the only way around is an entry in package.unmask.
/etc/portage/package.mask is a file or a directory (every regular file is read in name order; dotfiles are skipped; symlinks are rejected). One entry per line; *, a repository prefix and a trailing # comment are allowed.
ayugram-desktop-bin # a specific package, from any source
aur/*-bin # never install -bin packages from the AUR
*-git # no devel packages on this machine
extra/nano # a specific package from a specific repo
The repository prefix is honoured wherever the source is known (extra/nano fires only for extra, aur/foo-git only for the AUR). Portage version atoms (=cat/foo-1.2, >=cat/foo) are not supported: matching is by name, and such entries are reported with a warning and skipped. A mask is permanent, unlike --exclude, which applies to one run.
package.unmask (same syntax) lists exceptions: a package covered by an entry passes even if package.mask or the active profile's mask blocks it. The root helper honours it too.
aur/some-git # allowed, even though *-git is masked above
package.protect lists packages that must not be removed (syntax as in package.mask). It applies to -C, -c, --prune and removals caused by conflicts. --deselect can still drop the name from world, but the package stays installed and depclean will not touch it. @system packages from the profile are protected the same way.
package.freeze (and the optional EMERGE_FREEZE in make.conf) keeps packages at the installed version during -u, including AUR/ABS rebuilds. Stricter than pacman's IgnorePkg: it also applies to a selective emerge -u pkg.
/etc/portage/make.profile is a symlink to a profile directory (Portage layout). --list-profiles shows the tree from /var/db/repos/portage/profiles; a parent of the form repo:path is looked up in /var/db/repos/<repo>/profiles/. A profile may contain:
parent— chains are expanded all the way down;package.profile—*means the starter@systemset (the old namepackagesis still read);package.mask—-atomor!atomlifts a mask inherited from a parent;package.protect,make.defaults.
emerge @system installs the profile's system set; every package.profile entry is protected from depclean just like world.
emerge --list-profiles
sudo emerge --set-profile 12
# or via the eselect link: eselect profile set 12/usr/bin/eselect => emerge gives a minimal eselect (only eselect profile list|set|show). --list-profiles and --set-profile do not need it.
/etc/portage/world is the list of all explicitly installed packages. Entries are added on install, removed on removal, and can be edited by hand (one per line).
core/nano
extra/firefox
aur/ayugram-desktop-bin
abs/nano
local/my-pkg
chaotic-aur/visual-studio-code-bin
Prefixes: an official repository name, aur/, abs/, local/ (--usepkgbuild and --usepkg), Err/ (source unknown).
About
Err/: an installed package whose origin could not be determined, or anaur//abs/entry that stopped resolving.--regen-worldand--regen-setskeep a known prefix rather than falling back toErr/. Duringemerge @worldsuch entries are only listed; you can install them with--err-install.
If one name in a batch install is not found, the rest is still installed; the missing ones are printed at the end and the exit code is non-zero.
@world has two meanings:
| Command | Action |
|---|---|
emerge @world |
Provision: installs what is in world but not yet installed. Keep world in your dotfiles, clone it onto a new machine, run this |
emerge -u / emerge -u @world |
Upgrade: upgrades everything installed (repos + AUR); does not read world |
emerge --sync |
Only refreshes databases (-Sy / -Syy) |
Custom sets. /etc/portage/sets/<name> (or <name>.set) is invoked as @<name>. One package per line, # comments allowed; a line @other nests another set (recursive, cycle-safe). Installing @name records @name in world, so the set's members are protected from depclean until you remove them from the set file. If both game-kit and game-kit.set exist, @game-kit is rejected as ambiguous.
# /etc/portage/sets/game-kit
steam
lutris
gamemode
aur/protonup-qt
emerge @game-kit @dev-tools neovim # sets combine freely
emerge --list-sets # list sets (also: emerge @<TAB>)
emerge -s @game-kit # where each package comes from: repo / aur / not found
emerge --batchinstall pkgs.txt # same format, but the file can live anywhere and is not registered@world and @preserved-rebuild are actions, so -s @world and -s @preserved-rebuild are errors.
Without a prefix, emerge looks in the official repositories and falls back to the AUR. A prefix picks the source: aur/<name>, abs/<name>, <repo>/<name>. Prefixes work in commands, in world, in sets and in -s. --aur, --repos, --abs set the source for the whole run; AUR-only dependencies are built recursively.
--jobs=N installs up to N official-repo packages at once, --jobsa=N runs up to N AUR/ABS builds (defaults 1 and 1). --load-average=X holds back new builds while the one-minute load is above X (but never when nothing else is running). --nospinner removes the live Jobs line. Defaults are handy to keep in EMERGE_DEFAULT_OPTS.
>>> Emerging (3 of 12, 16%) noctalia-5.1.0-1.1
>>> Jobs: 26 of 26 complete 2m53s Load avg: 2.49, 3.11, 2.17
During a quiet build a heartbeat is printed every 30 s (pid, RSS: still building … — process alive); if the process is killed by a signal (OOM/SIGKILL), that is reported explicitly. If the helper rejects one package of a batch (for example, because it is masked), the batch is retried one package at a time so the rest still gets installed. --debug (or AE_DEBUG=1) shows compiler output live.
Shows the plan (with -p or before a real install) as a dependency tree. By default one level is shown; --deep goes to the bottom, --deep=N goes N levels.
[ebuild N ] noctalia-5.1.0-1.1
[ebuild N ] `-- libqalculate-5.12.0-1.1
[ebuild N ] `-- sdbus-cpp-2.3.1-1.1
A dependency that is not named in anyone's "Depends On" (resolved through provides, or deeper than --deep) is still shown, just without a parent. For a clean install via --aur, transitive AUR-only dependencies are not yet resolved at the plan step, so the tree is flat there.
--exclude <atom> (repeatable or comma-separated) excludes a package from the run: installs, -u, @world, --depclean/--prune (protects it from removal) and --revdep-rebuild.
--keep-going does not stop a batch operation (@world, -u, --batchinstall, several packages) at the first error: failures are remembered, a summary is printed at the end and the exit code is non-zero. The next --resume retries only what failed.
emerge -u --exclude linux --exclude aur/ayugram-desktop-bin
emerge -u --keep-going
emerge --resumeInstalled packages that block an incoming one are shown before the install starts, as Portage blockers:
[ebuild N ] pipewire-jack-1:1.4.2-1
[conflict ] jack2-1.9.22-1 ("jack2" is blocking pipewire-jack-1:1.4.2-1)
The check covers every source in the run: the repo plan (libalpm), AUR packages and their AUR dependencies, ABS packages (from .SRCINFO: provides/conflicts) and a bare @world. Sources are also checked against each other: if two packages in one run block each other (say, one from a repo and one from the AUR), it is shown as [blocks] and nothing is installed. Installed blockers need a single Yes (always asked); the packages that need them are listed first, and package.protect entries are never removed. Whatever the pre-check could not see (for example, no network for .SRCINFO) is still caught during the package's installation.
If an install would overwrite a file no package owns, emerge asks AE Force: Create .aenew for conflict files?. "Yes" leaves your file in place and stores the package's version as <file>.aenew.
| Flag | What happens |
|---|---|
--aeforce |
no prompt; your file is moved to <file>.aeforce, the new one takes its place |
--noaefile |
no prompt; no .ae* files are left: old kept, new discarded (with --aeforce: old discarded, new kept) |
<file>.aepark is left after an interrupted install; if the name is taken, a .N suffix is added. emerge --aelist lists all such files, emerge --aeclean [new|old|park|all] removes them after a prompt (no argument = all).
libalpm runs every *.hook on install, removal, -U and -Su, just like pacman (depmod, DKMS, mkinitcpio/dracut, fontconfig and icon caches, grub-mkconfig, …). On a name clash the earlier directory wins:
/usr/share/libalpm/hooks/ hooks shipped by packages
/etc/pacman.d/hooks/ administrator hooks
/etc/portage/hooks/ aura-emerge's own hooks (alpm-hooks(5) format)
All three are always registered, even without HookDir in pacman.conf. Progress: >>> Running pre-transaction hooks... / >>> (2 of 4) Install DKMS modules.
emerge -u upgrades the repos and the AUR (it does not read world). Two things a plain upgrade misses:
Devel packages (-git, -hg, -svn, -bzr). The AUR version changes only when the maintainer re-uploads the package, so -u often misses upstream changes. -u --devel (upgrade) and --check-devel (report only) close that gap: for each installed devel package they take the git+ URL from the PKGBUILD, run git ls-remote (no clone needed) and compare with the hash from last time (~/.cache/aura-emerge/devel.state). Git only for now; -hg/-svn/-bzr are reported as "couldn't determine" rather than skipped silently.
Broken library links. Arch has no preserved-libs tracking, so there are two tools:
@preserved-rebuildcollects the declared dependencies of all installed packages (pacman -Qi), checks them withpacman -Tand offers to reinstall the missing ones with--asdeps(so they do not end up in world via--regen-world-from-explicit);--revdep-rebuildreads ELF files (DT_NEEDED,DT_RPATH/DT_RUNPATH) and finds binaries linked against a.sothat no longer exists (the classic breakage after anopenssl/icu/boostupgrade). AUR/local packages are rebuilt through the sandbox; official-repo packages cannot be rebuilt here, so the missing library is looked up withpacman -Fand the package that provides it is offered for installation.--excludeand the mask apply.
emerge -u --devel
emerge --check-devel
emerge @preserved-rebuild -p # list only
emerge --revdep-rebuild -p # scan only
emerge --revdep-rebuild # scan, then ask before fixing-C removes the named packages, -c removes orphans, --prune removes everything that is not in world. -C prints what is selected, protected and omitted; then -C and -c wait 5 seconds (Unmerging in: 5 4 3 2 1, Ctrl-C aborts) unless -a has already asked or -p is set. After -C, the names are also dropped from world.
-c never removes a world entry, a member of a set recorded in world, a package.protect entry or an @system package from the profile. It reports how many were skipped; --show-protected lists them. With arguments, -c acts as a dependency-aware unmerge: only packages nobody needs are removed (-cv shows the reverse dependencies that block removal).
emerge -cp --show-protected
emerge -c
emerge --unmerge --ask linux-zen-headers-s searches the official repos, then ABS, then the AUR. -s aur/<name> — AUR only, -s abs/<name> — ABS, -s <repo>/<name> — that repo first; --repos limits the search to official repos; --search-all shows the same name from every repo. Masked packages are tagged [ Masked ]. -sv adds the installed version and, for the AUR, the maintainer, votes, popularity, homepage, last-update date and license.
emerge --info prints the version (and the libalpm version), kernel, CPU/memory/swap, the effective --jobs/--jobsa, every repository in pacman.conf order with its mirror, values from makepkg.conf and make.conf (and which overrides won), FEATURES, the profile, mask/world sizes and merge-log totals.
emerge --pkginfo nano is an installed-package card (like a short pacman -Qi); with -v it also lists the files.
| Flag | What it does |
|---|---|
-B, --buildpkgonly |
Archives only, no install: official => into CacheDir; AUR/ABS/local => built |
-f, --fetchonly |
Download only, the whole dependency tree: official => archives in CacheDir; AUR/ABS => clone + sources verified in the sandbox (makepkg --verifysource, into SRCDEST), for the package and its AUR/ABS dependencies; official dependencies as archives. No build, no install |
--outdistfiles <DIR> |
With -B/-f: copy the archives (with dependencies) into DIR; AUR/ABS checkouts are linked there |
-O, --nodeps |
Skip dependency resolution: official targets (pacman -Sdd); with --usepkg — a single archive (-Udd). AUR/ABS: not implemented, a warning is printed |
-o, --onlydeps |
Only the dependencies of official targets (not the targets themselves), implies -1. AUR/ABS: not implemented |
-B and -f do not use local binaries from ae-*. What you get can be deployed later: emerge --usepkg <DIR> installs every archive in a directory in one transaction, emerge --usepkg -O <file> installs a single archive without dependencies.
--resume continues an interrupted transaction (--skipfirst skips the first package). --undo rolls back the last successful operation (one history step):
- after an install — removes only the packages that were new in that run and restores installed packages that were removed as blockers;
- after a removal — reinstalls from the recorded source (
Err/andabs/are only listed); - after depclean — reinstalls the removed orphans as dependencies (not added to world): repo packages from the repos, local builds through the AUR if it still has them. Versions are recorded: if the repos now have a different one, you are told; a package that is nowhere to be found is listed with a
pacman -Uline for the cached file. If some packages failed to come back, only they remain in the saved state and--undocan be run again; - after
-u— not supported (there is no version snapshot).
/var/log/emerge.log is append-only, one line per event; a failed write never breaks a merge. AUR/ABS packages are built one at a time, so each has its own timer; pacman -S/-Syu is a single transaction, so its line holds all atoms and the total time. --info shows the totals.
2026-09-21 08:51:44 MERGE aur noctalia-5.1.0-1.1 (12s)
2026-09-21 09:03:02 MERGE repo nano-8.0-1 vim-9.1-1 (4s)
2026-09-21 09:10:05 UNMERGE - old-package-2.0-1
--log <PATH> additionally writes a session log (command, emerge.log lines, full build output) — for bug reports; append-only.
emerge --news fetches the Arch Linux news RSS feed; read state is kept in ~/.cache/aura-emerge/news.state (no root needed).
emerge --news # list, unread marked [N]
emerge --news 3 # read item 3
emerge --news all # mark everything readWith FEATURES="localrepo", every package aura-emerge built from the AUR, ABS or a local PKGBUILD (or took from a --usepkg archive) is, after the audit and install, filed under /var/lib/aura-emerge/repos/<repo>/ and the repository database is refreshed. The directories are owned by root (0755). It is an aurutils analogue: the aur / abs / local sources are kept apart at the libalpm database level.
| Repository | What it holds |
|---|---|
ae-aur |
AUR builds |
ae-abs |
ABS builds (--abs) |
ae-local |
--usepkgbuild and --usepkg |
The repositories are filled either way, but pacman sees them only if they are listed in /etc/pacman.conf after the official ones (core / extra / multilib). Two ways:
# 1) include the shipped file (misc/ae-repos.conf => /etc/portage/ae-repos.conf)
Include = /etc/portage/ae-repos.conf# 2) or write the sections yourself
[ae-aur]
SigLevel = Never
Server = file:///var/lib/aura-emerge/repos/ae-aur
[ae-abs]
SigLevel = Never
Server = file:///var/lib/aura-emerge/repos/ae-abs
[ae-local]
SigLevel = Never
Server = file:///var/lib/aura-emerge/repos/ae-localWhat this gives you: pacman -Qm no longer lists these packages, pacman -Si ae-aur/<pkg> works, and pacman -S / -Su can reinstall them from the audited copy. On a name clash the first repository that has the name wins, so the ae-* sections must come last — the official ones keep priority. SigLevel = Never is deliberate: nothing here is signed, the packages were audited and sha256-pinned by emerge itself, and the directories are root-owned, so nobody else can swap a file.
What emerge does next:
- Reuse: a regular install of an AUR package whose version in
ae-aurmatches the current one in the AUR is installed from the local repo — no clone, no build.--editand--pkgbuild-viewforce a rebuild;-B/-fdo not use local binaries; an explicitae-aur/<name>goes through the normal repo install. - Cleanup:
-C,-cand--prunealso drop what they removed fromae-*.emerge --localrepo-cleanremoves every entry whose package is no longer installed (-ponly lists,-aasks). - Empty databases are created by the package's
post_install/post_upgradehook, byemerge --syncand by the first publish, sopacman -Sydoes not stumble on a listedfile://server with no packages. - A publish failure is a warning, not a failed merge. If there are no
[ae-*]sections, emerge prints a hint with theIncludeline once.
A Portage-style repository list: /etc/portage/repos.conf (a file) or /etc/portage/repos.conf/*.conf. Enabled with FEATURES="repos". Then emerge --info shows the order by priority (descending) and writes /etc/portage/ae-generated-repos.conf. Include it in pacman instead of listing the same repositories by hand: remove the corresponding [repo] blocks from pacman.conf and add
Include = /etc/portage/ae-generated-repos.conf| Key | Meaning |
|---|---|
priority |
Higher = more preferred. On a tie, declaration order (a warning only, the numbers are not rewritten) |
sync-uri |
One or more URLs ($repo / $arch) |
include |
Path to a pacman mirrorlist (Server = …); compatible with rate-mirrors. Explicit sync-uri entries come first |
verify-signature |
A SigLevel string as is (Never, Required DatabaseOptional, …) |
location |
Optional (for file:// — the repository directory) |
The shipped template is misc/repos.conf (sections commented out):
[g14]
priority = 55
sync-uri = https://arch.asus-linux.org
verify-signature = Required DatabaseOptional
[core]
priority = 50
include = /etc/pacman.d/mirrorlist
verify-signature = Required DatabaseOptional
[ae-aur]
priority = 10
sync-uri = file:///var/lib/aura-emerge/repos/ae-aur
verify-signature = NeverWith FEATURES="localrepo", missing ae-aur / ae-abs / ae-local sections are filled in with priorities 10 / 9 / 8.
The frontend never runs as root. If started as root (sudo emerge …, doas, pkexec, su -), it first starts the root helper, then permanently drops privileges to the invoking user (taken from AE_USER, SUDO_UID, DOAS_USER, PKEXEC_UID or the audit login uid; if none is found — it stops). Started as a regular user, the helper is launched through sudo on first need. The resolver, AUR/ABS builds, the sandbox and all caches run unprivileged; all libalpm work (install/remove/sync/upgrade/-U, signature checks) goes through the helper (--ae-service), which validates every request and enforces package.mask itself (helper refused: … masked by …).
Helper start conditions: the binary is owned by root and not group/world-writable (install -m755 -o root -g root), uid = 0, stdin/stdout are pipes (not a TTY), the parent process is alive. File conflicts on -Su / -U are resolved through AE Force instead of breaking the whole upgrade.
Before every AUR install, the PKGBUILD (and any .install) is fetched from cgit and scanned in two layers:
- AST (
tree-sitter-bash):curl|sh,base64/xxd | sh,source <(curl …),eval "$(curl …)",sudo/pkexec/doas, inline execution for python/perl/ruby/node/lua,sh -cwith a suspicious payload, top-level command substitution, string-concatenation bypasses, and so on. - Line heuristics:
chmod 777, bare IPv4 addresses, third-party package managers (npm/pnpm/bun/yarn/pip/gem install …, remote-onlycargo install/go install),bash <(curl …),curl … | python3/perl/node/…, unpacking straight into a shell (gunzip/zstd -d/unzip -p/tar -xO | sh),/dev/tcpand/dev/udp, heredocs fed to a shell, paste sites,.onion, anti-sandbox checks, known campaign IOCs (Atomic Arch, openconnect-sso, the 2018compromised.txt, …).
Findings are Suspicious or ConfirmedIoc. A hit is not a hard block: you get the file and line, a cgit link and Continue anyway? [y/N].
Auxiliary files. When the checkout is on disk (a build, or --usepkgbuild <PATH> --scan), the following are checked as well:
- the
Makefile(Makefile/makefile/GNUmakefile) and shell scripts referenced by the PKGBUILD (*.sh,*.bash,*.zsh,*.fish) — line by line:curl|sh, base64/hex in shell, bare IPs and the rest of the shell IOCs; - patches (
*.patch,*.diff,*.dpatch,*.pch, or content that looks like a unified/git diff) — by headers and added lines: paths outside the source tree (absolute,..,.git), symlink creation, binary hunks, overly long added lines, network calls in build/script targets, and the same shell IOCs.
--scan <pkg> --aur sees only what cgit serves (PKGBUILD and .install).
--pkgbuild-viewshows the PKGBUILD right before the build and asks for confirmation: a diff against the last copy you were shown (cache in~/.cache/aura-emerge/pkgbuild-view/) or the whole file the first time. If you decline, it offers to open$EDITORinstead of just skipping the package. It works after--edit, so you see your own changes. It applies only to directly requested AUR/ABS packages — not to recursive dependencies and not to batch paths (@world,-u,--undo).--usepkgbuild <PATH>builds and installs a local directory with a PKGBUILD through the same pipeline as the AUR/ABS (scanner => sandbox) instead of a baremakepkg -si.PATHmust contain aPKGBUILD; a missing.SRCINFOis generated. It combines with--pkgbuild-view,-a,-1,--skippgp,--no-sandbox,--unshare-net-build,--skip-srcinfo-regen, but not with packages/@setsor--aur/--abs. It is recorded in world aslocal/unless-1is given.--usepkg <FILE…|DIR>installs prebuilt.pkg.tar.*archives (makepkg output, a package from a file-based repo, a directory after-f --outdistfiles) with no PKGBUILD at all. Each archive is hashed, unpacked and audited, re-hashed right before the privileged install, and only then handed to libalpm (details in "Auditing prebuilt archives"). Recorded in world aslocal/unless-1is given. Several archives in one run form a single transaction; dependencies among them are resolved together.--scanaudits the PKGBUILD (+.install) without building or installing: for the AUR it takes the files from cgit, for a local directory —--usepkgbuild <PATH> --scan. The report is the same as before a build, without the "Continue anyway?" prompt. Non-zero exit on any finding, so it is script-friendly. Not yet available for--abs.
emerge neovim-git --aur --pkgbuild-view
emerge --usepkgbuild ~/src/my-pkg --pkgbuild-view --skippgp
emerge neovim-git --aur --scanAUR and ABS builds run pkgver() / prepare() / build() / check() / package() inside bwrap. This is mandatory; the only way out is an explicit --no-sandbox. If bubblewrap is not installed, the build is rejected.
- an empty tmpfs over
/homeand/run(no real$HOME, no session D-Bus, ssh-agent or gpg-agent); --clearenvplus a small allowlist (PATH,TERM,LANG, the build destination directories, …);- a copy of the GnuPG keyring with public keys only;
- PKGBUILD and
*.installare re-mounted read-only; - writes only to the build directory (+ the configured
PKGDEST/SRCDEST/ …); - the network is shared by default, other namespaces are disabled;
fakerootinpackage()runs in a nestedbwrapwith uid 0;- a seccomp denylist (ptrace, kexec, module load/unload, mount/umount, pivot_root, reboot, swapon/swapoff, iopl/ioperm, bpf, userfaultfd, …).
| Flag | Effect |
|---|---|
--no-sandbox |
Disable bwrap; plain makepkg -si (also skips the confirmation of the no-audit fallback) |
--unshare-net-build |
Network only for download and prepare(); build()/check()/package() have none |
Dependency installation (pacman -S) and the final pacman -U run outside the sandbox — they do not execute PKGBUILD code.
The third barrier before installation: a prebuilt *.pkg.tar.* (a build result or --usepkg) is inspected with bsdtar:
- setuid/setgid binaries;
.INSTALLscripts (re-scanned with the PKGBUILD scanner);- sensitive paths: alpm hooks, systemd units, sudoers, udev, tmpfiles.d, binfmt.d, pam.d, dbus system.d, NetworkManager dispatcher.d, environment.d, sysusers.d,
ld.so.preload, and so on; - path traversal and symlink names among the archive members.
On a TTY a confirmation is required even without --ask; in non-interactive mode — a warning and carry on. A failed bsdtar audit stops the install instead of installing without an audit.
A PKGBUILD whose dependencies cannot be resolved statically (no .SRCINFO and a dynamic depends=(…)) is the only build path that ends in a bare makepkg -si with no sandbox and no audit. It never runs silently: interactively — an explicit Yes/No question for that package, with --noconfirm — a refusal (fail-closed). --no-sandbox skips this question: it is a conscious opt-out of the sandbox for the whole run.
- Arch news text is sanitised (ANSI/bidi cannot reach the terminal or
news.state). - Config, mask, env and world files are opened with
O_NOFOLLOW, so a symlink cannot be slipped in through a race. - Rust dependencies are checked with
cargo deny(make deny).
git clone https://github.com/Undercat037/ae-scanner-checker.git
emerge --usepkgbuild ./ae-scanner-checker --scan| Flag | Description |
|---|---|
-s, --search |
Search for packages |
-S, --searchdesc |
Search by description |
--search-all |
With -s: show the same name from every repo (like pacman -Ss) |
-sv |
Detailed package information |
-v, --verbose |
Verbose output / detailed info during search (-sv) |
-u, --update |
Full system upgrade (does not read world) |
--devel |
With -u: also rebuild -git/-hg/-svn/-bzr packages whose upstream moved ahead |
--check-devel |
Show devel packages with upstream changes (no rebuild) |
-C, --unmerge |
Remove packages (unmerge) |
-c, --depclean |
Remove orphans (depclean) |
--show-protected |
With -c: show orphans kept only because they are in world |
-p, --pretend |
Pretend (dry run) |
-a, --ask |
Ask before acting |
--sudoloop |
Keep the sudo timestamp warm (refreshed every 60 s) for the whole run |
-1, --oneshot |
Install as a dependency (does not go into world) |
-n, --noreplace |
Do not reinstall if already present (same or newer version) |
--with-optdeps |
Also install optional dependencies of official-repo packages |
--aur |
Force AUR only (AUR-only dependencies are always built recursively) |
--repos |
Official repositories only (leave the AUR alone) |
--abs |
Build from ABS (pkgctl) in the bwrap sandbox |
--no-sandbox |
Disable bwrap for AUR/ABS; plain makepkg with no isolation (also skips the fallback confirmation) |
--unshare-net-build |
No network during build()/check()/package() (the network stays on in prepare()) |
--skippgp |
Skip PGP checks during ABS builds (--skippgpcheck) |
--autopgp |
Auto-import missing PGP keys before an --abs build |
--edit |
Edit the PKGBUILD in $EDITOR before building (requested package only); regenerates .SRCINFO after saving |
--skip-srcinfo-regen |
With --edit: do not regenerate .SRCINFO |
--pkgbuild-view |
Show/diff the PKGBUILD and confirm before building (requested package only; on refusal offers $EDITOR) |
--usepkgbuild <PATH> |
Build and install a local directory with a PKGBUILD (scanner + bwrap); recorded in world as local/ without -1 |
--usepkg <FILE…|DIR> |
Install local .pkg.tar.* archives through audit + helper -U in one transaction (dependencies among them are resolved together; a directory = every archive in it, e.g. the result of -f --outdistfiles); recorded in world as local/ without -1 |
-O / --nodeps |
With --usepkg: install exactly one archive file with no dependency check (pacman -Udd) |
--scan |
Audit PKGBUILD/.install only, no build/install; non-zero exit on findings (AUR or --usepkgbuild) |
--sync |
Synchronise package databases |
--refresh |
Force -Syy (with --sync or -u) |
--info |
System information, like Gentoo's emerge --info |
--pkginfo <pkg…> |
Details of an installed package (-v lists files) |
--news [N|all] |
Arch Linux news: no argument — list, N — read an item, all — mark everything read |
--select |
Add to world without installing |
--deselect |
Remove from world without uninstalling |
--check-world |
Show world entries that are missing from the system or installed non-explicitly |
--sync-explicit |
Mark as dependencies the explicitly installed packages that are not in world, in a world @set or in package.profile (so -c can see them). Standalone: runs immediately (-p lists, -a asks). With an install/upgrade: after it completes successfully. Can go in EMERGE_DEFAULT_OPTS |
--prune |
Remove packages that are not in world |
--localrepo-clean |
Drop packages that are no longer on the system from ae-aur / ae-abs / ae-local (FEATURES="localrepo"; -p lists, -a asks) |
--regen |
Recreate the package metadata cache |
--regen-world |
Re-resolve repository prefixes in world |
--regen-sets <SET> |
Re-resolve prefixes in a custom set (@game-kit or game-kit) |
--regen-sort |
With --regen-sets: also sort the file (comments and grouping are lost) |
--regen-world-from-explicit |
Migration: add explicitly installed packages (pacman -Qeq) that are not in world, in a world @set or in package.profile to world (one-off). -p only lists, -a asks |
--err-install |
With @world: also install Err/ entries (source unknown) |
--resume |
Resume an interrupted transaction |
--skipfirst |
With --resume: skip the first package |
--undo |
Undo the last install/removal/depclean (one step; -u is not rolled back) |
--clean-source-cache |
Clear the persistent VCS source cache and exit |
--batchinstall <FILE> |
Bulk install from a text list (same format as a custom set) |
--list-sets |
List available @sets (also used by completion) |
--exclude <ATOM> |
Exclude a package from this run (repeatable / comma-separated) |
--keep-going |
Do not stop a batch operation at the first error; failures go into the summary at the end |
--revdep-rebuild |
Rebuild packages whose binaries link against a missing library |
-t, --tree |
Show the plan as a dependency tree |
-D, --deep[=N] |
With -t: nest N levels, without a value — all of them |
--jobs <N> |
Max parallel official-repo installs (default 1) |
--jobsa <N> |
Max parallel AUR/ABS builds (default 1) |
--load-average <X> |
Do not start new builds while the one-minute load average is above X |
--nospinner |
No live Jobs line |
--color <y|n|auto> |
Force colour on or off |
--quiet-build=n |
Same as --debug (Gentoo spelling) |
--list-profiles |
List Portage-style profiles (like eselect profile list) |
--set-profile <N|PATH> |
Set /etc/portage/make.profile: an index from --list-profiles or a path |
--aeforce |
AE Force: move files that block an install to <file>.aeforce without asking |
--noaefile |
AE Force: leave no .ae* files (keep the old one, discard the new; with --aeforce: discard the old one) |
--aelist |
List files left by AE Force (.aenew / .aeforce / .aepark) |
--aeclean [new|old|park|all] |
Remove AE Force files after a prompt (no argument = all) |
--ignore-default-opts |
Ignore EMERGE_DEFAULT_OPTS from make.conf for this run |
--debug |
Show makepkg/compiler output live (also AE_DEBUG=1); hidden by default to keep the >>> lines readable, and when a build fails the saved log is still printed |
--log <PATH> |
Write a session log (command, emerge.log lines, full build output) for bug reports — no ` |
-B / --buildpkgonly |
Archives only, no install (official => CacheDir; AUR/ABS/local => build) |
-f / --fetchonly |
Download only, the whole dependency tree: official => archives in CacheDir (with dependencies); AUR/ABS => clone + sources verified in the sandbox (makepkg --verifysource, into SRCDEST), for the package and its AUR/ABS dependencies, official dependencies as archives. No build, no install |
--outdistfiles <DIR> |
With -B/-f: copy the archives (with dependencies) into DIR; AUR/ABS checkouts are linked there |
-N/--newuse, -e/--emptytree, -q, -o, -l, -A, --onlydeps, --complete-graph, --changed-use, --backtrack, --columns, --newrepo, --reinstall, --with-bdeps, --metadata, --clean, --config, --noconfmem, --verbose-conflicts |
Gentoo compatibility: accepted, do nothing |
-h, --help |
Help |
-V, --version |
Version |
The emerge(1) man page is generated from the CLI (emerge --gen-manpage), so it cannot drift from --help.
Copyright (C) 2026 Undercat037 License GPL-3.0