openclacky 0.9.18 → 0.9.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.clacky/skills/oss-upload/SKILL.md +47 -0
  3. data/CHANGELOG.md +34 -0
  4. data/docs/c-end-user-positioning.md +64 -0
  5. data/lib/clacky/agent/llm_caller.rb +1 -1
  6. data/lib/clacky/agent/message_compressor_helper.rb +8 -0
  7. data/lib/clacky/default_parsers/docx_parser.rb +43 -27
  8. data/lib/clacky/default_skills/cron-task-creator/SKILL.md +65 -58
  9. data/lib/clacky/server/channel/adapters/weixin/adapter.rb +112 -13
  10. data/lib/clacky/server/channel/adapters/weixin/api_client.rb +28 -2
  11. data/lib/clacky/server/channel/channel_manager.rb +15 -4
  12. data/lib/clacky/server/http_server.rb +189 -119
  13. data/lib/clacky/server/scheduler.rb +55 -0
  14. data/lib/clacky/tools/browser.rb +2 -2
  15. data/lib/clacky/tools/web_search.rb +206 -63
  16. data/lib/clacky/ui2/layout_manager.rb +26 -11
  17. data/lib/clacky/ui2/ui_controller.rb +4 -2
  18. data/lib/clacky/utils/encoding.rb +21 -0
  19. data/lib/clacky/utils/environment_detector.rb +9 -6
  20. data/lib/clacky/utils/file_processor.rb +6 -4
  21. data/lib/clacky/utils/parser_manager.rb +6 -1
  22. data/lib/clacky/version.rb +1 -1
  23. data/lib/clacky/web/app.css +1 -1
  24. data/lib/clacky/web/tasks.js +10 -26
  25. data/lib/clacky.rb +10 -0
  26. data/scripts/install.ps1 +395 -136
  27. data/scripts/install.sh +13 -12
  28. data/scripts/install_simple.sh +37 -19
  29. metadata +3 -5
  30. data/lib/clacky/default_skills/cron-task-creator/scripts/list_tasks.rb +0 -121
  31. data/lib/clacky/default_skills/cron-task-creator/scripts/manage_schedule.rb +0 -149
  32. data/lib/clacky/default_skills/cron-task-creator/scripts/manage_task.rb +0 -81
  33. data/lib/clacky/default_skills/cron-task-creator/scripts/task_history.rb +0 -137
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 538f6014a8386fcddf69dbf69efd162a00ad594d776b812eba5ac04f98953995
4
- data.tar.gz: 4d9952dbbf2e20d1a598b136a0f01e821a1e53391240c197afe60e3570d4bfce
3
+ metadata.gz: 803023a686f9005d8bbed56fa2604d6cb4a426ba2ff1c24ddf6e297242c7faed
4
+ data.tar.gz: ee8738600a36146e4f56b8605a917066746b31e370a41c3e245066ec4e4e961c
5
5
  SHA512:
