Warning
This is a project I am using to LEARN GO. I am in no-way a GO expert. This was built with the help of AI as a learning tool.
A beautiful, interactive command-line tool for logging time entries to Clockify.
- 📅 Interactive date selection (defaults to today)
- 📂 Project selection with arrow key navigation
- ⏰ Simple time range input (e.g., "9a - 5p")
- 📝 Task description with suggestions from your previous entries
- ✨ Clean, colorful terminal UI using Bubble Tea
clockify-time-tracker/
├── main.go # Entry point
├── go.mod # Go module definition
├── .env # Your API key (not in git)
├── .env.example # Template for .env
├── .gitignore
├── README.md
│
└── internal/
├── api/ # API layer - talks to Clockify
│ ├── client.go # HTTP client for API requests
│ ├── types.go # Data structures (Project, TimeEntry, etc.)
│ ├── user.go # User-related API calls
│ ├── projects.go # Project-related API calls
│ └── timeentries.go # Time entry API calls
│
├── ui/ # UI layer - Bubble Tea components
│ ├── model.go # Application state
│ ├── update.go # State updates (handles messages)
│ ├── view.go # Rendering (displays UI)
│ ├── commands.go # Wraps API calls as Bubble Tea commands
│ ├── steps.go # Step/screen constants
│ └── styles.go # Visual styles (colors, formatting)
│
└── utils/ # Utilities
└── config.go # Configuration loading
This project follows the Bubble Tea (Elm Architecture) pattern with clear separation of concerns:
-
API Layer (
internal/api/):- Pure Go functions that make HTTP requests to Clockify
- Returns data or errors - no UI logic
- Reusable and testable
-
UI Layer (
internal/ui/):- Model: Holds all application state
- Update: Receives messages, updates state, returns commands
- View: Renders the current state as a string
- Commands: Bridge between API and UI - async operations that send messages
-
Flow:
User Input → Update() → New State → View() → Display ↓ Commands (API calls) ↓ Messages → Update() → ...
Messages: Data sent to Update() to trigger state changes
userInfoMsg- User info fetched from APIprojectsMsg- Projects fetched from APItasksMsg- Recent tasks fetched from APIerrMsg- An error occurredsubmitSuccessMsg- Time entry created successfully
Commands: Functions that return messages asynchronously
- Wrap API calls
- Run in background
- Send results back as messages
Steps: Different screens in the UI flow
- Date selection → Project selection → Time input → Task input → Confirm → Complete
- Go 1.21 or higher
- A Clockify account and API key
- Clone this repository:
git clone <your-repo-url>
cd clockify-time-tracker- Install dependencies:
go mod download- Create your
.envfile:
cp .env.example .env- Edit
.envand add your Clockify API key:
CLOCKIFY_API_KEY=your_api_key_here
- Log in to Clockify
- Go to Settings → Profile
- Scroll down to "API" section
- Generate or copy your API key
Run the tool:
go run main.goOr build and run:
go build -o clockify-tracker
./clockify-tracker- Date Selection: Use
←/→arrow keys to change dates,Enterto confirm - Project Selection: Use
↑/↓arrow keys to navigate,Enterto select - Time Range: Type in format like
9a - 5por9:30a - 3:45p - Task Description: Type your task description
- Quit: Press
qorCtrl+Cat any time
9a - 5p→ 9:00 AM to 5:00 PM9:30a - 3:45p→ 9:30 AM to 3:45 PM10a - 2p→ 10:00 AM to 2:00 PM
Build for your platform:
# macOS
GOOS=darwin GOARCH=amd64 go build -o clockify-tracker-mac
# Linux
GOOS=linux GOARCH=amd64 go build -o clockify-tracker-linux
# Windows
GOOS=windows GOARCH=amd64 go build -o clockify-tracker.exeLet's say you want to add a "billable" toggle:
-
Add to model (
ui/model.go):type model struct { // ... existing fields billable bool }
-
Add a step (
ui/steps.go):const ( // ... existing steps stepBillableSelect )
-
Handle in Update (
ui/update.go):case stepBillableSelect: // Handle billable selection
-
Render in View (
ui/view.go):case stepBillableSelect: return m.renderBillableSelect()
-
Update API call (
api/timeentries.go):type TimeEntryRequest struct { // ... existing fields Billable bool `json:"billable"` }
"Error loading .env file"
- Make sure you've created a
.envfile in the project root - Copy
.env.exampleto.envand fill in your API key
"CLOCKIFY_API_KEY not set"
- Check that your
.envfile containsCLOCKIFY_API_KEY=your_key - Make sure there are no extra spaces around the
=
"Loading projects..." never finishes
- Check your internet connection
- Verify your API key is correct
- Make sure you have projects in your Clockify workspace
"Failed to create entry"
- Verify your API key is correct
- Check that the time format is valid (e.g.,
9a - 5p) - Ensure you have access to the selected project
Feel free to open issues or submit pull requests!
MIT License - feel free to use this for personal or commercial projects.