AI-powered time tracking, client management, and project profitability for freelancers. Replaces Toggl Track + Harvest. One-time $9.99 via NormieClaw.
Freelancer Toolkit turns your OpenClaw agent into a personal freelance business manager. Track time by talking ("I worked 3 hours on the Acme redesign today"), manage clients and projects, monitor profitability, generate timesheets, and hand off invoices to InvoiceGen Pro — all through conversation.
No timers to click. No forms to fill. No apps to open. Just tell your agent what you did.
All data lives in JSON files under ~/.freelancer-toolkit/:
text
~/.freelancer-toolkit/
├── settings.json # Global config (default rate, categories, preferences)
├── clients.json # Client database
├── projects.json # Project database
├── time-entries.json # All time entries
├── timers.json # Active timers (start/stop tracking)
└── exports/ # Generated timesheets and reports
settings.json
json
{
"default_hourly_rate": 75,
"currency": "USD",
"currency_symbol": "$",
"week_start": "monday",
"billing_period": "monthly",
"categories": ["design", "development", "consulting", "meetings", "admin", "writing", "research"],
"non_billable_categories": ["admin", "internal"],
"weekly_summary_day": "monday",
"invoicegen_integration": true,
"rounding": "nearest_quarter"
}
clients.json — Array of client objects:
json
{
"id": "client_uuid",
"name": "Jane Smith",
"company": "Acme Corp",
"email": "jane@acmecorp.com",
"phone": "555-0123",
"default_rate": 85,
"payment_terms": "net_30",
"notes": "Prefers invoices on the 1st. Always pays on time.",
"status": "active",
"created_at": "2026-01-15T10:00:00Z",
"total_billed": 12400,
"total_paid": 9600,
"tags": ["design", "retainer"]
}
projects.json — Array of project objects:
json
{
"id": "proj_uuid",
"client_id": "client_uuid",
"name": "Website Redesign",
"description": "Full redesign of acmecorp.com",
"status": "active",
"billing_type": "fixed",
"quoted_price": 5000,
"hourly_rate": 85,
"estimated_hours": 60,
"hours_logged": 42.5,
"effective_rate": 117.65,
"budget_alert_threshold": 0.8,
"milestones": [
{"name": "Wireframes", "status": "completed", "due_date": "2026-02-01"},
{"name": "Visual Design", "status": "in_progress", "due_date": "2026-03-01"},
{"name": "Development", "status": "pending", "due_date": "2026-04-01"}
],
"created_at": "2026-01-10T10:00:00Z",
"completed_at": null,
"tags": ["web", "design"]
}
time-entries.json — Array of time entry objects:
json
{
"id": "entry_uuid",
"client_id": "client_uuid",
"project_id": "proj_uuid",
"date": "2026-03-10",
"hours": 3.0,
"description": "Logo concept exploration, 3 directions",
"category": "design",
"billable": true,
"invoiced": false,
"invoice_id": null,
"created_at": "2026-03-10T17:30:00Z"
}
timers.json — Active timer state:
json
{
"active": true,
"client_id": "client_uuid",
"project_id": "proj_uuid",
"description": "Working on homepage layout",
"category": "design",
"started_at": "2026-03-10T14:00:00Z",
"paused_at": null,
"accumulated_minutes": 0
}
On first use or when data files don't exist:
~/.freelancer-toolkit/ directorysettings.json from the skill's config/ directoryclients.json, projects.json, time-entries.jsontimers.json with {"active": false}exports/ directorybash
mkdir -p ~/.freelancer-toolkit/exports
If settings.json already exists, never overwrite — the user may have customized it.
This is the flagship feature. Parse natural language into structured time entries.
Input patterns to recognize:
User saysParsed result"I worked 3 hours on the Acme redesign today"client: Acme, project: redesign, hours: 3, date: today"Just finished 2.5 hours of consulting with BrightPath"client: BrightPath, hours: 2.5, category: consulting, date: today"Yesterday I spent 45 minutes on admin for Johnson & Co"client: Johnson & Co, hours: 0.75, category: admin, date: yesterday"4 hrs Acme, homepage wireframes"client: Acme, hours: 4, description: homepage wireframes"Logged 1 hour meeting with Sarah at Nova Labs"client: Nova Labs, hours: 1, category: meetings"6 hours last Friday on the BrightPath app"client: BrightPath, hours: 6, date: last Friday
Parsing rules:
clients.json. "Acme" matches "Acme Corp". If ambiguous, ask.non_billable_categories.settings.json.Always confirm before saving:
text
✅ Logged: 3.00 hrs — Acme Corp → Website Redesign
"Homepage wireframe revisions"
Date: March 10, 2026 | Billable | Rate: $85/hr ($255.00)
Unknown client/project: Offer to create on the fly. Ask for rate at minimum.
For users who prefer real-time tracking:
Starting a timer:
While running: Store state in timers.json. If user starts a new timer, stop and log the current one first.
Stopping: "Stop tracking" / "Stop timer" → Calculate elapsed, round per settings, confirm and log. Prompt for description.
Pausing: "Pause timer" saves accumulated time. "Resume" continues.
Adding a client:
Viewing clients:
Client detail view: Show contact info, rate, terms, active/completed project counts, total billed/paid/outstanding, and notes.
Editing: "Update Acme's rate to $95/hr", "Archive the Johnson account", etc.
Client memory: Proactively surface relevant context — last activity date, payment patterns ("BrightPath usually pays late"), average project size.
Creating a project:
Project fields:
billing_type: "fixed" (quoted price) or "hourly" (open-ended)status: "active", "paused", "completed"quoted_price and estimated_hourshours_logged and calculate effective_rateViewing projects:
Project detail view: Show status, billing type, hours vs estimate with percentage, effective rate, milestones with status, and recent time entries.
Updating: Support milestone completion, status changes (pause/complete), and scope adjustments. When marking complete, calculate final profitability and update client totals.
Per-project profitability (fixed-price projects):
Calculate effective_rate = quoted_price / hours_logged.
Budget alerts — proactive, triggered when logging time:
budget_alert_threshold (default 80%): ⚠️ warning with remaining hours, effective rate, and pace estimateCross-project analysis:
Summary format: List each active project with effective rate, status indicator (✅/⚠️/🚨), and weighted average across all projects vs target rate.
Generate timesheets on demand:
Markdown format: Table with Date, Client, Project, Hours, Description, Billable columns. Totals at bottom split by billable/non-billable with dollar amounts.
CSV export: Run scripts/export-timesheet.sh --start YYYY-MM-DD --end YYYY-MM-DD [--client "Name"]. Output to ~/.freelancer-toolkit/exports/. Columns: date,client,project,hours,description,category,billable,rate,amount.
Trigger invoice generation:
Process:
json
{
"client": {
"name": "Acme Corp",
"contact": "Jane Smith",
"email": "jane@acmecorp.com"
},
"payment_terms": "net_30",
"line_items": [
{
"description": "Website Redesign — Visual design concepts and revisions",
"hours": 12.5,
"rate": 85,
"amount": 1062.50
},
{
"description": "Website Redesign — Development and testing",
"hours": 8.0,
"rate": 85,
"amount": 680.00
}
],
"subtotal": 1742.50,
"total": 1742.50,
"period": "March 2026"
}
invoiced: true and store invoice_idtotal_billedIf InvoiceGen Pro is not installed: Export as JSON to ~/.freelancer-toolkit/exports/invoice-{client}-{period}.json and suggest installing it.
Delivered every Monday (or configured day). Contains:
Manual trigger: "Give me my weekly summary" or "How did last week look?"
The dashboard kit exposes these widgets via dashboard-kit/manifest.json:
Data sources: Read from ~/.freelancer-toolkit/*.json files.
See dashboard-kit/DASHBOARD-SPEC.md for full widget specifications.
These are conversational triggers, not slash commands. The agent recognizes intent.
User intentExampleLog time"I worked 3 hours on Acme today"Log with details"2.5 hrs BrightPath, API integration and testing"Log past date"Yesterday I did 4 hours on Nova Labs brand guide"Start timer"Start tracking Acme redesign"Stop timer"Stop tracking"Pause timer"Pause timer"Resume timer"Resume"Check timer"How long have I been tracking?"Edit entry"Change today's Acme entry to 3.5 hours"Delete entry"Delete the Nova Labs entry from yesterday"
User intentExampleAdd client"New client: Sarah Chen, Nova Labs, $95/hr, net 15"List clients"Show my clients"Client details"Tell me about Acme"Update client"Update Acme's rate to $100/hr"Archive client"Archive Johnson & Co"
User intentExampleCreate project"New project for Acme: Logo Refresh, $2,000 fixed, ~25 hours"List projects"Show active projects"Project status"How's the Acme redesign going?"Update milestone"Mark Acme wireframes as done"Complete project"The BrightPath app is finished"Pause project"Pause the Nova Labs project"
User intentExampleWeekly timesheet"Show me last week's timesheet"Monthly timesheet"March timesheet"Client timesheet"Timesheet for Acme, February"Export CSV"Export March timesheet as CSV"Generate invoice"Invoice Acme for March"Profitability"How am I doing on profitability?"Weekly summary"Give me my weekly summary"Client report"Billing summary for BrightPath"
*.backup, re-initialize, and alert the user.export-timesheet.sh scriptEdit ~/.freelancer-toolkit/settings.json to customize:
default_hourly_rate: Applied to new clients unless overridden (default: 75)currency / currency_symbol: Currency for display (default: "USD" / "$")week_start: "monday" or "sunday" (default: "monday")billing_period: "weekly", "biweekly", or "monthly" (default: "monthly")categories: List of time entry categoriesnon_billable_categories: Categories that default to non-billableweekly_summary_day: Day of week for auto-summary (default: "monday")invoicegen_integration: Enable InvoiceGen Pro handoff (default: true)rounding: "none", "nearest_quarter", "nearest_tenth", "round_up_quarter" (default: "nearest_quarter")FilePathSettings~/.freelancer-toolkit/settings.jsonClients~/.freelancer-toolkit/clients.jsonProjects~/.freelancer-toolkit/projects.jsonTime entries~/.freelancer-toolkit/time-entries.jsonActive timer~/.freelancer-toolkit/timers.jsonExports~/.freelancer-toolkit/exports/Setup script<skill_dir>/scripts/setup.shExport script<skill_dir>/scripts/export-timesheet.shReport script<skill_dir>/scripts/client-report.sh