6
- metadata.gz: 8ed52fb94f805bc83c8ab996c9a1f01635665b054750900623002edc29a0197c9ab99be08d192e2f1f1040c8665451e155d9878fec5a71c213d7c3130fbbb956
7
- data.tar.gz: 248569c522a59c37c3bda8342141be750609ca4fca996a8d563fcb953e6dcb1446fbc379082691b5503679d26d9168aa8e2503f7b169b3b4daeafa9428b7cf5b
6
+ metadata.gz: b5b27887365a698d193fee92d0672315c48963a9748509cae8a6b5426d0169f16b9fad709afa2232d80542999fc931ee48e09f2cee35100b39273b33c324b558
7
+ data.tar.gz: 5c5572d8a7b34af4eb03220dbf0e566ed0d2ab7b7278a89d8801f0c9ca58b100c90dd27fd17d1548016b21c20e1e458889a97a54983309c409479b863fc8b6ca
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: oss-upload
3
+ description: Upload local files to Tencent COS (oss.1024code.com CDN) using coscli. Use when user wants to upload a file to CDN/OSS, or deploy static assets.
4
+ ---
5
+
6
+ # OSS Upload Skill
7
+
8
+ Upload files to Tencent COS bucket `clackyai-1258723534`, served via `https://oss.1024code.com`.
9
+
10
+ ## Tool
11
+ `coscli` — config at `~/.cos.yaml`
12
+
13
+ ## Bucket Info
14
+ - Bucket: `clackyai-1258723534`
15
+ - Region: `ap-guangzhou`
16
+ - Endpoint: `cos.ap-guangzhou.myqcloud.com`
17
+ - Public CDN: `https://oss.1024code.com/<path>`
18
+
19
+ ## Upload Command
20
+
21
+ ```bash
22
+ coscli cp <local-file> cos://clackyai-1258723534/<remote-path>
23
+ ```
24
+
25
+ ### Examples
26
+
27
+ ```bash
28
+ # Upload a single file to bucket root
29
+ coscli cp /tmp/wsl.2.6.3.0.arm64.msi cos://clackyai-1258723534/wsl.2.6.3.0.arm64.msi
30
+
31
+ # Upload to a subdirectory
32
+ coscli cp /tmp/install.ps1 cos://clackyai-1258723534/clacky-ai/openclacky/main/scripts/install.ps1
33
+
34
+ # Upload entire directory recursively
35
+ coscli cp /tmp/dist/ cos://clackyai-1258723534/dist/ -r
36
+ ```
37
+
38
+ ## Public URL
39
+ After upload, the file is accessible at:
40
+ ```
41
+ https://oss.1024code.com/<remote-path>
42
+ ```
43
+
44
+ ## Steps
45
+ 1. Confirm local file exists
46
+ 2. Run `coscli cp <local> cos://clackyai-1258723534/<path>`
47
+ 3. Return the public URL: `https://oss.1024code.com/<path>`
data/CHANGELOG.md CHANGED
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.20] - 2026-03-30
11
+
12
+ ### Added
13
+ - **SSL error retry**: LLM API calls now automatically retry on SSL errors (same as other network failures — up to 10 retries with 5s delay)
14
+
15
+ ### Fixed
16
+ - **Brand wrapper not found under root**: the install script now places the brand command wrapper in the same directory as the `openclacky` binary, so it is always on PATH regardless of whether running as root or a normal user
17
+
18
+ ### Improved
19
+ - **Cron task management refactored to API**: cron task CRUD operations now go through the HTTP API instead of running ad-hoc Ruby scripts, making the scheduler more reliable and easier to maintain
20
+ - **UTF-8 encoding fix for browser tool on Windows**: browser command output with non-ASCII characters no longer causes encoding errors
21
+
22
+ ### More
23
+ - Installer no longer adds `~/.local/bin` to PATH (wrapper now colocated with gem binary, making the extra PATH entry unnecessary)
24
+ - Brand install tips in Windows PowerShell installer
25
+
26
+ ## [0.9.19] - 2026-03-29
27
+
28
+ ### Added
29
+ - **Bing search engine support**: the web search tool now supports Bing in addition to DuckDuckGo and Baidu — improves search coverage and fallback reliability
30
+ - **WSL1 fallback for Windows installer**: the PowerShell installer now automatically falls back to WSL1 when WSL2/Hyper-V is unavailable, ensuring installation succeeds on older or constrained Windows machines
31
+ - **Upgrade via OSS (CN mirror)**: the upgrade flow now downloads new gem versions from Tencent OSS, making upgrades faster and more reliable for users in China
32
+
33
+ ### Fixed
34
+ - **WeChat (Weixin) context token refresh**: the WeChat channel adapter now correctly refreshes the access token when it expires, preventing message delivery failures
35
+ - **DOCX parser UTF-8 encoding bug**: parsing `.docx` files with non-ASCII content no longer causes encoding errors
36
+ - **WSL version detection broadened**: installer now correctly handles old inbox `wsl.exe` (exit code -1) in addition to "feature not enabled" (exit code 1)
37
+ - **Ctrl+C handling in UI**: Ctrl+C now correctly interrupts the current operation without leaving the UI in a broken state
38
+ - **Layout scrollback double-render**: fixed a UI rendering issue that caused the scrollback buffer to render twice
39
+
40
+ ### More
41
+ - Support custom brand name in Windows PowerShell installer
42
+ - Redesigned Windows registration flow; removed Win10 MSI dependency
43
+
10
44
  ## [0.9.18] - 2026-03-28
