Concrete examples for each of the four principles in CLAUDE.md,
grounded in real slkernel scenarios (kernel .config, Kconfig symbols, the
build recipe). Snippets use Kconfig / shell / diffs.
Derived from forrestchang/andrej-karpathy-skills (MIT). Examples rewritten for kernel packaging + slkernel.
User request: "Enable Bluetooth."
What LLMs often do (wrong assumption):
-# CONFIG_BT is not set
+CONFIG_BT=yProblem: "enable Bluetooth" underspecifies several things, and each choice changes the result:
- Built-in (
=y) or module (=m)? A low-latency desktop kernel usually ships such drivers as modules to keep the image lean. - Which sub-options?
CONFIG_BT_RFCOMM,CONFIG_BT_BNEP,CONFIG_BT_HIDP, and the controller driver (CONFIG_BT_HCIBTUSB) are all separate symbols. - Dependencies:
CONFIG_BTpulls inCONFIG_CRYPTO,CONFIG_RFKILL, etc.
What should happen (surface the choice):
"Enable Bluetooth" spans several symbols. Before I touch the config:
- Built-in or module? (I'd default to
=m, matching the low-latency profile.)- Just core
CONFIG_BT+ USB controller (CONFIG_BT_HCIBTUSB), or also RFCOMM/BNEP/HIDP?I'll change only those symbols and run
make olddefconfigso dependencies resolve without churning the rest of the config.
User request: "Make the kernel smaller."
What LLMs often do (pick silently):
-CONFIG_MODULES=y
+# CONFIG_MODULES is not set(Disabling modules entirely — a huge, breaking change.)
What should happen:
"Smaller" could mean different things with different blast radius:
- Trim drivers you don't ship (built-in → module, or disable unused ones) — biggest safe win, but needs a target hardware list.
- Drop debug options (
CONFIG_DEBUG_INFO, etc.) — shrinks the image and build time, low risk.- Compression /
CONFIG_CC_OPTIMIZE_FOR_SIZE— modest, global effect.Which target — image size, module count, or memory footprint? I'd start with debug options + obviously-unused drivers, each boot-tested.
User request: "Add a way to toggle the low-latency option."
What LLMs often do (overengineered):
A whole config-fragment system: config/base.cfg, config/lowlatency.cfg,
config/server.cfg, plus a merge script and a recipe variable to select a
"profile" — to flip a single preemption symbol.
Problem: there is one shipping kernel: the low-latency desktop build. A profile/fragment framework for one symbol is indirection nobody needs yet.
What should happen (minimum change):
Set the symbol directly in the one config:
-# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT=y
+# CONFIG_PREEMPT_VOLUNTARY is not setThen make olddefconfig. Introduce a fragment system if and when a second
shipping profile actually exists.
User request: "We use ext4; make sure the kernel can mount the root filesystem."
What LLMs often do (feature creep):
+CONFIG_EXT4_FS=y
+CONFIG_BTRFS_FS=y
+CONFIG_XFS_FS=y
+CONFIG_F2FS_FS=y
+CONFIG_ZFS=y
+CONFIG_REISERFS_FS=y
+CONFIG_NILFS2_FS=yProblem: the ask was ext4. The rest are unrequested filesystems that bloat the kernel and widen the attack surface.
What should happen:
+CONFIG_EXT4_FS=yBuilt-in (=y, not =m) so the root filesystem mounts without an initramfs
module. Add other filesystems when the installer actually offers them.
User request: "Enable the i915 graphics driver."
What LLMs often do (too much):
$ make defconfig # regenerates the WHOLE config from arch defaults
$ # ...also bumps the recipe to a newer upstream tag "while here"
Result: hundreds of symbols change, the carefully-tuned low-latency config is gone, and the version bump is mixed into a one-driver change.
What should happen (surgical):
-# CONFIG_DRM_I915 is not set
+CONFIG_DRM_I915=m$ make olddefconfig # resolve only the new dependencies
$ git diff .config # confirm: i915 + its deps, nothing else
One driver, dependencies resolved, version untouched.
User request: "Disable the floppy driver, we don't need it."
What LLMs often do (collateral damage):
-CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_FD is not set
-CONFIG_EFI=y
+# CONFIG_EFI is not set # "more cleanup of stuff we don't use"
-CONFIG_EFI_STUB=y
+# CONFIG_EFI_STUB is not setProblem: disabling the floppy driver is fine — but the "while I'm here"
removal of CONFIG_EFI* makes the kernel unbootable on a UEFI-only distro.
The failure won't appear until install/boot.
What should happen:
-CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_FD is not setOnly the requested symbol. Boot-critical options (CONFIG_EFI*, the root
filesystem, block/initramfs) are never touched incidentally.
User request: "The new kernel builds but won't boot in UEFI."
What LLMs often do (fix without reproducing):
+CONFIG_EFI_STUB=y
+CONFIG_FB_EFI=y
+CONFIG_EFI_VARS=y # plus a few more "EFI-sounding" symbols on a hunchMaybe it boots, maybe not — and the config now carries cargo-cult symbols.
What should happen (reproduce in a VM):
Plan:
1. Reproduce under QEMU + OVMF (UEFI firmware) with the built kernel + a
scratch image.
Verify: firmware can't boot it / it panics — reproduced.
2. Diagnose: is CONFIG_EFI_STUB set? Is the root filesystem driver built-in
(=y, not =m, if there's no initramfs)? Is CONFIG_EFIVAR_FS present? Compare
against a known-good config.
Verify: identify the exact missing symbol (e.g. root fs was =m with no
initramfs).
3. Fix that one cause.
Verify: rebuilt kernel boots to a login prompt in the VM.
4. Re-run a clean VM boot.
Verify: boots cleanly; check dmesg for the relevant subsystem.
No "EFI-sounding" symbols added on a hunch — find the one that's actually missing.
User request: "Move to the next upstream Linux release."
What LLMs often do (all at once):
Bump the version, regenerate the config with make defconfig, re-roll all
patches, and commit — untested, with the low-latency tuning lost.
What should happen (incremental):
Plan:
1. Bump the upstream version in the recipe; update the source checksum.
Verify: the source fetches and its checksum/signature verifies.
2. Carry the existing config forward: `make olddefconfig`.
Verify: review every NEW symbol it prompts/sets — accept deliberately, not
blindly; git diff is understandable.
3. Re-apply the patch set; drop patches now upstream.
Verify: each patch applies cleanly or is removed with a note.
4. Build the package.
Verify: build succeeds.
5. Boot-test in QEMU + OVMF.
Verify: boots to login; low-latency profile intact (CONFIG_PREEMPT still y);
spot-check key drivers in dmesg.
Each step is independently checkable; the low-latency config is preserved, not regenerated.
| Principle | Anti-pattern | Fix |
|---|---|---|
| Think Before Coding | CONFIG_BT=y for "enable Bluetooth" |
Ask built-in vs module + which sub-options; make olddefconfig |
| Simplicity First | Enable a zoo of filesystems for an ext4 request | Set only CONFIG_EXT4_FS=y |
| Surgical Changes | make defconfig (+ version bump) to add one driver |
Set the one symbol, make olddefconfig, diff |
| Goal-Driven | Add "EFI-sounding" symbols on a hunch for a no-boot | Reproduce in QEMU+OVMF, find the one missing symbol, fix it |
The "overcomplicated" examples aren't obviously wrong — extra filesystems, profile frameworks, and "EFI-sounding" symbols all look thorough. The problem is timing and blast radius: in a kernel config, premature breadth and incidental edits can make every install unbootable, and the failure surfaces only after a successful build.
- A bad symbol doesn't fail the build — it fails the boot. Boot-test in a VM.
- Keep the delta minimal and the diff legible (
make olddefconfig, notdefconfig). - Boot-critical options (UEFI, root filesystem, block/initramfs) are never touched as a side effect.
Good slkernel changes are the smallest config/recipe delta that solves the need while keeping the kernel bootable on a UEFI-only system — verified in a VM, not assumed.