{"id":51476539,"url":"https://github.com/henrywen98/agendactl","last_synced_at":"2026-07-06T21:30:51.225Z","repository":{"id":367908940,"uuid":"1282758719","full_name":"henrywen98/agendactl","owner":"henrywen98","description":"An installable agent skill (bundled Swift CLI over EventKit) to control macOS Calendar \u0026 Reminders from any AI agent — Claude Code, Codex, Cursor, Gemini CLI, pi. No MCP, no servers, no arbitrary code execution.","archived":false,"fork":false,"pushed_at":"2026-06-28T07:55:48.000Z","size":280,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-28T09:09:58.502Z","etag":null,"topics":["agent-skills","ai-agent","apple-calendar","apple-reminders","automation","claude","claude-code","claude-skills","cli","eventkit","macos","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/henrywen98.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-28T06:53:28.000Z","updated_at":"2026-06-28T07:55:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/henrywen98/agendactl","commit_stats":null,"previous_names":["henrywen98/agendactl"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/henrywen98/agendactl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrywen98%2Fagendactl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrywen98%2Fagendactl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrywen98%2Fagendactl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrywen98%2Fagendactl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/henrywen98","download_url":"https://codeload.github.com/henrywen98/agendactl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrywen98%2Fagendactl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35206987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-skills","ai-agent","apple-calendar","apple-reminders","automation","claude","claude-code","claude-skills","cli","eventkit","macos","swift"],"created_at":"2026-07-06T21:30:51.118Z","updated_at":"2026-07-06T21:30:51.205Z","avatar_url":"https://github.com/henrywen98.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agendactl\n\n[![CI](https://github.com/henrywen98/agendactl/actions/workflows/ci.yml/badge.svg)](https://github.com/henrywen98/agendactl/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n![macOS 14+](https://img.shields.io/badge/macOS-14%2B-black?logo=apple)\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"docs/assets/demo.svg\" alt=\"agendactl: an agent answers a calendar question and creates a reminder by calling the agendactl CLI and parsing its JSON\" width=\"760\"\u003e\u003c/p\u003e\n\n**An installable agent skill that lets any AI agent read \u0026 write macOS Calendar and Reminders.** The skill bundles a single, auditable Swift CLI over Apple's [EventKit](https://developer.apple.com/documentation/eventkit) — `git clone` it into your agent's skills directory and it just works. **No MCP, no servers, no arbitrary code execution.**\n\n\u003e *\"Remind me to send the report at 9am tomorrow.\"* · *\"What meetings do I have this week?\"* · *\"Mark that one done.\"*\n\u003e The agent only ever calls `agendactl \u003capp\u003e \u003ccmd\u003e --flag …` and passes arguments — it never writes code, never touches EventKit, never gets an escape hatch.\n\n[English] · [中文](./README.zh-CN.md)\n\n---\n\n## In action\n\n```text\nyou  ▸ what meetings do I have this week?\n\nagent ▸ agendactl calendar list-events --from 2026-06-29T00:00:00 --to 2026-07-06T00:00:00\n      ← {\"_iso\":\"2026-06-29\",\"items\":[\n           {\"summary\":\"Design review\",\"calendar\":\"Work\",\n            \"start\":\"2026-07-02T01:00:00Z\",\"end\":\"2026-07-02T01:30:00Z\"} ]}\n      This week you have one meeting:\n        • Thu 07-02, 09:00–09:30 — Design review (Work)\n\nyou  ▸ remind me to send the report at 9am tomorrow\n\nagent ▸ agendactl reminders create --list Tasks --name \"Send report\" --due 2026-06-30T09:00:00\n      ← {\"id\":\"…\",\"name\":\"Send report\",\"list\":\"Tasks\",\"due\":\"2026-06-30T01:00:00.000Z\"}\n      Done — added \"Send report\" to Tasks, due tomorrow 09:00.\n```\n\nThe agent reads the SKILL.md, calls `agendactl` with arguments, parses the JSON, and answers\nin plain language. It never writes code or touches EventKit directly.\n\n## What it is\n\nA [Claude/agent **Skill**](https://github.com/VoltAgent/awesome-agent-skills): a folder with a `SKILL.md` (so the agent knows when and how to use it) plus a **prebuilt, signed universal binary** in `scripts/`. Install the folder, and any skill-aware agent — Claude Code, Codex, Cursor, Gemini CLI, pi — can manage your Calendar and Reminders. The same binary is a normal CLI you can run yourself or from cron/scripts.\n\n## Why a skill instead of an MCP server?\n\nThere are many MCP servers (and a few CLIs) for Apple Calendar/Reminders. `agendactl` takes a different shape:\n\n| | `agendactl` (skill + CLI) | typical Apple-app MCP server |\n|---|---|---|\n| Install | `git clone` a folder into your skills dir | configure an MCP server + its runtime |\n| Runtime to install | **none** — a bundled signed universal binary | Node / Python / bun |\n| Works with shell agents (Claude Code, Cursor, pi, cron, scripts) | ✅ directly | ❌ needs an MCP host |\n| Arbitrary code execution handed to the agent | ❌ none — arguments only, capability capped at the CLI surface | varies |\n| Auditable surface | one Swift file (~350 lines) you can read end-to-end | server + dependencies |\n| Backend | native EventKit (stable ids, millisecond queries) | EventKit / AppleScript / JXA |\n\n\u003e Scope is deliberate: shell-capable agents only. A GUI-only client that can't run a shell (e.g. Claude Desktop) is out of scope by design — that's the MCP servers' niche, and this isn't trying to be one.\n\nThe design wasn't arrived at lightly — it's the result of reversing an earlier \"JXA + escape-hatch\" architecture under scrutiny. Every reversal, with measurements, is in [`docs/adr/`](./docs/adr/).\n\n## Install\n\n**Requirements:** macOS 14+ (Sonoma or later), Apple Silicon or Intel. A prebuilt universal binary is committed at `skills/agendactl/scripts/agendactl`.\n\n**As an agent skill** (recommended) — copy the self-contained skill into your agent's skills directory:\n```bash\ngit clone https://github.com/henrywen98/agendactl.git\ncp -R agendactl/skills/agendactl ~/.agents/skills/agendactl    # shared agent-skills dir (pi, OpenCode, …)\n# or your agent's own dir: ~/.claude/skills/agendactl (Claude Code) · ~/.codex/skills/agendactl (Codex)\n```\nThe skill bundles the binary, so installing the skill is all that's needed — no `PATH` setup required.\nA skill-aware agent resolves the binary at `scripts/agendactl` relative to the skill's own directory. (`git clone` does not quarantine files, so the binary runs as-is. If you downloaded a ZIP from a browser, clear quarantine once: `xattr -dr com.apple.quarantine ~/.claude/skills/agendactl/scripts/agendactl`.)\n\n**As a plain CLI** (for your own scripts / cron) — put it on your `PATH`:\n```bash\nln -s \"$(pwd)/agendactl/skills/agendactl/scripts/agendactl\" /opt/homebrew/bin/agendactl\nagendactl --help\n```\n\n**Rebuild from source** (optional, for audit or a fresh build):\n```bash\n./skills/agendactl/scripts/build.sh        # 2× swiftc → lipo → codesign (universal2, ad-hoc)\n```\n\n## Permissions (one-time)\n\nEventKit is gated by macOS privacy (TCC). On first use, agendactl triggers the system prompt for **Calendar** and **Reminders** — approve it once in a logged-in GUI session (Calendar and Reminders are separate buckets). If not yet authorized, agendactl exits with code `3` and a hint. This step is inherent to any tool touching these apps and can't be skipped headlessly.\n\n## Usage\n\n```bash\nagendactl --help                 # overview\nagendactl reminders --help       # reminders commands\nagendactl calendar --help        # calendar commands\n\n# \"Remind me to send the report at 9am tomorrow\"\nagendactl reminders create --list \"Tasks\" --name \"Send report\" --due \"2026-06-29T09:00:00\"\n# → {\"id\":\"…\",\"name\":\"Send report\",\"list\":\"Tasks\",\"due\":\"2026-06-29T01:00:00.000Z\", …}\n\n# \"What meetings do I have this week?\"\nagendactl calendar list-events --from \"2026-06-29T00:00:00\" --to \"2026-07-06T00:00:00\"\n\n# \"Move that reminder to the day after\"\nagendactl reminders update \u003cid\u003e --due \"2026-07-01T09:00:00\"\n```\n\n**Contract** (so agents parse reliably):\n\n- Success → exit `0`, stdout is **JSON**. Every response carries `_at` / `_tz` / `_iso` / `_note` meta at the top level: list responses put the array under `items` (`{…meta, \"items\": [...]}`); write responses merge the meta keys onto the result fields. Failure → exit non-zero, stderr first line `agendactl: \u003creason\u003e`.\n- Exit codes: `0` ok · `1` usage/arg error · `2` not found (incl. duplicate-name ambiguity) · `3` not authorized · `4` runtime error.\n- Dates: input ISO 8601 (no tz suffix = local time); output UTC ISO. Every response carries `_at` / `_tz` / `_iso` / `_note` meta — use `._iso` to resolve \"today\".\n- Containers (calendars/lists) are addressed by **name**; duplicates return exit `2` + candidates, disambiguate with `--index \u003cn\u003e`.\n\n## Commands\n\n```\nagendactl calendar\n  calendars\n  list-events  [--calendar \u003cname\u003e] [--from \u003ciso\u003e] [--to \u003ciso\u003e] [--limit \u003cn\u003e]\n  create-event --calendar \u003cname\u003e --summary \u003ctext\u003e --start \u003ciso\u003e --end \u003ciso\u003e\n               [--location \u003ctext\u003e] [--notes \u003ctext\u003e] [--all-day]\n  update-event \u003cid\u003e [--summary] [--start] [--end] [--location] [--notes]\n  delete-event \u003cid\u003e\n\nagendactl reminders\n  lists\n  list     [--list \u003cname\u003e] [--status incomplete|completed|all] [--due today|\u003ciso\u003e] [--limit \u003cn\u003e]\n  create   --list \u003cname\u003e --name \u003ctext\u003e [--notes \u003ctext\u003e] [--due \u003ciso\u003e] [--priority 0-9]\n  update   \u003cid\u003e [--name] [--notes] [--due] [--priority] [--complete]\n  complete \u003cid\u003e\n  delete   \u003cid\u003e\n```\n\n## How it works\n\n```\nskill-aware agent (Claude Code / Codex / Cursor / Gemini CLI / pi)\n  └─ reads skills/agendactl/SKILL.md, calls:  agendactl \u003capp\u003e \u003ccmd\u003e --flag …  (args only)\n        │ runs the bundled binary\n        ▼\n  agendactl (Swift, EventKit) — arg validation, auth, time zones, stable ids, end\u003estart\n        ▼\n  macOS Calendar / Reminders (EKEvent / EKReminder) ← iCloud sync\n```\n\nThe CLI is the single source of truth: validation, authorization, time zones, stable ids, and business rules all live inside one Swift file.\n\n- **[ARCHITECTURE.md](./ARCHITECTURE.md)** — design contract (read this first)\n- **[docs/adr/](./docs/adr/)** — decision records (ADR-0001..0012, the v1→v2 evolution)\n- **[docs/glossary.md](./docs/glossary.md)** — domain language\n\n## Status\n\n- ✅ CLI runtime (`skills/agendactl/scripts/agendactl`, EventKit, Calendar + Reminders CRUD)\n- ✅ Agent skill (`skills/agendactl/SKILL.md`)\n- ✅ Tests: smoke (no-auth contract) and round-trip (EventKit CRUD, `__probe__`-tagged, idempotent, self-cleaning)\n- 🔜 Notes (needs a JXA backend) · Mail / Contacts · scheduled automation\n\n```bash\n./tests/smoke.sh        # contract checks, no authorization / no data written\n./tests/roundtrip.sh    # full EventKit CRUD round-trip (needs TCC auth; writes \u0026 cleans __probe__ items)\n```\n\n## License\n\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenrywen98%2Fagendactl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenrywen98%2Fagendactl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenrywen98%2Fagendactl/lists"}