11
45
 
12
46
  ### Fixed
@@ -0,0 +1,64 @@
1
+ # C-End User Positioning
2
+
3
+ > Date: 2026-03-30
4
+
5
+ ---
6
+
7
+ ## Market Context
8
+
9
+ The "OpenClaw ecosystem" has exploded in 2026. Key players:
10
+
11
+ - **OpenClaw** — open-source, self-hosted, community Skills. Designed for technical users who configure everything themselves.
12
+ - **QClaw** — Tencent's fork. Bundled Kimi model, WeChat binding. Mass-market but Tencent-ecosystem only.
13
+ - **Others** (Wukong, etc.) — same lane.
14
+
15
+ OpenClaw has 5,700+ Skills, but almost all are open-source, free, and easily copied. The ecosystem lacks **expertise-backed, production-grade Skills worth paying for**.
16
+
17
+ ---
18
+
19
+ ## Who openclacky Is For
20
+
21
+ **Ordinary users, not technical geeks.**
22
+
23
+ The target user knows OpenClaw exists, has heard about "raising a lobster", but can't or doesn't want to:
24
+ - configure Docker / environment / webhooks
25
+ - manage their own API keys without knowing what they'll spend
26
+ - troubleshoot when a long task breaks halfway
27
+
28
+ They want to use a lobster built by an expert (a lawyer, a trader, an SEO specialist) — not build one themselves.
29
+
30
+ > Core insight: **OpenClaw is built for people who create Skills. openclacky is built for people who use them.**
31
+
32
+ ---
33
+
34
+ ## Why openclacky Over OpenClaw: 3 Core Reasons
35
+
36
+ ### 1. Zero-friction IM setup — the strongest differentiator
37
+
38
+ OpenClaw requires users to manually configure webhooks, tokens, and config files to connect WeChat / Feishu / WeCom. High technical barrier, most ordinary users give up.
39
+
40
+ openclacky uses **AI-automated channel setup**: one sentence, and the AI configures the IM connection for you — no plugins, no docs, no engineering knowledge required. This is a genuine technical moat.
41
+
42
+ ### 2. Built for China, natively
43
+
44
+ - No VPN required, no overseas credit card
45
+ - WeChat / Feishu / WeCom are the primary daily tools for Chinese users — openclacky treats them as first-class citizens
46
+ - Supports domestic models (DeepSeek, Kimi, etc.) out of the box
47
+ - QClaw is domestic too, but locked to Tencent's ecosystem and model choices
48
+
49
+ ### 3. Cost transparency and long-task reliability
50
+
51
+ - Real-time token cost tracking — users always know what they're spending
52
+ - Automatic compression (up to 90% savings via Insert-then-Compress + Prompt Caching)
53
+ - Long tasks don't break: sub-agent isolation + Time Machine architecture keeps context intact
54
+
55
+ ---
56
+
57
+ ## The User Progression
58
+
59
+ ```
60
+ Can use it → Dare to use it → Keep using it
61
+ (zero setup) (cost clarity) (tasks don't break)
62
+ ```
63
+
64
+ Each of the 3 reasons maps directly to one stage of this progression.
@@ -34,7 +34,7 @@ module Clacky
34
34
  max_tokens: @config.max_tokens,
35
35
  enable_caching: @config.enable_prompt_caching
36
36
  )
37
- rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
37
+ rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Faraday::SSLError, Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
38
38
  @ui&.clear_progress
39
39
  retries += 1
40
40
  if retries <= max_retries
@@ -20,6 +20,14 @@ module Clacky
20
20
  @ui&.show_idle_status(phase: :start, message: "Idle detected. Compressing conversation to optimize costs...")
21
21
  if compression_context.nil?
