Skip to main content

lifetract

Query personal life-tracking data: Samsung Health (sleep, steps, heart rate, stress, exercise, weight) + aTimeLogger (18 time categories) + Home Assistant REST (live sensors via ha.junghanacs.com). All records use Denote IDs (YYYYMMDDTHHMMSS) for cross-referencing with denotecli. DB mode (lifetract.db) for instant queries, individual Samsung commands have CSV fallback, and today's DB gaps can use Home Assistant.

Jump to install

Source facts

Repository
junghan0611/agent-config
Last source activity
July 14, 2026 at 08:15
Detected SKILL.md language
Mixed languages
Stars
5
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions ยท Read-only preview
name
lifetract
description
Query personal life-tracking data: Samsung Health (sleep, steps, heart rate, stress, exercise, weight) + aTimeLogger (18 time categories) + Home Assistant REST (live sensors via ha.junghanacs.com). All records use Denote IDs (YYYYMMDDTHHMMSS) for cross-referencing with denotecli. DB mode (lifetract.db) for instant queries, individual Samsung commands have CSV fallback, and today's DB gaps can use Home Assistant.
# lifetract โ€” Life Tracking CLI Query and analyze personal health and time-tracking data. All records carry Denote IDs (`YYYYMMDDTHHMMSS`) โ€” same axis as denotecli. Binary is bundled in the skill directory. Invoke via `{baseDir}/lifetract`. All output is JSON. ## Why This Exists (not sqlite3/pandas) Do NOT open lifetract.db or CSV files directly with Python/sqlite3/pandas. 1. **Denote ID mapping** โ€” Raw CSVs use Samsung's epoch timestamps. The CLI converts them to `YYYYMMDDTHHMMSS` Denote IDs for cross-referencing with denotecli/gitcli. 2. **Multi-source join** โ€” Sleep, heart rate, steps, stress, exercise, time tracking from different tables/sources, unified per-day. Manual SQL gets this wrong. 3. **JSON for agents** โ€” Structured output ready for reasoning. No parsing needed. ## When to Use - "์˜ค๋Š˜ ๋ชธ ์ƒํƒœ" โ†’ `lifetract today` - "์–ด์ œ ๋ญ ํ–ˆ์ง€?" โ†’ `lifetract read 2026-03-09` - "์ตœ๊ทผ ์ˆ˜๋ฉด ํŒจํ„ด" โ†’ `lifetract sleep --days 30 --summary` - "์ด๋ฒˆ ์ฃผ ์‹œ๊ฐ„ ์‚ฌ์šฉ" โ†’ `lifetract time --days 7` - "์šด๋™ ๊ธฐ๋ก" โ†’ `lifetract exercise --days 30` - "30์ผ ์ถ”์ด" โ†’ `lifetract timeline --days 30` ## Quick Start ```bash lifetract status # ๋ฐ์ดํ„ฐ ์†Œ์Šค + DB ์ƒํƒœ lifetract import --exec # CSV+aTimeLogger โ†’ lifetract.db (1.5์ดˆ) lifetract today # ์˜ค๋Š˜ ํ†ตํ•ฉ ์š”์•ฝ lifetract read 2025-10-04 # ํŠน์ • ๋‚ ์งœ ์ข…ํ•ฉ (๊ฑด๊ฐ•+์‹œ๊ฐ„์ถ”์ ) lifetract timeline --days 30 # 30์ผ ํšก๋‹จ ๋ทฐ ``` ## Architecture ``` lifetract.db ์žˆ์Œ โ†’ ๋ชจ๋“  ๋ช…๋ น: DB ์ฟผ๋ฆฌ (~90ms) โ†’ JSON lifetract.db ์—†์Œ โ†’ sleep/steps/heart/stress/exercise: CSV ํŒŒ์‹ฑ (~300ms) โ†’ JSON โ†’ time/timeline/today/read: exit 1 ``` - `lifetract import --exec` ์‹คํ–‰ ํ›„ ๋ชจ๋“  ์กฐํšŒ๊ฐ€ DB ๋ชจ๋“œ - DB ์—†์œผ๋ฉด ๊ฐœ๋ณ„ Samsung ๋ช…๋ น(`sleep`/`steps`/`heart`/`stress`/`exercise`)๋งŒ CSV ์ง์ ‘ ํŒŒ์‹ฑ - `time`๊ณผ ์‹œ๊ฐ„์ถ•์„ ํ•ฉ์น˜๋Š” `timeline`/`today`/`read`๋Š” DB๊ฐ€ ์—†์œผ๋ฉด **exit 1** โ€” aTimeLogger๋ฅผ ๋ชป ์ฝ์€ ๊ตฌ๋ฉ์„ 0์œผ๋กœ ๋‚ด๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค ## Commands ### status โ€” ๋ฐ์ดํ„ฐ ์†Œ์Šค ํ™•์ธ ```bash lifetract status ``` ```json { "samsung_health": {"path": "...", "available": true, "csv_count": 78}, "atimelogger": {"path": "...", "available": true, "size_mb": 5.0}, "database": { "path": "...", "available": true, "size_mb": 37.3, "mode": "db", "last_time_block": "2026-07-13", "last_sleep": "2026-07-13", "last_steps": "2026-07-13", "stale_days": 1, "freshness_checked": true, "warnings": [] } } ``` **`last_*` / `stale_days` / `warnings` ๊ฐ€ ์ด ๋ช…๋ น์˜ ์š”์ ์ด๋‹ค.** Samsung export ๋Š” ์‚ฌ๋žŒ์ด ํฐ์—์„œ ์†์œผ๋กœ ๋‚ด๋ณด๋‚ด์•ผ ํ๋ฅธ๋‹ค โ€” ์•ˆ ๋„ฃ์–ด์ฃผ๋ฉด ์กฐ์šฉํžˆ ๋‚ก๋Š”๋‹ค. ์ˆซ์ž๋ฅผ ์ €๋„์— ์‚ฌ์‹ค๋กœ ๋ฐ•๊ธฐ ์ „์— ์—ฌ๊ธฐ๋ถ€ํ„ฐ ๋ด๋ผ (ยง์‹œ๊ฐ„ ๊ณ„์•ฝ 4ํ•ญ). **`warnings: []` ๋Š” `freshness_checked: true` ์ผ ๋•Œ๋งŒ "์„ฑํ•˜๋‹ค"๋Š” ๋œป์ด๋‹ค.** DB ๊ฐ€ ์—†๊ฑฐ๋‚˜ ๊ฒ€์‚ฌ ์ž์ฒด๊ฐ€ ์‹คํŒจํ•˜๋ฉด `freshness_checked: false` ์ด๊ณ , ๊ทธ๋•Œ์˜ ๋นˆ ๋ชฉ๋ก์€ "์ด์ƒ ์—†์Œ"์ด ์•„๋‹ˆ๋ผ **"๋ณด์ง€ ์•Š์•˜์Œ"** ์ด๋‹ค. ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด ํ•ฉ๊ฒฉ์œผ๋กœ ๋ณด์ด๋ฉด ๊ทธ๊ฑด ๊ฒ€์‚ฌ๊ฐ€ ์•„๋‹ˆ๋‹ค. ### import โ€” DB ์ƒ์„ฑ ```bash lifetract import # dry-run: ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํ™•์ธ lifetract import --exec # ์‹คํ–‰: CSV+aTimeLogger โ†’ lifetract.db ``` 202,479 rows, ~38MB, ~2s. Active tables: sleep, sleep_stage, heart_rate, steps_daily, stress, exercise, weight, atl_category, atl_interval. HRV๋Š” ์€ํ‡ดํ–ˆ๋‹ค: Samsung export 1,058ํ–‰์— `rmssd`๊ฐ€ ์—†๊ณ  `binning_data`๋งŒ ์žˆ์–ด, ์˜ˆ์ „ importer๊ฐ€ ์ „๋ถ€ `0.0`์œผ๋กœ ๋„ฃ๋˜ ๋นˆ ๊ป๋ฐ๊ธฐ์˜€๋‹ค. **import ๋Š” ์ž๊ธฐ๊ฐ€ ๋ญ˜ ์žƒ์—ˆ๋Š”์ง€ ๋งํ•œ๋‹ค.** `total_rows` ๋ง๊ณ  **`status` ๋ฅผ ๋จผ์ € ๋ด๋ผ.** ```json { "status": "warning", "warnings": ["stress: 27,598 rows (2026-07-14 12:25) โ†’ 0 โ€” stream lost [empty]"], "total_rows": 175941, "prev_total_rows": 203539, "tables": [ {"name": "stress", "rows": 0, "status": "empty", "prev_rows": 27598, "delta": -27598} ] } ``` | ๋‚ฑ๋ง | ๋œป | |---|---| | `ok` | ์ฝ์—ˆ๊ณ , ์ง€๋‚œ๋ฒˆ๋ณด๋‹ค ์ค„์ง€ ์•Š์•˜๋‹ค | | `empty` | ์ฝํžˆ๊ธด ํ–ˆ๋Š”๋ฐ **0 ํ–‰**. ์ง€๋‚œ๋ฒˆ์— ํ–‰์ด ์žˆ์—ˆ๋‹ค๋ฉด **์žƒ์€ ๊ฒƒ** | | `shrunk` | ์ง€๋‚œ import ๋ณด๋‹ค **์ ๋‹ค** โ€” Samsung export ๋Š” ๋ˆ„์  ๋คํ”„๋ผ ์ค„๋ฉด ์ด์ƒํ•˜๋‹ค | ์ง์ „ ํ–‰์ˆ˜๋Š” DB ์•ˆ `import_log` ์›์žฅ์— ์‚ฐ๋‹ค (import ๊ฐ€ DB ๋ฅผ ์ง€์›Œ๋„ ์ด์›”๋œ๋‹ค). **์ฒซ import ๋Š” ๋น„๊ต ๋Œ€์ƒ์ด ์—†์œผ๋‹ˆ ๊ฒฝ๊ณ ํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” `note` ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ๋งํ•œ๋‹ค. ์›์žฅ์„ ์ง์ ‘ ์ฝ๋Š”๋‹ค๋ฉด **`GROUP BY import_id`** ๋ฅผ ์จ๋ผ. `imported_at` ์€ ํ•œ import ๋ฅผ ๋ฌถ์ง€ ๋ชปํ•œ๋‹ค (์˜› ํ–‰๋“ค์€ ์ดˆ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด 2~3 ๊ฐœ๋กœ ์ชผ๊ฐœ์ ธ ์žˆ๋‹ค). **`rows` ๋Š” DB ์— ์‹ค์ œ๋กœ ์•‰์€ ํ–‰์ˆ˜๋‹ค** โ€” ์šฐ๋ฆฌ๊ฐ€ ๊ฑด๋„จ ํ–‰์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ. ์˜ˆ์ „์—” `INSERT` ๊ฒฐ๊ณผ๋ฅผ ์•ˆ ๋ณด๊ณ  ์„ธ์„œ, DB ๊ฐ€ ๊ฑฐ๋ถ€ํ•œ ํ–‰๋„ "imported" ๋กœ ์›์žฅ์— ๋ฐ•ํ˜”๋‹ค. **์†์‹ค ๊ฐ€๋“œ๊ฐ€ ๊ทธ ๊ฐ€์งœ ์ˆซ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์‚ผ๊ณ  ์žˆ์—ˆ๋‹ค.** **`rejected` ๋Š” ์Šน๊ฒฉ์„ ๋ง‰์ง€ ์•Š์ง€๋งŒ ๋ฐ˜๋“œ์‹œ ๋ณด๊ณ ๋œ๋‹ค.** ์žฌ๋ณธ ์  ์—†๋Š” ์‹œ๊ฐ(1970-01-01 epoch, 2000-01-01)์„ ์‹ค์€ ํ–‰๊ณผ, Samsung ์ด ๊ฐ™์€ ๋‚ ์„ ๋‹ค์‹œ ๋™๊ธฐํ™”ํ•ด ์ตœ์‹  ๊ฐœ์ •ํŒ์œผ๋กœ ๋Œ€์ฒด๋œ ํ–‰์ด๋‹ค. ์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ๋Š” ๋„๊ตฌ๋Š” ์กฐ์šฉํžˆ ์žƒ๋Š” ๋„๊ตฌ์™€ ๊ฐ™์€ ์นจ๋ฌต์ด๋ผ ๋งค run ์ด ์ด์œ ๋ณ„ ๊ฐœ์ˆ˜๋ฅผ ๋งํ•œ๋‹ค. ๊ฑฐ์ ˆ์€ ์˜๊ตฌ์ ์ธ ์†์‹ค ์˜ˆ์‚ฐ์ด ์•„๋‹ˆ๋‹ค. ์ •์ƒ baseline ๋’ค์—๋Š” accepted rows ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์ค„๋ฉด ํ˜„์žฌ rejected ๊ฐ€ ๋ช‡ ๊ฐœ๋“  `shrunk` ๋‹ค. ์ƒˆ ๊ฑฐ์ ˆ ์ •์ฑ…์€ ์ „์ˆ˜ ๋Œ€์กฐํ•œ ๋ช…์‹œ์  baseline ์ „ํ™˜์œผ๋กœ๋งŒ ๋“ค์–ด์˜ค๋ฉฐ, ์‚ฐ์ˆ  ํ—ˆ์šฉ๋Ÿ‰์„ ์ƒ์‹œ ์—ด์–ด๋‘์ง€ ์•Š๋Š”๋‹ค. **๊ฒฝ๊ณ ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์Šน๊ฒฉ๋˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ฒซ import ๋„ ์˜ˆ์™ธ๊ฐ€ ์•„๋‹ˆ๋‹ค. ์šฐํšŒ ํ”Œ๋ž˜๊ทธ๋Š” ์—†๋‹ค.** ์˜ˆ์ „์—” "๋นˆ ๊ฒƒ๋งŒ" ๋ง‰์•˜๋Š”๋ฐ, Samsung ์—ฌ๋Ÿฌ ์ŠคํŠธ๋ฆผ ์„ฑ๊ณต + aTimeLogger ์‹คํŒจ ๊ฐ™์€ **๋ถ€๋ถ„ ์„ฑ๊ณต**์€ ๊ทธ๋Œ€๋กœ ์šด์˜ DB ๊ฐ€ ๋๋‹ค. ๊ทธ ์ˆœ๊ฐ„ "๋ชป ๋ดค๋‹ค"๋ฅผ ๋งํ•  ์—๋Ÿฌ ๊ฒฝ๋กœ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค โ€” DB ๊ฐ€ ์žˆ์œผ๋‹ˆ ์ดํ›„๋กœ๋Š” ๊ทธ๋ƒฅ `[]` ๋‹ค. **๋ถˆ์™„์ „ํ•œ DB ๋Š” ์šด์˜ ์ž๋ฆฌ์— ์˜ค์ง€ ์•Š๋Š”๋‹ค.** ์ŠคํŠธ๋ฆผ ํ•˜๋‚˜๊ฐ€ ๋น ์ง„ DB ๋Š” ๊ทธ ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•ด ์˜์›ํžˆ `[]` ๋ฅผ ๋‹ตํ•˜๊ณ , ์†Œ๋น„์ž(๊ด€์ธก์†Œ)๋Š” ๊ทธ ๊ตฌ๋ฉ์„ 0 ์œผ๋กœ ๊ธฐ๋กํ•œ๋‹ค. **`rows` ์˜†์˜ `invalid` ๋ฅผ ๋ด๋ผ.** ํŒŒ์ผ์— ํ–‰์€ ์žˆ๋Š”๋ฐ ํ•„์ˆ˜ ํ•„๋“œ๊ฐ€ ์—†๊ฑฐ๋‚˜ ์‹œ๊ฐยทํ•„์ˆ˜ ์ˆ˜์น˜๊ฐ€ ํŒŒ์‹ฑ ์•ˆ ๋˜๋Š” ํ–‰ ์ˆ˜๋‹ค. Samsung ์ด ํ—ค๋” ํ•˜๋‚˜๋งŒ ๊ฐœ๋ช…ํ•˜๊ฑฐ๋‚˜ ์ˆซ์ž ์ž๋ฆฌ์— garbage๋ฅผ ๋„ฃ์–ด๋„ ์˜ˆ์ „์—” `empty` ๋˜๋Š” ์ธก์ •๊ฐ’ 0์œผ๋กœ ๋ณด์˜€๋‹ค (์ฒซ import ๋Š” baseline ์ด ์—†์–ด ๊ฒฝ๊ณ ์กฐ์ฐจ ์—†์—ˆ๋‹ค). **`invalid > 0` ์ด๋ฉด ์Šน๊ฒฉ์ด ๋ง‰ํžŒ๋‹ค.** ๋นˆ ์„ ํƒ ํ•„๋“œ๋Š” 0์œผ๋กœ ๋‘˜ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ’์ด ์žˆ๋Š”๋ฐ ์ฝํžˆ์ง€ ์•Š๋Š” ๊ฒƒ์€ 0์ด ์•„๋‹ˆ๋‹ค. **`atl_category` ๋Š” ๋…๋ฆฝ ์ŠคํŠธ๋ฆผ์ด๋‹ค.** `time` ์กฐํšŒ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ INNER JOIN ํ•˜๋ฏ€๋กœ, ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์‚ฌ๋ผ์ง€๋ฉด ๋ธ”๋ก ์ˆ˜๊ฐ€ ๊ทธ๋Œ€๋กœ์—ฌ๋„ **์‹œ๊ฐ„์ถ•์ด ์ „๋ฉธํ•œ๋‹ค.** ์˜ˆ์ „ ์›์žฅ์€ interval ๋งŒ ์„ธ์„œ ์ด ์†์‹ค์„ ๋ชป ๋ดค๋‹ค (`status: ok`, `warnings: []`, time 30์ผ โ†’ 0). ์„ธ์ง€ ์•Š๋Š” ์ŠคํŠธ๋ฆผ์€ ์žƒ์–ด๋„ ๋ชจ๋ฅธ๋‹ค. ๊ณ ์•„ ๋ธ”๋ก(์—†๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ธ”๋ก) ๊ฒ€์‚ฌ๋„ ํ•จ๊ป˜ ๋ˆ๋‹ค. *์™œ ์žˆ๋‚˜: 2026-07-14, ๊ธ€๋กญ ํ•˜๋‚˜๊ฐ€ 7MB stress ๋Œ€์‹  1KB histogram ์„ ์ง‘์–ด 27,598 ํ–‰์ด ํ†ต์งธ๋กœ 0 ์ด ๋๋Š”๋ฐ import ๋Š” `"ok"` ๋ผ๊ณ  ํ–ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋Š” ์ดˆ๋ก๋ถˆ์ด์—ˆ๋‹ค. ์žก์€ ๊ฑด ์ด ํ–‰์ˆ˜๊ฐ€ 203,539 โ†’ 175,941 ๋กœ ๋–จ์–ด์ง„ ๊ฑธ **์‚ฌ๋žŒ์ด ๋ˆˆ์œผ๋กœ ๋ณธ ๊ฒƒ**๋ฟ์ด์—ˆ๋‹ค. ์ด์ œ ๋„๊ตฌ๊ฐ€ ๋งํ•œ๋‹ค.* ### read โ€” Denote ID๋กœ ์กฐํšŒ ```bash lifetract read 20250115T000000 # Day ID โ†’ ๊ทธ๋‚  ์ข…ํ•ฉ lifetract read 2025-01-15 # ๊ฐ™์€ ๊ฒฐ๊ณผ (๋‚ ์งœ ๋‹จ์ถ•ํ˜•) lifetract read 20250115T233000 # Event ID โ†’ ๊ฐœ๋ณ„ ์ˆ˜๋ฉด/์šด๋™ ``` Day ์กฐํšŒ ์‹œ ๊ฑด๊ฐ• ๋ฉ”ํŠธ๋ฆญ + aTimeLogger ์‹œ๊ฐ„ ์นดํ…Œ๊ณ ๋ฆฌ + ์ˆ˜๋ฉด ์„ธ์…˜ + ์šด๋™ ๋ชจ๋‘ ํฌํ•จ. ### today โ€” ์˜ค๋Š˜ ์š”์•ฝ ```bash lifetract today ``` ```json // ๋ฐ์ดํ„ฐ ์žˆ๋Š” ๋‚  (read 2025-10-04 ํ˜•ํƒœ) {"date": "2025-10-04", "steps": 41382, "sleep_hours": 1.5, "avg_hr": 93.1, "stress_avg": 20.9, "time_categories": [...], "source": "db"} // ๋ฐ์ดํ„ฐ ์—†๋Š” ๋‚  โ€” DB ๊ฐ€ ๋นˆ ์ž๋ฆฌ๋Š” ์ž๋™์œผ๋กœ HA ๊ฐ€ ์ฑ„์›€ (phase 7 read-only fallback) {"date": "2026-05-26", "steps": 7099, "sleep_hours": 4.8, "avg_hr": 137, "stress_avg": 0, "source": "db+ha", "ha_sources": ["steps","heart_rate","sleep"]} ``` `time_categories` ๊ฐ€ ๋น„๋ฉด JSON ์—์„œ ํ‚ค ์ž์ฒด๊ฐ€ ๋น ์ง„๋‹ค (omitempty). ๋ฐ์ดํ„ฐ ์žˆ๋Š” ๋‚  vs ์—†๋Š” ๋‚  ๋‘˜ ๋‹ค ์ •์ƒ ์ถœ๋ ฅ. **์ž๋™ HA fallback (์˜ค๋Š˜ ์ž๋ฆฌ์— ํ•œ์ •)**: DB ๊ฐ€ ์˜ค๋Š˜ ์ž๋ฆฌ๋ฅผ ๋น„์› ์œผ๋ฉด (Samsung CSV ๊ฐ€ ์•„์ง ์•ˆ ๋“ค์–ด์™”์œผ๋ฉด) `today` ์™€ `read <์˜ค๋Š˜>` ์ด ์ž๋™์œผ๋กœ HA ๋ผ์ด๋ธŒ ๊ฐ’์œผ๋กœ ์ฑ„์šด๋‹ค. `source` ๊ฐ€ `"db+ha"` ๋กœ ๋ฐ”๋€Œ๊ณ , `ha_sources` ๊ฐ€ ์–ด๋–ค ํ•„๋“œ๊ฐ€ HA ์—์„œ ์™”๋Š”์ง€ ์•Œ๋ ค์ค€๋‹ค. *๊ณผ๊ฑฐ ๋‚ ์งœ๋Š” enrichment ์•ˆ ๋จ* โ€” HA recorder ๋Š” backfill ์ž๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋„๋ ค๋ฉด `LIFETRACT_NO_HA=1`. Sleep ์€ *์˜› row ๊ฐ€ ์˜ค๋Š˜๋กœ ์žกํžˆ๋Š” stale* ์ž๋ฆฌ๋„ ๊ฐ์ง€ํ•ด์„œ HA ๋กœ ๋ฎ์–ด์“ด๋‹ค (์ตœ๊ทผ 36h ์˜ sleep_duration history ๋ฅผ ํ•ฉ์‚ฐ โ€” main sleep + nap ๋‘˜ ๋‹ค ์žก์Œ). ### timeline โ€” ๋‚ ์งœ๋ณ„ ํšก๋‹จ ๋ทฐ ```bash lifetract timeline --days 7 lifetract timeline --days 30 ``` denotecli ์ €๋„๊ณผ ๊ฐ™์€ ๋‚ ์งœ ํ‚ค(`YYYYMMDDT000000`)๋กœ ์ •๋ ฌ. ๊ฑด๊ฐ•+์‹œ๊ฐ„+์šด๋™ ํ†ตํ•ฉ. ### sleep / steps / heart / stress / exercise ```bash lifetract sleep --days 7 lifetract sleep --days 30 --summary lifetract steps --days 7 lifetract heart --days 7 lifetract stress --days 7 lifetract exercise --days 30 ``` **๊ฑธ์Œ ์ˆ˜ ๊ณ„์•ฝ:** `steps_daily` ๋Š” ์ธก์ •์ผ๋งˆ๋‹ค ์ •ํ™•ํžˆ ํ•œ ํ–‰์ด๋‹ค. ๋‚ ์งœ๋Š” Samsung์˜ `day_time` ๋งŒ ์ฝ์œผ๋ฉฐ `create_time` ์œผ๋กœ ๋Œ€์‹ ํ•˜์ง€ ์•Š๋Š”๋‹ค. `day_time` ์€ epoch-ms์™€ ๋ฒฝ์‹œ๊ณ„ ๋ฌธ์ž์—ด ์–‘์ชฝ์„ ์ง€์›ํ•˜๊ณ , ๋ชป ์ฝ๊ฑฐ๋‚˜ ๋ฏธ๋ž˜๋ฉด invalid๋กœ ์Šน๊ฒฉ์„ ๋ง‰๋Š”๋‹ค. ๊ฐ™์€ ๋‚ ์˜ ์žฌ๋™๊ธฐํ™” ํ–‰์€ ์ตœ์‹  `update_time` ํ•œ ๊ฑด๋งŒ ๋‚จ๊ธฐ๋ฉฐ, ๋™์‹œ๊ฐ์— ๊ฐ’์ด ์ถฉ๋Œํ•˜๋ฉด ์ž„์˜๋กœ ๊ณ ๋ฅด์ง€ ์•Š๊ณ  invalid๋‹ค. DB๋„ ๋‚ ์งœ UNIQUE๋กœ ๊ฐ™์€ ๋ถˆ๋ณ€์‹์„ ๊ฐ•์ œํ•œ๋‹ค. ### time โ€” aTimeLogger ์‹œ๊ฐ„ ์ถ”์  ```bash lifetract time --days 7 lifetract time --days 30 --category ๋ณธ์ง“ ``` ์นดํ…Œ๊ณ ๋ฆฌ: ๋ณธ์ง“, ์ˆ˜๋ฉด, ๊ฐ€์กฑ, ์‹์‚ฌ, ๋…์„œ, ์šด๋™, ๊ฑท๊ธฐ, ์ˆ˜ํ–‰, ์…€ํ”„ํ† ํฌ, ๋‚ฎ์ž , ์ค€๋น„, ์ง‘์•ˆ์ผ, ์ด๋™, ์‡ผํ•‘, ๋”ด์ง“, ์œ ํŠœ๋ธŒ, ์งง์€ํœด์‹, ์—ฌ๊ฐ€ํ™œ๋™ (18์ข…) ### export โ€” ๊ณต๊ฐœ์šฉ ๋‚ด๋ณด๋‚ด๊ธฐ ๊ณ„ํš ```bash lifetract export ``` ### ha โ€” Home Assistant REST (live sensors) ```bash lifetract ha ping # ์—ฐ๊ฒฐ ํ™•์ธ lifetract ha state heart_rate # ๋„๋ฉ”์ธ ์ด๋ฆ„์œผ๋กœ ํ•œ sensor ๊ฐ€์ ธ์˜ค๊ธฐ lifetract ha state sleep_duration # (๋˜๋Š” literal entity_id ๋„ OK) lifetract ha states # ๋“ฑ๋ก๋œ 24๊ฐœ known sensor ์ผ๊ด„ ์กฐํšŒ lifetract ha entities # HA ๊ฐ€ ๋…ธ์ถœํ•˜๋Š” ๋ชจ๋“  entity (raw, known ํ”Œ๋ž˜๊ทธ ํ‘œ์‹œ) lifetract ha history sleep_duration --days 7 # 7์ผ์น˜ state ๋ณ€ํ™” (HA recorder) ``` ```json // ha state heart_rate { "entity_id": "sensor.sm_s942n_s26_glgman_heart_rate", "kind": "heart_rate", "state": "111.0", "value": 111, "unit": "bpm", "last_changed": "2026-05-17T22:34:11Z", "attributes": {...} } ``` **ํ† ํฐ**: `pass show 2fa/totp/ha/junghanacs` (primary) โ†’ env `HA_TOKEN` (fallback) โ†’ `~/.lifetract/ha.env`. ํ† ํฐ๊ฐ’ ์ž์ฒด๋Š” ์ ˆ๋Œ€ commit/push ๊ธˆ์ง€. **๋„๋ฉ”์ธ kind**: `sleep_duration`, `steps_daily`, `distance_daily`, `floors_daily`, `heart_rate`, `resting_heart_rate`, `heart_rate_variability`, `weight`, `body_fat`, `height`, `calories_burned`, `active_calories_burned`, `basal_metabolic_rate`, `hydration`, `detected_activity`, `geocoded_location`, `battery`, `sleep_confidence`, `respiratory_rate`, `oxygen_saturation`, `body_temperature`, `blood_glucose`, `systolic_blood_pressure`, `diastolic_blood_pressure` (24์ข…). ์ƒˆ sensor ์ถ”๊ฐ€ = `lifetract/ha_entities.go` ์˜ `KnownEntities` ์— ํ•œ ์ค„. **`ha history` ๋™์ž‘**: HA recorder ๋Š” *state ๋ณ€ํ™” ์‹œ์ ์—๋งŒ* row ์ €์žฅ. recorder 30์ผ ๋ณด๊ด€์€ "์žˆ๋Š” ๋ฐ์ดํ„ฐ ๋ณด์กด" ์ด์ง€ "์—†๋Š” ๋ฐ์ดํ„ฐ ์ฑ„์›Œ์คŒ" ์ด ์•„๋‹˜. HA ์ธํ”„๋ผ๊ฐ€ ๋„์›Œ์ง„ ์‹œ์  ์ด์ „ ๋ฐ์ดํ„ฐ๋Š” ์˜์›ํžˆ ์•ˆ ์žกํž˜. ๊ณผ๊ฑฐ๋Š” Samsung CSV export ๊ฐ€ ์œ ์ผํ•œ ๊ธธ. HA history = *๋‚ด์ผ๋ถ€ํ„ฐ์˜ ์ ๋ฆฝ* ์ž๋ฆฌ. ```json // ha history sleep_duration --days 7 { "entity_id": "sensor.sm_s942n_s26_glgman_sleep_duration", "kind": "sleep_duration", "unit": "min", "days": 7, "from": "2026-05-11T...+09:00", "to": "2026-05-18T...+09:00", "count": 2, "points": [ {"last_changed": "...", "value": 427, "unit": "min", "attributes": {"endTime": "..."}}, ... ] } ``` **ํ˜„์žฌ ์ƒํƒœ (phase 7 read-only)**: `cmdToday` / `cmdRead <์˜ค๋Š˜>` ์ด DB miss ๋˜๋Š” stale sleep ์ž๋ฆฌ์—์„œ ์ž๋™์œผ๋กœ HA `GetState` + `GetHistory` ๋ฅผ ํ˜ธ์ถœํ•ด ์‘๋‹ต์— ์ฑ„์›Œ์ค€๋‹ค (`source: "db+ha"`, `ha_sources: [...]`). DB upsert ๋Š” ์˜๋„์ ์œผ๋กœ ํ•˜์ง€ ์•Š๋Š”๋‹ค. Samsung export ๊ฐ€ ์˜๊ตฌ SSOT์ด๊ณ  HA recorder ๋Š” 30์ผ ๋ณด์กฐ๋ฉด์ด๋ผ, ๋œ ์•„๋Š” ๊ฐ’์„ ๋ณธ DB์— ํก์ˆ˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. ## Flags | Flag | Default | ์„ค๋ช… | |------|---------|------| | `--days N` | 7 | ์ฐฝ ๊ธธ์ด (**๋ฌด์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค** โ€” ์•„๋ž˜ ์กฐํ•ฉํ‘œ) | | `--from YYYY-MM-DD` | โ€” | ์ฐฝ ์‹œ์ž‘ (ํฌํ•จ) | | `--to YYYY-MM-DD` | โ€” | ์ฐฝ ๋ (**๋ฐฐํƒ€์ **) | | `--data-dir DIR` | `~/repos/gh/self-tracking-data` | ๋ฐ์ดํ„ฐ ๋ฃจํŠธ | | `--shealth-dir DIR` | ์ตœ์‹  ์ž๋™๊ฐ์ง€ | Samsung Health ๋””๋ ‰ํ† ๋ฆฌ | | `--summary` | false | ์š”์•ฝ ๋ชจ๋“œ | | `--category CAT` | ์ „์ฒด | ์‹œ๊ฐ„ ์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ | | `--exec` | false | import ์‹คํ–‰ ๋ชจ๋“œ | ### ์ฐฝ ์กฐํ•ฉ โ€” ๋ชจ๋“  ์กฐํ•ฉ์ด ๋œป์„ ๊ฐ–๋Š”๋‹ค | ์กฐํ•ฉ | ์ฐฝ | |------|-----| | `--days N` | `[๋‚ด์ผ-N, ๋‚ด์ผ)` โ€” **์˜ค๋Š˜ ํฌํ•จ ์ •ํ™•ํžˆ N์ผ** (`1`=์˜ค๋Š˜) | | `--days N --to T` | `[T-N, T)` โ€” **T ์— ๋๋‚˜๋Š” N์ผ** | | `--days N --from F` | `[F, F+N)` โ€” **F ์— ์‹œ์ž‘ํ•˜๋Š” N์ผ** | | `--from F --to T` | `[F, T)` | | `--from F` | `[F, ๋‚ด์ผ)` |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub