kfa-ai/hermes-timetree-sync
Non-interactive TimeTree calendar bridge for Hermes Agent
hermes-timetree-sync is a Python-based CLI and library that enables Hermes Agents to manage TimeTree calendar events without manual user intervention. Since TimeTree discontinued its official API, this bridge uses authenticated web endpoints and session cookies to perform non-interactive writes. It supports creating all-day events directly via HTTP requests and timed events through a Safari-backed automation path. The tool allows agents to translate natural language requests into structured calendar updates using locally stored credentials and optional label mapping policies.
- Syncs all-day and timed events using TimeTree web endpoints
- Supports non-interactive batch writes for multiple calendar entries
- Maps natural language terms to calendar labels via YAML policy
full readme from github
hermes-timetree-sync
Private TimeTree bridge for Hermes Agent calendar automation.
hermes-timetree-sync is a small Python CLI and client library that lets Hermes create and sync TimeTree calendar events without asking a chat user to open TimeTree.
TimeTree discontinued its official third-party API in December 2023. This project therefore uses TimeTree's current web endpoints through a deliberately narrow, tested client boundary. It is an internal bridge, not an official TimeTree integration; upstream web-app changes may require maintenance.
Why this exists
The target interaction is simple:
“Add Day off on May 18.”
Hermes should translate that request into a TimeTree write using locally stored credentials. No browser, TimeTree UI, cookie copying, or OAuth prompt should appear during normal chat usage.
Capabilities
| Area | Current support |
|---|---|
| Auth | Stored TimeTree web session cookie; experimental email/password exchange |
| Discovery | List calendars and labels |
| Reads | Sync calendar events through TimeTree's web sync endpoint |
| Writes | Create, update, and delete events through guarded client methods |
| Hermes UX | Non-interactive all-day event creation, batch writes, and Safari-backed timed event creation |
| Labels | Optional local YAML policy for mapping terms/categories to TimeTree labels |
| Safety | Redacted docs/tests, low-volume API usage, mocked HTTP coverage |
Installation
git clone git@github.com:kfa-ai/hermes-timetree-sync.git
cd hermes-timetree-sync
uv sync --dev
Run the local quality gates:
uv run pytest
uv run ruff check .
Configuration
Provide runtime configuration via .env or environment variables:
TIMETREE_SESSION_COOKIE=...
TIMETREE_CALENDAR_ID=...
TIMETREE_SESSION_COOKIEis the value of TimeTree's_session_idbrowser cookie. Treat it as a bearer secret.TIMETREE_CALENDAR_IDis the target TimeTree calendar ID for writes.
For local email/password TimeTree accounts, an experimental sign-in command can attempt to exchange credentials for a web session:
TIMETREE_EMAIL=you@example.com
TIMETREE_PASSWORD=...
uv run hermes-timetree-sync sign-in
Direct sign-in may fail depending on TimeTree's browser/session checks. Production Hermes usage should rely on a stored, locally refreshed session cookie. See docs/authentication.md.
CLI quickstart
Check configuration:
uv run hermes-timetree-sync doctor
List calendars:
uv run hermes-timetree-sync list-calendars
Create one all-day event:
uv run hermes-timetree-sync create-all-day --title "Day off" --date 2026-05-18
Create several all-day events with one current-user lookup:
uv run hermes-timetree-sync create-all-day-batch \
--event "2026-05-18|Day off" \
--event "2026-05-25|Public holiday"
The batch command was added in v0.1.1 for faster Hermes calendar writes. It also includes regression coverage for TimeTree accounts whose /api/v1/user ID is returned as a number rather than a string.
Create one timed event through Safari's authenticated TimeTree page context:
uv run hermes-timetree-sync create-timed \
--title "Lynsey out" \
--start 2026-05-24T12:00 \
--end 2026-05-24T18:00 \
--category lynsey
create-timed requires Safari to already be logged into TimeTree with Develop → Allow JavaScript from Apple Events enabled. It opens the target TimeTree calendar, posts a timed all_day: false event with browser credentials: include, then verifies the created event through /events/sync. This path exists because direct non-browser writes with only _session_id can return HTTP 422 even when browser-context writes succeed.
Hermes integration model
This package is intentionally UI-free at runtime:
- A local setup/bootstrap step stores or refreshes
TIMETREE_SESSION_COOKIEandTIMETREE_CALENDAR_IDoutside chat. - Hermes parses a natural-language calendar request into structured event data.
- Hermes calls this CLI/client directly.
- For all-day events, the TimeTree UI is not opened during the user request. Timed events currently use Safari page-context execution because the direct replay path is unreliable for writes.
For multiple requested all-day events, Hermes-facing wrappers should prefer create-all-day-batch so the current TimeTree user is fetched once and reused for all event attendees. For timed events, wrappers should prefer create-timed rather than embedding Safari JavaScript locally.
Label policy
Create/update helpers can set label_id from a local YAML policy instead of hard-coding calendar-specific terms in source code.
cp timetree-labels.yaml.example timetree-labels.yaml
Edit timetree-labels.yaml with the target calendar's label IDs and matching terms. The local file is ignored by git.
To use a different policy file:
export TIMETREE_LABEL_POLICY_FILE=/path/to/timetree-labels.yaml
Security
Never commit or paste into chat:
- TimeTree passwords;
_session_id/_timetree_sessioncookies;- raw private calendar payloads;
- Google OAuth tokens or other downstream calendar credentials.
Local .env files are for development/runtime configuration only. Keep examples, docs, tests, logs, and issue comments sanitized.
Documentation
docs/authentication.md— session-cookie, sign-in, and non-interactive runtime guidance.docs/reverse-engineered-api.md— observed TimeTree web endpoints and payload notes.docs/roadmap.md— likely next steps and maintenance considerations.CHANGELOG.md— release history.
Development notes
When adding endpoint coverage:
- keep TimeTree-specific behavior behind
TimeTreeClientor narrow CLI helpers; - prefer mocked HTTP tests over live credentials;
- redact
_session_id, passwords, cookies, and raw private calendar data; - run
uv run pytestanduv run ruff check .before publishing changes.
License
Private/internal project unless a license is added later.