22
22
  @ui&.show_idle_status(phase: :end, message: "Idle skipped.")
23
+ Clacky::Logger.info(
24
+ "Idle compression skipped",
25
+ enable_compression: @config.enable_compression,
26
+ previous_total_tokens: @previous_total_tokens,
27
+ history_size: @history.size,
28
+ idle_threshold: IDLE_COMPRESSION_THRESHOLD,
29
+ max_recent_messages: MAX_RECENT_MESSAGES
30
+ )
23
31
  return false
24
32
  end
25
33
 
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
+ # encoding: utf-8
4
+
5
+ Encoding.default_external = Encoding::UTF_8
6
+ Encoding.default_internal = Encoding::UTF_8
7
+
3
8
  #
4
9
  # Clacky DOCX Parser — CLI interface
5
10
  #
@@ -22,30 +27,43 @@ require "zip"
22
27
  require "rexml/document"
23
28
  require "stringio"
24
29
 
25
- def read_document_xml(body)
30
+ def safe_utf8(str)
31
+ # First try force_encoding (lossless, for content that IS valid UTF-8)
32
+ utf8 = str.dup.force_encoding("UTF-8")
33
+ return utf8 if utf8.valid_encoding?
34
+ # Fallback: transcode with replacement for genuinely invalid bytes
35
+ str.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "")
36
+ end
37
+
38
+ def read_zip_entry(body, name)
39
+ xml = nil
26
40
  Zip::File.open_buffer(StringIO.new(body)) do |zip|
27
- entry = zip.find_entry("word/document.xml")
28
- raise "Could not extract content — possibly encrypted or invalid format" unless entry
29
- entry.get_input_stream.read
41
+ entry = zip.find_entry(name)
42
+ xml = safe_utf8(entry.get_input_stream.read) if entry
30
43
  end
44
+ xml
45
+ end
46
+
47
+ def read_document_xml(body)
48
+ xml = read_zip_entry(body, "word/document.xml")
49
+ raise "Could not extract content — possibly encrypted or invalid format" unless xml
50
+ xml
31
51
  end
32
52
 
33
53
  def read_numbering(body)
34
54
  result = {}
35
- Zip::File.open_buffer(StringIO.new(body)) do |zip|
36
- entry = zip.find_entry("word/numbering.xml")
37
- break unless entry
38
- doc = REXML::Document.new(entry.get_input_stream.read)
39
- REXML::XPath.each(doc, "//w:abstractNum") do |an|
40
- id = an.attributes["w:abstractNumId"]
41
- levels = {}
42
- REXML::XPath.each(an, "w:lvl") do |lvl|
43
- ilvl = lvl.attributes["w:ilvl"].to_i
44
- fmt = REXML::XPath.first(lvl, "w:numFmt")&.attributes&.[]("w:val")
45
- levels[ilvl] = { fmt: fmt || "bullet" }
46
- end
47
- result[id] = levels
55
+ xml = read_zip_entry(body, "word/numbering.xml")
56
+ return result unless xml
57
+ doc = REXML::Document.new(xml)
58
+ REXML::XPath.each(doc, "//w:abstractNum") do |an|
59
+ id = an.attributes["w:abstractNumId"]
60
+ levels = {}
61
+ REXML::XPath.each(an, "w:lvl") do |lvl|
62
+ ilvl = lvl.attributes["w:ilvl"].to_i
63
+ fmt = REXML::XPath.first(lvl, "w:numFmt")&.attributes&.[]("w:val")
64
+ levels[ilvl] = { fmt: fmt || "bullet" }
48
65
  end
66
+ result[id] = levels
49
67
  end
50
68
  result
51
69
  rescue
@@ -54,16 +72,14 @@ end
54
72
 
55
73
  def read_styles(body)
56
74
  result = {}
