TomasPalsson/worklog/tree/main/mods/worklog
이 mod 소개
worklog
타이머를 싫어하는 개발자를 위한 개인 시간 추적기입니다. Claude Code, GitHub, Google Calendar, Jira에서 활동을 가져와 하나의 로컬 SQLite 파일에 모으고, 블록으로 묶은 뒤 claude -p를 사용해 각 블록의 티켓을 고르고 설명을 작성합니다. 로컬 웹 UI에서 검토한 결과는 Tempo Cloud로 동기화합니다.
모든 작업은 컴퓨터에서 실행됩니다. Tempo 동기화를 push하기 전까지 아무것도 밖으로 나가지 않으며, 그 전에 모든 블록을 검토합니다.
설치
curl -fsSL https://raw.githubusercontent.com/TomasPalsson/worklog/main/install.sh | bash
스크립트는 GitHub Releases에서 플랫폼에 맞는 서명된 릴리스 바이너리(macOS arm64 또는 linux x86_64)를 내려받아 검증한 뒤 ~/.local/bin/worklog에 둡니다. 그 다음:
worklog setup # 한 번만 수행하는 온보딩: db + secrets + Claude hook
worklog day # 하루 마감: collect → infer → estimate → review UI
업그레이드는 한 명령으로 수행하며 항상 서명을 확인합니다.
worklog upgrade # 릴리스 파이프라인을 통한 서명된 자체 업데이트
이전
uv tool install에서 마이그레이션하나요?docs/MIGRATION.md를 참고하세요. 한 단계면 됩니다.
아키텍처
┌──────────────────────────── 당신의 Mac ─────────────────────────────┐
│ │
│ ~/.local/share/worklog/worklog.db (단일 진실 공급원, │
│ WAL 모드 — 동시에 쓰는 동안 │
│ RO 읽기 안전) │
│ ▲ ▲ │
│ │ │ │
│ 쓰기(unix socket │ 직접 읽기 │
│ 또는 TCP 127.0.0.1:9323) │ bun:sqlite 사용 │
│ │ │ │
│ ┌────────┴────────┐ ┌───┴───────────────────┐ │
│ │ worklog(Rust) │ │ Docker: worklog-web │ │
│ │ · CLI │ │ · Bun + Next.js 15 │ │
│ │ · 수집기 │ │ · Server Components │ │
│ │ · 추정기 │───────▶│ · Server Actions → │ │
│ │ · axum 데몬 │ TCP │ host.docker │ │
│ │ · web 오케스트레이터│ │ .internal:9323 │ │
│ └────────┬────────┘ └───────────────────────┘ │
│ │ 생성/관리 │
│ ▼ │
└─────────────────────────────────────────────────────────────────────┘
이벤트는 AI 추정기가 Jira 티켓으로 분류합니다. 일치하지 않는 이벤트는 웹 UI에 「unassigned」로 표시되고 수동으로 재할당합니다. 웹 컨테이너는 SQLite를 직접 읽으며(WAL 모드에서는 동시에 읽어도 안전함), 쓰기는 Next.js Server Actions → Rust 데몬의 TCP를 통과합니다(Docker Desktop은 macOS VM을 통해 실시간 unix socket을 프록시할 수 없으므로 컨테이너와 호스트 사이에 TCP를 사용함).
DB에 쓰는 것은 Rust 데몬뿐입니다. Server Actions는 변경을 전달하고 revalidatePath를 호출하는 얇은 shim입니다.
빠른 시작
worklog setup # preflight + interactive secrets + db migrate
worklog hook install # Claude Code hook 등록
worklog day # 전체 일일 파이프라인(collect → infer → estimate → UI)
UI를 실행하지 않고 모두 가져오려면:
worklog day --no-serve
명령
| 명령 | 용도 |
|---|---|
| worklog version | 포함된 버전 출력 |
| worklog setup | preflight + secrets 캡처 + db migrate |
| worklog doctor | 환경, DB, secrets 상태 보고서 |
| worklog day [--day] [--no-serve] [--model] | 전체 일일 파이프라인: collect → infer → estimate → web UI |
| worklog collect [all\|jira\|github\|gcal] [--days] | 원격 활동 가져오기 |
| worklog infer [--day] | gap-timeout으로 이벤트를 블록으로 묶기 |
| worklog estimate [--day] [--model] | claude -p가 jira + description + minutes를 채움 |
| worklog sync [--day] [--dry-run] | 검토한 블록을 Tempo Cloud로 POST |
| worklog web up [--port] | docker화된 Next.js UI 시작 |
| worklog web down / status / logs / build | 컨테이너 수명주기 |
| worklog daemon [--socket] [--tcp] | Axum API 서버(unix + TCP) |
| worklog hook [install\|uninstall\|status] | Claude Code hook 연결 |
| worklog schedule [install\|uninstall\|status] | 예약 수집(launchd / systemd --user) |
| worklog secret [set\|get\|rm\|list] | OS 키체인의 자격 증명 |
| worklog db [migrate\|info\|path] | DB 작업 |
| worklog upgrade | 서명된 자체 업데이트 |
| worklog self-update [--check\|--dry-run\|--force] | upgrade의 하위 수준 별칭 |
| worklog dev [keygen\|sign\|make-patch\|apply-patch] | 유지 관리자 도구 |
모든 하위 명령은 구조화된 출력을 위해 --json을 받습니다.
저장소
- DB:
~/.local/share/worklog/worklog.db(SQLite, WAL 모드). - 설정:
~/.config/worklog/(.env,google_credentials.json,google_token.json). - 시크릿: 서비스 이름
worklog로 OS 키체인에 저장(macOS Keychain, Linux secret-service, Windows Credential Manager)..env파일도 계속 사용할 수 있으며worklog secret set …으로 설정하거나worklog setup을 다시 실행하면 시크릿이 느리게 마이그레이션됩니다. - 바이너리 및 릴리스:
~/.local/share/worklog/{bin,releases}/.
$WORKLOG_HOME=<dir>로 모든 것을 덮어쓸 수 있습니다. DB, socket, 설정, bin, 로그, 릴리스를 하나의 루트로 모읍니다. 주로 테스트와 고급 사용자용입니다.
추정기 제공자 전환
추정기에는 서로 바꿔 쓸 수 있는 백엔드가 2개 있습니다.
claude_subprocess(기본값)—claude -p를 셸에서 실행합니다. 설정이 필요 없지만PATH에 Claude Code CLI가 있어야 합니다.litellm— OpenAI 호환 프록시에 POST합니다. LiteLLM이 참조 구현입니다. worklog을 바꾸지 않고 Anthropic, OpenAI, 로컬 Ollama, Bedrock 등으로 라우팅할 수 있습니다.
worklog setup(대화형)에서 고르거나 환경 변수를 설정합니다.
export WORKLOG_ESTIMATOR_PROVIDER=litellm
worklog secret set litellm_base_url http://localhost:4000
worklog secret set litellm_api_key <your-proxy-key> # 인증되지 않은 로컬 프록시는 비워도 됨
worklog secret set litellm_model anthropic/claude-haiku-4-5
worklog doctor는 활성 제공자와 도달성 프로브를 보고합니다. WORKLOG_ESTIMATOR_PROVIDER를 해제하고(worklog secret rm worklog_estimator_provider도 실행)서브프로세스 경로로 돌아갑니다.
개발
cargo test --manifest-path rust/Cargo.toml
cargo clippy --manifest-path rust/Cargo.toml --all-targets --all-features -- -D warnings
cargo fmt --manifest-path rust/Cargo.toml --all
cd web && bun test && bun run typecheck && bun run build
로컬 릴리스 스모크(네트워크 없음, 태그 push 없음):
bash scripts/release-smoke.sh
bash tests/install/smoke.sh
CI: .github/workflows/rust.yml은 모든 push / PR에서 Linux와 macOS에 fmt + clippy + tests를 실행합니다. .github/workflows/release.yml은 모든 v* 태그에서 빌드하고 서명하고 게시합니다.
주요 파일
rust/crates/worklog-core/— 데이터 계층: paths, db, repo, secrets, collectors, infer, estimator, 서명된 업데이터rust/crates/worklog-cli/—worklog바이너리: CLI + 설정 마법사rust/crates/worklog-core/sql/schema.sql— 정식 SQL 스키마web/— Next.js + Bun 검토 UI(docker화)install.sh— curl 파이프로 실행하는 설치 프로그램scripts/release-smoke.sh— 릴리스 파이프라인의 호스트 측 dry-run
설치
먼저 작성자의 README에서 marketplace와 플러그인 이름을 확인하세요. 저장소 구조에 따라 명령어가 달라질 수 있습니다.
claude plugin marketplace add TomasPalsson/worklog claude plugin install worklog
원문 / README
worklog
Personal time-tracker for the developer who hates timers. Pulls
activity from Claude Code, GitHub, Google Calendar, and Jira into one
local SQLite file, clusters it into blocks, uses claude -p to pick a
ticket and write a description for each block, and syncs the result to
Tempo Cloud after you review it in a local web UI.
Everything runs on your machine. Nothing leaves until you push a Tempo sync — and you review every block before that happens.
Install
curl -fsSL https://raw.githubusercontent.com/TomasPalsson/worklog/main/install.sh | bash
The script downloads a signed release binary for your platform
(macOS arm64 or linux x86_64) from GitHub Releases, verifies it, and
drops it at ~/.local/bin/worklog. After that:
worklog setup # one-shot onboarding: db + secrets + Claude hook
worklog day # end-of-day: collect → infer → estimate → review UI
Upgrading is a single command and always verifies the signature:
worklog upgrade # signed self-update via the release pipeline
Migrating from the old
uv tool install? Seedocs/MIGRATION.md— one step.
Architecture
┌──────────────────────────── your Mac ─────────────────────────────┐
│ │
│ ~/.local/share/worklog/worklog.db (single source of truth, │
│ WAL mode — safe RO readers │
│ during concurrent writes) │
│ ▲ ▲ │
│ │ │ │
│ writes (unix socket │ reads direct │
│ OR TCP 127.0.0.1:9323) │ via bun:sqlite │
│ │ │ │
│ ┌────────┴────────┐ ┌───┴───────────────────┐ │
│ │ worklog (Rust) │ │ Docker: worklog-web │ │
│ │ · CLI │ │ · Bun + Next.js 15 │ │
│ │ · Collectors │ │ · Server Components │ │
│ │ · Estimator │───────▶│ · Server Actions → │ │
│ │ · axum daemon │ TCP │ host.docker │ │
│ │ · web orch. │ │ .internal:9323 │ │
│ └────────┬────────┘ └───────────────────────┘ │
│ │ spawns/manages │
│ ▼ │
└─────────────────────────────────────────────────────────────────────┘
Events are classified to a Jira ticket by the AI estimator; unmatched ones appear as "unassigned" in the web UI and are reassigned by hand. The web container reads SQLite directly (WAL mode = concurrent reads are safe), and writes flow through Next.js Server Actions → the Rust daemon over TCP (Docker Desktop can't proxy live unix sockets through its macOS VM, hence TCP between the container and host).
Only the Rust daemon writes to the DB — Server Actions are a thin
shim that forwards the mutation and calls revalidatePath.
Quickstart
worklog setup # preflight + interactive secrets + db migrate
worklog hook install # register the Claude Code hook
worklog day # full daily pipeline (collect → infer → estimate → UI)
To pull everything without running the UI:
worklog day --no-serve
Commands
| Command | Purpose |
|---|---|
| worklog version | Print the embedded version |
| worklog setup | Preflight + secrets capture + db migrate |
| worklog doctor | Environment, DB, secrets sanity report |
| worklog day [--day] [--no-serve] [--model] | Full daily pipeline: collect → infer → estimate → web UI |
| worklog collect [all\|jira\|github\|gcal] [--days] | Pull remote activity |
| worklog infer [--day] | Gap-timeout clustering of events into blocks |
| worklog estimate [--day] [--model] | claude -p fills jira + description + minutes |
| worklog sync [--day] [--dry-run] | POST reviewed blocks to Tempo Cloud |
| worklog web up [--port] | Bring up the dockerised Next.js UI |
| worklog web down / status / logs / build | Container lifecycle |
| worklog daemon [--socket] [--tcp] | Axum API server (unix + TCP) |
| worklog hook [install\|uninstall\|status] | Claude Code hook wiring |
| worklog schedule [install\|uninstall\|status] | Scheduled collection (launchd / systemd --user) |
| worklog secret [set\|get\|rm\|list] | Credentials in the OS keychain |
| worklog db [migrate\|info\|path] | DB operations |
| worklog upgrade | Signed self-update |
| worklog self-update [--check\|--dry-run\|--force] | Lower-level alias for upgrade |
| worklog dev [keygen\|sign\|make-patch\|apply-patch] | Maintainer tooling |
Every subcommand accepts --json for structured output.
Storage
- DB:
~/.local/share/worklog/worklog.db(SQLite, WAL mode). - Config:
~/.config/worklog/(.env,google_credentials.json,google_token.json). - Secrets: OS keychain under service name
worklog(macOS Keychain, Linux secret-service, Windows Credential Manager). The.envfile still works — secrets migrate lazily as you set them viaworklog secret set …or re-runworklog setup. - Binaries + releases:
~/.local/share/worklog/{bin,releases}/.
Override everything with $WORKLOG_HOME=<dir> — collapses db, socket,
config, bin, logs, releases into one root. Primarily for tests and
power users.
Switching estimator provider
The estimator has two interchangeable backends:
claude_subprocess(default) — shells out toclaude -p. Zero configuration. Requires the Claude Code CLI onPATH.litellm— POSTs to any OpenAI-compatible proxy (LiteLLM is the reference implementation). Lets you route to Anthropic, OpenAI, local Ollama, Bedrock, etc. without changing worklog.
Select via worklog setup (interactive) or set the env var:
export WORKLOG_ESTIMATOR_PROVIDER=litellm
worklog secret set litellm_base_url http://localhost:4000
worklog secret set litellm_api_key <your-proxy-key> # empty OK for unauthed local
worklog secret set litellm_model anthropic/claude-haiku-4-5
worklog doctor reports the active provider and a reachability probe.
Unset WORKLOG_ESTIMATOR_PROVIDER (and run worklog secret rm worklog_estimator_provider) to fall back to the subprocess path.
Dev
cargo test --manifest-path rust/Cargo.toml
cargo clippy --manifest-path rust/Cargo.toml --all-targets --all-features -- -D warnings
cargo fmt --manifest-path rust/Cargo.toml --all
cd web && bun test && bun run typecheck && bun run build
Local release smoke (no network, no tag push):
bash scripts/release-smoke.sh
bash tests/install/smoke.sh
CI: .github/workflows/rust.yml runs
fmt + clippy + tests on Linux and macOS on every push / PR;
.github/workflows/release.yml builds,
signs, and publishes on every v* tag.
Files of interest
rust/crates/worklog-core/— data layer: paths, db, repo, secrets, collectors, infer, estimator, signed updaterrust/crates/worklog-cli/— theworklogbinary: CLI + setup wizardrust/crates/worklog-core/sql/schema.sql— canonical SQL schemaweb/— the Next.js + Bun review UI (dockerised)install.sh— curl-piped installerscripts/release-smoke.sh— host-side dry-run of the release pipeline

