Sync Intervals time entries from SQLite to FreshBooks. Faster than browser-based sync since it reads local data. Use when asked to sync time to FreshBooks, enter FreshBooks time, or fill FreshBooks from Intervals.
Sync time entries from the local SQLite database to FreshBooks. Reads Intervals data from SQLite instead of browser automation.
Reading from: SQLite intervals_time_entries table via scripts/query-intervals.sh
Writing to: FreshBooks API via intervals-to-freshbooks/scripts/freshbooks-api.sh
Persisting: SQLite freshbooks_time_entries table via scripts/insert-freshbooks.sh
Mapping: intervals-to-freshbooks/references/project-mappings.md
$VAULT/.claude/time-entries.db with intervals_time_entries populated~/.config/freshbooks/credentials.json--remote-debugging-port=9222 (for refreshing FreshBooks at the end)$VAULT = /home/olivier/Code/github.com/olivoil/obsidian
=
= this skill's base directory
=
$DB$VAULT/.claude/time-entries.db$SKILL$FB_SKILL$SKILL/../intervals-to-freshbooksscripts/query-intervals.shQuery Intervals time entries grouped by date + project.
bash $SKILL/scripts/query-intervals.sh $DB [--from YYYY-MM-DD] [--to YYYY-MM-DD]
Output: TSV with columns date, project, hours
scripts/query-freshbooks.shQuery FreshBooks time entries from SQLite.
bash $SKILL/scripts/query-freshbooks.sh $DB [--from YYYY-MM-DD] [--to YYYY-MM-DD]
Output: TSV with columns date, project, description, hours
scripts/insert-freshbooks.shInsert a FreshBooks entry into the local SQLite database.
bash $SKILL/scripts/insert-freshbooks.sh $DB \
--date YYYY-MM-DD \
--project "<name>" \
--hours <hours> \
--description "<desc>" \
[--entry-id <fb_id>]
freshbooks-api.sh (from intervals-to-freshbooks)Create entries in FreshBooks via API.
bash $FB_SKILL/scripts/freshbooks-api.sh create-time-entry \
[--project "<name>" | --client "<name>"] \
--date YYYY-MM-DD \
--hours <hours> \
[--note "<note>"]
Other commands: projects, clients, list-time-entries --from DATE --to DATE
Read the mapping file at $FB_SKILL/references/project-mappings.md.
Build a lookup from Intervals project name to FreshBooks destination. Match using CONTAINS (Intervals project names may have SOW numbers appended like (20250040)).
| Intervals Project (contains) | FB Project | FB Note | Has FB Project? |
|---|---|---|---|
| Ignite Application Development | Technomic | Development | yes |
| Optimizely CMS | K Hovnanian | Development | yes |
| Drees Maintenance | Drees | Development | yes |
| DHDC Pre Buyer | Drees | Development | yes |
| EWG Feature Enhancement | EWG | Development | yes |
| EWG App v3 | EWG | Development | yes |
| Mattamy Homes | Mattamy Homes | Development | yes |
| CDS Digital Product | SLB | Development | yes |
| Monthly Maintenance Agreement | TeleDynamics | Development | yes |
| YPO - ProductOps | YPO | Development | yes |
| Meeting | (none) | Meetings | no (client-only) |
| Biz Dev / Sales | (none) | Business Development | no (client-only) |
| Training | (none) | Training | no (client-only) |
| Recruiting | (none) | Recruiting | no (client-only) |
Client-only entries (no FB project) use --client EXSquared without --project. In SQLite they are stored with project = "EXSquared".
query-intervals.sh to get Intervals daily totals by projectquery-freshbooks.sh to get existing FreshBooks entriesIf an Intervals project name doesn't match any mapping, flag it and ask the user. Update $FB_SKILL/references/project-mappings.md with the new mapping.
Multiple Intervals projects may map to the same FB project. Sum their hours per date before comparing. For example, if Intervals has "Optimizely CMS Decoupling" (3h) and "Optimizely CMS Health Check" (1h) on the same day, that's 4h total for "K Hovnanian" in FreshBooks.
Present gaps grouped by week:
**Week of March 2-8, 2026 (41.25h)**
| Date | FB Project | Hours | Note |
|------|-----------|------:|------|
| 2026-03-02 | K Hovnanian | 5.0 | Development |
| 2026-03-02 | Technomic | 0.5 | Development |
| 2026-03-02 | EXSquared | 1.0 | Meetings |
| ... | ... | ... | ... |
Ask the user to confirm before proceeding. If no gaps found, report that everything is synced.
For entries with a FB project:
bash $FB_SKILL/scripts/freshbooks-api.sh create-time-entry \
--project "<FB Project>" --date "<YYYY-MM-DD>" --hours <hours> --note "<Note>"
For client-only entries (Meetings, Biz Dev, etc.):
bash $FB_SKILL/scripts/freshbooks-api.sh create-time-entry \
--date "<YYYY-MM-DD>" --hours <hours> --note "<Note>"
Run entries in parallel batches (by project) for speed.
For each created entry, run insert-freshbooks.sh:
bash $SKILL/scripts/insert-freshbooks.sh $DB \
--date "YYYY-MM-DD" \
--project "<FB Project or EXSquared>" \
--hours <hours> \
--description "<Note>" \
--entry-id "<fb_entry_id>"
For each date with new entries, append a ### FreshBooks section to $VAULT/Daily Notes/YYYY-MM-DD.md:
------
### FreshBooks
| Project | Hours | Description |
|---------|------:|-------------|
| K Hovnanian | 5.0 | Development |
| Technomic | 0.5 | Development |
| **Total** | **8.0** | |
### FreshBooks already exists in the note, replace itlist_pages to find a FreshBooks tabselect_page then navigate_page to the relevant weeknew_page with the FreshBooks week URLURL format: https://my.freshbooks.com/#/time-tracking/week?week=YYYY-MM-DD
(where YYYY-MM-DD is the Monday of the first week with new entries)