{"slug": "show-hn-simple-tool-for-fdes-to-avoid-missing-hitl-steps-in-claude-code", "title": "Show HN: Simple tool for FDEs to avoid missing HITL steps in claude code", "summary": "Developer robertodf99 released Hook Me Up, a macOS menu-bar tool that surfaces Claude Code's permission requests, questions, plan approvals and turn completions as native notifications users can act on directly, built on Claude Code's hooks and designed to fail open to the usual terminal dialog if anything goes wrong. The tool requires macOS 14 or later and Claude Code, installs via a curl script that verifies the release's SHA-256 and asks before writing changes to ~/.claude/settings.json with a timestamped backup, and is also available as a Claude Code plugin with /hook-me-up:install, /hook-me-up:doctor and /hook-me-up:uninstall commands.", "body_md": "Answer Claude Code from native macOS notifications. When Claude Code needs permission for a tool, asks you a question, wants a plan approved or finishes a turn, Hook Me Up shows a notification you can act on right there: approve or deny, pick an answer, approve the plan or ask for changes. Click the notification to jump to the session. It is built on Claude Code's hooks and fails open: if anything is off, Claude Code simply shows its usual terminal dialog.\n\n```\ncurl -fsSL https://raw.githubusercontent.com/robertodf99/hook-me-up/main/install.sh | bash\n```\n\nThe installer downloads the latest release (and checks its SHA-256), installs\n`~/Applications/Hook Me Up.app`, shows the changes it would make to\n`~/.claude/settings.json` and **asks before writing them** (with a timestamped\nbackup), adds the [editor extension](#editor-extension) to VS Code, VS Code Insiders,\nCursor and Windsurf when it finds their command-line tool, and starts the menu-bar agent\nat login. Run it again to upgrade.\n\nUninstall:\n\n```\ncurl -fsSL https://raw.githubusercontent.com/robertodf99/hook-me-up/main/uninstall.sh | bash\n```\n\nIt stops the agent, removes Hook Me Up's hooks from your settings (again after showing the diff and asking), and removes the app, its support folder and the editor extension (with each editor's command-line tool it finds). Your settings backups stay where they are.\n\nRequirements: macOS 14 or later, and [Claude Code](https://docs.claude.com/en/docs/claude-code/overview).\n\nHook Me Up is also a Claude Code plugin with three commands that run the same installer and ask for your confirmation in the chat:\n\n```\n/plugin marketplace add robertodf99/hook-me-up\n/plugin install hook-me-up@hook-me-up\n```\n\n(On Claude Code 2.1.275 or later, `/plugin install hook-me-up --marketplace robertodf99/hook-me-up`\ndoes both in one step.) Then:\n\n- `/hook-me-up:install` installs or upgrades Hook Me Up: it shows the changes to`~/.claude/settings.json` and adds the hooks only after you say yes.\n- `/hook-me-up:doctor` checks the installation and explains how to fix what is off.\n- `/hook-me-up:uninstall` shows what would be removed and removes it after you say yes.\n\nThe plugin has commands only, no hooks: the hooks live in `~/.claude/settings.json` as\nwith the installer. Hooks inside the plugin would run in addition to those, and every\nrequest would be notified twice.\n\nOnce the agent runs, the installer waits (up to a minute in a terminal, 10 seconds without one) for you to answer macOS's question about notifications, shows a test notification, and tells you what is left to do:\n\n1. Allow notifications for **Hook Me Up** when macOS asks (or in System Settings →\nNotifications → Hook Me Up).\n2. In the same place, set the style to **Alerts** , so requests stay on screen until\nyou answer them. On a first install, the installer opens System Settings at\nNotifications when the style isn't Alerts yet; on an upgrade, only when\nnotifications are off.\n3. Restart Claude Code sessions that were already running, so they load the hooks.\n\n| When Claude Code… | Notification | Actions, in order | \n|---|---|---|\n| needs permission for a tool | `project · Needs permission` , with a plain-language summary and warnings such as \"⚠︎ Leaves your machine\" | Approve, Deny, Approve for session (when Claude Code suggests a session rule) | \n| asks a question with up to four options | `project · Question` | One action per option, then Reply… for your own answer | \n| asks a question with more options, or a multi-select one | `project · Question` , the options numbered in the body | Reply…: type `2` ,`1, 3` , or an option's label | \n| wants a plan approved | `project · Plan to approve` , with the first lines of the plan | Approve plan, Request changes… (your text goes back to Claude) | \n| finishes a turn, or waits for a reply | `project · Finished` /`Waiting for your reply` | none | \n\n- **Clicking a notification opens its session** : Terminal and iTerm2 select the exact\ntab. Ghostty (1.3 or later) focuses the terminal whose working directory is the folder\nClaude Code was started in. When several terminals are there (splits or tabs in the\nsame folder), Hook Me Up briefly sets the title of the session's own terminal to a\nrandom marker, asks Ghostty which terminal shows it, puts the old title back and\nfocuses that terminal; the title is back within about a second. When Ghostty doesn't\nshow the marker in time (a fixed`title = …` in its config, or the session changed its\ntitle first), the title is cleared instead, so no marker is left behind (a title the\nsession set meanwhile shows again when it next sets one), and Ghostty just comes to\nthe front, as it does when the session has ended, when no terminal is in the folder, or\nwhen Ghostty's AppleScript is off (`macos-applescript = false` ).\nVS Code and Cursor (and VS Code Insiders and Windsurf) focus the open window that\ncontains the folder Claude Code was started in: that folder's window, the window of\nthe repository a worktree or subfolder belongs to, or a saved`.code-workspace` that\nincludes it; with the[editor extension](#editor-extension) , the session's integrated\nterminal is shown too, even when the window has several. While the session's window is\nopen, a click opens no new window; when no open window contains the folder, the editor\njust comes to the front (and, with the extension, the front window shows the session's\nterminal if it has it). The editor keeps its list of windows up to date with a delay,\nso right after you close windows a click may just bring the editor to the front. Zed and\nother apps come to the front.\nThe click hands the request to Claude Code's terminal dialog: nothing is\napproved or answered from it. In a multi-question flow, the answers given so far are\ndropped and the terminal asks all the questions again.\n- macOS shows the **first action as a button** and the others under**Options** when\nyou hover the notification, so the most likely answer comes first.\n- Several questions arrive one at a time; Claude gets all the answers after the last. A reply that can't be understood brings the question back with a hint.\n- Answering needs an unlocked Mac, so nothing can be approved from the lock screen.\n- Notifications are grouped per repository, play the default sound once, and disappear when the request is answered (here or in the terminal), cancelled, or the session moves on.\n\nThe ✻ menu-bar item shows how many requests are waiting and offers **Pause for 30\nminutes**, **Resume** and **Quit**.\n\nVS Code can't be asked from outside which integrated terminal runs a session, so Hook Me\nUp comes with a small extension for VS Code, VS Code Insiders, Cursor and Windsurf (plain\nJavaScript, no dependencies; source in [editor-extension/](https://github.com/robertodf99/hook-me-up/blob/main/editor-extension)). On a\nclick, the agent writes a request to\n`~/Library/Application Support/hook-me-up/editor-focus-request.json`: a random id, the\ntime and the session's process ids, nothing else (no paths, titles or commands). Every\neditor window watches that file; the window with a terminal whose process is one of those\nids shows it, and the others do nothing. Without the extension (or with it disabled), a\nclick works exactly as before: it focuses the window.\n\n- The installer adds it with each editor's command-line tool (`code` ,`code-insiders` ,`cursor` ,`windsurf` , on your`PATH` or inside the app in`/Applications` or`~/Applications` ) and says so; if adding it fails, the install goes on. Set`HOOK_ME_UP_NO_EDITOR_EXTENSION=1` to skip it.\n- Windows that were already open may need a reload (**Developer: Reload Window** ) before\nthe extension runs in them.\n- The uninstaller removes it. You can also remove it from the editor's Extensions view\n(it is \"Hook Me Up\", id `hook-me-up.hook-me-up` ).\n- `hook-me-up-setup doctor` shows which editors have it (an INFO line; it never fails).\n- Profiles: Hook Me Up checks the extension in the default profile's list (where the installer adds it). A window that uses another profile runs it only if that profile has it too; otherwise the click focuses that window as before.\n\n```\nClaude Code ──hook──▶ hook-me-up ──Unix socket──▶ Hook Me Up (menu-bar agent)\n     ▲                    │                              │\n     └──── decision ◀─────┘ ◀──────── your answer ◀──── native notification\n```\n\nClaude Code runs the `hook-me-up` command for `PermissionRequest`, `Notification`,\n`Stop`, `UserPromptSubmit` and `SessionEnd`. For a permission request, the hook asks\nthe agent over a local socket and waits; the agent shows a notification and sends back\nyour decision, and the hook prints it for Claude Code. If there is no decision (the\nagent isn't running, notifications are off, the agent is paused, something fails, or\nthe request times out), the hook prints nothing and Claude Code shows its own terminal\ndialog. You can always answer in the terminal instead; the notification then goes\naway. See [docs/ARCHITECTURE.md](https://github.com/robertodf99/hook-me-up/blob/main/docs/ARCHITECTURE.md) for the details.\n\n- **Fail-open.** The hook outputs a decision only when you made one. Errors never turn\ninto an approval or a denial.\n- **Local, same-user socket.** The socket lives in a private folder (`0700` , socket`0600` ) and both sides check that the peer runs as the same user (`getpeereid` ).\n- **One answer per request.** Every request has its own id; the agent answers only on\nthat request's connection, at most once, and the hook ignores any answer for another\nid. An action only counts if it belongs to the notification currently shown.\n- **The hook builds the output.** Answers never carry tool input from the agent: the\nhook builds`updatedInput` from its own`tool_input` .\n- **Session-only rules.** \"Approve for session\" keeps only rule and directory\nsuggestions and always scopes them to the session; it never writes to your settings.\n- **Unlocked Mac only** for every answering action.\n- **Clicks reach only the session's own terminal.** For Ghostty, the title marker is\nwritten only to the session's tty, and only while the session runs and that tty is\nstill its controlling terminal (a character device of yours with the same device\nnumber, opened without following links); the marker is random, goes to Ghostty's\nAppleScript as an argument (never as script text), and the title written back has no\ncontrol characters. The editor extension acts only on a request that is exactly what\nthe agent writes: a file of yours in your private support folder, not a link, at most\n4 KiB, less than 5 seconds old, each id once, 1 to 16 process ids; it never writes the\nfile, logs nothing and sends nothing anywhere.\n- **Careful installer.** It verifies the package checksum, shows the settings diff and\nasks first, backs up, writes atomically, and refuses to write if the file changed\nmeanwhile.\n- **No content in logs.**`~/Library/Logs/hook-me-up.log` and the unified log (subsystem`io.github.robertodf99.hook-me-up` ) hold event kinds and short ids only.\n\nHook Me Up is signed ad-hoc: it has no Apple Developer ID and is not notarized. A Developer ID is a paid Apple membership, and this project won't buy one. What you see because of that:\n\n- System Settings → General → Login Items (Login Items & Extensions on newer macOS)\nlists Hook Me Up under **Allow in the Background** , marked as from an unidentified\ndeveloper.\n- When the installer starts the agent, macOS may show a notice that Hook Me Up added an item that can run in the background. That is the LaunchAgent that starts the agent at login.\n- `codesign -dv ~/Applications/\"Hook Me Up.app\"` shows`Signature=adhoc` .\n\n**Why the install isn't blocked.** Gatekeeper checks apps that carry the quarantine\nflag (`com.apple.quarantine`), which browsers and other apps add to what they download.\n`curl` doesn't add it, so the app the installer unpacks opens normally. The same zip\ndownloaded with a browser would be quarantined, and Gatekeeper would block the app from\nopening.\n\n**What to do.** Keep the Login Items entry enabled: turning it off stops the agent from\nstarting at login, and requests then go to the terminal dialog. Install with the script\nrather than by downloading the zip in a browser. Or build it yourself from this\nrepository ([Building from source](#building-from-source)).\n\n**How to check what you installed.**\n\n- \n`codesign --verify --strict --deep ~/Applications/\"Hook Me Up.app\"` checks that no\nfile changed since the package was signed. An ad-hoc signature can't tell you who\nsigned it.\n- \nThe installer compares the zip with the `.sha256` file published in the same\nrelease. That catches a corrupted or cut-short download. It doesn't protect against\na compromised account or release: whoever can replace the zip can replace its\nchecksum too.\n- \nReleases from v0.2.0 on carry a GitHub build provenance attestation, which ties the zip to the workflow run and the commit that built it: \n\n```\ngh release download v0.2.0 --repo robertodf99/hook-me-up --pattern '*.zip'\ngh attestation verify hook-me-up-0.2.0-macos.zip --repo robertodf99/hook-me-up \\\n  --signer-workflow robertodf99/hook-me-up/.github/workflows/release.yml\n# Compare it with the installed app:\nditto -x -k hook-me-up-0.2.0-macos.zip unpacked\ndiff -r unpacked/HookMeUp.app ~/Applications/\"Hook Me Up.app\"\n```\n\n This shows the zip was built by this repository's release workflow from that commit. It says nothing about what the code at that commit does: reading the source, or building it yourself, is still the strongest check.\n\nThe installer and uninstaller read these environment variables:\n\n| Variable | Effect | \n|---|---|\n| `HOOK_ME_UP_VERSION=v1.2.3` | Install that release instead of the latest | \n| `HOOK_ME_UP_YES=1` | Change `~/.claude/settings.json` without asking (non-interactive installs) | \n| `HOOK_ME_UP_ZIP=<path>` | Install a local package (its `.sha256` must sit next to it) | \n| `HOOK_ME_UP_NO_ONBOARDING=1` | Skip the notification check after starting the agent (no waiting, no test notification, System Settings stays closed) | \n| `HOOK_ME_UP_NO_EDITOR_EXTENSION=1` | Don't add the [editor extension](#editor-extension) to VS Code, VS Code Insiders, Cursor or Windsurf | \n\nExample: `curl -fsSL …/install.sh | HOOK_ME_UP_YES=1 bash`. Without a terminal and\nwithout `HOOK_ME_UP_YES=1`, the installer changes nothing in your settings and prints\nthe command to run.\n\nTo take a break, use **Pause for 30 minutes** in the menu bar: requests go to the\nterminal until it ends or you choose **Resume**.\n\nRequires Xcode 16 or later (Swift 6).\n\n```\nmake            # build the hook, the installer CLI and the agent\nmake test       # unit tests\nmake lint       # swift format lint (make format to apply)\nmake app        # .build/HookMeUp.app (with the editor extension in Contents/Resources)\nmake vsix       # the editor extension alone: .build/hook-me-up.vsix\nmake install    # package this checkout and run install.sh with it\nmake uninstall  # run uninstall.sh\nmake dist VERSION=1.2.3 UNIVERSAL=1   # .build/dist/hook-me-up-1.2.3-macos.zip and .sha256\n```\n\n[docs/TESTING.md](https://github.com/robertodf99/hook-me-up/blob/main/docs/TESTING.md) lists the automated checks and a manual end-to-end\nchecklist. Pushing a `v*` tag publishes a release with GitHub Actions.\n\nStart with the doctor. It checks the app, the LaunchAgent, the running agent, the hooks in\n`~/.claude/settings.json` and the notification settings, and says how to fix each\nproblem (it changes nothing itself):\n\n```\n~/Applications/\"Hook Me Up.app\"/Contents/MacOS/hook-me-up-setup doctor\n```\n\nFrom Claude Code, run `/hook-me-up:doctor`.\n\nThe agent writes its log to `~/Library/Logs/hook-me-up.log`.\n\n- \n**No notifications.** Check System Settings → Notifications → Hook Me Up. While\nnotifications are off, every request goes to the terminal and the log says how to\nturn them on.\n- \n**Nothing happens at all.** Make sure the agent runs (✻ in the menu bar; else run the\ninstaller again) and restart your Claude Code sessions so they load the hooks.\n- \n**The agent's folder was deleted** (`~/Library/Application Support/hook-me-up` , say by\na cleanup tool): the agent notices within about 5 seconds, creates it again and keeps\nlistening (the log says`socket was removed or replaced; listening again` ). Requests in\nbetween go to the terminal.\n- \n**The icon is out of date** after an upgrade. macOS caches it:\n\n```\n/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f ~/Applications/\"Hook Me Up.app\"\nkillall NotificationCenter usernoted\n```\n\n If it is still stale, log out and back in.\n- \n**Login Items shows \"unidentified developer\".** Releases are signed ad-hoc; keep the\nitem enabled. See[Why macOS says \"unidentified developer\"](#why-macos-says-unidentified-developer) for what that means and how to check what you installed.\n- \n**Clicking a notification doesn't select the tab.** The first time, macOS asks to let\nHook Me Up control Terminal, iTerm2 or Ghostty; allow it in System Settings → Privacy &\nSecurity → Automation. With several Ghostty terminals in the session's folder, the log\nsays why one wasn't picked (`ghostty: title marker not seen` , for instance when\nGhostty's config sets`title` ). In VS Code and the editors built on it, the terminal is\nshown only with the[editor extension](#editor-extension) : check it with the doctor, and\nreload windows opened before it was installed.\n\nTried it? Tell me what worked and what broke in\n[Feedback & ideas](https://github.com/robertodf99/hook-me-up/discussions/1); questions go to\n[Q&A](https://github.com/robertodf99/hook-me-up/discussions/categories/q-a). For a bug,\n[open an issue](https://github.com/robertodf99/hook-me-up/issues/new/choose) with the output\nof `hook-me-up-setup doctor`.\n\nThe app icon is drawn from the Claude symbol on Wikimedia Commons (CC0 1.0); see\n[THIRD_PARTY_NOTICES.md](https://github.com/robertodf99/hook-me-up/blob/main/THIRD_PARTY_NOTICES.md).", "url": "https://wpnews.pro/news/show-hn-simple-tool-for-fdes-to-avoid-missing-hitl-steps-in-claude-code", "canonical_source": "https://github.com/robertodf99/hook-me-up", "published_at": "2026-11-15 16:01:49+00:00", "updated_at": "2026-11-15 16:23:21.883006+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "developer-tools", "ai-products"], "entities": ["Hook Me Up", "Claude Code", "robertodf99", "macOS", "VS Code", "Cursor", "Windsurf", "iTerm2"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-simple-tool-for-fdes-to-avoid-missing-hitl-steps-in-claude-code", "markdown": "https://wpnews.pro/news/show-hn-simple-tool-for-fdes-to-avoid-missing-hitl-steps-in-claude-code.md", "text": "https://wpnews.pro/news/show-hn-simple-tool-for-fdes-to-avoid-missing-hitl-steps-in-claude-code.txt", "jsonld": "https://wpnews.pro/news/show-hn-simple-tool-for-fdes-to-avoid-missing-hitl-steps-in-claude-code.jsonld"}}