macOS · open source · MIT · v0.3.0

What just happened on my Mac?
And what mattered.

A terminal flashed. An app opened by itself. macOS said “Background Items Added”. The Mac restarted overnight. The answers are already on your Mac, buried in 14,000 log lines a minute. lately knows which few hundred matter and turns them into a short timeline. One command. No root, no daemon, no AI.

brew install matthew-eucaristo/tap/lately

Then run lately. It only reads. Other ways to install →

lately --replay demo/sample Try it: ⏎ card · A ancestry · f follow · R restart

The real output of lately --replay demo/sample, generated when this page was built, with times moved to your clock. Generic sample data, not your Mac, and nothing here reads your Mac.

42YAML rules, MITRE-tagged
5Sigma-style levels
8narrow unified-log lenses
0daemons, root or AI
0network connections

Classified, not dumped

Console shows everything. lately shows what matters.

Eight narrow log lenses, crash reports, boot and power records, install receipts and the folders software uses to start itself. 42 rules put every event at one of five levels, group bursts into one row (×3), hide Apple's own noise and stop marking things NEW once you have seen them.

  • ✖ CRIT act now
  • ▲ HIGH look at even one
  • ● MED look if unexpected
  • ○ LOW context
  • · INFO hidden by default

Glyphs and words always sit next to colour, and NO_COLOR is honoured.

The questions it answers

For the moments your Mac does something on its own.

“A terminal window just flashed.”

With sudo lately capture, a shell that an osascript, launchd job or cron job started, and that lived under 2 seconds, becomes an EXEC row. A shows the chain that started it. A parent that exited before capture is shown as chain broken, never guessed.

launchd (1)   Apple
└─ com.foovpn.helper (4300)   Dev ID ABCDE12345
   └─ osascript (4321)   Apple
      └─ zsh (4322)  zsh -c curl -fsSL https://… | sh  ◀

“Background Items Added.”

Every new launch agent, daemon, login item, system extension, cron entry, SSH key or shell-startup change becomes a row, with its signer and the install that wrote it. Persistence rules carry MITRE ATT&CK IDs.

▲ HIGH  PERSIST  Launch daemon added: com.foovpn.helper
WHY  Written during the Foo VPN install (Installer)
DO   Expected? press a. Not expected? launchctl bootout …

“Why did my Mac restart overnight?”

Apple silicon logs no shutdown cause code. lately combines wtmp, the panic breadcrumb, DumpPanic's check, shutdown-stall reports, the watchdog record, recent updates and the last power line into one verdict.

VERDICT  ● Hung shutdown
  ✓ watchdog  a watchdog reset (wdog)
  ✓ stall     1 shutdown_stall report

“It keeps crashing when I do this.”

Press f and reproduce it. One log stream per lens, plus crash reports, installs and launch items rechecked every 5 s. New rows land on top in green; a repeat bumps its ×N in place.

since 17:01 ● live 8s
▲ new HIGH at 17:16:35: shop-app crashed ×4

“What did I just allow?”

Screen Recording, camera and microphone answers, Gatekeeper checks and XProtect detections. Rows read from log text Apple does not document are marked ≈approx.

▲ HIGH  PERMIT  com.meetapp.desktop allowed Screen Recording
        NEW ≈approx

“Did something happen earlier?”

t reaches one step further back (5m … 7d) and reads only the span it adds; T comes back without rereading. The header says how far back the log really reaches.

window 5m 15m 30m 1h 2h 3h 6h 12h 1d 2d 3d 7d

An event card for every row

Not just what happened. Who, why, and what to do.

Press ⏎ on any row. Every card has the same sections, then the subject's own activity over the window and its related findings: the same process, its parent or children, the launch item that runs it, the install that delivered it, the same developer. Cards suggest commands; they never run them.

⏎ on a row
▲ HIGH · PERSIST · Launch daemon added: com.foovpn.helper
WHAT     A program will now start as root at every boot:
         /Library/PrivilegedHelperTools/com.foovpn.helper
WHO      com.foovpn.helper · Developer ID ABCDE12345
         Developer ID Application: Foo VPN Inc (ABCDE12345)
         first seen on this Mac
WHY      Written during the Foo VPN install (Installer, 17:02:52)
MATTERS  Launch daemons run as root without anyone logged in.
         They are how installers add services, and how
         malware stays on a Mac.
         MITRE ATT&CK T1543.004
