sincenety
v0.8.4
Published
Claude Code 작업 갈무리 도구 — 작업 이력 자동 분석 및 구조화된 기록 생성
Maintainers
Readme
sincenety
Automatic work session tracker for Claude Code — A 3-phase pipeline that retroactively collects, summarizes, and reports all Claude Code activity. No start/stop needed.
$ sincenety
☁️ D1 sync complete
☁️ D1 sync complete
✅ sincenety complete — 1 sent, 0 skipped
$ sincenety air
📋 air complete
Date range: 3 days (backfill 2 days)
Total sessions: 12
Changed dates: 2
Changed: 2026-04-06, 2026-04-07
$ sincenety circle
📋 circle complete
Date range: 3 days
Total sessions: 12
Changed dates: 2
Finalized: 2026-04-06
Needs summary: 2026-04-07Features
Default Command: Full Pipeline
v0.7.0 — Running sincenety with no arguments executes the entire pipeline automatically: air → circle → out. This is the recommended way to use sincenety — one command does everything.
If D1 or email is not configured, it shows help + setup instructions instead.
3-Phase Pipeline: air → circle → out
The pipeline can also be run in individual phases:
sincenety air— Collect and store work records by date- Date-based grouping (midnight boundary, startedAt-based)
- Automatic backfill: checkpoint-based, collects empty dates too
- Change detection: data hash skips unchanged dates
- Empty day records (no sessions = still recorded)
--jsonoutputs per-date JSON
sincenety circle— LLM-powered summaries- Internally runs
airfirst --json: outputs session data for AI summary (SKILL.md integration)--save: saves stdin JSON todaily_reports--type daily|weekly|monthly- Auto-finalization: midnight finalizes previous day, Monday finalizes previous week, 1st finalizes previous month
- Change detection: data hash comparison saves tokens
- Vacation days get a [vacation] label automatically
- Project-level session merge: all sessions within the same
projectNameare individually summarized, then consolidated into a single merged summary per project — eliminates duplicate entries and improves report coherence
- Internally runs
sincenety out— Smart email deliveryout: daily always, +weekly on Friday, +monthly on month-end- Unsent catchup: missed Friday → Monday auto-sends weekly
- 4 providers: Gmail MCP / Resend / Gmail SMTP / Custom SMTP
outd/outw/outm: force daily / weekly / monthly--preview,--render-only,--history
CLI Commands
| Command | Description |
|---------|-------------|
| sincenety | Full pipeline — air → circle → out in one command |
| sincenety air | Collect — date-grouped auto-backfill gathering |
| sincenety circle | Summarize — LLM summary (--json/--save/--type) |
| sincenety out | Smart dispatch (weekday + unsent catchup) |
| sincenety outd | Force send daily report |
| sincenety outw | Force send weekly report |
| sincenety outm | Force send monthly report |
| sincenety sync | D1 central cloud sync |
| sincenety config | Settings (--setup, --vacation, --d1-*) |
Retroactive Work Gathering
No need to remember to start/stop tracking. sincenety parses ~/.claude/ data at runtime and reconstructs everything:
- Session JSONL parsing — Extracts token usage, model names, millisecond-precision timestamps, and conversation turns from
~/.claude/projects/[project]/[sessionId].jsonl - Checkpoint-based backfill — Automatically fills gaps from last checkpoint; first run backfills 90 days
Rich Work Records
| Field | Description | |-------|-------------| | Title | Auto-extracted from first user message | | Description | Top 3-5 user messages joined | | Token usage | Per-message input/output/cache token aggregation | | Duration | First message → last message precise measurement | | Model | Extracted from assistant responses | | Category | Auto-classified from project path |
AI Summarization Engine
Unified AI provider system — ai_provider config is respected in all environments (CLI, cron, Claude Code):
| ai_provider | circle auto-summary | gatherer summary | Typical use case |
|----------------|----------------------|-------------------|-----------------|
| cloudflare | Workers AI (Qwen3-30B) → heuristic fallback | Workers AI | CLI / cron |
| anthropic | Skip (no auto-summary) | Claude API (Haiku) | API key available |
| claude-code | Skip (SKILL.md handles it) | Heuristic | Claude Code /sincenety |
| auto (default) | Auto-detect: cloudflare only | Auto-detect | First-time setup |
# AI provider configuration (controls behavior in ALL environments)
sincenety config --ai-provider cloudflare # Use Workers AI
sincenety config --ai-provider anthropic # Use Claude API
sincenety config --ai-provider claude-code # Claude Code direct summary (SKILL.md)
sincenety config --ai-provider auto # Auto-detect (default)
# Check current settings
sincenety config
# → AI summary: ai_provider = auto (auto → cloudflare)- Cloudflare Workers AI (Qwen3-30B) for Korean text summarization
- D1 token only needed — no separate API key required
circleauto-summarizes whenai_provideriscloudflare: per-session topic/outcome/flow/significance + daily overviewcircle --json --summarize: Workers AI summaries included in JSON output (requiresai_provider = cloudflare)- Free tier: 10,000 neurons/day (sufficient for personal use, ~300 summaries/day)
- Heuristic fallback: if Workers AI call fails for a session, falls back to heuristic summary (no data loss)
Email AI Summary Integration
Email reports include AI-generated summaries from daily_reports:
- Overview section at the top of each email with a full-day summary
- Per-session mapping:
daily_reportswrapUp data maps to each session's topic/outcome/flow/significance - Gmail 102KB clip prevention: actions capped at 5 per session, text length optimized to stay under Gmail's clipping threshold
Required Setup (Mandatory)
sincenety requires two configurations before any command can run:
- D1 Cloud Sync — Cloudflare API token (enables Workers AI + cloud sync)
- Email Delivery — SMTP or Resend (enables report email delivery)
# Step 1: D1 token (auto-detects account, creates DB, enables Workers AI)
sincenety config --d1-token <API_TOKEN>
# Step 2: Email setup (interactive wizard)
sincenety config --setup
# → Gmail app password: https://myaccount.google.com/apppasswordsAll commands (air, circle, out, sync, etc.) will refuse to run until both are configured. Only config is exempt.
Vacation Management
- Google Calendar auto-detection — SKILL.md instructs Claude Code to check Google Calendar for vacation events
- CLI manual registration —
config --vacation 2026-04-10 2026-04-11 - Vacation keywords (Korean + English): 휴가/vacation/연차/PTO/병가/sick/반차/half-day
- Vacation types: vacation / sick / holiday / half / other
- Report integration — vacation days get a [vacation] label in
circle;outskips vacation days automatically
Config Setup Wizard
Run sincenety config --setup for an interactive 3-choice wizard:
- Gmail SMTP (with app password URL guidance)
- Resend API
- Custom SMTP
Connection test runs automatically on setup completion.
Gmail MCP Integration
Zero-config email delivery inside Claude Code via gmail_create_draft MCP tool. No SMTP credentials needed — Claude Code drafts the email directly in Gmail. Use out --render-only to get HTML output for the MCP path.
Config Management
Run sincenety config with no arguments to see a formatted settings status table. Supports vacation registration, email provider selection (Gmail/Resend/custom SMTP), and more.
Scope Selection (Global / Project)
Choose whether to track all projects on this machine or a specific project only:
- Global mode — collects all Claude Code sessions across all projects
- Project mode — filters to sessions from a single project path
Scope is set during initial setup (npm install -g) or on first npx sincenety run. Stored at ~/.sincenety/scope.json.
Cloud Sync (Cloudflare D1)
Multi-machine data aggregation via Cloudflare D1:
- Local-first: encrypted local DB remains the source of truth
sincenety syncpushes local data to a central D1 database (push / pull-config / status / init)- Auto-sync after
outcompletes (non-fatal — network errors don't block email delivery) - Shared config: SMTP settings set once,
sync --pull-configon new machines to pull shared config - Machine ID: hardware-based auto-detection (see below),
config --machine-nameoverride for custom identification - Zero new dependencies: uses native
fetchfor D1 REST API — no extra packages added
Pipeline Mode Switch & Auto Weekly/Monthly Baseline
v0.8.4 — out/outd/outw/outm now always have a fresh weekly/monthly baseline in the DB, closing the gap where outw/outm could silently produce empty results:
- Auto baseline generation: On every run, the pipeline aggregates this week's (Mon–Sun) and this month's (1st–last day)
daily_reports, runs project-level consolidation, and upserts the weekly/monthly row - Emailed-report protection: Rows with
emailedAt != nullare never overwritten, preserving already-delivered reports --mode=full|smartswitch:full(default) regenerates baselines every run;smartpreserves v0.8.3 behavior (weekly only on Friday, monthly only on month-end — token-saving)- Config-level default:
sincenety config --pipeline-mode <full|smart>stores a persistent default - Silent failure hardening: Auto-summary failures are structured into
CircleResult.summaryErrors, promoted toresult.errorsbyrunOut, and propagated to CLI exit code (process.exitCode = 1) — cron environments can now detect weekly/monthly refresh failures via exit code emailedAt === 0falsy guard fixed: Explicit!= nullcomparison prevents edge-case overwrite of already-sent reports- JSON.parse warnings: Corrupted
summaryJsonin a daily row now emits a warning with the failingreportDateinstead of silently dropping data
Cross-Device Consolidated Reports
v0.8.0 — When working on multiple machines (e.g., Mac + Linux), sessions from all devices are automatically merged into a single daily report:
- Push-before-pull: local data is pushed to D1 first, then other devices' sessions are pulled for consolidation
- Circle cross-device merge:
circle(AI summarization) pulls other devices' sessions from D1 and generates a unified summary covering all machines — not just local work - Always-send policy:
outalways sends email regardless of whether another device already sent — no skip, no dedup - Session merge by topic: sessions with identical
projectName + titleare automatically merged — stats aggregated, best wrapUp selected, flow narratives concatenated - Graceful fallback: if D1 is unreachable, falls back to single-device local-only behavior
- Title extraction improvement: sessions starting with slash commands (e.g.,
/sincenety) now get meaningful fallback titles instead of empty strings
Cloudflare API Token Setup
- Go to dash.cloudflare.com/profile/api-tokens
- "Create Token" → "Custom token" (click "Get started" at the bottom)
- Set permissions:
| Permission | Access | Purpose |
|-----------|--------|---------|
| Account / D1 | Edit | DB creation + read/write |
| Account / Workers AI | Read | AI summary model (Qwen3-30B) |
| Account / Account Settings | Read | Account auto-detection on --d1-token setup |
All 3 are required. Without Account Settings Read,
--d1-tokensetup cannot find your account.
- Account Resources → Include → select your account
- "Create Token" → copy the token (shown only once!)
This single token powers D1 (central DB) + Workers AI (summary engine) + sync.
Token-Only D1 Setup
A single token is all you need. Everything else is auto-detected:
sincenety config --d1-token cfp_xxxxxxxx
# ✅ Account auto-detected
# ✅ D1 database auto-created/connected
# ✅ machine_id auto-detected (hardware UUID-based)
# ✅ Workers AI auto-enabled (Qwen3-30B)
# ✅ Schema setup completeAuto Machine ID
Hardware-based machine identification — zero configuration needed:
| Platform | Source | Characteristics | |----------|--------|-----------------| | macOS | IOPlatformUUID | Hardware-unique, survives OS reinstall | | Linux | /etc/machine-id | OS-unique | | Windows | MachineGuid | Install-unique |
- Format:
mac_a1b2c3d4_username - Auto-detected with no user action required
- Same machine always produces the same ID
- Used for D1 sync machine registry (
machinestable)
Encrypted Storage
All data is AES-256-GCM encrypted at ~/.sincenety/sincenety.db. Machine-bound key (hostname + username + random salt) by default.
Installation & Setup
There are two ways to run sincenety: npx (no install) or global install.
Option A: npx (recommended for first-time / one-shot use)
All three flags are required on first run. Without them, sincenety will show setup instructions and exit.
Prerequisites — get your tokens first:
Cloudflare D1 API Token — dash.cloudflare.com/profile/api-tokens
- Create a Custom token with these permissions:
| Permission | Access | Purpose | |-----------|--------|---------| | Account / D1 | Edit | DB creation + read/write | | Account / Workers AI | Read | AI summarization (Qwen3-30B) | | Account / Account Settings | Read | Account auto-detection |
Resend API Key — resend.com/api-keys
- Free tier: 100 emails/day (more than enough for daily reports)
Run:
npx sincenety --token <D1_TOKEN> --key <RESEND_KEY> --email [email protected]This single command will:
- Save D1 token → auto-detect Cloudflare account → create DB → setup schema
- Save Resend API key + recipient email
- Run the full pipeline: air → circle → out
Subsequent runs — config persists in ~/.sincenety/, so you only need:
npx sincenetyOption B: Global install (recommended for daily use)
npm install -g sincenety@latestThe installer runs an interactive setup wizard:
┌──────────────────────────────────────────────┐
│ sincenety — Initial Setup │
└──────────────────────────────────────────────┘
── Step 1/3: Scope ─────────────────────────────
1) Global — track all Claude Code projects on this machine
2) Project — track only a specific project
── Step 2/3: D1 Cloud Sync ─────────────────────
Guided Cloudflare API token creation with required permissions:
Account | Workers AI | Read
Account | D1 | Edit
Account | Account Settings | Read
── Step 3/3: Email Delivery ────────────────────
1) Gmail SMTP (app password required)
2) Resend API (resend.com API key)
3) Custom SMTPAfter setup, just run:
sincenetyNote: The setup wizard only runs on first install. Subsequent updates preserve your configuration. In non-TTY environments (CI/Docker), the wizard is skipped — configure manually with
sincenety config --setup.
Build from source
git clone https://github.com/pathcosmos/sincenety.git
cd sincenety
npm install && npm run build
npm linkVerify setup
sincenety config
# Shows all settings with ✅/❌ status
# AI summary: ai_provider = auto (auto → cloudflare)Usage
Default — Full Pipeline
# Run the entire pipeline: air → circle → out
sincenety
# If D1 or email is not configured, shows help + setup instructionsair — Collect Work Records
# Collect all sessions (checkpoint-based backfill, first run = 90 days)
sincenety air
# Specify custom history.jsonl path
sincenety air --history /path/to/history.jsonl
# JSON output (per-date structured data)
sincenety air --jsoncircle — AI Summary Pipeline
# Run air + check finalization status
sincenety circle
# Output session data as JSON for AI summary (SKILL.md integration)
sincenety circle --json
# Output with Workers AI summaries included (for SKILL.md cloudflare mode)
sincenety circle --json --summarize
# Save AI-generated summary to DB (stdin JSON)
sincenety circle --save < summary.json
sincenety circle --save --type weekly < weekly_summary.json
sincenety circle --save --type monthly < monthly_summary.jsonconfig — Settings Management
# Interactive setup wizard (Gmail SMTP / Resend / Custom SMTP)
sincenety config --setup
# Show current settings (ANSI table)
sincenety config
# Email settings
sincenety config --email [email protected]
sincenety config --smtp-user [email protected]
sincenety config --smtp-pass # Prompted securely
sincenety config --provider resend
sincenety config --resend-key rk_...
# AI provider (controls Claude Code behavior)
sincenety config --ai-provider cloudflare # Workers AI
sincenety config --ai-provider anthropic # Claude API
sincenety config --ai-provider claude-code # Claude Code direct summary
sincenety config --ai-provider auto # Auto-detect (default)
# Vacation management
sincenety config --vacation 2026-04-10 2026-04-11
sincenety config --vacation-list
sincenety config --vacation-clear 2026-04-10Generate Gmail app password: https://myaccount.google.com/apppasswords
out — Smart Email Delivery
# Smart dispatch (daily always, +weekly on Friday, +monthly on month-end)
sincenety out
# Preview (no send)
sincenety out --preview
# HTML JSON output (for Gmail MCP)
sincenety out --render-only
# View send history
sincenety out --history
# Force send specific report type
sincenety outd # daily report
sincenety outw # weekly report
sincenety outm # monthly report
# Target specific date (yyyyMMdd)
sincenety outd --date 20260408 # daily report for Apr 8
sincenety outw --date 20260408 # weekly report for week of Apr 6-12
sincenety outm --date 20260408 # monthly report for April 2026
sincenety out --date 20260408 # smart dispatch as if today is Apr 8sync — Cloud Sync (Cloudflare D1)
# D1 configuration
sincenety config --d1-account ACCOUNT_ID --d1-database DB_ID --d1-token TOKEN
sincenety config --machine-name "office-mac"
# Sync operations
sincenety sync --init # Create D1 schema
sincenety sync # Push local → D1
sincenety sync --pull-config # Pull shared config from D1
sincenety sync --status # Check sync statusClaude Code Skill (/sincenety)
Use /sincenety directly inside Claude Code sessions for AI-powered daily reports.
Installation
- Install the CLI (provides the data collection engine):
npm install -g sincenety@latest- Install the skill (registers
/sincenetycommand in Claude Code):
mkdir -p ~/.claude/skills/sincenety
cp node_modules/sincenety/src/skill/SKILL.md ~/.claude/skills/sincenety/SKILL.mdOr if installed globally:
mkdir -p ~/.claude/skills/sincenety
cp "$(npm root -g)/sincenety/src/skill/SKILL.md" ~/.claude/skills/sincenety/SKILL.md- Update to latest version:
Inside Claude Code, run:
! npm install -g sincenety@latestHow it works
When you type /sincenety inside Claude Code:
- Data collection —
aircollects all sessions with checkpoint-based backfill - JSON output —
circle --jsonoutputs session data with conversation turns - AI summary — Claude Code itself analyzes and generates topic/outcome/flow/significance
- Save to DB —
circle --savewrites summary todaily_reports - Email — If configured, sends an HTML email with AI summary
The key insight: Claude Code is the AI — no external API key needed.
Email setup (optional)
sincenety config --email [email protected]
sincenety config --smtp-user [email protected]
sincenety config --smtp-pass # Prompts for Gmail app passwordGenerate Gmail app password: https://myaccount.google.com/apppasswords
Architecture
sincenety/
├── src/
│ ├── cli.ts # CLI entry (default + air/circle/out/outd/outw/outm/sync/config)
│ ├── postinstall.ts # postinstall setup wizard (scope → D1 → email)
│ ├── core/
│ │ ├── air.ts # Phase 1: date-based gathering (backfill + hash)
│ │ ├── circle.ts # Phase 2: LLM summary pipeline (finalization + save)
│ │ ├── out.ts # Phase 3: smart email dispatch (out/outd/outw/outm)
│ │ ├── gatherer.ts # Core gathering logic (parse → group → store)
│ │ ├── summarizer.ts # AI summarization router (Workers AI / Claude API / heuristic)
│ │ └── ai-provider.ts # AI provider detection & routing (cloudflare/anthropic/claude-code)
│ ├── parser/
│ │ ├── history.ts # ~/.claude/history.jsonl streaming parser
│ │ └── session-jsonl.ts # Session JSONL parser (tokens/model/timing/turns)
│ ├── grouper/session.ts # Session grouping by sessionId + project
│ ├── storage/
│ │ ├── adapter.ts # StorageAdapter interface
│ │ └── sqljs-adapter.ts # sql.js implementation (encrypted DB, v4 migration)
│ ├── encryption/
│ │ ├── key.ts # PBKDF2 key derivation (machine-bound + passphrase)
│ │ └── crypto.ts # AES-256-GCM encrypt/decrypt
│ ├── report/
│ │ ├── terminal.ts # Terminal output formatter
│ │ └── markdown.ts # Markdown report generator
│ ├── email/
│ │ ├── sender.ts # nodemailer email sender
│ │ ├── renderer.ts # HTML email renderer (report → HTML, cross-device merge)
│ │ ├── merge-sessions.ts # Session merge by project (dedup same-project sessions)
│ │ ├── resend.ts # Resend API email provider
│ │ ├── provider.ts # Email provider abstraction (Gmail MCP/Resend/SMTP)
│ │ └── template.ts # Bright color-coded HTML email template
│ ├── vacation/
│ │ ├── manager.ts # Vacation CRUD (register/list/clear/check)
│ │ └── detector.ts # Vacation keyword detection (KO+EN)
│ ├── config/
│ │ ├── setup-wizard.ts # Interactive 3-choice setup wizard
│ │ └── scope.ts # Scope config (global/project) read/write/prompt
│ ├── cloud/
│ │ ├── d1-client.ts # Cloudflare D1 REST API client
│ │ ├── d1-schema.ts # D1 schema definition & migration
│ │ ├── d1-auto-setup.ts # Token-only auto-setup (account/DB detection)
│ │ ├── cf-ai.ts # Cloudflare Workers AI client (Qwen3-30B)
│ │ └── sync.ts # Sync logic (push/pull/status/init)
│ ├── util/
│ │ └── machine-id.ts # Cross-platform hardware ID detection
│ ├── scheduler/install.ts # launchd/cron auto-installer (disabled)
│ └── skill/SKILL.md # Claude Code skill definition
├── tests/
│ ├── encryption.test.ts # Encryption tests (26 cases)
│ ├── migration-v4.test.ts # DB v3→v4 migration tests (7 cases)
│ ├── air.test.ts # air command tests (7 cases)
│ ├── circle.test.ts # circle command tests (39 cases)
│ ├── out.test.ts # out command tests (47 cases)
│ ├── vacation.test.ts # Vacation management tests (13 cases)
│ ├── d1-client.test.ts # D1 client tests
│ ├── sync.test.ts # Sync tests
│ ├── cf-ai.test.ts # Cloudflare Workers AI tests
│ └── machine-id.test.ts # Machine ID detection tests
├── package.json
└── tsconfig.jsonInstall Flow
npm install -g sincenety@latest
│
▼
┌─ postinstall.js ─────────────────────────────────┐
│ │
│ TTY check ───→ No TTY? → "Run config --setup" │
│ │ │
│ ▼ (TTY) │
│ Already configured? ──→ Yes → "Updated. OK" │
│ │ │
│ ▼ (No) │
│ │
│ Step 1: Scope │
│ ┌────────────────────────┐ │
│ │ 1) Global (all) │ │
│ │ 2) Project (path) │ │
│ └───────┬────────────────┘ │
│ │ → ~/.sincenety/scope.json │
│ ▼ │
│ Step 2: D1 Cloud Sync │
│ ┌────────────────────────┐ │
│ │ D1 API token input │ │
│ │ → autoSetupD1() │ │
│ │ → ensureD1Schema() │ │
│ └───────┬────────────────┘ │
│ │ → ~/.sincenety/sincenety.db │
│ ▼ │
│ Step 3: Email │
│ ┌────────────────────────┐ │
│ │ 1) Gmail SMTP │ │
│ │ 2) Resend API │ │
│ │ 3) Custom SMTP │ │
│ └───────┬────────────────┘ │
│ │ → ~/.sincenety/sincenety.db │
│ ▼ │
│ ✅ Ready │
└───────────────────────────────────────────────────┘Run Flow
$ sincenety [--token T --key K --email E]
│
▼
Scope check ───→ missing? → prompt (global/project)
│
▼
Param check ───→ missing D1/email? → show setup guide + exit
│
▼
┌─ runOut(scope) ──────────────────────────────────┐
│ │
│ ┌─ air ─────────────────────────────────────┐ │
│ │ ~/.claude/history.jsonl │ │
│ │ → session list (sessionId + project) │ │
│ │ ~/.claude/projects/[p]/[id].jsonl │ │
│ │ → tokens / model / timing / turns │ │
│ │ │ │
│ │ scope filter (project mode) │ │
│ │ date grouping (midnight boundary) │ │
│ │ checkpoint backfill + data hash │ │
│ │ → gather_reports DB │ │
│ └───────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─ circle ──────────────────────────────────┐ │
│ │ auto-finalization │ │
│ │ (yesterday / last week / last month) │ │
│ │ D1 cross-device session pull + merge │ │
│ │ Workers AI summary (Qwen3-30B) │ │
│ │ → daily_reports DB (all devices) │ │
│ └───────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─ D1 pre-sync ────────────────────────────┐ │
│ │ push local → D1 (my data first) │ │
│ └──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─ out (smart dispatch) ────────────────────┐ │
│ │ daily — always │ │
│ │ weekly — Friday (or catchup) │ │
│ │ monthly — month-end (or catchup) │ │
│ │ --date yyyyMMdd — target specific date │ │
│ │ │ │
│ │ D1 cross-device session pull + merge │ │
│ │ Project-level session merge (×N) │ │
│ │ │ │
│ │ → Gmail MCP / Resend / │ │
│ │ Gmail SMTP / Custom SMTP │ │
│ └───────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─ D1 post-sync ───────────────────────────┐ │
│ │ push email logs → D1 │ │
│ └──────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────┘
│
▼
✅ sincenety complete — N sent, N skippedEncryption
- Algorithm: AES-256-GCM (authenticated encryption)
- Key derivation: PBKDF2 (SHA-256, 100,000 iterations)
- Key source:
hostname + username + random salt(machine-bound) - Salt:
~/.sincenety/sincenety.salt(32-byte random, created once, mode 0600) - File format:
[4B magic "SNCT"][12B IV][ciphertext][16B auth tag]
DB Schema (v4)
| Table | Description |
|-------|-------------|
| sessions | Per-session work records (22 columns — tokens, timing, title, description, model, etc.) |
| gather_reports | Report per gather run (markdown + JSON, report_date, data_hash, updated_at) |
| daily_reports | AI-generated summaries (status, progress_label, data_hash; UNIQUE(report_date, report_type)) |
| checkpoints | Last processed timestamp |
| config | Settings (email, SMTP, provider, etc.) |
| vacations | Vacation/holiday dates (date, type, source, label) |
| email_logs | Email delivery logs |
Auto-migration: v1 → v2 → v3 → v4
Tech Stack
| Component | Technology | |-----------|------------| | Language | TypeScript (ESM, Node16 modules) | | Runtime | Node.js >= 18 | | CLI | commander | | DB | sql.js (WASM SQLite, zero native deps) | | Encryption | Node.js built-in crypto (AES-256-GCM) | | Email | nodemailer (Gmail SMTP), Resend API | | Cloud | Cloudflare D1 REST API (native fetch, zero extra deps) | | AI Summarization | Cloudflare Workers AI (Qwen3-30B), zero extra deps | | Tests | vitest (128 cases across 11 test files) |
Development
npm install # Install dependencies
npm run build # Compile TypeScript (dist/)
npm run dev # Run with tsx (dev mode)
npm test # Run vitest tests (171 cases)
node dist/cli.js # Direct executionChangelog
v0.8.4 (2026-04-11) — Pipeline mode switch + auto weekly/monthly baseline + silent failure hardening
Highlights
- Auto weekly/monthly baseline generation:
out/outd/outw/outmnow regenerate this week's weekly and this month's monthly row on every run. Closes the gap whereoutw/outmpreviously produced empty results when weekly/monthly rows didn't exist in the DB (only daily_reports had rows). Already-sent reports (emailedAt != null) are protected from overwrite. --mode=full|smartpipeline switch: New CLI flag andconfig --pipeline-modesetting.full(default) regenerates weekly/monthly baselines on every run;smartpreserves v0.8.3 behavior (token-saving, weekday trigger only — weekly on Friday, monthly on month-end). The resolved mode is CLI option > config value > defaultfull.- Silent failure hardening: Several paths that previously swallowed errors now surface them through structured error channels, visible in CLI exit codes for cron monitoring.
Core changes
autoSummarizeWeekly/autoSummarizeMonthly(src/core/circle.ts): Gather this week's (Mon–Sun) or this month's (1st–last day)daily_reports, flatten theirsummaryJsonsessions, runmergeSummariesByTitlefor project-level consolidation, and upsert the weekly/monthly row. Both functions share a private helpersummarizeRangeIntothat handles the aggregation, period boundary computation, and upsert logic.PipelineModetype centralization (src/core/out.ts): Single source of truth — exportsPIPELINE_MODESconstant array,PipelineModeliteral union type,isPipelineMode()runtime type guard, andPIPELINE_MODE_CONFIG_KEYconstant. Replaces 4 copies of inline"smart" | "full"literals previously scattered acrossout.ts,circle.ts, andcli.ts.resolvePipelineMode(): Pure precedence function — explicit option > config value > default"full". Invalidconfiguredvalues (e.g., typo, old version data) silently fall back to"full"— validated byconfig --pipeline-modeon write.CircleResult.summaryErrors: New field capturing per-type auto-summary failures as{type: "weekly" | "monthly"; error: string}[].collectUnrecordedSummaryErrors(): Pure helper inout.tsthat promotescircleResult.summaryErrorstoOutResultEntryerror entries, deduplicating against existing render-loop entries.runOutrestructuring: Collects orphansummaryErrorsas global error entries immediately afterrunCircle(before vacation/force/reportTypes branching) — so failures surface even whenoutexits via the vacation early return or when the failed type is not inreportTypes.- CLI exit code propagation:
out/outd/outw/outmnow setprocess.exitCode = 1whenresult.errors > 0. UsesexitCode(notprocess.exit(1)) so thefinallyblock still runsstorage.close()for sql.js WASM DB flush safety.
Bug fixes
config --pipeline-mode smrtsilently exited 0: The validation path usedconsole.log+ fall-through without setting a non-zero exit code — automation couldn't detect typos. Now usesconsole.error+process.exit(1)consistent without --modevalidation elsewhere.emailedAt === 0falsy guard (src/core/circle.ts): The existing guardif (existing?.emailedAt) return falsewould classifyemailedAt === 0as "not emailed" (falsy) and allow overwriting an already-sent report.Date.now()can never return 0, but manual DB inserts or buggy write paths could produce this value. Replaced with explicit null check:if (existing && existing.emailedAt != null) return false.- JSON.parse silent drop:
summarizeRangeInto'stry { JSON.parse(...) } catch {}swallowed all exceptions without any log — a corrupted daily row would cause that day's sessions to silently vanish from the weekly/monthly aggregate, undercounting totals. Now narrows toSyntaxError, emitsconsole.warnwith the failingreportDate, and re-throws other error classes (e.g.,TypeErrorfrom unexpected shapes). - Dead
"finalized"branch removed:summarizeRangeIntohad astatus = todayTs <= periodTo ? "in_progress" : "finalized"line, but both callers (autoSummarizeWeekly,autoSummarizeMonthly) derive the range fromtoday— sotodayis structurally always within[rangeFrom, rangeTo]and the"finalized"branch was unreachable. Hardcoded to"in_progress"; the period-end transition remains handled byfinalizePreviousReportsas before.
Test improvements
171 tests passing (baseline 151 → +20 new tests). All new tests follow TDD red → green.
autoSummarizeWeekly/autoSummarizeMonthly— 8 tests: creates row from this week's/month's dailies, status isin_progress, no-data skip, upsert unemailed row, protects emailed row with full snapshot comparison (8 fields:summaryJson,overview,sessionCount,totalMessages,totalTokens,emailedAt,emailTo,createdAt),emailedAt === 0falsy guard.summarizeRangeIntoJSON corruption — 3 tests: malformed JSON warns withreportDateand continues with other dailies, non-array JSON (e.g.,"null","{}") is skipped, emptysummaryJsonstring is skipped.- Boundary cases — 5 tests: Sunday as today (exercises
getWeekBoundarySunday-specific branch), Monday as today, December→January month rollover, February 2028 leap year (includes Feb 29), February 2027 non-leap (excludes Mar 1). runCirclesummaryErrors propagation — 4 tests using a Proxy-wrapped throwingStorageAdapter: weekly failure recorded without aborting monthly, monthly failure recorded independently, smart mode skips weekly/monthly entirely (no errors even when would fail), healthy storage returns emptysummaryErrors.resolvePipelineMode— 7 tests: defaults tofull, explicit option override, config fallback, invalid values fall back tofull.collectUnrecordedSummaryErrors— 7 tests: empty input, promotes weekly/monthly to error entries, deduplication against existing entries, multiple failures, error message format embeds type label.- "Preserves emailed" tests strengthened: previously asserted only
projectName === "sent"andemailedAtpreservation (a false-confidence test that would pass even if aggregation ran). Now captures a full before-snapshot and asserts all 8 fields unchanged after, including a sentinel daily with totals that would change the aggregate if overwrite occurred. - Manual fault injection smoke tests:
runOutagainst a throwing storage Proxy confirmed Gap B fix — weekly failure on a vacation day now reportsresult.errors = 1and exit 1, and aforce: weeklyrun with a failing monthly auto-summary correctly records the orphaned monthly error.
Documentation
- SKILL.md — new "파이프라인 모드 (v0.8.4+)" section: explains
full/smartmodes and theemailedAt != nullprotection rule. - SKILL.md — "주간/월간 보고 고품질 재요약" workflow: replaces the old "워크플로우: 주간/월간 보고 생성" section with a 4-step flow — (1) baseline auto-generation via
out, (2) analysis viacircle --json, (3) re-summary viacircle --save --type weekly|monthly, (4) delivery viaoutw/outm.
Files changed
src/cli.ts (+54), src/core/circle.ts (+203), src/core/out.ts (+109), src/skill/SKILL.md (+54), tests/circle.test.ts (+625), tests/out.test.ts (+110). Total ~1143 insertions / ~12 deletions across 6 files.
v0.8.3 (2026-04-09) — Project-level session consolidation
- Simplified session consolidation: Changed merging logic from "same title within project" (
projectName::normalizedTitle) to "all sessions per project" (projectNameonly). Final result = one entry per project, regardless of session titles - circle.ts:
mergeSummariesByTitle()grouping key changed fromprojectName::normalizedTitletoprojectName - merge-sessions.ts:
mergeSessionsByTopic()grouping key changed fromprojectName::normalizedTitletoprojectName - SKILL.md updated (both copies): Removed the old 2-pass mergeGroup consolidation and 3-pass project consolidation. Replaced with a single 2-pass that groups by
projectNamedirectly --summarizepath: Also updated to perform the same project-level consolidation- Tests: Updated to expect same-project sessions to merge even with different topics
v0.8.2 (2026-04-09) — Circle same-title session merge summaries
- Same-title session merge in circle: When multiple sessions share the same
projectName + normalizedTitlewithin a date, circle now merges their individual summaries into a single consolidated summary. Each session is summarized individually first, then sessions in the same group are re-summarized together — outcome fields are joined, flows are concatenated with→, the longest significance is kept, and nextSteps comes from the last session. Merged entries show(×N)in the topic - Applied to both summary paths: The merge runs in
autoSummarize(CLI auto-summary via Cloudflare AI / heuristic) and in the SKILL.md flow (Claude Code direct summary viamergeGrouphint incircle --jsonoutput) mergeGroupfield in circleJson output: Each session incircle --jsonoutput now includes amergeGroupfield (projectName::normalizedTitle) so Claude Code can identify merge-eligible sessions during SKILL.md step 2- SKILL.md updated: Step 2 now includes a "통합 재요약" (consolidated re-summary) phase — after individual session analysis, sessions sharing a
mergeGroupare merged before overview generation - New function:
mergeSummariesByTitle()incircle.ts— groups byprojectName + normalizeTitle(topic), merges stats (messageCount, tokens, duration), and consolidates summary fields - Tests: 135/135 passing (11 test files, +7 new tests for mergeSummariesByTitle)
v0.8.1 (2026-04-09) — Circle cross-device merge + always-send policy
- Circle cross-device merge:
autoSummarizeincircle.tsnow pulls other devices' already-summarized sessions from D1 viapullCrossDeviceReports, deduplicates bysessionId, and generates a unified overview covering all machines — not just local work. Previously, circle only summarized local sessions; cross-device data was only used at email render time inout - Always-send policy: Removed cross-device email dedup check from
out.ts—outnow always sends email regardless of whether another device already sent for the same date+type. The previous behavior (checkCrossDeviceEmailSent→ skip) blocked email delivery when another device had already runsincenety - Architecture alignment: The 3-phase pipeline now follows a clear separation —
aircollects per-device,circlesummarizes all-devices,outalways delivers - Files changed:
src/core/circle.ts(D1 pull + merge inautoSummarize),src/core/out.ts(removed dedup skip block) - Tests: 128/128 passing (11 test files)
v0.8.0 (2026-04-09) — Cross-device consolidated reports + session merge
- Cross-device consolidated reports: When working on multiple machines,
outnow pushes local data to D1 first (pre-sync), then queries D1 for other devices' sessions. Sessions from all machines are merged into a single consolidated email report - Session merge by project: Sessions within the same
projectNamewithin a date are automatically merged in email reports — stats (messages, tokens, duration) are aggregated, the most detailed wrapUp is selected, flow narratives are concatenated with→separator. Merged sessions show(×N)count in the title - Title extraction improvement: Sessions starting with slash commands (e.g.,
/sincenety) now prefer meaningful messages (>5 chars) for titles; if none exist, falls back to[projectName] sessioninstead of empty strings - Graceful D1 fallback: All cross-device features are wrapped in try/catch — if D1 is unreachable, falls back to single-device local-only behavior with no disruption
- New files:
src/email/merge-sessions.ts(session merge utility),src/cloud/sync.tsadditions (pullCrossDeviceReports,checkCrossDeviceEmailSent) - Tests: 128/128 passing (11 test files)
v0.7.7 (2026-04-09) — claude-code summarization quality + Workers AI CLI sample report
- claude-code summarization quality improvements: When
ai_provider = claude-code,circle --jsonnow preprocessesconversationTurnsbefore output — applies path/filename removal, single-word response filtering, 30-turn limit, and 200/300-char truncation (matching Workers AI's preprocessing). This reduces noise and improves Claude Code's direct summarization quality - SKILL.md 2-pass restructuring: Step 2 now instructs Claude Code to analyze sessions one-by-one (1-pass per session), then synthesize overview separately (2-pass). Added concrete input/output examples for consistent quality
- Workers AI CLI sample report: Added
docs/sample-report-cli.html— actual daily report email generated by Workers AI (Cloudflare) summarization pipeline. Live at pathcosmos.github.io/sincenety/sample-report-cli.html - Tests: 128/128 passing (11 test files)
v0.7.6 (2026-04-09) — sessionId prefix matching + GitHub Pages sample report
- sessionId prefix matching fallback: When AI summaries are saved via
circle --savewith truncated or mistyped sessionIds, the renderer (renderer.ts) now falls back to prefix matching (first 12 chars) to still map AI summaries to the correct sessions — prevents silent degradation to raw data in emails circleSave()auto-correction: When saving AI summaries, if the input sessionId doesn't exactly match a DB session, prefix matching resolves the correct ID and stores the corrected version — ensures downstream rendering always has valid IDs- GitHub Pages sample report: Added
docs/index.htmllanding page anddocs/sample-report.htmlwith a real daily report email sample. Live at pathcosmos.github.io/sincenety - Tests: 128/128 passing (11 test files)
v0.7.4 (2026-04-09) — AI provider routing fix + summarization quality improvements
- Fixed
autoSummarize()ignoringai_providerconfig: In CLI environment (sincenety,sincenety circle), Workers AI was called whenever D1 tokens existed, regardless ofai_providersetting. Now usesresolveAiProvider()to respect the config - Added provider check to
circleJson --summarize:--summarizeflag now only calls Workers AI whenai_provider = cloudflare - Heuristic fallback on Workers AI failure: When Workers AI fails for individual sessions, falls back to
summarizer.tsheuristic summary (prevents data loss) autoSummarize()now runs for all AI providers: Previously only ran forcloudflare; now runs for all providers (cloudflare → Workers AI, anthropic → Claude API, claude-code/heuristic → heuristic), ensuringdaily_reportsalways has baseline summaries- Assistant output truncation raised from 300 to 1500 chars: Previously assistant responses were hard-capped at 300 characters, losing most content needed for quality summaries
- File path/filename filtering in text cleanup: Absolute paths (
/Users/...,/Volumes/...), relative paths (./foo,../bar), and filenames with common extensions (.ts,.js,.json, etc.) are now stripped from summary input to reduce technical noise - Improved heuristic fallback summaries: When no conversation turns exist, shows project name + message count instead of raw user input; when no result keywords found, extracts first sentence from assistant output instead of raw user input
tool_useblock extraction: Claude Code assistant responses are oftentool_useblocks (Edit, Bash, Read) with no text content; now extracts tool names as[Edit, Bash, Read]to give the heuristic summarizer meaningful input- Updated README AI Summarization section: Corrected "CLI always uses Workers AI" → "
ai_providerrespected in all environments"
Roadmap
- [x] Weekly/monthly summary reports
- [x] Email with AI summary (daily overview + per-session topic/outcome/flow)
- [x] Gmail clip prevention (actions capped at 5/session, text length optimized)
- [x] 3-phase pipeline (air → circle → out)
- [x] Checkpoint-based backfill with change detection
- [x] Vacation management
- [x]
outcommand — smart email delivery (out/outd/outw/outm, 4 providers, catchup) - [x]
config --setupwizard - [x] Gmail MCP integration (zero-config email via
gmail_create_draft) - [x] Cloud sync (Cloudflare D1 multi-machine aggregation)
- [x] Cloudflare Workers AI integration (Qwen3-30B summarization)
- [x] Auto machine ID (hardware-based, cross-platform)
- [x] Token-only D1 setup (account/database auto-detection)
- [x] Unified AI provider routing (cloudflare/anthropic/claude-code/heuristic)
- [x] Mandatory setup guard (D1 + SMTP required before any command)
- [x] Clean JSON output:
--render-onlystdout/stderr separation, single JSON output - [x] Default command:
sincenety(no args) runs full pipeline (air → circle → out) - [x] English CLI: all user-facing messages converted to English
- [x] AI provider setup required on first run in Claude Code
- [x] Scope selection: global (all projects) or project (specific path) mode
- [x] Postinstall setup wizard:
npm install -gtriggers interactive 3-step setup - [x] Date-targeted reports:
--date yyyyMMddfor out/outd/outw/outm commands - [x] Circle project-level session merge (individual summary → consolidated re-summary per project)
- [ ] Passphrase encryption option
- [ ] Similar task matching (TF-IDF)
- [ ] External DB connectors (MariaDB/PostgreSQL)
- [ ] ccusage integration (automatic cost calculation)
- [ ] Multi-language report output (KO toggle option)
- [x] Sample report page (GitHub Pages: pathcosmos.github.io/sincenety)
- [x] Defensive sessionId matching (prefix fallback + auto-correction)
- [x] claude-code summarization quality (turn preprocessing + SKILL.md 2-pass)
- [x] Workers AI CLI sample report (GitHub Pages)
- [x] Cross-device consolidated reports (D1 pull + circle merge + always-send)
- [x] Session merge by project (project-level dedup with ×N count)
- [x] Improved title extraction (meaningful message priority + fallback)
- [x] Auto weekly/monthly baseline generation (every
out/outd/outw/outmrun, emailed-report protected) - [x] Pipeline mode switch (
--mode=full|smart+config --pipeline-mode) - [x] Silent failure hardening (runCircle
summaryErrors+ CLI exit code propagation) - [ ] Report export (PDF/HTML standalone)
License
MIT
