ปัญหาเริ่มจากเรื่องเล็ก ๆ ทุกวันนี้เรากด ⌘+Space เปิด Spotlight เพื่อเปิดแอปกับหาไฟล์อยู่แล้ว มันทำสองอย่างนั้นได้ดี แต่พองานในแต่ละวันเริ่มมีของที่ต้องทำซ้ำ ๆ อย่างการเปิดหน้าจอเช็คสถานะบางอย่าง หรือสลับโหมดบางโหมดก่อนเริ่มประชุม Spotlight ช่วยอะไรไม่ได้เลย เพราะมันรู้จักแค่แอปกับไฟล์ ไม่รู้จักงาน
ช่วงที่ 1Raycast คืออะไร กันแน่
Raycast เกิดมาแก้ปัญหานี้ตรง ๆ หน้าตามันคือช่องค้นหาเหมือน Spotlight เปิดแอปได้ หาไฟล์ได้เหมือนเดิม แต่มันเปิดให้เราต่อคำสั่งของเราเองเข้าไปได้ด้วย พูดง่าย ๆ คือ Spotlight ตอบคำถามว่า "อยากเปิดอะไร" ส่วน Raycast ตอบคำถามว่า "อยากสั่งอะไร" ซึ่งกว้างกว่ากันมาก
คำอธิบายที่เจอบ่อยที่สุดเวลาค้นคำว่า raycast คือ อะไร คือมันเป็น launcher หรือ "ตัวเปิดโปรแกรมแบบเร็ว" ซึ่งไม่ผิด แต่บอกไม่ครบ เพราะฟีเจอร์เปิดแอปเป็นแค่ประตูแรกที่ทุกคนเจอตอนติดตั้งใหม่ ๆ ของจริงเริ่มตอนที่เรารู้ว่ามันเปิดให้ผูกสคริปต์ของเราเองเข้าไปในช่องค้นหานั้นได้ ตอนนั้นแหละที่มันเปลี่ยนจาก "Spotlight ที่สวยกว่า" ไปเป็นเครื่องมือที่ทำงานแทนเราได้จริง
บทความนี้เข้าซีรีส์ "คืออะไร" ของเราเอง ต่อจากที่เคยเล่าเรื่อง daemon และ AI agent มาก่อน แนวทางเดียวกันคือ เริ่มจากปัญหาที่จับต้องได้ ไม่ใช่จากฟีเจอร์ลิสต์ยาว ๆ ของตัวโปรแกรม
ช่วงที่ 2ประยุกต์ยังไง จากง่ายไปยาก
ระดับที่ 1: เปิดแอปกับหาไฟล์ (ทุกคนใช้ได้ทันที)
จุดเริ่มต้นเหมือน Spotlight แต่เร็วกว่าและพิมพ์ตกก็ยังหาเจอ พิมพ์บางส่วนของชื่อแอปหรือไฟล์ก็ขึ้นมาให้เลือก ไม่มีอะไรต้องตั้งค่าเพิ่ม แค่ติดตั้งแล้วกด hotkey แทน Spotlight เดิมได้เลย
ระดับที่ 2: คลิปบอร์ดฮิสตอรี
Raycast จำสิ่งที่เรา copy ไว้ย้อนหลังได้หลายรายการ ไม่ใช่แค่อันล่าสุดแบบคลิปบอร์ดปกติของ Mac เวลา copy เลขพัสดุไว้ตอนเช้า แล้วบ่ายมา copy อย่างอื่นทับ ของเดิมก็ยังค้นย้อนกลับมาแปะได้ ไม่ต้องสลับไปเปิดที่เก็บเดิมใหม่
ข้อแลกเปลี่ยนที่ต้องรู้ตั้งแต่วันแรก คือของทุกอย่างที่เคย copy จะถูกเก็บไว้และค้นหาได้ เพราะฉะนั้นรหัสผ่าน เลขบัตร หรือ token ที่เคย copy ผ่านมือไปจะไปนอนอยู่ในนั้นด้วย ตั้งเวลาลบอัตโนมัติในค่าตั้งได้ และของอ่อนไหวจริง ๆ ควรผ่านที่เก็บรหัสผ่านแทนการ copy ทิ้งไว้
ระดับที่ 3: snippet
พิมพ์ตัวย่อสั้น ๆ แล้วให้มันขยายเป็นข้อความยาวให้เอง เหมาะกับของที่พิมพ์ซ้ำทุกวันแบบคำต่อคำ เช่น ลายเซ็นอีเมล ที่อยู่จัดส่ง หรือประโยคตอบลูกค้าที่ใช้บ่อย ตั้งครั้งเดียว ใช้ได้ทุกแอปที่พิมพ์ข้อความได้
ระดับที่ 4: script command (เขียนเชลล์สั้น ๆ เอง)
ถึงจุดที่น่าสนใจที่สุด ถ้าเรามีคำสั่งเชลล์ที่รันซ้ำ ๆ อยู่แล้ว เอามาผูกเป็นคำสั่งค้นหาใน Raycast ได้เลย แค่เพิ่มคอมเมนต์รูปแบบเฉพาะไว้บรรทัดบน ๆ ของสคริปต์ ตัวอย่างจากปุ่มจริงที่เราใช้
#!/bin/bash
# @raycast.schemaVersion 1
# @raycast.title Demo Mode
# @raycast.mode fullOutput
# @raycast.icon 🔇
# @raycast.packageName Demo
# @raycast.argument1 { "type": "text", "placeholder": "2h / off / เว้นว่าง=สลับ", "optional": true }
# @raycast.description กันทุกอย่างเด้งขึ้นจอตอน present งานลูกค้า
แค่นี้ Raycast ก็เห็นไฟล์นี้เป็นคำสั่งค้นหาชื่อ "Demo Mode" ทันที เอกสารทางการของ Raycast เองก็ใช้คำว่า raycast script commands อธิบายฟอร์แมตคอมเมนต์นี้ไว้ครบ นี่คือจุดที่คนอ่านทั่วไปที่พอเขียนสคริปต์เป็นบ้างจะ "อ๋อ" เพราะไม่ต้องเรียนอะไรใหม่เลย แค่เอาสิ่งที่เขียนอยู่แล้วมาแปะคอมเมนต์เพิ่มไม่กี่บรรทัด
ช่วงที่ 3ของจริง ที่เราเจอ
ชั้นนี้ไม่ใช่ขั้นถัดไปที่ต่อจากบันไดชั้น 1-2 ข้างบนที่ทำตามได้ทันทีทีละขั้น แต่เป็นเบื้องหลังการใช้งานจริงของเรา ปุ่มสามปุ่มด้านล่างพึ่งสคริปต์ภายในที่ไม่ได้แสดงในบทความนี้ ก๊อปไปใช้ตรง ๆ ไม่ได้ ถ้าอยากลองเขียน script command แบบเต็มด้วยตัวเอง มีตัวอย่างที่ก๊อปไปรันได้จริงอยู่ท้ายหัวข้อกับดักด้านล่าง
สามปุ่มที่กดใช้จริง
Demo Mode (🔇) ก่อนพรีเซนต์งานให้ลูกค้า สิ่งที่กลัวที่สุดคือมีหน้าต่างหรือเสียงอะไรไม่รู้เด้งขึ้นมากลางจอที่แชร์อยู่ ปุ่มนี้กดครั้งเดียวปิดทุกอย่างที่จะเด้งขึ้นจอก่อนพรีเซนต์ในทีเดียว ทั้งหน้าต่างที่งานอัตโนมัติเปิดค้างไว้ แจ้งเตือน และเสียง พิมพ์ demo on 2h แล้วมันเงียบไปสองชั่วโมงแล้วกลับมาเองอัตโนมัติ ไม่ต้องจำไปปิดเอง
ปุ่มเช็คสถานะระบบ อีกปุ่มที่ใช้บ่อยไม่แพ้กัน สรุปภาพรวมของระบบเบื้องหลังทั้งหมดให้ดูในหน้าจอเดียว แทนที่จะต้องสลับไปเช็คทีละที่เอง จับเวลาตอนเขียนบทความนี้สามรอบได้ราวสามวินาทีกว่า ๆ ต่อครั้ง (ความรู้สึกส่วนตัวคือเร็วกว่าวิธีเช็คแบบเดิมมาก แต่ไม่เคยจับเวลาฝั่งเดิมไว้เทียบจริง ๆ) รายละเอียดว่าเช็คอะไรบ้างเป็นเรื่องภายในที่ยังไม่ได้เล่าในบทความนี้
Consult Bud (💬) ปุ่มนี้ผูกกับระบบผู้ช่วย AI หลายตัวที่เราตั้งให้ทำงานเฉพาะทางกันคนละด้าน กดแล้วเลือกจาก dropdown (เมนูให้เลือก) ว่าจะถามตัวไหน พิมพ์คำถาม กดส่ง แล้วรอคำตอบมาอ่านทีหลังได้เลย ไม่ต้องสลับไปเปิดแอปแชทเองก่อนแล้วค่อยพิมพ์ (รายละเอียดว่าผู้ช่วยแต่ละตัวคืออะไรและทำงานยังไงข้างหลังเป็นเรื่องภายในที่ยังไม่ได้เล่าในบทความนี้ สิ่งที่อยากเล่าคือรูปแบบปุ่ม ไม่ใช่ระบบข้างหลัง)
กับดัก 4 ข้อที่เจอจากการทำปุ่มพวกนี้จริง
ทั้งสี่ข้อเป็นสิ่งที่เจอบนเครื่องเราเอง Raycast 1.104.24 บน macOS 26.2 เมื่อ 3 สิงหาคม 2026 ไม่ใช่ข้อเท็จจริงถาวรของตัวผลิตภัณฑ์ ของแบบนี้เปลี่ยนได้ทุกเวอร์ชัน
1. เท่าที่ทดสอบบนเวอร์ชันที่ใช้อยู่ Raycast ไม่เดินตาม symlink ของโฟลเดอร์สคริปต์ (symlink คือลิงก์ที่ชี้ไปยังโฟลเดอร์จริงอีกที่หนึ่ง ไม่ใช่ตัวโฟลเดอร์นั้นเอง) เราลองรวมโฟลเดอร์สคริปต์ให้เหลือที่เดียวโดยเปลี่ยนโฟลเดอร์จริงเป็น symlink ชี้ไปที่ git repo ผลคือปุ่มหายหมดทันที ไม่มี error ไม่มีแจ้งเตือน ยิงคำสั่งไปแล้วเงียบ ที่แย่กว่านั้นคือรีบเปลี่ยนกลับเป็นโฟลเดอร์จริงแล้วปุ่มก็ยังไม่กลับมาทันที ต้องปิด Raycast แล้วเปิดใหม่ให้มัน re-index (สแกนแล้วสร้างรายชื่อคำสั่งใหม่ทั้งหมด) ก่อนถึงจะเห็นอีกครั้ง ทางที่ได้ผลจริงคือมีสองโฟลเดอร์แล้วก๊อปข้อมูลเข้าไป ไม่ใช้ symlink
2. เช็คไม่ได้ว่า Raycast อ่านโฟลเดอร์ไหนอยู่จริง ไฟล์ config (ไฟล์เก็บค่าที่ตั้งไว้) ของ Raycast อ่านตรง ๆ ไม่ได้ เช็คด้วยคำสั่ง file แล้วขึ้นแค่ "data" ไบต์แรกของไฟล์ก็ไม่ตรงกับลายเซ็นที่ไฟล์ฐานข้อมูลธรรมดาควรมี วิธีที่ใช้ได้จริงคือแทรกบรรทัดเขียนไฟล์ marker ชั่วคราวเข้าไปในสคริปต์ ยิง deeplink เรียกคำสั่งนั้น แล้ววนเช็คว่าไฟล์ marker โผล่มาไหมภายในไม่กี่วินาที ถ้าโผล่แปลว่า Raycast อ่านโฟลเดอร์นั้นจริงและรันสคริปต์จริง
rm -f /tmp/probe # สำคัญ: ถ้าไม่ลบของเก่าก่อน ผลรอบก่อนจะหลอกให้ผ่าน
open "raycast://script-commands/my-script"
for i in $(seq 1 20); do
[ -f /tmp/probe ] && break
sleep 1
done
[ -f /tmp/probe ] && echo REGISTERED || echo NOT-REGISTERED
3. ยิง deeplink พร้อม argument แล้วพฤติกรรมไม่นิ่ง จนตอนนี้ยังไม่รู้สาเหตุแน่ชัด ตอนแรกอยากทำ deeplink ที่เรียกดูสถานะแบบอ่านอย่างเดียวโดยยิง ?arguments=status ต่อท้าย ครั้งนั้นสคริปต์รันจริง แต่ argument (ค่าที่พิมพ์แนบไปกับคำสั่ง) ที่ได้กลับมาว่างเปล่า จึงตกไปที่เคส default ของสคริปต์ ซึ่งดันเป็นคำสั่ง toggle (สลับสถานะเปิด/ปิด) ผลคือกดเพื่อเช็คสถานะ กลับกลายเป็นเปิดโหมดเงียบไปเลยโดยไม่ตั้งใจ
ตอนไล่หาสาเหตุ เขียนสคริปต์ทดสอบที่ echo ค่า argument ที่ได้รับกลับมาตรง ๆ แล้วยิงซ้ำหลายแบบ ตอนแรกเข้าใจว่าต้องห่อค่าเป็น JSON array (รูปแบบข้อมูลที่ครอบด้วยวงเล็บเหลี่ยม) แล้ว urlencode (แปลงอักขระให้ใส่ใน URL ได้) ก่อนถึงจะผ่าน เช่น ?arguments=%5B%22hello%22%5D แต่พอทดสอบซ้ำแบบควบคุมตัวแปรจริง ๆ กลับไม่เป็นแบบนั้น ค่าที่ส่งแบบธรรมดา ?arguments=hello ต่างหากที่ผ่านเข้าสคริปต์ได้ปกติ ส่วนแบบห่อ JSON array กลับได้วงเล็บดิบทั้งชุดเข้าไปในสคริปต์โดยไม่ถูกแกะให้เลย ⇒ ยังสรุปไม่ได้ชัดว่าตอนที่เจอปัญหาจริงพังเพราะอะไร (สิ่งหนึ่งที่ต่างไปจากตอนทดสอบซ้ำคือมี dialog ยืนยันความน่าเชื่อถือของสคริปต์ที่ยิงจากนอก Raycast โผล่ขึ้นมาด้วย ซึ่งอาจเกี่ยวหรือไม่เกี่ยวก็ได้)
บทเรียนที่ยืนอยู่แน่นอนกว่าการเดาสาเหตุ ข้อแรกคือถ้าคำสั่งไหนต้องรับ argument อย่าพึ่ง deeplink ล้วน ๆ ให้ตั้ง hotkey ที่ตัวคำสั่งใน Raycast แทน มันจะเปิดช่องให้พิมพ์ argument จริง ๆ ข้อสองซึ่งสำคัญกว่า คือค่า default ของสคริปต์ไม่ควรเป็นการกระทำที่เปลี่ยนสถานะ ควรให้ default เป็นแค่แสดงสถานะ เพราะการเรียกใช้งานโดยไม่ตั้งใจเกิดขึ้นได้เสมอ ไม่ว่าสาเหตุจะเป็นอะไรก็ตาม
4. โฟลเดอร์ที่ Raycast รันจริงไม่มีอยู่ในระบบสำรองข้อมูลเลย โฟลเดอร์สคริปต์จริงที่ Raycast อ่านไม่ใช่ git repo และไม่เคยอยู่ในสคริปต์ backup มาก่อน สำเนาที่เคยก๊อปเข้า repo ไว้ครั้งหนึ่งก็ไม่มีอะไรคอยซิงก์ให้ทันสมัย ทำให้สคริปต์ที่เขียนใหม่ล่าสุดอยู่บนดิสก์ก้อนเดียว ไม่มีสำรอง แก้แล้วโดยให้สคริปต์ backup ก๊อปข้อมูล จาก โฟลเดอร์จริงที่ Raycast ใช้งาน ไปที่ git ไม่ใช่ทางกลับ เพราะโฟลเดอร์จริงคือตัวที่ระบบรันอยู่จริง จึงเป็นแหล่งความจริงที่ทุกอย่างต้องตามหลัง
ตัวอย่าง script command เต็มรูปแบบที่ก๊อปไปใช้ได้เลย
ปุ่มสามปุ่มด้านบนพึ่งสคริปต์ภายในที่ไม่ได้เอามาแปะที่นี่ แต่รูปแบบ script command เป็นแบบเดียวกันทุกที่ ด้านล่างนี้คือตัวอย่างที่ไม่พึ่งอะไรนอกจากเครื่องมือที่มากับ Mac อยู่แล้ว ก๊อปทั้งไฟล์ไปวางในโฟลเดอร์ script command ของ Raycast ได้เลย รันจริงแล้วได้ผลตามนี้
#!/bin/bash
# @raycast.schemaVersion 1
# @raycast.title My IP
# @raycast.mode fullOutput
# @raycast.icon 🌐
# @raycast.packageName Utilities
# @raycast.description แสดงว่าตอนนี้ออกเน็ตผ่านการ์ดตัวไหน และ IP ในวงแลนคืออะไร
IFACE=$(route get default 2>/dev/null | awk '/interface:/{print $2}')
LOCAL_IP=$(ipconfig getifaddr "${IFACE:-en0}" 2>/dev/null)
echo "Interface: ${IFACE:-ไม่พบ}"
echo "Local IP: ${LOCAL_IP:-ไม่พบ}"
Interface: en0
Local IP: 192.168.1.23
(ตัวเลขจริงจะเปลี่ยนไปตามเครื่องที่รัน สองบรรทัดข้างบนเป็นแค่ตัวอย่างรูปแบบผลลัพธ์)
ตัวอย่างนี้ตั้งใจให้ทำงานจบในเครื่องตัวเอง ไม่ยิงออกไปถามบริการข้างนอกเลย บรรทัดแรกถาม macOS ตรง ๆ ว่าตอนนี้ออกเน็ตผ่านการ์ดตัวไหน แทนการเดาว่าเป็น en0 ซึ่งจะผิดทันทีบนเครื่องที่ต่อ VPN หรือมีการ์ดเสียบเพิ่ม ถ้าอยากได้ IP ที่โลกภายนอกเห็นด้วยก็เติมบรรทัดเรียกบริการเช็ค IP เข้าไปได้ แต่ต้องรู้ตัวว่านั่นคือการส่งคำขอออกไปหาเซิร์ฟเวอร์ของคนอื่นทุกครั้งที่กดปุ่ม
ต่อยอดง่าย ๆ ได้อีกหลายแบบโดยไม่ต้องเปลี่ยนโครงเลย เช่นสลับบรรทัด echo ไปเช็คพื้นที่ดิสก์ด้วย df -h / แทน
สรุปสั้น ๆ ก่อนจบ
Raycast เริ่มจากการเป็น Spotlight ที่ดีกว่า แต่ของที่ทำให้เรากลับมาใช้ทุกวันไม่ใช่ความเร็วในการเปิดแอป มันคือการเอางานซ้ำ ๆ ที่เคยต้องเปิด terminal หรือสลับหลายแอปมาผูกไว้ในช่องค้นหาช่องเดียว คำถามที่น่าถามไม่ใช่ "ใช้แทน Spotlight ได้ไหม" เพราะได้อยู่แล้ว แต่คือ "มีอะไรที่เรากดซ้ำทุกวันบ้าง ที่ยังไม่ได้ผูกไว้"