{"id":"f0ea8faf-542d-4488-852b-fcbd4d05b761","entityType":"agent","slug":"clawhub-juicyroots-nextcloud-aio-oc","name":"NextCloud AIO OpenClaw","canonicalUrl":"https://www.xpersona.co/agent/clawhub-juicyroots-nextcloud-aio-oc","canonicalPath":"/agent/clawhub-juicyroots-nextcloud-aio-oc","generatedAt":"2026-10-12T09:05:33.297Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T19:55:53.921Z","emptyReason":null},"description":"Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update). Skill: NextCloud AIO OpenClaw Owner: juicyroots Summary: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update). Tags: latest:1.1.2 Version history: v1.1.2 | 2026-03-10T17:51:22.890Z | user Added ability to handle binary documents v1.1.1 | 2026-03-05T15:34:31.475Z | user Internal changes for ambiguity and validation v1.1.0 | 2026-","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17e4cef483zb51q01jbcz2erd884pqa:nextcloud-aio-oc","sourceUrl":"https://clawhub.ai/juicyroots/nextcloud-aio-oc","homepage":"https://clawhub.ai/juicyroots/skills/nextcloud-aio-oc","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/juicyroots/nextcloud-aio-oc","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/juicyroots/skills/nextcloud-aio-oc","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update). Skill: NextCloud"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T19:55:53.921Z","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-11T19:55:53.921Z","emptyReason":null},"stars":null,"forks":null,"downloads":1001,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.1.2","tractionLabel":"1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T19:55:53.863Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T19:55:53.921Z","lastCrawledAt":"2026-10-11T19:55:53.863Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T19:55:53.863Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.2","createdAt":"2026-03-10T17:51:22.890Z","changelog":"Added ability to handle binary documents","fileCount":5,"zipByteSize":92078},{"version":"1.1.1","createdAt":"2026-03-05T15:34:31.475Z","changelog":"Internal changes for ambiguity and validation","fileCount":3,"zipByteSize":86611},{"version":"1.1.0","createdAt":"2026-03-05T15:25:12.599Z","changelog":"Added machine-readable frontmatter metadata","fileCount":3,"zipByteSize":86595},{"version":"1.0.9","createdAt":"2026-03-05T15:22:12.232Z","changelog":"Added Runtime and Metadata Contract with explicit requirements, review list, etc.","fileCount":3,"zipByteSize":86221},{"version":"1.0.8","createdAt":"2026-03-05T14:54:30.526Z","changelog":"Simplified SKILL.md, removed redundancy.","fileCount":3,"zipByteSize":85635},{"version":"1.0.7","createdAt":"2026-03-05T14:05:22.659Z","changelog":"Small SKILL.md Update","fileCount":3,"zipByteSize":87028},{"version":"1.0.6","createdAt":"2026-03-05T14:00:19.019Z","changelog":"Initial release","fileCount":3,"zipByteSize":87028}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17e4cef483zb51q01jbcz2erd884pqa:nextcloud-aio-oc","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-juicyroots-nextcloud-aio-oc/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/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-12T09:05:33.294Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-juicyroots-nextcloud-aio-oc/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-11T19:55:53.921Z","emptyReason":null},"readme":"Skill: NextCloud AIO OpenClaw\n\nOwner: juicyroots\n\nSummary: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\n\nTags: latest:1.1.2\n\nVersion history:\n\nv1.1.2 | 2026-03-10T17:51:22.890Z | user\n\nAdded ability to handle binary documents\n\nv1.1.1 | 2026-03-05T15:34:31.475Z | user\n\nInternal changes for ambiguity and validation\n\nv1.1.0 | 2026-03-05T15:25:12.599Z | user\n\nAdded machine-readable frontmatter metadata\n\nv1.0.9 | 2026-03-05T15:22:12.232Z | user\n\nAdded Runtime and Metadata Contract with explicit requirements, review list, etc.\n\nv1.0.8 | 2026-03-05T14:54:30.526Z | user\n\nSimplified SKILL.md, removed redundancy.\n\nv1.0.7 | 2026-03-05T14:05:22.659Z | user\n\nSmall SKILL.md Update\n\nv1.0.6 | 2026-03-05T14:00:19.019Z | user\n\nInitial release\n\nArchive index:\n\nArchive v1.1.2: 5 files, 92078 bytes\n\nFiles: scripts/files_binary.py (7292b), scripts/nextcloud.js (682605b), skill-card.md (2188b), SKILL.md (17796b), _meta.json (135b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: nextcloud-aio-oc (NextCloud AIO OpenClaw)\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nrequired-binaries:\n  - node>=20\nrequired-env-vars:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptional-env-vars:\n  - NEXTCLOUD_TIMEZONE\nrequiredBinaries:\n  - node\nrequiredEnv:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptionalEnv:\n  - NEXTCLOUD_TIMEZONE\nprimaryEnv: NEXTCLOUD_TOKEN\nallowed-tools: Bash Read\n---\n\n# NextCloud AIO OpenClaw Skill\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: Predictable, loss-resistant Nextcloud reads/writes.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Runtime and Metadata Contract\n\nThis section is the source of truth for registry metadata parity.\n\n- Required binary: `node` (Node.js `20+`)\n- Required environment variables: `NEXTCLOUD_URL`, `NEXTCLOUD_USER`, `NEXTCLOUD_TOKEN`\n- Optional environment variable: `NEXTCLOUD_TIMEZONE`\n- Required network target: the host defined by `NEXTCLOUD_URL` (plus normal redirects from that host)\n\nIf a registry entry says \"no required binaries\" or \"no required env vars\", treat it as stale metadata and fix before publishing.\n\n## Preflight Audit Gate\n\nBefore first execution in any new environment:\n\n- Complete the bundled script review checklist below.\n- Confirm no unexpected endpoints or privileged system calls are present.\n- If checks are incomplete, do not run the skill.\n- Prefer sandbox/container validation and least-privilege app credentials first.\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Bundled Script Review Checklist (Before First Use)\n\nThe skill ships two scripts: `scripts/nextcloud.js` (Node.js, text operations) and `scripts/files_binary.py` (Python 3, binary file transfers). Review both before running in new environments:\n\n1. Confirm runtime requirements:\n   - `node --version` (must be `20+`)\n2. Check obvious outbound endpoints:\n   - `rg -n \"https?://\" scripts/nextcloud.js`\n3. Check sensitive capability usage:\n   - `rg -n \"child_process|spawn\\\\(|exec\\\\(|require\\\\(\\\"fs\\\"\\\\)|require\\\\('fs'\\\\)|fs\\\\.\" scripts/nextcloud.js`\n4. Verify credentials are env-driven only:\n   - `rg -n \"NEXTCLOUD_URL|NEXTCLOUD_USER|NEXTCLOUD_TOKEN|NEXTCLOUD_TIMEZONE\" scripts/nextcloud.js`\n5. Run in low-risk mode first:\n   - Use a dedicated low-privilege Nextcloud app password\n   - Test against non-production data when possible\n\nIf review confidence is low, do not run until code is reviewed by a trusted maintainer.\n\n### Static audit snapshot (current bundle)\n\nQuick grep-style checks on `scripts/nextcloud.js` should currently show:\n\n- Config is read from `process.env.NEXTCLOUD_URL|USER|TOKEN|TIMEZONE`.\n- Request path is built as `${CONFIG.url}${endpoint}` and uses `fetch(...)`.\n- No obvious `child_process` or `fs` usage in the bundle entry path.\n\nQuick checks on `scripts/files_binary.py`:\n\n- Config is read from `os.environ.get(\"NEXTCLOUD_URL|USER|TOKEN\")`.\n- DAV URL is built as `{url}/remote.php/dav/files/{user}/{path}`.\n- Uses only stdlib (`urllib`, `base64`, `xml.etree`); no third-party deps.\n\nThis is not a full security audit. Re-run checks after every bundle update.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files (text)\n- `files list [--path <path>]`\n- `files search --query <query>` (supports natural-language input; ranks by filename/path token relevance)\n- `files get --path <path>` (accepts relative user path or full DAV href)\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Files (binary) — ODT, DOCX, PDF, images, etc.\n\n`nextcloud.js` passes file content as text strings, which corrupts binary formats.\nUse the companion Python script for any binary file:\n\n```bash\npython3 scripts/files_binary.py download <nc_path> <local_path>\npython3 scripts/files_binary.py upload   <local_path> <nc_path>\npython3 scripts/files_binary.py exists   <nc_path>\npython3 scripts/files_binary.py list     [<nc_path>]\n```\n\nReads the same `NEXTCLOUD_URL`, `NEXTCLOUD_USER`, `NEXTCLOUD_TOKEN` env vars.\nAuto-detects MIME type from file extension (ODT, DOCX, XLSX, PDF, PNG, JPG, and more).\n\n**When to use which:**\n\n| Situation | Command |\n|-----------|---------|\n| Plain text files (`.md`, `.txt`, `.csv`) | `node scripts/nextcloud.js files get/upload` |\n| Binary files (`.odt`, `.docx`, `.pdf`, images) | `python3 scripts/files_binary.py download/upload` |\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules (Quick Reference)\n\nApply these on every write to prevent corruption and confusion:\n\n1) Identity and naming\n- Never infer `UID` from URL; always use payload `uid`.\n- Use `fullName` and `structuredName` for user-facing names; keep `nameRaw` diagnostic-only.\n\n2) Contact and birthday integrity\n- Birthday input formats: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons to `BDAY`.\n- Birthdays are contact fields: use `contacts create/edit --birthday ...`; never edit birthday-derived calendar entries directly.\n\n3) Intent-preserving updates\n- Modify only fields explicitly requested by the user.\n- To clear a value, pass explicit empty values.\n- Respect explicit `--addressbook`; otherwise use remembered default or ask once.\n\n4) Calendar and task validation\n- Validate date/datetime inputs before sending; require `end > start` for timed events.\n- Escape ICS text fields (`SUMMARY`, `DESCRIPTION`).\n- Validate task priority range (`0..9`).\n- For timezone-less timed input, use `--timezone` or `NEXTCLOUD_TIMEZONE`.\n- For all-day events, use `VALUE=DATE` semantics with exclusive `DTEND`.\n\n5) Capability and safety checks\n- Do not assume listed event calendars are writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explain event mutation is unavailable until writable access exists.\n- Some calendars are multi-component (`VEVENT` + `VTODO`); keep them eligible for both event/task flows.\n\n6) Files and post-write verification\n- Require non-empty file paths for `files upload/get/delete`.\n- Escape XML filter/search values for CardDAV/WebDAV operations.\n- After mutations (`create`, `edit`, `complete`, `delete`), verify with follow-up read/list when practical.\n- For propagation delay, retry around `0.5s`, `1s`, `2s` before declaring failure.\n\n## Known Nextcloud/CardDAV Behaviors\n\n- Servers/clients may negotiate or normalize vCard versions (`3.0` vs `4.0`) and content on write/read.\n- `FN` and `N` should each appear once in valid contacts.\n- `BDAY` failures are often malformed input (for example stray delimiters), not server instability.\n- Folded vCard lines must be unfolded before parsing.\n\n## Error to Action Map (Fast)\n\n- `HTTP 403` on `calendar create/edit/delete` -> likely read-only/system calendar or missing permission; switch to writable events calendar.\n- `HTTP 501` on `files search` -> WebDAV `SEARCH` unsupported; fallback to recursive `PROPFIND` + client-side filter.\n- `HTTP 415` on task/event update -> malformed ICS payload; normalize formatting and retry once.\n- Contact write succeeded but UI still stale -> run verification retry cycle before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior Playbooks (Condensed)\n\nThese playbooks are execution shortcuts. Reliability and safety rules above still apply.\n\n### Contacts and Birthdays\n1. Resolve address book (`--addressbook` or remembered default).\n2. For create/edit, pass only user-requested fields; use explicit empty values when user wants fields cleared.\n3. Use `--name` for full-name input; use structured-name flags for split-name input.\n4. Pass multiple emails/phones as CSV values.\n5. Birthday changes always go through contacts (`contacts create/edit --birthday ...`), never calendar mutation commands.\n6. Verify birthday/name-sensitive writes with `contacts get --uid ...` when confidence is important.\n\n### Tasks\n1. Resolve task calendar when omitted.\n2. Validate due and priority (`0..9`) before write.\n3. After create/edit/complete/delete, verify via focused list/get when practical.\n\n### Calendar Events\n1. Resolve writable events calendar; treat `Contact birthdays` and system calendars as read-only.\n2. Validate `start`/`end` and require `end > start` for timed events.\n3. For timezone-less date-times, pass `--timezone` or use `NEXTCLOUD_TIMEZONE`.\n4. For all-day intent, use `--all-day` with date values (not timed midnight ranges).\n5. Re-list in a focused window after mutation when confidence is important.\n\nAll-day end-date normalization behavior:\n- `start=YYYY-MM-DD`, `end=YYYY-MM-DD` -> inclusive single-day input, normalized.\n- `start=YYYY-MM-DD`, `end=next-day` -> already-exclusive single-day input.\n- Multi-day inclusive ranges -> normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. `files get/upload/delete` accept either a relative user path (for example `/Share-Family/file.docx`) or a full DAV href returned by search.\n3. For binary files (ODT, DOCX, PDF, images), use `python3 scripts/files_binary.py` — never pass binary content through `nextcloud.js files upload`.\n4. Use deterministic test paths for temporary validation files.\n5. Read back uploaded content and then delete test files.\n6. Use `files search` with user phrasing directly; it auto-normalizes query text and ranks likely matches.\n7. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\nUse least-privilege credentials for tests and monitor outbound traffic; the process should only communicate with `NEXTCLOUD_URL`.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Persistent Rules (Store These)\n\nPersist these high-value rules in memory/rules:\n\n1. Birthdays are contact fields: use `contacts create/edit --birthday ...`; never mutate `Contact birthdays` directly.\n2. For all-day events, always use `calendar create/edit --all-day` with date values (avoid timed midnight ranges).\n3. For timezone-less timed values, use `--timezone` or `NEXTCLOUD_TIMEZONE`; ask if timezone is unknown.\n4. Prefer writable user calendars for event mutations; if `403`, report likely read-only/permission issue.\n5. Verify event/contact writes with a focused read/list before declaring final success.\n6. Keep canonical all-day encoding (`VALUE=DATE`); avoid duplicate compatibility events unless explicitly requested.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1773165082890\n}\n\nFile v1.1.2:skill-card.md\n\n## Description:\n\nReliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[juicyroots](https://clawhub.ai/user/juicyroots)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to manage Nextcloud notes, tasks, calendar events, files, and contacts through OpenClaw. It is intended for environments where a configured Nextcloud account can safely support remote reads, writes, uploads, and deletes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill handles Nextcloud credentials that may grant access to private account data.\n\nMitigation: Use a dedicated, revocable, least-privilege Nextcloud app password and keep credentials in environment variables or a local secret store.\n\nRisk: Remote upload and delete commands can modify or remove account data, including unintended paths if requests are not reviewed.\n\nMitigation: Test on non-production data first, use explicit reviewed paths, review commands before execution, and verify mutations with follow-up reads where practical.\n\nRisk: Unencrypted or redirected Nextcloud endpoints can expose credentials or data.\n\nMitigation: Configure an HTTPS-only NEXTCLOUD_URL and avoid untrusted redirects.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/juicyroots/skills/nextcloud-aio-oc)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with shell command examples and JSON command results]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires Node.js 20+, NEXTCLOUD_URL, NEXTCLOUD_USER, and NEXTCLOUD_TOKEN; binary file transfers use the Python helper.]\n\n## Skill Version(s):\n\n1.1.2 (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 v1.1.1: 3 files, 86611 bytes\n\nFiles: scripts/nextcloud.js (679402b), SKILL.md (16061b), _meta.json (135b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: nextcloud-aio-oc (NextCloud AIO OpenClaw)\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nrequired-binaries:\n  - node>=20\nrequired-env-vars:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptional-env-vars:\n  - NEXTCLOUD_TIMEZONE\nrequiredBinaries:\n  - node\nrequiredEnv:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptionalEnv:\n  - NEXTCLOUD_TIMEZONE\nprimaryEnv: NEXTCLOUD_TOKEN\nallowed-tools: Bash Read\n---\n\n# NextCloud AIO OpenClaw Skill\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: Predictable, loss-resistant Nextcloud reads/writes.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Runtime and Metadata Contract\n\nThis section is the source of truth for registry metadata parity.\n\n- Required binary: `node` (Node.js `20+`)\n- Required environment variables: `NEXTCLOUD_URL`, `NEXTCLOUD_USER`, `NEXTCLOUD_TOKEN`\n- Optional environment variable: `NEXTCLOUD_TIMEZONE`\n- Required network target: the host defined by `NEXTCLOUD_URL` (plus normal redirects from that host)\n\nIf a registry entry says \"no required binaries\" or \"no required env vars\", treat it as stale metadata and fix before publishing.\n\n## Preflight Audit Gate\n\nBefore first execution in any new environment:\n\n- Complete the bundled script review checklist below.\n- Confirm no unexpected endpoints or privileged system calls are present.\n- If checks are incomplete, do not run the skill.\n- Prefer sandbox/container validation and least-privilege app credentials first.\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Bundled Script Review Checklist (Before First Use)\n\nThe skill ships executable JavaScript at `scripts/nextcloud.js`. Review before running in new environments:\n\n1. Confirm runtime requirements:\n   - `node --version` (must be `20+`)\n2. Check obvious outbound endpoints:\n   - `rg -n \"https?://\" scripts/nextcloud.js`\n3. Check sensitive capability usage:\n   - `rg -n \"child_process|spawn\\\\(|exec\\\\(|require\\\\(\\\"fs\\\"\\\\)|require\\\\('fs'\\\\)|fs\\\\.\" scripts/nextcloud.js`\n4. Verify credentials are env-driven only:\n   - `rg -n \"NEXTCLOUD_URL|NEXTCLOUD_USER|NEXTCLOUD_TOKEN|NEXTCLOUD_TIMEZONE\" scripts/nextcloud.js`\n5. Run in low-risk mode first:\n   - Use a dedicated low-privilege Nextcloud app password\n   - Test against non-production data when possible\n\nIf review confidence is low, do not run until code is reviewed by a trusted maintainer.\n\n### Static audit snapshot (current bundle)\n\nQuick grep-style checks on `scripts/nextcloud.js` should currently show:\n\n- Config is read from `process.env.NEXTCLOUD_URL|USER|TOKEN|TIMEZONE`.\n- Request path is built as `${CONFIG.url}${endpoint}` and uses `fetch(...)`.\n- No obvious `child_process` or `fs` usage in the bundle entry path.\n\nThis is not a full security audit. Re-run checks after every bundle update.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files\n- `files list [--path <path>]`\n- `files search --query <query>`\n- `files get --path <path>`\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules (Quick Reference)\n\nApply these on every write to prevent corruption and confusion:\n\n1) Identity and naming\n- Never infer `UID` from URL; always use payload `uid`.\n- Use `fullName` and `structuredName` for user-facing names; keep `nameRaw` diagnostic-only.\n\n2) Contact and birthday integrity\n- Birthday input formats: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons to `BDAY`.\n- Birthdays are contact fields: use `contacts create/edit --birthday ...`; never edit birthday-derived calendar entries directly.\n\n3) Intent-preserving updates\n- Modify only fields explicitly requested by the user.\n- To clear a value, pass explicit empty values.\n- Respect explicit `--addressbook`; otherwise use remembered default or ask once.\n\n4) Calendar and task validation\n- Validate date/datetime inputs before sending; require `end > start` for timed events.\n- Escape ICS text fields (`SUMMARY`, `DESCRIPTION`).\n- Validate task priority range (`0..9`).\n- For timezone-less timed input, use `--timezone` or `NEXTCLOUD_TIMEZONE`.\n- For all-day events, use `VALUE=DATE` semantics with exclusive `DTEND`.\n\n5) Capability and safety checks\n- Do not assume listed event calendars are writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explain event mutation is unavailable until writable access exists.\n- Some calendars are multi-component (`VEVENT` + `VTODO`); keep them eligible for both event/task flows.\n\n6) Files and post-write verification\n- Require non-empty file paths for `files upload/get/delete`.\n- Escape XML filter/search values for CardDAV/WebDAV operations.\n- After mutations (`create`, `edit`, `complete`, `delete`), verify with follow-up read/list when practical.\n- For propagation delay, retry around `0.5s`, `1s`, `2s` before declaring failure.\n\n## Known Nextcloud/CardDAV Behaviors\n\n- Servers/clients may negotiate or normalize vCard versions (`3.0` vs `4.0`) and content on write/read.\n- `FN` and `N` should each appear once in valid contacts.\n- `BDAY` failures are often malformed input (for example stray delimiters), not server instability.\n- Folded vCard lines must be unfolded before parsing.\n\n## Error to Action Map (Fast)\n\n- `HTTP 403` on `calendar create/edit/delete` -> likely read-only/system calendar or missing permission; switch to writable events calendar.\n- `HTTP 501` on `files search` -> WebDAV `SEARCH` unsupported; fallback to recursive `PROPFIND` + client-side filter.\n- `HTTP 415` on task/event update -> malformed ICS payload; normalize formatting and retry once.\n- Contact write succeeded but UI still stale -> run verification retry cycle before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior Playbooks (Condensed)\n\nThese playbooks are execution shortcuts. Reliability and safety rules above still apply.\n\n### Contacts and Birthdays\n1. Resolve address book (`--addressbook` or remembered default).\n2. For create/edit, pass only user-requested fields; use explicit empty values when user wants fields cleared.\n3. Use `--name` for full-name input; use structured-name flags for split-name input.\n4. Pass multiple emails/phones as CSV values.\n5. Birthday changes always go through contacts (`contacts create/edit --birthday ...`), never calendar mutation commands.\n6. Verify birthday/name-sensitive writes with `contacts get --uid ...` when confidence is important.\n\n### Tasks\n1. Resolve task calendar when omitted.\n2. Validate due and priority (`0..9`) before write.\n3. After create/edit/complete/delete, verify via focused list/get when practical.\n\n### Calendar Events\n1. Resolve writable events calendar; treat `Contact birthdays` and system calendars as read-only.\n2. Validate `start`/`end` and require `end > start` for timed events.\n3. For timezone-less date-times, pass `--timezone` or use `NEXTCLOUD_TIMEZONE`.\n4. For all-day intent, use `--all-day` with date values (not timed midnight ranges).\n5. Re-list in a focused window after mutation when confidence is important.\n\nAll-day end-date normalization behavior:\n- `start=YYYY-MM-DD`, `end=YYYY-MM-DD` -> inclusive single-day input, normalized.\n- `start=YYYY-MM-DD`, `end=next-day` -> already-exclusive single-day input.\n- Multi-day inclusive ranges -> normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. Use deterministic test paths for temporary validation files.\n3. Read back uploaded content and then delete test files.\n4. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\nUse least-privilege credentials for tests and monitor outbound traffic; the process should only communicate with `NEXTCLOUD_URL`.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Persistent Rules (Store These)\n\nPersist these high-value rules in memory/rules:\n\n1. Birthdays are contact fields: use `contacts create/edit --birthday ...`; never mutate `Contact birthdays` directly.\n2. For all-day events, always use `calendar create/edit --all-day` with date values (avoid timed midnight ranges).\n3. For timezone-less timed values, use `--timezone` or `NEXTCLOUD_TIMEZONE`; ask if timezone is unknown.\n4. Prefer writable user calendars for event mutations; if `403`, report likely read-only/permission issue.\n5. Verify event/contact writes with a focused read/list before declaring final success.\n6. Keep canonical all-day encoding (`VALUE=DATE`); avoid duplicate compatibility events unless explicitly requested.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1772724871475\n}\n\nArchive v1.1.0: 3 files, 86595 bytes\n\nFiles: scripts/nextcloud.js (679402b), SKILL.md (15925b), _meta.json (135b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: nextcloud-aio-oc (NextCloud AIO OpenClaw)\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nrequired-binaries:\n  - node>=20\nrequired-env-vars:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptional-env-vars:\n  - NEXTCLOUD_TIMEZONE\nallowed-tools: Bash Read\n---\n\n# NextCloud AIO OpenClaw Skill\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: predictable, loss-resistant Nextcloud reads/writes, especially for Contacts.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Runtime and Metadata Contract\n\nThis section is the source of truth for registry metadata parity.\n\n- Required binary: `node` (Node.js `20+`)\n- Required environment variables: `NEXTCLOUD_URL`, `NEXTCLOUD_USER`, `NEXTCLOUD_TOKEN`\n- Optional environment variable: `NEXTCLOUD_TIMEZONE`\n- Required network target: the host defined by `NEXTCLOUD_URL` (plus normal redirects from that host)\n\nIf a registry entry says \"no required binaries\" or \"no required env vars\", treat it as stale metadata and fix before publishing.\n\n## Preflight Audit Gate\n\nBefore first execution in any new environment:\n\n- Complete the bundled script review checklist below.\n- Confirm no unexpected endpoints or privileged system calls are present.\n- If checks are incomplete, do not run the skill.\n- Prefer sandbox/container validation and least-privilege app credentials first.\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Bundled Script Review Checklist (Before First Use)\n\nThe skill ships executable JavaScript at `scripts/nextcloud.js`. Review before running in new environments:\n\n1. Confirm runtime requirements:\n   - `node --version` (must be `20+`)\n2. Check obvious outbound endpoints:\n   - `rg -n \"https?://\" scripts/nextcloud.js`\n3. Check sensitive capability usage:\n   - `rg -n \"child_process|spawn\\\\(|exec\\\\(|require\\\\(\\\"fs\\\"\\\\)|require\\\\('fs'\\\\)|fs\\\\.\" scripts/nextcloud.js`\n4. Verify credentials are env-driven only:\n   - `rg -n \"NEXTCLOUD_URL|NEXTCLOUD_USER|NEXTCLOUD_TOKEN|NEXTCLOUD_TIMEZONE\" scripts/nextcloud.js`\n5. Run in low-risk mode first:\n   - Use a dedicated low-privilege Nextcloud app password\n   - Test against non-production data when possible\n\nIf review confidence is low, do not run until code is reviewed by a trusted maintainer.\n\n### Static audit snapshot (current bundle)\n\nQuick grep-style checks on `scripts/nextcloud.js` should currently show:\n\n- Config is read from `process.env.NEXTCLOUD_URL|USER|TOKEN|TIMEZONE`.\n- Request path is built as `${CONFIG.url}${endpoint}` and uses `fetch(...)`.\n- No obvious `child_process` or `fs` usage in the bundle entry path.\n\nThis is not a full security audit. Re-run checks after every bundle update.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files\n- `files list [--path <path>]`\n- `files search --query <query>`\n- `files get --path <path>`\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules (Quick Reference)\n\nApply these on every write to prevent corruption and confusion:\n\n1) Identity and naming\n- Never infer `UID` from URL; always use payload `uid`.\n- Use `fullName` and `structuredName` for user-facing names; keep `nameRaw` diagnostic-only.\n\n2) Contact and birthday integrity\n- Birthday input formats: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons to `BDAY`.\n- Birthdays are contact fields: use `contacts create/edit --birthday ...`; never edit birthday-derived calendar entries directly.\n\n3) Intent-preserving updates\n- Modify only fields explicitly requested by the user.\n- To clear a value, pass explicit empty values.\n- Respect explicit `--addressbook`; otherwise use remembered default or ask once.\n\n4) Calendar and task validation\n- Validate date/datetime inputs before sending; require `end > start` for timed events.\n- Escape ICS text fields (`SUMMARY`, `DESCRIPTION`).\n- Validate task priority range (`0..9`).\n- For timezone-less timed input, use `--timezone` or `NEXTCLOUD_TIMEZONE`.\n- For all-day events, use `VALUE=DATE` semantics with exclusive `DTEND`.\n\n5) Capability and safety checks\n- Do not assume listed event calendars are writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explain event mutation is unavailable until writable access exists.\n- Some calendars are multi-component (`VEVENT` + `VTODO`); keep them eligible for both event/task flows.\n\n6) Files and post-write verification\n- Require non-empty file paths for `files upload/get/delete`.\n- Escape XML filter/search values for CardDAV/WebDAV operations.\n- After mutations (`create`, `edit`, `complete`, `delete`), verify with follow-up read/list when practical.\n- For propagation delay, retry around `0.5s`, `1s`, `2s` before declaring failure.\n\n## Known Nextcloud/CardDAV Behaviors\n\n- Servers/clients may negotiate or normalize vCard versions (`3.0` vs `4.0`) and content on write/read.\n- `FN` and `N` should each appear once in valid contacts.\n- `BDAY` failures are often malformed input (for example stray delimiters), not server instability.\n- Folded vCard lines must be unfolded before parsing.\n\n## Error to Action Map (Fast)\n\n- `HTTP 403` on `calendar create/edit/delete` -> likely read-only/system calendar or missing permission; switch to writable events calendar.\n- `HTTP 501` on `files search` -> WebDAV `SEARCH` unsupported; fallback to recursive `PROPFIND` + client-side filter.\n- `HTTP 415` on task/event update -> malformed ICS payload; normalize formatting and retry once.\n- Contact write succeeded but UI still stale -> run verification retry cycle before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior Playbooks (Condensed)\n\nThese playbooks are execution shortcuts. Reliability and safety rules above still apply.\n\n### Contacts and Birthdays\n1. Resolve address book (`--addressbook` or remembered default).\n2. For create/edit, pass only user-requested fields; use explicit empty values when user wants fields cleared.\n3. Use `--name` for full-name input; use structured-name flags for split-name input.\n4. Pass multiple emails/phones as CSV values.\n5. Birthday changes always go through contacts (`contacts create/edit --birthday ...`), never calendar mutation commands.\n6. Verify birthday/name-sensitive writes with `contacts get --uid ...` when confidence is important.\n\n### Tasks\n1. Resolve task calendar when omitted.\n2. Validate due and priority (`0..9`) before write.\n3. After create/edit/complete/delete, verify via focused list/get when practical.\n\n### Calendar Events\n1. Resolve writable events calendar; treat `Contact birthdays` and system calendars as read-only.\n2. Validate `start`/`end` and require `end > start` for timed events.\n3. For timezone-less date-times, pass `--timezone` or use `NEXTCLOUD_TIMEZONE`.\n4. For all-day intent, use `--all-day` with date values (not timed midnight ranges).\n5. Re-list in a focused window after mutation when confidence is important.\n\nAll-day end-date normalization behavior:\n- `start=YYYY-MM-DD`, `end=YYYY-MM-DD` -> inclusive single-day input, normalized.\n- `start=YYYY-MM-DD`, `end=next-day` -> already-exclusive single-day input.\n- Multi-day inclusive ranges -> normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. Use deterministic test paths for temporary validation files.\n3. Read back uploaded content and then delete test files.\n4. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\nUse least-privilege credentials for tests and monitor outbound traffic; the process should only communicate with `NEXTCLOUD_URL`.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Persistent Rules (Store These)\n\nPersist these high-value rules in memory/rules:\n\n1. Birthdays are contact fields: use `contacts create/edit --birthday ...`; never mutate `Contact birthdays` directly.\n2. For all-day events, always use `calendar create/edit --all-day` with date values (avoid timed midnight ranges).\n3. For timezone-less timed values, use `--timezone` or `NEXTCLOUD_TIMEZONE`; ask if timezone is unknown.\n4. Prefer writable user calendars for event mutations; if `403`, report likely read-only/permission issue.\n5. Verify event/contact writes with a focused read/list before declaring final success.\n6. Keep canonical all-day encoding (`VALUE=DATE`); avoid duplicate compatibility events unless explicitly requested.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.1.0\",\n  \"publishedAt\": 1772724312599\n}\n\nArchive v1.0.9: 3 files, 86221 bytes\n\nFiles: scripts/nextcloud.js (679402b), SKILL.md (15029b), _meta.json (135b)\n\nFile v1.0.9:SKILL.md\n\n---\nname: nextcloud-aio-oc (NextCloud AIO OpenClaw)\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nallowed-tools: Bash Read\n---\n\n# NextCloud AIO OpenClaw Skill\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: predictable, loss-resistant Nextcloud reads/writes, especially for Contacts.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Runtime and Metadata Contract\n\nThis section is the source of truth for registry metadata parity.\n\n- Required binary: `node` (Node.js `20+`)\n- Required environment variables: `NEXTCLOUD_URL`, `NEXTCLOUD_USER`, `NEXTCLOUD_TOKEN`\n- Optional environment variable: `NEXTCLOUD_TIMEZONE`\n- Required network target: the host defined by `NEXTCLOUD_URL` (plus normal redirects from that host)\n\nIf a registry entry says \"no required binaries\" or \"no required env vars\", treat it as stale metadata and fix before publishing.\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Bundled Script Review Checklist (Before First Use)\n\nThe skill ships executable JavaScript at `scripts/nextcloud.js`. Review before running in new environments:\n\n1. Confirm runtime requirements:\n   - `node --version` (must be `20+`)\n2. Check obvious outbound endpoints:\n   - `rg -n \"https?://\" scripts/nextcloud.js`\n3. Check sensitive capability usage:\n   - `rg -n \"child_process|spawn\\\\(|exec\\\\(|require\\\\(\\\"fs\\\"\\\\)|require\\\\('fs'\\\\)|fs\\\\.\" scripts/nextcloud.js`\n4. Verify credentials are env-driven only:\n   - `rg -n \"NEXTCLOUD_URL|NEXTCLOUD_USER|NEXTCLOUD_TOKEN|NEXTCLOUD_TIMEZONE\" scripts/nextcloud.js`\n5. Run in low-risk mode first:\n   - Use a dedicated low-privilege Nextcloud app password\n   - Test against non-production data when possible\n\nIf review confidence is low, do not run until code is reviewed by a trusted maintainer.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files\n- `files list [--path <path>]`\n- `files search --query <query>`\n- `files get --path <path>`\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules (Quick Reference)\n\nApply these on every write to prevent corruption and confusion:\n\n1) Identity and naming\n- Never infer `UID` from URL; always use payload `uid`.\n- Use `fullName` and `structuredName` for user-facing names; keep `nameRaw` diagnostic-only.\n\n2) Contact and birthday integrity\n- Birthday input formats: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons to `BDAY`.\n- Birthdays are contact fields: use `contacts create/edit --birthday ...`; never edit birthday-derived calendar entries directly.\n\n3) Intent-preserving updates\n- Modify only fields explicitly requested by the user.\n- To clear a value, pass explicit empty values.\n- Respect explicit `--addressbook`; otherwise use remembered default or ask once.\n\n4) Calendar and task validation\n- Validate date/datetime inputs before sending; require `end > start` for timed events.\n- Escape ICS text fields (`SUMMARY`, `DESCRIPTION`).\n- Validate task priority range (`0..9`).\n- For timezone-less timed input, use `--timezone` or `NEXTCLOUD_TIMEZONE`.\n- For all-day events, use `VALUE=DATE` semantics with exclusive `DTEND`.\n\n5) Capability and safety checks\n- Do not assume listed event calendars are writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explain event mutation is unavailable until writable access exists.\n- Some calendars are multi-component (`VEVENT` + `VTODO`); keep them eligible for both event/task flows.\n\n6) Files and post-write verification\n- Require non-empty file paths for `files upload/get/delete`.\n- Escape XML filter/search values for CardDAV/WebDAV operations.\n- After mutations (`create`, `edit`, `complete`, `delete`), verify with follow-up read/list when practical.\n- For propagation delay, retry around `0.5s`, `1s`, `2s` before declaring failure.\n\n## Known Nextcloud/CardDAV Behaviors\n\n- Servers/clients may negotiate or normalize vCard versions (`3.0` vs `4.0`) and content on write/read.\n- `FN` and `N` should each appear once in valid contacts.\n- `BDAY` failures are often malformed input (for example stray delimiters), not server instability.\n- Folded vCard lines must be unfolded before parsing.\n\n## Error to Action Map (Fast)\n\n- `HTTP 403` on `calendar create/edit/delete` -> likely read-only/system calendar or missing permission; switch to writable events calendar.\n- `HTTP 501` on `files search` -> WebDAV `SEARCH` unsupported; fallback to recursive `PROPFIND` + client-side filter.\n- `HTTP 415` on task/event update -> malformed ICS payload; normalize formatting and retry once.\n- Contact write succeeded but UI still stale -> run verification retry cycle before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior Playbooks (Condensed)\n\nThese playbooks are execution shortcuts. Reliability and safety rules above still apply.\n\n### Contacts and Birthdays\n1. Resolve address book (`--addressbook` or remembered default).\n2. For create/edit, pass only user-requested fields; use explicit empty values when user wants fields cleared.\n3. Use `--name` for full-name input; use structured-name flags for split-name input.\n4. Pass multiple emails/phones as CSV values.\n5. Birthday changes always go through contacts (`contacts create/edit --birthday ...`), never calendar mutation commands.\n6. Verify birthday/name-sensitive writes with `contacts get --uid ...` when confidence is important.\n\n### Tasks\n1. Resolve task calendar when omitted.\n2. Validate due and priority (`0..9`) before write.\n3. After create/edit/complete/delete, verify via focused list/get when practical.\n\n### Calendar Events\n1. Resolve writable events calendar; treat `Contact birthdays` and system calendars as read-only.\n2. Validate `start`/`end` and require `end > start` for timed events.\n3. For timezone-less date-times, pass `--timezone` or use `NEXTCLOUD_TIMEZONE`.\n4. For all-day intent, use `--all-day` with date values (not timed midnight ranges).\n5. Re-list in a focused window after mutation when confidence is important.\n\nAll-day end-date normalization behavior:\n- `start=YYYY-MM-DD`, `end=YYYY-MM-DD` -> inclusive single-day input, normalized.\n- `start=YYYY-MM-DD`, `end=next-day` -> already-exclusive single-day input.\n- Multi-day inclusive ranges -> normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. Use deterministic test paths for temporary validation files.\n3. Read back uploaded content and then delete test files.\n4. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\nUse least-privilege credentials for tests and monitor outbound traffic; the process should only communicate with `NEXTCLOUD_URL`.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Persistent Rules (Store These)\n\nPersist these high-value rules in memory/rules:\n\n1. Birthdays are contact fields: use `contacts create/edit --birthday ...`; never mutate `Contact birthdays` directly.\n2. For all-day events, always use `calendar create/edit --all-day` with date values (avoid timed midnight ranges).\n3. For timezone-less timed values, use `--timezone` or `NEXTCLOUD_TIMEZONE`; ask if timezone is unknown.\n4. Prefer writable user calendars for event mutations; if `403`, report likely read-only/permission issue.\n5. Verify event/contact writes with a focused read/list before declaring final success.\n6. Keep canonical all-day encoding (`VALUE=DATE`); avoid duplicate compatibility events unless explicitly requested.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.0.9:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.0.9\",\n  \"publishedAt\": 1772724132232\n}\n\nArchive v1.0.8: 3 files, 85635 bytes\n\nFiles: scripts/nextcloud.js (679402b), SKILL.md (13542b), _meta.json (135b)\n\nFile v1.0.8:SKILL.md\n\n---\nname: nextcloud-aio-oc (NextCloud AIO OpenClaw)\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nallowed-tools: Bash Read\n---\n\n# NextCloud AIO OpenClaw Skill\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: predictable, loss-resistant Nextcloud reads/writes, especially for Contacts.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files\n- `files list [--path <path>]`\n- `files search --query <query>`\n- `files get --path <path>`\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules (Quick Reference)\n\nApply these on every write to prevent corruption and confusion:\n\n1) Identity and naming\n- Never infer `UID` from URL; always use payload `uid`.\n- Use `fullName` and `structuredName` for user-facing names; keep `nameRaw` diagnostic-only.\n\n2) Contact and birthday integrity\n- Birthday input formats: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons to `BDAY`.\n- Birthdays are contact fields: use `contacts create/edit --birthday ...`; never edit birthday-derived calendar entries directly.\n\n3) Intent-preserving updates\n- Modify only fields explicitly requested by the user.\n- To clear a value, pass explicit empty values.\n- Respect explicit `--addressbook`; otherwise use remembered default or ask once.\n\n4) Calendar and task validation\n- Validate date/datetime inputs before sending; require `end > start` for timed events.\n- Escape ICS text fields (`SUMMARY`, `DESCRIPTION`).\n- Validate task priority range (`0..9`).\n- For timezone-less timed input, use `--timezone` or `NEXTCLOUD_TIMEZONE`.\n- For all-day events, use `VALUE=DATE` semantics with exclusive `DTEND`.\n\n5) Capability and safety checks\n- Do not assume listed event calendars are writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explain event mutation is unavailable until writable access exists.\n- Some calendars are multi-component (`VEVENT` + `VTODO`); keep them eligible for both event/task flows.\n\n6) Files and post-write verification\n- Require non-empty file paths for `files upload/get/delete`.\n- Escape XML filter/search values for CardDAV/WebDAV operations.\n- After mutations (`create`, `edit`, `complete`, `delete`), verify with follow-up read/list when practical.\n- For propagation delay, retry around `0.5s`, `1s`, `2s` before declaring failure.\n\n## Known Nextcloud/CardDAV Behaviors\n\n- Servers/clients may negotiate or normalize vCard versions (`3.0` vs `4.0`) and content on write/read.\n- `FN` and `N` should each appear once in valid contacts.\n- `BDAY` failures are often malformed input (for example stray delimiters), not server instability.\n- Folded vCard lines must be unfolded before parsing.\n\n## Error to Action Map (Fast)\n\n- `HTTP 403` on `calendar create/edit/delete` -> likely read-only/system calendar or missing permission; switch to writable events calendar.\n- `HTTP 501` on `files search` -> WebDAV `SEARCH` unsupported; fallback to recursive `PROPFIND` + client-side filter.\n- `HTTP 415` on task/event update -> malformed ICS payload; normalize formatting and retry once.\n- Contact write succeeded but UI still stale -> run verification retry cycle before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior Playbooks (Condensed)\n\nThese playbooks are execution shortcuts. Reliability and safety rules above still apply.\n\n### Contacts and Birthdays\n1. Resolve address book (`--addressbook` or remembered default).\n2. For create/edit, pass only user-requested fields; use explicit empty values when user wants fields cleared.\n3. Use `--name` for full-name input; use structured-name flags for split-name input.\n4. Pass multiple emails/phones as CSV values.\n5. Birthday changes always go through contacts (`contacts create/edit --birthday ...`), never calendar mutation commands.\n6. Verify birthday/name-sensitive writes with `contacts get --uid ...` when confidence is important.\n\n### Tasks\n1. Resolve task calendar when omitted.\n2. Validate due and priority (`0..9`) before write.\n3. After create/edit/complete/delete, verify via focused list/get when practical.\n\n### Calendar Events\n1. Resolve writable events calendar; treat `Contact birthdays` and system calendars as read-only.\n2. Validate `start`/`end` and require `end > start` for timed events.\n3. For timezone-less date-times, pass `--timezone` or use `NEXTCLOUD_TIMEZONE`.\n4. For all-day intent, use `--all-day` with date values (not timed midnight ranges).\n5. Re-list in a focused window after mutation when confidence is important.\n\nAll-day end-date normalization behavior:\n- `start=YYYY-MM-DD`, `end=YYYY-MM-DD` -> inclusive single-day input, normalized.\n- `start=YYYY-MM-DD`, `end=next-day` -> already-exclusive single-day input.\n- Multi-day inclusive ranges -> normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. Use deterministic test paths for temporary validation files.\n3. Read back uploaded content and then delete test files.\n4. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Persistent Rules (Store These)\n\nPersist these high-value rules in memory/rules:\n\n1. Birthdays are contact fields: use `contacts create/edit --birthday ...`; never mutate `Contact birthdays` directly.\n2. For all-day events, always use `calendar create/edit --all-day` with date values (avoid timed midnight ranges).\n3. For timezone-less timed values, use `--timezone` or `NEXTCLOUD_TIMEZONE`; ask if timezone is unknown.\n4. Prefer writable user calendars for event mutations; if `403`, report likely read-only/permission issue.\n5. Verify event/contact writes with a focused read/list before declaring final success.\n6. Keep canonical all-day encoding (`VALUE=DATE`); avoid duplicate compatibility events unless explicitly requested.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.0.8:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.0.8\",\n  \"publishedAt\": 1772722470526\n}\n\nArchive v1.0.7: 3 files, 87028 bytes\n\nFiles: scripts/nextcloud.js (679402b), SKILL.md (17419b), _meta.json (135b)\n\nFile v1.0.7:SKILL.md\n\n---\nname: openclaw-nextcloud\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nallowed-tools: Bash Read\n---\n\n# OpenClaw Nextcloud Skill (Refactored for Reliability)\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: predictable, loss-resistant Nextcloud reads/writes, especially for Contacts.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files\n- `files list [--path <path>]`\n- `files search --query <query>`\n- `files get --path <path>`\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules for OpenClaw\n\nFollow these rules every time to avoid data corruption or user confusion:\n\n1) Do not infer `UID` from URL  \n- Always use `uid` from payload; URL is an implementation detail.\n\n2) Do not display or store raw structured-name strings as user-facing names  \n- Raw `N` values contain semicolon-separated vCard structure.\n- Prefer `fullName` and `structuredName`.\n\n3) Birthday format hygiene  \n- Valid input only: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons.\n- Use date-only values by default.\n\n4) Preserve user intent on updates  \n- Update only fields requested by the user.\n- If user asks to clear a field, pass an explicit empty value.\n\n5) Address book scoping  \n- If user specifies address book, pass `--addressbook`.\n- If not specified, use remembered default or ask once and store preference.\n\n6) CardDAV query safety  \n- Escape values used in XML filters (`UID`, search query).\n\n7) CalDAV safety and validation\n- Validate task/event date inputs before sending.\n- Ensure event end is after event start.\n- Escape iCalendar text fields (`SUMMARY`, `DESCRIPTION`) to avoid malformed ICS lines.\n- Validate task priority range (`0..9`).\n- For timezone-less date/time inputs, interpret in `NEXTCLOUD_TIMEZONE` (or explicit `--timezone`) before converting to UTC.\n- For all-day events, use date semantics (`VALUE=DATE`) with an exclusive `DTEND` (next day for a single-day event).\n\n8) Files safety\n- Require non-empty file paths for upload/get/delete.\n- Escape WebDAV SEARCH query values used in XML.\n\n9) Calendar capability awareness\n- Do not assume every listed events calendar is writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explicitly say event create/edit/delete is unavailable until the user creates or grants write access to an events calendar.\n- Some calendars support both `VEVENT` and `VTODO` (multi-component). Do not exclude these from either events or tasks flows.\n\n10) Command routing for birthdays\n- For a person birthday field: use `contacts create/edit --birthday ...`.\n- For generic calendar events (meetings/reminders): use `calendar create/edit`.\n- Never try to create/edit/delete birthday-derived entries inside `Contact birthdays`.\n\n11) Post-write verification policy\n- After mutating data (`create`, `edit`, `complete`, `delete`), verify with a follow-up read/list when practical.\n- For eventual-consistency/UI-delay cases, retry verification at short intervals: ~`0.5s`, `1s`, `2s`.\n- If write succeeded but first read does not reflect change yet, report as \"write accepted, propagation pending\" and retry before declaring failure.\n\n## Known Nextcloud/CardDAV Pitfalls (Research-Based)\n\n- Many clients default to vCard 3.0 unless they explicitly request 4.0 via `Accept`/`address-data` version negotiation.\n- Nextcloud/Sabre setups may transform or normalize cards at write/read time.\n- `BDAY` validation errors are often malformed input issues (for example trailing delimiters), not server instability.\n- `FN` and `N` must appear exactly once each in valid contact cards; duplicates can fail import/update paths.\n- Folded vCard lines must be unfolded correctly before parsing.\n\n## Error to Action Map\n\nUse this map to choose the next action quickly:\n\n- `HTTP 403` during `calendar create/edit/delete`\n  - Probable cause: read-only/system calendar (often `Contact birthdays`) or missing permissions.\n  - Action: select writable events calendar or ask user to create/grant one.\n\n- `HTTP 501` during `files search`\n  - Probable cause: WebDAV `SEARCH` not implemented by server/proxy stack.\n  - Action: use fallback strategy (recursive PROPFIND + client-side filtering).\n\n- `HTTP 415` during task/event update\n  - Probable cause: malformed ICS payload or line/encoding issue.\n  - Action: normalize calendar payload formatting and retry once.\n\n- Contact mutation says success but birthday/name does not appear immediately in UI\n  - Probable cause: delayed sync/index/UI propagation.\n  - Action: run post-write verification retry sequence before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior: Contact Operations\n\n### Create contact workflow\n1. Resolve address book (`--addressbook` or default).\n2. Resolve name fields:\n   - If user gives full name, pass `--name`.\n   - If user gives split name parts, pass structured name flags.\n3. Pass emails/phones as comma-separated lists when multiple values exist.\n4. For birthdays, validate format before command call.\n5. After create, run `contacts get --uid <uid> --addressbook <name>` for verification when confidence is critical.\n\n### Edit contact workflow\n1. Fetch contact first (`contacts get`) when operation is complex.\n2. Pass only fields user asked to change.\n3. For clearing fields, pass empty values explicitly.\n4. Re-read contact after edit if user asks for confirmation or if birthday/name was changed.\n\n### Birthday workflow (strict)\n1. If user asks to add/change/remove a person birthday, always operate on the contact record (`contacts edit --birthday ...`).\n2. Do not use calendar commands for birthday edits.\n3. Explain that `Contact birthdays` is generated from contact birthday fields and is read-only.\n4. After updating birthday, verify with `contacts get --uid ...`.\n\n## Agent Behavior: Tasks, Calendar, Files, Notes\n\n### Tasks\n1. Confirm target task calendar if user did not specify one.\n2. Validate due date and priority before command execution.\n3. After create/edit/complete, read task list or the specific task context to confirm result.\n\n### Calendar Events\n1. Validate `start` and `end` are valid ISO-like values.\n2. Require `end > start`.\n3. Prefer writable user calendars for event creation (avoid birthday/system calendars when auto-selecting).\n4. If selected/implicit calendar is read-only, stop and explain the limitation clearly.\n5. Re-list events in a focused time window after create/edit/delete when confidence is needed.\n6. If only read-only calendars exist (for example only `Contact birthdays`), report that event create/edit/delete cannot be executed without a writable calendar.\n7. If user gives timezone-less values (for example `2026-03-02T10:00:00`), use `--timezone` or `NEXTCLOUD_TIMEZONE` to avoid UTC drift.\n8. For all-day events, pass `--all-day`; provide date values and avoid midnight-to-23:59 timed ranges when possible.\n9. All-day end-date autofix is enabled:\n   - `start=YYYY-MM-DD`, `end=YYYY-MM-DD` is treated as inclusive single-day input and normalized.\n   - `start=YYYY-MM-DD`, `end=next-day` is treated as already-exclusive single-day input.\n   - Multi-day inclusive ranges are normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. Use deterministic test paths for temporary validation files.\n3. Read back uploaded content and then delete test files.\n4. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Decision Matrix (Use This Exactly)\n\n- User asks \"set birthday for contact X\" -> `contacts edit --birthday ...`\n- User asks \"show upcoming birthdays\" -> `calendar list` (read-only listing is fine)\n- User asks \"create meeting/reminder\" -> `calendar create` on writable events calendar\n- User asks \"fix birthday event entry directly\" -> explain birthday entries are generated from contacts and redirect to contact update flow\n- User gives local time without timezone -> use `--timezone <IANA>` (or rely on `NEXTCLOUD_TIMEZONE`) before creating/updating task/event\n- User asks for \"all day\" event -> use `calendar create/edit ... --all-day` with date values\n- User asks \"send me details/address of appointment today\" -> run appointment briefing workflow using `calendar list` and return a concise plain-text message\n\n## Permanent OpenClaw Instructions (Store These)\n\nPersist these rules in OpenClaw memory/rules exactly:\n\n1. For all-day events, always call `calendar create/edit` with `--all-day` and date values (`YYYY-MM-DD` preferred).\n2. Never represent all-day events as timed ranges (`00:00` to `23:59` or `00:00` to next midnight).\n3. If user gives an all-day-like timed range, convert to `--all-day` flow before command execution.\n4. If all-day input uses date values and `end` is next-day, treat that as already-exclusive for single-day intent.\n5. For timed events, require timezone-aware input (`Z` or offset) OR pass `--timezone` explicitly.\n6. Default timezone for timezone-less timed input is `NEXTCLOUD_TIMEZONE`; if missing, ask user to confirm timezone before writing.\n7. Treat `Contact birthdays` as read-only; birthdays are edited via `contacts edit --birthday ...`.\n8. Prefer writable user calendars (e.g., `Main Calendar`, `Personal`) for event mutations.\n9. After any event create/edit/delete, perform verification (`calendar list` in a focused window) before declaring success.\n10. If server returns `403` on event mutation, report likely read-only/permission issue and ask for writable calendar.\n11. If event behavior is ambiguous on DST boundaries, still keep canonical all-day encoding (`VALUE=DATE`) and do not create duplicate compatibility events unless user explicitly requests that workaround.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.0.7:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.0.7\",\n  \"publishedAt\": 1772719522659\n}\n\nArchive v1.0.6: 3 files, 87028 bytes\n\nFiles: scripts/nextcloud.js (679402b), SKILL.md (17419b), _meta.json (135b)\n\nFile v1.0.6:SKILL.md\n\n---\nname: openclaw-nextcloud\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nallowed-tools: Bash Read\n---\n\n# OpenClaw Nextcloud Skill (Refactored for Reliability)\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: predictable, loss-resistant Nextcloud reads/writes, especially for Contacts.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Run\n\n```bash\nnode scripts/nextcloud.js <command> <subcommand> [options]\n```\n\n## Commands\n\n### Notes\n- `notes list`\n- `notes get --id <id>`\n- `notes create --title <title> --content <content> [--category <category>]`\n- `notes edit --id <id> [--title <title>] [--content <content>] [--category <category>]`\n- `notes delete --id <id>`\n\n### Tasks\n- `tasks list [--calendar <calendar-name>]`\n- `tasks create --title <title> [--calendar <calendar-name>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks edit --uid <uid> [--calendar <calendar-name>] [--title <title>] [--due <iso>] [--priority <0-9>] [--description <text>] [--timezone <IANA>]`\n- `tasks delete --uid <uid> [--calendar <calendar-name>]`\n- `tasks complete --uid <uid> [--calendar <calendar-name>]`\n\n### Calendar Events\n- `calendar list [--from <iso>] [--to <iso>]` (default: next 7 days)\n- `calendar create --summary <summary> --start <iso-or-date> --end <iso-or-date> [--calendar <calendar-name>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar edit --uid <uid> [--calendar <calendar-name>] [--summary <summary>] [--start <iso-or-date>] [--end <iso-or-date>] [--description <text>] [--timezone <IANA>] [--all-day]`\n- `calendar delete --uid <uid> [--calendar <calendar-name>]`\n\nImportant:\n- In many setups, `Contact birthdays` appears as an events calendar but is read-only.\n- Birthdays must be managed through `contacts create/edit --birthday ...`, not through `calendar create/edit`.\n- `calendar list` returns event `summary`, `start`, `end`, and may include `location` and `description` when present.\n\n### Calendar Discovery\n- `calendars list [--type <tasks|events>]`\n\n### Files\n- `files list [--path <path>]`\n- `files search --query <query>`\n- `files get --path <path>`\n- `files upload --path <path> --content <content>`\n- `files delete --path <path>`\n\n### Contacts\n- `contacts list [--addressbook <name>]`\n- `contacts get --uid <uid> [--addressbook <name>]`\n- `contacts search --query <query> [--addressbook <name>]`\n- `contacts create [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--addressbook <name>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts edit --uid <uid> [--addressbook <name>] [--name <full-name>] [--first-name <given>] [--last-name <family>] [--middle-name <middle>] [--prefix <prefix>] [--suffix <suffix>] [--email <single>] [--emails <csv>] [--phone <single>] [--phones <csv>] [--organization <org>] [--title <title>] [--note <note>] [--birthday <YYYY-MM-DD|YYYYMMDD|--MM-DD|--MMDD>]`\n- `contacts delete --uid <uid> [--addressbook <name>]`\n\n### Address Book Discovery\n- `addressbooks list`\n\n## Contact Data Contract (Important)\n\nUse `fullName` and `structuredName` as canonical name fields.\n\nContact output includes:\n- `uid`\n- `addressBook`\n- `fullName`\n- `structuredName` with:\n  - `familyName`\n  - `givenName`\n  - `additionalNames`\n  - `honorificPrefixes`\n  - `honorificSuffixes`\n- `nameRaw` (raw `N` value for diagnostics only; do not display to users by default)\n- `emails` array or `null`\n- `phones` array or `null`\n- `organization`, `title`, `note`\n- `birthday` normalized for readability (`YYYY-MM-DD` or `--MM-DD` when possible)\n- `birthdayRaw` (raw CardDAV value)\n\n## Reliability Rules for OpenClaw\n\nFollow these rules every time to avoid data corruption or user confusion:\n\n1) Do not infer `UID` from URL  \n- Always use `uid` from payload; URL is an implementation detail.\n\n2) Do not display or store raw structured-name strings as user-facing names  \n- Raw `N` values contain semicolon-separated vCard structure.\n- Prefer `fullName` and `structuredName`.\n\n3) Birthday format hygiene  \n- Valid input only: `YYYY-MM-DD`, `YYYYMMDD`, `--MM-DD`, `--MMDD`.\n- Never add trailing semicolons.\n- Use date-only values by default.\n\n4) Preserve user intent on updates  \n- Update only fields requested by the user.\n- If user asks to clear a field, pass an explicit empty value.\n\n5) Address book scoping  \n- If user specifies address book, pass `--addressbook`.\n- If not specified, use remembered default or ask once and store preference.\n\n6) CardDAV query safety  \n- Escape values used in XML filters (`UID`, search query).\n\n7) CalDAV safety and validation\n- Validate task/event date inputs before sending.\n- Ensure event end is after event start.\n- Escape iCalendar text fields (`SUMMARY`, `DESCRIPTION`) to avoid malformed ICS lines.\n- Validate task priority range (`0..9`).\n- For timezone-less date/time inputs, interpret in `NEXTCLOUD_TIMEZONE` (or explicit `--timezone`) before converting to UTC.\n- For all-day events, use date semantics (`VALUE=DATE`) with an exclusive `DTEND` (next day for a single-day event).\n\n8) Files safety\n- Require non-empty file paths for upload/get/delete.\n- Escape WebDAV SEARCH query values used in XML.\n\n9) Calendar capability awareness\n- Do not assume every listed events calendar is writable.\n- Treat `Contact birthdays` as read-only/system calendar.\n- If no writable event calendar exists, explicitly say event create/edit/delete is unavailable until the user creates or grants write access to an events calendar.\n- Some calendars support both `VEVENT` and `VTODO` (multi-component). Do not exclude these from either events or tasks flows.\n\n10) Command routing for birthdays\n- For a person birthday field: use `contacts create/edit --birthday ...`.\n- For generic calendar events (meetings/reminders): use `calendar create/edit`.\n- Never try to create/edit/delete birthday-derived entries inside `Contact birthdays`.\n\n11) Post-write verification policy\n- After mutating data (`create`, `edit`, `complete`, `delete`), verify with a follow-up read/list when practical.\n- For eventual-consistency/UI-delay cases, retry verification at short intervals: ~`0.5s`, `1s`, `2s`.\n- If write succeeded but first read does not reflect change yet, report as \"write accepted, propagation pending\" and retry before declaring failure.\n\n## Known Nextcloud/CardDAV Pitfalls (Research-Based)\n\n- Many clients default to vCard 3.0 unless they explicitly request 4.0 via `Accept`/`address-data` version negotiation.\n- Nextcloud/Sabre setups may transform or normalize cards at write/read time.\n- `BDAY` validation errors are often malformed input issues (for example trailing delimiters), not server instability.\n- `FN` and `N` must appear exactly once each in valid contact cards; duplicates can fail import/update paths.\n- Folded vCard lines must be unfolded correctly before parsing.\n\n## Error to Action Map\n\nUse this map to choose the next action quickly:\n\n- `HTTP 403` during `calendar create/edit/delete`\n  - Probable cause: read-only/system calendar (often `Contact birthdays`) or missing permissions.\n  - Action: select writable events calendar or ask user to create/grant one.\n\n- `HTTP 501` during `files search`\n  - Probable cause: WebDAV `SEARCH` not implemented by server/proxy stack.\n  - Action: use fallback strategy (recursive PROPFIND + client-side filtering).\n\n- `HTTP 415` during task/event update\n  - Probable cause: malformed ICS payload or line/encoding issue.\n  - Action: normalize calendar payload formatting and retry once.\n\n- Contact mutation says success but birthday/name does not appear immediately in UI\n  - Probable cause: delayed sync/index/UI propagation.\n  - Action: run post-write verification retry sequence before reporting failure.\n\n## Agent Behavior: Default Calendar Selection\n\nWhen user creates tasks/events without explicit calendar:\n1. Run `calendars list --type tasks` or `calendars list --type events`.\n2. For `events`, filter out likely read-only calendars first (`Contact birthdays`, `Holidays`, names containing `read only` or `readonly`).\n3. If at least one writable calendar remains, ask for selection.\n4. Ask whether to remember as default.\n5. Store in memory.\n6. If no writable events calendar remains, explain why event mutation is unavailable and suggest creating a writable calendar in Nextcloud Calendar.\n\nMemory keys:\n- `default_task_calendar`\n- `default_event_calendar`\n\n## Agent Behavior: Default Address Book Selection\n\nWhen user creates contacts without explicit address book:\n1. Run `addressbooks list`.\n2. Ask for selection.\n3. Ask whether to remember default.\n4. Store in memory.\n\nMemory key:\n- `default_addressbook`\n\n## Agent Behavior: Contact Operations\n\n### Create contact workflow\n1. Resolve address book (`--addressbook` or default).\n2. Resolve name fields:\n   - If user gives full name, pass `--name`.\n   - If user gives split name parts, pass structured name flags.\n3. Pass emails/phones as comma-separated lists when multiple values exist.\n4. For birthdays, validate format before command call.\n5. After create, run `contacts get --uid <uid> --addressbook <name>` for verification when confidence is critical.\n\n### Edit contact workflow\n1. Fetch contact first (`contacts get`) when operation is complex.\n2. Pass only fields user asked to change.\n3. For clearing fields, pass empty values explicitly.\n4. Re-read contact after edit if user asks for confirmation or if birthday/name was changed.\n\n### Birthday workflow (strict)\n1. If user asks to add/change/remove a person birthday, always operate on the contact record (`contacts edit --birthday ...`).\n2. Do not use calendar commands for birthday edits.\n3. Explain that `Contact birthdays` is generated from contact birthday fields and is read-only.\n4. After updating birthday, verify with `contacts get --uid ...`.\n\n## Agent Behavior: Tasks, Calendar, Files, Notes\n\n### Tasks\n1. Confirm target task calendar if user did not specify one.\n2. Validate due date and priority before command execution.\n3. After create/edit/complete, read task list or the specific task context to confirm result.\n\n### Calendar Events\n1. Validate `start` and `end` are valid ISO-like values.\n2. Require `end > start`.\n3. Prefer writable user calendars for event creation (avoid birthday/system calendars when auto-selecting).\n4. If selected/implicit calendar is read-only, stop and explain the limitation clearly.\n5. Re-list events in a focused time window after create/edit/delete when confidence is needed.\n6. If only read-only calendars exist (for example only `Contact birthdays`), report that event create/edit/delete cannot be executed without a writable calendar.\n7. If user gives timezone-less values (for example `2026-03-02T10:00:00`), use `--timezone` or `NEXTCLOUD_TIMEZONE` to avoid UTC drift.\n8. For all-day events, pass `--all-day`; provide date values and avoid midnight-to-23:59 timed ranges when possible.\n9. All-day end-date autofix is enabled:\n   - `start=YYYY-MM-DD`, `end=YYYY-MM-DD` is treated as inclusive single-day input and normalized.\n   - `start=YYYY-MM-DD`, `end=next-day` is treated as already-exclusive single-day input.\n   - Multi-day inclusive ranges are normalized to canonical exclusive `DTEND`.\n\n### Appointment briefing workflow (high priority intent)\nUse this when user asks for appointment details, address, or \"what is my appointment today\":\n1. Determine \"today\" in `NEXTCLOUD_TIMEZONE` (or ask if timezone is unclear).\n2. Run `calendar list --from <start-of-day-iso> --to <end-of-day-iso>`.\n3. Filter events by user terms (for example `dermatology`, `doctor`, provider name).\n4. For the selected event, include `summary`, time window, `location`, and key lines from `description`.\n5. If multiple events match, ask a quick disambiguation question.\n6. If none match, clearly say none found for today and offer to check tomorrow or full week.\n7. Provide a plain-text message suitable for SMS/chat (short lines, no markdown).\n\n### Files\n1. Require explicit file path for mutating operations.\n2. Use deterministic test paths for temporary validation files.\n3. Read back uploaded content and then delete test files.\n4. On large instances, prefer narrower path-based listing before broad search to reduce load.\n\n### Notes\n1. Create with explicit title/content.\n2. Read back by id after create/edit.\n3. Delete temporary test notes after verification.\n\n## Internal Smoke Test Protocol\n\nWhen validating this skill in a live environment:\n1. Contacts: create -> get -> edit -> get -> optional delete.\n2. Notes: create -> get -> edit -> get -> delete.\n3. Files: upload -> get -> search/list -> delete.\n4. Tasks: create -> list/locate -> edit -> complete -> delete.\n5. Calendar: create -> list/locate -> edit -> delete.\n\nUse a unique timestamped suffix on all test data and clean up all temporary artifacts unless the user requests keeping them.\n\nCalendar exception handling:\n- If no writable event calendar exists, mark calendar mutation tests as intentionally skipped (environment limitation), and still run `calendar list`.\n- Do not treat this as a skill failure; treat it as a server capability/permission constraint.\n\n## Decision Matrix (Use This Exactly)\n\n- User asks \"set birthday for contact X\" -> `contacts edit --birthday ...`\n- User asks \"show upcoming birthdays\" -> `calendar list` (read-only listing is fine)\n- User asks \"create meeting/reminder\" -> `calendar create` on writable events calendar\n- User asks \"fix birthday event entry directly\" -> explain birthday entries are generated from contacts and redirect to contact update flow\n- User gives local time without timezone -> use `--timezone <IANA>` (or rely on `NEXTCLOUD_TIMEZONE`) before creating/updating task/event\n- User asks for \"all day\" event -> use `calendar create/edit ... --all-day` with date values\n- User asks \"send me details/address of appointment today\" -> run appointment briefing workflow using `calendar list` and return a concise plain-text message\n\n## Permanent OpenClaw Instructions (Store These)\n\nPersist these rules in OpenClaw memory/rules exactly:\n\n1. For all-day events, always call `calendar create/edit` with `--all-day` and date values (`YYYY-MM-DD` preferred).\n2. Never represent all-day events as timed ranges (`00:00` to `23:59` or `00:00` to next midnight).\n3. If user gives an all-day-like timed range, convert to `--all-day` flow before command execution.\n4. If all-day input uses date values and `end` is next-day, treat that as already-exclusive for single-day intent.\n5. For timed events, require timezone-aware input (`Z` or offset) OR pass `--timezone` explicitly.\n6. Default timezone for timezone-less timed input is `NEXTCLOUD_TIMEZONE`; if missing, ask user to confirm timezone before writing.\n7. Treat `Contact birthdays` as read-only; birthdays are edited via `contacts edit --birthday ...`.\n8. Prefer writable user calendars (e.g., `Main Calendar`, `Personal`) for event mutations.\n9. After any event create/edit/delete, perform verification (`calendar list` in a focused window) before declaring success.\n10. If server returns `403` on event mutation, report likely read-only/permission issue and ask for writable calendar.\n11. If event behavior is ambiguous on DST boundaries, still keep canonical all-day encoding (`VALUE=DATE`) and do not create duplicate compatibility events unless user explicitly requests that workaround.\n\n## Troubleshooting Playbook\n\n- Birthday was updated but not visible in Nextcloud UI yet:\n  - Run `contacts get --uid ...` immediately.\n  - If value is correct in API, advise short wait + UI refresh.\n  - Re-check after retry intervals before escalating.\n\n- `contacts get` and `contacts search` disagree briefly:\n  - Prefer retry cycle and then trust latest consistent result.\n  - Do not create duplicate contact entries while waiting.\n\n- Event creation keeps failing:\n  - Run `calendars list --type events` and verify at least one writable non-system calendar exists.\n  - If only birthday/system calendars exist, explain limitation and stop mutation attempts.\n\n## Output Envelope\n\nAll commands return JSON:\n\nSuccess:\n```json\n{\n  \"status\": \"success\",\n  \"data\": {}\n}\n```\n\nError:\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}\n```\n\nFile v1.0.6:_meta.json\n\n{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.0.6\",\n  \"publishedAt\": 1772719219019\n}","readmeExcerpt":"Skill: NextCloud AIO OpenClaw Owner: juicyroots Summary: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update). Tags: latest:1.1.2 Version history: v1.1.2 | 2026-03-10T17:51:22.890Z | user Added ability to handle binary documents v1.1.1 | 2026-03-05T15:34:31.475Z | user Internal changes for ambiguity and validation v1.1.0 | 2026-","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"node scripts/nextcloud.js <command> <subcommand> [options]"},{"language":"bash","snippet":"python3 scripts/files_binary.py download <nc_path> <local_path>\npython3 scripts/files_binary.py upload   <local_path> <nc_path>\npython3 scripts/files_binary.py exists   <nc_path>\npython3 scripts/files_binary.py list     [<nc_path>]"},{"language":"json","snippet":"{\n  \"status\": \"success\",\n  \"data\": {}\n}"},{"language":"json","snippet":"{\n  \"status\": \"error\",\n  \"message\": \"Error description\"\n}"},{"language":"bash","snippet":"node scripts/nextcloud.js <command> <subcommand> [options]"},{"language":"json","snippet":"{\n  \"status\": \"success\",\n  \"data\": {}\n}"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: nextcloud-aio-oc (NextCloud AIO OpenClaw)\ndescription: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\nlicense: MIT\ncompatibility: Requires Node.js 20+. Needs network access to Nextcloud instance.\nrequired-binaries:\n  - node>=20\nrequired-env-vars:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptional-env-vars:\n  - NEXTCLOUD_TIMEZONE\nrequiredBinaries:\n  - node\nrequiredEnv:\n  - NEXTCLOUD_URL\n  - NEXTCLOUD_USER\n  - NEXTCLOUD_TOKEN\noptionalEnv:\n  - NEXTCLOUD_TIMEZONE\nprimaryEnv: NEXTCLOUD_TOKEN\nallowed-tools: Bash Read\n---\n\n# NextCloud AIO OpenClaw Skill\n\nThis skill connects OpenClaw to Nextcloud for:\n- Notes API\n- CalDAV Tasks and Events\n- WebDAV Files\n- CardDAV Contacts\n\nPrimary goal: Predictable, loss-resistant Nextcloud reads/writes.\n\nThis skill is validated against:\n- Nextcloud Hub 25 Autumn (`32.0.6`)\n- OpenClaw (`2026.3.2`)\n\n## Required Configuration\n\nSet these environment variables:\n- `NEXTCLOUD_URL` (example: `https://cloud.example.com`)\n- `NEXTCLOUD_USER`\n- `NEXTCLOUD_TOKEN` (App Password strongly preferred)\n- `NEXTCLOUD_TIMEZONE` (recommended, IANA timezone like `America/Los_Angeles`; used for timezone-less date/time inputs)\n\n## Runtime and Metadata Contract\n\nThis section is the source of truth for registry metadata parity.\n\n- Required binary: `node` (Node.js `20+`)\n- Required environment variables: `NEXTCLOUD_URL`, `NEXTCLOUD_USER`, `NEXTCLOUD_TOKEN`\n- Optional environment variable: `NEXTCLOUD_TIMEZONE`\n- Required network target: the host defined by `NEXTCLOUD_URL` (plus normal redirects from that host)\n\nIf a registry entry says \"no required binaries\" or \"no required env vars\", treat it as stale metadata and fix before publishing.\n\n## Preflight Audit Gate\n\nBefore first execution in any new environment:\n\n- Complete the bundled script review checklist below.\n- Confirm no unexpected endpoints or privileged system calls are present.\n- If checks are incomplete, do not run the skill.\n- Prefer sandbox/container validation and least-privilege app credentials first.\n\n## Security and Publish Safety\n\n- Never hardcode credentials in `SKILL.md`, scripts, examples, commit messages, or changelog text.\n- Store secrets only in environment variables or local secret stores.\n- Use dedicated app passwords for integrations; rotate if leaked or shared.\n- Keep local `.env` files out of git (see `.gitignore`).\n- Before publishing, run a quick scan for obvious secrets and remove any accidental values.\n\n## Bundled Script Review Checklist (Before First Use)\n\nThe skill ships two scripts: `scripts/nextcloud.js` (Node.js, text operations) and `scripts/files_binary.py` (Python 3, binary file transfers). Review both before running in new environments:\n\n1. Confirm runtime requirements:\n   - `node --version` (must be `20+`)\n2. Check obvious outbound endpoints:\n   - `rg -n \"https?://\" scripts/nextcloud.js`\n3. Check sensitive capability usage:\n   - `rg -n \"ch"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn79ykv1rxnxrwtxg7vekk61d182brn2\",\n  \"slug\": \"nextcloud-aio-oc\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1773165082890\n}"},{"path":"skill-card.md","content":"## Description:\n\nReliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update).\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[juicyroots](https://clawhub.ai/user/juicyroots)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to manage Nextcloud notes, tasks, calendar events, files, and contacts through OpenClaw. It is intended for environments where a configured Nextcloud account can safely support remote reads, writes, uploads, and deletes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill handles Nextcloud credentials that may grant access to private account data.\n\nMitigation: Use a dedicated, revocable, least-privilege Nextcloud app password and keep credentials in environment variables or a local secret store.\n\nRisk: Remote upload and delete commands can modify or remove account data, including unintended paths if requests are not reviewed.\n\nMitigation: Test on non-production data first, use explicit reviewed paths, review commands before execution, and verify mutations with follow-up reads where practical.\n\nRisk: Unencrypted or redirected Nextcloud endpoints can expose credentials or data.\n\nMitigation: Configure an HTTPS-only NEXTCLOUD_URL and avoid untrusted redirects.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/juicyroots/skills/nextcloud-aio-oc)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with shell command examples and JSON command results]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires Node.js 20+, NEXTCLOUD_URL, NEXTCLOUD_USER, and NEXTCLOUD_TOKEN; binary file transfers use the Python helper.]\n\n## Skill Version(s):\n\n1.1.2 (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."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update). Skill: NextCloud AIO OpenClaw Owner: juicyroots Summary: Reliable Nextcloud integration for Notes, Tasks, Calendar, Files, and Contacts (CardDAV-safe vCard handling with robust contact create/update). Tags: latest:1.1.2 Version history: v1.1.2 | 2026-03-10T17:51:22.890Z | user Added ability to handle binary documents v1.1.1 | 2026-03-05T15:34:31.475Z | user Internal changes for ambiguity and validation v1.1.0 | 2026-","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1114,"uniquenessScore":51,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T19:55:53.921Z","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-11T19:55:53.921Z","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-12T09:05:33.297Z","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"}]}}}