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 agentic-ai/Claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
@rules/common/general.md
@rules/common/agents.md
@rules/bash/style.md<!-- railguard:start -->
@rules/bash/style.md
# graphify
- **graphify** (`~/.claude/skills/graphify/SKILL.md`) - any input to knowledge graph. Trigger: `/graphify`
When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"` before doing anything else.
<!-- railguard:start -->
# Railguard — Active Guardrails

Railguard is monitoring this session. Every tool call (Bash, Write, Edit, Read) passes through Railguard before execution.
Expand Down
1 change: 1 addition & 0 deletions agentic-ai/Claude/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ After a fresh install, run each check to confirm hooks and railguard are wired c
- [ ] `validate-write.sh` — writes to `~/.ssh/`, `/etc/` blocked (exit 2); project paths allowed (exit 0)
- [ ] `post-edit-shellcheck.sh` — fires after shell script edits and blocks on shellcheck errors
- [ ] `post-test-runner.sh` — auto-detects test suite and runs after source edits; exits 2 on failure
- **uv projects**: `.claude/test-cmd` must use `uv run --no-sync pytest`, not bare `uv run pytest`. Without `--no-sync`, every edit triggers `uv sync` which reverts out-of-band package installs (e.g. ROCm torch back to CUDA torch). Consider patching `post-test-runner.sh` to inject `--no-sync` when it detects `uv run` in the resolved test command.
- [ ] `driftcheck.sh` — flags `.sh` files missing execute permission or shebang at session end

### Railguard
Expand Down
1 change: 1 addition & 0 deletions linux-desktop/ghostty.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Ghostty Config

theme = Dark Pastel
font-family = MesloLGS Nerd Font Mono
shell-integration = zsh
term = xterm-256color
13 changes: 13 additions & 0 deletions linux-desktop/lact_default_backup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# LACT default config — Sapphire R9700 AI Pro, CachyOS, captured 2026-05-29
# This is the stock state before any tuning. Restore with:
# sudo cp linux-desktop/lact_default_backup.yaml /etc/lact/config.yaml
# sudo systemctl restart lactd

version: 5
daemon:
log_level: info
admin_group: wheel
disable_clocks_cleanup: false
apply_settings_timer: 5
current_profile: null
auto_switch_profiles: false
76 changes: 76 additions & 0 deletions linux-desktop/lact_r9700.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# LACT config for AMD Radeon AI PRO R9700 — AI inference / daily driver tuning
#
# Place at: /etc/lact/config.yaml
# After editing: sudo systemctl restart lactd
#
# Find your GPU ID: lact-cli list-gpus
# Replace GPU_ID_HERE with the output (e.g. 0000:09:00.0)
#
# ── BEFORE APPLYING: verify fan control works on your unit ──────────────────
# Some R9700 boards (ASUS Turbo, vBIOS 115-G287BP00-100) have a known SMU
# firmware mismatch (driver v46 vs card v50) that makes pwm1 read-only and
# grays out LACT's fan controls entirely. Check first:
#
# ls /sys/class/drm/card0/device/gpu_od/fan_ctrl/
# # must exist and list: fan_curve acoustic_limit_rpm_threshold ...
# sudo dmesg | grep -i "smu.*version"
# # if you see "SMU driver if version not matched" → fan curve is a no-op
#
# If broken: see lact_r9700_tuning.md → "Known issue: fan control" for status
# and the sysfs fallback for undervolting without fan control.
#
# ── PREREQUISITES ────────────────────────────────────────────────────────────
# ppfeaturemask MUST be set via kernel boot parameter — NOT via modprobe.d.
# The driver silently strips the OD feature bit (0x4000) when loaded from
# modprobe, resulting in 0xfff7bfff instead of 0xfff7ffff.
#
# CachyOS systemd-boot: add to options line in /boot/loader/entries/*.conf
# GRUB: add to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub, then:
# sudo grub-mkconfig -o /boot/grub/grub.cfg
#
# amdgpu.ppfeaturemask=0xfff7ffff
#
# Verify after reboot:
# cat /sys/module/amdgpu/parameters/ppfeaturemask
# # must print 0xfff7ffff — if 0xfff7bfff, you used modprobe (fix it)
#
# ── TUNING RATIONALE ─────────────────────────────────────────────────────────
# voltage_offset: -80mV — conservative, proven on R9700 Linux; reduces heat
# without touching max clock. Go lower (-100 to
# -120mV) only after stability testing.
# power_cap: 210W — stock is 300W (confirmed max on R9700 AI Pro);
# range is 210–300W. 210W is enough for sustained
# inference (token gen is memory-bandwidth bound).
# Reduces fan noise. ~15% slower prefill (TTFT).
# For max performance: 300W + -75mV (see tuning doc)
# fan curve (junction) — 5 entries required on RDNA3+. Quiet below 70°C,
# gradual 5°C-step ramp to 60% at 90°C junction.
# Silently ignored if SMU mismatch bug is present.

