DopaDone Vault Format

The DopaDone vault is an Obsidian-compatible directory of markdown files with YAML frontmatter. All user data — tasks, projects, habits, calendar prep, and settings — lives in plain-text files you can read, edit, process with AI, or move anywhere.

Directory Structure

<vault-root>/
└── dopadone/
    ├── tasks.md                    # Internal tasks
    ├── projects.md                 # Internal projects
    ├── presets.md                  # Weight presets, schedules, location rules
    ├── settings.md                 # App settings
    ├── profile.md                  # User profile (XP, level, stats)
    ├── habits/
    │   ├── definitions.md          # Habit definitions
    │   └── active.md               # Active habit instances
    ├── calendar/
    │   ├── feeds.md                # Calendar feed configs
    │   ├── rules.md                # Event-matching rules + prep steps
    │   └── active.md               # Prep step completions

The vault location is user-selectable and stored in ~/Library/Application Support/dopadone/vault-path.txt.

Conventions

File Format

Every data file uses YAML frontmatter (parsed by gray-matter):

---
key:
  - id: example
    name: Example Item
---

Optional markdown body content

IDs

Two ID strategies are used, depending on the collection:

StrategyUsed ByFormat
Slug (kebab-case)Projects, Habits, Presetsmy-project-name
UUID (v4)Tasks, Habit Instances, Calendar Feeds/Rules/Steps/Completions123e4567-e89b-12d3-a456-426614174000

Slug generation: Unicode-normalized, lowercased, non-word characters removed, spaces/underscores replaced with hyphens, collapsed, trimmed. Falls back to "untitled" if empty. Uniqueness enforced by appending -2, -3, etc.

Priority Scale

A consistent 0–4 scale shared across tasks, habits, and calendar prep:

ValueLabelMeaning
0PausedInactive, excluded from task pool
1P4No priority (default)
2P3Low
3P2Medium
4P1High / Urgent

Higher values = higher priority = more likely to be selected.

Time Representation

  • Dates — ISO 8601: YYYY-MM-DD (e.g., 2026-03-19)
  • Timestamps — ISO 8601 with time: 2026-03-19T14:30:45.123Z
  • Time of day — minutes since midnight (integer). 0 = 00:00, 540 = 09:00, 1440 = 24:00. Values above 1440 represent the next day (e.g., 1560 = 02:00 next day).
  • Schedule blocks use 15-minute increments (0, 15, 30, 45, …).

Colors

Always stored as hex strings (e.g., "#b8256f"). Todoist color names are converted to hex at the sync boundary.

Sort Order

Collections use integer sort_order or order fields for explicit ordering. Lower values appear first.

Write Mechanics

All vault writes use an atomic temp-file-rename pattern:

  1. Content is written to a temporary file (.{random-hex}.tmp) in the same directory
  2. The temp file is atomically renamed to the target path
  3. The file watcher marks self-writes to avoid reacting to its own changes (500ms debounce window)

File watching uses chokidar with a 200ms stability threshold. Dotfiles and .tmp files are ignored.


File Reference

tasks.md

Internal tasks (not from Todoist or other connectors).

Frontmatter key: tasks ID type: UUID

FieldTypeDescription
idstringUUID primary key
project_idstringReferences an internal project slug
contentstringTask title
descriptionstringTask details (empty string if none)
prioritynumber0–4 (see priority scale; 0 = paused)
sort_ordernumberInteger position within project
start_datestring | nullISO date — when task becomes eligible
deadline_datestring | nullISO date — deadline
is_completedbooleanCompletion status
completed_atstring | nullISO timestamp when marked done
labelsstring[]Array of label slugs
created_atstring | undefinedISO timestamp (optional)
depends_onstring[]Task IDs this depends on (omitted if empty)
tasks:
  - id: 123e4567-e89b-12d3-a456-426614174000
    project_id: personal
    content: Review Q1 planning
    description: Go through quarterly goals
    priority: 4
    sort_order: 0
    start_date: null
    deadline_date: "2026-03-31"
    is_completed: false
    completed_at: null
    labels: [urgent, planning]
    created_at: "2026-03-15T09:30:00.000Z"

projects.md

Internal projects (Todoist projects are transient and not stored in the vault).

Frontmatter key: projects ID type: Slug

