tankslab.com/recall/source
bin/paths.py
85 lines, exactly as they ship in the download.
"""
paths.py - where Recall keeps things, on whichever machine you are on.
WHY THIS EXISTS
---------------
The internal build this grew from hardcoded /opt/friday/recall. That is correct for a service on a
box we own and wrong for something a stranger installs: it is not writable without
root, it does not exist on Windows, and it puts a person's data next to the program
instead of in their own space.
WHERE THE DATA GOES, and this is what the README promises:
Windows %LOCALAPPDATA%\\friday-recall (usually C:\\Users\\<you>\\AppData\\Local)
Linux $XDG_DATA_HOME/friday-recall, else ~/.local/share/friday-recall
macOS ~/Library/Application Support/friday-recall
One directory, per user, in the place that platform already uses for application
data. `recall wipe` deletes exactly that directory, which is why it can honestly say
"nothing of Recall's remains".
FRIDAY_RECALL_ROOT overrides all of it, so you can put the store on an encrypted
volume, a USB stick, or nowhere near your home directory if you would rather.
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
# ⚠️ EVERY read_text/write_text/open IN THIS PACKAGE PASSES encoding="utf-8".
#
# Python on Windows does not default to UTF-8 - it uses the machine's legacy code
# page. So a file this tool wrote as UTF-8 comes back as a UnicodeDecodeError on the
# very next read, and a file it rewrites can be written back MANGLED. It bit the test
# suite first, on the harmless bytes in a comment.
#
# The dangerous instance was in wipe.py, which reads the user's settings.json and
# writes it back: on a Windows machine with anything non-ASCII in that file - an
# accented path, a name in another language - the command whose whole job is to leave
# the machine clean would have corrupted their editor configuration instead. Never
# omit it, even where today's content happens to be ASCII: transcripts carry whatever
# language the person writes in.
APP = "friday-recall"
def root() -> Path:
env = os.environ.get("FRIDAY_RECALL_ROOT")
if env:
return Path(env).expanduser()
if sys.platform.startswith("win"):
base = os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA")
return Path(base) / APP if base else Path.home() / "AppData" / "Local" / APP
if sys.platform == "darwin":
return Path.home() / "Library" / "Application Support" / APP
xdg = os.environ.get("XDG_DATA_HOME")
return (Path(xdg) / APP) if xdg else Path.home() / ".local" / "share" / APP
def ensure_root() -> Path:
r = root()
r.mkdir(parents=True, exist_ok=True)
return r
def db() -> Path:
env = os.environ.get("FRIDAY_RECALL_DB")
return Path(env).expanduser() if env else root() / "recall.db"
def archive_dir() -> Path:
return root() / "archive"
def log_file() -> Path:
return root() / "hook.log"
def report_file() -> Path:
return root() / "last_failure.txt"
def transcripts_root() -> Path:
"""Claude Code's own project directory. Recall READS this and never writes to it."""
return Path.home() / ".claude" / "projects"