Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ansible/group_vars/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ factory_desktop_packages:
- iproute2

# --- Tool installer ---------------------------------------------------------
factory_core_tools: [herdr, node, bun, uv]
factory_core_tools: [herdr, node, bun, uv, btop]
# The installer flags that choose which tools a run covers. tasks/preflight.yml
# resolves exactly this set (plus the sources Ansible installs itself) and
# tasks/tools.yml installs it, so a host never resolves, and never fails on, a
Expand Down Expand Up @@ -210,6 +210,10 @@ factory_no_mistakes_omp_overlay: "{{ factory_cfg.home }}/.no-mistakes/omp-config
# Stdlib-only reporter that feeds the Spaces sidebar layout, run by herdr-spaces.timer.
factory_herdr_spaces_source: "{{ code_factory_repo }}/maintenance/herdr-spaces.py"
factory_herdr_spaces_script: "{{ factory_local_bin }}/herdr-spaces.py"
# btop: ~/.local/bin/btop is a launcher that picks a preset of the saved config
# by pane size, so it also loads in a phone's 50-column pane (docs/herdr.md#btop).
factory_btop_launcher_source: "{{ code_factory_repo }}/maintenance/btop.sh"
factory_btop_config: "{{ factory_cfg.home }}/.config/btop/btop.conf"

# --- Browser pruning --------------------------------------------------------
# Flags confirmed by Main (owner of maintenance/chrome-autoprune.py): without
Expand Down
32 changes: 32 additions & 0 deletions ansible/tasks/herdr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,38 @@
remote_src: true
become: true

# btop fitted to its pane (docs/herdr.md#btop): the launcher takes the place of
# the btop command and runs the installer's btop-bin with a preset of this
# config. btop rewrites its config on exit; every apply puts the saved one back.
- name: Install the btop launcher
ansible.builtin.copy:
src: "{{ factory_btop_launcher_source }}"
dest: "{{ factory_local_bin }}/btop"
owner: "{{ factory_cfg.user }}"
group: "{{ factory_group }}"
mode: "0755"
remote_src: true
become: true

- name: Ensure the btop configuration directory
ansible.builtin.file:
path: "{{ factory_btop_config | dirname }}"
state: directory
owner: "{{ factory_cfg.user }}"
group: "{{ factory_group }}"
mode: "0755"
become: true

- name: Install the btop configuration
ansible.builtin.copy:
src: "{{ code_factory_repo }}/config/btop.conf"
dest: "{{ factory_btop_config }}"
owner: "{{ factory_cfg.user }}"
group: "{{ factory_group }}"
mode: "0644"
remote_src: true
become: true

- name: Render the Herdr Spaces reporter unit and timer
ansible.builtin.template:
src: "{{ item }}.j2"
Expand Down
2 changes: 1 addition & 1 deletion ansible/tasks/tools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# latest releases tasks/preflight.yml resolved.
#
# Contract: python3 <repo>/scripts/install_tools.py
# --home <factory.home> --tools herdr,node,bun,uv [--npm] [--development]
# --home <factory.home> --tools herdr,node,bun,uv,btop [--npm] [--development]
# --resolved <factory_latest as JSON>
# The installer is idempotent and prints a final JSON object
# {"changed": bool, "installed": [...]}, which is the only changed signal this
Expand Down
3 changes: 3 additions & 0 deletions ansible/tasks/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
factory_user_units ~ '/default.target.wants/herdr.service',
factory_herdr_spaces_script,
factory_local_bin ~ '/herdr-sidebar-to-client.py',
factory_local_bin ~ '/btop',
factory_local_bin ~ '/btop-bin',
factory_btop_config,
factory_user_units ~ '/herdr-spaces.service',
factory_user_units ~ '/herdr-spaces.timer',
factory_user_units ~ '/timers.target.wants/herdr-spaces.timer',
Expand Down
254 changes: 254 additions & 0 deletions config/btop.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
#? Config file for btop v.1.4.7

#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
color_theme = "Default"

#* If the theme set background should be shown, set to False if you want terminal background transparency.
theme_background = false

