feat: audit fixes and documentation improvements
- Refactored model selection to drop legacy fallback and add warning - Improved heartbeat content validation - Added Skill Creation guide - Updated CONTRIBUTING.md with roadmap
This commit is contained in:
parent
003fff067a
commit
f3991055fa
@ -40,3 +40,13 @@ Please include in your PR:
|
|||||||
- [ ] Confirm you understand what the code does
|
- [ ] Confirm you understand what the code does
|
||||||
|
|
||||||
AI PRs are first-class citizens here. We just want transparency so reviewers know what to look for.
|
AI PRs are first-class citizens here. We just want transparency so reviewers know what to look for.
|
||||||
|
|
||||||
|
## Current Focus & Roadmap 🗺
|
||||||
|
|
||||||
|
We are currently prioritizing:
|
||||||
|
- **Stability**: Fixing edge cases in channel connections (WhatsApp/Telegram).
|
||||||
|
- **UX**: Improving the onboarding wizard and error messages.
|
||||||
|
- **Skills**: Expanding the library of bundled skills and improving the Skill Creation developer experience.
|
||||||
|
- **Performance**: Optimizing token usage and compaction logic.
|
||||||
|
|
||||||
|
Check the [GitHub Issues](https://github.com/clawdbot/clawdbot/issues) for "good first issue" labels!
|
||||||
|
|||||||
41
docs/tools/creating-skills.md
Normal file
41
docs/tools/creating-skills.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Creating Custom Skills 🛠
|
||||||
|
|
||||||
|
Clawdbot is designed to be easily extensible. "Skills" are the primary way to add new capabilities to your assistant.
|
||||||
|
|
||||||
|
## What is a Skill?
|
||||||
|
A skill is a directory containing a `SKILL.md` file (which provides instructions and tool definitions to the LLM) and optionally some scripts or resources.
|
||||||
|
|
||||||
|
## Step-by-Step: Your First Skill
|
||||||
|
|
||||||
|
### 1. Create the Directory
|
||||||
|
Skills live in your workspace, usually `~/clawd/skills/`. Create a new folder for your skill:
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/clawd/skills/hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Define the `SKILL.md`
|
||||||
|
Create a `SKILL.md` file in that directory. This file uses YAML frontmatter for metadata and Markdown for instructions.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
name: hello_world
|
||||||
|
description: A simple skill that says hello.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Hello World Skill
|
||||||
|
When the user asks for a greeting, use the `echo` tool to say "Hello from your custom skill!".
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Add Tools (Optional)
|
||||||
|
You can define custom tools in the frontmatter or instruct the agent to use existing system tools (like `bash` or `browser`).
|
||||||
|
|
||||||
|
### 4. Refresh Clawdbot
|
||||||
|
Ask your agent to "refresh skills" or restart the gateway. Clawdbot will discover the new directory and index the `SKILL.md`.
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
- **Be Concise**: Instruct the model on *what* to do, not how to be an AI.
|
||||||
|
- **Safety First**: If your skill uses `bash`, ensure the prompts don't allow arbitrary command injection from untrusted user input.
|
||||||
|
- **Test Locally**: Use `clawdbot agent --message "use my new skill"` to test.
|
||||||
|
|
||||||
|
## Shared Skills
|
||||||
|
You can also browse and contribute skills to [ClawdHub](https://clawdhub.com).
|
||||||
@ -137,7 +137,12 @@ export function resolveConfiguredModelRef(params: {
|
|||||||
aliasIndex,
|
aliasIndex,
|
||||||
});
|
});
|
||||||
if (resolved) return resolved.ref;
|
if (resolved) return resolved.ref;
|
||||||
// TODO(steipete): drop this fallback once provider-less agents.defaults.model is fully deprecated.
|
|
||||||
|
// Default to anthropic if no provider is specified, but warn as this is deprecated.
|
||||||
|
console.warn(
|
||||||
|
`[clawdbot] Model "${trimmed}" specified without provider. Falling back to "anthropic/${trimmed}". ` +
|
||||||
|
`Please use "anthropic/${trimmed}" in your config.`,
|
||||||
|
);
|
||||||
return { provider: "anthropic", model: trimmed };
|
return { provider: "anthropic", model: trimmed };
|
||||||
}
|
}
|
||||||
return { provider: params.defaultProvider, model: params.defaultModel };
|
return { provider: params.defaultProvider, model: params.defaultModel };
|
||||||
@ -153,20 +158,20 @@ export function resolveDefaultModelForAgent(params: {
|
|||||||
const cfg =
|
const cfg =
|
||||||
agentModelOverride && agentModelOverride.length > 0
|
agentModelOverride && agentModelOverride.length > 0
|
||||||
? {
|
? {
|
||||||
...params.cfg,
|
...params.cfg,
|
||||||
agents: {
|
agents: {
|
||||||
...params.cfg.agents,
|
...params.cfg.agents,
|
||||||
defaults: {
|
defaults: {
|
||||||
...params.cfg.agents?.defaults,
|
...params.cfg.agents?.defaults,
|
||||||
model: {
|
model: {
|
||||||
...(typeof params.cfg.agents?.defaults?.model === "object"
|
...(typeof params.cfg.agents?.defaults?.model === "object"
|
||||||
? params.cfg.agents.defaults.model
|
? params.cfg.agents.defaults.model
|
||||||
: undefined),
|
: undefined),
|
||||||
primary: agentModelOverride,
|
primary: agentModelOverride,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
}
|
||||||
: params.cfg;
|
: params.cfg;
|
||||||
return resolveConfiguredModelRef({
|
return resolveConfiguredModelRef({
|
||||||
cfg,
|
cfg,
|
||||||
@ -282,8 +287,8 @@ export function resolveAllowedModelRef(params: {
|
|||||||
}):
|
}):
|
||||||
| { ref: ModelRef; key: string }
|
| { ref: ModelRef; key: string }
|
||||||
| {
|
| {
|
||||||
error: string;
|
error: string;
|
||||||
} {
|
} {
|
||||||
const trimmed = params.raw.trim();
|
const trimmed = params.raw.trim();
|
||||||
if (!trimmed) return { error: "invalid model: empty" };
|
if (!trimmed) return { error: "invalid model: empty" };
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,8 @@ export function isHeartbeatContentEffectivelyEmpty(content: string | undefined |
|
|||||||
// This intentionally does NOT skip lines like "#TODO" or "#hashtag" which might be content
|
// This intentionally does NOT skip lines like "#TODO" or "#hashtag" which might be content
|
||||||
// (Those aren't valid markdown headers - ATX headers require space after #)
|
// (Those aren't valid markdown headers - ATX headers require space after #)
|
||||||
if (/^#+(\s|$)/.test(trimmed)) continue;
|
if (/^#+(\s|$)/.test(trimmed)) continue;
|
||||||
|
// Skip empty markdown list items like "- [ ]" or "* [ ]" or just "- "
|
||||||
|
if (/^[-*+]\s*(\[[\sXx]?\]\s*)?$/.test(trimmed)) continue;
|
||||||
// Found a non-empty, non-comment line - there's actionable content
|
// Found a non-empty, non-comment line - there's actionable content
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user