Skip to content

feat: preloaded skills + external-services category - #115

Merged
exiao merged 1 commit into
mainfrom
feat/preloaded-skills-reorg
Apr 30, 2026
Merged

feat: preloaded skills + external-services category#115
exiao merged 1 commit into
mainfrom
feat/preloaded-skills-reorg

Conversation

@exiao

@exiao exiao commented Apr 30, 2026

Copy link
Copy Markdown
Owner

Summary

Two-tier skill loading: 26 skills get preloaded: true in frontmatter so they always appear in the system prompt with full descriptions. Everything else is hidden behind category summaries. Requires the runtime change in exiao/hermes-agent#6.

New: external-services/ category

Consolidated all third-party service CLI skills into one category:

New name Old name Old location
porkbun-cli porkbun + 6 sub-skills devops/porkbun/
copilot-money-cli copilot-money finance/
appfigures-cli appfigures marketing/
dataforseo-cli dataforseo marketing/
google-ads-cli google-ads marketing/
meta-ads-cli meta-ads marketing/
prometheus-cli prometheus marketing/
higgsfield (recovered) creative/
stably-cli stably-cli devops/
firecrawl firecrawl coding/
bird-twitter bird-twitter marketing/
apple-search-ads Apple Search Ads marketing/

Preloaded skills (26)

All get preloaded: true in frontmatter:
web-search, recall, writer, plan, skill-creator, render-cli, sentry-debug, grok-search, mcporter, bloom-cli, babysit-pr, ralph-mode, firecrawl, stably-cli, porkbun-cli, copilot-money-cli, higgsfield, appfigures-cli, bird-twitter, apple-search-ads, dataforseo-cli, google-ads-cli, meta-ads-cli, prometheus-cli, last30days, dogfood

DESCRIPTION.md fixes

Fixed category DESCRIPTION.md files to use proper YAML frontmatter format so category descriptions appear in the system prompt.

Token impact

Metric Before After
System prompt tokens ~6,100 ~2,800
Entries model scans 266 26 preloaded + 30 category lines
Description quality Truncated 60 chars Full text

…ategory

Add 'preloaded: true' frontmatter to 25 skills that should always appear
in the system prompt with full descriptions. All other skills are hidden
behind category summaries.

New external-services/ category for CLI integrations:
- porkbun-cli (merged from porkbun + 6 sub-skills)
- copilot-money-cli (renamed from copilot-money)
- appfigures-cli (renamed from appfigures)
- dataforseo-cli (renamed from dataforseo)
- google-ads-cli (renamed from google-ads)
- meta-ads-cli (renamed from meta-ads)
- prometheus-cli (renamed from prometheus)
- higgsfield (found and added)
- stably-cli, firecrawl, bird-twitter, apple-search-ads (moved)

Also fixed DESCRIPTION.md files to use proper YAML frontmatter format
so category descriptions appear in the system prompt.

Works with the runtime change in exiao/hermes-agent#6 which adds
preloaded-aware rendering to build_skills_system_prompt().
@exiao
exiao merged commit f8c3ddc into main Apr 30, 2026
4 of 5 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds several new AI tools and CLI integrations, including Apple Search Ads, DataForSEO, Copilot Money, and Prometheus. It also updates existing skill descriptions to mark them as preloaded. My feedback focuses on improving the robustness of CSV parsing in shell scripts, correcting an API method in the Google Ads documentation, aligning JWT expiration times, and improving error handling and code maintainability in the provided scripts.


# Build JSON array from CSV (skip header if present)
local keywords_json="[]"
while IFS=',' read -r text match bid; do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The while IFS=',' read ... loop for parsing the CSV file is not robust. It will fail if any field, such as the keyword text, contains a comma. This could lead to incorrect data being processed or script failures. Consider using a more robust parsing method, like a small Python script with its csv module, which can handle quoted fields and commas within values correctly.

fi

local negatives_json="[]"
while IFS=',' read -r text match; do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to keywords.sh, the CSV parsing here using while IFS=',' read ... is fragile. It will break if the keyword text contains a comma. This can lead to unexpected behavior and data corruption. It's recommended to switch to a more robust CSV parser, for instance by using Python's csv module, to handle such edge cases properly.

const conversions = stats.getConversions();
const ctr = stats.getClickThroughRate(); // As decimal (0-1)
const cpc = stats.getAverageCpc(); // Average cost per click
const cpa = stats.getAveragePageviews(); // NOTE: check specific metric

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The example code incorrectly uses stats.getAveragePageviews() to retrieve the Cost Per Acquisition (CPA). The correct method is stats.getCostPerConversion(). This is a significant error in an API reference document that could lead to incorrect script implementations and flawed performance analysis.

Suggested change
const cpa = stats.getAveragePageviews(); // NOTE: check specific metric
const cpa = stats.getCostPerConversion(); // NOTE: check specific metric


# Create JWT payload
now=$(date +%s)
exp=$((now + 15552000)) # 180 days

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The JWT expiration time for the client secret is set to 180 days in this example script, but the implementation in scripts/asa-auth.sh uses a 1-hour expiration. While both are technically valid according to Apple's documentation, this inconsistency can be confusing. For better maintainability and security, it's recommended to align the documentation with the shorter, safer 1-hour expiration used in the actual script.

Suggested change
exp=$((now + 15552000)) # 180 days
exp=$((now + 3600)) # 1 hour

local body
body=$(_build_report_body "$start" "$end" "DAILY" "localSpend" "1000")
local response
response=$(asa_api POST "/reports/campaigns/${cid}/keywords" "$body") 2>/dev/null || continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Suppressing stderr with 2>/dev/null can hide important error messages from the asa_api function, such as authentication failures or invalid requests. While this might be intended to ignore campaigns without keyword data, it makes debugging other potential issues difficult. A better approach would be to handle specific error cases inside the loop or modify asa_api to support a quiet mode.

#### 5d — Generate Each Creative

```bash
GEMINI_API_KEY=$(python3 -c "import json, os; d=json.load(open(os.path.expanduser('~/.openclaw/openclaw.json'))); print(d.get('skills',{}).get('entries',{}).get('nano-banana-pro',{}).get('apiKey','') or d['env']['vars'].get('GEMINI_API_KEY',''))" 2>/dev/null)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This one-liner to extract the GEMINI_API_KEY is overly complex and hard to maintain. It attempts to read from a JSON configuration file with multiple fallbacks, all within a single shell command. This should be refactored into a dedicated helper script or function for clarity, testability, and easier debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant