Show HN: Simple tool for FDEs to avoid missing HITL steps in claude code 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. 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. curl -fsSL https://raw.githubusercontent.com/robertodf99/hook-me-up/main/install.sh | bash The installer downloads the latest release and checks its SHA-256 , installs ~/Applications/Hook Me Up.app , shows the changes it would make to ~/.claude/settings.json and asks before writing them with a timestamped backup , adds the editor extension editor-extension to VS Code, VS Code Insiders, Cursor and Windsurf when it finds their command-line tool, and starts the menu-bar agent at login. Run it again to upgrade. Uninstall: curl -fsSL https://raw.githubusercontent.com/robertodf99/hook-me-up/main/uninstall.sh | bash It 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. Requirements: macOS 14 or later, and Claude Code https://docs.claude.com/en/docs/claude-code/overview . Hook Me Up is also a Claude Code plugin with three commands that run the same installer and ask for your confirmation in the chat: /plugin marketplace add robertodf99/hook-me-up /plugin install hook-me-up@hook-me-up On Claude Code 2.1.275 or later, /plugin install hook-me-up --marketplace robertodf99/hook-me-up does both in one step. Then: - /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. - /hook-me-up:doctor checks the installation and explains how to fix what is off. - /hook-me-up:uninstall shows what would be removed and removes it after you say yes. The plugin has commands only, no hooks: the hooks live in ~/.claude/settings.json as with the installer. Hooks inside the plugin would run in addition to those, and every request would be notified twice. Once 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: 1. Allow notifications for Hook Me Up when macOS asks or in System Settings → Notifications → Hook Me Up . 2. In the same place, set the style to Alerts , so requests stay on screen until you answer them. On a first install, the installer opens System Settings at Notifications when the style isn't Alerts yet; on an upgrade, only when notifications are off. 3. Restart Claude Code sessions that were already running, so they load the hooks. | When Claude Code… | Notification | Actions, in order | |---|---|---| | 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 | | asks a question with up to four options | project · Question | One action per option, then Reply… for your own answer | | 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 | | 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 | | finishes a turn, or waits for a reply | project · Finished / Waiting for your reply | none | - Clicking a notification opens its session : Terminal and iTerm2 select the exact tab. Ghostty 1.3 or later focuses the terminal whose working directory is the folder Claude Code was started in. When several terminals are there splits or tabs in the same folder , Hook Me Up briefly sets the title of the session's own terminal to a random marker, asks Ghostty which terminal shows it, puts the old title back and focuses that terminal; the title is back within about a second. When Ghostty doesn't show the marker in time a fixed title = … in its config, or the session changed its title first , the title is cleared instead, so no marker is left behind a title the session set meanwhile shows again when it next sets one , and Ghostty just comes to the front, as it does when the session has ended, when no terminal is in the folder, or when Ghostty's AppleScript is off macos-applescript = false . VS Code and Cursor and VS Code Insiders and Windsurf focus the open window that contains the folder Claude Code was started in: that folder's window, the window of the repository a worktree or subfolder belongs to, or a saved .code-workspace that includes it; with the editor extension editor-extension , the session's integrated terminal is shown too, even when the window has several. While the session's window is open, a click opens no new window; when no open window contains the folder, the editor just comes to the front and, with the extension, the front window shows the session's terminal if it has it . The editor keeps its list of windows up to date with a delay, so right after you close windows a click may just bring the editor to the front. Zed and other apps come to the front. The click hands the request to Claude Code's terminal dialog: nothing is approved or answered from it. In a multi-question flow, the answers given so far are dropped and the terminal asks all the questions again. - macOS shows the first action as a button and the others under Options when you hover the notification, so the most likely answer comes first. - 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. - Answering needs an unlocked Mac, so nothing can be approved from the lock screen. - 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. The ✻ menu-bar item shows how many requests are waiting and offers Pause for 30 minutes , Resume and Quit . VS Code can't be asked from outside which integrated terminal runs a session, so Hook Me Up comes with a small extension for VS Code, VS Code Insiders, Cursor and Windsurf plain JavaScript, no dependencies; source in editor-extension/ https://github.com/robertodf99/hook-me-up/blob/main/editor-extension . On a click, the agent writes a request to ~/Library/Application Support/hook-me-up/editor-focus-request.json : a random id, the time and the session's process ids, nothing else no paths, titles or commands . Every editor window watches that file; the window with a terminal whose process is one of those ids shows it, and the others do nothing. Without the extension or with it disabled , a click works exactly as before: it focuses the window. - 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. - Windows that were already open may need a reload Developer: Reload Window before the extension runs in them. - The uninstaller removes it. You can also remove it from the editor's Extensions view it is "Hook Me Up", id hook-me-up.hook-me-up . - hook-me-up-setup doctor shows which editors have it an INFO line; it never fails . - 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. Claude Code ──hook──▶ hook-me-up ──Unix socket──▶ Hook Me Up menu-bar agent ▲ │ │ └──── decision ◀─────┘ ◀──────── your answer ◀──── native notification Claude Code runs the hook-me-up command for PermissionRequest , Notification , Stop , UserPromptSubmit and SessionEnd . For a permission request, the hook asks the agent over a local socket and waits; the agent shows a notification and sends back your decision, and the hook prints it for Claude Code. If there is no decision the agent isn't running, notifications are off, the agent is paused, something fails, or the request times out , the hook prints nothing and Claude Code shows its own terminal dialog. You can always answer in the terminal instead; the notification then goes away. See docs/ARCHITECTURE.md https://github.com/robertodf99/hook-me-up/blob/main/docs/ARCHITECTURE.md for the details. - Fail-open. The hook outputs a decision only when you made one. Errors never turn into an approval or a denial. - 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 . - One answer per request. Every request has its own id; the agent answers only on that request's connection, at most once, and the hook ignores any answer for another id. An action only counts if it belongs to the notification currently shown. - The hook builds the output. Answers never carry tool input from the agent: the hook builds updatedInput from its own tool input . - Session-only rules. "Approve for session" keeps only rule and directory suggestions and always scopes them to the session; it never writes to your settings. - Unlocked Mac only for every answering action. - Clicks reach only the session's own terminal. For Ghostty, the title marker is written only to the session's tty, and only while the session runs and that tty is still its controlling terminal a character device of yours with the same device number, opened without following links ; the marker is random, goes to Ghostty's AppleScript as an argument never as script text , and the title written back has no control characters. The editor extension acts only on a request that is exactly what the agent writes: a file of yours in your private support folder, not a link, at most 4 KiB, less than 5 seconds old, each id once, 1 to 16 process ids; it never writes the file, logs nothing and sends nothing anywhere. - Careful installer. It verifies the package checksum, shows the settings diff and asks first, backs up, writes atomically, and refuses to write if the file changed meanwhile. - 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. Hook 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: - System Settings → General → Login Items Login Items & Extensions on newer macOS lists Hook Me Up under Allow in the Background , marked as from an unidentified developer. - 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. - codesign -dv ~/Applications/"Hook Me Up.app" shows Signature=adhoc . Why the install isn't blocked. Gatekeeper checks apps that carry the quarantine flag com.apple.quarantine , which browsers and other apps add to what they download. curl doesn't add it, so the app the installer unpacks opens normally. The same zip downloaded with a browser would be quarantined, and Gatekeeper would block the app from opening. What to do. Keep the Login Items entry enabled: turning it off stops the agent from starting at login, and requests then go to the terminal dialog. Install with the script rather than by downloading the zip in a browser. Or build it yourself from this repository Building from source building-from-source . How to check what you installed. - codesign --verify --strict --deep ~/Applications/"Hook Me Up.app" checks that no file changed since the package was signed. An ad-hoc signature can't tell you who signed it. - The installer compares the zip with the .sha256 file published in the same release. That catches a corrupted or cut-short download. It doesn't protect against a compromised account or release: whoever can replace the zip can replace its checksum too. - Releases 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: gh release download v0.2.0 --repo robertodf99/hook-me-up --pattern ' .zip' gh attestation verify hook-me-up-0.2.0-macos.zip --repo robertodf99/hook-me-up \ --signer-workflow robertodf99/hook-me-up/.github/workflows/release.yml Compare it with the installed app: ditto -x -k hook-me-up-0.2.0-macos.zip unpacked diff -r unpacked/HookMeUp.app ~/Applications/"Hook Me Up.app" 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. The installer and uninstaller read these environment variables: | Variable | Effect | |---|---| | HOOK ME UP VERSION=v1.2.3 | Install that release instead of the latest | | HOOK ME UP YES=1 | Change ~/.claude/settings.json without asking non-interactive installs | | HOOK ME UP ZIP=