#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
truecolor = true

#* Set to true to force tty mode regardless if a real tty has been detected or not.
#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols.
force_tty = false

#* Option to disable presets. Either the default preset, custom presets, or all presets.
#* "Off" All presets are enabled.
#* "Default" preset is disabled.#* "Custom" presets are disabled.#* "All" presets are disabled.
disable_presets = "Off"

#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.
#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box.
#* Use whitespace " " as separator between different presets.
#* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty"
presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty proc:0:default"

#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
vim_keys = false

#* Disable all mouse events.
disable_mouse = false

#* Rounded corners on boxes, is ignored if TTY mode is ON.
rounded_corners = true

#* Use terminal synchronized output sequences to reduce flickering on supported terminals.
terminal_sync = true

#* Default symbols to use for graph creation, "braille", "block" or "tty".
#* "braille" offers the highest resolution but might not be included in all fonts.
#* "block" has half the resolution of braille but uses more common characters.
#* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY.
#* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view.
graph_symbol = "braille"

# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_cpu = "default"

# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_mem = "default"

# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_net = "default"

# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_proc = "default"

#* Manually set which boxes to show. Available values are "cpu mem net proc" and "gpu0" through "gpu5", separate values with whitespace.
shown_boxes = "cpu mem net proc"

#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs.
update_ms = 100

#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct",
#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly.
proc_sorting = "cpu direct"

#* Reverse sorting order, True or False.
proc_reversed = false

#* Show processes as a tree.
proc_tree = false

#* Use the cpu graph colors in the process list.
proc_colors = true

#* Use a darkening gradient in the process list.
proc_gradient = true

#* If process cpu usage should be of the core it's running on or usage of the total available cpu power.
proc_per_core = false

#* Show process memory as bytes instead of percent.
proc_mem_bytes = true

#* Show cpu graph for each process.
proc_cpu_graphs = true

#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)
proc_info_smaps = false

#* Show proc box on left side of screen instead of right.
proc_left = false

#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop).
proc_filter_kernel = false

#* Should the process list follow the selected process when detailed view is open.
proc_follow_detailed = true

#* In tree-view, always accumulate child process resources in the parent process.
proc_aggregate = false

#* In tree-view, auto-collapse processes with this many or more direct children when
#* entering tree mode. 0 to disable. Useful for collapsing multi-process apps like browsers.
proc_tree_auto_collapse = 0

#* Should cpu and memory usage display be preserved for dead processes when paused.
keep_dead_proc_usage = false

#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available.
#* Select from a list of detected attributes from the options menu.
cpu_graph_upper = "Auto"

#* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available.
#* Select from a list of detected attributes from the options menu.
cpu_graph_lower = "Auto"

#* Toggles if the lower CPU graph should be inverted.
cpu_invert_lower = true

#* Set to True to completely disable the lower CPU graph.
cpu_single_graph = false

#* Show cpu box at bottom of screen instead of top.
cpu_bottom = false

#* Shows the system uptime in the CPU box.
show_uptime = true

#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo.
show_cpu_watts = true

#* Show cpu temperature.
check_temp = true

#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors.
cpu_sensor = "Auto"

#* Show temperatures for cpu cores also if check_temp is True and sensors has been found.
show_coretemp = true

#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.
#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.
#* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries.
#* Example: "4:0 5:1 6:3"
cpu_core_map = ""

#* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine".
temp_scale = "celsius"

#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024.
base_10_sizes = false

#* Show CPU frequency.
show_cpu_freq = true

#* How to calculate CPU frequency, available values: "first", "range", "lowest", "highest" and "average".
freq_mode = "first"

#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.
#* Special formatting: /host = hostname | /user = username | /uptime = system uptime
clock_format = "%X"

#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort.
background_update = true

#* Custom cpu model name, empty string to disable.
custom_cpu_name = ""

#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ".
#* Only disks matching the filter will be shown. Prepend exclude= to only show disks not matching the filter. Examples: disks_filter="/boot /home/user", disks_filter="exclude=/boot /home/user"
disks_filter = ""