57
- Zip::File.open_buffer(StringIO.new(body)) do |zip|
58
- entry = zip.find_entry("word/styles.xml")
59
- break unless entry
60
- doc = REXML::Document.new(entry.get_input_stream.read)
61
- REXML::XPath.each(doc, "//w:style") do |s|
62
- sid = s.attributes["w:styleId"]
63
- name = REXML::XPath.first(s, "w:name")&.attributes&.[]("w:val").to_s
64
- if name =~ /^heading (\d)/i
65
- result[sid] = { heading: $1.to_i }
66
- end
75
+ xml = read_zip_entry(body, "word/styles.xml")
76
+ return result unless xml
77
+ doc = REXML::Document.new(xml)
78
+ REXML::XPath.each(doc, "//w:style") do |s|
79
+ sid = s.attributes["w:styleId"]
80
+ name = REXML::XPath.first(s, "w:name")&.attributes&.[]("w:val").to_s
81
+ if name =~ /^heading (\d)/i
82
+ result[sid] = { heading: $1.to_i }
67
83
  end
68
84
  end
69
85
  result
@@ -17,21 +17,14 @@ Storage:
17
17
  ~/.clacky/schedules.yml # All scheduled plans (YAML list)
18
18
  ~/.clacky/logger/clacky-*.log # Execution logs (daily rotation)
19
19
 
20
- WebUI Task Panel (Clacky Web Interface):
21
- - Automatically reads tasks/ + schedules.yml and renders the task list
22
- - Each row shows task name, cron expression, and content preview
23
- - Action buttons: Run (execute now), ✎ Edit (edit in session), ✕ (delete)
24
- - Run button triggers POST /api/tasks/run executes task in a new session
25
-
26
- API Endpoints (available when clacky server is running):
27
- GET /api/tasks list all tasks
28
- POST /api/tasks → create task {name, content}
29
- GET /api/tasks/:name → get task content
30
- DELETE /api/tasks/:name → delete task
31
- POST /api/tasks/run → run immediately {name}
32
- GET /api/schedules → list all schedules
33
- POST /api/schedules → create schedule {name, task, cron}
34
- DELETE /api/schedules/:name → delete schedule
20
+ API Base: http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}
21
+
22
+ Cron-Tasks API (unified manages task file + schedule together):
23
+ GET /api/cron-tasks → list all cron tasks with schedule info
24
+ POST /api/cron-tasks create task + schedule {name, content, cron, enabled?}
25
+ PATCH /api/cron-tasks/:name → update {content?, cron?, enabled?}
26
+ DELETE /api/cron-tasks/:name → delete task file + schedule
27
+ POST /api/cron-tasks/:name/run execute immediately (creates a new session)
35
28
  ```
36
29
 
37
30
  ## Cron Expression Quick Reference
@@ -54,10 +47,11 @@ Field order: `minute hour day-of-month month day-of-week`
54
47
 
55
48
  ### 1. LIST — Show all tasks
56
49
 
57
- When user asks "what tasks do I have", "list scheduled tasks", etc.:
50
+ ```bash
51
+ curl -s http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks
52
+ ```
58
53
 
59
- 1. Run `ruby ~/.clacky/skills/cron-task-creator/scripts/list_tasks.rb`
60
- 2. Display results: task name, cron schedule, enabled status, last run status
54
+ Display each task: name, cron schedule, enabled status, content preview.
61
55
 
62
56
  If no tasks exist, inform the user and offer to create one or show templates.
63
57
 
@@ -69,15 +63,14 @@ If no tasks exist, inform the user and offer to create one or show templates.
69
63
 
70
64
  **Step 1: Gather required info** (only ask for what's missing)
71
65
  - What should the task DO? (goal, behavior, output format)
72
- - How often should it run? (or is it manual-only?)
66
+ - How often should it run? (or is it manual-only without a schedule?)
73
67
  - Any specific parameters? (URLs, file paths, output location, language)
74
68
 
75
69
  **Step 2: Generate task name**
76
70
  - Rule: only `[a-z0-9_-]`, lowercase, no spaces
77
71
  - Examples: `daily_report`, `price_monitor`, `weekly_summary`
78
72
 
79
- **Step 3: Write the task prompt file**
80
- Path: `~/.clacky/tasks/<name>.md`
73
+ **Step 3: Write the task prompt**
81
74
 
82
75
  The prompt must be:
83
76
  - **Self-contained**: the agent running it has zero prior context — include everything needed
@@ -85,7 +78,7 @@ The prompt must be:
85
78
  - **Detailed**: include URLs, file paths, output format, language, expected output location
86
79
 
87
80
  Good task prompt example:
88
- ```markdown
81
+ ```
89
82
  You are a price monitoring assistant. Complete the following task:
90
83
 
91
84
  ## Goal
@@ -100,14 +93,17 @@ Check the current BTC price on CoinGecko, compare with yesterday's price, and lo
100
93
  Execute immediately.
101
94
  ```
