Covers the three provisioning profiles (oem/collaborator/orchard), all
install.sh flags, the extras system (model-cache-redirect), and the full
CF apps manifest registry. The old README only described the bare PRbL
bashrc install and was stale relative to the cf-apps provisioning system.
for each in {1..${#_extras[@]}} doesn't expand as a range - bash does
brace expansion before parameter expansion, so the range endpoint
isn't resolved yet when brace expansion runs. The loop always ran
exactly once, leaving preselect at length 1 regardless of how many
extras exist. Invisible until now because there was only ever one
extra (model-cache-redirect); would have silently broken any
preselected-true default on a 2nd+ extra. Switched to a C-style loop.
This is almost certainly the multiselect misbehavior from years back -
tracked down while verifying multiselect() itself (functions/PRbL
submodule, fixed separately) didn't have a toggle-isolation bug.
run() re-splits its argument as a bare string with no eval, so any
call like run "git clone \"$url\" \"$dir\"" corrupts the quoted
arguments (embedded escaped quotes survive as literal characters,
e.g. git sees the protocol as '"https). Each of the 4 affected call
sites papered over this by following run() with a second, correctly
quoted manual execution of the same command - meaning every real run
double-executed (git clone twice, pip install -e twice, conda env
create twice), with the first, corrupted attempt's failure masked by
the working second attempt.
Fixed by dropping run() at these sites entirely and gating on
$dry_run directly with a single, properly quoted real execution path
(matches the pattern already used in the new model-cache-redirect
extra):
- lib/cf-apps.functions: install-cf-app's clone, provision-orchard-node's clone
- cf-apps/circuitforge-core.manifest: pip install -e setup hook
- cf-apps/kiwi.manifest: conda env create setup hook
Verified on sif via a scratch-dir harness (install-cf-app
circuitforge-core): first run now clones cleanly with no mangled-URL
error, second run correctly skips the clone and re-runs the
idempotent pip install; state.conf stays single-entry across both.
Ports the ~/.cache -> /devl/user-cache redirect pattern (already applied
manually on heimdall) into cf-node-bootstrap's extras/ plugin system, so
it's an optional step for any future node with the same secondary-SSD
layout (heimdall/navi/sif convention: small root + /devl for fast local
storage). Skips cleanly on nodes without a separate /devl mount.
Redirects XDG_CACHE_HOME plus symlinks the hardcoded ~/.cache/{pip,
whisper,clip,huggingface} paths that ignore XDG_CACHE_HOME. Leaves
HF_HOME (curated model store) untouched.
Verified with -D (dry-run) and -i (real) against sif.
- lib/cf-apps.functions: cf-provision-node/install-cf-app/
provision-orchard-node now write to ~/.config/cf-node-bootstrap/state.conf
(record-cf-node-state) - provisioning profile, each installed app
(name:install_type:clone_dir), and orchard role/coordinator URL. The
orchard role/coordinator is read back from circuitforge-orch's own
generated ~/.config/circuitforge/cf-orch.env rather than tracked
separately, since that's the actual source of truth for what its
interactive installer decided.
- 11-quickinfo.bashrc: new "CircuitForge Node" section (show_cf_node_info,
default true) displaying the provisioning profile, orchard role/
coordinator if joined, and each installed app with a best-effort
running/stopped status. Docker-compose apps are checked by compose
project from their clone dir rather than by container name, since
compose's generated container names don't match the app name directly.
Section is entirely absent if the state file doesn't exist yet (i.e.
the CF Apps menu has never been run on this node).
Adds a manifest-driven "Install CircuitForge Apps" menu to install.sh,
alongside the existing extras-menu pattern.
- cf-apps/*.manifest: one file per product (circuitforge-core, peregrine,
kiwi, snipe, turnstone, pagepiper, linnet - the beta/alpha menagerie
products), declaring repo URLs, supported install types, conda env,
.env template, and per-install-type setup hooks. Hooks prefer shelling
out to each product's own install.sh/Makefile/docker-compose rather
than reimplementing their setup logic.
- lib/cf-apps.functions: registry loader, provisioning-profile prompt
(oem/collaborator/orchard), app multiselect menu, and the install
dispatcher (clone, .env bootstrap, install-type selection, hook
dispatch). circuitforge-core installs automatically as a dependency
for apps that declare app_needs_core=true.
Provisioning profiles gate both which apps are offered and which remote
credentials are used:
- oem: public CircuitForgeLLC GitHub mirrors only, no Forgejo access,
no circuitforge-orch (product install menu only)
- collaborator: private Circuit-Forge Forgejo, same product menu
- orchard: narrow flow, not the product menu - clones circuitforge-orch
(Forgejo-only, no public mirror exists) and hands off interactively to
its own install.sh, which gathers agent/coordinator topology itself
(it has no --topology/--coordinator-url flags to script around).
NOTE: circuitforge-orch has no model-sync/cache-sync mechanism today
(checked its install.sh and README); this wrapper doesn't invent one.
Design rationale and survey of each product's real install story:
circuitforge-plans/cf-node-bootstrap/superpowers/plans/2026-07-17-cf-apps-install-menu.md
- get_top_processes: use 'comm' instead of 'args' so the actual binary
name is shown instead of a path truncated before reaching it; also
exclude the ps invocation itself, which was always appearing with an
inflated %cpu artifact from its own brief runtime.
- Network Information: interfaces matching grouped_adapter_patterns
(Docker br-*/veth*/docker0 by default) are now tallied into a single
summary line instead of printed individually. On a host running many
containers this cut the section from 100+ lines to a handful.
- get_security_info: failed-login count used `journalctl -u sshd`, but
the systemd unit is named ssh.service on Debian/Ubuntu, so the query
silently matched zero entries there. Filter by `_COMM=sshd` instead,
which matches the actual binary name regardless of unit naming, and
add /var/log/secure as a fallback alongside /var/log/auth.log.
- Pin LC_ALL=C on free/uptime/sensors calls parsed by grep/awk on
English words and fixed column positions; these broke under
non-English locales. Uptime's token-position parsing is still
format-fragile across procps versions/distros; noted as a follow-up
for a /proc/uptime-based rewrite.
- Replace hardcoded '°C' with a deg_symbol variable that collapses to
plain "C" when PRbL/functions reports unicode_supported=false, so
temperature readouts stay pure ASCII on terminals/locales that can't
render the degree sign.
- Bump PRbL submodule for the ANSI-code and box-border fallback fixes.
bc is required by power monitoring functions for floating-point math
and was missing from the apt packages list, causing failures on
minimal installs like RPiOS Lite.
Slipstream.install and golang.install extras removed as they are
no longer maintained here.