#* Show graphs instead of meters for memory values.
mem_graphs = true

#* Show mem box below net box instead of above.
mem_below_net = false

#* Count ZFS ARC in cached and available memory.
zfs_arc_cached = true

#* If swap memory should be shown in memory box.
show_swap = true

#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk.
swap_disk = true

#* If mem box should be split to also show disks info.
show_disks = true

#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar.
only_physical = true

#* Read disks list from /etc/fstab. This also disables only_physical.
use_fstab = true

#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)
zfs_hide_datasets = false

#* Set to true to show available disk space for privileged users.
disk_free_priv = false

#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view.
show_io_stat = true

#* Toggles io mode for disks, showing big graphs for disk read/write speeds.
io_mode = false

#* Set to True to show combined read/write io graphs in io mode.
io_graph_combined = false

#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ".
#* Example: "/mnt/media:100 /:20 /boot:1".
io_graph_speeds = ""

#* Swap the positions of the upload and download speed graphs. When true, upload will be on top.
swap_upload_download = false

#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False.
net_download = 100

net_upload = 100

#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest.
net_auto = true

#* Sync the auto scaling for download and upload to whichever currently has the highest scale.
net_sync = true

#* Starts with the Network Interface specified here.
net_iface = ""

#* "True" shows bitrates in base 10 (Kbps, Mbps). "False" shows bitrates in binary sizes (Kibps, Mibps, etc.). "Auto" uses base_10_sizes.
base_10_bitrate = "Auto"

#* Show battery stats in top right if battery is present.
show_battery = true

#* Which battery to use if multiple are present. "Auto" for auto detection.
selected_battery = "Auto"

#* Show power stats of battery next to charge indicator.
show_battery_watts = true

#* Set loglevel for "~/.local/state/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info.
log_level = "WARNING"

#* Automatically save current settings to config file on exit.
save_config_on_exit = true
4 changes: 2 additions & 2 deletions docs/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Everything the recipe installs, grouped by where it comes from. Nothing is pinne

`scripts/install_tools.py`. Native tools are linked into `~/.local/bin`; npm tools are each installed with `npm install` into `~/.local/share/code-factory/<tool>/<version>` (npm checks the registry integrity) and linked from there. Superseded versions stay on disk.

