@torsday/omnifocus-mcp 1.0.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -2
- package/README.md +68 -10
- package/dist/index.js +2258 -193
- package/package.json +11 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,153 @@ All notable changes to `@torsday/omnifocus-mcp` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). See [ADR-0011](./docs/adr/0011-versioning-and-stability.md) for the explicit definition of breaking vs additive changes in this project.
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
## [1.2.0](https://github.com/torsday/omnifocus-mcp/compare/v1.1.0...v1.2.0) (2026-04-29)
|
|
9
|
+
|
|
10
|
+
**Summary** — The headline additions are **outbound webhooks** (a full HTTPS + HMAC delivery subsystem that fires when OmniFocus state changes), **macOS Calendar integration** via a Swift EventKit bridge (with new `omnifocus://calendar` and `omnifocus://agenda` resources that merge calendar events with the OF Forecast view), **decision-journal** support (record user judgment on tasks/projects so agent-driven scans stop re-litigating the same anomaly), **natural-language perspective authoring** (a new MCP prompt + `perspective_create`/`update`/`delete`/`evaluate_dry_run` tools), **`task_defer_smart`** (intent-bearing defer-date grammar so agents stop landing tasks on weekends or 11 pm), and **mutation testing** wired in as a release-time hard gate (Stryker, calibrated baseline, fails publish on regression). Several existing surfaces were tightened — `task_extract_from_image` moved its post-parse validation rules into the Zod schema for cleaner error envelopes, several batch tools gained `.describe()` coverage on inner fields, and a handful of read-side responses now pair human-readable names with opaque IDs for the same reason v1.1.0 introduced the convention. Two new ADRs lock the architectures (ADR-0016 webhook delivery, ADR-0018 calendar bridge). No breaking changes; all v1.0.x / v1.1.x call shapes are unchanged.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Outbound webhooks — `webhook_register`, `webhook_list`, `webhook_delete`, `webhook_test` (closes [#483](https://github.com/torsday/omnifocus-mcp/issues/483))** — first-class agent-observable event subsystem per [ADR-0016](./docs/adr/0016-webhook-delivery.md). Triggers cover **task-completed**, **task-created**, and **project-status-changed**, with optional per-trigger filters on `projectId` / `tagId`. Delivery is HTTPS-only at registration (http:// rejected), payload is JSON, optional HMAC-SHA256 signing via `X-OmniFocus-Signature: sha256=<hex>` (GitHub's header convention) when a secret is registered. Retry policy is **1s/5s/30s exponential backoff** (~36s total) on transport failure or non-2xx response, with a **per-webhook circuit breaker** that auto-disables a hook for **1 hour** after **10 consecutive failed deliveries**. Persistence lives at `~/Library/Application Support/omnifocus-mcp/webhooks.json` (mode 0600, schema-versioned, atomic tmp+rename writes). The whole subsystem is **off by default** behind `OMNIFOCUS_WEBHOOKS_ENABLED=1`, mirroring `OMNIFOCUS_ALLOW_RAW_SCRIPT`. URLs and HMAC secrets are stored on disk only — never echoed back through any tool response or surfaced on `omnifocus://capabilities` (which gains a `webhooks: { enabled, count, names }` field for visibility without leakage). `webhook_test` fires a synthetic event through the same HTTPS + HMAC + retry + circuit-breaker path as a real delivery — if the receiver doesn't see the synthetic, real events won't reach it either. Real-event firing rides the existing `DatabaseWatcher` chain: every detected OF state change feeds a fresh full snapshot to the orchestrator's diff/dispatch loop, with a `shouldObserve()` fast path so the snapshot fetch is skipped entirely when no webhook is registered (zero overhead for the default case). Failure-mode discipline (ADR-0016 §4e): every failure path is caught internally and logged to stderr, never propagates into the OF read path. The `node:https` import is allowlisted via the repo's network-import lint rule for `src/webhooks/` only.
|
|
15
|
+
|
|
16
|
+
- **macOS Calendar bridge + `omnifocus://calendar` and `omnifocus://agenda` resources (closes [#484](https://github.com/torsday/omnifocus-mcp/issues/484))** — read-only EventKit access via a tiny Swift subprocess bundled in `dist/`, per [ADR-0018](./docs/adr/0018-calendar-bridge.md). The Node-side `CalendarBridge` wrapper (`src/bridge/calendarBridge.ts`) exposes `ping()`, `getPermission()`, `requestAccess()`, and `readEvents(from, to, sources?)`. New typed errors: `CalendarPermissionDenied` (suggests granting Calendar access in System Settings) and `CalendarBridgeUnavailable` (suggests `pnpm build:calendar-bridge`). The `omnifocus://calendar{?from,to}` resource returns `{ events: CalendarEvent[] }` carrying `id, title, startsAt, endsAt, allDay, calendarName, calendarSource, location?, status, isAttendee?` — defaults span the current local-zone day, cached 60s on the `(from, to, sourcesEnv)` tuple. Calendar source filter via `OMNIFOCUS_CALENDAR_SOURCES` (read at request time so operators can change it without restarting). The `omnifocus://agenda{?date}` resource is the user-facing payoff — a sorted timeline of `{ items, floating }` where `items[]` interleaves calendar events and timed OF tasks by `startsAt` and `floating[]` is the bucket of OF tasks with no `dueDate`. The `omnifocus://capabilities` resource and `internal_status` tool both gain a `calendarAccess: { available, permission }` block: `available` is `true` when the bridge binary is callable, `permission` mirrors `EKEventStore.authorizationStatus(for: .event)` mapped to `granted | denied | restricted | not-determined`. Probes are read-only — they never trigger the macOS Calendar TCC prompt. ([#484](https://github.com/torsday/omnifocus-mcp/issues/484), [#637](https://github.com/torsday/omnifocus-mcp/issues/637))
|
|
17
|
+
|
|
18
|
+
- **Decision journal — `decision_record`, `decision_clear`, and project-health honor (closes [#485](https://github.com/torsday/omnifocus-mcp/issues/485))** — agent-memory of user judgment via a `decision-journal` fenced YAML block on a task or project note. `Decision` carries a `kind` from a closed set (`stall-is-intentional`, `deferred-by-choice`, `blocked-on-external`, `awaiting-decision`, `acknowledged-zombie`), a human-readable `reason`, an automatically-set `recordedAt`, and an optional `until` ISO-8601 auto-expiry (`isDecisionActive` returns false when `until` is in the past). The fence reuses the shared `noteFences` helper from #482 so `waiting-on` and `decision-journal` blocks coexist without conflict. Read-side integration: `task_get`, `task_get_many`, `project_get`, and `project_get_many` now surface a `decision` field whenever a fence is present (or a `decisions` map keyed by id on the `*_many` variants). The `omnifocus://project-health` resource partitions flagged projects into a new `acknowledged: ProjectHealthEntry[]` array when an active decision-journal fence is present, so callers can surface the user's recorded judgment ("Strategic pause until Q3 budget cycle") inline instead of re-litigating it. When `until` passes, the project re-emerges in `projects` automatically — the fence is preserved as audit history, never deleted. Malformed fences degrade silently. DESIGN.md §31 documents the fenced-metadata convention. ([#485](https://github.com/torsday/omnifocus-mcp/issues/485), [#589](https://github.com/torsday/omnifocus-mcp/issues/589))
|
|
19
|
+
|
|
20
|
+
- **Natural-language perspective authoring — `perspective-author` MCP prompt + `perspective_create` / `perspective_update` / `perspective_evaluate_dry_run` (closes [#476](https://github.com/torsday/omnifocus-mcp/issues/476), [#577](https://github.com/torsday/omnifocus-mcp/issues/577), [#659](https://github.com/torsday/omnifocus-mcp/issues/659))** — full authoring loop for OmniFocus custom perspectives. The new `perspective-author` MCP prompt turns a free-text description ("everything I could do at home, on a phone, with under 15 minutes") into a saved perspective via a three-step flow: (1) propose a `PerspectiveRule[]` tree from the prose, (2) preview matched tasks via `perspective_evaluate_dry_run`, (3) save via `perspective_create` only after user confirmation. The prompt embeds a reference card of every rule-tree atom (`actionAvailability`, `actionStatus`, `actionHasAllOfTags`, `actionHasAnyOfTags`, `actionHasNoProject`, `actionHasDueDate`, `actionHasDeferDate`, `actionIsLeaf`, `actionIsProject`, `actionMatchingSearch`, `actionWithinFocus`) with three worked examples, so agents have the full vocabulary without web access. `perspective_create` lands a custom perspective via OmniJS with atomic rollback (a partial create is undone if any step fails), `perspective_update` patches name/aggregation/rules/iconColor without rebuilding from scratch. `perspective_evaluate_dry_run` previews a proposed rule tree without persisting it — implementation creates a temporary perspective with a sentinel name, evaluates it, and **always** deletes the temp inside one OmniJS execution so a transport-level retry between hops can't leave an orphan. Inputs flow through a strict `PerspectiveRuleInputSchema` with disjointness + strict-shape refinements at the boundary. Custom perspectives require OmniFocus Pro; built-in perspective IDs are rejected with a typed error. ([#476](https://github.com/torsday/omnifocus-mcp/issues/476), [#577](https://github.com/torsday/omnifocus-mcp/issues/577), [#617](https://github.com/torsday/omnifocus-mcp/issues/617), [#618](https://github.com/torsday/omnifocus-mcp/issues/618), [#619](https://github.com/torsday/omnifocus-mcp/issues/619), [#659](https://github.com/torsday/omnifocus-mcp/issues/659))
|
|
21
|
+
|
|
22
|
+
- **`task_defer_smart` + `task_batch_defer_smart` — intent-bearing defer-date grammar (closes [#479](https://github.com/torsday/omnifocus-mcp/issues/479))** — two new tools that wrap `task_update`'s defer path with a high-level intent so agents stop landing tasks on weekends or 11 pm. `DeferIntent` is a discriminated union with six variants: `next-work-day` (Mon if today is Fri/Sat/Sun, else tomorrow; at the configured morning or afternoon hour), `next-weekday: { weekday: 0..6 }` (next *strict* occurrence — today→full week away if the day matches), `in-business-days: { days: N }` (skips weekends; returns morning hour), `next-month-start` (first of next month, midnight), `explicit-with-skip-weekends: { date: ISO }` (snaps forward to Monday if the input lands on Sat/Sun), and `after-event: { eventId }` (gated on calendar bridge — currently throws a typed `CalendarBridgeUnavailable` for follow-up). Morning/afternoon defaults via env: `OMNIFOCUS_MORNING_HOUR` (default 9), `OMNIFOCUS_AFTERNOON_HOUR` (default 14). Resolution is pure (no I/O); tests inject `now` deterministically. The tool composes with `dry_run`, `idempotency_key`, and `expectedModifiedAt` like the rest of the write surface. Returns `{ taskId, resolvedDeferDate, reason }` so the agent can echo `"deferred to Mon 27 Apr 09:00 (next work morning)"` verbatim. The batch variant accepts `entries: [{ taskId, intent }]` and surfaces per-entry success/error rows so one malformed intent does not abort siblings. ([#479](https://github.com/torsday/omnifocus-mcp/issues/479))
|
|
23
|
+
|
|
24
|
+
- **`clarification-needed` response kind — third response variant for negotiation rather than guess-and-fail ([#493](https://github.com/torsday/omnifocus-mcp/issues/493))** — one of the five children of the NL-excellence epic (#491) lands as a new envelope variant. When a tool can't proceed without user-supplied disambiguation but the underlying request is structurally valid, it returns `{ kind: "clarification-needed", question, choices?, replayToken }` instead of throwing a validation error. The agent re-prompts the user, then replays the original call with the user's selection plus the `replayToken` so the server can correlate the second attempt with the first. Lets agents treat ambiguity as a conversation rather than an immediate failure, without losing the original input shape across the round-trip.
|
|
25
|
+
|
|
26
|
+
- **`project_template_delete` ([#588](https://github.com/torsday/omnifocus-mcp/issues/588))** — companion to v1.1.0's `project_template_save` / `_list` / `_instantiate`. Removes a saved template by name from the configured Templates folder, reporting `noChange:true` when the template was already absent so the call is idempotent across retries.
|
|
27
|
+
|
|
28
|
+
- **Mutation-score surface on `internal_status` (slice 1D of [#502](https://github.com/torsday/omnifocus-mcp/issues/502))** — the `internal_status` response gains `mutation: { score, lastRunAt } | null`. `score` is the live mutation score computed from `<package-root>/reports/mutation/mutation.json` using Stryker's standard formula `(killed + timeout) / (killed + survived + timeout + noCoverage)`; `lastRunAt` is the report file's mtime as ISO-8601. Returns `null` when no report is present — the published npm tarball ships without `reports/`, so end-user installs degrade cleanly while dev / CI clones surface live calibration freshness. Probe is read-only and synchronous; injectable via `InternalStatusContext.probeMutationScore` for tests.
|
|
29
|
+
|
|
30
|
+
- **NL-quality follow-ups — name-paired responses across remaining batch and review surfaces ([#571](https://github.com/torsday/omnifocus-mcp/issues/571), [#607](https://github.com/torsday/omnifocus-mcp/issues/607), [#608](https://github.com/torsday/omnifocus-mcp/issues/608), [#609](https://github.com/torsday/omnifocus-mcp/issues/609))** — extends v1.1.0's "pair human-readable name with opaque ID" convention to the remaining surfaces that hadn't yet been covered: every batch tool's inner `.describe()` lines, `task_find_similar` candidate rows, the `review_*` family + `project_mark_reviewed` + `project_set_next_review_date`, and `import_opml` / `import_taskpaper` owner names on the import-result rows. Same payoff as v1.1.0: agents echo the human-readable identifier without a follow-up `*_get` call. Closes [#601](https://github.com/torsday/omnifocus-mcp/issues/601).
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- **`task_extract_from_image` — schema-discipline refactor (closes [#574](https://github.com/torsday/omnifocus-mcp/issues/574))** — closes the Class-5 finding from the NL-quality audit. The image-extension validity check (previously a runtime `ValidationError` thrown after Zod parse) and the `attachment-mode source requires attachSourceTo='none'` rule (likewise post-parse) are now expressed as Zod refinements at the input boundary, so violations surface as structured `ActionableValidation` failures keyed on the offending field rather than as opaque error throws partway through the handler. Inner fields on the `source` discriminated-union members (`attachmentId`, `ownerTaskId`, `ownerProjectId`) and the top-level `targetProjectId` gained `.describe()` lines per the rubric. No behavior change for valid inputs; tighter rejection (with structured errors) for invalid ones. The single-tool shape was kept — splitting into propose-then-commit tools was considered but rejected since #479's `task_defer_smart` and `repetition_from_prose` already model the `*_from_prose` pattern as single-tool.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **README — `omnifocus://intents` row no longer claims a tool count ([#645](https://github.com/torsday/omnifocus-mcp/issues/645))** — the README's intents-row mentioned a numeric tool count, which the repo's `no-tool-counts` lint gate prohibits (counts drift the moment new tools land). Restored gate compliance ([#646](https://github.com/torsday/omnifocus-mcp/issues/646)).
|
|
39
|
+
|
|
40
|
+
### Documentation
|
|
41
|
+
|
|
42
|
+
- **ADR-0016 — Webhook delivery for OmniFocus state changes (closes [#662](https://github.com/torsday/omnifocus-mcp/issues/662))** — locks the architecture for [#483](https://github.com/torsday/omnifocus-mcp/issues/483)'s outbound webhook subsystem. Four decisions: (1) **trigger source** — polling-on-cache-refresh, riding the existing 30-second LRU cache (ADR-0006) rather than undocumented OmniJS observers or a new timer; lag bound by cache TTL is documented as a known property; (2) **persistence** — JSON config file at `~/Library/Application Support/omnifocus-mcp/webhooks.json`, mode 0600, schema-versioned, hot-reloaded via `fs.watch`; (3) **retry policy** — exponential 1s/5s/30s with a per-webhook circuit breaker (10 consecutive failures → auto-disable for 1h); best-effort delivery, no dead-letter queue; (4) **security model** — off by default behind `OMNIFOCUS_WEBHOOKS_ENABLED=1` (mirroring ADR-0004's escape-hatch discipline), HTTPS-only at registration, optional HMAC-SHA256 signatures using GitHub's header convention, capability resource exposes counts + names but never URLs or secrets, delivery failures log to stderr and never propagate into the OF read path. Status: Accepted.
|
|
43
|
+
|
|
44
|
+
- **ADR-0018 — Calendar bridge: EventKit only, Swift-binary subprocess** — formalises the architecture that unblocks [#484](https://github.com/torsday/omnifocus-mcp/issues/484) (calendar + agenda resources). Decisions: EventKit is the sole calendar substrate (third-party APIs handled by separate MCP servers, composed at the agent layer); access via a tiny Swift binary subprocess bundled in `dist/` (rejecting JXA/Calendar.app shim and direct Node FFI for documented reasons); read-only; permission UX mirrors the existing OF Automation prompt. Status: Accepted. ([#603](https://github.com/torsday/omnifocus-mcp/issues/603))
|
|
45
|
+
|
|
46
|
+
- **README — agent-native value-add lead (closes [#477](https://github.com/torsday/omnifocus-mcp/issues/477))** — new top-of-README section "Agent-native OmniFocus — beyond the app surface" frames the agent-unique capabilities (project-health triage, semantic dedupe, taxonomy audit, NL perspective authoring, time-budget reconciliation, retrospective, project templates, inbox-triage, calendar + agenda) ahead of the existing tool-list content. Honest split between mechanical aggregations the app could have shipped and capabilities only valuable with an LLM in the call path; closes the long-standing narrative gap that the README led with "wrapper" framing rather than the actual value-add.
|
|
47
|
+
|
|
48
|
+
- **README — Resources table refreshed for 24 URIs (closes [#643](https://github.com/torsday/omnifocus-mcp/issues/643))** — the README's MCP resources table had drifted to ten entries while the resource surface grew to twenty-four. Refreshed to the current set so users browsing the README see the actual capability surface.
|
|
49
|
+
|
|
50
|
+
- **DESIGN.md §31 — fenced note metadata convention ([#589](https://github.com/torsday/omnifocus-mcp/issues/589))** — formalises the fenced-YAML pattern that `waiting-on`, `decision-journal`, and `project-template` all share. New conventions filed under §31 so agents and contributors have one place to look for "how do we encode structured metadata in a free-text note without forcing the user to see it."
|
|
51
|
+
|
|
52
|
+
- **Stryker mutation-testing docs (slice 1E of [#502](https://github.com/torsday/omnifocus-mcp/issues/502))** — adds a `mutation-tested: stryker` badge to the README badge row (links to ADR-0017) and a "Mutation testing (release-time hard gate)" section to `CONTRIBUTING.md` covering local run command (`pnpm mutation`, ~6–7 min wall-clock), report locations, the equivalent-mutant policy per ADR §5 (default response to a survivor is to write the test; only observably equivalent mutations belong in `stryker-equivalents.json`, with a one-line rationale), the release-time gate placement, and how to query live calibration freshness via `internal_status`.
|
|
53
|
+
|
|
54
|
+
### Build
|
|
55
|
+
|
|
56
|
+
- **Stryker mutation testing — installation, calibration, and release-time hard gate (slices 1A/1B/1C of [#502](https://github.com/torsday/omnifocus-mcp/issues/502))** — three slices land Stryker as a release-time quality gate per [ADR-0017](./docs/adr/0017-mutation-testing.md). Slice 1A added the dependencies (`@stryker-mutator/core`, `typescript-checker`, `vitest-runner`), `stryker.conf.json` with the ADR §2 mutator allowlist (`src/domain`, `src/errors`, `src/middleware`, `src/server`, tool input-validation schemas), the `pnpm mutation` script, and the `stryker-equivalents.json` scaffold with the §5 header convention. Slice 1B captured the calibration baseline — 2740 mutants instrumented across 35 source files, 6m42s wall-clock, mutation score **62.74%** — and set `thresholds.break = baseline − 5 = 57.74` per ADR §3. Three slice-1A defects were fixed during calibration: removed nonexistent `ignorers` plugin references, dropped two empty allowlist globs, and added an explicit `plugins:` array because pnpm's strict node_modules layout breaks Stryker's auto-discovery in spawned children. Slice 1C wired `pnpm mutation` into `release.yml` between `pnpm test` and `pnpm build`; the gate fails the release on any drop below `thresholds.break`, and the HTML + JSON reports upload as a `mutation-report-<tag>` workflow artifact (90-day retention, `if: always()` so a failed run still uploads). Runs once per release tag, not per PR.
|
|
57
|
+
|
|
58
|
+
- **Calendar bridge — Swift scaffold + build pipeline (slices 1–5 of [#484](https://github.com/torsday/omnifocus-mcp/issues/484))** — five slices land the Swift `calendar-bridge` subprocess and Node-side wrapper that the calendar/agenda resources ride on. Adds `tools/calendar-bridge/calendar-bridge.swift` and `scripts/build-calendar-bridge.sh` (mirroring `build-watcher.sh`: single-arch / `--all` for fat universal binary / `--verify` for typecheck-only). Build hooks: `pnpm build:calendar-bridge` and `pnpm build:calendar-bridge:all`. Binaries gitignored. Subcommands lay down progressively: `ping`, `permission` (read-only `EKEventStore.authorizationStatus(for: .event)` — does NOT trigger TCC prompt), `request-access` (calls `requestFullAccessToEvents` on macOS 14+, falls back to `requestAccess(to:completion:)` for older macOS — first invocation triggers the TCC prompt), and finally `calendar FROM TO` (event read via `predicateForEvents(withStart:end:calendars:)` + `events(matching:)` with hand-rolled JSON output). The Node-side `CalendarBridge` wrapper spawns the binary as a one-shot subprocess and parses one JSON line of stdout. Constructor accepts `{ binaryPath, spawn, existsSync }` overrides for tests, so the wrapper has full coverage on Linux CI without a built binary or TCC grant.
|
|
59
|
+
|
|
60
|
+
- **Bundle budget bumps for new subsystems** — bundle-size budget raised in step with new code: 610 → 625 KiB for the perspective-write tools (#577), then to 680 KiB through the webhooks subsystem (#483). Each bump landed with the slice that consumed it; the budget remains enforced in `release.yml` via `scripts/check-bundle-size.sh`.
|
|
61
|
+
|
|
62
|
+
- **Lint allowlist — `src/webhooks/` may import `node:https`** — the repo's `customRules.ts` `no-network-import` rule and `biome.json` `noRestrictedImports` were extended with a `src/webhooks/` allowlist so the dispatcher can call `node:https.request`. Per ADR-0016, outbound HTTPS is permitted only there.
|
|
63
|
+
|
|
64
|
+
- **CI — required-status-checks documentation ([#648](https://github.com/torsday/omnifocus-mcp/issues/648))** — documents which CI checks `main` branch protection requires, so contributors don't get blocked merging when an advisory check fails. No behavior change.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
## [1.1.0](https://github.com/torsday/omnifocus-mcp/compare/v1.0.2...v1.1.0) (2026-04-28)
|
|
68
|
+
|
|
69
|
+
**Summary** — The headline additions are project templates, waiting-on tracking, and several new analytics resources. Alongside new tools, the entire tool surface went through a focused NL-quality pass: every description now carries a worked `Example:` line, every mutation response pairs a human-readable name alongside the opaque ID, and enum inputs accept common aliases so loosely-worded agent inputs succeed rather than bounce. Agents calling this server cold will be able to compose correct calls with substantially less trial-and-error. No breaking changes; all v1.0.x call shapes are unchanged.
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **Project templates — `project_template_save`, `project_template_list`, `project_template_instantiate`** — capture a project's task tree as TaskPaper into a `Templates` folder (folder name configurable via `OMNIFOCUS_TEMPLATES_FOLDER_NAME`), then spawn a new project from any saved template with `{{placeholder}}` substitution and automatic `@due`/`@defer` date-shifting anchored to the template's earliest due date. Parameters are validated on instantiation — every declared `{{name}}` must have a supplied value, and all missing names are reported in a single typed `MissingTemplateParameter` error. Convention documented in DESIGN.md §30. ([#472](https://github.com/torsday/omnifocus-mcp/issues/472), [#587](https://github.com/torsday/omnifocus-mcp/issues/587))
|
|
74
|
+
|
|
75
|
+
- **Waiting-on tracking** — `task_set_waiting_on` and `task_clear_waiting_on` write/strip a fenced YAML block at the top of a task's note recording `whom`, `what`, `since`, and `followUpAfter`. The configured `@waiting` tag is added/removed automatically. `task_get` and `task_get_many` surface a structured `waitingOn` field on affected tasks. New `omnifocus://waiting-on` resource lists every open waiting-on task sorted by days overdue. ([#482](https://github.com/torsday/omnifocus-mcp/issues/482))
|
|
76
|
+
|
|
77
|
+
- **`perspective_get` and `perspective_delete`** — `perspective_get` returns the full rule tree for a custom perspective so agents can inspect what it filters without evaluating it. `perspective_delete` removes it and invalidates the perspective cache. Both reject built-in perspective IDs with a typed error; both require OmniFocus Pro. ([#523](https://github.com/torsday/omnifocus-mcp/issues/523))
|
|
78
|
+
|
|
79
|
+
- **`*_describe` preview tools for every write operation** — a companion `task_create_describe`, `project_create_describe`, etc. returns a human-readable summary of what the live call would do, without touching OmniFocus. Lets agents confirm intent before firing a mutation. ([#494](https://github.com/torsday/omnifocus-mcp/issues/494))
|
|
80
|
+
|
|
81
|
+
- **`database_undo` and `database_redo`** — exposes OmniFocus's undo/redo stack so agents can recover from mistakes without manual user intervention. ([#544](https://github.com/torsday/omnifocus-mcp/issues/544))
|
|
82
|
+
|
|
83
|
+
- **`task_extract_from_image`** — vision tool that accepts a base64-encoded image and returns structured task proposals extracted from handwritten notes, whiteboard photos, or screenshots. ([#486](https://github.com/torsday/omnifocus-mcp/issues/486))
|
|
84
|
+
|
|
85
|
+
- **`task_extract_from_note`** — parses free-form prose (meeting notes, bullet lists, brain dumps) into structured `task_batch_create` candidates with optional project and tag assignments. ([#536](https://github.com/torsday/omnifocus-mcp/issues/536))
|
|
86
|
+
|
|
87
|
+
- **`task_reclassify`** — moves a task between inbox, project, or parent with a mandatory dry-run first pass showing the proposed change before committing. ([#545](https://github.com/torsday/omnifocus-mcp/issues/545))
|
|
88
|
+
|
|
89
|
+
- **`task_find_similar`** — lexical-similarity search across task names to detect near-duplicates before creating new tasks. ([#543](https://github.com/torsday/omnifocus-mcp/issues/543))
|
|
90
|
+
|
|
91
|
+
- **`task_convert_to_project`** — promotes a task to a first-class project via `Database.convertTasksToProjects`, preserving subtasks and metadata.
|
|
92
|
+
|
|
93
|
+
- **`task_set_alarms` and `task_clear_alarms`** — add or remove OmniFocus notification alarms on a task; supports absolute-date, relative-to-due, and relative-to-defer alarm types. ([#461](https://github.com/torsday/omnifocus-mcp/issues/461))
|
|
94
|
+
|
|
95
|
+
- **`repetition_from_prose`** — deterministic converter from natural-language repetition strings ("every weekday", "every 2 weeks on Monday") to a validated `RepetitionRule` ready for `task_create` or `task_update`. ([#535](https://github.com/torsday/omnifocus-mcp/issues/535))
|
|
96
|
+
|
|
97
|
+
- **`forecast_pack`** — time-budget reconciliation: given a target date and a daily minute budget, assigns tasks from the Forecast view into day buckets and surfaces overloaded days. ([#473](https://github.com/torsday/omnifocus-mcp/issues/473))
|
|
98
|
+
|
|
99
|
+
- **Forecast tag preference (`forecast_get_tag`, `forecast_set_tag`)** — read and write the OmniFocus Forecast tag preference (the tag whose tasks appear in the Forecast view). ([#465](https://github.com/torsday/omnifocus-mcp/issues/465))
|
|
100
|
+
|
|
101
|
+
- **`project_set_next_review_date`** — set the next scheduled review date on a project without waiting for the review cycle to elapse naturally. ([#467](https://github.com/torsday/omnifocus-mcp/issues/467))
|
|
102
|
+
|
|
103
|
+
- **`app_window_new` and `app_window_new_tab`** — open a new OmniFocus window or a new tab on the frontmost window for guided-review flows. ([#558](https://github.com/torsday/omnifocus-mcp/issues/558))
|
|
104
|
+
|
|
105
|
+
- **`window_set_focus` and `window_set_perspective`** — set the focus context and switch the active perspective on the front window, enabling agent-driven guided workflows. ([#466](https://github.com/torsday/omnifocus-mcp/issues/466))
|
|
106
|
+
|
|
107
|
+
- **`task_batch_assign` + inbox-triage prompt** — bulk-assign tags, projects, and dates to a list of task IDs in one round trip; paired with a built-in `inbox-triage` MCP prompt that sequences the tool calls for a full GTD-style processing sweep. ([#539](https://github.com/torsday/omnifocus-mcp/issues/539))
|
|
108
|
+
|
|
109
|
+
- **`deferDateFloating` and `dueDateFloating` on all date-bearing tools** — mark a date as "floating" (timezone-independent) at the field level, matching OmniFocus's own semantics for travel-friendly tasks. ([#462](https://github.com/torsday/omnifocus-mcp/issues/462))
|
|
110
|
+
|
|
111
|
+
- **Seven new read resources:**
|
|
112
|
+
- `omnifocus://intents` — index of every tool grouped by the eight core verb intents, for agent orientation ([#530](https://github.com/torsday/omnifocus-mcp/issues/530))
|
|
113
|
+
- `omnifocus://project-health` — stalled-project triage: projects with no incomplete tasks, overdue reviews, or no activity in 30+ days ([#534](https://github.com/torsday/omnifocus-mcp/issues/534))
|
|
114
|
+
- `omnifocus://retrospective` — completed-task summary over a caller-specified date range ([#474](https://github.com/torsday/omnifocus-mcp/issues/474))
|
|
115
|
+
- `omnifocus://stats` — database statistics (task counts by status, project counts, tag usage) ([#533](https://github.com/torsday/omnifocus-mcp/issues/533))
|
|
116
|
+
- `omnifocus://velocity` and `omnifocus://burndown` — completion-rate and open-task-trend analytics over rolling windows ([#513](https://github.com/torsday/omnifocus-mcp/issues/513))
|
|
117
|
+
- `omnifocus://taxonomy-audit` — detects tag and project name collisions before a batch import causes duplicates ([#509](https://github.com/torsday/omnifocus-mcp/issues/509))
|
|
118
|
+
- `omnifocus://recent-activity` — session-priming snapshot of tasks touched in the last N hours, useful for resuming context at the start of a session ([#505](https://github.com/torsday/omnifocus-mcp/issues/505))
|
|
119
|
+
|
|
120
|
+
- **Response envelope improvements** — every `ok` response now carries a `hints[]` array (agent-readable suggestions about next steps) and a `humanReadableSummary` string (one-line confirmation of what was just done). Both fields are defined in ADR-0015. ([#524](https://github.com/torsday/omnifocus-mcp/issues/524))
|
|
121
|
+
|
|
122
|
+
### Improved
|
|
123
|
+
|
|
124
|
+
- **NL-quality: `Example:` on every tool description** — all ~95 `*_DESCRIPTION` constants now end with at least one `Example: tool_name({ … })` line; multi-mode tools include 2–3 representative examples. Agents can construct a first call from the description alone. ([#570](https://github.com/torsday/omnifocus-mcp/issues/570))
|
|
125
|
+
|
|
126
|
+
- **NL-quality: name paired with id in all mutation responses** — tools that previously returned a bare `{ id }` now return `{ id, name }`. Agents can confirm what was just created or modified without a follow-up `*_get` call. Covers task verbs, project verbs, batch operations, attachments, notes, and forecast-tag operations. ([#572](https://github.com/torsday/omnifocus-mcp/issues/572), [#585](https://github.com/torsday/omnifocus-mcp/issues/585), [#590](https://github.com/torsday/omnifocus-mcp/issues/590), [#592](https://github.com/torsday/omnifocus-mcp/issues/592), [#597](https://github.com/torsday/omnifocus-mcp/issues/597), [#606](https://github.com/torsday/omnifocus-mcp/issues/606))
|
|
127
|
+
|
|
128
|
+
- **NL-quality: forgiving enum aliases** — status, completion-criterion, and related fields now accept common synonyms (`"done"`, `"dropped"`, `"active"`, etc.) alongside the canonical values. Mis-typed or loosely-worded agent inputs are accepted rather than rejected. ([#573](https://github.com/torsday/omnifocus-mcp/issues/573))
|
|
129
|
+
|
|
130
|
+
- **NL-quality: `zodToActionable` input-error rewriting** — Zod validation failures at the tool boundary are translated into structured, agent-actionable messages naming the failing field and stating the accepted value set, instead of surfacing raw Zod issue arrays. ([#575](https://github.com/torsday/omnifocus-mcp/issues/575))
|
|
131
|
+
|
|
132
|
+
### Fixed
|
|
133
|
+
|
|
134
|
+
- **Repeating-task IDs accepted everywhere** — OmniFocus appends a `.N` suffix to IDs of repeating-task instances (e.g. `abc123.1`). These were previously rejected by the ID validator, causing lookups on the second and later occurrences of a repeating task to fail. ([#497](https://github.com/torsday/omnifocus-mcp/issues/497))
|
|
135
|
+
|
|
136
|
+
- **`export_taskpaper` includes project-level tasks** — tasks attached directly to the project node were silently dropped from TaskPaper exports. ([#499](https://github.com/torsday/omnifocus-mcp/issues/499))
|
|
137
|
+
|
|
138
|
+
- **JXA date metadata no longer throws on inaccessible objects** — certain completed tasks returned a `can't get object` AppleScript error when `creationDate`/`modificationDate` were read. The JXA layer now guards these reads and returns `null` instead. ([#498](https://github.com/torsday/omnifocus-mcp/issues/498))
|
|
139
|
+
|
|
140
|
+
- **`tag_list`/`folder_list` null filters treated as no-filter** — passing `null` for an optional filter (e.g. `parentId: null`) was misinterpreted as an active filter and returned empty results. ([#515](https://github.com/torsday/omnifocus-mcp/issues/515))
|
|
141
|
+
|
|
142
|
+
### Performance
|
|
143
|
+
|
|
144
|
+
- **`forecast_get` ~50× faster** — bucket filters are pushed into the JXA `whose()` clause so OmniFocus evaluates them database-side rather than returning all tasks and filtering in JavaScript. Cold fetches on large databases drop from 4–8 s to under 200 ms. ([#500](https://github.com/torsday/omnifocus-mcp/issues/500))
|
|
145
|
+
|
|
146
|
+
### Documentation
|
|
147
|
+
|
|
148
|
+
- **Setup guides for OpenCode and Pi** — `docs/clients/opencode.md` covers OpenCode's `opencode.json` MCP config format. `docs/clients/pi.md` documents that Pi (pi.ai) has no MCP client support as of mid-2025. ([#559](https://github.com/torsday/omnifocus-mcp/issues/559))
|
|
149
|
+
- **Homebrew tap** — `torsday/homebrew-tap` now carries a formula; the release workflow patches it automatically after each npm publish. Non-Node users can install via `brew install torsday/tap/omnifocus-mcp`.
|
|
150
|
+
- **ADR-0015** — NL-excellence response envelope (hints, humanReadableSummary). ([#524](https://github.com/torsday/omnifocus-mcp/issues/524))
|
|
151
|
+
- **ADR-0017** — mutation testing as release gate. ([#528](https://github.com/torsday/omnifocus-mcp/issues/528))
|
|
152
|
+
- **ADR-0018** — calendar bridge architecture: EventKit only, Swift-binary subprocess.
|
|
153
|
+
|
|
7
154
|
## [1.0.2](https://github.com/torsday/omnifocus-mcp/compare/v1.0.1...v1.0.2) (2026-04-26)
|
|
8
155
|
|
|
9
156
|
**Summary** — One contributor-facing fix and one architectural-decision spike note; otherwise an internal-infrastructure release validating the post-v1.0.1 release flow under the new release-please + OIDC + PAT identity. **Bytes on the wire are identical to v1.0.1**: the published bundle, tool surface, tool descriptions, and runtime behaviour are unchanged. Consumers running `npx -y @torsday/omnifocus-mcp` see no difference. Internal-only commits (CI hygiene, release-please workflow tuning, comment-block cleanups) are intentionally hidden from this CHANGELOG by `release-please-config.json` and are not enumerated below.
|
|
@@ -39,8 +186,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
39
186
|
|
|
40
187
|
## [Unreleased]
|
|
41
188
|
|
|
42
|
-
_Nothing yet — see [GitHub Issues](https://github.com/torsday/omnifocus-mcp/issues) and [Project #4](https://github.com/users/torsday/projects/4) for the live backlog and status._
|
|
43
|
-
|
|
44
189
|
---
|
|
45
190
|
|
|
46
191
|
## [1.0.0] — 2026-04-25
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
[](./package.json)
|
|
7
7
|
[](https://www.apple.com/macos/)
|
|
8
|
+
[](./docs/adr/0017-mutation-testing-release-gate.md)
|
|
8
9
|
|
|
9
10
|
> **Give any MCP-compatible AI assistant full, typed access to your OmniFocus.** Read your inbox, create tasks, close projects, batch-update dozens of items, evaluate perspectives, trigger sync — all through natural language. `omnifocus-mcp` wires an 80-tool MCP server directly to OmniFocus on macOS via JXA and OmniJS, with circuit breakers, rate limits, and an agent-aware error hierarchy so the assistant knows exactly what to do next when something goes wrong.
|
|
10
11
|
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
|
|
13
14
|
## Table of contents
|
|
14
15
|
|
|
16
|
+
- [Agent-native OmniFocus — beyond the app surface](#agent-native-omnifocus--beyond-the-app-surface)
|
|
15
17
|
- [Why this exists](#why-this-exists)
|
|
16
18
|
- [Quick start](#quick-start)
|
|
17
19
|
- [Security & trust](#security--trust)
|
|
@@ -33,6 +35,26 @@
|
|
|
33
35
|
|
|
34
36
|
---
|
|
35
37
|
|
|
38
|
+
## Agent-native OmniFocus — beyond the app surface
|
|
39
|
+
|
|
40
|
+
A plain MCP wrapper would be a one-to-one mirror of the OmniFocus app. This server is more than that. It exposes a small set of capabilities that exist *because* an LLM is the caller — capabilities the app itself doesn't ship and probably never will, because they're only worth the effort when the consumer is an agent that can reason over structured input and act on the result.
|
|
41
|
+
|
|
42
|
+
These are the agent-native capabilities, framed in the user outcome they enable:
|
|
43
|
+
|
|
44
|
+
- **Stalled-project triage** — `omnifocus://project-health` returns granular signals (last activity, available task count, deferred-future tasks, review-overdue) so an agent can identify projects worth a status nudge without the user opening the app. Mechanical aggregation; the app could do it but doesn't.
|
|
45
|
+
- **Semantic dedupe** — [`task_find_similar`](docs/tools.md#task_find_similar) does lexical similarity search across task names so an agent confirms intent ("is this a duplicate of X?") before creating a new task. Possible without an LLM, but only useful with one in the loop.
|
|
46
|
+
- **Taxonomy audit** — `omnifocus://taxonomy-audit` flags inconsistent tag/folder usage so an agent can propose cleanup grounded in the actual structure of the database. Mechanical.
|
|
47
|
+
- **NL perspective authoring** *(in development — [#476](https://github.com/torsday/omnifocus-mcp/issues/476))* — describe a perspective in prose; the agent compiles a rule tree and writes it via `perspective_create`. Exists *because* of the agent — the rule tree is a non-trivial structure most users won't compose by hand.
|
|
48
|
+
- **Time-budget reconciliation** — [`forecast_pack`](docs/tools.md#forecast_pack) takes a daily minute budget and packs the forecast into it, surfacing overloaded days. Asking "I have 90 minutes, what should I do?" gets a structured answer.
|
|
49
|
+
- **Retrospective resource** — `omnifocus://retrospective?from=…&to=…` aggregates the closed-task surface so an agent can write the user's weekly review against real data instead of asking them to recap.
|
|
50
|
+
- **Project templates** — [`project_template_save`](docs/tools.md#project_template_save) / [`_instantiate`](docs/tools.md#project_template_instantiate) capture and replay project structures with parameter substitution and date shifting. The agent fills the parameters from conversation context.
|
|
51
|
+
- **Inbox-triage prompt** — the bundled `inbox-triage` MCP prompt sequences the tool calls for a full GTD-style processing sweep. Intentionally a prompt, not a tool — the value is in orchestrating the existing surface.
|
|
52
|
+
- **Calendar + agenda** — `omnifocus://calendar` and `omnifocus://agenda` merge macOS Calendar events with the OF forecast so an agent can answer "what does my day actually look like?" without the user holding two windows side by side.
|
|
53
|
+
|
|
54
|
+
> **How this is different from a plain wrapper.** A wrapper exposes the app's verbs. This server adds verbs the app doesn't have, because LLMs change what's worth building. Some of the additions (project-health, taxonomy-audit) are mechanical aggregations the app *could* ship and never has — they sit unbuilt because no human wants to click through them. Others (NL perspective authoring, semantic dedupe, time-budget reconciliation) are only valuable with an LLM in the call path. Both kinds belong here. The split is honest: don't pretend the mechanical stuff is novel, and don't pretend the agent-only stuff is just sugar.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
36
58
|
## Why this exists
|
|
37
59
|
|
|
38
60
|
OmniFocus is a powerful GTD tool, but it's an island. Your tasks sit there while you context-switch between your AI assistant and your task manager, manually copy-pasting notes, updating projects, and trying to keep everything in sync with your actual work.
|
|
@@ -52,6 +74,10 @@ The server is built to a single-user local-first standard: no network surface, n
|
|
|
52
74
|
|
|
53
75
|
1. **Install**
|
|
54
76
|
```bash
|
|
77
|
+
# Homebrew (no Node required)
|
|
78
|
+
brew install torsday/tap/omnifocus-mcp
|
|
79
|
+
|
|
80
|
+
# or npm
|
|
55
81
|
npm install -g @torsday/omnifocus-mcp
|
|
56
82
|
```
|
|
57
83
|
|
|
@@ -223,7 +249,7 @@ There is exactly one feature that's gated behind an environment variable because
|
|
|
223
249
|
|
|
224
250
|
Three recipes that take seconds; you don't have to take this README's word for any of the above.
|
|
225
251
|
|
|
226
|
-
1. **Audit the source.** The repo at [github.com/torsday/omnifocus-mcp](https://github.com/torsday/omnifocus-mcp) is the canonical source.
|
|
252
|
+
1. **Audit the source.** The repo at [github.com/torsday/omnifocus-mcp](https://github.com/torsday/omnifocus-mcp) is the canonical source. Each published artifact is built from its own tagged commit (`v<version>`); compare `dist/index.js` against the build output of the tag matching the version you installed.
|
|
227
253
|
2. **Verify the published artifact's provenance.** npm publishes attestations via [Sigstore](https://www.sigstore.dev/):
|
|
228
254
|
```bash
|
|
229
255
|
npm view @torsday/omnifocus-mcp dist.attestations
|
|
@@ -471,7 +497,7 @@ All responses have this shape:
|
|
|
471
497
|
|
|
472
498
|
## Tools
|
|
473
499
|
|
|
474
|
-
|
|
500
|
+
Tools are organized by domain — tasks, projects, tags, folders, perspectives, forecast, review, search, notes, attachments, sync, export, and observability. See [`docs/tools.md`](./docs/tools.md) for the full auto-generated reference with the live registered count, input schemas, example calls, and example responses.
|
|
475
501
|
|
|
476
502
|
### App lifecycle
|
|
477
503
|
| Tool | Description |
|
|
@@ -610,20 +636,41 @@ All responses have this shape:
|
|
|
610
636
|
|
|
611
637
|
## Resources
|
|
612
638
|
|
|
613
|
-
|
|
639
|
+
The server registers resources under the `omnifocus://` scheme. Resources are read-only, URI-addressable, and enumerable via `resources/list`. Templated URIs follow [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570) and accept the listed parameters as query strings or path segments.
|
|
640
|
+
|
|
641
|
+
**Static URIs** — read with no parameters:
|
|
614
642
|
|
|
615
643
|
| URI | Returns |
|
|
616
644
|
|---|---|
|
|
617
|
-
| `omnifocus://capabilities` | Server capabilities: OF version, edition, transport status, feature flags |
|
|
618
|
-
| `omnifocus://snapshot` |
|
|
645
|
+
| `omnifocus://capabilities` | Server capabilities: OF version, edition, transport status, feature flags, calendar-bridge availability |
|
|
646
|
+
| `omnifocus://snapshot` | Orientation counts: inbox, flagged, overdue, dueToday, reviewDue, syncStatus |
|
|
619
647
|
| `omnifocus://inbox` | Inbox tasks as `Task[]` |
|
|
620
|
-
| `omnifocus://
|
|
648
|
+
| `omnifocus://tasks/inbox` | Inbox tasks (alias of `omnifocus://inbox`) |
|
|
649
|
+
| `omnifocus://forecast/today` | Today's forecast grouped by overdue / dueToday / deferredToday / flagged |
|
|
621
650
|
| `omnifocus://overdue` | All overdue tasks sorted by dueDate ASC |
|
|
622
651
|
| `omnifocus://flagged` | All flagged available tasks |
|
|
623
652
|
| `omnifocus://review-due` | Projects with nextReviewDate ≤ today |
|
|
624
|
-
| `omnifocus://
|
|
625
|
-
| `omnifocus://
|
|
626
|
-
| `omnifocus://
|
|
653
|
+
| `omnifocus://intents` | User-phrase → tool-sequence map: a small set of human-meaningful verbs that compose the full tool surface |
|
|
654
|
+
| `omnifocus://stats` | Database-wide rollup: counts by project, tag, completion state |
|
|
655
|
+
| `omnifocus://taxonomy-audit` | Structural audit — inconsistent tag/folder usage, orphans, drift signals |
|
|
656
|
+
| `omnifocus://waiting-on` | Every task carrying a `waiting-on` fence, sorted by daysOverdue DESC |
|
|
657
|
+
|
|
658
|
+
**Templated URIs** — accept parameters:
|
|
659
|
+
|
|
660
|
+
| URI Template | Parameters | Returns |
|
|
661
|
+
|---|---|---|
|
|
662
|
+
| `omnifocus://project/{id}` | `id` | Single project + full task tree |
|
|
663
|
+
| `omnifocus://tag/{id}` | `id` | Single tag + its active tasks |
|
|
664
|
+
| `omnifocus://perspective/{id}` | `id` | Perspective evaluation result (same shape as `perspective_evaluate`); Pro only |
|
|
665
|
+
| `omnifocus://tasks/project/{projectId}` | `projectId` | Active tasks under a project |
|
|
666
|
+
| `omnifocus://tasks/tag/{tagId}` | `tagId` | Active tasks carrying a tag |
|
|
667
|
+
| `omnifocus://recent-activity{?hours}` | `hours` (default: 24) | Tasks completed/dropped/created in the last N hours |
|
|
668
|
+
| `omnifocus://retrospective{?from,to}` | `from`, `to` (ISO-8601) | Closed-task aggregation for a date range — weekly review fuel |
|
|
669
|
+
| `omnifocus://velocity{?weeks}` | `weeks` (default: 4) | Per-week throughput: completed counts, completion rate trend |
|
|
670
|
+
| `omnifocus://burndown/{projectId}` | `projectId` | Per-project burndown vs naive linear ideal; needs project dueDate |
|
|
671
|
+
| `omnifocus://project-health{?staleDays}` | `staleDays` (default: 14) | Triage list: stalled projects, no-activity, review-overdue |
|
|
672
|
+
| `omnifocus://calendar{?from,to}` | `from`, `to` (ISO-8601, defaults to today local) | macOS Calendar events from EventKit; needs Calendar TCC grant |
|
|
673
|
+
| `omnifocus://agenda{?date}` | `date` (ISO-8601, defaults to today local) | Merged daily timeline: calendar events + OF forecast, kind-tagged |
|
|
627
674
|
|
|
628
675
|
---
|
|
629
676
|
|
|
@@ -698,7 +745,7 @@ The full layered diagram with queues, circuit breakers, and the test adapter liv
|
|
|
698
745
|
|
|
699
746
|
## Status and roadmap
|
|
700
747
|
|
|
701
|
-
|
|
748
|
+
The package is [published on npm](https://www.npmjs.com/package/@torsday/omnifocus-mcp); see the [latest release](https://github.com/torsday/omnifocus-mcp/releases/latest) for the current version and notes. The phase table below records the milestone work that shipped in v1.0.0; the live backlog and future enhancements track on the [Project board](https://github.com/users/torsday/projects/4), and the [unreleased section of the CHANGELOG](./CHANGELOG.md#unreleased) lists what's already merged toward the next release.
|
|
702
749
|
|
|
703
750
|
| Phase | Milestone | Status |
|
|
704
751
|
|---|---|---|
|
|
@@ -715,6 +762,12 @@ Track open issues and future enhancements on the [**GitHub Project board**](http
|
|
|
715
762
|
|
|
716
763
|
## Install
|
|
717
764
|
|
|
765
|
+
**Homebrew** (recommended for non-Node users):
|
|
766
|
+
```bash
|
|
767
|
+
brew install torsday/tap/omnifocus-mcp
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
**npm** (recommended if you already have Node 24+):
|
|
718
771
|
```bash
|
|
719
772
|
# Global install
|
|
720
773
|
npm install -g @torsday/omnifocus-mcp
|
|
@@ -890,6 +943,11 @@ Writes are saved locally and show up immediately in subsequent tool calls. Chang
|
|
|
890
943
|
| [0011](./docs/adr/0011-versioning-and-stability.md) | Semver with explicit contract |
|
|
891
944
|
| [0012](./docs/adr/0012-distribution-npx.md) | Distribution via `npx` / npm |
|
|
892
945
|
| [0013](./docs/adr/0013-tool-response-envelope.md) | Uniform response envelope |
|
|
946
|
+
| [0014](./docs/adr/0014-e2e-harness-strategy.md) | In-memory adapter switch for E2E |
|
|
947
|
+
| [0015](./docs/adr/0015-nl-excellence-response-envelope.md) | NL-excellence envelope: clarification, hints, summary |
|
|
948
|
+
| [0016](./docs/adr/0016-webhook-delivery.md) | Webhook delivery for OmniFocus state changes |
|
|
949
|
+
| [0017](./docs/adr/0017-mutation-testing-release-gate.md) | Stryker mutation testing as release-time hard gate |
|
|
950
|
+
| [0018](./docs/adr/0018-calendar-bridge-eventkit-only.md) | Calendar bridge — EventKit-only via Swift-binary subprocess |
|
|
893
951
|
|
|
894
952
|
---
|
|
895
953
|
|