Skill: clinchcc/notesctl-skill-for-openclaw (version 0.1.0)

--- name: notesctl description: Manage Apple Notes via deterministic local scripts (create, append, list, search, export, and edit). Use when a user asks OpenClaw to add a note, list notes, search notes, or manage note folders. metadata: { "openclaw": { "emoji": "📝", "os": ["darwin"], "requires": { "bins": ["memo", "python3", "osascript"] } } } --- # notesctl (Apple Notes, low-token) ## Goal Minimize token usage and avoid fragile quoting by routing Apple Notes operations through bundled scripts. ## Quick start ### Create a new note (deterministic title/body) - JSON stdin (recommended): ```bash echo '{"title":"Title","body":"Line 1\nLine 2","folder":"Notes"}' | {baseDir}/scripts/notes_post.sh ``` - Direct args: ```bash {baseDir}/scripts/notes_new.sh "Title" $'Body line 1\nBody line 2' "Notes" ``` ### List/search/export ```bash {baseDir}/scripts/notes_list.sh "Notes" {baseDir}/scripts/notes_search.sh "query" "Notes" {baseDir}/scripts/notes_export.sh "query" "Notes" "/tmp" # interactive select then export ``` ## Output conventions - Keep receipts short: `Wrote to Notes: <title>`. ## Notes on editing Editing existing notes is inherently more fragile: - Prefer append workflows or create a new note with a reference. - If the user explicitly wants interactive editing, use `memo notes -e` (manual selection + editor).

path: README.md
content: # notesctl (Apple Notes skill)

A small, deterministic Apple Notes helper skill for OpenClaw.

It wraps Apple Notes operations in scripts so the agent can reliably create/search/export notes without fragile quoting or UI automation.

Why: this was built to replace the original OpenClaw Apple Notes skill, which can occasionally create a note titled "New Notes" and can be token-expensive; notesctl keeps the system logic deterministic and minimizes LLM usage (ideally a single call to produce the final output).

## Requirements (macOS)

- `python3`
- `osascript`
- `memo` (CLI used by the scripts)

## What’s inside

- `SKILL.md` — the skill metadata + concise operating instructions
- `scripts/`
  - `notes_new.sh` — create a new note with title/body/folder
  - `notes_post.sh` — create a new note via JSON stdin (recommended for automation)
  - `notes_list.sh` — list notes in a folder
  - `notes_search.sh` — search notes (optionally within a folder)
  - `notes_export.sh` — interactively select a matching note and export it to a directory

## Usage

### 1) Create a new note (recommended: JSON stdin)

```bash
baseDir=/path/to/notesctl

echo '{"title":"标题","body":"第一行\n第二行","folder":"Notes"}' \
  | "$baseDir/scripts/notes_post.sh"
```

### 2) Create a new note (direct args)

```bash
baseDir=/path/to/notesctl

"$baseDir/scripts/notes_new.sh" \
  "标题" \
  $'正文第一行\n正文第二行' \
  "Notes"
```

### 3) List notes in a folder

```bash
baseDir=/path/to/notesctl

"$baseDir/scripts/notes_list.sh" "Notes"
```

### 4) Search notes

```bash
baseDir=/path/to/notesctl

# search all folders
"$baseDir/scripts/notes_search.sh" "keyword"

# search within a specific folder
"$baseDir/scripts/notes_search.sh" "keyword" "Notes"
```

### 5) Export a note

This is interactive: it searches, then prompts you to choose which note to export.

```bash
baseDir=/path/to/notesctl

"$baseDir/scripts/notes_export.sh" "keyword" "Notes" "/tmp"
```

## Notes / gotchas

- Editing existing notes is intentionally not the default workflow (fragile). Prefer append workflows or creating a new note.
- If you do need manual editing, use `memo notes -e` (interactive selection + editor).

## License

Internal / personal use (adjust as needed).


path: scripts/notes_list.sh
content: #!/usr/bin/env bash
set -euo pipefail

# List notes in a folder (default: Notes)
FOLDER="${1:-Notes}"

