Skip to content

Commit 3cc7579

Browse files
chore: sync template lineage support
1 parent 99eca48 commit 3cc7579

6 files changed

Lines changed: 79 additions & 18 deletions

File tree

.github/template-source.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
template:
22
name: codegraphtheory/hermes-profile-template
33
url: https://github.com/codegraphtheory/hermes-profile-template
4-
commit: e731d0e
4+
commit: d0a6aa4
55
relationship: rebuilt-from-template
66
notes:
77
- ChainForge preserves its original git history.

distribution.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ license: MIT
88
template_source:
99
name: codegraphtheory/hermes-profile-template
1010
url: https://github.com/codegraphtheory/hermes-profile-template
11-
commit: e731d0e
11+
commit: d0a6aa4
1212
relationship: rebuilt-from-template
1313
env_requires:
1414
- name: OPENROUTER_API_KEY

scripts/generate_profile.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,36 @@ def render_distribution(params: dict[str, Any], slug: str, description: str) ->
6262
env_requires = params.get("env_requires") or []
6363
if not isinstance(env_requires, list):
6464
raise ValueError("env_requires must be a list")
65-
manifest = {
65+
manifest: dict[str, Any] = {
6666
"name": slug,
6767
"version": str(params.get("version") or "0.1.0"),
6868
"description": description,
6969
"hermes_requires": str(params.get("hermes_requires") or ">=0.12.0"),
7070
"author": str(params.get("author") or "Hermes profile author"),
7171
"license": str(params.get("license") or "MIT"),
72-
"env_requires": env_requires,
73-
"distribution_owned": [
74-
"SOUL.md",
75-
"config.yaml",
76-
"mcp.json",
77-
"skills/",
78-
"templates/",
79-
"scripts/",
80-
"distribution.yaml",
81-
"README.md",
82-
"AGENTS.md",
83-
".env.EXAMPLE",
84-
],
8572
}
73+
template_source = params.get("template_source")
74+
if template_source:
75+
if not isinstance(template_source, dict):
76+
raise ValueError("template_source must be a mapping")
77+
manifest["template_source"] = template_source
78+
manifest.update(
79+
{
80+
"env_requires": env_requires,
81+
"distribution_owned": [
82+
"SOUL.md",
83+
"config.yaml",
84+
"mcp.json",
85+
"skills/",
86+
"templates/",
87+
"scripts/",
88+
"distribution.yaml",
89+
"README.md",
90+
"AGENTS.md",
91+
".env.EXAMPLE",
92+
],
93+
}
94+
)
8695
return yaml.safe_dump(manifest, sort_keys=False, default_flow_style=False)
8796

8897

@@ -127,7 +136,6 @@ def render_config(params: dict[str, Any]) -> str:
127136
"memory": {"memory_enabled": True, "user_profile_enabled": True},
128137
"security": {"redact_secrets": True},
129138
"approvals": {"mode": "manual"},
130-
"toolsets": toolsets,
131139
},
132140
sort_keys=False,
133141
)
@@ -229,10 +237,16 @@ def render_agents(display_name: str) -> str:
229237

230238

231239
def render_readme(params: dict[str, Any], slug: str, display_name: str, description: str) -> str:
240+
template_source = params.get("template_source")
241+
lineage = ""
242+
if isinstance(template_source, dict) and template_source.get("url"):
243+
template_name = str(template_source.get("name") or "profile template")
244+
template_url = str(template_source["url"])
245+
lineage = f"\nTemplate lineage: built from [{template_name}]({template_url}).\n"
232246
return f"""# {display_name}
233247
234248
{description}
235-
249+
{lineage}
236250
This is a Hermes Agent profile distribution. It can be installed with `hermes profile install` and updated from git.
237251
238252
## Install
@@ -274,6 +288,22 @@ def render_readme(params: dict[str, Any], slug: str, display_name: str, descript
274288
"""
275289

276290

