FreshBooks Time Tracking Skill
Manage FreshBooks time entries using the fb CLI tool.
Prerequisites
Always run this preflight before any time logging or entry mutation:
command -v fb >/dev/null 2>&1
fb auth status --format json
fb cache status --format json
If fb is missing:
- Stop and tell the user to install the FreshBooks CLI binary first.
- Do not continue with auth or logging commands until
fbis available.
If both fb and ./fb are available:
- Prefer
./fbwhen working inside this repository to preserve project-local behavior. - Otherwise use
fb.
Deterministic Auth State Machine (Minimize Back-and-Forth)
Use fb auth status --format json and branch exactly once per blocker:
-
If
config_existsisfalse:- Ask once for both values in one message:
client_idandclient_secret - Run:
fb auth setup --client-id ID --client-secret SECRET --format jsonfb auth url --format json
- Provide auth URL and request one value only: full redirect URL (
https://localhost/?code=...)
- Ask once for both values in one message:
-
If
config_existsistrueandtokens_existisfalse:- Run:
fb auth url --format json - Ask only for full redirect URL
- Run:
-
After redirect URL is provided:
- Run:
fb auth callback "REDIRECT_URL" --format json - If response contains
"business_selected": false:- Ask only for business ID, then run
fb business --select ID --format json
- Ask only for business ID, then run
- Run:
-
If
tokens_exististruebutbusiness_idis null:- Run:
fb business --format json - Ask only for business ID, then run
fb business --select ID --format json
- Run:
-
After auth completion:
- Re-run:
fb auth status --format json - Proceed only when
config_exists=true,tokens_exist=true, andbusiness_idis set.
- Re-run:
Question Minimization Rules
- Ask at most one targeted question per true blocker.
- Never ask permission questions (e.g. "should I proceed?").
- Never ask for values that can be derived from API data.
- Batch credential asks together when setup is missing (
client_id+client_secret). - For OAuth completion, ask only for the full callback URL.
- For business selection, ask only for the business ID.
- If a command fails, show the concrete error and ask only for the single missing input needed to continue.
Client/Project/Service Resolution Rules
- Before logging, resolve resources in this order:
fb clients --format jsonfb projects --client "Name" --format json
- Services are project-scoped. Always resolve service from the selected project's
servicesarray. - Never depend on
fb servicesalone for logging decisions. - If multiple clients exist and user did not specify one, ask once for client name.
- If project is ambiguous, ask once for project name.
- If service cannot be inferred from user intent, ask once for service name.
Dynamic Context
Current auth and cache state:
!fb auth status 2>&1
!fb cache status --format json 2>&1
Agent Rules
When executing fb commands:
- Always use
--format jsonfor parseable output - Always use
--yesto skip confirmation prompts on mutations - Always pass explicit flags (
--client,--duration,--note,--id) — never rely on interactive prompts - Always use
--idforeditanddeletecommands - Parse JSON output to extract entry IDs, totals, and status
- After each mutation (
log,edit,delete), run one verification read (fb entries ... --format jsonorfb status --format json) and report the result.
Important: Services are project-scoped and MUST always be specified when logging time. fb services may return empty — services are embedded in project data. Use --service "Name" with the service name from the project (visible in fb projects --format json under the services array). Common service names: Development, Research, General, Meetings. Infer the service from context clues in the user's request (e.g. "development work" → "Development", "a meeting" → "Meetings"). If the service cannot be inferred, ask the user before logging.
Command Reference
Check Status
fb status --format json # Hours summary (today/week/month)
fb entries --format json # Current month entries
fb entries --from YYYY-MM-DD --to YYYY-MM-DD --format json # Date range
Log Time
fb log --client "Client Name" --project "Project" --service "Service" --duration HOURS --note "Description" --yes --format json
# --project is required when multiple projects are possible and should be supplied for deterministic automation.
# --date is optional; --client, --duration, --note, and --service are required.
# IMPORTANT: Always include --service. Infer the service from context (e.g. "development work" → "Development",
# "meeting" → "Meetings", "research" → "Research"). If unsure, ask the user. Never omit --service.
Edit Entry
fb edit --id ENTRY_ID --duration HOURS --yes --format json
fb edit --id ENTRY_ID --note "New note" --yes --format json
fb edit --id ENTRY_ID --service "Meetings" --yes --format json
# Edit preserves all existing fields — only specified flags are changed
Delete Entry
fb delete --id ENTRY_ID --yes --format json
List Resources
fb clients --format json
fb projects --format json # Includes project-scoped services in response
fb projects --client "Name" --format json # Filter by client; services array shows available services
fb business --format json
Cache Management
fb cache status --format json # Check cache freshness
fb cache refresh # Force refresh
Workflows
Log multiple entries for one date (batch mode)
- Ensure auth is valid via the auth state machine above.
- Resolve client/project/services once:
fb clients --format jsonfb projects --client "Name" --format json
- Execute all
fb logcommands in sequence (same date) with explicit flags:--client,--project,--service,--date,--duration,--note,--yes,--format json
- Verify in one command:
fb entries --from YYYY-MM-DD --to YYYY-MM-DD --format json
- Return:
- created entry IDs
- per-entry duration and note
- total hours for the date
Recovery flow for common failures
No config found:- Run auth state machine step 1.
Could not find 'code' parameter:- Ask user to paste full redirect URL including query string.
Multiple clients found. Use --client:- Ask once for client name, then continue.
Multiple projects found. Use --project:- Ask once for project name, then continue.
Service not found:- Refresh project list for selected client and pick service from that project.
- Missing required flags in non-interactive mode:
- Re-run command with explicit required flags; do not switch to interactive prompts.
Response Contract
When reporting results to the user:
- Include what command(s) were run.
- Include key IDs and totals (entry ID, duration, date range, total hours).
- If verification fails, state exactly what failed and the next corrective action.
- Keep output concise and machine-checkable when possible (prefer JSON-derived facts, not guesses).
Log hours for today
fb clients --format json— get available clientsfb projects --client "Name" --format json— get projects and their servicesfb log --client "Name" --project "Project" --service "Service" --duration 2.5 --note "Work description" --yes --format json
Check how many hours logged today
fb status --format json
Parse today.total_hours from the response.
Edit the most recent entry
fb entries --from TODAY --to TODAY --format json— get today's entries- Find the entry to edit, get its
id fb edit --id ID --duration 3 --yes --format json
Full auth setup (new user)
fb auth setup --client-id ID --client-secret SECRET --format jsonfb auth url --format json— show URL to user- User authorizes and provides full redirect URL (
https://localhost/?code=...) fb auth callback "REDIRECT_URL" --format json- If response shows
business_selected: false:fb business --format jsonthenfb business --select ID --format json