FieldTypeDescription
idstringSlug primary key (e.g., personal-tasks)
namestringDisplay name
colorstringHex color
is_sequentialbooleanWhen true, only the first non-completed task is eligible
ordernumberSort order
parent_idstring | nullParent project ID for hierarchy
projects:
  - id: personal-tasks
    name: Personal Tasks
    color: "#b8256f"
    is_sequential: false
    order: 0
    parent_id: null
  - id: home-renovation
    name: Home Renovation
    color: "#60a5fa"
    is_sequential: true
    order: 1
    parent_id: null

At runtime, a source: 'internal' field is added (not stored in the file).


presets.md

Named weight sets that shape the task probability pool, with schedule and location triggers.

Frontmatter key: presets (array of preset objects) Additional key: system_activation_overrides (Record<string, ActivationMode>) ID type: Slug (presets)

Labels are bare strings — there is no label registry or labels.md file. Labels are auto-discovered from usage across all task sources.

Preset fields

FieldTypeDescription
idstringSlug primary key
namestringDisplay name
colorstringHex color
sort_ordernumberSort order
activation_modestring | undefined'always_on', 'always_off', or 'triggers' (default 'always_off' for new presets)
trigger_modestring | undefined'all' or 'any' (default 'all', only relevant when activation_mode is 'triggers')
criteria_weightsRecord<string, number>Criterion string to weight multiplier mapping
default_weightnumberWeight for tasks matching no criteria (default 1)
schedule_blocksScheduleBlock[]Time windows for trigger-based activation
location_ruleLocationRule | undefinedGeographic trigger rule

Criteria keys are bare strings — labels like work, errands, or auto-injected criteria like priority:p1, due:overdue, deadline:today, assignee:me, last-commenter:others.

ScheduleBlock fields

FieldTypeDescription
idstringUUID
preset_idstringParent preset slug
daysnumber[]Days of week (0 = Monday, 6 = Sunday)
start_minutesnumberStart time (minutes since midnight, 15-min increments)
end_minutesnumberEnd time (can exceed 1440 for overnight)

LocationRule fields

FieldTypeDescription
latnumberLatitude
lngnumberLongitude
radius_metersnumberActivation radius
modestring'inside' or 'outside'
labelstring | undefinedGeocoded place name for display

system_activation_overrides

System presets are defined in code (read-only rules). Only their activation mode can be overridden in the vault. The system_activation_overrides key maps system preset IDs to activation modes.

presets:
  - id: work
    name: Work
    color: "#3b82f6"
    sort_order: 0
    activation_mode: triggers
    trigger_mode: all
    criteria_weights:
      work: 2
      personal: 0.2
      "priority:p1": 5
    default_weight: 0.5
    schedule_blocks:
      - id: a1b2c3d4-...
        preset_id: work
        days: [0, 1, 2, 3, 4]
        start_minutes: 540
        end_minutes: 1020
    location_rule:
      lat: 52.2297
      lng: 21.0122
      radius_meters: 500
      mode: inside
      label: Office
system_activation_overrides:
  "system:defaults": always_on

habits/definitions.md

Recurring habit definitions with scheduling rules.

Frontmatter key: habits ID type: Slug

FieldTypeDescription
idstringSlug primary key
contentstringHabit title
descriptionstringDetails
prioritynumber0 = paused, 1–4 = P4 through P1
sort_ordernumberSort order
rrulestringRecurrence rule (e.g., "FREQ=DAILY")
time_window_startnumberMinutes since midnight when habit appears (default 540 = 9:00am)
linger_minutesnumberHow long after occurrence to keep showing (default 960 = 16 hours)
day_window_startnumber | nullRestrict to after this time of day
day_window_endnumber | nullRestrict to before this time of day
created_atstringISO timestamp
labelsstring[]Label slugs
depends_onstring[]Habit IDs this depends on (omitted if empty)
habits:
  - id: take-medication
    content: Take medication
    description: ""
    priority: 4
    sort_order: 0
    rrule: "FREQ=DAILY"
    time_window_start: 480
    linger_minutes: 240
    day_window_start: null
    day_window_end: null
    created_at: "2026-01-15T10:00:00.000Z"
    labels: [health]
  - id: lunch
    content: Have lunch
    description: ""
    priority: 3
    sort_order: 1
    rrule: "FREQ=DAILY"
    time_window_start: 720
    linger_minutes: 180
    day_window_start: null
    day_window_end: null
    created_at: "2026-01-15T10:00:00.000Z"
    labels: []

habits/active.md

Active habit instances — created when a habit occurrence is due, removed when the linger window expires.

Frontmatter key: instances ID type: UUID

