From ffc70be7b04f50707323e781033da06d7d5bd57f Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Thu, 26 Mar 2026 10:49:57 +0200 Subject: [PATCH] include SKILL.md and assets in generated skill package wheels. Add README to generated skills --- .../haiku/rag/skill_generator/__init__.py | 4 ++ .../skill_generator/templates/README.md.j2 | 11 ++++ .../templates/pyproject.toml.j2 | 4 ++ tests/test_skill_generator.py | 59 +++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 haiku_rag_slim/haiku/rag/skill_generator/templates/README.md.j2 diff --git a/haiku_rag_slim/haiku/rag/skill_generator/__init__.py b/haiku_rag_slim/haiku/rag/skill_generator/__init__.py index 004db953..9b09b514 100644 --- a/haiku_rag_slim/haiku/rag/skill_generator/__init__.py +++ b/haiku_rag_slim/haiku/rag/skill_generator/__init__.py @@ -99,6 +99,10 @@ def render_templates( template = env.get_template("pyproject.toml.j2") (result_dir / "pyproject.toml").write_text(template.render(context)) + # Render README.md + template = env.get_template("README.md.j2") + (result_dir / "README.md").write_text(template.render(context)) + # Render __init__.py template = env.get_template("__init__.py.j2") (pkg_dir / "__init__.py").write_text(template.render(context)) diff --git a/haiku_rag_slim/haiku/rag/skill_generator/templates/README.md.j2 b/haiku_rag_slim/haiku/rag/skill_generator/templates/README.md.j2 new file mode 100644 index 00000000..1c5ae808 --- /dev/null +++ b/haiku_rag_slim/haiku/rag/skill_generator/templates/README.md.j2 @@ -0,0 +1,11 @@ +# {{ name }}-skill + +{{ description }} + +This skill package was generated by [`haiku-rag create-skill`](https://ggozad.github.io/haiku.rag/). + +## Installation + +```bash +pip install {{ name }}-skill/ +``` diff --git a/haiku_rag_slim/haiku/rag/skill_generator/templates/pyproject.toml.j2 b/haiku_rag_slim/haiku/rag/skill_generator/templates/pyproject.toml.j2 index e8aa675a..c571f03e 100644 --- a/haiku_rag_slim/haiku/rag/skill_generator/templates/pyproject.toml.j2 +++ b/haiku_rag_slim/haiku/rag/skill_generator/templates/pyproject.toml.j2 @@ -6,6 +6,7 @@ build-backend = "setuptools.build_meta" name = "{{ name }}-skill" version = "0.1.0" description = "{{ description }}" +readme = "README.md" requires-python = ">=3.12" dependencies = [ "haiku.rag-slim >= {{ rag_version }}", @@ -14,3 +15,6 @@ dependencies = [ [project.entry-points."haiku.skills"] {{ name }} = "{{ pkg_name }}_skill:create_skill" + +[tool.setuptools.package-data] +{{ pkg_name }}_skill = ["SKILL.md", "assets/**/*"] diff --git a/tests/test_skill_generator.py b/tests/test_skill_generator.py index fc8309a6..9197295d 100644 --- a/tests/test_skill_generator.py +++ b/tests/test_skill_generator.py @@ -1,3 +1,7 @@ +import shutil +import subprocess +import zipfile + import pytest from haiku.rag.skill_generator import ( @@ -95,6 +99,7 @@ class TestRenderTemplates: ) assert result == tmp_path / "recipes-skill" assert result.is_dir() + assert (result / "README.md").is_file() pkg = result / "recipes_skill" assert (pkg / "__init__.py").is_file() assert (pkg / "SKILL.md").is_file() @@ -164,8 +169,11 @@ class TestRenderTemplates: content = toml.read_text() assert 'name = "recipes-skill"' in content assert 'description = "A recipe skill."' in content + assert 'readme = "README.md"' in content assert 'recipes = "recipes_skill:create_skill"' in content assert "haiku.rag-slim >= " in content + assert "[tool.setuptools.package-data]" in content + assert 'recipes_skill = ["SKILL.md", "assets/**/*"]' in content def test_skill_md_conditionals(self, tmp_path): render_templates( @@ -240,6 +248,18 @@ class TestRenderTemplates: content = init.read_text() assert "from haiku.rag.skills._tools import create_skill_tools" in content + def test_readme(self, tmp_path): + render_templates( + output_dir=tmp_path, + name="recipes", + description="A recipe skill.", + tool_names=["search"], + ) + readme = tmp_path / "recipes-skill" / "README.md" + content = readme.read_text() + assert "recipes" in content + assert "haiku-rag" in content + def test_generated_python_is_valid(self, tmp_path): render_templates( output_dir=tmp_path, @@ -350,3 +370,42 @@ class TestGenerateSkill: skill_md = result / "recipes_skill" / "SKILL.md" content = skill_md.read_text() assert "You are a recipe expert." in content + + def test_wheel_includes_package_data(self, tmp_path): + if not shutil.which("uv"): + pytest.skip("uv not available") + db_path = _make_fake_lancedb(tmp_path / "test.lancedb") + config_file = tmp_path / "haiku.rag.yaml" + config_file.write_text("storage:\n data_dir: /tmp\n") + result = generate_skill( + db_path=db_path, + output_dir=tmp_path, + name="recipes", + description="A recipe skill.", + tool_names=["search"], + config_path=config_file, + ) + dist_dir = result / "dist" + subprocess.check_call( + [ + "uv", + "run", + "--with", + "build", + "--no-project", + "python", + "-m", + "build", + "--wheel", + "--outdir", + str(dist_dir), + str(result), + ] + ) + wheels = list(dist_dir.glob("*.whl")) + assert len(wheels) == 1 + with zipfile.ZipFile(wheels[0]) as zf: + names = zf.namelist() + assert any(n.endswith("SKILL.md") for n in names) + assert any("assets/" in n and n.endswith("data.lance") for n in names) + assert any(n.endswith("haiku.rag.yaml") for n in names)