102
95
 
103
- **Step 4: Write file and add schedule**
96
+ **Step 4: Create via API**
104
97
 
105
98
  ```bash
106
- # Write task file
107
- ruby ~/.clacky/skills/cron-task-creator/scripts/manage_task.rb create "<name>" "<content>"
108
-
109
- # Add schedule (if applicable)
110
- ruby ~/.clacky/skills/cron-task-creator/scripts/manage_schedule.rb add "<name>" "<task_name>" "<cron_expr>"
99
+ curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks \
100
+ -H "Content-Type: application/json" \
101
+ -d '{
102
+ "name": "task_name",
103
+ "content": "task prompt content...",
104
+ "cron": "0 9 * * *",
105
+ "enabled": true
106
+ }'
111
107
  ```
112
108
 
113
109
  **Step 5: Confirm creation**
@@ -116,7 +112,6 @@ ruby ~/.clacky/skills/cron-task-creator/scripts/manage_schedule.rb add "<name>"
116
112
  ✅ Task created successfully!
117
113
 
118
114
  📋 Task name: daily_standup
119
- 📄 File: ~/.clacky/tasks/daily_standup.md
120
115
  ⏰ Schedule: Weekdays at 09:00 (cron: 0 9 * * 1-5)
121
116
 
122
117
  View and manage this task in the Clacky WebUI → Tasks panel. Click ▶ Run to execute immediately.
@@ -126,24 +121,27 @@ View and manage this task in the Clacky WebUI → Tasks panel. Click ▶ Run to
126
121
 
127
122
  ### 3. EDIT — Modify an existing task
128
123
 
129
- When the user wants to change task content, cron schedule, or rename:
124
+ **Step 1**: Identify the task (if unclear, LIST first and ask)
130
125
 
131
- **Step 1**: Identify the task to modify (if unclear, LIST first and ask)
126
+ **Step 2**: Show current state via LIST or ask user to confirm
132
127
 
133
- **Step 2**: Show current state (first 10 lines + cron expression)
134
-
135
- **Step 3**: Determine what to change
136
- - Prompt only → rewrite `~/.clacky/tasks/<name>.md`
137
- - Schedule only → update `cron` field in `schedules.yml`
138
- - Both → do both
139
- - Rename → rename .md file + update schedules.yml
128
+ **Step 3**: Update via API
140
129
 
141
130
  ```bash
142
- # Update task content
143
- ruby ~/.clacky/skills/cron-task-creator/scripts/manage_task.rb update "<name>" "<new_content>"
144
-
145
- # Update cron schedule
146
- ruby ~/.clacky/skills/cron-task-creator/scripts/manage_schedule.rb update "<schedule_name>" "<new_cron>"
131
+ # Update content only
132
+ curl -s -X PATCH http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name \
133
+ -H "Content-Type: application/json" \
134
+ -d '{"content": "new prompt content..."}'
135
+
136
+ # Update cron schedule only
137
+ curl -s -X PATCH http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name \
138
+ -H "Content-Type: application/json" \
139
+ -d '{"cron": "0 8 * * 1-5"}'
140
+
141
+ # Update both
142
+ curl -s -X PATCH http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name \
143
+ -H "Content-Type: application/json" \
144
+ -d '{"content": "...", "cron": "0 8 * * 1-5"}'
147
145
  ```
148
146
 
149
147
  **Step 4**: Confirm changes
