{% extends "base.html" %} {% block title %}Settings Β· {{ app_name }}{% endblock %} {% block body %}

βš™ Settings every rule and every editor lives here β€” the play pages stay clean

{% for gid, gtitle, _ in groups %}{{ gtitle }}{% endfor %} 🐾 Activities {% for m, p in panels %}{{ m.icon }} {{ m.title }}{% endfor %} System
{% for gid, gtitle, keys in groups %}

{{ gtitle }} πŸ“–

{% for key, label, default in keys %} {% endfor %}
{% endfor %} {# πŸ”΄ ACTIVITIES ARE LENSES, NOT LOGS. Every row here is a saved query over `events` β€” which is why a new one is populated from the whole existing log the moment it is saved, and why deleting one destroys nothing. Changing a matcher RE-READS history; it does not rewrite it. πŸ”΄ ONE
PER ROW, AND THE ROWS ARE DIVS, NOT A . A is not a legal child of : the parser hoists it out of the table and every input inside it stops being submitted β€” a broken editor that looks perfectly fine. Rows-as-divs also survive a phone, which is where this app is actually used. #}

🐾 Activities πŸ“–

A thing you want to count. It selects events you already have β€” so a new one fills in from your whole log straight away, and removing one deletes nothing. Each gets five stats you can put on a share card: since_, days_, streak_, total_, count_ + its slug.

{% macro act_form(a, is_new) %}
{% if a %}{% endif %} {% if a %}
{% endif %}
{% endmacro %} {% for a in acts_all %}{{ act_form(a, false) }}{% endfor %} {{ act_form(none, true) }}

Your own thing? Leave match module as activity and match kind as your slug, tick one-tap button, and it gets a button on the dashboard that it then counts. Counting something a module already does? Put that module's kind in match kind and untick one-tap button.

streak Β· daily every day Β· weekly_n counts whole weeks carrying target or more Β· every_n_days allows a gap of target days Β· none means this has no streak, and none is shown β€” a counter has no run to break, so a 0 there would claim one was. time from is where β€œtime doing this” is read: entry (headspace), media (recordings), trance (sits). Blank means this has no duration and none is shown.

every stat id you can put in a share / stamp / recap token list ({{ token_ref|length }})

Paste any of these, comma-separated, into the token fields under Stamps & recap. Unknown ids are ignored, and a stat with nothing to say at that moment is left out rather than printed as a zero.

{% for t in token_ref %}{{ t }} {% endfor %}

{% for m, p in panels %}

{{ m.icon }} {{ m.title }} πŸ“–

{% if m.settings_keys %}
{% for key, label, default in m.settings_keys %} {% endfor %}
{% endif %} {% if p %}{% set c = p %}{% include p.template %}{% endif %}
{% endfor %}

System πŸ“–

API
{% if api_enabled %}enabled bearer token Β· /api/v1{% else %}disabled set LATCH_API_TOKEN{% endif %}
data
{{ data_dir }}
timezone
{{ tz }}
modules
{% for m in modules %}{{ m.icon }} {{ m.name }} {% endfor %}
version
{{ version }}

Local only. No outbound calls. Exports strip EXIF. How that is enforced β†’

Export your data β†’

{% endblock %}