{"id":"8e4d0829-9b7e-48cb-a0f7-8f2b6735b765","entityType":"agent","slug":"clawhub-chrischall-ofw-mcp","name":"Tmp.BcPQA7YzJI","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-ofw-mcp","canonicalPath":"/agent/clawhub-chrischall-ofw-mcp","generatedAt":"2026-10-10T01:28:19.188Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":null},"description":"This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries. Skill: Tmp.BcPQA7YzJI Owner: chrischall Summary: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entrie","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 3.1K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:ofw-mcp","sourceUrl":"https://clawhub.ai/chrischall/ofw-mcp","homepage":"https://clawhub.ai/chrischall/skills/ofw-mcp","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/ofw-mcp","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/ofw-mcp","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":70,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW "},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":null},"stars":null,"forks":null,"downloads":3092,"packageName":null,"latestVersion":"2.11.0","tractionLabel":"3.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T09:49:02.055Z","lastCrawledAt":"2026-10-09T09:49:02.055Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T09:49:02.055Z","lastVerifiedAt":null,"highlights":[{"version":"2.11.0","createdAt":"2026-08-23T21:33:07.374Z","changelog":"ofw-mcp 2.11.0 - Enhanced paging for message, draft, and unread sent listings: metadata keys like nextPage, hasMore, and returned now lead JSON results and are more structured. - Added sort:\"oldest\" support to ofw_list_messages for more flexible message ordering. - Improved documentation for message tool outputs and paging in SKILL.md. - Removed the old skill-card.md file.","fileCount":3,"zipByteSize":7010},{"version":"2.10.2","createdAt":"2026-08-09T14:17:02.646Z","changelog":"- Removed \"skill-card.md\"; simplified to a single documentation file. - SKILL.md rewritten for clarity and conciseness; removed duplicated content and extra referencing. - No changes to actual functionality—documentation update only.","fileCount":3,"zipByteSize":6911},{"version":"2.10.1","createdAt":"2026-08-06T00:43:28.621Z","changelog":"- Removed the file skill-card.md. - No changes to functionality or features. - Documentation remains unchanged apart from file removal.","fileCount":3,"zipByteSize":7084},{"version":"2.10.0","createdAt":"2026-07-31T15:17:20.447Z","changelog":"**Major update with breaking changes to draft and message sending.** - Breaking change: `ofw_send_message` now requires a `draftId` (plus optional overrides) for sending an existing draft; `recipientIds` are required at send time because OFW no longer stores recipients on drafts. - Draft management is now auto-verified: `ofw_list_drafts` runs a cheap server check before returning drafts to ensure accuracy. - Sending, editing, and deleting drafts now include better lifecycle tracking using the new `draftKey` concept. - Removed redundant tool calls and clarified required/optional arguments for draft/message operations. - File `skill-card.md` has been removed.","fileCount":3,"zipByteSize":7040},{"version":"2.9.2","createdAt":"2026-07-30T12:53:51.848Z","changelog":"- Removed the file: skill-card.md. - No changes to core functionality or documented interface. - This update is limited to file cleanup only.","fileCount":3,"zipByteSize":6579},{"version":"2.9.1","createdAt":"2026-07-29T03:02:31.318Z","changelog":"- Removed the file: skill-card.md - No other changes to functionality or documentation.","fileCount":3,"zipByteSize":6731},{"version":"2.9.0","createdAt":"2026-07-28T16:39:24.890Z","changelog":"ofw-mcp version 2.9.0 - Enhanced message, draft, and sent status tracking with new `complete` flag and improved cache freshness/refusal logic across tools. - Expanded tool surface: new/updated parameters for pagination and auto-refresh (e.g., `page`, `size`, `autoRefresh` for drafts/messages, etc.). - Introduced `draftKey` for persistent draft tracking, plus new `ofw_status` tool for reliable, live lifecycle/entity verification. - Improved documentation and guidance on cache use, data freshness, result completeness, and lifecycle queries. - Removed outdated `skill-card.md`.","fileCount":3,"zipByteSize":6735},{"version":"2.8.0","createdAt":"2026-07-27T14:55:00.327Z","changelog":"- Added allowMarkRead option to ofw_get_message, allowing safer fetches without marking messages read or stamping irreversible read receipts. - Enhanced ofw_download_attachment: now supports inline text/image extraction (including per-sheet CSV, per-page text for PDFs/Office docs, and more granular control with extract, maxChars, and parts options). - Removed skill-card.md from the distribution. - Updated documentation to clarify message read actions and attachment extraction features.","fileCount":3,"zipByteSize":5532}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:ofw-mcp","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T01:28:19.183Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-ofw-mcp/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":null},"readme":"Skill: Tmp.BcPQA7YzJI\n\nOwner: chrischall\n\nSummary: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n\nTags: latest:2.11.0\n\nVersion history:\n\nv2.11.0 | 2026-08-23T21:33:07.374Z | auto\n\nofw-mcp 2.11.0\n\n- Enhanced paging for message, draft, and unread sent listings: metadata keys like nextPage, hasMore, and returned now lead JSON results and are more structured.\n- Added sort:\"oldest\" support to ofw_list_messages for more flexible message ordering.\n- Improved documentation for message tool outputs and paging in SKILL.md.\n- Removed the old skill-card.md file.\n\nv2.10.2 | 2026-08-09T14:17:02.646Z | auto\n\n- Removed \"skill-card.md\"; simplified to a single documentation file.\n- SKILL.md rewritten for clarity and conciseness; removed duplicated content and extra referencing.\n- No changes to actual functionality—documentation update only.\n\nv2.10.1 | 2026-08-06T00:43:28.621Z | auto\n\n- Removed the file skill-card.md.\n- No changes to functionality or features.\n- Documentation remains unchanged apart from file removal.\n\nv2.10.0 | 2026-07-31T15:17:20.447Z | auto\n\n**Major update with breaking changes to draft and message sending.**\n\n- Breaking change: `ofw_send_message` now requires a `draftId` (plus optional overrides) for sending an existing draft; `recipientIds` are required at send time because OFW no longer stores recipients on drafts.\n- Draft management is now auto-verified: `ofw_list_drafts` runs a cheap server check before returning drafts to ensure accuracy.\n- Sending, editing, and deleting drafts now include better lifecycle tracking using the new `draftKey` concept.\n- Removed redundant tool calls and clarified required/optional arguments for draft/message operations.\n- File `skill-card.md` has been removed.\n\nv2.9.2 | 2026-07-30T12:53:51.848Z | auto\n\n- Removed the file: skill-card.md.\n- No changes to core functionality or documented interface.\n- This update is limited to file cleanup only.\n\nv2.9.1 | 2026-07-29T03:02:31.318Z | auto\n\n- Removed the file: skill-card.md\n- No other changes to functionality or documentation.\n\nv2.9.0 | 2026-07-28T16:39:24.890Z | auto\n\nofw-mcp version 2.9.0\n\n- Enhanced message, draft, and sent status tracking with new `complete` flag and improved cache freshness/refusal logic across tools.\n- Expanded tool surface: new/updated parameters for pagination and auto-refresh (e.g., `page`, `size`, `autoRefresh` for drafts/messages, etc.).\n- Introduced `draftKey` for persistent draft tracking, plus new `ofw_status` tool for reliable, live lifecycle/entity verification.\n- Improved documentation and guidance on cache use, data freshness, result completeness, and lifecycle queries.\n- Removed outdated `skill-card.md`.\n\nv2.8.0 | 2026-07-27T14:55:00.327Z | auto\n\n- Added allowMarkRead option to ofw_get_message, allowing safer fetches without marking messages read or stamping irreversible read receipts.\n- Enhanced ofw_download_attachment: now supports inline text/image extraction (including per-sheet CSV, per-page text for PDFs/Office docs, and more granular control with extract, maxChars, and parts options).\n- Removed skill-card.md from the distribution.\n- Updated documentation to clarify message read actions and attachment extraction features.\n\nv2.7.1 | 2026-07-27T01:27:33.709Z | auto\n\n- Removed the file: skill-card.md\n- No other changes to code or documentation.\n\nv2.7.0 | 2026-07-22T03:38:17.737Z | auto\n\n**Version 2.7.0 – Improved cache freshness tracking for drafts and messages**\n\n- Added `ofw_check_freshness` tool to verify cache vs. OFW state for messages and drafts.\n- Drafts now include a `serverConfirmed` flag for clarity about their synchronization status.\n- All read tools return a `freshness` block, detailing staleness, timestamp, and caveats.\n- Expanded documentation with a new \"Freshness\" section explaining how to interpret and act on cache status.\n- Removed the `skill-card.md` file.\n\nv2.6.7 | 2026-07-19T19:29:18.895Z | auto\n\n- Removed the file: skill-card.md\n- No changes to the main skill documentation or functionality.\n- This update is a minor cleanup to the codebase.\n\nv2.6.6 | 2026-07-19T14:55:10.534Z | auto\n\n- Removed the file skill-card.md from the project.\n- No changes to functionality or documentation content.\n- This update is maintenance only and does not affect setup, usage, or supported features.\n\nv2.6.5 | 2026-07-19T12:47:04.301Z | auto\n\n- Removed the file skill-card.md from the project.\n- No changes to functionality or user-facing features.\n\nv2.6.4 | 2026-07-18T12:37:13.601Z | auto\n\n- Removed the file skill-card.md.  \n- No feature or behavior changes in this release.  \n- All documentation, setup instructions, and tool descriptions remain unchanged.\n\nv2.6.3 | 2026-07-17T12:45:28.209Z | auto\n\n- Added note about hosted [claude.ai](https://claude.ai) remote connector providing the same tools and behavior as local installation.\n- Removed the file skill-card.md.\n- No changes to functionality or tool descriptions.\n\nv2.4.0 | 2026-06-12T18:34:55.286Z | auto\n\n- Removed the file: skill-card.md\n- No user-facing feature or functionality changes included.\n\nv2.3.2 | 2026-06-10T02:09:57.469Z | auto\n\n- Removed the file skill-card.md.  \n- No other user-facing changes.  \n- Existing setup, tools, and workflow documentation remain unchanged.\n\nv2.3.1 | 2026-06-02T11:56:03.612Z | auto\n\n- Removed the file skill-card.md.  \n- No changes to functionality or documentation in SKILL.md.\n\nv2.3.0 | 2026-05-29T20:17:45.447Z | auto\n\nofw-mcp 2.3.0\n\n- No file changes detected in this release.\n- All functionality, setup instructions, and usage remain unchanged from the previous version.\n\nv2.2.0 | 2026-05-28T16:45:50.634Z | auto\n\n- Removed file: skill-card.md\n- No changes to code or documentation content except for the file removal.\n\nv2.1.0 | 2026-05-28T01:30:09.247Z | auto\n\n- Removed the file skill-card.md from the repository.\n- No other changes were made to skill behavior or documentation.\n\nv2.0.19 | 2026-05-26T00:30:13.389Z | auto\n\n- No changes detected in this release.\n- Version remains functionally identical to the previous release.\n\nv2.0.18 | 2026-05-24T15:41:06.850Z | auto\n\nVersion 2.0.18 of \"ofw-mcp\"\n\n- No functional or documentation changes in this release.\n- No file changes detected.\n\nv2.0.17 | 2026-05-22T21:12:30.648Z | auto\n\nofw-mcp 2.0.17 changelog:\n\n- Expanded message toolset: added tools for syncing messages, listing unread sent messages, file attachments (upload/download), and enhanced drafts management.\n- Message tools now emphasize cache usage for efficiency, with fallbacks to live data when needed.\n- Draft workflows improved: saving a draft replaces the old one (with explanatory notes) due to OFW’s backend limitations.\n- Documentation updated to detail new parameters and behaviors for tools including attachments and cache operations.\n- Existing caution notes retained regarding message read status and legal importance.\n\nv2.0.16 | 2026-05-22T16:34:46.480Z | auto\n\nVersion 2.0.16 of ofw-mcp – No file changes detected.\n\n- No updates or modifications were made in this release.\n- Functionality and documentation remain unchanged.\n\nv2.0.15 | 2026-05-22T16:26:53.114Z | auto\n\nVersion 2.0.15 of ofw-mcp\n\n- No file changes detected in this version.\n- Behavior, features, and documentation remain the same as the previous version.\n\nv2.0.14 | 2026-05-21T20:11:57.068Z | auto\n\nVersion 2.0.14 of ofw-mcp\n\n- No file changes were detected in this release.\n- Functionality, setup instructions, and workflows remain unchanged.\n\nv2.0.13 | 2026-05-16T02:32:35.737Z | auto\n\nVersion 2.0.13 of ofw-mcp\n\n- No code or documentation changes; release content is identical to the previous version.\n- No file changes detected in this update.\n\nv2.0.12 | 2026-05-15T22:42:29.541Z | auto\n\nNo changes detected in this version.\n\n- No modifications were made to any files.\n- Functionality and documentation remain the same as the previous version.\n\nv2.0.11 | 2026-05-14T19:06:28.592Z | auto\n\nVersion 2.0.11 of ofw-mcp\n\n- No file changes detected in this release.\n- Functionality, workflows, and documentation remain unchanged.\n\nv2.0.10 | 2026-05-14T18:59:49.960Z | auto\n\nNo user-facing changes in this version.\n\n- Version 2.0.10 contains no updates to documentation or skill files.\n- Functionality and setup remain unchanged.\n\nv2.0.9 | 2026-05-14T18:52:17.222Z | auto\n\nVersion 2.0.9 of ofw-mcp\n\n- No file changes detected in this release.\n- All features, documentation, and behaviors remain unchanged from the previous version.\n\nv2.0.8 | 2026-05-11T23:09:41.915Z | auto\n\nNo changes detected in this release.\n\n- Version 2.0.8 contains no updates to documentation or code.\n\nv2.0.7 | 2026-05-06T10:31:24.860Z | auto\n\nVersion 2.0.7 of ofw-mcp\n\n- No file changes detected in this release.\n- No updates or modifications to features, tools, or documentation.\n\nv2.0.6 | 2026-05-06T10:27:10.473Z | auto\n\n- Improved documentation on triggers and setup for both Claude Code and mcporter.\n- Clarified usage, workflows, and tool descriptions for accessing messages, calendar, expenses, and journal features in OurFamilyWizard.\n- Added detailed usage cautions regarding read receipts, last-seen status, and the legal nature of OFW records.\n- Explicitly listed available tools and step-by-step example workflows for common co-parenting tasks.\n\nArchive index:\n\nArchive v2.11.0: 3 files, 7010 bytes\n\nFiles: skill-card.md (2082b), SKILL.md (12980b), _meta.json (127b)\n\nFile v2.11.0:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, sort?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. `sort:\"oldest\"` starts at the old end of a range instead of paging to it (default `\"newest\"`). Returns `complete` for the RESULT SET plus **`nextPage`** (null when done) — and the paging keys come FIRST in the JSON, before `messages`. `returned` carries the record count as a scalar, beside `total`. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(draftId?, subject?, body?, recipientIds?, replyToId?, expectedRevision?, deleteDraftOnSuccess?, myFileIDs?, force?)` | Send a message — **the one irreversible operation**. Preferred path: pass `draftId` (+ `expectedRevision`) to send an existing draft **as it exists on the server** — the tool re-reads it from OFW first and refuses if it changed since you read it (or was already sent/deleted); `subject`/`body` become optional overrides. `recipientIds` is usually still required: OFW does not store recipients on drafts. After a **confirmed** send the draft is auto-deleted (`deleteDraftOnSuccess:false` to keep it); on any failure or ambiguity it is retained and the response says why (`draftRetained`). Response leads with `sentMessageId`, `draftKey`, `threaded`, `draftDeleted`. Compose from scratch by passing `subject`/`body`/`recipientIds` with no `draftId`. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Leads with `complete`/`hasMore`/`nextPage`, then `scanned`/`total`, then `unread`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, verify?, autoRefresh?)` | Leads with `complete`/`hasMore`/`nextPage`; `drafts` comes last. List saved drafts, **auto-verified**: when the cache is not verified-fresh a cheap drafts sync runs first (default `verify:true`), so one call answers server-confirmed. `verify:false` serves straight from cache. Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response leads with `draftKey`, which stays the same across every edit — **track that, not the id**. Note: OFW does **not** store recipients on drafts — `recipientIds` are accepted but come back empty (a one-line NOTE says so; supply them at send time instead). Threading warnings fire only on genuine drops — a draft echoing `inReplyTo`/`showContext` IS threaded. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| If not, how do I get the rest? | `nextPage` (message tools) or `nextStart` (`ofw_list_expenses` / `ofw_list_journal_entries`) — null means there is no more |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user; note the returned `draftKey` and `revision`\n2. `ofw_send_message(draftId, recipientIds, expectedRevision)` after approval — sends the **server's** copy of the draft (no body re-supply), refuses if it changed since review, and deletes the draft only after the send is confirmed\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.11.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.11.0\",\n  \"publishedAt\": 1787520787374\n}\n\nFile v2.11.0:skill-card.md\n\n## Description:\n\nMCP server for OurFamilyWizard that provides read/write access to messages, calendar events, expenses, and journal entries.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal OurFamilyWizard users use this skill to let an agent inspect and manage co-parenting messages, calendar events, shared expenses, and journal entries. It is intended for workflows where the user wants OFW data access through MCP while preserving explicit review for sensitive actions.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill asks users to run external MCP server code with reusable OFW credentials and broad read/write access to sensitive legal-family records.\n\nMitigation: Use a pinned, reviewed package version, keep OFW credentials out of project files and shell history, and store secret files with restrictive permissions.\n\nRisk: Some OFW operations can send messages, delete records, mark messages read, or update last-seen status.\n\nMitigation: Require explicit user confirmation before sending messages, deleting records, reading unread messages that may mark them read, or calling notification reads that update status.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/chrischall/skills/ofw-mcp)\n- [npm Package](https://www.npmjs.com/package/ofw-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline JSON and bash code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide MCP tool calls that read or modify OurFamilyWizard records.]\n\n## Skill Version(s):\n\n2.11.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.10.2: 3 files, 6911 bytes\n\nFiles: skill-card.md (2458b), SKILL.md (12438b), _meta.json (127b)\n\nFile v2.10.2:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(draftId?, subject?, body?, recipientIds?, replyToId?, expectedRevision?, deleteDraftOnSuccess?, myFileIDs?, force?)` | Send a message — **the one irreversible operation**. Preferred path: pass `draftId` (+ `expectedRevision`) to send an existing draft **as it exists on the server** — the tool re-reads it from OFW first and refuses if it changed since you read it (or was already sent/deleted); `subject`/`body` become optional overrides. `recipientIds` is usually still required: OFW does not store recipients on drafts. After a **confirmed** send the draft is auto-deleted (`deleteDraftOnSuccess:false` to keep it); on any failure or ambiguity it is retained and the response says why (`draftRetained`). Response leads with `sentMessageId`, `draftKey`, `threaded`, `draftDeleted`. Compose from scratch by passing `subject`/`body`/`recipientIds` with no `draftId`. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, verify?, autoRefresh?)` | List saved drafts, **auto-verified**: when the cache is not verified-fresh a cheap drafts sync runs first (default `verify:true`), so one call answers server-confirmed. `verify:false` serves straight from cache. Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response leads with `draftKey`, which stays the same across every edit — **track that, not the id**. Note: OFW does **not** store recipients on drafts — `recipientIds` are accepted but come back empty (a one-line NOTE says so; supply them at send time instead). Threading warnings fire only on genuine drops — a draft echoing `inReplyTo`/`showContext` IS threaded. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user; note the returned `draftKey` and `revision`\n2. `ofw_send_message(draftId, recipientIds, expectedRevision)` after approval — sends the **server's** copy of the draft (no body re-supply), refuses if it changed since review, and deletes the draft only after the send is confirmed\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.10.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.10.2\",\n  \"publishedAt\": 1786285022646\n}\n\nFile v2.10.2:skill-card.md\n\n## Description:\n\nThis skill helps an agent work with OurFamilyWizard co-parenting data, including messages, calendar events, expenses, and journal entries.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and agents use this skill when they need to read, draft, send, or update OurFamilyWizard co-parenting records through the ofw-mcp toolset. It is intended for sensitive family-record workflows where message state, draft freshness, and explicit confirmation matter.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can access and change sensitive co-parenting records in OurFamilyWizard.\n\nMitigation: Install only when this account access is intended, use the narrowest available configuration, and require explicit confirmation before sends, deletes, calendar changes, expenses, or journal writes.\n\nRisk: Broad automatic activation could expose private family-record workflows to unintended agent actions.\n\nMitigation: Keep activation scoped to explicit OurFamilyWizard requests and avoid background actions that read messages, update last-seen status, or modify records.\n\nRisk: Account credentials may be exposed if stored in shared project or user configuration.\n\nMitigation: Store OFW credentials only in appropriately restricted local configuration or secret storage, not broadly shared workspace files.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp)\n- [npm package listed by the skill](https://www.npmjs.com/package/ofw-mcp)\n- [GitHub repository listed by the skill](https://github.com/chrischall/ofw-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with inline JSON and shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide agent calls that read or modify OurFamilyWizard records; user confirmation is expected for sensitive write operations.]\n\n## Skill Version(s):\n\n2.10.2 (source: server-resolved release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.10.1: 3 files, 7084 bytes\n\nFiles: skill-card.md (2597b), SKILL.md (12672b), _meta.json (127b)\n\nFile v2.10.1:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(draftId?, subject?, body?, recipientIds?, replyToId?, expectedRevision?, deleteDraftOnSuccess?, myFileIDs?, force?)` | Send a message — **the one irreversible operation**. Preferred path: pass `draftId` (+ `expectedRevision`) to send an existing draft **as it exists on the server** — the tool re-reads it from OFW first and refuses if it changed since you read it (or was already sent/deleted); `subject`/`body` become optional overrides. `recipientIds` is usually still required: OFW does not store recipients on drafts. After a **confirmed** send the draft is auto-deleted (`deleteDraftOnSuccess:false` to keep it); on any failure or ambiguity it is retained and the response says why (`draftRetained`). Response leads with `sentMessageId`, `draftKey`, `threaded`, `draftDeleted`. Compose from scratch by passing `subject`/`body`/`recipientIds` with no `draftId`. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, verify?, autoRefresh?)` | List saved drafts, **auto-verified**: when the cache is not verified-fresh a cheap drafts sync runs first (default `verify:true`), so one call answers server-confirmed. `verify:false` serves straight from cache. Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response leads with `draftKey`, which stays the same across every edit — **track that, not the id**. Note: OFW does **not** store recipients on drafts — `recipientIds` are accepted but come back empty (a one-line NOTE says so; supply them at send time instead). Threading warnings fire only on genuine drops — a draft echoing `inReplyTo`/`showContext` IS threaded. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user; note the returned `draftKey` and `revision`\n2. `ofw_send_message(draftId, recipientIds, expectedRevision)` after approval — sends the **server's** copy of the draft (no body re-supply), refuses if it changed since review, and deletes the draft only after the send is confirmed\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.10.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.10.1\",\n  \"publishedAt\": 1785977008621\n}\n\nFile v2.10.1:skill-card.md\n\n## Description:\n\nThis skill helps an agent work with OurFamilyWizard co-parenting data, including messages, calendar events, expenses, and journal entries.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and agents use this skill for explicit OurFamilyWizard tasks such as checking co-parenting messages, reviewing calendar events, managing shared expenses, and drafting or sending OFW communications.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The broad trigger could activate sensitive OurFamilyWizard read/write tools for general co-parenting requests.\n\nMitigation: Use the skill only for explicit OFW tasks and confirm user intent before accessing account data.\n\nRisk: Some reads can change user-visible state, such as last-seen status or marking unread messages as read.\n\nMitigation: Warn the user and require confirmation before calling notifications or reading unread messages when visible status could change.\n\nRisk: Write operations can affect legal co-parenting records, including sent messages, drafts, events, expenses, and journal entries.\n\nMitigation: Require clear confirmation before sending messages, deleting drafts or events, creating expenses or journal entries, or updating calendar data.\n\nRisk: Cached message or draft state can be stale and lead to incorrect statements about current OFW records.\n\nMitigation: Use live status, freshness, and completeness checks before reporting current states, counts, or whether a draft still exists.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/chrischall/skills/ofw-mcp)\n- [npm Package](https://www.npmjs.com/package/ofw-mcp)\n- [Artifact-Linked GitHub Repository](https://github.com/chrischall/ofw-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown responses with inline JSON and shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May use OFW tools that read or update sensitive account data; require clear user confirmation before operations that change records or visible read status.]\n\n## Skill Version(s):\n\n2.10.1 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.10.0: 3 files, 7040 bytes\n\nFiles: skill-card.md (2447b), SKILL.md (12672b), _meta.json (127b)\n\nFile v2.10.0:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(draftId?, subject?, body?, recipientIds?, replyToId?, expectedRevision?, deleteDraftOnSuccess?, myFileIDs?, force?)` | Send a message — **the one irreversible operation**. Preferred path: pass `draftId` (+ `expectedRevision`) to send an existing draft **as it exists on the server** — the tool re-reads it from OFW first and refuses if it changed since you read it (or was already sent/deleted); `subject`/`body` become optional overrides. `recipientIds` is usually still required: OFW does not store recipients on drafts. After a **confirmed** send the draft is auto-deleted (`deleteDraftOnSuccess:false` to keep it); on any failure or ambiguity it is retained and the response says why (`draftRetained`). Response leads with `sentMessageId`, `draftKey`, `threaded`, `draftDeleted`. Compose from scratch by passing `subject`/`body`/`recipientIds` with no `draftId`. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, verify?, autoRefresh?)` | List saved drafts, **auto-verified**: when the cache is not verified-fresh a cheap drafts sync runs first (default `verify:true`), so one call answers server-confirmed. `verify:false` serves straight from cache. Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response leads with `draftKey`, which stays the same across every edit — **track that, not the id**. Note: OFW does **not** store recipients on drafts — `recipientIds` are accepted but come back empty (a one-line NOTE says so; supply them at send time instead). Threading warnings fire only on genuine drops — a draft echoing `inReplyTo`/`showContext` IS threaded. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user; note the returned `draftKey` and `revision`\n2. `ofw_send_message(draftId, recipientIds, expectedRevision)` after approval — sends the **server's** copy of the draft (no body re-supply), refuses if it changed since review, and deletes the draft only after the send is confirmed\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.10.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.10.0\",\n  \"publishedAt\": 1785511040447\n}\n\nFile v2.10.0:skill-card.md\n\n## Description: <br>\nProvides agent access to OurFamilyWizard co-parenting messages, calendar events, expenses, journal entries, and related account information. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nExternal users and developers use this skill to let an agent inspect and manage OurFamilyWizard co-parenting records, including messages, calendars, expenses, journals, drafts, attachments, and account notifications. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can access highly sensitive co-parenting records and uses account credentials. <br>\nMitigation: Install only when OFW account access is intended, prefer a local setup unless the hosted connector's operator and logging practices are understood, and avoid using it for generic co-parenting questions. <br>\nRisk: Write, delete, send, mark-read, and status-changing actions can have visible or irreversible effects in OurFamilyWizard. <br>\nMitigation: Require explicit user confirmation before any write, delete, send, mark-read, or other status-changing action. <br>\nRisk: Cached message or draft state may be stale and can mislead the agent about the current OFW state. <br>\nMitigation: Use live freshness, status, and completeness checks before stating current state or final counts. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [npm package listed by skill artifact](https://www.npmjs.com/package/ofw-mcp) <br>\n- [Source link listed by skill artifact](https://github.com/chrischall/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Guidance, Shell commands, Configuration, API Calls] <br>\n**Output Format:** [Markdown with command, JSON configuration, and tool-call guidance] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May guide MCP tool calls that read or modify OurFamilyWizard account data.] <br>\n\n## Skill Version(s): <br>\n2.10.0 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.9.2: 3 files, 6579 bytes\n\nFiles: skill-card.md (2502b), SKILL.md (11496b), _meta.json (126b)\n\nFile v2.9.2:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, autoRefresh?)` | List saved drafts (cache-backed). Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. An empty result from a non-fresh cache is refused. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. It also returns a `draftKey` that stays the same across every edit — **track that, not the id**. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user\n2. `ofw_send_message(..., draftId)` after approval — draft is auto-deleted on send\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.9.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.9.2\",\n  \"publishedAt\": 1785416031848\n}\n\nFile v2.9.2:skill-card.md\n\n## Description: <br>\nThis skill helps an agent work with OurFamilyWizard co-parenting data, including messages, calendar events, shared expenses, and journal entries. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nExternal users and developers use this skill to connect an agent to OurFamilyWizard records for co-parenting workflows such as checking messages, managing calendar events, logging expenses, and creating journal entries. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can expose or modify sensitive OurFamilyWizard co-parenting records. <br>\nMitigation: Install it only for intended OFW workflows, protect credentials, and limit agent access to users who are allowed to view or change those records. <br>\nRisk: Some actions can create durable or visible changes, including sending messages, deleting records, creating expenses or journal entries, uploading files, and changing read or last-seen status. <br>\nMitigation: Require explicit user confirmation before any write action or read action that can update visible OFW status. <br>\nRisk: The trigger scope may activate the skill even when the user did not explicitly request OFW access. <br>\nMitigation: Confirm OFW intent before using the skill when the request is ambiguous or only generally relates to co-parenting data. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [npm package: ofw-mcp](https://www.npmjs.com/package/ofw-mcp) <br>\n- [Source repository](https://github.com/chrischall/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration instructions, Guidance] <br>\n**Output Format:** [Markdown with inline JSON and shell command examples] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May propose or invoke MCP tool calls that read or modify OFW messages, calendar entries, expenses, files, and journal entries.] <br>\n\n## Skill Version(s): <br>\n2.9.2 (source: server release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.9.1: 3 files, 6731 bytes\n\nFiles: skill-card.md (2840b), SKILL.md (11496b), _meta.json (126b)\n\nFile v2.9.1:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, autoRefresh?)` | List saved drafts (cache-backed). Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. An empty result from a non-fresh cache is refused. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. It also returns a `draftKey` that stays the same across every edit — **track that, not the id**. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user\n2. `ofw_send_message(..., draftId)` after approval — draft is auto-deleted on send\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.9.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.9.1\",\n  \"publishedAt\": 1785294151318\n}\n\nFile v2.9.1:skill-card.md\n\n## Description: <br>\nProvides guidance for using the ofw-mcp OurFamilyWizard MCP server to access messages, calendar events, expenses, journal entries, drafts, attachments, and account notifications. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agent users use this skill when they need an agent to configure or operate the ofw-mcp MCP server for OurFamilyWizard co-parenting workflows, including reading records and performing controlled write actions. It is intended for users who deliberately want agent-assisted access to sensitive OFW account data. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can enable broad access to sensitive co-parenting records through a configured OurFamilyWizard account. <br>\nMitigation: Install only when agent access to the account is intentional, and treat credentials plus any local cache as sensitive records. <br>\nRisk: Some reads may change visible account state, such as marking a message viewed or updating last-seen status. <br>\nMitigation: Use explicit user confirmation before reads that may mark content viewed, and warn users when preserving unread or unseen status matters. <br>\nRisk: Write actions can send messages, delete drafts or events, create expenses, create journal entries, and upload or download attachments. <br>\nMitigation: Require explicit user confirmation before sends, deletes, event changes, expense creation, journal creation, and attachment transfer actions. <br>\nRisk: Cached message or draft state can be stale and may not reflect the current server state. <br>\nMitigation: Verify freshness, completeness, and lifecycle status before presenting current OFW state as fact. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [npm package: ofw-mcp](https://www.npmjs.com/package/ofw-mcp) <br>\n- [Project source link stated in artifact](https://github.com/chrischall/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Guidance, Shell commands, Configuration instructions] <br>\n**Output Format:** [Markdown with inline JSON and shell commands] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May describe MCP tool calls and cautions for actions that read or modify OurFamilyWizard records.] <br>\n\n## Skill Version(s): <br>\n2.9.1 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.9.0: 3 files, 6735 bytes\n\nFiles: skill-card.md (2798b), SKILL.md (11496b), _meta.json (126b)\n\nFile v2.9.0:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. Returns `complete` for the RESULT SET. An **empty** result from a non-fresh cache is refused (`UNVERIFIED_EMPTY`) — pass `autoRefresh:true` to sync and answer instead. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |\n| `ofw_get_unread_sent(page?, size?, autoRefresh?)` | Sent messages your co-parent hasn't read yet (from cache). Reports `scanned`/`total`/`complete`; an empty sent cache that is not fresh is refused rather than reported as \"nothing sent\". |\n| `ofw_list_drafts(page?, size?, autoRefresh?)` | List saved drafts (cache-backed). Each draft carries `serverConfirmed`, `revision` and `draftKey`. Returns `complete` — **check it before saying \"you have N drafts\"**. An empty result from a non-fresh cache is refused. See [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?, expectedRevision?, force?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. It also returns a `draftKey` that stays the same across every edit — **track that, not the id**. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Each id gets a live `state` (`draft`/`sent`/`received`/`deleted`/`unknown`) plus `folder` and `sentAt`. Probes ids cached as drafts, as sent, or as already-read inbox messages freely; anything else needs `allowMarkRead:true` (it would mark an inbox message read). |\n| `ofw_status(ids?, draftKeys?, includeDraftInventory?, allowMarkRead?)` | **The status call.** One live round trip. With no arguments: the full, server-verified draft inventory. With `ids`/`draftKeys`: each one's live lifecycle state. Top-level `complete` is true only when every part was verified live. |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness, completeness, and lifecycle\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Three separate questions, three separate signals — do not substitute one for another:\n\n| Question | Signal |\n|---|---|\n| How old is this data? | `freshness` — `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, a quotable `warning` |\n| Is this the WHOLE answer? | `complete` on `ofw_list_messages` / `ofw_list_drafts` / `ofw_get_unread_sent` / `ofw_status` |\n| Is this entity still what I think it is? | `state` from `ofw_status` / `ofw_check_freshness` |\n\nRules:\n\n- **Verification is cheaper than recollection. Use it.** Any status summary about drafts costs exactly one `ofw_status()` call. There is no situation in which recalling an earlier tool result is the better option.\n- **Never state current state from memory.** A draft you saved earlier in the session is not evidence it still exists unsent now — the user may have sent, edited or deleted it in the web app since. This has gone wrong twice: drafts described as \"still sitting unsent\" that had already been sent.\n- **`existsOnServer` does not mean \"still a draft\".** A draft that was SENT still exists on the server. Only `state` distinguishes them.\n- **Check `complete` before quoting a count.** `complete: false` means the result set is a slice, or unverified, or both — `completeNote` says which. \"You have 3 drafts\" requires `complete: true`.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Call `ofw_status` / `ofw_check_freshness` first, or say plainly that you are reporting cached state and give its age.\n- **A refusal is a good outcome.** `result: \"UNVERIFIED_EMPTY\"` means the tool declined to report an absence it could not verify. Do the `remedy` — never re-report it as \"nothing found\". A wrong \"no, that was never sent\" is far costlier here than one extra call.\n- **`state: \"unknown\"` is not \"fine\".** It means the question was not answered.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n### Draft identity (`draftKey`)\n\nEditing a draft mints a **new OFW id every time** — `ofw_save_draft` replaces by create-then-delete, so one message can burn through ten ids in a session. Track the `draftKey` it returns, not the id:\n\n- `ofw_status(draftKeys: [\"dk_…\"])` resolves the key to the chain's **current** id and state.\n- The key keeps resolving after the draft is sent: `state: \"sent\"` with `sentMessageId` and `sentAt`.\n- `draftKey: null` on a draft means it was authored outside this tool; it is adopted into a chain the first time you save over it.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user\n2. `ofw_send_message(..., draftId)` after approval — draft is auto-deleted on send\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Before saying what \"is\" true on OFW right now, call `ofw_status` — one live round trip that answers drafts, ids and draft keys at once. Never assemble a status summary from earlier tool results in the conversation; re-read.\n\nFile v2.9.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.9.0\",\n  \"publishedAt\": 1785256764890\n}\n\nFile v2.9.0:skill-card.md\n\n## Description: <br>\nProvides agent guidance for using the ofw-mcp MCP server to access OurFamilyWizard messages, calendar, expenses, journal entries, drafts, and attachments. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agents use this skill when a user wants to work with OurFamilyWizard co-parenting records through the ofw-mcp MCP server. It guides read/write workflows for messages, drafts, calendar events, expenses, journal entries, and attachments while emphasizing freshness checks and confirmation before sensitive actions. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can grant broad access to sensitive legal co-parenting records. <br>\nMitigation: Install only when OFW account access is intended, configure the least privilege available, and prefer read-only or draft-only operation where possible. <br>\nRisk: Write tools can send messages, create records, delete items, upload files, or otherwise change OFW data. <br>\nMitigation: Avoid auto-approving write tools and require explicit user confirmation before sending, creating, deleting, or uploading. <br>\nRisk: Opening unread messages or notifications can create visible status changes such as read receipts or last-seen updates. <br>\nMitigation: Warn the user before actions that may mark content as read, use refusal options such as allowMarkRead:false when appropriate, and avoid silent background reads. <br>\nRisk: Cached message or draft state can be stale or incomplete. <br>\nMitigation: Use live status and freshness checks before stating current OFW state, and check completeness signals before quoting counts or absences. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [ofw-mcp npm package](https://www.npmjs.com/package/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with tool names, JSON MCP configuration examples, and shell command snippets.] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Covers cached and live OurFamilyWizard workflows; requires user confirmation before writes or actions that may create read receipts.] <br>\n\n## Skill Version(s): <br>\n2.9.0 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.8.0: 3 files, 5532 bytes\n\nFiles: skill-card.md (2699b), SKILL.md (8746b), _meta.json (126b)\n\nFile v2.8.0:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. |\n| `ofw_get_message(messageId, allowMarkRead?)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them read AND stamps a \"First Viewed\" time the co-parent can see — irreversible. Pass `allowMarkRead:false` to refuse that fetch instead; cached, sent and already-read messages are unaffected. |\n| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |\n| `ofw_get_unread_sent` | Sent messages your co-parent hasn't read yet (from cache). |\n| `ofw_list_drafts` | List saved drafts (cache-backed). Each draft carries `serverConfirmed` — see [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?, extract?, maxChars?, parts?)` | Download an attachment. Inline delivery returns the first rung that works: image → `ImageContent`; .xlsx/.csv/.pdf/.docx/.pptx/text → **extracted content** under `extracted` (per-sheet CSV, per-page/slide text); anything else → raw bytes. Default writes to `~/Downloads/ofw-mcp/` (add `extract:true` for content too). Use `parts:\"1-2\"` / a sheet name and `maxChars` on large files. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Use before asserting current state. Only probes ids in the drafts cache unless `allowMarkRead:true` (probing others marks inbox messages read). |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Every read tool returns a `freshness` block: `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, and a `warning` whenever it is not `fresh`. Drafts additionally carry `serverConfirmed`.\n\nRules for using it:\n\n- **Never state current state from memory.** If you saved a draft earlier in the session, that is not evidence it still exists unsent now — the user may have sent or deleted it in the web app since.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Do not say a draft \"is still sitting unsent\" on that basis. Call `ofw_check_freshness(messageIds: [id])` first, or say plainly that you are reporting cached state and give its age.\n- **If `freshness.staleness` is not `fresh`, either re-read or surface the caveat** in your answer. The `warning` string is written to be quotable.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is tracked separately and compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user\n2. `ofw_send_message(..., draftId)` after approval — draft is auto-deleted on send\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Check `freshness`/`serverConfirmed` before saying what \"is\" true on OFW right now, and prefer `ofw_check_freshness` over guessing — it is one cheap call.\n\nFile v2.8.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.8.0\",\n  \"publishedAt\": 1785164100327\n}\n\nFile v2.8.0:skill-card.md\n\n## Description: <br>\nThis skill helps an agent work with OurFamilyWizard co-parenting data, including messages, calendar events, expenses, journal entries, and attachments. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nExternal users and their agents use this skill to inspect and manage OurFamilyWizard co-parenting records, including inbox state, message drafts and replies, calendar items, shared expenses, journal entries, and attachments. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill connects an agent to sensitive co-parenting and legal records using OurFamilyWizard credentials. <br>\nMitigation: Install only when the user intends to grant this access, keep credentials protected, and avoid using the skill for general co-parenting advice that does not require OFW data. <br>\nRisk: Write-capable tools can send messages, delete drafts, create calendar events, log expenses, or create journal entries. <br>\nMitigation: Confirm with the user before any write action and present the exact action or message content for review first. <br>\nRisk: Some read operations can update last-seen status or create irreversible read receipts visible to a co-parent. <br>\nMitigation: Avoid silent background checks, warn before reads that can mark messages read, and use no-read-receipt options such as allowMarkRead:false when appropriate. <br>\nRisk: Cached message and draft state can be stale while still appearing usable. <br>\nMitigation: Check freshness before stating current OFW state and clearly label cached or unverified results. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [npm package](https://www.npmjs.com/package/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with JSON configuration examples and shell command snippets] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May return OFW account data, attachment extracts, cache freshness warnings, and proposed write actions when connected to a configured account.] <br>\n\n## Skill Version(s): <br>\n2.8.0 (source: server release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.7.1: 3 files, 5352 bytes\n\nFiles: skill-card.md (2952b), SKILL.md (8242b), _meta.json (126b)\n\nFile v2.7.1:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. |\n| `ofw_get_message(messageId)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them as read. |\n| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |\n| `ofw_get_unread_sent` | Sent messages your co-parent hasn't read yet (from cache). |\n| `ofw_list_drafts` | List saved drafts (cache-backed). Each draft carries `serverConfirmed` — see [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?)` | Download an attachment. `inline:true` returns bytes as MCP content; default writes to `~/Downloads/ofw-mcp/`. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Use before asserting current state. Only probes ids in the drafts cache unless `allowMarkRead:true` (probing others marks inbox messages read). |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Every read tool returns a `freshness` block: `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, and a `warning` whenever it is not `fresh`. Drafts additionally carry `serverConfirmed`.\n\nRules for using it:\n\n- **Never state current state from memory.** If you saved a draft earlier in the session, that is not evidence it still exists unsent now — the user may have sent or deleted it in the web app since.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Do not say a draft \"is still sitting unsent\" on that basis. Call `ofw_check_freshness(messageIds: [id])` first, or say plainly that you are reporting cached state and give its age.\n- **If `freshness.staleness` is not `fresh`, either re-read or surface the caveat** in your answer. The `warning` string is written to be quotable.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is tracked separately and compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user\n2. `ofw_send_message(..., draftId)` after approval — draft is auto-deleted on send\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Check `freshness`/`serverConfirmed` before saying what \"is\" true on OFW right now, and prefer `ofw_check_freshness` over guessing — it is one cheap call.\n\nFile v2.7.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.7.1\",\n  \"publishedAt\": 1785115653709\n}\n\nFile v2.7.1:skill-card.md\n\n## Description: <br>\nThis skill helps an agent work with OurFamilyWizard (OFW) co-parenting data, including messages, calendar events, expenses, journal entries, and related MCP workflows. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agent users use this skill to configure and operate the OFW MCP server for co-parenting workflows. It supports reading account context and managing messages, calendar events, shared expenses, journal entries, drafts, and attachments with user-aware cautions for sensitive actions. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Persistent agent access to sensitive co-parenting records can expose messages, contact details, calendar events, expenses, journal entries, and attachments. <br>\nMitigation: Install only for users who intentionally want OFW account access, use the narrowest available configuration, and avoid storing OFW credentials in broadly readable files. <br>\nRisk: Write-capable tools can send messages, create expenses or journal entries, upload attachments, create calendar items, or delete drafts and events. <br>\nMitigation: Require explicit user approval before any message, expense, calendar, journal, attachment, send, or delete action; prefer draft-only workflows for sensitive messages. <br>\nRisk: Some read operations can change OFW state, such as marking messages read or updating last-seen status. <br>\nMitigation: Warn the user before calls that may mark content as read or update status, and avoid background reads that could change account state silently. <br>\nRisk: Cached message and draft data can be stale and may not reflect current OFW state. <br>\nMitigation: Check freshness before making current-state claims and clearly identify cached or unverified results with their age when fresh confirmation is unavailable. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [npm package: ofw-mcp](https://www.npmjs.com/package/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Guidance, Shell commands, Configuration, MCP tool calls] <br>\n**Output Format:** [Markdown with inline JSON and bash code blocks] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [The skill may guide read and write operations against sensitive OFW records and should surface freshness, mark-as-read, and approval caveats when relevant.] <br>\n\n## Skill Version(s): <br>\n2.7.1 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.7.0: 3 files, 5146 bytes\n\nFiles: skill-card.md (2390b), SKILL.md (8242b), _meta.json (126b)\n\nFile v2.7.0:SKILL.md\n\n---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n> These tools are also available via the hosted [claude.ai](https://claude.ai) remote connector (a Cloudflare Worker) — the tool set and behaviour are identical to the local stdio install. See the repo's `docs/DEPLOY-CONNECTOR.md`.\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, page?, size?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. |\n| `ofw_get_message(messageId)` | Read a message OR draft body. Cache-first. Ids in the drafts cache return `folder: \"drafts\"`. ⚠️ Falls through to OFW for unread inbox messages, which marks them as read. |\n| `ofw_send_message(subject, body, recipientIds[], replyToId?, draftId?, myFileIDs?)` | Send a message. Pass `replyToId` to thread original history. Pass `draftId` to auto-delete the draft after sending. Pass `myFileIDs` (from `ofw_upload_attachment`) to attach files. |\n| `ofw_get_unread_sent` | Sent messages your co-parent hasn't read yet (from cache). |\n| `ofw_list_drafts` | List saved drafts (cache-backed). Each draft carries `serverConfirmed` — see [Freshness](#freshness). |\n| `ofw_save_draft(subject, body, recipientIds?, messageId?, replyToId?, myFileIDs?)` | Create a new draft. Pass `messageId` to **replace** an existing draft: the tool creates a fresh draft and deletes the old one (OFW's update-in-place endpoint silently no-ops). The returned `id` is the NEW id; the response includes a `NOTE` documenting the swap. |\n| `ofw_delete_draft(messageId)` | Delete a draft. |\n| `ofw_upload_attachment(path, shareClass?, label?, description?)` | Upload a local file to My Files; returns a fileId to pass into `myFileIDs`. |\n| `ofw_download_attachment(fileId, inline?, saveTo?, force?)` | Download an attachment. `inline:true` returns bytes as MCP content; default writes to `~/Downloads/ofw-mcp/`. |\n| `ofw_check_freshness(folders?, messageIds?, allowMarkRead?)` | Cheap live check that the cache still matches OFW — one request for folder counts plus one per id, no bodies, no sync. Use before asserting current state. Only probes ids in the drafts cache unless `allowMarkRead:true` (probing others marks inbox messages read). |\n\n### Calendar\n| Tool | Notes |\n|------|-------|\n| `ofw_list_events(startDate, endDate, detailed?)` | Dates as `YYYY-MM-DD` |\n| `ofw_create_event(title, startDate, endDate, ...)` | `startDate`/`endDate` as ISO datetime |\n| `ofw_update_event(eventId, ...)` | Partial update — only pass fields to change |\n| `ofw_delete_event(eventId)` | Permanent delete |\n\n### Expenses\n| Tool | Notes |\n|------|-------|\n| `ofw_get_expense_totals` | Summary of owed/paid totals |\n| `ofw_list_expenses(start?, max?)` | Paginated; default max 20 |\n| `ofw_create_expense(amount, description)` | Log a new expense |\n\n### Journal\n| Tool | Notes |\n|------|-------|\n| `ofw_list_journal_entries(start?, max?)` | 1-based offset; default max 10 |\n| `ofw_create_journal_entry(title, body)` | Create a new entry |\n\n## Freshness\n\nMessage and draft reads come from a local cache, so **a result can be stale without looking stale**. Every read tool returns a `freshness` block: `staleness` (`fresh`/`unverified`/`stale`), `asOf`, `ageSeconds`, and a `warning` whenever it is not `fresh`. Drafts additionally carry `serverConfirmed`.\n\nRules for using it:\n\n- **Never state current state from memory.** If you saved a draft earlier in the session, that is not evidence it still exists unsent now — the user may have sent or deleted it in the web app since.\n- **`serverConfirmed: false` means \"remembered, not known.\"** Do not say a draft \"is still sitting unsent\" on that basis. Call `ofw_check_freshness(messageIds: [id])` first, or say plainly that you are reporting cached state and give its age.\n- **If `freshness.staleness` is not `fresh`, either re-read or surface the caveat** in your answer. The `warning` string is written to be quotable.\n- OFW does **not** bump a draft's timestamp when it is edited in the web app, which is why freshness is tracked separately and compared by content revision. \"Nothing changed\" and \"we didn't look\" are otherwise indistinguishable.\n- A missing folder count in `ofw_sync_messages` output means that folder was **not checked** — it is never \"no changes\". Check `notRefreshed`.\n\n\n## Workflows\n\n**Check inbox:**\n1. `ofw_list_message_folders` → find inbox folder ID\n2. `ofw_list_messages(folderId)` → list messages\n3. `ofw_get_message(messageId)` → read a specific message\n\n**Send a message:**\n1. `ofw_get_profile` → get co-parent's user ID\n2. `ofw_send_message(subject, body, [coParentId])`\n\n**Reply to a message (with thread history):**\n1. `ofw_get_message(messageId)` → read the message to reply to\n2. `ofw_send_message(subject, body, [coParentId], replyToId: messageId)` — original message is included in the thread\n\n**Draft before sending (sensitive messages):**\n1. `ofw_save_draft(subject, body)` → review with user\n2. `ofw_send_message(..., draftId)` after approval — draft is auto-deleted on send\n\n**Check what's coming up:**\n- `ofw_get_notifications` for a quick summary\n- `ofw_list_events(today, +30days)` for calendar detail\n\n## Caution\n\n- **Always confirm before sending messages or deleting anything** — OFW is a legal co-parenting record.\n- `ofw_get_notifications` updates last-seen status — avoid calling silently in the background.\n- `ofw_get_message` marks messages read — warn the user if they want to keep something unread.\n- **Do not narrate cached state as present fact.** Check `freshness`/`serverConfirmed` before saying what \"is\" true on OFW right now, and prefer `ofw_check_freshness` over guessing — it is one cheap call.\n\nFile v2.7.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.7.0\",\n  \"publishedAt\": 1784691497737\n}\n\nFile v2.7.0:skill-card.md\n\n## Description: <br>\nProvides agent access to OurFamilyWizard co-parenting messages, calendar events, shared expenses, and journal entries through an MCP server. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[chrischall](https://clawhub.ai/user/chrischall) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nExternal users and developers use this skill to connect an agent to their OurFamilyWizard account, review co-parenting records, and perform message, calendar, expense, and journal workflows with appropriate confirmation. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can grant an agent broad access to sensitive OurFamilyWizard co-parenting records. <br>\nMitigation: Install only when agent access to the OFW account is intended, use explicit OFW requests, and avoid background checks. <br>\nRisk: Cached OFW data can be stale while still appearing usable. <br>\nMitigation: Check the provided freshness signals before relying on cached messages, drafts, or other OFW state. <br>\nRisk: Some operations can write, upload, send, delete, or change read and last-seen status in a legal-family record system. <br>\nMitigation: Require user confirmation before writes, uploads, sends, deletes, or status-changing reads. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/ofw-mcp) <br>\n- [npm package](https://www.npmjs.com/package/ofw-mcp) <br>\n- [Source repository](https://github.com/chrischall/ofw-mcp) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown instructions with JSON and shell command examples; MCP tool results may include text and structured data.] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May access or modify OFW records through MCP tools; cached read results include freshness signals that should be checked before relying on current state.] <br>\n\n## Skill Version(s): <br>\n2.7.0 (source: server release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>","readmeExcerpt":"Skill: Tmp.BcPQA7YzJI Owner: chrischall Summary: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entrie","codeSnippets":[],"executableExamples":[{"language":"json","snippet":"{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}"},{"language":"bash","snippet":"npm install -g ofw-mcp"},{"language":"bash","snippet":"git clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build"},{"language":"bash","snippet":"cp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD"},{"language":"bash","snippet":"mcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json"},{"language":"bash","snippet":"mcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: ofw-mcp\ndescription: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries.\n---\n\n# ofw-mcp\n\nMCP server for OurFamilyWizard — provides read/write access to messages, calendar, expenses, and journal.\n\n- **npm:** [npmjs.com/package/ofw-mcp](https://www.npmjs.com/package/ofw-mcp)\n- **Source:** [github.com/chrischall/ofw-mcp](https://github.com/chrischall/ofw-mcp)\n\n\n## Setup\n\n### Option A — Claude Code (direct MCP, no mcporter)\n\nAdd to `.mcp.json` in your project or `~/.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ofw\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ofw-mcp\"],\n      \"env\": {\n        \"OFW_USERNAME\": \"you@example.com\",\n        \"OFW_PASSWORD\": \"yourpassword\"\n      }\n    }\n  }\n}\n```\n\n### Option B — mcporter\n\n#### 1. Install\n\n```bash\nnpm install -g ofw-mcp\n```\n\nOr from source:\n```bash\ngit clone https://github.com/chrischall/ofw-mcp\ncd ofw-mcp\nnpm install && npm run build\n```\n\n#### 2. Configure credentials\n\n```bash\ncp .env.example .env\n# Edit .env: set OFW_USERNAME and OFW_PASSWORD\n```\n\n#### 3. Register with mcporter\n\n```bash\nmcporter config add ofw \\\n  --command \"ofw-mcp\" \\\n  --env \"OFW_USERNAME=you@example.com\" \\\n  --env \"OFW_PASSWORD=yourpassword\" \\\n  --config ~/.mcporter/mcporter.json\n```\n\n#### 4. Verify\n\n```bash\nmcporter list --config ~/.mcporter/mcporter.json\nmcporter call ofw.ofw_get_profile --config ~/.mcporter/mcporter.json\n```\n\n## Calling tools (mcporter)\n\n```bash\nmcporter call ofw.<tool_name> [key=value ...] --config ~/.mcporter/mcporter.json\n```\n\nAlways pass `--config ~/.mcporter/mcporter.json` unless a local `config/mcporter.json` exists.\n\n## Tools\n\n### User\n| Tool | Description |\n|------|-------------|\n| `ofw_get_profile` | Current user + co-parent info (IDs, contact details) |\n| `ofw_get_notifications` | Dashboard summary: unread count, upcoming events, outstanding expenses. ⚠️ Updates last-seen status. |\n\n### Messages\n| Tool | Notes |\n|------|-------|\n| `ofw_sync_messages(folders?, deep?, fetchUnreadBodies?)` | Sync OFW → local cache. **Call first if the cache might be stale.** Returns unread inbox hints (bodies not fetched, to avoid mark-as-read). |\n| `ofw_list_message_folders` | List OFW folders with unread counts. Most reads use the cache; this is mainly for folder IDs and live unread counts. |\n| `ofw_list_messages(folderId?, since?, until?, q?, sort?, page?, size?, autoRefresh?)` | Cache-backed list. Supports folder (\"inbox\"/\"sent\"/\"both\"), date range, and substring search. `sort:\"oldest\"` starts at the old end of a range instead of paging to it (default `\"newest\"`). Returns `complete` for the RESULT SET plus **`nextPage`** (null when done) — and the paging keys come FIRST in the JSON, befo"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"ofw-mcp\",\n  \"version\": \"2.11.0\",\n  \"publishedAt\": 1787520787374\n}"},{"path":"skill-card.md","content":"## Description:\n\nMCP server for OurFamilyWizard that provides read/write access to messages, calendar events, expenses, and journal entries.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal OurFamilyWizard users use this skill to let an agent inspect and manage co-parenting messages, calendar events, shared expenses, and journal entries. It is intended for workflows where the user wants OFW data access through MCP while preserving explicit review for sensitive actions.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill asks users to run external MCP server code with reusable OFW credentials and broad read/write access to sensitive legal-family records.\n\nMitigation: Use a pinned, reviewed package version, keep OFW credentials out of project files and shell history, and store secret files with restrictive permissions.\n\nRisk: Some OFW operations can send messages, delete records, mark messages read, or update last-seen status.\n\nMitigation: Require explicit user confirmation before sending messages, deleting records, reading unread messages that may mark them read, or calling notification reads that update status.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/chrischall/skills/ofw-mcp)\n- [npm Package](https://www.npmjs.com/package/ofw-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline JSON and bash code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide MCP tool calls that read or modify OurFamilyWizard records.]\n\n## Skill Version(s):\n\n2.11.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entries. Skill: Tmp.BcPQA7YzJI Owner: chrischall Summary: This skill should be used when the user asks about OurFamilyWizard (OFW) co-parenting data. Triggers on phrases like \"check OFW\", \"OurFamilyWizard inbox\", \"OFW messages\", \"OFW calendar\", \"OFW expenses\", \"what did my co-parent say\", \"log an expense in OFW\", \"OFW journal\", or any request involving co-parenting messages, calendar events, shared expenses, or journal entrie","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1370,"uniquenessScore":47,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T09:49:02.055Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T01:28:19.188Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}