beck ▸ README.md
updated 2026-08-03

Beck

Scott’s health companion. Replaces iris360, which paywalled him out on 2–3 August 2026 in the middle of a blood-pressure titration. Named after Aaron Beck.

Design rationale and the build-vs-pay argument: docs/rebuild-scope.md. Project status: BRIEF.md.

The split that matters

Code and docs live here~/Projects/Unicorn.Land/beck, git, private repo.

Scott’s data lives in BECK_HOME~/Projects/Obadiah/workspace/beck, which sits inside Obadiah’s gitignored workspace/. His health record, the iris360 transcripts, the guides, the database, and the curated notes are all on that side and none of it is tracked anywhere.

This repo’s .gitignore blocks the same paths as a second line of defence. Keep the split.

BECK_HOME/
  beck.db                 store
  notes/
    identity.md           who Scott is — rarely changes
    current-focus.md      the live picture — read before every reply
    autopilot.md          cadence, milestones, weekly review
    topics/               blood-pressure.md, and others as they matter
    archive/
  data/
    transcripts/          188 iris360 daily files (10.12.2025 → 03.08.2026)
    guides/               iris360's guide library, saved 03.08.2026
    notes/                iris360's own case file — 17 notes, exported as PDF 03.08 and
      pdf/                text-extracted. Read-only archive; the live notes are above.
  entries.md              the hand-written Phase 0 log, superseded by beck.db

Setup

./beck.py init                    # create the db + notes tree
./seed_transcripts.py --dry-run   # check what the parser finds
./seed_transcripts.py             # import readings + conversation index
./beck.py status

Seeding is idempotent — a unique index on (ts, kind, payload) means re-running it cannot duplicate readings.

Daily use

./beck.py context                 # READ THIS FIRST — notes + recent record
./beck.py log "128/79 p:73" --at 21:38
./beck.py trend bp --days 14

beck.py log parses BP shorthand (142/92 p:100), sleep durations, and dose/posture context. Anything it cannot parse is still kept as a note rather than dropped.

Pre-dose versus post-dose and seated versus post-walk are stored as separate fields, because a reading can be both and the dose relation is the clinically load-bearing one. Getting that backwards is worse than leaving it blank — see the comment in beck.py.

The agents

Three, not iris360’s five.

Prompt Role
prompts/beck.md The front door. The only one Scott talks to. Carries the safety discipline.
prompts/autopilot.md Decides whether and what to check in on. Allowed to stay silent.
prompts/curator.md Not written yet — will maintain and compress the notes.

Autopilot — NOT ENABLED

The scripts work. The cron entries are deliberately not installed.

Turning them on means an automated system starts messaging Scott about his health on a schedule he has not agreed to. His preference is documented (see below) but it was a preference given to iris360, not consent for Beck to start messaging him. Confirm with him before switching this on.

Test without messaging him:

BECK_DRY_RUN=1 BECK_SLOT=morning BECK_NOW="Tuesday 4 August 2026, 06:15" \
  ./scripts/beck-checkin.sh

When it is time to go live:

30 8  * * * BECK_SLOT=morning /Users/joshua/Projects/Unicorn.Land/beck/scripts/beck-checkin.sh >> /tmp/beck-checkin.log 2>&1
0  18 * * * BECK_SLOT=evening /Users/joshua/Projects/Unicorn.Land/beck/scripts/beck-checkin.sh >> /tmp/beck-checkin.log 2>&1
0  *  * * * /Users/joshua/Projects/Unicorn.Land/beck/scripts/beck-heartbeat.sh >> /tmp/beck-heartbeat.log 2>&1

Those times are Scott’s documented preference, recovered from iris360’s own autopilot.md: morning 08:00–08:30 after the school drop-off, evening 18:00–19:00. He asked for one check-in a day during a calm baseline, two only around a known gate, and explicitly not to be chased — so the evening slot exists but should mostly resolve to SKIP.

Install the heartbeat at the same time as the check-ins, not later. It alerts #secure-it when no check-in has posted in 26 hours, which is the failure this whole design is most worried about: cron dies quietly, Scott stops being asked, and nobody notices for a week.

The viewer — running

server.py gives Scott his own record on the home network. Live at http://192.168.178.53:8771 and http://joshuas-mac-mini-2.local:8771, under launchd, restarting on crash and on reboot.

launchctl load -w ~/Library/LaunchAgents/land.unicorn.beck-viewer.plist    # start
launchctl unload -w ~/Library/LaunchAgents/land.unicorn.beck-viewer.plist  # stop
tail -f /tmp/beck-viewer.log

Four pages: today’s reading with a 21-day chart and what Beck is watching · every BP reading · sleep · the notes, rendered.

Three constraints hold it together, and all three are load-bearing:

Still missing