memo notes -f "$FOLDER"

path: scripts/notes_search.sh
content: #!/usr/bin/env bash
set -euo pipefail

# Search notes (fuzzy) optionally within a folder.
QUERY="${1:-}"
FOLDER="${2:-}"

if [[ -z "$QUERY" ]]; then
  echo "Usage: notes_search.sh <query> [folder]" >&2
  exit 1
fi

if [[ -n "$FOLDER" ]]; then
  memo notes -f "$FOLDER" -s "$QUERY"
else
  memo notes -s "$QUERY"
fi

path: scripts/notes_post.sh
content: #!/usr/bin/env bash
set -euo pipefail

# Read a JSON payload from stdin and create a new Apple Note.
# JSON schema:
#   {"title":"...","body":"...","folder":"Notes"}
# Usage:
#   echo '{"title":"T","body":"Line1\nLine2","folder":"Notes"}' | scripts/notes_post.sh

payload="$(cat)"

export NOTES_PAYLOAD="$payload"

# Extract fields (title required)
TITLE=$(python3 - <<'PY'
import json, os
obj=json.loads(os.environ.get('NOTES_PAYLOAD','') or '{}')
print(obj.get('title',''))
PY
)

if [[ -z "$TITLE" ]]; then
  echo "ERROR: title is required in JSON stdin" >&2
  exit 1
fi

BODY=$(python3 - <<'PY'
import json, os
obj=json.loads(os.environ.get('NOTES_PAYLOAD','') or '{}')
print(obj.get('body',''))
PY
)

FOLDER=$(python3 - <<'PY'
import json, os
obj=json.loads(os.environ.get('NOTES_PAYLOAD','') or '{}')
print(obj.get('folder','Notes'))
PY
)

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
"$SCRIPT_DIR/notes_new.sh" "$TITLE" "$BODY" "$FOLDER" >/dev/null

echo "OK: wrote note -> $FOLDER / $TITLE"

path: scripts/notes_new.sh
content: #!/usr/bin/env bash
set -euo pipefail

# Create a new Apple Note with explicit title/body (stable; avoids "New Note" placeholder).
# Usage:
#   notes_new.sh "TITLE" "BODY" [FOLDER]
# Example:
#   notes_new.sh "My title" $'Line1\nLine2' "Notes"

TITLE="${1:-}"
BODY="${2:-}"
FOLDER="${3:-Notes}"

if [[ -z "$TITLE" ]]; then
  echo "ERROR: TITLE is required" >&2
  exit 1
fi

# Notes body is HTML-ish: escape + convert newlines to <br>
export TITLE BODY
BODY_HTML=$(python3 - <<'PY'
import html, os
s = os.environ.get('BODY','')
print(html.escape(s).replace('\n','<br>'))
PY
)

# Escape for AppleScript string literal
export BODY_HTML
BODY_AS=$(python3 - <<'PY'
import os
s=os.environ['BODY_HTML']
print(s.replace('\\','\\\\').replace('"','\\"'))
PY
)

TITLE_AS=$(python3 - <<'PY'
import os
s=os.environ['TITLE']
print(s.replace('\\','\\\\').replace('"','\\"'))
PY
)

osascript -e "tell application \"Notes\" to make new note at folder \"$FOLDER\" with properties {name:\"$TITLE_AS\", body:\"$BODY_AS\"}"

path: scripts/notes_export.sh
content: #!/usr/bin/env bash
set -euo pipefail

# Export a note via memo (interactive selection).
# Usage: notes_export.sh [query] [folder] [outdir]
QUERY="${1:-}"
FOLDER="${2:-Notes}"
OUTDIR="${3:-.}"

mkdir -p "$OUTDIR"

if [[ -n "$QUERY" ]]; then
  # Narrow down list first; export remains interactive in memo.
  memo notes -f "$FOLDER" -s "$QUERY"
fi

# memo will prompt for which note to export
(cd "$OUTDIR" && memo notes -f "$FOLDER" -ex)

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)