daemon:
log_level: info
admin_group: wheel

apply_settings_timer: 5

gpus:
GPU_ID_HERE:
fan_control_enabled: true
fan_control_settings:
mode: curve
temperature_key: junction
interval_ms: 500
# RDNA3+ requires exactly 5 curve entries.
# Keys = junction temp (°C), values = fan speed (0.0–1.0).
curve:
35: 0.25
70: 0.38
75: 0.42
80: 0.50
90: 0.60
spindown_delay_ms: 0
change_threshold: 2
clocks_configuration:
voltage_offset: -80
power_cap: 210.0
performance_level: manual
238 changes: 238 additions & 0 deletions linux-desktop/lact_r9700_tuning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
# LACT Tuning Guide — AMD Radeon AI PRO R9700

LACT (Linux AMD Configuration Tool) is a GUI + daemon that persists GPU tuning across reboots via a background service. The R9700 runs RDNA 4 (`navi48`/gfx1201), which uses a **voltage offset** model — you shift the entire voltage curve down by N mV rather than editing individual VF points (that was RDNA 1/Vega).

## Known issue: fan control AND voltage offset broken on some R9700 units

Before doing anything else, verify the GPU control interfaces actually exist on your board. Some R9700 units (confirmed: ASUS Turbo, vBIOS `115-G287BP00-100`) have a firmware mismatch that blocks both fan control and voltage offset on Linux. LACT's fan and OC controls are grayed out, `pwm1` is read-only, `pp_od_clk_voltage` doesn't exist, and the GPU can reach 109 °C with fans physically stationary.

**Root cause:** the card's SMU firmware reports interface version 50 (`0x32`), but the amdgpu driver only supports up to version 46 (`0x2e`). This affects all kernel versions tested through 7.0 as of May 2026.

The card number varies by system (card0, card1, etc.). Find yours first:
```bash
# Find your AMD GPU card path
CARD=$(grep -rl "0x1002" /sys/class/drm/card*/device/vendor 2>/dev/null | head -1 | sed 's|/device/vendor||')
# e.g. → /sys/class/drm/card1
```

```bash
# Check 1: does the gpu_od fan+voltage interface exist?
ls $CARD/device/gpu_od/fan_ctrl/
# Good: lists fan_curve acoustic_limit_rpm_threshold ...
# Bad: "No such file or directory" → fan + voltage offset blocked on your unit

# Check 2: does the voltage offset sysfs path exist?
ls $CARD/device/pp_od_clk_voltage
# Good: file exists → voltage offset works
# Bad: "No such file or directory" → voltage control also blocked

# Check 3: confirm the SMU mismatch
sudo dmesg | grep -i "smu.*version"
# Bad: "SMU driver if version not matched" → confirms the bug
```

If you're affected: **only power cap works** until AMD ships the driver fix (targeting TheRock 7.13 / ROCm 7.13). See [ROCm issue #6101](https://github.com/ROCm/ROCm/issues/6101) for status.

---

## Prerequisites

### 1. Install LACT

```bash
# Arch / CachyOS — official repos
sudo pacman -S lact

# Enable and start the daemon
sudo systemctl enable --now lactd
```