- Always: herdr ([herdrdev/herdr](https://github.com/herdrdev/herdr/releases/latest)), bun ([oven-sh/bun](https://github.com/oven-sh/bun/releases/latest), the x64 `baseline` build), uv ([astral-sh/uv](https://github.com/astral-sh/uv/releases/latest)), verified against the GitHub release-asset digest. A herdr upgrade rewrites and restarts `herdr.service`.
- Always: herdr ([herdrdev/herdr](https://github.com/herdrdev/herdr/releases/latest)), bun ([oven-sh/bun](https://github.com/oven-sh/bun/releases/latest), the x64 `baseline` build), uv ([astral-sh/uv](https://github.com/astral-sh/uv/releases/latest)), btop ([aristocratos/btop](https://github.com/aristocratos/btop/releases/latest), the static musl build, linked as `btop-bin`; `btop` is the launcher in [btop](herdr.md#btop)), verified against the GitHub release-asset digest. A herdr upgrade rewrites and restarts `herdr.service`.
- Always: node, the newest release in the [nodejs.org index](https://nodejs.org/dist/index.json) (not the LTS line), verified against that release's `SHASUMS256.txt`.
- `agents` profile, native: gh ([cli/cli](https://github.com/cli/cli/releases/latest)), treehouse ([kunchenguid/treehouse](https://github.com/kunchenguid/treehouse/releases/latest)), verified against the GitHub release-asset digest.
- `agents` profile, no-mistakes ([kunchenguid/no-mistakes](https://github.com/kunchenguid/no-mistakes/releases)): the one tool that tracks the prerelease channel. Each apply resolves the newest non-draft release, betas included (not only the latest stable one), and verifies it against the GitHub release-asset digest.
Expand All @@ -23,7 +23,7 @@ Everything the recipe installs, grouped by where it comes from. Nothing is pinne
- `agents` profile, omp plugins: ponytail ([DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)), i-have-adhd ([ayghri/i-have-adhd](https://github.com/ayghri/i-have-adhd)) and caveman ([JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman)) from their GitHub marketplaces, installed once and upgraded with `omp plugin upgrade` on every apply. These are the only installs that are not checksum-verified: no publisher posts a checksum for them, so they track each author's default branch and load as agent instructions and hooks. The operator accepted this to keep them at the latest commit.
- `development` profile: rustup-init, the version in rustup's [stable release](https://static.rust-lang.org/rustup/release-stable.toml), verified against the `.sha256` published beside it, installing the Rust `stable` toolchain (minimal profile + rustfmt + clippy). Every apply moves the toolchain to the newest stable.

The GitHub lookups use the GitHub API, which allows 60 unauthenticated requests an hour per IP (shared IPs such as CI runners exhaust it); a resolution makes one request per GitHub-hosted tool the host installs, at most eight. Only the tools a run installs are resolved, so a source the host does not use cannot fail it. The lookups authenticate with `GITHUB_TOKEN` from the environment that runs `./factory apply` or `./bootstrap.sh`, else run unauthenticated; the token is sent to the GitHub API only. Container builds take the token as the optional BuildKit secret `github_token` (`docker build --secret id=github_token,env=GITHUB_TOKEN ...`), so it never lands in the image.
The GitHub lookups use the GitHub API, which allows 60 unauthenticated requests an hour per IP (shared IPs such as CI runners exhaust it); a resolution makes one request per GitHub-hosted tool the host installs, at most nine. Only the tools a run installs are resolved, so a source the host does not use cannot fail it. The lookups authenticate with `GITHUB_TOKEN` from the environment that runs `./factory apply` or `./bootstrap.sh`, else run unauthenticated; the token is sent to the GitHub API only. Container builds take the token as the optional BuildKit secret `github_token` (`docker build --secret id=github_token,env=GITHUB_TOKEN ...`), so it never lands in the image.

## Ubuntu packages

Expand Down
8 changes: 8 additions & 0 deletions docs/herdr.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ What the mobile layout forces, compared with the desktop sidebar:
- A home's counts and shares are on its own agent's entry, so a home with no agent pane carrying a `who` token shows none. Without a `machine` workspace, the machine's shares do not show either.
- The issue (`○`) is left out for width.

### btop

btop draws nothing in a pane smaller than its shown boxes need; it shows `Terminal size too small` instead. All four boxes need 80x24 in btop 1.4 (the cpu box is 60 columns wide, the proc box 44 beside the 36 of mem and net), so a 50-column phone pane is too small.

`./factory apply` installs the latest btop release as `~/.local/bin/btop-bin`, [`config/btop.conf`](../config/btop.conf) as `~/.config/btop/btop.conf`, and [`maintenance/btop.sh`](../maintenance/btop.sh) as `~/.local/bin/btop`. The launcher starts btop with preset 0 (all four boxes) in a pane of at least 80x24, and otherwise with preset 4 (processes only, which needs 44x16). When a phone attaches to the same session and the pane crosses 80x24, the launcher restarts btop with the other preset. Quitting btop ends the launcher.

btop saves its config on exit, including the last preset's boxes; the launcher always passes a preset, so that never changes what it shows. Every apply rewrites the config, so make lasting changes in `config/btop.conf`, and keep preset 4 there.

## Viewing from another machine

Sidebar layouts are client-side: Herdr draws the sidebar from the config of the machine you view from, even over `herdr --remote`. The host still reports every token, but the viewing machine needs the host's layout to show them. `./factory apply` installs [`maintenance/herdr-sidebar-to-client.py`](../maintenance/herdr-sidebar-to-client.py) as `~/.local/bin/herdr-sidebar-to-client.py`. On the viewing machine, run it against the host with Python 3 and ssh access, where `<host>` is anything `ssh` accepts, such as `user@host`:
Expand Down
Loading