DO       Expected? press a to mark it known. Not expected?
         sudo launchctl bootout system/com.foovpn.helper
RAW      /Library/LaunchDaemons/com.foovpn.helper.plist
SOURCE   persist · rule persist.launch_daemon v1 · confidence ✓
── ACTIVITY ──────────────────────────────────────────────
         17:01 ·····█································ 17:16
── RELATED · 1 install · 2 same developer ────────────────
▌  -3s  install         · INFO  Installed Foo VPN 3.2
    +3s  same developer  ✖ CRIT  System extension added
  1. What happened, in plain words, with the path.
  2. Who: the signer, the team, and whether this Mac has seen it before.
  3. Why: the evidence behind it, such as the install that wrote this launch daemon.
  4. Matters: why this kind of event deserves a look, with its MITRE ATT&CK ID.
  5. Do: the exact next step. Mark it known with a, or remove it yourself.
  6. Raw: the file, or the exact /usr/bin/log show command to check it yourself.

lately why-restart

One verdict. With the evidence.

Apple silicon Macs log no shutdown cause code, so lately weighs everything that is left and says exactly one of:

  • ● clean restart
  • ● update restart
  • ● kernel panic
  • ● hung shutdown
  • ● unexpected, with the likely cause

When the verdict is inferred, it says so. Press R in the demo above to see this one live.

lately why-restart
Why did my Mac restart?   booted 03:12 today (Apple silicon)
VERDICT  ● Hung shutdown
  A shutdown or restart got stuck and macOS wrote a
  shutdown-stall report. It never finished: the
  hardware watchdog reset the Mac.
────────────────────────────────────────────────────
  ✓ wtmp        no shutdown record   → not clean
  · panic       DumpPanic found no panic log
  ✓ watchdog    reset (wdog)   → stopped responding
  ✓ stall       1 shutdown_stall report
  · update      no macOS update around it
  ✓ power       the Mac was awake   → AC, 64%
  ✓ last words  03:12:19 (WindowServer)
────────────────────────────────────────────────────
  No shutdown cause code: inferred.

Honest about blind spots

A tool that silently shows less is worse than one that admits it.

Every limit is named on screen, every run. ? lists all of them.

The log is short

macOS keeps a few days at most, and log stats overstates it. lately reads the oldest file in the log store and prints how far back it really reaches.

macOS redacts

Many log fields read <private>. lately counts them instead of pretending they are not there.

Short-lived commands need capture

Without sudo lately capture you see that Terminal launched, not the 200 ms shell inside it.

Restart causes are inferred

No shutdown cause code on Apple silicon, so the verdict says “inferred”.

Some rows are approximate

Permission and Gatekeeper rows come from log text Apple does not document, and they carry ≈.

No network history exists

Recording which app talked to which host needs a firewall extension such as LuLu. lately net shows live connections only.

ⓘ The unified log reaches back to Oct 25 13:02 (2.1 days); older log events are gone.
ⓘ 12 field(s) were redacted by macOS as <private>.
ⓘ Commands and parents of short-lived processes need capture: sudo lately capture
ⓘ Restart causes are inferred: Apple silicon Macs log no shutdown cause code.

What it reads

Evidence your Mac already keeps, read by Apple's own tools.

Everything below is readable by a normal user. lately runs /usr/bin/log, pmset, last, codesign, systemextensionsctl, lsof, nettop and ps, or reads files directly. No frameworks, no cgo.

Unified log, 8 lenses

RunningBoard launches, TCC decisions, Gatekeeper, XProtect Remediator, Background Task Management, DumpPanic, jetsam and shutdown cause, log erase.

Diagnostic reports

Crashes, faults, hangs, jetsam, resource reports, shutdown stalls and panics, from one JSON line per .ips.

Boot records

kern.boottime, last reboot, last shutdown and the DumpPanic breadcrumb.

Power log

Sleep, wake, dark wake and failures, and whether the Mac was on AC before a restart.

Installs

InstallHistory, install.log and Homebrew logs, so a new background item points to the install that wrote it.

Persistence

Launch agents and daemons with their signatures, crontab, shell startup files, authorized_keys and system extensions.

Live network

