I have a custom Claude Code status line (model, git branch, context %, cost). Then I installed kickbacks.ai — a plugin that pays you to show ads in your dev tools — and it took over my status bar. I wanted both. Here's the rabbit hole and the fix that finally stuck.
kickbacks.ai (internally "vibe-ads", a VS Code extension) writes a statusLine
into ~/.claude/settings.json pointing at its own script
(~/.vibe-ads/vibe-ads-statusline.mjs), plus a spinnerVerbs ad.
The good news: it's designed to coexist. Its script prints the ad and then runs
your previous status line, stacking your output on the lines below. It reads "your
previous command" from a chain file: ~/.vibe-ads/cli-prev-statusline.json.
The reason it looked like a pure hijack: my custom bar was never registered in
settings.json, so kickbacks captured nothing to chain → ad-only.
// ~/.vibe-ads/cli-prev-statusline.json
{ "statusLine": { "type": "command", "command": "python3 ~/.claude/statusline-command.py" } }Both showed: ad on top, my bar underneath. 🎉 …for a while.
kickbacks flaps between two states — inject (its script) and restore (puts your
old bar back) — and its auth was throwing 401s, so it cycled constantly. Two problems:
- its
restore()deletes the chain file every cycle, and - it had captured
nullas the "previous" bar (becausesettings.jsonhad no status line when it first took over).
Result: a degenerate state where both the ad-chain and the restore came up empty → blank.
Stop fighting it; feed it. kickbacks restores from a backup file. Put your bar in both the chain file and that backup:
~/.claude/settings.json.vibe-ads-backup → statusLine = your bar (used by restore())
~/.vibe-ads/cli-prev-statusline.json → your bar (used by inject chain)
Now both states self-heal: every inject shows ad + your bar, every restore puts your bar back. Stable across the flapping.
Two realizations killed Fix Y as a final answer:
- kickbacks auto-updates (I watched
0.3.174 → .176 → .177). One update that renames a file and my manual seed is silently gone. - The breakage isn't at startup — it's continuous, mid-session. kickbacks reconciles on a ~90s ad-poll (plus auth flaps) and deletes the chain file each restore.
I first tried a SessionStart hook that re-seeds on every Claude Code launch. Good,
but insufficient: it fires once per session, and a once-per-session fix can't keep up
with a plugin that wipes your files every couple of minutes. I needed something that
re-asserts reactively, the moment kickbacks touches the config.
A macOS LaunchAgent with WatchPaths on ~/.claude/settings.json. launchd (already
running as part of the OS) fires the keeper via kernel file events only when
settings.json changes — which is exactly when kickbacks reconciles and deletes the
chain. No polling, no resident process; ~50ms per fire, hard-capped to once per 10s by
ThrottleInterval. Tested: deleted the chain mid-session → re-seeded in ~2s, exit 0.
keeper.plist (in this gist) + the keeper script. Install:
# 1) keeper script
mkdir -p ~/.claude/hooks
cp kickbacks-statusline-keeper.py ~/.claude/hooks/
# 2) statusLine + SessionStart hook → merge settings.snippet.jsonc into ~/.claude/settings.json
# 3) launchd watcher (substitutes your real home path, then loads it)
mkdir -p ~/Library/LaunchAgents
sed "s#__HOME__#$HOME#g" keeper.plist > ~/Library/LaunchAgents/com.kickbacks-statusline-keeper.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.kickbacks-statusline-keeper.plistBelt and suspenders: the SessionStart hook guarantees a good state at every launch; the watcher covers everything in between.
- Read its code first. It may already support chaining/coexistence.
- Seed its durable restore path, not just the live config it keeps overwriting.
- Re-assert reactively (a file-watch), not just once at startup — the breakage is continuous, so the fix has to be too.
Now kickbacks can flap all it wants — at worst the ad blinks; my status bar stays. 🧱
Paths use ~/$HOME. Point the statusLine command at your own status line script.
launchd plists need absolute paths (no ~), hence the __HOME__ substitution above.
Tested against kickbacks.ai / vibe-ads 0.3.177, Claude Code 2.1.181, macOS 26.