Track your work time automatically through git commits with both a powerful MCP server and an interactive terminal UI
Features β’ Installation β’ Quick Start β’ Usage β’ Documentation
Clockwork is a dual-mode time tracking system that transforms your git commits into actionable worklog entries. Whether you prefer working through AI assistants (MCP mode) or an interactive terminal interface (TUI mode), Clockwork has you covered.
π€ MCP Server Mode - Integrate with Claude and other LLM applications
- Expose time tracking as MCP tools
- Natural language interactions: "track the last 2 hours of work"
- Seamless integration with your AI workflow
π» TUI Mode - Interactive terminal interface
- Full-featured terminal UI for direct interaction
- Browse projects and entries with keyboard shortcuts
- Real-time statistics and filtering
- Perfect for quick reviews and manual entries
- Automatic Commit Aggregation - Collects commits since your last entry
- Intelligent Duration Calculation - Estimates work time from commit timestamps
- Custom Overrides - Manually adjust duration and messages when needed
- Flexible Entry Creation - Git-based or manual entry modes
- Projects Dashboard - Visual overview of all your projects
- Entries Browser - Sortable, filterable entry list with summaries
- Statistics View - Time breakdowns by project and invoice status
- Keyboard-Driven - Efficient navigation without touching the mouse
- Color-Coded - Invoiced/uninvoiced status at a glance
- Multi-Project Support - Track time across unlimited projects
- Flexible Commit Sources - Each project chooses how its commits are found: none, a local git repo, or supplied by an MCP client
- Invoice Tracking - Mark entries as invoiced for billing
- Advanced Filtering - By project, date range, or invoice status
- Embedded Database - bbolt key-value store, no external dependencies
- Single File Storage -
~/.local/clockwork/default.db - MCP Protocol - Works with Claude Desktop, Claude Code, and other MCP clients
- Data Persistence - All data safely stored between sessions
- Go 1.21+ - Download here
- Git - Installed and configured
# Clone the repository
git clone https://github.com/techthos/clockwork.git
cd clockwork
# Build the static binary to ./bin/clockwork
make build
# Or install to $GOPATH/bin
make install# The binary supports two modes
./bin/clockwork # Starts terminal UI (default)
./bin/clockwork mcp # Starts MCP server
# Either mode can point at a specific database file
./bin/clockwork --db /path/to/clockwork.dbClaude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"clockwork": {
"command": "/absolute/path/to/clockwork",
"args": ["mcp"]
}
}
}Claude Code CLI (~/.claude/config.json):
{
"mcpServers": {
"clockwork": {
"command": "/absolute/path/to/clockwork",
"args": ["mcp"]
}
}
}π‘ Tip: Use $(go env GOPATH)/bin/clockwork if you ran go install
The Clockwork tools will now be available in your Claude sessions.
You: "Create a new project called 'Website Redesign' in /home/user/projects/website"
You: "Track the work I did today on the website project"
./bin/clockwork- Press
nto create a new project - Enter project name and git repository path
- Press Tab to navigate, Enter to save
- Press Enter on a project to view its entries
- Press
nto create a new entry - Choose Git mode (auto-aggregates commits) or Manual mode
- Fill in the details and save
- From the entries view, press
sto see statistics - View time breakdowns by project and invoice status
- Use
fto apply filters
Ctrl+CorCtrl+Q- Quit applicationTab- Navigate form fieldsEsc- Close modal/cancel
n- New projecte- Edit selected projectd- Delete selected project (with confirmation)Enter- View project entriesq- Quit applicationβ/β- Navigate list
n- New entry (choose git or manual mode)e- Edit selected entryd- Delete selected entryi- Toggle invoiced statusf- Configure filterss- View statisticsq- Back to projectsβ/β- Navigate list
f- Configure filtersr- Refresh statisticsq- Back to entries
Git Mode (Automatic):
- Select project
- Clockwork fetches commits since last entry
- Auto-calculates duration from timestamps
- Auto-generates message from commit summaries
- Optional: Override duration or message
Manual Mode:
- Select project
- Enter duration (formats:
1h 30m,90m,1.5h) - Enter message/description
- Mark as invoiced (optional)
Apply filters in entries or statistics views:
- Project - Select specific project or "All Projects"
- Date Range - Start/end dates (format: YYYY-MM-DD)
- Invoice Status - All, Invoiced Only, or Uninvoiced Only
| Tool | Description | Example |
|---|---|---|
create_project |
Create a new project | Create project "API Server" at /code/api |
get_commit_baseline |
Show a project's source and last commit hash | What commit should I start from? |
update_project |
Update project details | Rename project to "API v2" |
delete_project |
Delete project and all entries | Delete the API project |
list_projects |
List all projects | Show all my projects |
create_entry |
Create worklog from commits or manually | Track 2 hours on the API project |
update_entry |
Update entry details | Mark last entry as invoiced |
delete_entry |
Delete an entry | Delete yesterday's entry |
list_entries |
List entries with filters, search, ordering, pagination | Show uninvoiced entries from last month |
new_project_form / edit_project_form |
Open the interactive project form | Show me a form to add a project |
new_entry_form / edit_entry_form |
Open the interactive entry form | Let me fill in an entry by hand |
Hosts that support the MCP Apps extension (io.modelcontextprotocol/ui) render the
project and entry tools as interactive tables and forms. The widgets are registered as
ui://clockwork/... resources and linked from the tool definitions, so tables repaint
after every create, update or delete, rows carry Edit and Delete actions, and form
submissions call the same tools the model uses. Hosts without the extension see the
normal tool results.
"Create a new project called 'Mobile App' at /Users/me/code/mobile"
"Track my work today on the mobile app project"
"Show me all uninvoiced time entries"
"Mark the last 3 entries as invoiced"
"How much time did I spend on the API project this week?"
"Create a manual entry for 2 hours of meeting time on the mobile project"
// Create a project backed by a local git repository
create_project({
name: "My Project",
source_type: "local",
git_repo_path: "/absolute/path/to/repo"
})
// Create a project with no repository at all (manual entries only)
create_project({
name: "Consulting",
source_type: "none"
})
// Create a project whose commits you look up yourself
create_project({
name: "Remote App",
source_type: "mcp",
repository: "owner/remote-app"
})
// Create entry from git commits (source_type "local", automatic)
create_entry({
project_id: "project-uuid",
invoiced: false
})
// Create entry from commits you fetched yourself (source_type "mcp")
get_commit_baseline({ project_id: "project-uuid" })
// β { source_type: "mcp", repository: "owner/remote-app", last_commit_hash: "abc123..." }
create_entry({
project_id: "project-uuid",
commits: [
{ hash: "3f2a91c...", author: "Alex", message: "feat: add widget",
timestamp: "2026-07-20T09:00:00Z" }
]
})
// Create manual entry (no git aggregation)
create_entry({
project_id: "project-uuid",
duration: 120, // minutes
message: "Client meeting and planning",
invoiced: false
})
// List entries with filters, search, ordering and pagination
list_entries({
project_id: "project-uuid", // optional, empty = all projects
start_date: "2025-01-01", // optional
end_date: "2025-01-31", // optional
invoiced: false, // optional, null = all entries
search: "invoice", // optional, matches message, commit hash, project name
sort_by: "created_at", // optional: created_at | updated_at | duration | message
order: "desc", // optional: desc (default) | asc
page: 1, // optional, 1-based
page_size: 50 // optional, clamped to 50
})
// β rows plus page, page_size, total, total_pages, has_more
// Update entry
update_entry({
id: "entry-uuid",
duration: 180, // optional
message: "Updated", // optional
invoiced: true // optional
})βββββββββββββββββββ
β Last Entry β
β commit_hash β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β git log <hash>..HEAD β
β Fetch new commits β
ββββββββββ¬βββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β Aggregate commit messages β
β Calculate duration β
ββββββββββ¬βββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β Create worklog entry β
β Store latest commit hash β
βββββββββββββββββββββββββββββββ
- Single commit β Default 30 minutes
- Multiple commits β
(last_commit_time - first_commit_time) + 30 minutes
Example: Commits at 9:00 AM and 11:30 AM
- Time span: 2.5 hours
- Buffer: 0.5 hours
- Total duration: 3 hours (180 minutes)
~/.local/clockwork/default.db (bbolt)
βββ projects/
β βββ <uuid> β {id, name, source_type, git_repo_path?, repository?, created_at, updated_at}
βββ entries/
βββ <uuid> β {id, project_id, duration, message, commit_hash, invoiced, created_at, updated_at}
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Website Redesign",
"source_type": "local",
"git_repo_path": "/home/user/projects/website",
"created_at": "2025-01-27T10:00:00Z",
"updated_at": "2025-01-27T10:00:00Z"
}{
"id": "660e8400-e29b-41d4-a716-446655440001",
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"duration": 180,
"message": "Aggregated 3 commits:\n1. [abc123d] Implement login form\n2. [def456e] Add form validation\n3. [ghi789f] Update styles",
"commit_hash": "ghi789f...",
"invoiced": false,
"created_at": "2025-01-27T14:30:00Z",
"updated_at": "2025-01-27T14:30:00Z"
}{
"total_minutes": 540,
"total_hours": 9.0,
"entry_count": 3,
"invoiced_minutes": 180,
"uninvoiced_minutes": 360,
"project_breakdown": {
"project-uuid-1": 300,
"project-uuid-2": 240
},
"earliest_entry": "2025-01-20T09:00:00Z",
"latest_entry": "2025-01-27T14:30:00Z"
}# All tests
go test ./...
# With coverage
go test -cover ./...
# Verbose output
go test ./... -v
# Specific package
go test ./internal/db -v
go test ./internal/git -vclockwork/
βββ cmd/
β βββ clockwork/ # Main entry point
βββ internal/
β βββ db/ # Database operations (bbolt)
β βββ models/ # Data structures
β βββ git/ # Git integration
β βββ server/ # MCP server implementation
β βββ tui/ # Terminal UI components
β β βββ app.go # Main TUI app structure
β β βββ projects.go # Projects view
β β βββ entries.go # Entries view
β β βββ stats.go # Statistics view
β β βββ modals.go # Dialog boxes
β β βββ theme.go # Color scheme
β β βββ helpers.go # Utilities
β βββ utils/ # Shared utilities
βββ go.mod
βββ go.sum
βββ CLAUDE.md # AI assistant context
βββ README.md
# Build with optimizations (static, like release assets)
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/clockwork ./cmd/clockwork
# Build for specific platform
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/clockwork-linux ./cmd/clockwork
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o bin/clockwork-macos ./cmd/clockwork
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o bin/clockwork.exe ./cmd/clockworkThe TUI and the MCP server can run at the same time. Clockwork opens the bbolt file per operation β read-only for reads, read-write for writes β and closes it again, so an idle process holds no lock. A collision between the two is retried with backoff (75ms attempts, 3s budget) before it is reported.
- β TUI and MCP server side by side on one database
β οΈ Writes still serialize: the second writer waits for the first to finish its (short) operationβ οΈ The TUI reloads on navigation; it does not auto-refresh when the MCP server writes
Error: open bbolt at "...": timeout β something held the lock for more than 3 seconds. Check
for a stuck process on the same file.
Details and trade-offs: docs/bbolt-concurrent-access-strategy.md.
Resolved in one place (db.DefaultPath()), highest precedence first:
| Source | Value |
|---|---|
--db <path> flag |
used verbatim; accepted by both modes (clockwork --db ..., clockwork mcp --db ...) |
CLOCKWORK_DB env var |
used verbatim (an empty value counts as unset) |
| default | ~/.local/clockwork/default.db |
Paths are used exactly as given β the shell expands ~, clockwork does not.
A repository is optional. Each project declares a source_type:
source_type |
Locator field | Where commits come from |
|---|---|---|
none |
β | Nowhere. Only manual entries are possible. |
local |
git_repo_path |
A git repository on this machine, read by clockwork with the git CLI. |
mcp |
repository |
Clockwork does not look them up. The calling client β typically an AI with access to a repository MCP server or API β fetches them and passes them to create_entry in the commits array. |
Projects created before source_type existed are read as local when they
have a repository path and none when they do not, so no migration is needed.
For source_type: "local":
- The path must be a valid git repository
- The repository must have at least one commit
- Git must be accessible in the system PATH
For source_type: "mcp":
- Call
get_commit_baselineto learn the last recorded commit hash - Fetch the commits made after it using your own tooling
- Pass them to
create_entry; each commit needs amessage, and atimestampunless you also pass an explicitduration - The TUI cannot create git-mode entries for these projects, since no client is present to supply the commits β use manual entries there
Cause: No commits exist between the last entry and HEAD
Solution: Make new commits, then create an entry
Cause: Git not configured properly
Solution:
git config user.name "Your Name"
git config user.email "your@email.com"Cause: Invalid project ID or project was deleted
Solution: List projects to verify:
# In TUI: View projects screen
# In MCP: Use list_projects toolCause: Duration not in recognized format
Solution: Use one of these formats:
1h 30m- Hours and minutes90m- Minutes only1.5h- Decimal hours90- Plain number (treated as minutes)
Rare but possible. If the database becomes corrupted:
# Backup current database
cp ~/.local/clockwork/default.db ~/.local/clockwork/backup.db
# Remove corrupted database
rm ~/.local/clockwork/default.db
# Clockwork will create a new database on next runContributions are welcome! Here's how:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
go test ./...) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow standard Go formatting (
gofmt) - Add comments for exported functions
- Keep functions focused and testable
- Update tests for any changes
MIT License - see LICENSE for details
Built with these excellent open-source projects:
- mcp-go - Model Context Protocol implementation by Mark3 Labs
- bbolt - Pure Go embedded key-value database
- tview - Rich terminal UI library
- tcell - Terminal cell-based view library
- GitHub: github.com/techthos/clockwork
- MCP Protocol: modelcontextprotocol.io
- Issues: Report bugs or request features
Made with βοΈ and β€οΈ by the Techthos team
Automate your time tracking. Focus on building great things.
Built and maintained by Techthos.