AGENTS.md
Guidelines for AI agents working in this repository.
Project Overview
spank is a macOS CLI tool that detects physical hits/slaps on Apple Silicon MacBooks via the accelerometer and plays audio responses. Single-file Go application with embedded MP3 assets.
- Platform: macOS on Apple Silicon (M2+) only
- Runtime requirement:
sudo(for IOKit HID accelerometer access) - Architecture: Single
main.gofile with embedded audio assets
Commands
Build & Run
# Build
go build -o spank .
# Run (requires sudo)
sudo ./spank
sudo ./spank --sexy # escalating responses mode
sudo ./spank --halo # Halo death sounds mode
sudo ./spank --custom /path/to/mp3s # custom audio directory
Install
go install github.com/taigrr/spank@latest
Release
Releases are automated via GitHub Actions + GoReleaser Pro when a v* tag is pushed:
git tag v1.0.0
git push origin v1.0.0
Code Organization
spank/
├── main.go # All application code (single file)
├── audio/
│ ├── pain/ # Default "ow!" responses (10 MP3s)
│ ├── sexy/ # Escalating responses (60 MP3s)
│ └── halo/ # Halo death sounds (9 MP3s)
├── go.mod
├── .goreleaser.yaml # Release configuration
└── .github/workflows/ # CI/CD
Key Dependencies
| Package | Purpose |
|---|---|
github.com/taigrr/apple-silicon-accelerometer |
Reads accelerometer via IOKit HID |
github.com/gopxl/beep/v2 |
Audio playback (MP3 decoding, speaker output) |
github.com/spf13/cobra |
CLI framework |
github.com/charmbracelet/fang |
CLI config/execution wrapper |
Code Patterns
Embedded Assets
Audio files are embedded at compile time using //go:embed:
//go:embed audio/pain/*.mp3
var painAudio embed.FS
Play Modes
Two playback strategies in playMode:
modeRandom: Random file selection (pain, halo, custom modes)modeEscalation: Intensity increases with slap frequency (sexy mode)
Slap Detection Flow
sensor.Run()reads accelerometer in background goroutine- Data shared via
shm.RingBuffer(POSIX shared memory) detector.New()processes samples with vibration detection algorithms- Events trigger audio playback with 750ms cooldown
Concurrency
speakerMu sync.Mutexprotects speaker initializationslapTracker.mu sync.Mutexprotects slap scoring state- Audio playback runs in goroutines (
go playAudio(...))
Constants
Key tuning parameters in main.go:
| Constant | Value | Purpose |
|---|---|---|
decayHalfLife |
30s | How fast escalation fades |
slapCooldown |
750ms | Minimum time between audio plays |
sensorPollInterval |
10ms | Accelerometer polling rate |
maxSampleBatch |
200 | Max samples processed per tick |
Gotchas
-
Root required: The app must run with
sudofor IOKit HID access. Therun()function checksos.Geteuid() != 0. -
Apple Silicon only: Only builds for
darwin/arm64. Intel Macs are not supported. -
Private dependency:
github.com/taigrr/apple-silicon-accelerometerrequiresGOPRIVATEsetting and GitHub PAT for CI. -
Single file: All code is in
main.go. When adding features, follow the existing pattern of types and functions in the same file. -
Mutually exclusive modes:
--sexy,--halo, and--customflags cannot be combined. -
CGO disabled: Builds use
CGO_ENABLED=0despite targeting macOS.
Adding Audio
To add a new sound pack:
- Create directory under
audio/ - Add MP3 files (numbered for escalation mode, any names for random)
- Add
//go:embed audio/newpack/*.mp3variable - Add flag and case in
run()switch statement - Create
soundPackwith appropriateplayMode
Version
Version is injected via ldflags at build time:
var version = "dev"
GoReleaser sets -X main.version={{.Version}} during release builds.