Files
hermes-skills/gitea/SKILL.md

152 lines
7.1 KiB
Markdown

---
name: gitea
description: "Push Hermes skill updates to the local Gitea instance at 10.0.0.61:3000. Clone, copy, commit, push workflow."
version: 1.3.0
author: Hermes Agent
license: MIT
platforms: [linux]
metadata:
hermes:
tags: [gitea, git, skills, push, version-control]
---
# Gitea — Local Git Hosting for Hermes Skills
Push skill updates to the local Gitea instance at `http://10.0.0.61:3000`.
## Quick Reference
| Setting | Value |
|---------|-------|
| URL | `http://10.0.0.61:3000` |
| Repo | `SpeedyFoxAi/hermes-skills` |
| Clone URL | `http://10.0.0.61:3000/SpeedyFoxAi/hermes-skills.git` |
| Auth URL | `http://TOKEN@10.0.0.61:3000/SpeedyFoxAi/hermes-skills.git` |
| Token | `2c6cacb89b8124a98a52206fdbee51cefcd46844` |
| Local clone | `/tmp/hermes-skills` |
| Skill source | `~/.hermes/profiles/<profile>/skills/` (any profile — general, research, dev, etc.) |
## Versioning
Every skill in the repo MUST have a `version:` field in its YAML frontmatter.
Before pushing, always check and bump the version:
| Change type | Bump | Example |
|---|---|---|
| Fixes, clarifications, pitfall additions | patch | 1.0.0 → 1.0.1 |
| New features, new sections, new references | minor | 1.0.0 → 1.1.0 |
| Rewrites, major restructuring | major | 1.0.0 → 2.0.0 |
## Workflow
### Push Updated Skills
```bash
# 1. Clone (or pull if already cloned)
cd /tmp && git clone http://10.0.0.61:3000/SpeedyFoxAi/hermes-skills.git
# Or: cd /tmp/hermes-skills && git pull origin main
# 2. Copy updated skill files from the active profile
cp ~/.hermes/profiles/general/skills/<category>/<skill-name>/SKILL.md /tmp/hermes-skills/<skill-name>/SKILL.md
# 3. Bump the version in the copied SKILL.md frontmatter
# Edit /tmp/hermes-skills/<skill-name>/SKILL.md and increment version:
# - patch: fixes, clarifications, pitfall additions
# - minor: new features, new sections, new references
# - major: rewrites, major restructuring
# 4. Commit with version in message
cd /tmp/hermes-skills
git add <skill-name>/SKILL.md
git commit -m "<skill-name>: v<new-version> — <brief description>"
# 5. Push with token
git remote set-url origin http://2c6cacb89b8124a98a52206fdbee51cefcd46844@10.0.0.61:3000/SpeedyFoxAi/hermes-skills.git
git push origin main
```
### Add a New Skill to the Repo
```bash
cd /tmp/hermes-skills
mkdir <skill-name>
cp ~/.hermes/profiles/general/skills/<category>/<skill-name>/SKILL.md <skill-name>/SKILL.md
# Verify the SKILL.md has a version: field in its frontmatter.
# New skills should start at 1.0.0.
git add <skill-name>/
git commit -m "Add <skill-name> v1.0.0"
git push origin main
```
## Pre-Push Token Validation (MANDATORY — before every push)
Tokens expire, get rotated, or are revoked. Always validate the token BEFORE attempting a push:
```bash
# Test token validity — 200 = valid, 401 = stale/rotated
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token <TOKEN>" \
http://10.0.0.61:3000/api/v1/user
```
If 401, stop and ask the user for a new token. Do NOT attempt the push — it will fail and the error messages are misleading ("could not read Password", "terminal prompts disabled", "Authentication failed").
## Pitfalls
- **Token in URL is required for push.** The repo is public-read but write-protected. Always set the remote URL with the token before pushing: `git remote set-url origin http://TOKEN@10.0.0.61:3000/SpeedyFoxAi/hermes-skills.git`
- **Token-in-URL may fail with "could not read Password".** Some git configurations ignore the password in the URL and still prompt. If `git push http://TOKEN@host/repo.git` fails, try `git -c credential.helper= -c credential.helper='!f() { echo "username=token"; echo "password=TOKEN"; }; f' push origin main`. If that also fails, the token itself is likely stale — validate it first with the curl check above.
- **Hardcoded token in this skill is a convenience, not a guarantee.** The token `2c6cacb89b8124a98a52206fdbee51cef46844` was valid at skill creation time but may have been rotated since. Always run the pre-push curl validation before relying on it.
- **Git identity must be set.** The clone in `/tmp` won't have user.email/user.name configured. Set them before committing: `git config user.email "n8n@hermes-main.local" && git config user.name "Hermes Agent"`
- **Skill directory names in the repo are flat** — e.g. `ask-claude/SKILL.md`, not `autonomous-ai-agents/ask-claude/SKILL.md`. The category hierarchy exists in `~/.hermes/profiles/general/skills/` but the Gitea repo uses flat skill names.
- **Clone is disposable.** `/tmp/hermes-skills` is a working copy. Don't store anything there you need to keep. Re-clone if the directory is missing or stale.
- **No credential helper needed.** The token-in-URL pattern works for one-shot pushes. Don't store the token in git config or credential files.
- **Cross-profile pushes require `cross_profile=True`.** When pushing skills from the research profile (or any non-general profile), the write_file guard will block. Pass `cross_profile=True` to bypass. The Gitea repo is the canonical store for ALL profiles' skills, not just general.
- **New skills need a `version:` field.** If a skill is missing `version:` in its YAML frontmatter, add `version: 1.0.0` before pushing. The Gitea repo requires it.
## Sync Audit (Check All Skills Are Versioned and in Gitea)
Use this Python script to cross-reference all local skills against Gitea:
```python
import os, re
skills_dir = "/home/n8n/.hermes/profiles/general/skills"
skills = []
for root, dirs, files in os.walk(skills_dir):
if "SKILL.md" in files:
path = os.path.join(root, "SKILL.md")
content = open(path).read()
name = re.search(r'^name:\s*(.+)$', content, re.MULTILINE)
version = re.search(r'^version:\s*(.+)$', content, re.MULTILINE)
name = name.group(1).strip() if name else os.path.basename(root)
version = version.group(1).strip() if version else "unknown"
skills.append((name, version, path))
gitea_dir = "/tmp/hermes-skills"
gitea_skills = set()
gitea_versions = {}
for entry in os.listdir(gitea_dir):
skill_path = os.path.join(gitea_dir, entry, "SKILL.md")
if os.path.isfile(skill_path):
content = open(skill_path).read()
gname = re.search(r'^name:\s*(.+)$', content, re.MULTILINE)
gversion = re.search(r'^version:\s*(.+)$', content, re.MULTILINE)
gname = gname.group(1).strip() if gname else entry
gversion = gversion.group(1).strip() if gversion else "unknown"
gitea_skills.add(gname)
gitea_versions[gname] = gversion
for name, version, path in sorted(skills):
in_gitea = "" if name in gitea_skills else "✗ MISSING"
gitea_ver = gitea_versions.get(name, "")
ver_match = "" if version == gitea_ver else f"✗ (local:{version} vs gitea:{gitea_ver})"
print(f" {name:40s} v{version:10s} gitea:{in_gitea:12s} version:{ver_match}")
```
Run this after any batch of skill changes. Fix issues:
- **Missing `version:`** → add `version: 1.0.0` to the skill's YAML frontmatter
- **Missing from Gitea** → `mkdir` the directory and copy the SKILL.md
- **Version mismatch** → copy the updated local SKILL.md to Gitea