Skip to content

Repository files navigation

TimeForged

license

Self-hosted time tracking for developers. Daemon + CLI + Web Dashboard + MCP, written in Rust.


Quick Start

git clone https://github.com/Blysspeak/timeforged.git
cd timeforged
bash install.sh

The installer will:

  • Build the web dashboard (Vue 3 + Tailwind)
  • Compile Rust binaries (timeforged daemon + tf CLI)
  • Install to ~/.local/bin/
  • Set up a systemd user service
  • Register on the remote server (timeforged.nexalix.io) for sync & public profile card
  • Configure auto-sync (every 15 min via systemd timer)
  • Install Claude Code hooks (if detected)
  • Install the Waybar module (if Waybar is detected)
  • Start the daemon and display your API key

Then initialize tracking:

tf init ~/projects    # watch a directory tree

Open http://127.0.0.1:6175 in your browser — the dashboard works immediately, no login required on localhost.

Manual build

# Build dashboard
cd crates/timeforged/web && npm install && npx vite build && cd ../../..

# Build binaries
cargo build --release

# Run daemon
./target/release/timeforged

On first run, an admin user and API key are created automatically:

==============================================
  TimeForged — first run setup
  Created admin user with API key:
  tf_abc123...
  Save this key! It won't be shown again.
==============================================

Web Dashboard

The daemon serves a built-in web dashboard at http://127.0.0.1:6175:

  • Period switcher — Today / 7 Days / 30 Days / All Time
  • All Time total — always visible, shows cumulative hours, active days, and project count
  • Activity chart — time per day for the selected period
  • Projects & Languages — breakdown with progress bars and language icons
  • Sessions — recent coding sessions with duration
  • Stats — top project, session count

Localhost requests are auto-authenticated — no API key needed to view the dashboard.

File Watcher

TimeForged automatically tracks your coding activity via filesystem events — no editor plugins needed.

tf init ~/projects          # start watching (recursive, inotify-based)
tf list                     # show watched directories
tf unwatch ~/projects       # stop watching

The daemon watches registered directories recursively and creates heartbeat events on file changes. Features:

  • Project detection — first-level subdirectory of the watched root becomes the project name
  • Language detection — inferred from file extension and filename patterns
  • Git branch — cached per project (60s TTL)
  • Debounce — 30s per file to avoid event spam
  • Ignored paths.git, node_modules, target, __pycache__, lock files, binaries
  • Window tracker (optional) — polls hyprctl / xdotool every 15s for active editor file

Watched directories persist in ~/.config/timeforged/watched.toml.

Waybar Module

Show today's coding time in your Waybar panel:

bash contrib/waybar/install.sh

This installs a custom module that queries the TimeForged API every 60s, displays time as 󱑂 1:25, and opens the dashboard on click. The tooltip shows per-project breakdown.

The installer is also run automatically by install.sh when Waybar is detected.

Claude Code Integration

TimeForged can automatically track your AI-assisted coding sessions via Claude Code hooks.

bash install.sh   # choose "yes" when prompted for Claude Code hooks

Or install manually:

mkdir -p ~/.claude/hooks
cp contrib/claude-code/timeforged-heartbeat.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/timeforged-heartbeat.sh

Then add to ~/.claude/settings.json:

{
  "hooks": {
    "UserPromptSubmit": [{ "type": "command", "command": "~/.claude/hooks/timeforged-heartbeat.sh" }],
    "PostToolUse": [{ "type": "command", "command": "~/.claude/hooks/timeforged-heartbeat.sh" }],
    "Stop": [{ "type": "command", "command": "~/.claude/hooks/timeforged-heartbeat.sh" }]
  }
}

The hook fires on every interaction with 30s debounce, sends heartbeats in the background (non-blocking), and auto-detects project, language, branch, and file paths from hook context.

Architecture

crates/
  timeforged-core/   # Shared types, models, config
  timeforged/        # Daemon — Axum REST API + SQLite + embedded SPA
    web/             # Vue 3 + Tailwind CSS dashboard
  tf/                # CLI client
contrib/
  waybar/            # Waybar module + installer
  claude-code/       # Claude Code heartbeat hook
File Watcher (inotify) ──┐
Window Tracker (optional) ┼──→ Events ──→ Storage (SQLite)
Claude Code (hooks) ──────┤
HTTP API (POST /events) ──┘
                                            ↓