lsof and nettop: what your processes are connected to right now.

Elevated: sudo lately capture

Apple's eslogger as a child process for exec, fork, exit, background items, TCC, XProtect and more. In memory only, and it stops when you quit.

Privacy & footprint

Safe to run. Safe to paste.

  • Read-only. lately never changes the system, installs or schedules nothing, and never asks for your password. Cards print commands; they never run them.
  • No daemon. It runs only while you have it open. Quitting stops everything it started, log stream children included.
  • No network, no AI. It sends nothing anywhere.
  • One small file. The baseline holds salted SHA-256 hashes and dates: no names, paths or URLs. lately forget deletes it.
  • Light. Idle: 0.15% CPU and 14 MB. Following: 0.30%, plus eight log stream children at 0.1–0.4% together. Child tools run at nice 10.
--json · --md · export
read/Users/ana/… on anas-mbp · C02XK1ZZJGH5 · 10.0.4.21
↓ redacted by default
out~/… on HOST-1 · SERIAL · IP-1

Home folder, user and host names, serial number, UUIDs, IP and e-mail addresses and URL paths become stable placeholders, so an export can go straight into an issue or a chat.

Use

A TUI when you look. A script when you don't.

Plain text when piped, redacted JSON with a stable contract, and exit codes that say what was found.

Exit codes
0nothing at or above the floor
1Medium or High rows
2a Critical row
3the requested tier needs privileges
4usage error, or every source failed
# TUI: last 15 minutes, Medium and above
lately
# any window: 5m, 1h, 24h, 2d, boot…
lately --since 1h
# plain text, redacted JSON, redacted Markdown
lately --list
lately --json
lately --md > incident.md
# redacted brief for an AI agent (TUI: y)
lately --brief | pbcopy
# the restart verdict; live network
lately why-restart
lately net
# every rule, level band, tier and MITRE ID
lately rules
# elevated: process ancestry while it runs
sudo lately capture
# speak up when something serious happened
lately --since 1h --min-level high --list >/dev/null \
  || say "check your Mac"

Install

One command. Nothing left running.

brew install matthew-eucaristo/tap/lately

The recommended way on macOS.

macOSTested on macOS 27. The elevated tier needs eslogger (macOS 13 or later).
Try it on sample dataFrom a clone, lately --replay demo/sample reads nothing from your Mac.
Fast15 minutes in about 2.5 s on an M4. The TUI fills in as each source finishes.
Uninstalling leaves nothing behind
lately forget                      # removes the baseline file and its folder
brew uninstall lately
brew untap matthew-eucaristo/tap   # if nothing else uses the tap

Questions

Fair questions.

Is this an antivirus?

No. lately is a diagnostics tool: it explains what happened, with evidence, and suggests what to do. It removes nothing and changes nothing. It does surface XProtect detections and the persistence tricks malware relies on, which makes it a good first look before you reach for anything heavier.

Why not just open Console?

Console shows everything, about 14,000 lines a minute, mostly Apple talking to itself. lately reads eight narrow slices of the log plus evidence Console does not show at all (crash report headers, boot records, install receipts, launch items), classifies it with 42 rules and groups the rest away.

Does it need sudo?

No. Everything in the timeline is readable by a normal user. Only sudo lately capture is elevated, for short-lived processes and their command lines, and it runs only while you keep it open. lately never asks for your password itself.

Does it send anything anywhere, or use AI?

No network connections, no telemetry, no AI. The classification is 42 readable YAML rules you can tune without touching Go. If you want an agent's read anyway, y (or --brief) copies a redacted brief that you paste yourself. This page loads nothing from third parties either.

What does NEW mean, and what does it store?

NEW means this Mac has not seen the subject before. To know that, lately keeps one file of salted hashes and dates, never names or paths. The first run marks nothing NEW and says so. --no-baseline runs without it; lately forget deletes it.

Can I share the output?

Yes, that is what --md, --json and the e export are for. They are redacted by default; --no-redact shows real names when you need them.

Linux or Windows?

macOS only for now. The sources sit behind a cross-platform interface, so a port is a new package beside the macOS one; rules and views stay.

Next time your Mac does something odd, ask it.

brew install matthew-eucaristo/tap/lately

Then just type lately.

The real TUI, recorded with VHS on sample data