# Fresco Dashboard Handover
Updated: 2026-04-26
This note describes the working Fresco dashboard setup: what runs on the
desktop, what needs to be repeated on the laptop, where the files live, and how
to recover it if something stops working.
## Current desktop status
The desktop is ready to use.
- Dashboard URL: `http://127.0.0.1:8765/Fresco-v15.html`
- Local server: installed and loaded
- Snapshot writer: installed and loaded
- Refresh cadence: every 15 minutes
- Google Calendar: checked working
- Google Tasks: checked working
- Readwise highlights: checked working for rotating quotes
- Readwise Reader saves: checked working for the seven-day save list
- Obsidian eval: checked working
- Obsidian bookmarks: checked working from `.obsidian/bookmarks.json`
- Train data: checked working in both directions
- Raycast command: installed in `/Users/nickyoung/raycast scripts`
The last successful doctor run reported all checks OK.
## How the dashboard works
The dashboard has three layers.
1. App files live in the synced vault:
```text
~/My Obsidian Vault/Apps/Fresco Dashboard/
```
2. A local writer generates the live data frame every 15 minutes:
```text
~/Library/Application Support/Fresco Dashboard/dashboard-data.json
```
3. A local server serves the app at:
```text
http://127.0.0.1:8765/Fresco-v15.html
```
The app files sync between Macs. The live JSON does not need to sync. Each Mac
generates its own current frame so the desktop and laptop do not fight over the
same `dashboard-data.json`.
## Raycast launcher
The Raycast command is here:
```text
/Users/nickyoung/raycast scripts/open-fresco-dashboard.sh
/Users/nickyoung/raycast scripts/open-fresco-dashboard.jxa.js
```
It appears in Raycast as:
```text
Open Fresco Dashboard
```
The command targets Zen. Each time it runs, it opens the dashboard with a
cache-busting query string so the page reloads rather than showing a stale
frame.
Zen limitation: Zen does not expose inactive tab URLs through AppleScript/JXA in
the way Chrome does. The launcher can focus and refresh a visible dashboard
window when macOS Accessibility can see its title. If the dashboard is buried as
an inactive Zen tab, the launcher cannot reliably discover that tab. In that
case it brings the dashboard up in Zen.
To finish the keyboard shortcut:
1. Open Raycast Settings.
2. Go to Extensions.
3. Find `Open Fresco Dashboard`.
4. Assign the hotkey you want.
5. If macOS asks, grant Raycast Accessibility permission.
Raycast is already watching the folder containing `quote.sh`, so the command was
moved there rather than into a new script directory.
## Install on a Mac
On the laptop, after the vault has synced, run:
```bash
cd "$HOME/My Obsidian Vault"
./_scripts/install-fresco-dashboard-mac.sh
```
Then open:
```text
http://127.0.0.1:8765/Fresco-v15.html
```
The installer creates or reloads:
- `com.nickyoung.fresco-dashboard-server`
- `com.nickyoung.dashboard-snapshot`
It also runs the doctor at the end.
## Check the setup
```bash
python3 "$HOME/My Obsidian Vault/_scripts/fresco-dashboard-doctor.py"
```
The doctor checks the app files, Google Calendar, Google Tasks, the local
server, the launch agents, and the freshness of the local data frame.
## If Google auth fails
Run:
```bash
gws auth login -s calendar,tasks
```
Then rerun the doctor.
If the laptop does not have `gws`, `obsidian`, or the Homebrew certificate
bundle, the doctor will say so.
## What is local per Mac
- `~/Library/LaunchAgents/com.nickyoung.fresco-dashboard-server.plist`
- `~/Library/LaunchAgents/com.nickyoung.dashboard-snapshot.plist`
- `~/Library/Application Support/Fresco Dashboard/dashboard-data.json`
- `~/Library/Logs/fresco-dashboard-server.log`
- `~/Library/Logs/dashboard-snapshot.log`
## What syncs through the vault
- `Apps/Fresco Dashboard/`
- `.obsidian/bookmarks.json`
- `_scripts/build-dashboard-snapshot.py`
- `_scripts/serve-fresco-dashboard.py`
- `_scripts/serve-fresco-dashboard.sh`
- `_scripts/dashboard_snapshot_tick.sh`
- `_scripts/fresco-dashboard-doctor.py`
- `_scripts/install-fresco-dashboard-mac.sh`
The Raycast script folder at `/Users/nickyoung/raycast scripts` is outside the
vault. If you want the same Raycast launcher on the laptop, copy these two files
or add a synced Raycast script folder later:
- `open-fresco-dashboard.sh`
- `open-fresco-dashboard.jxa.js`
## Files to know
Dashboard app:
```text
~/My Obsidian Vault/Apps/Fresco Dashboard/Fresco-v15.html
~/My Obsidian Vault/Apps/Fresco Dashboard/direction-fresco-v15.jsx
~/My Obsidian Vault/Apps/Fresco Dashboard/tokens.css
```
Dashboard data writer:
```text
~/My Obsidian Vault/_scripts/build-dashboard-snapshot.py
~/My Obsidian Vault/_scripts/dashboard_snapshot_tick.sh
```
Local server:
```text
~/My Obsidian Vault/_scripts/serve-fresco-dashboard.py
~/My Obsidian Vault/_scripts/serve-fresco-dashboard.sh
```
Setup and check:
```text
~/My Obsidian Vault/_scripts/install-fresco-dashboard-mac.sh
~/My Obsidian Vault/_scripts/fresco-dashboard-doctor.py
```
Generated local data:
```text
~/Library/Application Support/Fresco Dashboard/dashboard-data.json
```
LaunchAgents:
```text
~/Library/LaunchAgents/com.nickyoung.fresco-dashboard-server.plist
~/Library/LaunchAgents/com.nickyoung.dashboard-snapshot.plist
```
Logs:
```text
~/Library/Logs/fresco-dashboard-server.log
~/Library/Logs/dashboard-snapshot.log
```
## Manual refresh
To regenerate the data immediately:
```bash
bash "$HOME/My Obsidian Vault/_scripts/dashboard_snapshot_tick.sh"
```
Then reload:
```text
http://127.0.0.1:8765/Fresco-v15.html
```
Or use the Raycast command, which reloads with a fresh query string.
## Restart services
If the dashboard stops updating, rerun the installer:
```bash
cd "$HOME/My Obsidian Vault"
./_scripts/install-fresco-dashboard-mac.sh
```
That rewrites the LaunchAgents and restarts both services.
## Data sources currently wired
- Google Calendar, including event links to Google Calendar
- Google Tasks, including links to the relevant task in Google Tasks
- TaskNotes, linking back into Obsidian
- Task completion from the dashboard task column:
- Google Tasks are completed through `gws`
- TaskNotes are marked `status: done` with `completedDate`
- Vault activity, via Obsidian eval
- Recent Claude/Codex conversations, via generated conversation notes
- Weather for Milano and Genova, via Open-Meteo
- Rotating quotes, via Readwise highlights with source attribution and links
- Recent Readwise Reader saves from the last seven days, excluding RSS/feed noise
- Italian learning prompt, generated automatically from the current snapshot slot
- Obsidian bookmarks, read from `.obsidian/bookmarks.json`
- Trains in both directions:
- Milano Lambrate to Genova P. Principe
- Genova P. Principe to Milano Lambrate
The train writer filters out departures that have already left and refreshes on
the 15-minute snapshot cadence.
The quote panel is regenerated with each snapshot. It reads recent Readwise
highlights, resolves their parent Reader documents for title/author/site
attribution, links each quote back to the source text, and avoids reusing the
previously displayed quote where possible. If Readwise is unavailable, the
refresh fails visibly and the dashboard keeps the last good frame until Readwise
is fixed.
The chat list shows a compact local date/time rail (`today · 16:20`,
`yday · 22:34`, or `25 apr · 18:10`) beside each session.
The Italian bay is local generated content, not an SRS write. It does not edit
`Notes/Italian SRS.md`; it just displays a rotating prompt on the dashboard.
The writing/bookmarks bay shows edited writing drafts in the top half and
Obsidian bookmarks in the lower half.
## Known limitations
- Zen cannot expose all inactive tab URLs to automation, so the Raycast launcher
cannot perfectly deduplicate a dashboard tab hidden somewhere in Zen.
- The Raycast launcher uses macOS Accessibility to focus and refresh visible Zen
windows. Raycast needs Accessibility permission.
- The laptop will need its own Google auth. Do not expect desktop Google tokens
to sync safely.
- The desktop was very low on disk space during setup. At one point the system
reported about 116 MB free, which can break temp-file creation and unrelated
automation.
## Quick desktop confidence check
Run:
```bash
python3 "$HOME/My Obsidian Vault/_scripts/fresco-dashboard-doctor.py"
```
Healthy output should show OK for:
- `Fresco-v15.html`
- `direction-fresco-v15.jsx`
- `snapshot builder`
- `local data server`
- `gws calendar`
- `gws tasks`
- `obsidian eval`
- both LaunchAgents
- `localhost:8765`
- local `dashboard-data.json`