Skill tracker push pr
Git-backed oversight of your Hermes Agents' skills.
npx -y skills add cnuahs/skill-tracker --skill skill-tracker-push-prAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Push settled commits and create PRs. Collect settled commit groups across all configured repos, examine diffs, write PR titles/bodies, and submit PRs via cherry-pick.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
11.8 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it
Push Settled Commits and Create PRs
Overview
This skill takes commits that have accumulated on the agent's branches across your skill repos, groups them by skill, and creates pull requests for human review. It is the primary mechanism for promoting agent-made skill changes into the stable main branch.
Key concepts: Each tracked skill repo has an agent branch — a dedicated branch where all agent-made commits land (as opposed to main, the stable branch that humans review and merge into). The agent branch accumulates changes over time from self-improvement, curator passes, bundled sync, and direct agent edits. This skill reads those commits and creates PRs against main.
How it works end-to-end:
- Collect settled groups (scripted) —
collect.pyfetches each repo, groups settled commits by skill, deduplicates against existing PRs, and outputs JSON. - Examine diffs (agent) — For each group, read the actual code diffs to understand what changed and why.
- Write PR title and body (agent) — Summarize the changes based on the diffs, not commit message metadata.
- Create PR (scripted) —
push.pycreates a git worktree, cherry-picks commits, pushes, and opens a PR via the GitHub API. - Report results (agent) — Summarize which PRs were created and any failures.
When to Use
- Triggered by the skill-tracker-push-pr cron job (approximately every 6 hours)
- When the user asks to "push settled commits" or "create PRs for settled groups"
- When the user asks to run the workflow for a single repo or a specific skill
- After fixing a failed PR and wanting to retry
Rules
Do not modify scripts, skill files, or plugin files
The cron agent must NOT modify any file in $HERMES_HOME/plugins/skill-tracker/
or $HERMES_HOME/skills/skill-tracker/. Do not modify any of these
files. They are maintained separately and your changes will be overwritten.
If you encounter what looks like a bug, STOP and REPORT it. Do not work around it, patch the script, or improvise a fix. The correct response is to abort the run and describe the problem so a human (or a future session with explicit instructions) can fix it.
Prerequisites
skill-trackerplugin is installed and configured in$HERMES_HOME/config.yamlskill_tracker.reposlist in config.yaml has at least one valid repo entry- Each configured repo has a valid
originremote (or expliciturlin config) - Agent branch exists on each repo (created automatically by the plugin at registration time)
collect.py,group.py,push.py, and the shared modules (plugin/gitutils.py,plugin/config.py,plugin/gh_api.py,plugin/queries.py,plugin/commitmsg.py) existPyYAMLis available in the Python environment (required bycollect.pyfor reading config.yaml)token_envis configured inskill_trackerconfig and the referenced env var is set (for push/PR, dedup via GitHub API; the workflow works without it but skips dedup and may fail on private repos)
Finding the scripts: The scripts are in the scripts/ subdirectory of the skill-tracker plugin directory ($HERMES_HOME/plugins/skill-tracker/scripts/). All script paths below use <scripts-dir> to refer to this location.
Python environment: The scripts must run in the Hermes venv. Activate it in each terminal session before running the scripts, e.g.,
source /opt/hermes/.venv/bin/activate && python3 <scripts-dir>/collect.py --threshold 30
Workflow
Step 1: Collect Settled Groups
Run collect.py:
source /opt/hermes/.venv/bin/activate && python3 <scripts-dir>/collect.py --threshold 30
The script reads $HERMES_HOME/config.yaml, iterates over all configured repos, fetches their main branches, and outputs a JSON array of settled groups to stdout.
What the script does internally: For each repo, it fetches main from the remote, lists commits on the agent branch that are not yet on main (in chronological order), parses each commit's structured message, groups them by target skill using the configured strategy (default: contiguous), and filters out any commits whose UUID already appears in an existing PR (open or closed) via the GitHub API.
Output format — JSON array of groups:
[
{
"target": "hermes-agent",
"sources": ["agent"],
"settled_by": "interleaving",
"commits": [
{
"sha": "abc123def456...",
"action": "patch",
"target": "hermes-agent",
"uuid": "a1b2c3d4",
"source": "agent",
"time": "2026-01-15T10:30:00+00:00",
"outcome": "success",
"session": "sess-xyz",
"files": "skills/hermes-agent/SKILL.md"
}
],
"repo_path": "/opt/data/agent-skills",
"agent_branch": "agent/hermes-gateway",
"main_branch": "main",
"agent_name": "hermes-gateway",
"token_env": "<token_env>"
}
]
Error handling: If collect.py exits non-zero, log stderr and abort. Do not proceed with partial results.
Empty result: If the output is [], report "No settled groups found" and exit.
Step 2: Iterate Over Groups
For each group in the JSON output, perform Steps 3–6. Groups whose commits are already in an existing PR have been filtered out by collect.py — do not re-check.
Extract these fields from each group JSON:
repo_path— where to run git commandstarget— skill name (for PR title)commits[].sha— ordered SHAs to cherry-pickcommits[].action— action type (for PR body)commits[].files— changed files (for PR body)agent_name,main_branch,token_env— forpush.pyargs
Step 3: Examine Diffs
For each commit in the group, run git commands inside repo_path:
cd <repo_path>
# Full diff for a single commit
git show <sha>
If the group has multiple commits, also check the cumulative diff:
cd <repo_path>
# Cumulative diff from main to the last commit
git diff <main_branch>..<last-sha>
Use read_file on changed files (from the files field) for full context. Focus on:
- What changed (additions, modifications, deletions)
- Why the change was made (infer from the diffs themselves)
- Whether the changes are coherent and complete
Note: Commit messages contain structured metadata (action, source, outcome) but do not describe the changes or explain reasoning. The diffs are the source of truth for the PR body.
Step 4: Write PR Title
Write a concise PR title (under 72 characters):
<agent-name>: consolidate <N> changes to <skill-name>
Examples:
hermes-gateway: consolidate 4 agent changes to hermes-agenthermes-gateway: bundled-sync update to github-authhermes-gateway: unknown changes to agent-skills-synchermes-gateway: consolidate 2 changes to github-auth(single commit still uses "consolidate")
Step 5: Write PR Body
Base the PR body on the actual diffs from Step 3, not on commit message metadata. Include:
## Summary
<One paragraph summarizing what changed and why, based on the diffs.>
## Changes
- **<action>**: <what the diff shows> (`<short-sha>`, <file>)
- **<action>**: <what the diff shows> (`<short-sha>`, <file>)
## Files Changed
- `<file>`: <brief description of what changed>
- `<file>`: <brief description of what changed>
Action types and how to describe them:
patch: What was updated/improved and which filecreate: What was added and its purposeedit: What was revisedbundled-sync: Upstream update applied to the skillunknown: Changes observed in the diff (provenance unknown)
Step 6: Create the PR
Call push.py with the group's metadata:
source /opt/hermes/.venv/bin/activate && python3 <scripts-dir>/push.py <repo_path> \
--agent-name <agent_name> \
--target <target> \
--shas <sha1> <sha2> ... \
--title "<pr-title>" \
--body "<pr-body>" \
--main-branch <main_branch> \
--token-env <token_env>
The script will: fetch main, resolve the repo root (which may differ from repo_path if it's a subdirectory), generate a unique PR branch name (skill-tracker/<agent-name>/<target>/<date>), create a git worktree as a sibling directory of the repo root (../<branch-slug>/ where / in the branch name is replaced with -), create the PR branch from fetched main, cherry-pick each SHA in order inside the worktree, push, open a PR via the GitHub API, and remove the worktree. It prints the PR URL to stdout. The original repo's working directory is never modified.
Error handling: If push.py exits non-zero for a group, log stderr and continue with the next group. One group's failure must not block others.
Step 7: Report Results
After processing all groups, report:
Push+PR run complete.
PRs created:
- <skill-name> (<repo>): <pr-url>
- <skill-name> (<repo>): <pr-url>
Failed:
- <skill-name> (<repo>): <error reason>
If no groups were found, report: "No settled groups found. Nothing to push."
Common Pitfalls
Token not available in subprocess
The configured token_env variable is available in the agent process environment. The scripts read it from os.environ for URL injection. If testing via execute_code, the token won't be available — use the terminal tool instead.
Cherry-pick conflicts
If push.py fails with a cherry-pick conflict, the script aborts the cherry-pick and exits with an error. Log the error and continue with the next group — do not attempt to resolve conflicts manually unless asked.
Partial failures
If some groups succeed and others fail, report both. Do not abort the entire run because one group failed.
GitHub API unreachable
If collect.py cannot reach the GitHub API, it logs a warning to stderr and returns all groups without dedup filtering. This means commits already in PRs may be re-PR'd. Action: stop the run, report the API error to the user, and do not proceed with cherry-pick or PR creation. The dedup filter is safety-critical — without it, the same commits get re-PR'd every run.
Missing PyYAML
collect.py imports yaml (PyYAML) to read config.yaml. If not installed, the script will fail with ModuleNotFoundError. Action: stop the run and report the missing dependency to the user. Do not attempt to install it yourself.
Token env var empty or insufficient
If the configured token_env variable is empty, unset, or has insufficient GitHub API permissions, dedup is silently skipped and all groups are returned unfiltered — meaning commits already in PRs may be re-PR'd. Action: if the token is empty or unset, stop the run and report to the user. If the token is set but API calls fail (caught as exceptions in stderr), stop the run and report the auth error.
Sync commit grouping (sync_pr_mode not yet wired into scripts)
The sync_pr_mode config option (per-skill vs per-sync) is read by the plugin at registration time, but the push+PR scripts (collect.py / group.py) do not yet use it. All commits are currently grouped by target skill regardless of source. When per-sync is implemented, sync commits from a single maintenance pass will be batched into one PR instead of per-skill.
Verification Checklist
-
collect.pycompleted successfully (exit code 0) - JSON output parsed correctly
- All groups from the JSON output were processed (each group --> one PR or a logged failure)
- Diffs examined for each group
- PR titles are under 72 characters
- PR bodies explain what changed and why (based on diffs, not metadata)
-
push.pycalled with correct arguments for each group - Results reported (PR URLs and any failures)
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.