feat(sync): add hermes sync for profile backup to a personal git repo - #39343
Closed
kshitijk4poor wants to merge 1 commit into
Closed
feat(sync): add hermes sync for profile backup to a personal git repo#39343kshitijk4poor wants to merge 1 commit into
hermes sync for profile backup to a personal git repo#39343kshitijk4poor wants to merge 1 commit into
Conversation
kshitijk4poor
force-pushed
the
feat/profile-sync-git
branch
from
June 4, 2026 22:41
e04fa8e to
1bc86bf
Compare
kshitijk4poor
force-pushed
the
feat/profile-sync-git
branch
6 times, most recently
from
June 6, 2026 07:36
f675c8d to
386f341
Compare
Adds a new `hermes sync` subcommand that lets independent git users back up
and sync a curated subset of their ~/.hermes profile to a git repository they
control. Plain git over subprocess; no Nous portal / object store.
Subcommands:
- init choose PRIVATE (default) or PUBLIC, create via gh or paste a remote,
write a secret-excluding .gitignore, persist under config.yaml sync:
- push stage the synced subset, run a pre-push secret scan (reusing the
credential-exposure patterns from tools/skills_guard.py) and ABORT
if anything secret-shaped would be committed, then commit + push
- pull fetch + reset the staging mirror, restore into the live profile
(last-writer-wins; confirms before clobbering unless --force)
- status remote + visibility, last sync, pending changes
- share print the `npx skills add <url> --skill <name>` install command
(mirroring tools/skills_hub.py); optional --push for one skill
What syncs: skills/ tree, memories/MEMORY.md, memories/USER.md, SOUL.md, and
an allow-listed slice of config (display.skin, default_toolsets) materialized
as a generated sync-config.yaml. The raw config.yaml is never synced.
Uses a dedicated staging git dir (<hermes_home>/.sync-git) that mirrors only
the curated subset, so it is structurally impossible to commit secrets living
elsewhere in the profile. Profile-aware via get_hermes_home(); no new deps.
kshitijk4poor
force-pushed
the
feat/profile-sync-git
branch
from
June 6, 2026 08:15
386f341 to
d0e969b
Compare
benbarclay
added a commit
that referenced
this pull request
Jul 28, 2026
…SP naming
Encapsulates the feature behind one command for launch, and adopts the
official product name.
One command:
- `propose` moves from `hermes skills propose` to `hermes sync propose`, so
the whole feature is one command to learn and one to document. Its handler
moves from cmd_skills to cmd_sync accordingly.
- The `hermes sync` parser now documents both halves plainly: personal sync
across your devices, and sharing with your organisation. Added an examples
epilog; rewrote the verb help in user language ("Include a skill in your
sync" rather than "Opt a skill into sync").
- Every user-facing string that pointed at `hermes skills propose` now points
at `hermes sync propose` (8 sites, including the agent-visible guidance
returned by skill_manage and the org provenance header).
This also clears the way for #39343, which adds its own top-level `sync` for
git-repo profile backup — that feature nests under `skills`, this one owns
`sync`.
Naming:
- HSP / "Hermes Sync Protocol" is gone from prose, docstrings, and comments.
The feature is "Skill Sync".
- Public identifiers renamed: HSPClient -> SyncClient, HSPError -> SyncError,
HSPConflict -> SyncConflict, hsp_address -> wire_address, HSP_VERSION ->
WIRE_VERSION.
- The WIRE names are deliberately NOT renamed: the `hsp_version` capability
field and the `x-hsp-object-type` response header are set by the deployed
gateway-gateway sync plane (verified in src/sync/syncRouter.ts), so
renaming them client-side would break sync against a live server. A comment
at the version constant records why they differ from the product name.
- The version-mismatch error is now actionable ("this server speaks sync
version X, but this Hermes speaks Y — update Hermes to sync with it")
instead of leaking the protocol acronym.
Also fixes a wiring gap found on the way: the gateway housekeeping tick
pulled personal skills but never org skills — the same defect already fixed
for the CLI. Org pull now runs there too, gated on real org membership.
Tests: the jargon guard now also fails on a bare "HSP". The two tests that
asserted the old cross-command structure are replaced by three asserting the
new one (propose IS under sync, propose is NOT under skills, sync usage
lists it). 2294 passed / 0 failed across all 51 suites that import the
changed modules, via scripts/run_tests.sh.
Verified by running the real CLI: `hermes sync --help` lists all eight verbs,
`hermes skills --help` no longer mentions propose, `hermes sync propose
--help` parses, and `hermes sync status` still reports live org state.
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…SP naming
Encapsulates the feature behind one command for launch, and adopts the
official product name.
One command:
- `propose` moves from `hermes skills propose` to `hermes sync propose`, so
the whole feature is one command to learn and one to document. Its handler
moves from cmd_skills to cmd_sync accordingly.
- The `hermes sync` parser now documents both halves plainly: personal sync
across your devices, and sharing with your organisation. Added an examples
epilog; rewrote the verb help in user language ("Include a skill in your
sync" rather than "Opt a skill into sync").
- Every user-facing string that pointed at `hermes skills propose` now points
at `hermes sync propose` (8 sites, including the agent-visible guidance
returned by skill_manage and the org provenance header).
This also clears the way for NousResearch#39343, which adds its own top-level `sync` for
git-repo profile backup — that feature nests under `skills`, this one owns
`sync`.
Naming:
- HSP / "Hermes Sync Protocol" is gone from prose, docstrings, and comments.
The feature is "Skill Sync".
- Public identifiers renamed: HSPClient -> SyncClient, HSPError -> SyncError,
HSPConflict -> SyncConflict, hsp_address -> wire_address, HSP_VERSION ->
WIRE_VERSION.
- The WIRE names are deliberately NOT renamed: the `hsp_version` capability
field and the `x-hsp-object-type` response header are set by the deployed
gateway-gateway sync plane (verified in src/sync/syncRouter.ts), so
renaming them client-side would break sync against a live server. A comment
at the version constant records why they differ from the product name.
- The version-mismatch error is now actionable ("this server speaks sync
version X, but this Hermes speaks Y — update Hermes to sync with it")
instead of leaking the protocol acronym.
Also fixes a wiring gap found on the way: the gateway housekeeping tick
pulled personal skills but never org skills — the same defect already fixed
for the CLI. Org pull now runs there too, gated on real org membership.
Tests: the jargon guard now also fails on a bare "HSP". The two tests that
asserted the old cross-command structure are replaced by three asserting the
new one (propose IS under sync, propose is NOT under skills, sync usage
lists it). 2294 passed / 0 failed across all 51 suites that import the
changed modules, via scripts/run_tests.sh.
Verified by running the real CLI: `hermes sync --help` lists all eight verbs,
`hermes skills --help` no longer mentions propose, `hermes sync propose
--help` parses, and `hermes sync status` still reports live org state.
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…SP naming
Encapsulates the feature behind one command for launch, and adopts the
official product name.
One command:
- `propose` moves from `hermes skills propose` to `hermes sync propose`, so
the whole feature is one command to learn and one to document. Its handler
moves from cmd_skills to cmd_sync accordingly.
- The `hermes sync` parser now documents both halves plainly: personal sync
across your devices, and sharing with your organisation. Added an examples
epilog; rewrote the verb help in user language ("Include a skill in your
sync" rather than "Opt a skill into sync").
- Every user-facing string that pointed at `hermes skills propose` now points
at `hermes sync propose` (8 sites, including the agent-visible guidance
returned by skill_manage and the org provenance header).
This also clears the way for NousResearch#39343, which adds its own top-level `sync` for
git-repo profile backup — that feature nests under `skills`, this one owns
`sync`.
Naming:
- HSP / "Hermes Sync Protocol" is gone from prose, docstrings, and comments.
The feature is "Skill Sync".
- Public identifiers renamed: HSPClient -> SyncClient, HSPError -> SyncError,
HSPConflict -> SyncConflict, hsp_address -> wire_address, HSP_VERSION ->
WIRE_VERSION.
- The WIRE names are deliberately NOT renamed: the `hsp_version` capability
field and the `x-hsp-object-type` response header are set by the deployed
gateway-gateway sync plane (verified in src/sync/syncRouter.ts), so
renaming them client-side would break sync against a live server. A comment
at the version constant records why they differ from the product name.
- The version-mismatch error is now actionable ("this server speaks sync
version X, but this Hermes speaks Y — update Hermes to sync with it")
instead of leaking the protocol acronym.
Also fixes a wiring gap found on the way: the gateway housekeeping tick
pulled personal skills but never org skills — the same defect already fixed
for the CLI. Org pull now runs there too, gated on real org membership.
Tests: the jargon guard now also fails on a bare "HSP". The two tests that
asserted the old cross-command structure are replaced by three asserting the
new one (propose IS under sync, propose is NOT under skills, sync usage
lists it). 2294 passed / 0 failed across all 51 suites that import the
changed modules, via scripts/run_tests.sh.
Verified by running the real CLI: `hermes sync --help` lists all eight verbs,
`hermes skills --help` no longer mentions propose, `hermes sync propose
--help` parses, and `hermes sync status` still reports live org state.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
hermes sync— a CLI subcommand that lets independent users back up and sync their Hermes profile (skills, memory, persona, and a safe slice of config) to a git repository they control. Plain git under the hood, the user's own repo, no external service involved. This is the self-hosted / independent path: your data, your remote, zero dependency on any hosted backend.It is distinct from the existing
skills_hub(which installs skills from public GitHub repos) andskills_sync(which seeds bundled skills). Neither does bidirectional personal-profile sync; this fills that gap.Commands
hermes sync init— set up sync. Prompts private or public (defaults to private for safety). Usesgh repo createwhen available, otherwise prompts for an existing remote URL. Writes a secret-excluding.gitignoreand records the remote + visibility under async:key inconfig.yaml.hermes sync push— stage the curated subset, run a pre-push secret scan, commit, and push. Aborts with a per-file report if anything secret-shaped is about to be committed.hermes sync pull— fetch and restore into the live profile. Last-writer-wins; confirms before overwriting locally-modified files unless--force.hermes sync status— remote, visibility, last sync time, pending changes, ahead/behind.hermes sync share <skill>— print the exact install command others run (mirrors theskills_hubinstall format). Warns when the repo is private.What syncs (and what never does)
Synced:
skills/,memories/MEMORY.md,memories/USER.md, persona (SOUL.md), and an allow-listed config slice (display.skin,default_toolsets) materialized into a generatedsync-config.yaml.Never synced (
.gitignore+ a generated-config indirection so the raw file is never staged):.env,auth.json, the rawconfig.yaml(model/provider keys),state.db*,sessions.db*, logs, caches, heapdumps, checkpoints, plugin runtime data,*.pem/*.key.Safety: pre-push secret scan
The push path reuses the existing
tools/skills_guard.pyscanner (scan_file+ its credential-exposure pattern table) rather than introducing new regexes. The gate is restricted to credential-leak pattern ids (hardcoded secrets, private keys, GitHub/OpenAI/Anthropic/AWS keys). If a staged file trips one, the push aborts. Verified live: a planted AWS + Anthropic key blocks the push; a normal skill file passes.Design notes
<hermes_home>/.sync-git) that physically contains only the curated subset — chosen over a worktree over the live profile so it is structurally impossible to commit secrets that live elsewhere in~/.hermes.get_hermes_home(); no hardcoded~/.hermes.gitviasubprocess; no new dependencies.Tests
tests/hermes_cli/test_sync_cmd.py— 17 tests covering secret exclusion, allow-listed-config enforcement, private-by-default init, and status output. All pass; neighboring CLI tests unaffected.Test plan
pytest tests/hermes_cli/test_sync_cmd.py— 17/17 passmodel.api_keydid not) → secret-abort path → pull into a fresh profile → sharehermes sync --helpregisters all five subcommands