Skip to content

[client] Delete the Hammerspoon client - #14

Closed
drycode wants to merge 1 commit into
dy/native-swift-agentfrom
dy/remove-hammerspoon-client
Closed

[client] Delete the Hammerspoon client#14
drycode wants to merge 1 commit into
dy/native-swift-agentfrom
dy/remove-hammerspoon-client

Conversation

@drycode

@drycode drycode commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Part 2 of 2 for #2. Stacked on #13 — based on dy/native-swift-agent, so review that first; GitHub will retarget this to main when #13 merges.

Both machines have been migrated and are dictating on the native agent, so the Lua client can go.

What this removes

  • client/init.lua (543 lines) and client/hark-config.example.lua
  • tests/test_client_record.lua and the Lua toolchain from CI
  • the hammerspoon cask from the install path

Net −2178 / +767.

The point was never the line count. Accessibility — permission to observe every keystroke — was granted to a general-purpose scriptable Lua runtime whose config was a symlink into this repo, so a git pull changed what that grant covered without re-prompting. Leaving the files behind would leave that path installable.

install-agent.sh becomes install-client.sh

So the documented entry point is unchanged for anyone following the README. Two capabilities the old installer had were not in the agent installer and had to come across first, or a two-machine install would have regressed to "copy this file by hand":

  • SSH key fetch. ./install-client.sh <ssh-host> takes the host as a bare argument, or prompts. Non-interactive callers get a failure with a message rather than a read that hangs forever.
  • The /health doctor check. Everything local can be healthy while the server is simply unreachable, and from the user's chair that is indistinguishable from a microphone fault: hold the key, speak, nothing appears.

The SSH host is still deliberately not derived from the server URL, nor the URL from the host. An alias that works for ssh <host> is not necessarily an address curl can reach, and guessing is how a config ends up looking healthy while the client silently fails. A mismatch is warned about rather than "fixed".

What is deliberately kept

Migration. ~/.hammerspoon/hark-config.lua is still read into ~/.config/hark/client.json when the latter is absent — for anyone mid-upgrade, that file is the only place their key lives. It is read, never modified.

Quitting Hammerspoon, since Ctrl+Alt+Space is a system-wide registration and exactly one process gets it.

What the installer does not do is uninstall Hammerspoon or revoke its grants. The README says to do both by hand:

brew uninstall --cask hammerspoon
rm ~/.hammerspoon/init.lua

Revoking the Accessibility and Microphone grants is the actual point of the exercise, and quitting the app does not do it. That felt like the wrong thing to do silently to someone's machine.

Also

rec's permission message now names hark. It named neither app while both clients shipped, because the row a user has to switch on is the responsible process — which depended on which client was running.

The README's permissions, troubleshooting, two-machine, hotkey and repo-layout sections are rewritten for the agent, including the two traps found during bring-up: the hardened-runtime entitlement, and why neither permission check may be measured from outside the process.

Verification

Studio and laptop both dictating on the agent, the laptop over a two-machine setup against dans-mac-studio. 138 tests, shellcheck, and the signed bundle build all green, with new coverage for the deletion, the SSH fetch, the non-interactive fallback, and /health.

Now that both machines run the native agent, the Lua client goes. The
point was never the 505 lines: Accessibility - permission to observe
every keystroke - was granted to a general-purpose scriptable Lua
runtime whose config was a symlink into this repo, so a `git pull`
changed what that grant covered without re-prompting. Leaving the files
behind would leave that path installable.

Removed: client/init.lua, client/hark-config.example.lua,
tests/test_client_record.lua, the Lua toolchain and suite from CI, and
the hammerspoon cask from the install path.

install-agent.sh becomes install-client.sh, so the documented entry
point is unchanged for anyone following the README. Two things the old
installer did had to come across first, or a laptop install would have
regressed to "copy this file by hand":

  - fetching the shared secret from the server over SSH, for a
    two-machine setup, with the host taken as a bare argument
  - the /health doctor check. Everything local can be healthy while the
    server is simply unreachable, and from the user's chair that is
    indistinguishable from a microphone fault.

The SSH host is still deliberately not derived from the server URL, nor
the URL from the host: an alias that works for `ssh <host>` is not
necessarily an address curl can reach, and guessing is how a config ends
up looking healthy while the client silently fails. A mismatch is warned
about rather than "fixed".

Migration is kept, not dropped. ~/.hammerspoon/hark-config.lua is still
read into ~/.config/hark/client.json when the latter is absent, since
for anyone mid-upgrade that file is the only place their key lives. The
installer does not uninstall Hammerspoon or revoke its grants - the
README says to do both by hand, because revoking them is the actual
point and quitting the app does not do it.

rec's permission message now names hark. It named neither while both
clients shipped, because the row to switch on is the RESPONSIBLE process
and that depended on which client you were running.

Verified: Studio and laptop both dictating on the agent, laptop over a
two-machine setup against dans-mac-studio.

Solves: GitHub issue #2, part 2 of 2
Tests: 138 pass; new coverage for the deletion, the SSH fetch, non-interactive fallback, and the /health check
@drycode

drycode commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #12, which solves the same issue more thoroughly — it replaces the server as well as the client.

Closing rather than merging, but the work is not lost. The findings from running this on hardware are ported onto #12's tree on dy/swift-rewrite-integration, and the reasoning is preserved in this branch's commits:

  • 98ac8d4 — bundle vs bare binary, Carbon vs NSEvent monitor, why the mic-status contract exists
  • dc9ae34 — the hardened-runtime entitlement, and why TCC refuses to prompt without it
  • e8f3b60 — never determine Accessibility from TCC.db (stale row, false PASS)
  • 9d5a7bd — clearing the stale grant a rebuild invalidates
  • this branch — the installer rewiring, doctor contracts and the Lua deletion, which still need doing on Swift rewrite of the dictation client (hark serve / hark agent) #12's tree

Branch kept, not deleted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant