Two computers... one-bit. A tiny E2E encrypted messenger, tucked inside your capslock key.
Hold Caps Lock on your Mac. A little light comes on on someone else’s keyboard. Let go, and it goes off.
That’s the whole idea. Caps Lock has spent quite enough time shouting. It can have a small, gentle job now.
slock lives in your menu bar and connects exactly two Macs. Send a tiny hello, invent a secret blink language, or sit at opposite desks and be a little ridiculous. If you both opt in, the same key becomes a walkie-talkie.
The firefly is Dit. Dit has one light and considerable enthusiasm.
An honest note before you download. slock is an experiment with rough edges. It uses a public MQTT test relay, is not notarized (macOS will ask you to confirm the first launch), and its encryption has no forward secrecy. Keyboard lights also vary by model. Please use it with someone you trust and keep sensitive conversations elsewhere. The security details · What’s been tested
You’ll need two Macs running macOS 13 or newer, an internet connection, and one willing accomplice.
Light signals start as soon as they arrive. Short blinks and gaps retain their timing when packets arrive in time; a hold or gap longer than one second resets playback to the earliest opportunity. Hold Option in the menu and choose Test Caps Lock Light to check whether your keyboard’s LED cooperates. Some keyboards are more willing participants than others.
While slock is active, Caps Lock stops capitalizing text. Your keyboard light follows the other person’s key; Dit’s tail shows your own outgoing activity. Pause Slock hands Caps Lock its old job back whenever you like.
Both people must agree, and either can turn it off for both. Only one person talks at a time; if you press together, the apps pick one sender consistently. Excellent practice for saying “over.” Voice is end-to-end encrypted Opus and runs independently of light timing.
Do Not Disturb and other Focus modes pause voice on your Mac, including an ongoing talk. Light signals keep working, and both people’s PTT consent stays enabled. Once Focus is off, release Caps Lock and hold it again to talk; interrupted audio is discarded. The menu shows Audio Paused while Focus is active. If macOS’s Focus status cannot be read, voice stays paused and the menu explains why.
| What you see | What it means |
|---|---|
| Yellow-green tail | You’re holding the key or transmitting. Hello, person. |
| Slowly pulsing green tail | Pairing was accepted. Ready for the first light signal in either direction. |
| Blue tail | Your paired Mac is unavailable: offline, paused, or still connecting. |
| Red tail | A required permission is missing, or a pairing/PTT request needs attention. |
| Hollow tail | No outgoing activity. An incoming signal appears on your keyboard’s light. |
With Reduce Motion enabled, the accepted-pairing tail stays steady green.
A few useful things in the menu:
| Control | What it does |
|---|---|
| Pause Slock / Resume Slock | Give Caps Lock its old job back, or return to blinking. Pause also stops voice. |
| Pairing… | Connect, name your Mac, or save nicknames. |
| Recent | Revisit a past pairing. Reconnecting sends a fresh request. |
| Unpair | Disconnect immediately and stop lights and voice. |
| Launch at Login | Start slock when you sign in. Turned on at first launch when macOS allows it; switch it off here. |
| Check for Updates… / Update slock… | Hidden when the installed version matches GitHub's latest release. Otherwise checks, downloads, verifies, and installs the latest update. |
| Quit slock | Restore the previous keyboard mapping and let Dit clock out. |
When either Mac unpairs, the other returns to Unpaired too. If the message is missed, the other Mac catches up when both Macs are online and check in.
Hold Option in the menu to reveal This Mac (your fingerprint), Test Caps Lock Light, Diagnostics…, and the installed version.
Full details, including the limits of the current relay and encryption, are in SECURITY.md. Found a vulnerability? Please use private reporting.
Releases from 0.3.0 are signed with Developer ID but are not notarized, so macOS may still block the first launch. See Apple’s instructions for opening an app blocked by macOS.
Keep slock in Applications so permissions and the login item use a stable path. The app needs Accessibility and Input Monitoring for keyboard capture. It requests each keyboard permission automatically once; the setup guide returns whenever a required grant is missing, including after an update.
Older releases used ad-hoc signatures that changed the app's identity with each build. Version 0.3.0 switches to a persistent Developer ID identity, so later consistently signed releases should retain existing privacy approvals. This first switch may require one final approval on each Mac. The updater's separate download signature continues to verify update packages.
The red Permissions Required item appears only while the current mode lacks access. Push-to-talk adds Microphone after you choose to enable it; receiving an invitation alone never requests microphone access. Use lights only turns PTT off and removes that requirement. Physical F18 is also consumed while capture is active.
Sending a pairing request shares your nickname with its recipient. The recipient shares theirs after accepting. A nickname you give someone else stays on your Mac and is used if they haven’t supplied their own. Save Nicknames edits names without starting another pairing request. Names are for convenience, not identity: always compare the full pairing code or the This Mac fingerprint.
Recent lists accepted pairings, newest first. It uses the other Mac’s name, then your local nickname, then the last six characters of its code. Unpairing keeps this history but clears active voice consent. Switching to another Mac asks before disconnecting your current peer.
slock checks GitHub for updates at launch and hourly. Check for Updates… disappears when GitHub confirms the installed version is current, and Update slock… appears when a newer release is known. Either action checks the latest release again, downloads and verifies its signed update, then replaces slock and relaunches it in the same location. No extra updater, administrator access, or Keychain permission is required. Keep slock in a writable Applications folder. Pairings and preferences stay. Moving from an older ad-hoc release to 0.3.0 may require one final keyboard permission approval; later releases use the same Developer ID identity.
Versions 0.2.6–0.2.8 only open a release page. Download the latest ZIP once, quit slock, replace the app in Applications, and reopen it to receive the restored updater. Upgrade both Macs together: version 0.2 uses protocol 2 and cannot communicate with version 0.1.
This is still a prototype. Bug reports are welcome, especially from keyboards that have decided to express themselves in unexpected ways.
wss://test.mosquitto.org:8081/mqtt. Availability is not guaranteed; other
clients can send spam or interrupt delivery. A production service would need an
operated broker with per-user authentication and abuse controls.Curious how the blinking sausage is made? See the architecture.
Start with Option → Diagnostics… in slock’s menu. Pairing tells you the Macs can communicate; each still needs working keyboard capture and LED access.
| What’s happening | What to try |
|---|---|
| Caps Lock still capitalizes or shows a blue cursor indicator | Check Accessibility trusted: true and Caps capture active: true in Diagnostics. Look for another Caps Lock utility or an existing Modifier Keys reassignment. |
| Permissions look enabled, but nothing happens | Open Permissions Required if shown. Remove stale Accessibility/Input Monitoring entries, add the current app from Applications, and reopen if macOS asks. |
| The light test fails | Check LED mode, HID listening access, and LED error. Grant Input Monitoring if requested. The keyboard may not support independent LED control. |
| The other Mac stays offline | Check both app versions, internet connections, and access to test.mosquitto.org on TCP port 8081. The test broker may also be having a day. |
| Voice is silent | Both menus should show PTT Enabled. Check Microphone permission and system input/output devices, then the first audio error in Diagnostics. |
| Launch at Login needs approval | Allow slock in System Settings → General → Login Items. |
Local Caps presses should increase when you hold the key. If it stays at zero,
check permissions and the keyboard event mask (required: 7168). Key messages
queued on the sender and Key messages received on the recipient help
separate capture trouble from delivery trouble. Queued does not mean delivered.
For a stale Input Monitoring entry that won’t budge, you can reset only slock’s record, then reopen the installed app and follow the guide:
tccutil reset ListenEvent com.jonaraphael.CapsLink
The LED driver retries after keyboard access is granted. If the light changes independently of your peer, check for another Caps Lock utility using the same Caps→F18 mapping. Network stalls or a busy Mac can also stretch a blink or gap; the next hold or gap longer than one second lets playback shed accumulated delay.
For a useful bug report, include both Mac models, macOS and app versions, keyboard types, and whether capture, the light test, and voice each work. Copy Diagnostics helps, too—please review it before sharing, since it contains device fingerprints and activity counters. Thank you for helping a very small firefly find its feet.
Install Xcode or the Xcode Command Line Tools, then run:
git clone https://github.com/jonaraphael/slock.git
cd slock
./build.command
The build renders Dit’s vector artwork into an app
icon and produces a universal app plus a distributable ZIP in dist/. Signing
defaults to ad-hoc. There is no Xcode project and no third-party dependency;
the default build needs no internet access.
CAPSLINK_ARCHS=arm64 ./build.command # one architecture only (or x86_64)
./test.command # regression, security, and timing suites
To keep a stable macOS identity across builds, save a code-signing certificate
fingerprint from security find-identity -v -p codesigning in the Git-ignored
.release-signing/codesign-identity file, or set SLOCK_CODESIGN_IDENTITY for
one build. Use an Apple Development identity
for local development and a Developer ID Application identity for releases.
Certificate signing requests an online secure timestamp and fails if signing
fails; it never retries with an ad-hoc signature. Publication requires a
Developer ID Application signature. See
release signing
for setup and migration details.
The tests use temporary identities, fake keyboard commands, and synthetic audio. They never capture your keyboard, use your microphone, or contact the relay. Maintainers can find the tagging and publishing steps in docs/RELEASING.md.
| File | Purpose |
|---|---|
| slock.swift | Application, keyboard capture, pairing, relay, and audio. |
| UpdateInstaller.swift | Signed update verification, replacement, and relaunch. |
| build.command | Builds, packages, and signs the app. |
| test.command | Runs the regression suite and friends. |
| docs/releases/ | Changelog and upgrade notes for each release. |
| ARCHITECTURE.md | Design, protocol, state machines, and manual test plan. |
| VALIDATION.md | Verified results and remaining hardware checks. |
| SECURITY.md | Privacy, security limits, and private vulnerability reporting. |
| SECURITY_REVIEW.md | Security reviews, fixes, and verification. |
slock was previously called CapsLink. Internal preference keys, the identity storage directory, bundle identifier, and wire identifiers keep the old name so existing settings and pairings keep working.
Issues and pull requests are welcome. Keep changes small, add a regression test
where one fits, and run ./test.command before opening a PR. For anything
security-related, please use private reporting first.
MIT. See third-party notices for attribution. Dit is happy to be forked, as long as the light stays gentle.
30 commits
Swift
97.4%
Shell
2.6%
Two computers... one-bit. A tiny E2E encrypted messenger, tucked inside your capslock key.
Hold Caps Lock on your Mac. A little light comes on on someone else’s keyboard. Let go, and it goes off.
That’s the whole idea. Caps Lock has spent quite enough time shouting. It can have a small, gentle job now.
slock lives in your menu bar and connects exactly two Macs. Send a tiny hello, invent a secret blink language, or sit at opposite desks and be a little ridiculous. If you both opt in, the same key becomes a walkie-talkie.
The firefly is Dit. Dit has one light and considerable enthusiasm.
An honest note before you download. slock is an experiment with rough edges. It uses a public MQTT test relay, is not notarized (macOS will ask you to confirm the first launch), and its encryption has no forward secrecy. Keyboard lights also vary by model. Please use it with someone you trust and keep sensitive conversations elsewhere. The security details · What’s been tested
You’ll need two Macs running macOS 13 or newer, an internet connection, and one willing accomplice.
Light signals start as soon as they arrive. Short blinks and gaps retain their timing when packets arrive in time; a hold or gap longer than one second resets playback to the earliest opportunity. Hold Option in the menu and choose Test Caps Lock Light to check whether your keyboard’s LED cooperates. Some keyboards are more willing participants than others.
While slock is active, Caps Lock stops capitalizing text. Your keyboard light follows the other person’s key; Dit’s tail shows your own outgoing activity. Pause Slock hands Caps Lock its old job back whenever you like.
Both people must agree, and either can turn it off for both. Only one person talks at a time; if you press together, the apps pick one sender consistently. Excellent practice for saying “over.” Voice is end-to-end encrypted Opus and runs independently of light timing.
Do Not Disturb and other Focus modes pause voice on your Mac, including an ongoing talk. Light signals keep working, and both people’s PTT consent stays enabled. Once Focus is off, release Caps Lock and hold it again to talk; interrupted audio is discarded. The menu shows Audio Paused while Focus is active. If macOS’s Focus status cannot be read, voice stays paused and the menu explains why.
| What you see | What it means |
|---|---|
| Yellow-green tail | You’re holding the key or transmitting. Hello, person. |
| Slowly pulsing green tail | Pairing was accepted. Ready for the first light signal in either direction. |
| Blue tail | Your paired Mac is unavailable: offline, paused, or still connecting. |
| Red tail | A required permission is missing, or a pairing/PTT request needs attention. |
| Hollow tail | No outgoing activity. An incoming signal appears on your keyboard’s light. |
With Reduce Motion enabled, the accepted-pairing tail stays steady green.
A few useful things in the menu:
| Control | What it does |
|---|---|
| Pause Slock / Resume Slock | Give Caps Lock its old job back, or return to blinking. Pause also stops voice. |
| Pairing… | Connect, name your Mac, or save nicknames. |
| Recent | Revisit a past pairing. Reconnecting sends a fresh request. |
| Unpair | Disconnect immediately and stop lights and voice. |
| Launch at Login | Start slock when you sign in. Turned on at first launch when macOS allows it; switch it off here. |
| Check for Updates… / Update slock… | Hidden when the installed version matches GitHub's latest release. Otherwise checks, downloads, verifies, and installs the latest update. |
| Quit slock | Restore the previous keyboard mapping and let Dit clock out. |
When either Mac unpairs, the other returns to Unpaired too. If the message is missed, the other Mac catches up when both Macs are online and check in.
Hold Option in the menu to reveal This Mac (your fingerprint), Test Caps Lock Light, Diagnostics…, and the installed version.
Full details, including the limits of the current relay and encryption, are in SECURITY.md. Found a vulnerability? Please use private reporting.
Releases from 0.3.0 are signed with Developer ID but are not notarized, so macOS may still block the first launch. See Apple’s instructions for opening an app blocked by macOS.
Keep slock in Applications so permissions and the login item use a stable path. The app needs Accessibility and Input Monitoring for keyboard capture. It requests each keyboard permission automatically once; the setup guide returns whenever a required grant is missing, including after an update.
Older releases used ad-hoc signatures that changed the app's identity with each build. Version 0.3.0 switches to a persistent Developer ID identity, so later consistently signed releases should retain existing privacy approvals. This first switch may require one final approval on each Mac. The updater's separate download signature continues to verify update packages.
The red Permissions Required item appears only while the current mode lacks access. Push-to-talk adds Microphone after you choose to enable it; receiving an invitation alone never requests microphone access. Use lights only turns PTT off and removes that requirement. Physical F18 is also consumed while capture is active.
Sending a pairing request shares your nickname with its recipient. The recipient shares theirs after accepting. A nickname you give someone else stays on your Mac and is used if they haven’t supplied their own. Save Nicknames edits names without starting another pairing request. Names are for convenience, not identity: always compare the full pairing code or the This Mac fingerprint.
Recent lists accepted pairings, newest first. It uses the other Mac’s name, then your local nickname, then the last six characters of its code. Unpairing keeps this history but clears active voice consent. Switching to another Mac asks before disconnecting your current peer.
slock checks GitHub for updates at launch and hourly. Check for Updates… disappears when GitHub confirms the installed version is current, and Update slock… appears when a newer release is known. Either action checks the latest release again, downloads and verifies its signed update, then replaces slock and relaunches it in the same location. No extra updater, administrator access, or Keychain permission is required. Keep slock in a writable Applications folder. Pairings and preferences stay. Moving from an older ad-hoc release to 0.3.0 may require one final keyboard permission approval; later releases use the same Developer ID identity.
Versions 0.2.6–0.2.8 only open a release page. Download the latest ZIP once, quit slock, replace the app in Applications, and reopen it to receive the restored updater. Upgrade both Macs together: version 0.2 uses protocol 2 and cannot communicate with version 0.1.
This is still a prototype. Bug reports are welcome, especially from keyboards that have decided to express themselves in unexpected ways.
wss://test.mosquitto.org:8081/mqtt. Availability is not guaranteed; other
clients can send spam or interrupt delivery. A production service would need an
operated broker with per-user authentication and abuse controls.Curious how the blinking sausage is made? See the architecture.
Start with Option → Diagnostics… in slock’s menu. Pairing tells you the Macs can communicate; each still needs working keyboard capture and LED access.
| What’s happening | What to try |
|---|---|
| Caps Lock still capitalizes or shows a blue cursor indicator | Check Accessibility trusted: true and Caps capture active: true in Diagnostics. Look for another Caps Lock utility or an existing Modifier Keys reassignment. |
| Permissions look enabled, but nothing happens | Open Permissions Required if shown. Remove stale Accessibility/Input Monitoring entries, add the current app from Applications, and reopen if macOS asks. |
| The light test fails | Check LED mode, HID listening access, and LED error. Grant Input Monitoring if requested. The keyboard may not support independent LED control. |
| The other Mac stays offline | Check both app versions, internet connections, and access to test.mosquitto.org on TCP port 8081. The test broker may also be having a day. |
| Voice is silent | Both menus should show PTT Enabled. Check Microphone permission and system input/output devices, then the first audio error in Diagnostics. |
| Launch at Login needs approval | Allow slock in System Settings → General → Login Items. |
Local Caps presses should increase when you hold the key. If it stays at zero,
check permissions and the keyboard event mask (required: 7168). Key messages
queued on the sender and Key messages received on the recipient help
separate capture trouble from delivery trouble. Queued does not mean delivered.
For a stale Input Monitoring entry that won’t budge, you can reset only slock’s record, then reopen the installed app and follow the guide:
tccutil reset ListenEvent com.jonaraphael.CapsLink
The LED driver retries after keyboard access is granted. If the light changes independently of your peer, check for another Caps Lock utility using the same Caps→F18 mapping. Network stalls or a busy Mac can also stretch a blink or gap; the next hold or gap longer than one second lets playback shed accumulated delay.
For a useful bug report, include both Mac models, macOS and app versions, keyboard types, and whether capture, the light test, and voice each work. Copy Diagnostics helps, too—please review it before sharing, since it contains device fingerprints and activity counters. Thank you for helping a very small firefly find its feet.
Install Xcode or the Xcode Command Line Tools, then run:
git clone https://github.com/jonaraphael/slock.git
cd slock
./build.command
The build renders Dit’s vector artwork into an app
icon and produces a universal app plus a distributable ZIP in dist/. Signing
defaults to ad-hoc. There is no Xcode project and no third-party dependency;
the default build needs no internet access.
CAPSLINK_ARCHS=arm64 ./build.command # one architecture only (or x86_64)
./test.command # regression, security, and timing suites
To keep a stable macOS identity across builds, save a code-signing certificate
fingerprint from security find-identity -v -p codesigning in the Git-ignored
.release-signing/codesign-identity file, or set SLOCK_CODESIGN_IDENTITY for
one build. Use an Apple Development identity
for local development and a Developer ID Application identity for releases.
Certificate signing requests an online secure timestamp and fails if signing
fails; it never retries with an ad-hoc signature. Publication requires a
Developer ID Application signature. See
release signing
for setup and migration details.
The tests use temporary identities, fake keyboard commands, and synthetic audio. They never capture your keyboard, use your microphone, or contact the relay. Maintainers can find the tagging and publishing steps in docs/RELEASING.md.
| File | Purpose |
|---|---|
| slock.swift | Application, keyboard capture, pairing, relay, and audio. |
| UpdateInstaller.swift | Signed update verification, replacement, and relaunch. |
| build.command | Builds, packages, and signs the app. |
| test.command | Runs the regression suite and friends. |
| docs/releases/ | Changelog and upgrade notes for each release. |
| ARCHITECTURE.md | Design, protocol, state machines, and manual test plan. |
| VALIDATION.md | Verified results and remaining hardware checks. |
| SECURITY.md | Privacy, security limits, and private vulnerability reporting. |
| SECURITY_REVIEW.md | Security reviews, fixes, and verification. |
slock was previously called CapsLink. Internal preference keys, the identity storage directory, bundle identifier, and wire identifiers keep the old name so existing settings and pairings keep working.
Issues and pull requests are welcome. Keep changes small, add a regression test
where one fits, and run ./test.command before opening a PR. For anything
security-related, please use private reporting first.
MIT. See third-party notices for attribution. Dit is happy to be forked, as long as the light stays gentle.
30 commits
Swift
97.4%
Shell
2.6%