FieldTypeDescription
idstringUUID primary key
habit_idstringParent habit slug
occurrence_datestringISO date of this occurrence
notestringUser note
encounter_countnumberTimes this instance has been shown
created_atstringISO timestamp
instances:
  - id: abc12345-...
    habit_id: take-medication
    occurrence_date: "2026-03-19"
    note: ""
    encounter_count: 2
    created_at: "2026-03-19T08:00:00.000Z"

calendar/feeds.md

ICS calendar feed configurations.

Frontmatter key: feeds ID type: UUID

FieldTypeDescription
idstringUUID primary key
namestringDisplay name
ics_urlstringICS calendar URL
colorstringHex color (default "#60a5fa")
is_enabledbooleanEnable/disable feed
sort_ordernumberSort order
feeds:
  - id: f1e2d3c4-...
    name: Work Calendar
    ics_url: "https://calendar.example.com/feed.ics"
    color: "#60a5fa"
    is_enabled: true
    sort_order: 0

calendar/rules.md

Rules that match calendar events and define prep steps.

Frontmatter key: rules ID type: UUID (rules and steps)

Rule fields

FieldTypeDescription
idstringUUID primary key
sort_ordernumberSort order (catch-all rules always last)
match_patternstringPattern to match event summary
match_typestring'contains', 'exact', or 'regex'
is_catch_allbooleanMatches all unmatched events
stepsCalendarRuleStep[]Prep steps for matched events

CalendarRuleStep fields

FieldTypeDescription
idstringUUID
rule_idstringParent rule UUID
sort_ordernumberSort order
namestringStep title (e.g., “Anything to prepare?”)
hours_beforenumberHours before event to surface this step
prioritynumber0–4 priority scale
labelsstring[]Labels applied to generated tasks
rules:
  - id: r1a2b3c4-...
    sort_order: 0
    match_pattern: "standup"
    match_type: contains
    is_catch_all: false
    steps:
      - id: s1a2b3c4-...
        rule_id: r1a2b3c4-...
        sort_order: 0
        name: Review yesterday's progress
        hours_before: 2
        priority: 3
        labels: [work]
  - id: r5e6f7g8-...
    sort_order: 999
    match_pattern: "*"
    match_type: contains
    is_catch_all: true
    steps:
      - id: s5e6f7g8-...
        rule_id: r5e6f7g8-...
        sort_order: 0
        name: Anything to prepare?
        hours_before: 48
        priority: 2
        labels: []
      - id: s9a0b1c2-...
        rule_id: r5e6f7g8-...
        sort_order: 1
        name: Anything else before this?
        hours_before: 2
        priority: 2
        labels: []

calendar/active.md

Tracks which prep steps have been completed for upcoming events.

Frontmatter key: prep_completions ID type: UUID

FieldTypeDescription
idstringUUID primary key
event_uidstringCalendar event UID
event_startstringISO timestamp of event start
prep_step_idstringCompleted step UUID
completed_atstringISO timestamp when marked done
prep_completions:
  - id: c1d2e3f4-...
    event_uid: "abc123@google.com"
    event_start: "2026-03-20T10:00:00.000Z"
    prep_step_id: s1a2b3c4-...
    completed_at: "2026-03-19T14:00:00.000Z"

Completions are automatically cleaned up after the event has passed.


settings.md

App-level settings stored as a flat key-value document.

Frontmatter key: top-level keys (no collection wrapper)

KeyTypeDescription
todoist_tokenstringTodoist API token
todoist_user_idstringTodoist user ID
sound_enabledstring'true' or 'false'
analytics_enabledstring'true' or 'false' (default 'true')
update_channelstring'stable' or 'beta' (default 'stable')
connectorsobjectPer-connector config (nested)
weight_assignee_matchstringNumeric string (default '2')
weight_response_bonusstringNumeric string (default '2')
collaborator_assignee_weightsstringJSON object: collaborator ID to weight
collaborator_response_weightsstringJSON object: collaborator ID to weight
todoist_token: "abc123..."
todoist_user_id: "12345678"
sound_enabled: "true"
analytics_enabled: "true"

Note: values are stored as strings and parsed at read time.


profile.md

User profile with running counters for the XP/leveling system.

Frontmatter key: top-level keys (no collection wrapper)

FieldTypeDescription
total_xpnumberCumulative experience points (default 0)
levelnumberCurrent level (default 1)
tasks_completednumberTotal tasks completed (default 0)
total_xp: 4250
level: 7
tasks_completed: 142