Skills (#50)
Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
type PackagedSkillFile = {
|
||||
relativePath: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
// Keep this string synchronized with assets/skills/todo-board/SKILL.md.
|
||||
const TODO_BOARD_SKILL_MD = `---
|
||||
name: todo
|
||||
description: Maintain a shared workspace TODO list with blocked tasks.
|
||||
metadata: {"openclaw":{"skillKey":"todo-board"}}
|
||||
---
|
||||
|
||||
# TODO Board
|
||||
|
||||
Use this skill when the user wants to manage a shared task list for the current workspace.
|
||||
|
||||
## Trigger
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"activation": {
|
||||
"anyPhrases": [
|
||||
"todo",
|
||||
"todo list",
|
||||
"blocked task",
|
||||
"blocked tasks",
|
||||
"add to my todo",
|
||||
"show my todo"
|
||||
]
|
||||
},
|
||||
"movement": {
|
||||
"target": "desk",
|
||||
"skipIfAlreadyThere": true
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
When this skill is activated, the agent should return to its assigned desk before handling the request.
|
||||
|
||||
- If the user asks from Telegram or any other external surface to add, block, unblock, remove, or read TODO items, treat that as a trigger for this skill.
|
||||
- The physical behavior for this skill is: go sit at the assigned desk, then perform the TODO board workflow.
|
||||
- If the agent is already at the desk, continue without adding extra movement narration.
|
||||
|
||||
## Storage location
|
||||
|
||||
The authoritative task file is \`todo-skill/todo-list.json\` in the workspace root.
|
||||
|
||||
- Always treat that file as the source of truth.
|
||||
- Never rely on chat memory alone for the latest task state.
|
||||
- Create the \`todo-skill\` directory and \`todo-list.json\` file if they do not exist.
|
||||
|
||||
## Required workflow
|
||||
|
||||
1. Read \`todo-skill/todo-list.json\` before answering any task-management request.
|
||||
2. If the file does not exist, create it with the schema in this document before continuing.
|
||||
3. After every add, remove, block, or unblock action, write the full updated JSON back to disk.
|
||||
4. If the file exists but is invalid JSON or does not match the schema, repair it into a valid structure, preserve any recoverable items, and mention that repair in your response.
|
||||
5. If the user request is ambiguous, ask a clarifying question instead of guessing.
|
||||
|
||||
## Supported actions
|
||||
|
||||
- Add a task.
|
||||
Create a new item unless an equivalent active item already exists.
|
||||
- Block a task.
|
||||
Change the matching item to \`status: "blocked"\`. If the task does not exist and the request is clear, create it directly as blocked.
|
||||
- Unblock a task.
|
||||
Change the matching item back to \`status: "todo"\` and clear \`blockReason\`.
|
||||
- Remove a task.
|
||||
Delete only the matching item. If multiple items could match, ask for clarification.
|
||||
- Read the list.
|
||||
Summarize tasks grouped into \`TODO\` and \`BLOCKED\`.
|
||||
|
||||
## File format
|
||||
|
||||
Use this JSON shape:
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"version": 1,
|
||||
"updatedAt": "2026-03-22T00:00:00.000Z",
|
||||
"items": [
|
||||
{
|
||||
"id": "task-1",
|
||||
"title": "Example task",
|
||||
"status": "todo",
|
||||
"createdAt": "2026-03-22T00:00:00.000Z",
|
||||
"updatedAt": "2026-03-22T00:00:00.000Z",
|
||||
"blockReason": null
|
||||
}
|
||||
]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Field rules
|
||||
|
||||
- Keep \`version\` at \`1\`.
|
||||
- Generate stable, human-readable IDs such as \`prepare-demo\` or \`task-2\`.
|
||||
- Keep titles concise and preserve the user's intent.
|
||||
- Use only \`todo\` or \`blocked\` for \`status\`.
|
||||
- Use ISO timestamps for \`createdAt\`, item \`updatedAt\`, and top-level \`updatedAt\`.
|
||||
- Keep \`blockReason\` as \`null\` unless the user gave a reason or a short precise reason is clearly implied.
|
||||
|
||||
## Mutation rules
|
||||
|
||||
- Avoid duplicate active items that describe the same work.
|
||||
- Preserve existing IDs and \`createdAt\` values for unchanged items.
|
||||
- Update the touched item's \`updatedAt\` whenever you modify it.
|
||||
- Update the top-level \`updatedAt\` on every write.
|
||||
- Keep untouched items in their original order unless there is a strong reason to reorder them.
|
||||
|
||||
## Response style
|
||||
|
||||
- After each mutation, say what changed.
|
||||
- When showing the list, group tasks into \`TODO\` and \`BLOCKED\`.
|
||||
- Include each blocked task's reason when one exists.
|
||||
`;
|
||||
|
||||
// Keep this string synchronized with assets/skills/todo-board/todo-list.example.json.
|
||||
const TODO_BOARD_EXAMPLE_JSON = `{
|
||||
"version": 1,
|
||||
"updatedAt": "2026-03-22T00:00:00.000Z",
|
||||
"items": [
|
||||
{
|
||||
"id": "draft-roadmap",
|
||||
"title": "Draft the TODO skill roadmap",
|
||||
"status": "todo",
|
||||
"createdAt": "2026-03-22T00:00:00.000Z",
|
||||
"updatedAt": "2026-03-22T00:00:00.000Z",
|
||||
"blockReason": null
|
||||
},
|
||||
{
|
||||
"id": "gateway-access",
|
||||
"title": "Confirm gateway install access",
|
||||
"status": "blocked",
|
||||
"createdAt": "2026-03-22T00:00:00.000Z",
|
||||
"updatedAt": "2026-03-22T00:00:00.000Z",
|
||||
"blockReason": "Waiting for gateway credentials"
|
||||
}
|
||||
]
|
||||
}
|
||||
`;
|
||||
|
||||
const PACKAGED_SKILL_FILES: Record<string, PackagedSkillFile[]> = {
|
||||
"todo-board": [
|
||||
{
|
||||
relativePath: "SKILL.md",
|
||||
content: TODO_BOARD_SKILL_MD,
|
||||
},
|
||||
{
|
||||
relativePath: "todo-list.example.json",
|
||||
content: TODO_BOARD_EXAMPLE_JSON,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const readPackagedSkillFiles = (packageId: string): PackagedSkillFile[] => {
|
||||
const files = PACKAGED_SKILL_FILES[packageId];
|
||||
if (!files || files.length === 0) {
|
||||
throw new Error(`Packaged skill assets are missing: ${packageId}`);
|
||||
}
|
||||
if (!files.some((file) => file.relativePath === "SKILL.md")) {
|
||||
throw new Error(`Packaged skill is missing SKILL.md: ${packageId}`);
|
||||
}
|
||||
return files.map((file) => ({ ...file }));
|
||||
};
|
||||
Reference in New Issue
Block a user