The project lifecycle is now documented as stable: its public API has remained stable since 0.1.0 and is protected by an extensive regression suite and repeated independent adversarial reviews.
create_metapackage(reexport = TRUE) now exposes
explicit component exports through lazy, read-only active bindings
without making components installation dependencies. Generated
metapackages can load offline before their components are installed, and
the bindings resolve after a later installation.
Runtime re-exports now exclude S4 class and method directives,
reserve every generated helper symbol, preserve untracked
reexports.R and reexports.Rd files during
updates, avoid loading components for startup reporting, and support
installation into a new library directory.
Component inputs now accept a bare package name when exactly one
archive in the supplied directories declares that Package
identity. Ambiguous versions or sources are rejected with the full
candidate list.
pegeler/metapackage as a related
online declarative metapackage.Bare package-name discovery now warns when an unreadable archive is excluded and suppresses uncontrolled tar diagnostics while retaining readable matches.
Runtime re-exports quote non-syntactic names in generated NAMESPACE files, so legal exports containing spaces or Unicode characters produce installable metapackages and working active bindings.
removed_files now includes partial documentation
outputs that a generation call created and cleaned up after roxygen
failed. Dry-run plans continue to report only removals that are knowable
before generation starts.
This release makes the package accept component packages as an
organisation actually keeps them, instead of requiring one directory,
one archive extension, and a version in every filename. Package identity
now comes from each archive’s DESCRIPTION rather than its
filename, generation can report a plan without writing anything, and the
checks that concern project tidiness can be relaxed individually. The
checks that protect whoever installs the generated meta-package cannot:
they remain hard errors during generation.
It also supersedes 0.2.0, which was prepared and verified but never submitted. Everything listed under 0.2.0 below reaches CRAN for the first time here, so a user updating from 0.1.0 should read both sections.
reexport is deprecated and ignored. Generated
metapackages attach installed components, so their exports remain
available directly or through each component namespace, but they are not
copied into the metapackage namespace. Re-exporting would require
declaring components as installation-time dependencies, which conflicts
with explicit offline component installation; the option did not produce
a valid package in the published 0.1.0 release.packages that is an existing file is
used as a path, so components can come from several
directories in one call and mix .tar.gz,
.tar and .zip. Stems still work, resolved
against pkg_dir, which now accepts more than one
directory.DESCRIPTION, not from its filename, so a filename
without a version is valid. A filename that disagrees with the
DESCRIPTION produces a warning and the
DESCRIPTION wins.DESCRIPTION at its root, built for you with the optional
pkgbuild package. It requires
include_archives = TRUE, because the archive built for it
lives in a temporary directory that does not outlive the call.packages may be the path to a
manifest: one component per line, # for
comments. Relative paths resolve against the manifest’s own directory,
absolute and ~ paths are used as given, and bare filenames
are also looked up in pkg_dir, so the list can live under
version control while the archives do not. A missing entry reports every
directory that was searched.create_metapackage(dry_run = TRUE) resolves and
validates everything and returns the plan — components, installation
order, files that would be written, and every validation finding —
without creating dest_dir or writing
anything.create_metapackage() gains a final
tolerate argument taking a closed list of named
relaxations: "filename_mismatch" silences the
filename-versus- DESCRIPTION warning, and
"unincluded_local_dep" turns the error for a local
dependency available in the supplied sources but omitted from
packages into a warning. That second relaxation means the
dependency does not travel, so the recipient has to supply it. Unknown
names are errors, not silent no-ops.tolerated table naming
every applied relaxation, the component it affected, and why.on_component_error = "skip" generates from the
components that are valid instead of aborting, and reports the ones it
left out. The exclusion is transitive: a component that depends on an
excluded one is excluded too, and the chain is reported. When the
omitted archive can be read, its declared Package drives
the exclusion; when it cannot, the filename fallback is reported
explicitly. Excluding every component is an error.tolerate, and there is
no switch that turns validation off as a whole. It also states
explicitly that bigbang does not run
R CMD check on component packages, so a component with
check warnings or notes can be included.create_metapackage(update = TRUE) regenerates an
existing project, which relaxes the rule that a destination must be new
or empty. Generation records a manifest of the files it wrote together
with their content hashes; update rewrites only those, and
refuses to run if the manifest is missing or if a generated file was
modified or removed by hand.update
refuses when a generated file, or any parent directory on the way to it,
is a symbolic link, and it replaces generated files and shipped archives
atomically, so a regeneration cannot write outside the project
tree.update
reconciles: generated files and shipped component archives that the new
plan no longer includes are removed transactionally, so the regenerated
meta-package cannot end up importing from a component it no longer
declares. Before changing an existing project, bigbang backs up all
generated files and its manifest. If generation or reconciliation fails,
that state is restored and the update remains retryable. Dry runs and
completed updates report the affected paths in
removed_files; removing a component may remove the last
available copy of its shipped archive.<meta>_install(only = ...) installs a subset;
local dependencies of the selection are added automatically, and an
unknown component name is an error.<meta>_install(lib = ...) chooses the library in
which components must be installed and verified. Non-local dependencies
may already be available in that library or anywhere on
.libPaths(); they no longer need to be duplicated into the
component destination.create_metapackage(install_upgrade = ...) fixes the
default upgrade policy of the installer that gets emitted, so the person
generating decides whether recipients stay pinned to the versions being
shipped or keep anything newer they already have. The default is
unchanged.order field as dry-run plans. The planned
files field remains specific to dry runs.install_local_pkg() and generated installers now report the
error lines of the installation subprocess itself – for example, which
dependency it could not find – instead of only a generic verification
failure.update = TRUE no
longer deletes or leaves partially overwritten an untracked Rd file
whose name is reserved for generated documentation. Such files are
backed up before roxygen runs and restored without being adopted into
the generation manifest.inst/archives/
remains untracked and is never removed by a later update..git/.on_component_error = "skip", a failed update input
no longer authorizes deletion of a previously shipped component archive.
If the old component cannot be identified safely, archive reconciliation
is deferred until a clean update.verbose = FALSE in both install_local_pkg()
and generated installers; failure details still retain the child
process’s ERROR lines.install_local_pkg(lib = ...) and generated installers
now distinguish the component destination from the dependency search
path: a component present only elsewhere is installed into
lib, while a non-local dependency already available
elsewhere on .libPaths() is reused. This also works under
the dependency isolation used by R CMD check on
Windows.PKG_1.0.TAR.GZ, as they often arrive from Windows — was
shipped under its original name while the generated installer looked for
the normalised one. The component was never installed on a
case-sensitive filesystem, with no error anywhere. Archives are now
copied under canonical names, and names that collide only by case are
rejected.upgrade = "never"; under the
default policy only the archive’s DESCRIPTION is read
before deciding whether the archive is needed at all. An unreadable
archive is reported as unchanged when the installed package can be kept,
instead of failing the call.DESCRIPTION and the archive it came from when the two
differ, instead of reporting the filename as though it were the
package.upgrade = "never" the component is identified from its
filename, because the archive is deliberately not read; use the default
policy when the declared Package has to be checked against
what is installed.Prepared and verified but never submitted: CRAN submissions were closed between 2026-08-05 and 2026-08-19. These changes are released as part of 0.3.0.
crear_meta_paquete_local(),
diagnosticar_dependencias() and
install_loc_pkg_w_dep() were removed. They existed to ease
a rename inside the organisation the package grew in, while it was still
unpublished. Use create_metapackage(),
diagnose_dependencies() and
install_local_pkg().include_archives = FALSE,
<meta>_install() requires pkg_dir. In
0.1.0 that argument defaulted to the absolute archive path of the
machine where the meta-package had been generated, which exists nowhere
else. With the new default, include_archives = TRUE, the
argument is optional again because the archives travel inside the
package.unchanged element of the installation result
instead of appearing in installed labelled “Already
installed”. Reporting a package as installed when nothing was installed
was misleading.dependencies = NA instead of TRUE, so their
Suggests are no longer installed. Everything a component
needs in order to run is still installed; what is no longer pulled in is
the tooling those dependencies use for their own examples, tests and
vignettes.detect_implicit_dependencies()
are now diagnostic only. Dependencies declared by a component, or
supplied explicitly through
additional_deps/force_deps, remain binding;
guessed packages must be opted in explicitly. This prevents comments and
common function names from making a distributed meta-package depend on
unrelated packages.pkg_dir but was not included in
packages. Component R version requirements are propagated
to the generated DESCRIPTION for enforcement on the recipient’s R
version.create_metapackage() gained
include_archives, TRUE by default, which
copies the component archives into inst/archives/ of the
generated meta-package. Its installer then defaults pkg_dir
to system.file("archives", package = "<meta>"),
resolved when the installer is called, so the meta-package is the only
artifact that has to be distributed and its components install with no
arguments, with no path agreed on beforehand. Network access remains
necessary only for components that depend on a package coming from a
repository. Pass include_archives = FALSE to keep the
archives in a shared location the recipient can reach.inst/archives/, so shipped components reach the tarball
while every other archive anywhere in the tree is still excluded.cli
two-column startup message that falls back to the ASCII banner when
cli is absent, a <meta>.quiet option,
<meta>_conflicts() for masking conflicts, explicit
reinstall and upgrade policies (force, and
upgrade = "newer" | "always" | "never"), and an optional
ordered workflow vignette through the workflow
argument.Config/bigbang/packages, and the generated package tests
that the list agrees with what it exports.tempdir() sits under
/var, itself a link to /private/var. Both
sides are now normalised at the same moment.._<dir> member is accepted. Archiving a package
directory on macOS with extended attributes emits one, and R installs
such an archive, so rejecting it rejected a working package.diagnose_dependencies() extracts through the same
guarded path as generation. A component carrying a symbolic link made
the scanner read a file outside the archive and return its contents in
the result.dest_dir and
pkg_dir paths, and roll back incomplete project trees
created by a failed invocation.create_metapackage() validates name before
writing anything: against the R package name grammar, and against the
names R itself ships. A name carrying a path separator or a parent
reference previously placed the generated tree outside
dest_dir and still reported success.dependencies = NA, which covers Depends, Imports and
LinkingTo, instead of TRUE, which also covered Suggests.
Asking for one small dependency used to pull development tooling and its
whole tree into the library.result$path came
back in the platform convention and therefore did not compare equal to a
path the caller had built with file.path(). The containment
checks normalise both sides the same way, so a destination that does not
exist yet cannot be compared against one that does in a different
convention.Package and Version
fields are validated against their filenames, duplicate component
versions and archive basenames are rejected while generating, and
generated installers verify the declared version..Rbuildignore rules that could exclude the generated
package’s own files or shipped archives.unchanged element of an installation result now carries the
same two versions instead of the label “Already installed”, which is
untrue when the installed package only shares a component’s name; the
result is the only thing a calling script can inspect.tests/DESCRIPTION files are allowed, while a missing
root DESCRIPTION is reported clearly.safe_unlink() uses temporary-directory
containment rather than a broad basename heuristic.Matrix, and an identifier beginning with
st_ no longer suggests sf.The maintainer’s given name is spelled Sebastián, and the author entry now carries an ORCID identifier.
Documented that distributing the component archives inside a meta-package is a redistribution, so their licenses have to allow it, and that a component still installs only where its format can.
Documented related meta-package projects and design precedents.
Added the r-universe version badge and the one-line install from the universe binaries.
First release on CRAN, accepted on 2026-08-08.
bigbang — create custom R metapackages from local packages
.onLoad() hooks are side-effect free; component
installation is explicit via <meta>_install().tmp, and content hashes for decoy
directories.scan_bigbang_artifact() to identify the
historical V1/V2/V3/V7 signatures in source trees, archives, and
installed packages without loading them.bigbang_error_cycle
condition.skip,
error, install) and content-based distinction
between source ZIPs and Windows binary ZIPs.create_metapackage(),
install_local_pkg(), and
diagnose_dependencies(). Spanish aliases remain available
as deprecated transition wrappers.bigbang and generated
metapackages.