291+
def render_template_source_file(params: dict[str, Any]) -> str | None:
292+
template_source = params.get("template_source")
293+
if not template_source:
294+
return None
295+
if not isinstance(template_source, dict):
296+
raise ValueError("template_source must be a mapping")
297+
data = {
298+
"template": template_source,
299+
"notes": [
300+
"GitHub native generated-from-template linkage is only available when a repository is created through GitHub's template flow.",
301+
"This file records template lineage explicitly for humans and automation.",
302+
],
303+
}
304+
return yaml.safe_dump(data, sort_keys=False, default_flow_style=False)
305+
306+
277307
def render_params_example(slug: str, display_name: str, description: str, author: str) -> str:
278308
data = {
279309
"name": slug,
@@ -284,6 +314,11 @@ def render_params_example(slug: str, display_name: str, description: str, author
284314
"license": "MIT",
285315
"model_provider": "openrouter",
286316
"model_default": "anthropic/claude-sonnet-4",
317+
"template_source": {
318+
"name": "codegraphtheory/hermes-profile-template",
319+
"url": "https://github.com/codegraphtheory/hermes-profile-template",
320+
"relationship": "generated-from-template",
321+
},
287322
"toolsets": ["file", "terminal", "skills", "web", "session_search", "clarify"],
288323
"env_requires": [],
289324
"principles": [
@@ -343,6 +378,9 @@ def generate(params: dict[str, Any], output: Path, force: bool, template_root: P
343378
write(output / "mcp.json", "{\n \"mcpServers\": {}\n}")
344379
write(output / "templates" / "profile.params.yaml", render_params_example(slug, display_name, description, author))
345380
copy_support_files(template_root, output)
381+
template_source_file = render_template_source_file(params)
382+
if template_source_file:
383+
write(output / ".github" / "template-source.yml", template_source_file)
346384

347385
result = subprocess.run(
348386
["python3", str(output / "scripts" / "validate_profile.py"), str(output)],

scripts/new_profile.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ def main() -> int:
2929
"license": "MIT",
3030
"model_provider": "openrouter",
3131
"model_default": "anthropic/claude-sonnet-4",
32+
"template_source": {
33+
"name": "codegraphtheory/hermes-profile-template",
34+
"url": "https://github.com/codegraphtheory/hermes-profile-template",
35+
"relationship": "generated-from-template",
36+
},
3237
"toolsets": ["file", "terminal", "skills", "web", "session_search", "clarify"],
3338
"env_requires": [],
3439
}

scripts/validate_profile.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ def check_manifest(root: Path, errors: list[str]) -> None:
7676
if name and not re.fullmatch(r"[a-z0-9][a-z0-9-]{0,62}", name):
7777
fail(errors, "distribution.yaml name must be lowercase kebab case")
7878
env_requires = data.get("env_requires", [])
79+
template_source = data.get("template_source")
80+
if template_source is not None:
81+
if not isinstance(template_source, dict):
82+
fail(errors, "distribution.yaml template_source must be a mapping")
83+
elif template_source.get("url") and not str(template_source["url"]).startswith("https://github.com/"):
84+
fail(errors, "distribution.yaml template_source.url should be a GitHub HTTPS URL")
85+
lineage_file = root / ".github" / "template-source.yml"
86+
if template_source and not lineage_file.exists():
87+
fail(errors, "template_source is declared but .github/template-source.yml is missing")
88+
if lineage_file.exists():
89+
lineage = load_yaml(lineage_file, errors)
90+
if isinstance(lineage, dict) and not isinstance(lineage.get("template"), dict):
91+
fail(errors, ".github/template-source.yml must contain a template mapping")
7992
if env_requires and not isinstance(env_requires, list):
8093
fail(errors, "distribution.yaml env_requires must be a list")
8194
owned = data.get("distribution_owned", [])

templates/profile.params.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ license: MIT
77
hermes_requires: ">=0.12.0"
88
model_provider: openrouter
99
model_default: anthropic/claude-sonnet-4
10+
template_source:
11+
name: codegraphtheory/hermes-profile-template
12+
url: https://github.com/codegraphtheory/hermes-profile-template
13+
commit: d0a6aa4
14+
relationship: rebuilt-from-template
1015

1116
toolsets:
1217
- file

0 commit comments

Comments
 (0)