summaryrefslogtreecommitdiff
path: root/config
AgeCommit message (Collapse)Author
2026-10-02SyncIgor Soarez
2026-10-02pi: drop pi-mcp-adapter, MCP is native nowIgor Soarez
pi 1.0.0 has MCP built in, and while the adapter is installed it suppresses that and prints a warning at every start. The browser gates that answered the adapter's approval event now hook pi's own tool_call as well. From change request 562974.
2026-10-01hammerspoon: Caps Lock sends F20, and stays that wayIgor Soarez
hidutil remaps inside the IOKit HID driver, below the window server, so the key stops being Caps Lock before anything above the driver sees it: no toggle to suppress, and F20 is a real key to other apps, to System Settings shortcuts, to a password field. An eventtap cannot do this -- Caps Lock is not reachable from there, which is why hs.hid exists as its own IOKit module. What hidutil will not do is cover a keyboard attached after it ran, so dotlib re-applies on USB attach, on wake, and on a Caps Lock event. That last one is the general answer: a mapped keyboard cannot produce a Caps Lock event, so an event arriving at all is proof of a keyboard the remap missed, and the fault triggers its own repair. The watchers are there to get the common cases before a key is pressed, since the repairing press is spent repairing. No launchd job and no link/ part. The remap lives and dies with Hammerspoon, which already owns the keyboard on these machines, and a plist would only have bought independence from it for the second or two before it starts -- a user agent does not run at the login window either. Nothing is bound to f20 here; bind it like any other key. A machine gives the key back with capslock_off() from its local.lua, which loads last: shadowing cannot undo a side effect that has already run. hs.ipc is required so capslock_status() answers from a shell.
2026-09-28AGENTS.md is the file; CLAUDE.md imports itIgor Soarez
Every agent here except Claude Code reads AGENTS.md -- pi, codex, and aider now that its read: says so. The vendor-neutral name was the symlink and the Claude-specific one the real file, with a header saying the file was guidance "to Claude Code". Swapped, keeping history on the real file through git mv. Claude Code has read AGENTS.md directly since v2.1.277 and the machine this was done on is newer, so the obvious move was to delete CLAUDE.md. Checking the other machines first was worth it: four were on versions between 2.1.158 and 2.1.263, and a session on any of them would have found no instructions at all. So CLAUDE.md stays as one line, `@AGENTS.md`, which the documentation endorses for exactly this case and which -- unlike the symlink it replaces -- works on Windows and does not trip Claude Code's refusal to write through a symlink. The header says to delete it once every machine is current.
2026-09-28tmux: the command prompt gets an opaque backgroundIgor Soarez
Every theme set message-style with a bg and no fill. From tmux 3.7 the command prompt is drawn over the status line, where only the prompt's own characters take that bg and the rest of the line takes fill; with status-style bg=default everywhere here, the terminal showed through around the prompt. Reported from a machine running 3.7c. fill now matches bg in all eight. It has existed since tmux 3.2 and older versions ignore it, so this is safe on the fleet: checked on 3.5a, where each theme sources cleanly and reports the fill back.
2026-09-28pi: the siliconflow key is a reference, not a nameIgor Soarez
models.json gave the provider an apiKey of "SILICONFLOW_API_KEY", which pi sends verbatim as the credential: it interpolates "$NAME" and "${NAME}", runs "!command", and treats anything else as a literal. So that provider has been authenticating with the 19-character string "SILICONFLOW_API_KEY" and getting a 401 for as long as it has existed. Confirmed by calling pi's own resolver: "SILICONFLOW_API_KEY" resolves to itself, "$SILICONFLOW_API_KEY" to the value. Nothing catches this -- isConfigValueConfigured returns true for both and reports no missing variables, so `pi auth check` says ready either way, and only a real request fails. Hence the note in CLAUDE.md beside the models.d row: the rule is invisible in the file, and the next provider added would repeat it. Reported as a change request from the machine that hit it; the sweep for other instances found none.
2026-09-25profile: stop shadowing exitIgor Soarez
`exit` was a function that ran `tmux detach` instead of exiting, whenever a shell was interactive and inside tmux. What it bought was a keystroke: tmux already binds detach to prefix-d, which this config does not touch. What it cost was an afternoon. Claude Code captures shell functions into a snapshot and sources it in every tool call, so agent shells inheriting $TMUX ran the function too: terminal windows closed on their own for weeks before anyone connected it to `exit`, and a poll loop that called `exit 0` detached a client every minute instead of stopping, because the function detached and then returned. The call-time guard added on 2026-07-16 fixed that case; it did not make shadowing a POSIX builtin a good idea. Nothing in either repo calls it and nothing documents the behaviour.
2026-09-21hammerspoon: the example's header is init.lua's, so bindings move either wayIgor Soarez
It unpacked only hotkey and mods, so a line copied from init.lua -- which writes `hotkey('9', csa, type_text(...))` with bare names -- did not run here, and a line moved the other way had to be rewritten. The header is now the same block init.lua has, name for name, and the examples use the bare names too. Unused names in it are harmless, and keeping them whole is the point: paste a binding in either direction and it works as written.
2026-09-21hammerspoon: shared helpers move to dotlib.lua, which local.lua can requireIgor Soarez
A machine's local.lua is a separate chunk, so init.lua's locals were invisible to it and anything it wanted -- hotkey(), the mod tables, type_text -- had to be copied. They live in dotlib.lua now, linked beside init.lua, and both files reach them the same way: require("dotlib"). init.lua keeps its own vocabulary by aliasing what it uses, so the 500 lines below are untouched. It prepends its own directory to package.path first: Hammerspoon already puts the config directory there (Contents/Resources/ setup.lua), but taking it from this file's path holds however the config was found. A machine that pulls without re-linking has no dotlib.lua beside init.lua, which would lose every hotkey silently -- that case notifies and names the fix. Checked with a stubbed hs: the module's hotkey, focus, execute, type_text and type_current_date all behave, and local-example.lua binds its four keys through it.
2026-09-21hammerspoon, ghostty: example files for their machine-local configsIgor Soarez
ssh and git each ship one; these two hooks were discoverable only by reading the config that loads them. Both examples carry what is easy to get wrong: init.lua's hotkey() helper and mod tables are locals, so a local.lua calls hs.hotkey.bind directly, and a binding there can only be shadowed, never deleted; in Ghostty a single-value key replaces while keybind accumulates, and `ignore` is how a binding is switched off rather than added to. Checked rather than assumed: the lua parses, and the Ghostty example validates and, dropped in as ~/.config/ghostty-local, does what it says -- font-size, command and background-opacity replaced, super+shift+n added, alt+enter turned off.
2026-09-21ghostty: read ~/.config/ghostty-local last, where a machine has oneIgor Soarez
Ghostty had no way to differ per machine. It cannot take the shape the other tools use -- a file beside the linked one -- because link.sh links this whole directory, so ~/.config/ghostty is the checkout itself and a sibling file would be an untracked file in the repo every machine shares. An optional include at the end does the same job: later values replace earlier ones, so a local file overrides anything here, the theme colours included, and its keybinds add to these. Verified against the shipped config: font-size 12 becomes 18 with a local file, back to 12 without, and the config still validates when there is none.
2026-09-21hammerspoon: load ~/.config/hammerspoon/local.lua where a machine has oneIgor Soarez
The shell has ~/.localprofile and ssh and git their config-local; Hammerspoon had nothing, so a machine wanting one different hotkey had to edit the file every machine shares. Only init.lua is linked, so the directory around it is already the machine's own -- a sibling file there is in no repo. Loaded last, so it can override anything above, and through pcall: a mistake in a local file must not take the rest of the config down. Reload with ctrl-shift-alt-h as usual.
2026-09-21zshrc: find Homebrew's completions on the prefix this machine usesIgor Soarez
fpath carried /usr/local/share/zsh-completions, which is wrong twice over: Apple Silicon puts Homebrew under /opt/homebrew, and formulae install their completions into share/zsh/site-functions, not the share/zsh-completions of the formula by that name. The directory existed on neither Mac, so _brew, _bat, _deno and the rest have been missing all along -- silently, since a missing fpath entry says nothing. All four candidates are probed now, HOMEBREW_PREFIX first where a machine exports it. No `brew --prefix`: that forks on every interactive shell, and this file already pays for one of those further down.
2026-09-21supermaven off unless asked for; a blocked cask no longer ends install.shIgor Soarez
Supermaven was running everywhere. Its `condition` option reads the other way round from what the code assumed -- `true` stops it -- so `return false` meant "never stop", and the plugin loaded on InsertEnter, started its agent and offered inline suggestions on every machine. Only blink's source for it was off, which is what made it look disabled. It sends buffer context to a third party, so it is now opt-in: DOT_SUPERMAVEN=1, in ~/.localenv where it is wanted. Off, lazy keeps both plugins off disk entirely. install.sh no longer stops at brew bundle either. A managed machine can refuse a cask outright -- "disabled because it does not pass the macOS Gatekeeper check" -- and brew bundle fails the whole run for one such entry, which left the checkouts, nvim plugins and colour files undone. It warns and carries on; brew has already named the entry.
2026-09-21install.sh: install Homebrew, add bash, and seed the colour filesIgor Soarez
Three things a machine set up from this repo alone hit on its first run: Homebrew was a dead end -- install.sh printed the command and exited, leaving the one prerequisite everything else needs to be run by hand. It installs it now, NONINTERACTIVE so it does not wait on a RETURN; the sudo password is still asked for, which is why this script is run by hand. bash was missing from the Brewfile, so bin/open and secrets/ ran under the 3.2 macOS ships and failed on `${v,,}`; config/bashrc also looks for the bash-completion 2.x that wants 4.2. Ghostty refused to start -- "error opening config-file ... error.FileNotFound" -- because config-file pointed at the colour file bin/theme writes, which does not exist until theme has run. The include is optional now (`?`), and this script seeds the colour files when a machine has none, leaving a machine that already has a theme alone.
2026-09-17dotfilesIgor Soarez
Shell, editor and terminal configuration, the tools that go with them, and szecret, an age-based secret manager whose store lives elsewhere. History restarts here. What came before was not written to be read by anyone else, and carried machine names, addresses and an encrypted secret store; it is kept privately instead. What is left is meant to be safe on any machine, including one whose owner is not me: see CLAUDE.md for the rule it is written to.