Install
openclaw skills install @durenzidu/powpow-simple-viĐăng bài viết và bút ký du lịch lên PowPow (global.powpow.online), đồng thời tạo Người số (digital human) biết trò chuyện và ghim lên bản đồ công khai. Kích hoạt khi người dùng muốn đưa nội dung du lịch (ảnh, bút ký, kỷ niệm chuyến đi) lên PowPow, ví dụ “đăng một bài lên PowPow”“đăng ảnh chuyến đi này lên PowPow”“publish a PowPow post”“发一篇 PowPow 帖子”, hoặc khi muốn tạo và công khai Người số lên bản đồ, ví dụ “tạo một Người số”“công khai Người số”. Cần tài khoản PowPow (chưa có thì đăng ký trước). Các năng lực hỗ trợ (đều thuộc luồng đăng/tạo nêu trên) gồm đăng nhập và quản lý phiên, tự kiểm môi trường chạy, phân giải tên địa điểm thành tọa độ, tìm kiếm và ghép chủ đề Người số, tìm kiếm và tải ảnh, dựng và đăng bài, xác minh sau khi đăng, xóa bài do chính mình đăng (chỉ dọn bài kiểm thử, JWT giới hạn ở bài của bản thân). Không gồm đăng lên mạng xã hội khác, không gồm gói đăng ký hay quảng bá tiếp thị.
openclaw skills install @durenzidu/powpow-simple-viBiến ảnh hay tư liệu của bạn thành một bút ký du lịch rồi đăng lên PowPow nhân danh bạn; hoặc biến một người/nhân vật thành Người số (digital human) biết trò chuyện, ghim lên bản đồ công khai.
Phiên bản 1.0.0 · 20-09-2026 (lịch sử phiên bản xem references/changelog.md; kiến trúc bảo mật và danh sách API xem references/security.md; cấu trúc tệp xem references/file-structure.md; ảnh chụp màn hình sản phẩm xem references/screenshots.md)
Quy tắc ngôn ngữ (quy tắc cứng): Cuộc trò chuyện luôn dùng ngôn ngữ của người dùng. Tài liệu này viết bằng tiếng Việt, nhưng kỹ năng phục vụ người dùng ở mọi ngôn ngữ — câu hỏi, lựa chọn, giải thích và nội dung bài viết đều bám theo ngôn ngữ của người dùng. Kỹ năng cũng nhận diện câu kích hoạt bằng tiếng Anh và tiếng Trung.
Đây là kỹ năng kiểu chỉ thị: SKILL.md mô tả luồng, còn scripts/*.js là các script Node thuần (chỉ dùng fetch/fs nội bộ, không phụ thuộc bên thứ ba).
fetch toàn cục). Kiểm tra trước đã: node -vscripts/ của thư mục kỹ năng này. Trước khi chạy hãy chuyển về thư mục gốc của kỹ năng, ví dụ:
cd <thư-mục-kỹ-năng> && node scripts/doctor.jsPOWPOW_STATE_DIR (mặc định ~/.powpow/session.json). Thư mục kỹ năng có thể chỉ đọc, nên tuyệt đối không ghi tệp nào vào thư mục kỹ năng. Muốn đổi vị trí, người dùng đặt biến môi trường này.--image; đường dẫn tương đối sẽ thất bại.Đa số người dùng chưa từng thấy PowPow. Một bức ảnh thuyết phục hơn mọi lời — khi cần, gửi thẳng liên kết ảnh chụp màn hình cho người dùng (dạng ảnh Markdown hoặc liên kết trần đều được). Danh sách, mô tả và thời điểm dùng xem references/screenshots.md; ánh xạ nhanh:
Quy tắc:
screenshots/ của kho công khai durenzidu/durenzidu (powpow-0N.jpg); không tải ảnh vào thư mục kỹ năng, cũng không gửi đường dẫn cục bộ như thể đó là ảnh.raw.githubusercontent.com không mở được, dùng liên kết dự phòng qua jsdelivr (xem references/screenshots.md).references/screenshots.md.Kỹ năng kích hoạt khi người dùng muốn đăng nội dung du lịch (bút ký/ảnh/chuyến đi) lên PowPow, hoặc muốn tạo Người số đặt lên bản đồ. Các cách nói điển hình:
Quy tắc đồng xuất hiện (chống kích hoạt nhầm): Chỉ nhắc đến du lịch/ảnh/bút ký là chưa đủ — người dùng còn phải bộc lộ ý định đăng (đăng/đưa lên/post/publish) hoặc gọi tên nền tảng (PowPow/powpow). 「Bức ảnh này đẹp thật」 thì không kích hoạt; 「gửi ảnh này lên PowPow」 thì có. Không kích hoạt với mạng xã hội nói chung hay nền tảng khác.
Đa số người dùng chưa từng đăng gì qua trợ lý trò chuyện. Chạy script đúng mới là nửa việc — mỗi lượt phải để người dùng biết vừa xảy ra chuyện gì, tôi cần họ làm gì, bước tiếp theo là gì.
Đây là sản phẩm dành cho người dùng phổ thông; ta đang phục vụ người dùng, không phải hướng dẫn họ. Nhẹ nhàng và tôn trọng, nhất quán từ đầu đến cuối.
| Không nói thế này (thuyết giảng, trên xuống) | Nói thế này (phục vụ, kề vai, mời gọi) |
|---|---|
| Để tôi nói rõ một chuyện trước…… | Có một chút muốn chia sẻ với bạn trước khi bắt đầu…… |
| Nhắc bạn một câu…… / Tôi buộc phải nhắc bạn…… | Có một chỗ muốn nhờ bạn xác nhận giúp |
| Hai điều này tôi không thể đoán, bạn phải nói rõ | Thời gian và địa điểm trong ảnh tôi không xem được, mong bạn kể giúp hai điều đó |
| Tôi không quyết thay bạn / Bạn cần biết điều này | Việc này tôi ngại quyết thay bạn — nó sẽ được viết vào bài, chọn lệch là mất tự nhiên ngay |
| Tọa độ có cần bạn lo không? Không | Tọa độ để tôi lo, bạn chỉ cần chọn đúng tên địa điểm |
Luôn luôn:
Cấm cụ thể: không thuyết giảng; không báo trước 「tôi phải nhắc bạn」; không đánh giá lựa chọn của người dùng; không dùng 「tôi buộc phải」; không giải thích cơ chế nội bộ, giới hạn hay thiết kế bảo mật khi người dùng chưa hỏi.
Cách gọi trung lập (quy tắc cứng): Không bao giờ nhắc tên nhà cung cấp bản đồ cụ thể với người dùng. Khi cần nói đến, diễn đạt bằng hành động — 「tôi tra giúp bạn địa điểm」, 「bản đồ tìm được vài nơi trùng tên, bạn chọn một chỗ nhé」, và đừng dùng lối nói "cơ sở dữ liệu bản đồ". Đường dẫn API là endpoint của chính nền tảng, không thuộc phạm vi hạn chế này.
Khi kích hoạt lần đầu (doctor báo không có phiên, hoặc người dùng hỏi kỹ năng làm được gì), hãy mở đầu bằng một đoạn ngắn (~120 từ, đừng chất chức năng lên nhau), phân nhánh theo ý định người dùng, rồi mới hỏi câu đầu tiên:
Mẫu (dùng để khởi đầu, tinh chỉnh theo ngôn ngữ của người dùng, đừng đọc y như mẫu):
Rất hân hạnh được phục vụ bạn — chào mừng đến với thế giới PowPow. Ở đây, bạn có thể biến những tấm ảnh chụp vội hôm nay thành một bút ký du lịch, và tôi sẽ viết nó cho bạn, ghim lên bản đồ, đăng lên PowPow hộ bạn — ai đó mở bản đồ ra là thấy con đường bạn đã đi trong ngày hôm ấy. 〔Phần 2: thành phẩm trông thế nào — viên nang, ảnh, lối chơi bong bóng bản đồ (dùng câu thoại chuẩn bên trên)〕 〔Phần 3: cần gì — đăng nhập một lần; nếu có thể chưa có tài khoản thì kèm liên kết đăng ký + video giới thiệu〕 〔Phần 4: nhịp 3 phách, đăng nhập là bước đầu〕 Sẵn sàng chưa? Đưa cho tôi thứ bạn muốn đăng hôm nay, chúng ta bắt đầu từ bước đầu tiên.
Trong tin nhắn dài, người dùng bị rơi mất trọng tâm — không phải vì nội dung sai, mà vì hành động bị chìm. Vì vậy khối cuối cùng của mọi câu trả lời phải là khối 「Bước tiếp theo」 cố định: tách bằng đường phân cách, đánh dấu bằng mũi tên, để người dùng nhìn một cái là biết việc cần làm ngay.
Định dạng cố định:
────────────────────
👉 Việc cần bạn lúc này: trả lời 1 / 2 / 3, chọn một địa điểm
(chọn xong tôi ra bản nháp, lượt sau bạn sẽ thấy bản xem trước kèm viên nang)
Ba quy tắc cứng:
Kết quả đăng bài cũng tuân theo nguyên tắc này (xem Bước 8): liên kết và vị trí đặt ở cuối toàn bộ câu trả lời, sát điểm dừng của ánh mắt.
fetch toàn cục).node scripts/doctor.js
printf '%s' '<password>' | node scripts/login.js <username>
printf): có thể chạy
node scripts/login.js <username>
POWPOW_STATE_DIR, mặc định ~/.powpow/session.json), không nằm trong thư mục kỹ năng.pending_payment — tài khoản tồn tại nhưng chưa hoàn tất kích hoạt trên nền tảng. Dừng lại, đừng thử lại, cứ nói: 「Tài khoản của bạn chưa hoàn tất kích hoạt nên tạm chưa đăng được. Bạn mở PowPow, đăng nhập rồi làm theo hướng dẫn trên trang để hoàn tất kích hoạt; xong báo tôi một tiếng, chúng ta làm tiếp.」 Đây không phải lỗi tạm thời cũng không phải lỗi đăng nhập — đừng bắt người dùng nhập lại thông tin, cũng đừng tiếp tục gom tư liệu.config.json (đi kèm chỉ giá trị mặc định, không chứa khóa; chỉ đọc):
{
"platformUrl": "https://global.powpow.online",
"unsplashAccessKey": "",
"sessionMaxAgeDays": 6
}
unsplashAccessKey là tùy chọn, người dùng tự điền; không có thì bỏ qua tìm ảnh (bài không ảnh vẫn được hỗ trợ đầy đủ), hoặc người dùng đưa liên kết trực tiếp.
Ghi đè cấu hình dưới OpenClaw: đừng sửa config.json trong gói kỹ năng (có thể chỉ đọc). Đặt một tệp config.json cùng tên vào thư mục trạng thái (POWPOW_STATE_DIR, mặc định ~/.powpow/config.json), giá trị của nó sẽ đè lên mặc định trong gói. Hoặc đặt biến môi trường UNSPLASH_ACCESS_KEY.
Quy ước thực thi (OpenClaw): mọi lệnh
node scripts/...dưới đây mặc định thư mục hiện hành là thư mục gốc của kỹ năng. Không chắc thì chạy bằng đường dẫn tuyệt đối —node <thư-mục-kỹ-năng>/scripts/xxx.js. Tệp tạm (nháp, xem trước, manifest) ghi vào thư mục làm việc, đừng ghi vào thư mục kỹ năng.
Luồng chủ lực: người dùng gửi ảnh, bạn viết quanh ảnh một bút ký du lịch ngôi thứ nhất.
Các kiểu đầu vào khác đều nhận: Mode A người dùng giao bản hoàn chỉnh — bỏ qua khâu tạo; Mode C đầu vào một phần — bạn đắp tiếp. Mọi trường hợp, địa điểm và thời gian đều đến từ người dùng, không đến từ việc đọc ảnh.
Liệt kê/đề xuất các Người số khỏe mạnh:
node scripts/match-digital-human.js "<topic>" --limit 3 --json # gợi ý đã xếp hạng
node scripts/list-digital-humans.js "<name>" --json # tìm theo tên
Bộ lọc sức khỏe tích hợp: tự động loại Người số bị vô hiệu, tên dạng kiểm thử, avatar hỏng, avatar mờ. Trình bày các kết quả khớp tốt nhất kèm mô tả để người dùng chọn (người dùng bảo "bạn quyết đi" thì chọn tự động). Nếu Người số người dùng muốn không tồn tại, đưa trang tạo: https://global.powpow.online Ghi chú: thư viện Người số của nền tảng hiện tập trung ở tiếng Trung; tìm bằng chủ đề tiếng Trung cho kết quả tốt nhất.
Địa điểm được khuyến nghị mạnh, nhưng là tùy chọn. Nó quyết định bài có lên bản đồ công khai hay không (lối chơi cốt lõi).
node scripts/geocode.js "潮白河大桥" --limit 5 # thêm --city 北京 để thu hẹp
--loc <name> --lng <x> --lat <y>.--city <thành phố> (quận, địa danh, tên đường).--limit (ví dụ 10), mỗi ứng viên kèm quận + địa chỉ nhà, để người dùng nhận ra cái đúng.isLocationExposed: false). Người dùng giữ được chữ, Người số, ảnh; chỉ mất viên bong bóng trên bản đồ. Nói thẳng đây là kết quả, không phải thất bại.
Bắt người dùng thường đưa kinh vĩ tuyến không bao giờ là hạ cấp chính đáng: họ không có cách lấy, mà lấy được thì đa số cũng là GCJ-02, ghim lệch cả trăm mét — thành lỗi dữ kiện thấy được trong bài ngôi thứ nhất. Tọa độ là kênh cho người sành: chỉ dùng khi người dùng chủ động đưa.isLocationExposed: false). Tuyệt đối không gây áp lực, tuyệt đối không chặn việc đăng — đó là lựa chọn của họ.locationName, lng, lat).Địa điểm đã đưa chắc chắn lên bản đồ công khai (isLocationExposed: true) — quy tắc nội bộ, không cung cấp tùy chọn "ẩn khỏi bản đồ" cho người dùng. Bài đăng tham gia vòng đời bong bóng trên bản đồ (nhạt dần theo thời gian), là lối chơi dự kiến.
Định dạng thành phần địa điểm:
<span data-type="location" data-lng="116.316" data-lat="39.979" name="中关村">
<span class="location-name">中关村</span>
</span>
Ba cách gắn ảnh:
--image @<đường-dẫn-cục-bộ>. Lúc compose không gửi gì lên server — tệp được ghi vào <out>.manifest.json, xem trước cục bộ bằng file://. Tải lên chỉ diễn ra khi publish.js đăng bài (POST /api/upload/post-image; JPEG/PNG/WebP/GIF/BMP/HEIC, không nhận SVG, mỗi tệp ≤10MB, server tự nén). Sửa nháp không bao giờ đụng server, không sinh tệp mồ côi.unsplash.com/photos/..., hay copy từ trình duyệt) — tự phân giải thành liên kết trực tiếp images.unsplash.com. Liên kết dạng ID tệp (unsplash.com/photos/1507513319174-...) phân giải được cục bộ không cần khóa; dạng slug/ID ngắn cần Unsplash API key (hệ thống chống bot của trang chặn việc lấy khi không có khóa). Gặp dạng slug mà không có khóa thì bỏ qua và báo — nhờ người dùng đưa liên kết trực tiếp; tuyệt đối không nhúng liên kết trang làm ảnh (sẽ vỡ hình).--image search:<từ khóa tiếng Anh> (hoặc node scripts/search-image.js "<keywords>")Không có giới hạn cứng về số ảnh. Nền tảng giới hạn 50000 ký tự (mỗi thẻ ảnh ≈100 ký tự); tới gần 200 ảnh thì nhắc người dùng. Về hiển thị: lưới feed hiện 9 ảnh đầu +「+N」; trình xem toàn màn hình hiện hết.
Thành phần tương tác (Người số/địa điểm) được frontend web dựng từ HTML giàu trong content. Viết suông <span data-type="digital-human">Marie Curie</span> chỉ ra chữ thường — duy nhất span mang đúng cấu trúc chính xác của trình soạn thảo tiptap (class Tailwind, thẻ <img> avatar bên trong, biểu tượng chim ghim, .location-name) mới hiện thành viên nang bấm được.
Bắt buộc: luôn dựng HTML bài đăng bằng scripts/compose.js. Tuyệt đối không tự tay viết span thành phần, tuyệt đối không tự viết code dán nối vòng qua html-formatter.js.
# 1. Lưu nội dung bài vào tệp. Đoạn văn ngăn cách bằng dòng trống.
# Placeholder (đều tùy chọn; dùng sai bất kỳ dạng nào là lỗi cứng, tuyệt đối không tự sửa lặng lẽ):
# {{dh}} hoặc {{数字人}} -> viên nang Người số (cần --dh)
# {{loc}} hoặc {{位置}} -> viên nang địa điểm (cần --loc)
# {{img}} hoặc {{图}} -> đoạn ảnh; phải đứng thành đoạn riêng, tiêu thụ --image theo thứ tự
# (mỗi placeholder cần một --image sẵn, thiếu là compose hỏng)
# Ghi chú: bả danh tiếng Trung bên trên là token nguyên văn script nhận diện —
# dùng dạng nào cũng được, đừng bịa token mới.
# Placeholder lạ/thừa/đặt sai chỗ làm compose.js thoát với mã 1 và không ghi gì.
# Sửa tệp chữ rồi chạy lại — tuyệt đối không xóa chữ cho xuôi.
# 2. Dựng bằng một lệnh (toàn bộ cục bộ, không cần mạng):
node scripts/compose.js --text-file post.txt \
--dh name:岳飞 \ # hoặc --dh <id>, hoặc --dh auto --topic "..."
--loc dh \ # hoặc --loc <name> --lng 116.3 --lat 39.9
--image @./photos/west-lake.jpg \ # tệp cục bộ (tải lên lúc đăng); hoặc <liên-kết-trực-tiếp>, hoặc search:<từ khóa>
--out post-draft.html
Quy tắc cứng của compose.js:
--dh/--loc mà chữ không có placeholder thì viên nang tự chèn trước đoạn đầu / sau đoạn cuối.powpow-local://N + post-draft.html.manifest.json; publish.js tải lên lúc đăng.post-draft.html.preview.html — bản xem trước tiếng Trung, người dùng mở bằng trình duyệt. Nó có banner nói rõ bài có lên bản đồ công khai hay không, lên thì ghim ở đâu — để hậu quả bản đồ lộ ngay trên trang người dùng thật sự đọc (bản đồ cục bộ dựng bằng file://). Nội dung banner kể lại bằng ngôn ngữ của người dùng.publish.js chạy lại validateEditorFormat() và từ chối mọi thứ khác.contentItems — frontend khi có contentItems sẽ ưu tiên dựng kiểu cấu trúc, danh sách thiếu làm mất nội dung chữ. publish.js đã xử lý.<img> đầu làm ảnh thu nhỏ cho thẻ bài.Trình bày bốn mục chi tiết dưới đây trước, rồi kết lượt bằng khối 「Bước tiếp theo」 có hành động duy nhất là quyết định đăng (đăng / sửa nữa / để sau):
<out>.preview.html) — bản xem trước tiếng Trung, banner cũng nói bài có lên bản đồ công khai hay không. Kèm một câu: đây là bản gần đúng, không phải bản sao từng điểm ảnh.Quyết định phải là khối cuối, tuyệt đối không chôn sau phần chi tiết. (Vì sao nghiêm đến vậy: trong thử nghiệm, người dùng đọc đúng những nội dung này và đáp 「rồi sao nữa?」 — thông tin đầy đủ cả, nhưng hành động không rơi vào điểm dừng của ánh mắt.)
Vòng lặp sửa nháp: người dùng muốn sửa thì sửa, chạy lại compose.js — toàn cục bộ, tùy số vòng, không đụng server, không tải lên mồ côi. Không giới hạn số lần; chỉ kết thúc khi người dùng nói rõ đăng/publish/xác nhận. Trước thời điểm đó tuyệt đối không đăng.
node scripts/publish.js <đường-dẫn-tệp-html>
Nháp có ảnh cục bộ thì đúng khoảnh khắc này mới tải lên — từng tệp, trước khi đăng bài. Tiến trình được lưu sau mỗi lần thành công (HTML + manifest viết lại URL thật), nên chạy lại sau lỗi không phải tải lại phần đã xong.
Bài được tạo với tư cách người dùng đang đăng nhập — danh tính đến từ JWT, không có cửa mượn danh người khác. Server thực thi kiểm duyệt nội dung và giới hạn tần suất. Gặp 429, script tự tuân thủ Retry-After.
node scripts/verify.js <post-id>
Kiểm tra khả năng truy cập, tác giả, thành phần Người số/địa điểm, số ảnh, số ký tự. Báo theo đúng thứ tự — chi tiết trước, kết quả sau cùng:
────────────────────
✅ Bài đã được đăng
📍 Vị trí bài: Di tích Hành cung Yên Kiều (116.816667, 39.95)
👉 Mở liên kết kiểm tra giúp nhé: hai viên nang bấm được không, thứ tự ảnh đúng chưa
(dòng lệnh kiểm tra không ra chuyện này, mắt bạn mới là ải cuối)
🔗 https://global.powpow.online/posts/<post-id>
Không có địa điểm thì nói cùng khối: 「📍 Không kèm địa điểm — bài sẽ không xuất hiện trên bản đồ công khai」.
Kết xuất tương tác (bấm viên nang, khung xem ảnh) CLI kiểm tra không được — mắt người dùng là ải cuối.
Dọn bài kiểm thử:
node scripts/delete-post.js <post-id>
Một luồng độc lập với đăng bài: biến một người (nhân vật lịch sử, nhân vật hư cấu, avatar của chính người dùng…) thành Người số biết trò chuyện, ghim lên bản đồ công khai. Kích hoạt: 「tạo một Người số」「biến người này thành Người số đặt lên bản đồ」「công khai Người số」.
Chi phí — xác nhận trước khi chạy, đúng như quyết định đăng:
Thu thập từ người dùng:
--avatar-ref). Nền tảng tạo avatar từ thiết lập nhân vật + ảnh tham chiếu (8~30 giây). Ảnh tham chiếu cục bộ cũng được — tải lên /api/upload/post-image trước, rồi đưa URL công khai đó vào --avatar-ref.--avatar @<path>): dùng thẳng ảnh của người dùng.--avatar <url>): URL ảnh trực tiếp.node scripts/create-digital-human.js \
--name 史铁生 \
--desc-file persona.txt \ # hoặc --desc "..."
--avatar-ref https://...jpg \ # hoặc --avatar @./photo.jpg, hoặc --avatar <url>
--lng 116.408195 --lat 39.952372 # từ kết quả phân giải người dùng chọn
Sau khi tạo, báo lại ID Người số, địa điểm, ngày hết hạn (30 ngày) và số dư huy hiệu, kèm liên kết bản đồ: https://global.powpow.online/map . Người dùng lập tức có thể @ Người số trong bài (compose.js --dh <id>); Người số cũng thành ứng viên liên quan của match-digital-human.js.
Tra Người số sẵn có: node scripts/list-digital-humans.js --search "<name>".
Quy tắc cứng: không bao giờ ném nguyên văn script, lệnh node, mã lỗi (như DEVICE_MISMATCH) vào mặt người dùng; mọi lỗi phải dịch thành một câu người + hành động kế tiếp.
login.js, thử lại một lần. Mọi thứ đã làm vẫn còn nguyên: nháp, tư liệu, Người số và địa điểm đã chọn đều nằm trên máy — nối tiếp từ chỗ đó, tuyệt đối không chạy lại các bước trước.printf '%s' '<password>' | node scripts/login.js <username>. Tuyệt đối không dùng dạng vị trí (login.js <user> <password>): đọng trong lịch sử shell và danh sách tiến trình. Không echo, không ghi đĩa, không để biến shell. login.js vẫn nhận dạng vị trí vì tương thích — đó không phải giấy phép cho bạn dùng. Xin thông tin đăng nhập phải bằng một tin nhắn giản dị, không kèm thuyết giảng an toàn (xem UX hội thoại → Giọng điệu).--text-file/--image người dùng chỉ đích danh, hoặc tệp bạn tự tạo trong thư mục làm việc hiện hành. Tuyệt đối không quét máy, không đoán đường dẫn — đường dẫn sai sẽ phát tán tệp riêng tư.