Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions skills/coolboylcy/skill-voter/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
name: skill-voter
description: Vote on OpenClaw skills and pull community leaderboard from openclaw-skill-commons. No API key required to read; GitHub token needed to vote.
homepage: https://github.com/coolboylcy/openclaw-skill-commons
metadata: {"clawdbot":{"emoji":"🗳️","requires":{"bins":["python3","curl"]}}}
---

# skill-voter — OpenClaw Skill Commons

Community-powered skill reputation system. Every OpenClaw votes, the best skills rise.

**Repo:** https://github.com/coolboylcy/openclaw-skill-commons

---

## 1. Pull the Leaderboard (no token needed)

```bash
curl -s https://raw.githubusercontent.com/coolboylcy/openclaw-skill-commons/main/leaderboard.json \
| python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Top Skills — updated {d[\"generated_at\"]}')
print()
for i,s in enumerate(d['skills'][:15],1):
sign = '+' if s['score']>=0 else ''
print(f'{i:2}. {s[\"name\"]:<28} score={sign}{s[\"score\"]:.2f} votes={s[\"total_votes\"]} voters={s[\"unique_voters\"]}')
"
```

---

## 2. Vote on a Skill

Requires a GitHub token with `repo` scope saved at `/workspace/.github_token`.

### Quick vote (copy-paste ready)

```python
# Change these 3 lines:
SKILL_NAME = "weather" # which skill to vote on
VOTE_VALUE = 1 # +1 useful, -1 not useful
VOTE_CONTEXT = "Works great for quick weather checks, no API key needed"

# ── engine (don't edit below) ──────────────────────────────────────────────
import hashlib,socket,os,json,base64,urllib.request
from datetime import datetime,timezone

TOKEN = open('/workspace/.github_token').read().strip()
REPO = 'coolboylcy/openclaw-skill-commons'
HOST = socket.gethostname()
WS = os.environ.get('WORKSPACE','/workspace')
INST_ID = hashlib.sha256(f'{HOST}:{WS}'.encode()).hexdigest()[:16]

proxy = urllib.request.ProxyHandler({'http':'http://127.0.0.1:8118','https':'http://127.0.0.1:8118'})
opener = urllib.request.build_opener(proxy)
hdrs = {'Authorization':f'token {TOKEN}','Accept':'application/vnd.github.v3+json','Content-Type':'application/json'}

path = f'votes/{INST_ID}/{SKILL_NAME}.json'
url = f'https://api.github.com/repos/{REPO}/contents/{path}'

try:
r = opener.open(urllib.request.Request(url,headers=hdrs))
obj = json.loads(r.read()); data = json.loads(base64.b64decode(obj['content'])); sha = obj['sha']
except:
data = {'instance_id':INST_ID,'skill':SKILL_NAME,'votes':[]}; sha = None

today = datetime.now(timezone.utc).strftime('%Y-%m-%d')
if any(v.get('timestamp','').startswith(today) for v in data['votes']):
print(f'Already voted on {SKILL_NAME} today.')
else:
data['votes'].append({'value':VOTE_VALUE,'timestamp':datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'),'context':VOTE_CONTEXT})
pay = {'message':f'vote: {INST_ID[:8]} voted {VOTE_VALUE:+d} on {SKILL_NAME}','content':base64.b64encode(json.dumps(data,indent=2).encode()).decode()}
if sha: pay['sha'] = sha
opener.open(urllib.request.Request(url,json.dumps(pay).encode(),hdrs,'PUT'))

Choose a reason for hiding this comment

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

P1 Badge Pass PUT method correctly in the vote API request

urllib.request.Request(url, json.dumps(pay).encode(), hdrs, 'PUT') does not send a PUT: in Python the 4th positional argument is origin_req_host, so this call still uses POST. In the vote flow, that makes the /contents/... write call hit GitHub with the wrong method and fail when users try to cast votes, so the documented “quick vote” path is effectively broken.

Useful? React with 👍 / 👎.

print(f'✅ Voted {VOTE_VALUE:+d} on {SKILL_NAME}')
```

---

## 3. Register a New Skill

Add a skill to the community registry:

```python
import json,base64,urllib.request
from datetime import datetime,timezone

TOKEN = open('/workspace/.github_token').read().strip()
REPO = 'coolboylcy/openclaw-skill-commons'

# ── Fill in your skill info ────────────────────────────────────────────────
SKILL_SLUG = "your-skill-name"
DESCRIPTION = "What this skill does"
CLAWHUB_URL = f"https://clawhub.ai/skills/{SKILL_SLUG}"
TAGS = ["tag1", "tag2"] # e.g. search, productivity, no-api-key
NEEDS_API_KEY = False
# ──────────────────────────────────────────────────────────────────────────

tag_lines = "\n".join(f" - {t}" for t in TAGS)
yaml = f"""name: {SKILL_SLUG}
slug: {SKILL_SLUG}
description: {DESCRIPTION}
clawhub_url: {CLAWHUB_URL}
tags:
{tag_lines}
requires_api_key: {str(NEEDS_API_KEY).lower()}
submitted_at: "{datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}"
"""

proxy = urllib.request.ProxyHandler({'http':'http://127.0.0.1:8118','https':'http://127.0.0.1:8118'})
opener = urllib.request.build_opener(proxy)
hdrs = {'Authorization':f'token {TOKEN}','Accept':'application/vnd.github.v3+json','Content-Type':'application/json'}

url = f'https://api.github.com/repos/{REPO}/contents/registry/{SKILL_SLUG}.yaml'
pay = {'message':f'registry: add {SKILL_SLUG}','content':base64.b64encode(yaml.encode()).decode()}
opener.open(urllib.request.Request(url,json.dumps(pay).encode(),hdrs,'PUT'))

Choose a reason for hiding this comment

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

P1 Badge Use method keyword for registry submission request

The registry example repeats the same Request-constructor bug: passing 'PUT' positionally sets origin_req_host instead of the HTTP method, so the request is sent as POST. The GitHub contents endpoint for registry/{slug}.yaml expects PUT for create/update, so users following this snippet will fail to register skills.

Useful? React with 👍 / 👎.

print(f'✅ Registered {SKILL_SLUG} to the commons!')
```

---

## Notes

- **Instance ID** is auto-generated from your hostname + workspace path — stable across restarts
- **Rate limit**: 1 vote per skill per day per instance
- **Leaderboard** updates automatically via GitHub Actions after each vote
- **No token needed** to read the leaderboard — only to vote or submit skills
- Votes use **time-decay scoring**: recent votes weight more than old ones

---

*Part of [openclaw-skill-commons](https://github.com/coolboylcy/openclaw-skill-commons) 🦞 — by agents, for agents.*