@@ -151,7 +149,6 @@ ruby ~/.clacky/skills/cron-task-creator/scripts/manage_schedule.rb update "<sche
151
149
  ```
152
150
  ✅ Task updated!
153
151
  📋 daily_standup
154
- Prompt: updated ✓
155
152
  Schedule: 0 9 * * 1-5 → 0 8 * * 1-5 (now weekdays at 08:00)
156
153
  ```
157
154
 
@@ -160,7 +157,15 @@ ruby ~/.clacky/skills/cron-task-creator/scripts/manage_schedule.rb update "<sche
160
157
  ### 4. ENABLE / DISABLE — Toggle a task
161
158
 
162
159
  ```bash
163
- ruby ~/.clacky/skills/cron-task-creator/scripts/manage_schedule.rb toggle "<schedule_name>" true|false
160
+ # Disable
161
+ curl -s -X PATCH http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name \
162
+ -H "Content-Type: application/json" \
163
+ -d '{"enabled": false}'
164
+
165
+ # Enable
166
+ curl -s -X PATCH http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name \
167
+ -H "Content-Type: application/json" \
168
+ -d '{"enabled": true}'
164
169
  ```
165
170
 
166
171
  Confirm:
@@ -180,15 +185,22 @@ Always confirm before deleting (unless the user has explicitly said to delete):
180
185
  ```
181
186
 
182
187
  ```bash
183
- ruby ~/.clacky/skills/cron-task-creator/scripts/manage_task.rb delete "<name>"
188
+ curl -s -X DELETE http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name
184
189
  ```
185
190
 
186
191
  ---
187
192
 
188
193
  ### 6. HISTORY — View run history
189
194
 
195
+ Read the daily log files directly:
196
+
190
197
  ```bash
191
- ruby ~/.clacky/skills/cron-task-creator/scripts/task_history.rb "<task_name>"
198
+ grep "task_name" ~/.clacky/logger/clacky-$(date +%Y-%m-%d).log | tail -20
199
+ ```
200
+
201
+ Or search across recent days:
202
+ ```bash
203
+ grep -h "task_name" ~/.clacky/logger/clacky-*.log | tail -30
192
204
  ```
193
205
 
194
206
  Display format:
@@ -198,24 +210,21 @@ Display format:
198
210
  Mar 10 19:00 ❌ Failed — JSON::ParserError: unexpected end of input
199
211
  Mar 09 19:00 ✅ Success — took 1m 42s
200
212
  Mar 08 19:00 ✅ Success — took 2m 10s
201
- Mar 07 19:00 ⚠️ Skipped — (task was disabled)
202
-
203
- Recent error:
204
- JSON::ParserError at line 226
205
- Possible cause: API response was truncated or empty
206
213
  ```
207
214
 
208
215
  ---
209
216
 
210
217
  ### 7. RUN NOW — Execute immediately
211
218
 
219
+ ```bash
220
+ curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/cron-tasks/task_name/run
212
221
  ```
213
- ▶️ Go to the Clacky WebUI → Tasks panel, find the task, and click ▶ Run.
214
222
 
215
- The task will execute in a new session. You can watch it run in real time via the WebUI.
223
+ This creates a new session. Tell the user:
224
+ ```
225
+ ▶️ Task started in a new session.
226
+ View it in the Clacky WebUI → Sessions panel.
216
227
  ```
217
-
218
- If the user wants to run the task in the current session, read the task file and execute the instructions directly.
219
228
 
220
229
  ---
221
230
 
@@ -243,8 +252,6 @@ Tell me which one interests you, or describe your own use case!
243
252
  ## Important Notes
244
253
 
245
254
  - Task names: only `[a-z0-9_-]`, no spaces, no uppercase
246
- - When modifying `schedules.yml`: always read → modify → write back the full file (never append directly)
247
255
  - Task prompt files must be **self-contained** — the executing agent has no prior memory
248
256
  - Clacky server must be running for cron to trigger automatically (checked every minute)
249
257
  - The WebUI Task Panel is the preferred interface for managing tasks — always remind the user to check it after changes
250
- - Path expansion: always use absolute paths, expand `~` to the actual home directory