Ubuntu: download the matching `.deb` from [LACT releases](https://github.com/ilya-zlobintsev/LACT/releases).

### 2. Enable AMD overdrive — kernel cmdline only

Add `amdgpu.ppfeaturemask=0xfff7ffff` as a **kernel boot parameter**. Do not use `/etc/modprobe.d/` — the driver silently strips the OD feature bit (0x4000) when loaded from modprobe, resulting in `0xfff7bfff` instead of `0xfff7ffff` with no log warning.

**CachyOS / systemd-boot:** add to the `options` line in `/boot/loader/entries/*.conf`, then reboot.

**GRUB:**
```bash
# /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="... amdgpu.ppfeaturemask=0xfff7ffff"

sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo reboot
```

Verify after reboot:
```bash
cat /sys/module/amdgpu/parameters/ppfeaturemask
# Must print 0xfff7ffff — if you see 0xfff7bfff you used modprobe, fix it
```

---

## Applying the LACT config

Find your GPU's PCI ID:
```bash
lact-cli list-gpus
# e.g. → 0000:09:00.0 AMD Radeon AI PRO R9700
```

Copy the config template and replace `GPU_ID_HERE`:
```bash
sudo cp linux-desktop/lact_r9700.yaml /etc/lact/config.yaml
sudo sed -i 's/GPU_ID_HERE/0000:09:00.0/' /etc/lact/config.yaml # use your actual ID
sudo systemctl restart lactd
```

Verify settings are live:
```bash
lact-cli info
watch -n1 lact-cli info
```

### lact-cli reference

The CLI is intentionally minimal — all tuning is done via config file, not CLI flags.

```bash
lact-cli list-gpus # list GPU PCI IDs
lact-cli info # current clocks, temps, power, fan speed
lact-cli info --gpu <id> # target a specific GPU
```

For scripting or deeper integration, use the LACT Unix socket API directly.

---

## What the config does

| Setting | Value | Why |
|---|---|---|
| `voltage_offset` | **-80 mV** | Conservative, proven on R9700 Linux. Reduces heat without capping clocks. Go to -100 or -120 mV after stability testing. No-op on SMU bug units until driver fix ships. |
| `power_cap` | **210 W** | Stock is 300 W (confirmed); range is 210–300 W. Token generation is memory-bandwidth bound so lowering this barely affects t/s while cutting thermals and fan noise. ~15% slower prefill (TTFT) is the tradeoff. |
| `performance_level` | **manual** | Required for power cap and voltage controls to be honored by the driver. |
| Fan curve | **junction temp, 5 entries** | Quiet below 70 °C, 5 °C-step ramp to 60% at 90 °C. No-op on SMU bug units (pwm1 is read-only). |

---

## Sysfs fallback (power cap only on SMU bug units)

If `gpu_od` is missing, `pp_od_clk_voltage` doesn't exist, and LACT's OC controls are grayed out, **only power cap is accessible** via hwmon. Fan and voltage controls remain blocked until the driver fix ships.

Find your card first (number varies by system):
```bash
CARD=$(grep -rl "0x1002" /sys/class/drm/card*/device/vendor 2>/dev/null | head -1 | sed 's|/device/vendor||')

# Check what's actually accessible
ls $CARD/device/pp_od_clk_voltage 2>/dev/null || echo "voltage offset: blocked"
cat $CARD/device/hwmon/hwmon*/power1_cap_min # e.g. 210000000 → 210W
cat $CARD/device/hwmon/hwmon*/power1_cap_max # e.g. 300000000 → 300W
```

```bash
# Power cap only (range 210–300W on R9700 AI Pro)
echo "210000000" | sudo tee $CARD/device/hwmon/hwmon*/power1_cap # quiet
echo "300000000" | sudo tee $CARD/device/hwmon/hwmon*/power1_cap # stock

# If voltage offset IS available (no SMU bug):
echo "manual" | sudo tee $CARD/device/power_dpm_force_performance_level
echo "vo -75" | sudo tee $CARD/device/pp_od_clk_voltage
echo "c" | sudo tee $CARD/device/pp_od_clk_voltage
cat $CARD/device/pp_od_clk_voltage # verify: OD_VDDGFX_OFFSET: -75mV
```

These reset on reboot. LACT handles persistence once the SMU bug is fixed.

---

## Tuning further

### Performance profile (max inference throughput)

From the [amd-r9700-vllm-toolboxes](https://github.com/kyuz0/amd-r9700-vllm-toolboxes) project — higher power budget + lower voltage = more clock headroom for prefill:

```yaml
clocks_configuration:
voltage_offset: -75
power_cap: 300.0 # 300W is the confirmed max on R9700 AI Pro
```

vs the config's conservative 210 W / -80 mV. Tradeoff: more power and heat, faster TTFT.

### More aggressive undervolt (gaming / max perf)

RDNA 4 has exceptional undervolt headroom. Community data on 9070/9070 XT (same arch):

| Tester | Offset | Result |
|---|---|---|
| Der8auer (9070 XT) | -170 mV | +10% FPS, 2.9 → 3.36 GHz |
| Alva Jonathan (9070) | -125 mV | +10% FPS, 2.6 → 3.0 GHz |
| Conservative start | -75 mV | safe baseline |

For gaming: raise `power_cap` toward stock (300 W max), drop `voltage_offset` to -100 to -150 mV, test stability.

### Capping max clock for pure inference

Token generation is memory-bandwidth bound — capping the GPU clock saves power with no t/s impact:

```yaml
clocks_configuration:
voltage_offset: -80
max_core_clock: 2000 # MHz — adjust to taste
```

### Automatic profiles (inference vs gaming)

```yaml
profiles:
inference:
gpus:
GPU_ID_HERE:
power_cap: 210.0
clocks_configuration:
voltage_offset: -80
rule:
type: process
filter:
name: llama-server
gaming:
gpus:
GPU_ID_HERE:
power_cap: 285.0
clocks_configuration:
voltage_offset: -150
rule:
type: process
filter:
name: steam
auto_switch_profiles: true
```

---

## Stability testing

After changing `voltage_offset`, stress the GPU before trusting the settings:

```bash
# Watch temps, clocks, power live
watch -n1 'rocm-smi --showtemp --showclocks --showpower'

# Run a large LLM for 10–15 min under inference load
# If you see crashes, GPU resets, or display corruption → back off by 10–15 mV
```

---

## References

- [ROCm issue #6101 — R9700 fan not spinning (54 comments, open)](https://github.com/ROCm/ROCm/issues/6101)
- [ROCm issue #6078 — SMU interface version mismatch (closed, superseded)](https://github.com/ROCm/ROCm/issues/6078)
- [amd-r9700-vllm-toolboxes TUNING.md](https://github.com/kyuz0/amd-r9700-vllm-toolboxes)
- [Undervolting the R9700 — Level1Techs Forums](https://forum.level1techs.com/t/undervolting-the-r9700/249946)
- [Undervolted RX 9070 XT beats RTX 5080 — Tom's Hardware](https://www.tomshardware.com/pc-components/gpus/undervolted-rx-9070-xt-beats-rtx-5080-rx-9070-and-9070-xt-models-with-heavy-coolers-have-massive-oc-headroom)
- [LACT GitHub](https://github.com/ilya-zlobintsev/LACT)
- [LACT CONFIG.md](https://github.com/ilya-zlobintsev/LACT/blob/master/docs/CONFIG.md)
14 changes: 14 additions & 0 deletions linux-desktop/linux_desktop_packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
"optional": false,
"description": "Lightweight zsh plugin manager — handles autosuggestions, syntax highlighting, completions, substring search, and abbreviations via a plugins file"
},
{
"name": "zsh-theme-powerlevel10k",
"package_manager": { "arch": "yay" },
"priority": "high",
"optional": false,
"description": "Powerlevel10k zsh prompt — rich git status, command duration, exit code, instant prompt; Arch only (Ubuntu: add romkatv/powerlevel10k to zsh_plugins.txt); run `p10k configure` to set up"
},
{
"name": "zoxide",
"package_manager": { "ubuntu": "apt", "arch": "yay" },
Expand Down Expand Up @@ -132,6 +139,13 @@
"optional": false,
"description": "GPU process monitor — complements htop with GPU visibility"
},
{
"name": "lact",
"package_manager": { "arch": "yay" },
"priority": "medium",
"optional": false,
"description": "Linux AMD GPU control panel — fan curves, voltage offset, power cap, clock limits via GUI + background daemon; see linux-desktop/lact_r9700_tuning.md for R9700 config"
},
{
"name": "tmux",
"package_manager": { "ubuntu": "apt", "arch": "yay" },
Expand Down
Loading
Loading