# Amphetamine: A Memory and Contention Tool for Apple Silicon
Amphetamine frees memory and reduces CPU contention on macOS, so your editor gets
the machine's attention.
It closes only the apps you have named, clears only caches that belong to
installed applications, and refuses to make any change it cannot undo.
## Contents
- [Scope](#scope)
- [Installation](#installation)
- [Usage](#usage)
- [Configuration](#configuration)
- [Permissions](#permissions)
- [Safety Model](#safety-model)
- [Tests](#tests)
- [The Other Amphetamine](#the-other-amphetamine)
- [Bug Reports](#bug-reports)
## Scope
Amphetamine can free memory and reduce contention; it cannot make your cores run
faster. Being straight about that matters more than the pitch.
### Clock Speed
There is no overclocking. Apple Silicon exposes no user-space clock control — no
`cpufreq`, no multiplier, nothing, SIP enabled or not.
The only performance selector is the Energy Mode in System Settings, and `amph
status` will tell you if you are not already on High Power. If nothing is
thermally throttling you, there is no clock speed to win back, and any tool
claiming otherwise is lying.
### Available Levers
What is real is contention and memory pressure.
- **Closing apps** — a quit request, as if you pressed Cmd-Q, frees RAM and,
critically, drains swap.
- **Clearing caches** — age-gated file deletion frees disk and reduces
cache-warming I/O.
- **Deprioritising** — `nice` gives rival processes a weaker claim on the CPU.
- **Idle-sleep hold** — an IOKit power assertion keeps long builds from being
interrupted.
### Swap
Swap is usually the real culprit. Free RAM is a poor health signal; swap is a
better one.
Pages pushed to swap during past pressure stay there, and every touch of one is
a disk read. Swap only drains as the processes owning those pages exit — no
amount of free RAM, and no `purge`, brings it back.
That is why closing apps helps even on a 128 GB machine.
### Efficiency Cores
`nice` is not efficiency-core parking. `PRIO_DARWIN_PROCESS`, the mechanism
behind `taskpolicy -b`, silently does nothing when aimed at another process on
current macOS: it reports success and changes no state.
Amphetamine uses `nice`, which measurably works, and does not claim to do more.
## Installation
Amphetamine requires macOS on Apple Silicon and a recent stable Rust. The
package is named `amphetamine` and the command it installs is `amph`.
Install it from [crates.io](https://crates.io/crates/amphetamine).
```bash
cargo install amphetamine
```
Build from source instead if you want to run the tests or track `main`.
```bash
cargo build --release
cp target/release/amph /usr/local/bin/
```
## Usage
Every command is listed here, and `amph` with no argument is the read-only
status view.
```bash
amph # same as `amph status`
amph status # read-only: memory, swap, thermal, heaviest apps
amph pick # choose what to close, interactively
amph boost --dry-run # exactly what would be closed and cleared
amph boost # do it
amph focus --for 90 # a 90-minute focus session
amph restore # undo any leftover deprioritisation
```
The first run writes `~/.config/amphetamine/config.toml` with empty lists and
changes nothing. That is the design, not an oversight: Amphetamine closes an app
only after you name it.
## Configuration
You never have to open the config by hand.
```bash
amph pick # tick apps from what's running, ranked by memory
amph add Slack Spotify # or name them directly
amph add -d Dropbox # -d: deprioritise during focus instead
amph add -p Notion # -p: protect, never close
amph rm Spotify # remove from a list
amph config show # every setting, annotated with what's running
```
`amph pick` opens a checklist of running apps pre-ticked to match your current
config, so it reads as an editor rather than a one-way import. Apps that are
protected are never offered, and entries for apps that aren't running are left
untouched rather than silently dropped.
Names match a bundle ID, an app name, or the last component of a bundle ID,
case-insensitively. They are stored using the app's own spelling, so `amph add
slack` records `Slack`.
Adding something the built-in denylist protects is refused with the reason
rather than accepted as a line that could never fire.
```console
$ amph add Cursor Docker
close list
! Cursor not added — protected (Cursor) — it would never be touched
! Docker not added — protected (Docker) — it would never be touched
```
Edits are made in place with `toml_edit`, so the config's explanatory comments
survive. Each result is parsed back and validated before it replaces the file,
and the swap is atomic, so a failed edit leaves the previous config whole.
For hand-editing, `amph config edit` opens `$EDITOR` and `amph config raw`
prints the file as-is.
A filled-in config is short.
```toml
[apps]
close = ["Slack", "Spotify", "Messages"]
[caches]
min_age_days = 7
[focus]
demote = ["Spotify", "Dropbox"]
nice_level = 10
```
## Permissions
Closing apps, clearing your caches, and reading every statistic here need no
privileges at all, and there is no daemon.
Focus mode needs exactly one grant, because of a macOS asymmetry: any user may
raise a process's nice value, but only root may lower it again. Without help,
deprioritising an app would be a one-way door — so Amphetamine refuses to demote
anything until it can prove it can undo it.
`amph setup` asks for your password once and installs a single sudoers rule.
```
you ALL=(root) NOPASSWD: /usr/bin/renice 0 -p [0-9]*
```
The `0` is literal. The rule can only ever return a process to normal priority:
it cannot deprioritise anything, cannot run any other command, and cannot open a
shell.
It is validated with `visudo -c` before installation, because a malformed file
in `/etc/sudoers.d` can lock you out of `sudo` entirely.
Inspect it with `amph setup --print`, remove it with `amph setup --remove`.
## Safety Model
Amphetamine is built so that the dangerous operations are the ones it refuses to
perform.
### The Denylist
A hard-coded denylist that config cannot override covers three groups: the OS
and your session (WindowServer, Finder, Dock, loginwindow), your work surface
(Cursor, every common terminal), and everything holding mutable state (all VMs,
Docker, Parallels, UTM). All of them are refused even if you name them
explicitly.
Killing a VM abruptly can corrupt its disk image, so Amphetamine reports those
and stops.
### Quit Requests
Apps are asked, never killed. Closing goes through
`NSRunningApplication::terminate`, the same quit request as Cmd-Q, so the app
runs its normal shutdown and is free to put up an unsaved-work sheet.
If it does not exit within the timeout it is simply left running — a stalled app
is usually one asking you to save something.
`SIGKILL` is never sent; `--force` exists and is never implied.
### Cache Eligibility
Caches must prove they are caches. `~/Library/Caches` is not one kind of thing:
alongside app caches it holds compiler and package-manager state that is
ruinously expensive to rebuild.
On the machine this was developed against, `go-build` alone was 91 GB and a
dead-code analyser's cache was 39 GB.
So the rule is a positive test rather than a denylist that could never keep
pace: a bucket is eligible only if an application with that bundle identifier is
actually installed, per LaunchServices. Everything unrecognised is left alone,
which makes tools you install next year safe by default.
Four more brakes apply on top of that test.
- **Live state** — buckets holding it (CloudKit, container manager) are
permanently excluded.
- **Developer tools** — IDEs and browsers are skipped by default.
- **Running apps** — a cache whose app is currently running is never touched,
including its `.ShipIt` updater.
- **Age** — only files untouched, by both modification and access time, for
`min_age_days` are eligible.
### Deletion Scope
Deletion is narrow by construction. Only `~/Library/Caches` and
`~/Library/Logs`, never configurable.
Symlinks are never followed, and a symlinked bucket is skipped whole. Every path
is re-canonicalised and re-vetted against its root immediately before removal,
so nothing can escape through a link swapped in mid-run.
There is no recursive delete anywhere: files are removed individually and
directories only via `remove_dir`, which fails unless already empty.
### Reversibility
Nothing is irreversible. Focus mode verifies its restore path before touching a
process, only demotes processes already at nice 0 (so restoring to 0 is exact
rather than a guess), and restores on exit.
If a session is killed outright, `amph restore` is the safety net.
## Tests
The suite asserts refusals more than successes.
Run it against your own machine.
```bash
cargo test
```
53 tests, run against the live machine rather than mocks.
The ones that matter check that the built-in denylist beats an explicit close
request, that a symlink cannot lead a delete outside its root, that build-tool
caches are never touched, and that nothing is demoted without a proven way back.
One is a canary: lowering a nice value without privileges still fails. If it
ever passes, the sudoers grant is no longer needed.
## The Other Amphetamine
If you came here for the macOS menu-bar utility that keeps your Mac awake, that
is [a different and unrelated
program](https://apps.apple.com/app/amphetamine/id937984704).
This tool holds off idle sleep only for the length of a focus session, and it is
not a keep-awake utility. The two share a name and nothing else.
There are two other reasons to leave. No tool can give you overclocking on
Apple Silicon, and Amphetamine is built on Mach, libproc, AppKit and IOKit, so
it refuses to compile anywhere but macOS.
## Bug Reports
Bugs and feature requests belong in [the issue
tracker](https://github.com/GriffinCanCode/amphetamine/issues).
Security problems do not. Amphetamine installs a sudoers rule and deletes files,
so a flaw in either could matter to people other than you; report those through
[a private security
advisory](https://github.com/GriffinCanCode/amphetamine/security/advisories/new)
instead of a public issue.