clawaxis 1.0.0

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.
package/CLAWAXIS.md ADDED
@@ -0,0 +1,954 @@
1
+ # CLAWAXIS.md — Agent Instruction Manual
2
+
3
+ > This is the definitive guide for how to use the ClawAxis tools.
4
+ > It ships alongside the plugin and is injected into the agent's context.
5
+ > **Last updated: February 2026**
6
+
7
+ ---
8
+
9
+ ## Core Philosophy: Transparency
10
+
11
+ **ALWAYS log what you're doing.** Users feel disconnected when they don't know what's happening. Use logs to:
12
+ - Show progress ("Starting competitive analysis research...")
13
+ - Celebrate wins ("Posted daily blog with hero image")
14
+ - Explain setbacks ("API rate limit hit, retrying in 30s...")
15
+
16
+ Think of logs as your way to "show your work" — it builds trust and keeps users engaged.
17
+
18
+ ---
19
+
20
+ ## Content System — The Most Important Section
21
+
22
+ The `content_type` you choose determines **which visual card the iOS app uses to render your content**. Getting this wrong means the content looks broken. Getting the body format wrong means it renders as garbage.
23
+
24
+ ### Content Type Reference
25
+
26
+ | `content_type` | Card | Body Format | Char Limit | Title Displayed? | Media? | Tags? |
27
+ |---|---|---|---|---|---|---|
28
+ | `twitter` | Tweet preview | **Plain text** | **280** | No | Up to 4 images (16:9) | No |
29
+ | `instagram` | Caption preview | **Plain text** | **2,200** | No | 1st image (1:1 square) | Yes → #hashtags |
30
+ | `linkedin` | Post preview | **Plain text** | **3,000** | No | No | No |
31
+ | `facebook` | Post preview | **Plain text** | None | No | 1st image | No |
32
+ | `tiktok` | Caption preview | **Plain text** | **4,000** | No | 1st image (9:16 tall) | Yes → #hashtags |
33
+ | `youtube` | Description preview | **Plain text** | **5,000** | **YES — shown as video title** | 1st image (16:9 thumbnail) | Yes (pills) |
34
+ | `website` | Live HTML render | **Raw HTML** | None | No | No (HTML rendered) | Yes (pills) |
35
+ | `blog` | Markdown render | **Markdown** | None | No | No | Yes (pills + SEO keywords) |
36
+ | `report` | Markdown render | **Markdown** | None | No | No | Yes (pills + SEO keywords) |
37
+ | `email` | Markdown render | **Markdown** | None | No | No | Yes (pills) |
38
+ | `ad` | Markdown render | **Markdown** | None | No | No | Yes (pills) |
39
+ | `document` | Markdown render | **Markdown** | None | No | No | Yes (pills) |
40
+ | `other` | Markdown render | **Markdown** | None | No | No | Yes (pills) |
41
+
42
+ ### Body Format Rules
43
+
44
+ **Social platforms** (twitter, instagram, linkedin, facebook, tiktok, youtube):
45
+ - **Plain text ONLY** — no Markdown, no HTML, no formatting symbols
46
+ - Respect character limits — the app shows red warnings when exceeded
47
+ - Write conversational, human-readable text
48
+
49
+ **Website**:
50
+ - **Raw HTML** — the body is rendered directly in a WKWebView
51
+ - Include complete HTML structure (`<!DOCTYPE html>` through `</html>`)
52
+ - Include all styling (inline `<style>` or external stylesheet references)
53
+ - Must be valid, well-formed HTML5
54
+
55
+ **Blog, Report, Email, Ad, Document, Other**:
56
+ - **Markdown** — rendered via the MarkdownUI library
57
+ - Full Markdown support: headings, bold, italic, code blocks, links, lists, tables, images
58
+
59
+ ### What You Must Always Provide
60
+
61
+ | Field | When | Why |
62
+ |---|---|---|
63
+ | `title` | **ALWAYS** | Card list header, search, identification |
64
+ | `body` | **ALWAYS** | The actual content |
65
+ | `content_type` | **ALWAYS** | Determines which card renders. **Never omit.** |
66
+ | `word_count` | For blog, report, email, document | Displayed prominently in card header |
67
+ | `tags` | For instagram, tiktok, blog, report, website | Instagram/TikTok convert to #hashtags; blog/report show as pill badges |
68
+ | `seo_keywords` | For blog, report | Shown as "SEO Keywords" in card footer |
69
+ | `media` | For twitter, instagram, facebook, tiktok, youtube | These platforms expect images. Without them you get a grey placeholder. |
70
+ | `prompt_used` | Recommended | Shown in "Generation Info" section on detail view |
71
+ | `model_used` | Recommended | Shown in "Generation Info" section on detail view |
72
+
73
+ ### The #1 Rule
74
+
75
+ **Always set `content_type` to the correct platform value.** If you're writing an Instagram caption, use `instagram`. If you're writing a blog post, use `blog`, not `other`. The wrong type means the wrong card renders and the content looks broken.
76
+
77
+ ---
78
+
79
+ ## Media Format
80
+
81
+ The `media` field MUST be a JSON object with this structure:
82
+
83
+ ```json
84
+ {
85
+ "images": [
86
+ { "url": "https://example.com/image1.jpg", "alt": "Description of image" }
87
+ ],
88
+ "videos": [
89
+ { "url": "https://example.com/video.mp4", "alt": "Video description" }
90
+ ]
91
+ }
92
+ ```
93
+
94
+ **Rules:**
95
+ - `url` is **required** — must be a full HTTPS URL
96
+ - `alt` is optional but recommended
97
+ - **Use permanent URLs only** — temporary URLs (DALL-E, etc.) expire. Upload to R2 first with `clawaxis_upload_media`.
98
+ - The app accesses `media.images[0]` for platforms that show a single image (Instagram, Facebook, TikTok, YouTube)
99
+ - Twitter supports up to 4 images (rendered as a grid)
100
+
101
+ **The Swift decoder also accepts a flat array** (legacy format):
102
+ ```json
103
+ [{ "url": "...", "alt": "..." }]
104
+ ```
105
+ This is treated as `{ images: [...], videos: [] }`. But always prefer the nested format.
106
+
107
+ ---
108
+
109
+ ## Content Examples
110
+
111
+ ### Twitter
112
+ ```json
113
+ {
114
+ "title": "AI Governance Tweet",
115
+ "body": "The future of autonomous vehicles depends on the governance frameworks we build today. Our latest research dives into what this means. 🚗🤖",
116
+ "content_type": "twitter",
117
+ "word_count": 22,
118
+ "media": {
119
+ "images": [
120
+ { "url": "https://media.example.com/ai-auto.jpg", "alt": "AI governance infographic" }
121
+ ],
122
+ "videos": []
123
+ }
124
+ }
125
+ ```
126
+
127
+ ### Instagram
128
+ ```json
129
+ {
130
+ "title": "AI Governance Instagram Post",
131
+ "body": "The future of autonomous vehicles depends on the governance frameworks we build today. Our latest research dives deep into what this means for the automotive industry.",
132
+ "content_type": "instagram",
133
+ "tags": ["AIGovernance", "AutomotiveAI", "AutonomousVehicles", "FutureOfDriving", "TechPolicy"],
134
+ "media": {
135
+ "images": [
136
+ { "url": "https://media.example.com/ai-auto-square.jpg", "alt": "AI governance visual" }
137
+ ],
138
+ "videos": []
139
+ }
140
+ }
141
+ ```
142
+ Note: Don't put `#` in the tags array — the app adds it automatically.
143
+
144
+ ### LinkedIn
145
+ ```json
146
+ {
147
+ "title": "AI Governance LinkedIn Post",
148
+ "body": "The automotive industry stands at a crossroads.\n\nAs AI systems become more autonomous, the frameworks we build today will determine whether these technologies earn public trust — or erode it.\n\nOur latest research explores three critical governance areas...",
149
+ "content_type": "linkedin"
150
+ }
151
+ ```
152
+
153
+ ### YouTube
154
+ ```json
155
+ {
156
+ "title": "AI Governance in the Automotive Industry",
157
+ "body": "In this video, we explore the critical governance frameworks needed for autonomous vehicles.\n\n00:00 Introduction\n02:15 ISO 26262 Overview\n05:30 SOTIF Framework\n...",
158
+ "content_type": "youtube",
159
+ "tags": ["AI governance", "autonomous vehicles", "ISO 26262"],
160
+ "media": {
161
+ "images": [
162
+ { "url": "https://media.example.com/yt-thumbnail.jpg", "alt": "Video thumbnail" }
163
+ ],
164
+ "videos": []
165
+ }
166
+ }
167
+ ```
168
+ Note: YouTube is the **only** social card that displays the `title` as the video title.
169
+
170
+ ### Blog (Markdown)
171
+ ```json
172
+ {
173
+ "title": "AI Governance in the Automotive Industry",
174
+ "body": "# AI Governance in the Automotive Industry\n\nThe automotive industry stands at a crossroads...\n\n## Key Frameworks\n\n1. **ISO 26262** — Functional safety\n2. **SOTIF** — Safety of the intended functionality\n\n## Conclusion\n\nThe frameworks we build today will shape...",
175
+ "content_type": "blog",
176
+ "word_count": 1250,
177
+ "tags": ["AI", "automotive", "governance", "safety"],
178
+ "seo_keywords": ["AI governance automotive", "autonomous vehicle safety frameworks"],
179
+ "prompt_used": "Write a blog post about AI governance in the automotive industry",
180
+ "model_used": "anthropic/claude-sonnet-4-5"
181
+ }
182
+ ```
183
+
184
+ ### Website (HTML)
185
+ ```json
186
+ {
187
+ "title": "Company Landing Page",
188
+ "body": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Welcome</title><style>body{font-family:system-ui;margin:0;padding:2rem;max-width:800px;margin:0 auto;}</style></head><body><h1>Welcome to Our Company</h1><p>We build the future of autonomous systems.</p></body></html>",
189
+ "content_type": "website",
190
+ "tags": ["landing-page", "company"]
191
+ }
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Available Tools
197
+
198
+ ### clawaxis_post_content
199
+ Post content to the ClawAxis app for user review.
200
+
201
+ **Parameters:**
202
+ | Param | Required | Description |
203
+ |---|---|---|
204
+ | `title` | **YES** | Content title |
205
+ | `body` | **YES** | Full content body (plain text, Markdown, or HTML depending on content_type) |
206
+ | `content_type` | **YES** | Must be one of: `twitter`, `instagram`, `linkedin`, `facebook`, `tiktok`, `youtube`, `website`, `blog`, `report`, `email`, `ad`, `document`, `other` |
207
+ | `tags` | Recommended | Array of strings. Instagram/TikTok auto-prefix with `#`. Blog/report show as pills. |
208
+ | `seo_keywords` | For blog/report | Array of keyword phrases. Shown in card footer. |
209
+ | `word_count` | For long-form | Integer. Shown in card header for blog/report/email. |
210
+ | `prompt_used` | Recommended | The prompt that generated this. Shown in "Generation Info". |
211
+ | `model_used` | Recommended | Model ID (e.g. `anthropic/claude-sonnet-4-5`). Shown in "Generation Info". |
212
+ | `media` | For visual platforms | `{images: [{url, alt?}], videos: [{url, alt?}]}`. Required for twitter/instagram/facebook/tiktok/youtube. |
213
+ | `platform` | Legacy | Don't use. Use `content_type` instead. |
214
+
215
+ ### clawaxis_update_content
216
+ Update existing content. The relay auto-increments `edit_count` and preserves `original_body` on first edit.
217
+
218
+ **Parameters:**
219
+ | Param | Required | Description |
220
+ |---|---|---|
221
+ | `content_id` | **YES** | UUID of content to update |
222
+ | `body` | **YES** | Complete updated body. Same format rules apply. |
223
+ | `title` | No | Updated title. Omit to keep existing. |
224
+ | `media` | No | Updated media. Omit to keep existing. |
225
+
226
+ ### clawaxis_get_content
227
+ Retrieve content from the queue. Always uses HTTP (needs synchronous response).
228
+
229
+ **Parameters:**
230
+ | Param | Required | Description |
231
+ |---|---|---|
232
+ | `content_id` | No | UUID of specific item. Omit to get recent list. |
233
+
234
+ ### clawaxis_post_log
235
+ Log activity to the ClawAxis dashboard. Users see this in the Home screen's "Recent Activity" feed.
236
+
237
+ **Parameters:**
238
+ | Param | Required | Type | Description |
239
+ |---|---|---|---|
240
+ | `action` | **YES** | String (ENUM) | See table below. **Invalid values are rejected by the database.** |
241
+ | `detail` | **YES** | String | Human-readable description. This is the PRIMARY text the user reads. Make it useful. |
242
+ | `level` | **YES** (effectively) | String (ENUM) | See table below. Default: `info`. Controls the colored dot next to the log. |
243
+ | `tokens_used` | No | Number | Token count. Shown as badge if > 0. |
244
+ | `cost` | No | Number | Cost in USD (e.g. 0.015). Shown as badge if > 0. |
245
+ | `duration_ms` | No | Number | How long the action took in ms. Shown as badge. |
246
+ | `metadata` | No | Object | Additional context as JSON. Stored in JSONB column. |
247
+
248
+ ### Valid `action` Values (DATABASE ENUM — no other values work)
249
+
250
+ | Value | When to Use |
251
+ |---|---|
252
+ | `chat_message` | Responding to a user message |
253
+ | `content_generate` | Starting to create content (blog, report, tweet, etc.) |
254
+ | `content_post` | Content was posted to the queue (after `clawaxis_post_content`) |
255
+ | `web_search` | Performed a web search |
256
+ | `web_fetch` | Fetched/scraped a webpage |
257
+ | `browser_action` | Browser automation (navigating, clicking, screenshots) |
258
+ | `cron_execute` | Running a scheduled task / cron job |
259
+ | `skill_update` | Updated agent skills or knowledge base |
260
+ | `file_operation` | Read, wrote, or edited a file |
261
+ | `system` | System-level operations (startup, config, etc.) |
262
+ | `error` | An error occurred |
263
+ | `tool_call` | Called an external tool |
264
+
265
+ **Common mistakes:**
266
+ - `"research"` — NOT valid. Use `web_search` or `web_fetch`
267
+ - `"search"` — NOT valid. Use `web_search`
268
+ - `"generate"` — NOT valid. Use `content_generate`
269
+ - `"post"` — NOT valid. Use `content_post`
270
+ - `"install"` — NOT valid. Use `system`
271
+ - `"api_call"` — NOT valid. Use `tool_call`
272
+ - `"log"` — NOT valid. Use `system`
273
+
274
+ ### Valid `level` Values (DATABASE ENUM)
275
+
276
+ | Value | Dot Color | When to Use |
277
+ |---|---|---|
278
+ | `info` | Blue | Starting a task, neutral updates, progress notes |
279
+ | `success` | Green | Task completed, content posted, cron set up |
280
+ | `warning` | Yellow | Partial failure, retry needed, rate limit hit |
281
+ | `error` | Red | Something broke, exception caught, tool failed |
282
+
283
+ **Frontend rendering:**
284
+
285
+ The Home screen "Recent Activity" card shows each log as a row:
286
+ ```
287
+ [colored dot] detail text (primary, up to 2 lines)
288
+ action_name • 3 min ago [tokens badge]
289
+ ```
290
+
291
+ - The **colored dot** comes from `level` (blue/green/yellow/red)
292
+ - The **action** is displayed as text with underscores replaced by spaces (e.g. `content_post` → "content post")
293
+ - The **detail** is the main text the user reads — make it descriptive
294
+ - **tokens_used** shows as a small badge on the right if > 0
295
+ - **cost** shows as a badge if > 0
296
+
297
+ ### Log Examples
298
+
299
+ ```json
300
+ // Starting research
301
+ {
302
+ "action": "web_search",
303
+ "detail": "Searching for AI governance frameworks in the automotive industry",
304
+ "level": "info"
305
+ }
306
+
307
+ // Content created
308
+ {
309
+ "action": "content_post",
310
+ "detail": "Posted blog post: AI Governance in the Automotive Industry (1,250 words)",
311
+ "level": "success",
312
+ "tokens_used": 3200,
313
+ "duration_ms": 15000
314
+ }
315
+
316
+ // Error occurred
317
+ {
318
+ "action": "error",
319
+ "detail": "Failed to generate hero image: API rate limit exceeded, retrying in 30s",
320
+ "level": "error",
321
+ "metadata": { "retry_in": 30, "service": "image_api" }
322
+ }
323
+
324
+ // Cron job created
325
+ {
326
+ "action": "cron_execute",
327
+ "detail": "Created routine: Daily AI News — runs every day at 8:00 AM ET",
328
+ "level": "success"
329
+ }
330
+
331
+ // Installing a dependency
332
+ {
333
+ "action": "system",
334
+ "detail": "Installing @sinclair/typebox for plugin schema validation",
335
+ "level": "info"
336
+ }
337
+
338
+ // Used a tool
339
+ {
340
+ "action": "tool_call",
341
+ "detail": "Called web_fetch on 5 competitor websites for analysis",
342
+ "level": "info",
343
+ "tokens_used": 800,
344
+ "duration_ms": 4500
345
+ }
346
+ ```
347
+
348
+ **CRITICAL:** `action` and `level` are real Postgres ENUMs. If you send an invalid value, the database INSERT fails silently and the log is **lost forever**. The relay now validates and defaults invalid values to `system`/`info`, but you should always use exact values from the tables above.
349
+
350
+ ### clawaxis_upload_media
351
+ Upload images to permanent R2 storage. Always uses HTTP (binary payloads).
352
+
353
+ **Parameters:**
354
+ | Param | Required | Description |
355
+ |---|---|---|
356
+ | `image_url` | **YES** | URL of image to download and re-upload to R2 |
357
+ | `filename` | No | Custom filename without extension. Defaults to timestamp. |
358
+ | `folder` | No | Subfolder in R2 (e.g. `blog`, `social`). Defaults to agent ID. |
359
+
360
+ **Returns:** `{ ok: true, url: "https://...", key: "...", size: 12345 }`
361
+
362
+ **Always upload before posting content.** Temporary URLs (DALL-E, etc.) expire. Use permanent R2 URLs in your media objects.
363
+
364
+ ### clawaxis_notify_routine
365
+ Register a new agent-created routine in the app.
366
+
367
+ **Parameters:**
368
+ | Param | Required | Description |
369
+ |---|---|---|
370
+ | `name` | **YES** | Short name (e.g. "Daily AI News") |
371
+ | `cron_expression` | **YES** | Standard cron (e.g. `0 8 * * *`) |
372
+ | `instruction` | **YES** | What the routine does |
373
+ | `openclaw_cron_id` | **YES** | OpenClaw cron job ID |
374
+ | `schedule_human` | Recommended | Human-readable schedule (e.g. "Every day at 8:00 AM") |
375
+ | `next_run_at` | Recommended | ISO 8601 timestamp of next execution |
376
+ | `timezone` | Recommended | IANA timezone (e.g. `America/New_York`). Default: America/New_York |
377
+ | `frequency` | Recommended | Must be: `once`, `hourly`, `daily`, `weekly`, `monthly`, `custom` |
378
+ | `description` | No | Longer description |
379
+ | `status` | No | Must be: `active`, `paused`, `disabled`. Default: active |
380
+
381
+ **Rule:** Every cron job you create MUST be registered with the app. No hidden automation.
382
+
383
+ ### clawaxis_update_routine
384
+ Update an existing routine.
385
+
386
+ **Parameters:**
387
+ | Param | Required | Description |
388
+ |---|---|---|
389
+ | `routine_id` | **YES** | UUID of routine to update |
390
+ | `openclaw_cron_id` | No | Updated OpenClaw cron job ID (if the cron job was recreated) |
391
+ | `name` | No | Updated routine name |
392
+ | `cron_expression` | No | Updated cron expression |
393
+ | `schedule_human` | No | Human-readable schedule |
394
+ | `instruction` | No | Updated task instructions |
395
+ | `timezone` | No | IANA timezone string |
396
+ | `next_run_at` | No | ISO 8601 timestamp of next run |
397
+ | `description` | No | Updated description |
398
+ | `status` | No | `active`, `paused`, or `disabled` |
399
+
400
+ **Rule:** Any time you modify a cron job (schedule, name, status), ALWAYS call this so the app stays in sync.
401
+
402
+ ### clawaxis_confirm_doc_sync
403
+ Confirm a document uploaded through the app has been received.
404
+
405
+ **Parameters:**
406
+ | Param | Required | Description |
407
+ |---|---|---|
408
+ | `document_id` | **YES** | UUID of the document |
409
+ | `agent_skill_path` | Recommended | Where the document was saved on the agent machine |
410
+
411
+ ### clawaxis_confirm_routine_sync
412
+ Confirm a routine created through the app has been set up.
413
+
414
+ **Parameters:**
415
+ | Param | Required | Description |
416
+ |---|---|---|
417
+ | `routine_id` | **YES** | UUID of the routine |
418
+ | `openclaw_cron_id` | Recommended | OpenClaw cron job ID that was created |
419
+
420
+ ---
421
+
422
+ ## Message System
423
+
424
+ ### Message Types
425
+
426
+ Every message has a `message_type` field. This tells you what kind of message the user sent:
427
+
428
+ | `message_type` | Description | Content Format |
429
+ |---|---|---|
430
+ | `text` | Normal typed message | Plain text |
431
+ | `voice` | Spoken via voice-to-text | `[VOICE_INPUT] {transcribed text}` |
432
+ | `content_edit` | User wants to edit existing content | `@content_edit:{UUID}:{Title}\n{user instructions}` |
433
+ | `image` | Image attachment | Text with attachment metadata |
434
+ | `document` | Document attachment | Text with attachment metadata |
435
+
436
+ ### Message Status Lifecycle
437
+
438
+ Every message goes through these statuses. The plugin now sends status updates automatically:
439
+
440
+ ```
441
+ User sends message
442
+
443
+ [pending] — Message created, not yet delivered to agent
444
+
445
+ [processing] — Agent received message, thinking/working on it
446
+ ↓ ↓
447
+ [complete] — Agent replied [error] — Something broke
448
+ ```
449
+
450
+ **What the user sees for each status:**
451
+ | Status | UI Indicator |
452
+ |---|---|
453
+ | `pending` | Clock icon + "Sending" (grey) |
454
+ | `processing` | Brain icon + "Thinking..." (accent color, animated) |
455
+ | `complete` | Checkmark + "Delivered" (green) |
456
+ | `error` | Warning triangle + "Failed" (red) |
457
+
458
+ ### Content Edit Requests
459
+
460
+ When a user taps "Edit" on a content item in the app, they can type instructions. The app sends a message with:
461
+ - `message_type: "content_edit"`
462
+ - `ref_id: UUID` (the content item's UUID)
463
+ - Content formatted as: `@content_edit:{UUID}:{Title}\n{user instructions}`
464
+
465
+ **Example message you'll receive:**
466
+ ```
467
+ @content_edit:908DE83B-3ECB-4866-9981-CEB8300501D1:AI Governance Blog Post
468
+ Make the introduction more concise and add a section about GDPR compliance
469
+ ```
470
+
471
+ **What to do:**
472
+ 1. Parse the `ref_id` (content UUID) from the message or use the `ref_id` field
473
+ 2. Fetch the content: `clawaxis_get_content(content_id: "908DE83B-...")`
474
+ 3. Make the requested changes to the body/title
475
+ 4. Update: `clawaxis_update_content(content_id: "908DE83B-...", body: revised_content)`
476
+ 5. Log: `clawaxis_post_log(action: "content_post", detail: "Updated blog post: AI Governance (added GDPR section)", level: "success")`
477
+ 6. Reply confirming what you changed
478
+
479
+ **The frontend shows:**
480
+ - A `@ContentEdit — AI Governance Blog Post` badge above the user's message bubble
481
+ - The user's instructions below the badge (the `@content_edit:...` prefix is stripped for display)
482
+
483
+ ### Voice Messages
484
+
485
+ Messages prefixed with `[VOICE_INPUT]` were spoken by the user via voice-to-text. The `message_type` will be `voice`.
486
+
487
+ **Example message you'll receive:**
488
+ ```
489
+ [VOICE_INPUT] Hey can you write me a blog post about AI governance in the automotive industry
490
+ ```
491
+
492
+ **What the user sees:**
493
+ - The bubble shows: "Hey can you write me a blog post about AI governance in the automotive industry" (prefix stripped)
494
+ - A small "Voice transcription" label with mic icon appears below the bubble
495
+
496
+ **How to respond:**
497
+ - Respond conversationally — no code blocks, no Markdown formatting, no structured lists
498
+ - Keep responses natural and readable aloud
499
+ - The app automatically reads your response aloud via text-to-speech when in voice conversation mode
500
+ - The user hears your response through the device speaker
501
+
502
+ ### Routine Management Messages
503
+
504
+ When a user creates, pauses, resumes, or deletes a routine in the app, the app inserts a structured message into the `messages` table. You receive it as a regular chat message. These are **system instructions** — act on them immediately.
505
+
506
+ **Message format:** Each message starts with a system tag in brackets:
507
+
508
+ #### `[system:routine_created:<UUID>]`
509
+ The user created a new routine. The message body includes the name, frequency, schedule, and instructions.
510
+
511
+ **Example message you'll receive:**
512
+ ```
513
+ [system:routine_created:908DE83B-3ECB-4866-9981-CEB8300501D1]
514
+ New routine created: "Daily AI News"
515
+ Frequency: Daily
516
+ Schedule: Every day at 8:00 AM (0 8 * * *)
517
+ Instructions: Check AI news sources and post a summary blog post
518
+
519
+ Please set up this cron job and confirm when ready by calling clawaxis_confirm_routine_sync with routine_id: 908DE83B-3ECB-4866-9981-CEB8300501D1
520
+ ```
521
+
522
+ **What to do:**
523
+ 1. Parse the routine details (name, cron expression, instruction)
524
+ 2. Create the cron job: `cron({ action: "add", job: { name, schedule: { kind: "cron", expr: "0 8 * * *", tz: "America/New_York" }, payload: { kind: "agentTurn", message: instruction }, sessionTarget: "isolated" } })`
525
+ 3. Confirm sync: `clawaxis_confirm_routine_sync(routine_id: "<UUID>", openclaw_cron_id: cronResult.jobId)`
526
+ 4. Log it: `clawaxis_post_log(action: "cron_execute", detail: "Created routine: Daily AI News", level: "success")`
527
+ 5. Reply confirming setup
528
+
529
+ #### `[system:routine_paused:<UUID>]`
530
+ The user paused a routine. The message includes the routine name and OpenClaw cron ID.
531
+
532
+ **What to do:**
533
+ 1. Remove or pause the cron job: `cron({ action: "remove", jobId: "<openclaw_cron_id>" })`
534
+ 2. Reply confirming it's paused
535
+
536
+ #### `[system:routine_resumed:<UUID>]`
537
+ The user resumed a paused routine. The message includes the schedule and instructions.
538
+
539
+ **What to do:**
540
+ 1. Re-create the cron job with the original schedule
541
+ 2. Confirm sync: `clawaxis_confirm_routine_sync(routine_id: "<UUID>", openclaw_cron_id: newCronId)`
542
+ 3. Reply confirming it's active again
543
+
544
+ #### `[system:routine_deleted:<UUID>]`
545
+ The user deleted a routine. The message includes the OpenClaw cron ID.
546
+
547
+ **What to do:**
548
+ 1. Remove the cron job: `cron({ action: "remove", jobId: "<openclaw_cron_id>" })`
549
+ 2. Reply confirming it's deleted
550
+
551
+ ### Pending Routines via Sync / Heartbeat
552
+
553
+ Besides chat messages, you also receive pending routines via two WebSocket paths:
554
+
555
+ 1. **On connect (`sync` message):** The relay sends all routines where `synced_at IS NULL` — these are routines the user created while you were offline.
556
+ 2. **On heartbeat (`heartbeat_ack` message):** The relay periodically sends any unsynced routines — these are routines created mid-session.
557
+
558
+ Both deliver routine objects with all fields: `id`, `name`, `instruction`, `cron_expression`, `status`, `frequency`, `timezone`, `schedule_human`, `description`, `openclaw_cron_id`, `created_by`.
559
+
560
+ **What to do:** Same as `[system:routine_created]` — create or update the cron job and confirm sync. If `openclaw_cron_id` is present, this is an update to an existing routine.
561
+
562
+ ### When YOU Create Cron Jobs
563
+
564
+ If you create a cron job independently (not from an app routine message):
565
+ 1. Create the cron job as usual
566
+ 2. **Immediately call `clawaxis_notify_routine`** to register it in the app
567
+ 3. The user should ALWAYS see every cron job you have running
568
+
569
+ **Rule:** Never have a cron job running that isn't visible in the app. Full transparency.
570
+
571
+ ---
572
+
573
+ ## Document Management
574
+
575
+ Documents are files the user creates and manages in the ClawAxis app (style guides, reference materials, knowledge bases, etc.). They're synced to your workspace and indexed in memory for search.
576
+
577
+ ### How Documents Reach You
578
+
579
+ Documents arrive through **two paths**, just like routines:
580
+
581
+ 1. **Via sync/heartbeat:** When you connect (or on each heartbeat), the relay sends any documents where `synced_at IS NULL`. Each document includes: `id`, `name`, `content`, `doc_type`, `category`, `tags`, `description`, `version`, `storage_path`, `agent_skill_path`.
582
+
583
+ 2. **Via chat message:** The plugin writes the document to your workspace and dispatches a short notification message to you. You do NOT receive the full document content in the message — only metadata and the file path. Read the file if you need the content.
584
+
585
+ ### Document Lifecycle
586
+
587
+ ```
588
+ User creates/edits document in app
589
+
590
+ Plugin writes file to memory/docs/{category}/{slug}.md
591
+ (with YAML frontmatter for searchability)
592
+
593
+ Plugin dispatches notification to agent:
594
+ [DOC_UPLOADED] — new document
595
+ [DOC_UPDATED] — edited document (includes version number)
596
+
597
+ Agent reads file if needed, confirms sync:
598
+ clawaxis_confirm_doc_sync(document_id: "...", agent_skill_path: "...")
599
+
600
+ Relay marks document as synced (sets synced_at, agent_skill_path)
601
+ ```
602
+
603
+ ### Where Documents Are Stored
604
+
605
+ Documents are written to your workspace under `memory/docs/{category}/{slug}.md`. This path is inside OpenClaw's memory directory, so the file is **automatically indexed by vector search** — you can find it with `memory_search` without any extra setup.
606
+
607
+ **Example file structure:**
608
+ ```
609
+ ~/.openclaw/workspace/memory/docs/
610
+ ├── branding/
611
+ │ └── brand-voice-guide.md
612
+ ├── reference/
613
+ │ └── competitor-analysis.md
614
+ └── general/
615
+ └── project-overview.md
616
+ ```
617
+
618
+ Each file has YAML frontmatter:
619
+ ```yaml
620
+ ---
621
+ title: "Brand Voice Guide"
622
+ type: style_guide
623
+ category: branding
624
+ tags: [voice, tone, brand]
625
+ description: "How to write in the company's voice"
626
+ version: 1
627
+ synced: 2026-02-09T12:00:00.000Z
628
+ ---
629
+
630
+ # Brand Voice Guide
631
+
632
+ (document content follows...)
633
+ ```
634
+
635
+ ### Document Notification Messages
636
+
637
+ **`[DOC_UPLOADED]`** — A new document was saved to your workspace.
638
+ ```
639
+ [DOC_UPLOADED] The user uploaded a new document: "Brand Voice Guide".
640
+ Type: style_guide | Category: branding | Tags: voice, tone, brand.
641
+ Saved to: /path/to/memory/docs/branding/brand-voice-guide.md.
642
+ This file is now searchable via memory_search. Read it with the read tool
643
+ if you want to review. Confirm sync by calling clawaxis_confirm_doc_sync
644
+ with document_id: <UUID>.
645
+ ```
646
+
647
+ **What to do:**
648
+ 1. Optionally read the file if you want to review it
649
+ 2. Confirm sync: `clawaxis_confirm_doc_sync(document_id: "<UUID>")`
650
+ 3. Reply to the user acknowledging the document
651
+
652
+ **`[DOC_UPDATED]`** — An existing document was updated on disk.
653
+ ```
654
+ [DOC_UPDATED] The user updated document "Brand Voice Guide" (v2).
655
+ File updated at: /path/to/memory/docs/branding/brand-voice-guide.md.
656
+ Read it with the read tool if you need to review the changes.
657
+ Confirm sync by calling clawaxis_confirm_doc_sync with document_id: <UUID>.
658
+ ```
659
+
660
+ **What to do:**
661
+ 1. Read the file to see what changed (if relevant to your current work)
662
+ 2. Confirm sync: `clawaxis_confirm_doc_sync(document_id: "<UUID>")`
663
+ 3. Reply acknowledging the update
664
+
665
+ **`[DOC_DELETED]`** — The user deleted a document. The file has been removed from disk.
666
+ ```
667
+ [DOC_DELETED] The user deleted document "Brand Voice Guide"
668
+ (was at: /path/to/memory/docs/branding/brand-voice-guide.md).
669
+ The file has been removed from your workspace.
670
+ Memory search will no longer return results from this document.
671
+ ```
672
+
673
+ **What to do:**
674
+ 1. Acknowledge the deletion
675
+ 2. No sync confirmation needed — the document is already gone
676
+
677
+ ### Using Documents in Your Work
678
+
679
+ Documents in `memory/docs/` are automatically searchable. When the user asks you to "write in our brand voice" or "follow the style guide," you can:
680
+
681
+ 1. **Search memory:** `memory_search("brand voice style guide")` — returns relevant snippets
682
+ 2. **Read the full file:** `read("/path/to/memory/docs/branding/brand-voice-guide.md")`
683
+ 3. **Apply the guidelines** to your content
684
+
685
+ The governance system also automatically searches memory for style documents when you use content or image tools (Layer 2: Style Injection). So brand guidelines are often injected automatically.
686
+
687
+ ---
688
+
689
+ ## Token Tracking
690
+
691
+ Token usage is tracked automatically. You don't need to do anything special, but understanding how it works helps you provide better data.
692
+
693
+ ### How It Works
694
+
695
+ ```
696
+ Plugin (your runtime)
697
+ ↓ per-reply: tokens_used delta
698
+ ↓ per-heartbeat: accumulated session tokens
699
+
700
+ ws-relay
701
+ ↓ calls increment_agent_tokens() RPC on every reply
702
+
703
+ Database
704
+ ├── agents.tokens_used_today (daily counter, auto-resets)
705
+ ├── agents.total_tokens_used (lifetime counter)
706
+ ├── agents.cost_today (estimated from model_pricing)
707
+ ├── agents.total_cost (lifetime cost)
708
+ └── token_usage_daily (daily aggregates for the 7-day chart)
709
+ ```
710
+
711
+ ### What Gets Tracked
712
+
713
+ | Source | What | Where Stored |
714
+ |---|---|---|
715
+ | Every agent reply | `tokens_used` from the reply message | `messages.tokens_used` + agents counters + daily aggregate |
716
+ | Every log entry | `tokens_used` from `clawaxis_post_log` | `session_logs.tokens_used` |
717
+ | Heartbeat (60s) | Accumulated session tokens (delta since last heartbeat) | agents counters + daily aggregate |
718
+
719
+ ### Cost Estimation
720
+
721
+ Cost is estimated automatically from the `model_pricing` table using the `model_used` field you send with each reply. The system assumes a 70/30 input/output token split. If the model isn't found in the pricing table, cost is recorded as $0.
722
+
723
+ ### What the User Sees
724
+
725
+ On the Home Dashboard:
726
+ - **Tokens Used Today** — from `agents.tokens_used_today`
727
+ - **Cost Today** — from `agents.cost_today`
728
+ - **7-Day Usage Chart** — from `token_usage_daily` table
729
+ - **Lifetime Stats** — from `agents.total_tokens_used` and `agents.total_cost`
730
+
731
+ Budget controls:
732
+ - `daily_token_budget` and `daily_cost_budget` set limits
733
+ - The app shows warnings when usage approaches the budget
734
+ - Counters auto-reset at `budget_reset_at` (midnight UTC by default)
735
+
736
+ ### What You Should Do
737
+
738
+ 1. **Always provide `tokens_used` in logs** when reporting significant operations
739
+ 2. **Include `model_used`** in your replies so cost estimation works
740
+ 3. **Log tool calls with `tokens_used`** so the user sees accurate resource consumption
741
+
742
+ ---
743
+
744
+ ## Image Generation & Media
745
+
746
+ ### Blog Image Best Practice
747
+
748
+ When creating blog or website content, generating a hero image significantly improves the content's visual appeal.
749
+
750
+ **Recommended Process:**
751
+ 1. Write the content
752
+ 2. Generate an image that represents the article's topic using your available image generation tools
753
+ 3. Upload to permanent storage with `clawaxis_upload_media` (temporary URLs from DALL-E etc. expire)
754
+ 4. Include the permanent URL in the `media` field, or embed directly in HTML body for `website` content
755
+ 5. For `website` content, update `og:image` meta tag with the permanent URL
756
+
757
+ **Image Style:** Check memory for brand style guides. The governance system automatically searches for image style docs when you use image tools (Layer 2: Style Injection). If the user has uploaded brand guidelines as a document, those will be injected into your image prompts automatically.
758
+
759
+ **Recommended Dimensions:**
760
+ | Use Case | Dimensions | Aspect Ratio |
761
+ |---|---|---|
762
+ | Blog hero / og:image | 1200×630 | 1.91:1 (landscape) |
763
+ | Instagram | 1080×1080 | 1:1 (square) |
764
+ | Twitter | 1200×675 | 16:9 (landscape) |
765
+ | TikTok | 1080×1920 | 9:16 (portrait) |
766
+ | YouTube thumbnail | 1280×720 | 16:9 (landscape) |
767
+
768
+ ### Permanent URLs
769
+
770
+ **Always upload images before posting content.** Temporary URLs from AI image generators (DALL-E, Stability, etc.) expire within hours. Use `clawaxis_upload_media` to get a permanent R2 URL first, then use that URL in your content.
771
+
772
+ ---
773
+
774
+ ## Website Content Type — Detailed Guide
775
+
776
+ The `website` content type produces deployable HTML files that render live in the app's WebView.
777
+
778
+ ### Getting Styling Information
779
+
780
+ **ALWAYS ask for context before generating website content:**
781
+
782
+ 1. **Web Link (Preferred):** "Share a link to your blog/site so I can match the styling."
783
+ - Use `browser` or `web_fetch` to load the page
784
+ - Extract HTML structure and CSS classes
785
+ - Generate new content that matches exactly
786
+
787
+ 2. **HTML Template:** "Do you have an existing page I can use as a template?"
788
+ - Analyze structure, identify key elements
789
+ - Generate content using same patterns
790
+
791
+ 3. **CSS Reference:** "Do you have a stylesheet URL I should reference?"
792
+ - Include `<link rel="stylesheet" href="path/to/style.css">` in head
793
+
794
+ ### Best Practices
795
+ - Match existing site structure — don't invent new patterns
796
+ - Include proper navigation and footer
797
+ - Use semantic HTML: `<article>`, `<header>`, `<nav>`, `<section>`
798
+ - Always include responsive design (viewport meta tag)
799
+ - Proper heading hierarchy, alt text, ARIA labels
800
+
801
+ ### When to Use Website vs Blog
802
+ - **`website`** — Deployable HTML file, styled to match their site, landing pages
803
+ - **`blog`** — Plain Markdown content, CMS drafts, content that will be styled later
804
+
805
+ ---
806
+
807
+ ## Common Workflow Patterns
808
+
809
+ ### After generating content
810
+ ```
811
+ 1. Log start: clawaxis_post_log(action: "content_generate", detail: "Starting research...", level: "info")
812
+ 2. Do the work
813
+ 3. Post to app: clawaxis_post_content(...)
814
+ 4. Log complete: clawaxis_post_log(action: "content_post", detail: "Posted report (850 words)", level: "success")
815
+ ```
816
+
817
+ ### Creating a cron job
818
+ ```
819
+ 1. Create cron: cron({ action: "add", job: {...} })
820
+ 2. Register: clawaxis_notify_routine(name, cron_expression, instruction, openclaw_cron_id, ...)
821
+ 3. Log: clawaxis_post_log(action: "cron_execute", detail: "Created routine: Daily AI News", level: "success")
822
+ ```
823
+
824
+ ### Modifying a cron job
825
+ ```
826
+ 1. Update cron: cron({ action: "update", jobId: "...", patch: {...} })
827
+ 2. Sync app: clawaxis_update_routine(routine_id: "...", cron_expression: "...", schedule_human: "...")
828
+ ```
829
+
830
+ ### When a document is uploaded
831
+ ```
832
+ 1. Receive: [DOC_UPLOADED] notification (file already written to workspace)
833
+ 2. Optionally: Read the file if you want to review it
834
+ 3. Confirm: clawaxis_confirm_doc_sync(document_id: "...")
835
+ 4. Reply: Acknowledge to the user
836
+ ```
837
+
838
+ ### When Logging
839
+
840
+ **DO log:**
841
+ - Starting any task that takes >5 seconds
842
+ - Installing dependencies or making system changes
843
+ - API calls or external requests
844
+ - Completing major steps
845
+ - Errors or warnings
846
+ - Resource usage (tokens, API calls, costs)
847
+
848
+ **DON'T log:**
849
+ - Reading small files (<100 lines)
850
+ - Simple calculations
851
+ - Internal micro-steps
852
+ - Every single thought process
853
+
854
+ **Golden rule:** If the user might wonder "is it still working?", log it.
855
+
856
+ ---
857
+
858
+ ## Quick Reference: All Valid Enum Values
859
+
860
+ ### content_type (for clawaxis_post_content)
861
+ | Value | Body Format | Notes |
862
+ |---|---|---|
863
+ | `twitter` | Plain text | 280 char max |
864
+ | `instagram` | Plain text | 2200 char max, tags → #hashtags |
865
+ | `linkedin` | Plain text | 3000 char max |
866
+ | `facebook` | Plain text | No limit |
867
+ | `tiktok` | Plain text | 4000 char max, tags → #hashtags |
868
+ | `youtube` | Plain text | 5000 char max, title shown as video title |
869
+ | `website` | Raw HTML | Rendered in WebView |
870
+ | `blog` | Markdown | Show word_count, tags, seo_keywords |
871
+ | `report` | Markdown | Show word_count, tags, seo_keywords |
872
+ | `email` | Markdown | |
873
+ | `ad` | Markdown | |
874
+ | `document` | Markdown | Can be transferred to Documents registry |
875
+ | `other` | Markdown | Catch-all |
876
+
877
+ ### log_action (for clawaxis_post_log)
878
+ `chat_message` · `content_generate` · `content_post` · `web_search` · `web_fetch` · `browser_action` · `cron_execute` · `skill_update` · `file_operation` · `system` · `error` · `tool_call`
879
+
880
+ ### log_level (for clawaxis_post_log)
881
+ `info` · `success` · `warning` · `error`
882
+
883
+ ### routine_status
884
+ `active` · `paused` · `disabled`
885
+
886
+ ### routine_frequency
887
+ `once` · `hourly` · `daily` · `weekly` · `monthly` · `custom`
888
+
889
+ **These are database enums. Using invalid values causes a 500 error. Always use values from these lists.**
890
+
891
+ ---
892
+
893
+ ## Troubleshooting
894
+
895
+ ### Content Posting Issues
896
+
897
+ **Problem: 500 error on content_type**
898
+ - Ensure using a valid enum value from the list above
899
+ - NOT valid: `article`, `post`, `marketing`, `newsletter` — use `blog`, `email`, or `other`
900
+
901
+ **Problem: Content not appearing in app**
902
+ - Check content was actually posted (no error returned)
903
+ - Verify `content_type` is a valid enum value
904
+ - Pull to refresh in the app
905
+
906
+ **Problem: Images not showing**
907
+ - Verify `media` structure: `{"images": [{"url": "...", "alt": "..."}], "videos": []}`
908
+ - Check image URL is accessible and not expired
909
+ - For website content, images can be embedded directly in HTML body
910
+
911
+ **Problem: Content renders as plain text instead of Markdown**
912
+ - Check `content_type` is set to `blog`, `report`, `email`, `ad`, `document`, or `other`
913
+ - If you set it to a social platform type, body renders as plain text only
914
+
915
+ **Problem: Content renders in wrong card**
916
+ - The `content_type` alone determines the card. Double-check the value.
917
+ - `blog` renders as Markdown. `website` renders as HTML. `twitter` renders as a tweet.
918
+
919
+ ### Routine Sync Issues
920
+
921
+ **Problem: Cron job created but not showing in app**
922
+ - Always call `clawaxis_notify_routine` after creating a cron job
923
+ - Include `openclaw_cron_id` from the cron creation result
924
+
925
+ **Problem: Routine shows wrong schedule**
926
+ - Call `clawaxis_update_routine` with correct `cron_expression` and `schedule_human`
927
+ - Include `next_run_at` as ISO 8601 timestamp
928
+
929
+ ### Image Generation Issues
930
+
931
+ **Problem: Generated image URL doesn't work after posting**
932
+ - AI-generated image URLs (DALL-E, Stability, etc.) are time-limited (2-24 hours)
933
+ - **Always upload to R2 first** with `clawaxis_upload_media`, then use the permanent URL
934
+
935
+ ---
936
+
937
+ ## WebSocket Connection
938
+
939
+ The plugin connects to the ws-relay via WebSocket (persistent, real-time). This is the primary transport for all tools. If WebSocket is unavailable, tools automatically fall back to HTTP via agent-relay.
940
+
941
+ **The connection lifecycle:**
942
+ 1. Connect → authenticate with agent token → receive `auth_ok`
943
+ 2. Receive `sync` with any pending documents/routines/undelivered messages
944
+ 3. Send `ping` every 30s, `heartbeat` every 60s
945
+ 4. Heartbeat responses include pending docs/routines (mid-session uploads)
946
+ 5. Connection auto-closes after ~400s (Supabase limit) → plugin auto-reconnects
947
+
948
+ **Tools that always use HTTP** (not WebSocket):
949
+ - `clawaxis_get_content` — needs synchronous response with data
950
+ - `clawaxis_upload_media` — binary/large payloads
951
+
952
+ ---
953
+
954
+ **Remember:** This documentation is for YOU (future agent sessions). The tool descriptions in the plugin also contain this information, but this file is the comprehensive reference. Keep it updated as features change.