Browser → Embedded SPA (rust-embed) ──→ Reports API ──→ Storage
Waybar module ─────────────────────────→ Reports API

CLI

tf init ~/projects              # watch a directory tree
tf list                         # show watched directories
tf unwatch ~/projects           # stop watching

tf status                       # daemon status
tf today                        # today's summary
tf report --range week          # weekly report
tf report --range month --project myapp

tf send /path/to/file.rs --project myapp --language Rust  # manual heartbeat

API key is configured once in ~/.config/timeforged/cli.toml or via TF_API_KEY.

Remote Sync & GitHub Profile Card

TimeForged can sync your local activity to a remote server and generate an SVG card for your GitHub profile.

Setup

The installer handles this automatically. To set up manually:

# Register on the remote server
tf register <username> --remote https://timeforged.nexalix.io

# Enable public profile (makes your card visible)
tf profile --public

# Sync events
tf sync

GitHub README Card

Add this to your GitHub profile README:

<a href="https://github.com/Blysspeak/timeforged">
  <img src="https://timeforged.nexalix.io/api/v1/card/<username>?theme=dark" width="766" alt="TimeForged Activity" />
</a>

The card updates automatically as you sync. Available parameters:

  • themedark (default) or light
  • days — number of days to show (1-365, default 7)

CLI config for sync

# ~/.config/timeforged/cli.toml
server_url = "http://127.0.0.1:6175"
api_key = "tf_..."
remote_url = "https://timeforged.nexalix.io"
remote_key = "tf_..."

Public API (no auth required)

Method Path Description
POST /api/v1/register Register new user (rate limited)
GET /api/v1/card/{username} Public SVG profile card
GET /api/v1/status Server status
GET /health Health check

Docker

docker compose up -d

Or build manually:

docker build -t timeforged .
docker run -d -p 6175:6175 -v timeforged-data:/data timeforged

REST API

All authenticated endpoints require the X-Api-Key header (or localhost access).

Method Path Auth Description
GET /health Health check
GET /api/v1/status Daemon status
POST /api/v1/register Register new user (rate limited)
GET /api/v1/card/{username} Public SVG profile card
GET /api/v1/card.svg key Private SVG card
POST /api/v1/events key Create event
POST /api/v1/events/batch key Batch create (up to 100)
GET /api/v1/events key Export events (for sync)
GET /api/v1/reports/summary key Time summary by project/language/day
GET /api/v1/reports/sessions key Coding sessions
GET /api/v1/reports/activity key Hourly activity
GET /api/v1/me key Current user
PUT /api/v1/me/public-profile key Toggle public profile
POST /api/v1/api-keys key Create API key
GET /api/v1/api-keys key List API keys
DELETE /api/v1/api-keys/{id} key Delete API key
POST /api/v1/watch key Add watched directory
DELETE /api/v1/watch key Remove watched directory
GET /api/v1/watched key List watched directories

Query parameters

from, to (ISO 8601), project, language

Event body

{
  "timestamp": "2026-02-27T10:00:00Z",
  "event_type": "file",
  "entity": "/home/user/project/src/main.rs",
  "project": "app",
  "language": "Rust",
  "branch": "main",
  "activity": "coding"
}

event_type: file | terminal | browser | meeting | custom activity: coding | browsing | debugging | building | communicating | designing | other

Project and language are auto-inferred from file path when omitted.

Configuration

Daemon — ~/.config/timeforged/config.toml

host = "127.0.0.1"
port = 6175
database_url = "sqlite:~/.local/share/timeforged/timeforged.db?mode=rwc"
idle_timeout = 300
log_level = "info"

CLI — ~/.config/timeforged/cli.toml

server_url = "http://127.0.0.1:6175"
api_key = "tf_..."
remote_url = "https://timeforged.nexalix.io"
remote_key = "tf_..."

Watched directories — ~/.config/timeforged/watched.toml

[[directories]]
path = "/home/user/projects"

Managed via tf init / tf unwatch.

Environment variables

All settings can be overridden with TF_ prefix:

TF_HOST, TF_PORT, TF_DATABASE_URL, TF_IDLE_TIMEOUT, TF_LOG_LEVEL, TF_SERVER_URL, TF_API_KEY, TF_REMOTE_URL, TF_REMOTE_KEY

License

MIT

About

Self-hosted time tracking for developers. Daemon + CLI + MCP, written in Rust.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages