Current section

42 Versions

Jump to

Compare versions

5 files changed
+47 additions
-78 deletions
  @@ -12,6 +12,15 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
12 12
13 13 <!-- changelog -->
14 14
15 + ## v1.0.0-rc.3 (2026-02-10)
16 +
17 +
18 +
19 +
20 + ### Improvements:
21 +
22 + * use refernece files for all usage rules by Zach Daniel
23 +
15 24 ## v1.0.0-rc.2 (2026-02-07)
  @@ -122,15 +122,12 @@ defp usage_rules do
122 122 deps: [:ash, :req],
123 123 # Supports regex for matching multiple deps:
124 124 # deps: [~r/^ash_/],
125 - # Use {:dep, :reference} to build as reference files instead of inlining:
126 - # deps: [:ash, {:req, :reference}, {~r/^ash_/, :reference}],
127 125
128 126 # Compose custom skills from multiple packages
129 127 build: [
130 128 "ash-framework": [
131 129 description: "Expert on the Ash Framework ecosystem.",
132 - # Use {:dep, :reference} or {~r/.../, :reference} for reference files
133 - usage_rules: [:ash, {:ash_postgres, :reference}, {~r/^ash_phoenix/, :reference}]
130 + usage_rules: [:ash, ~r/^ash_/]
134 131 ]
135 132 ]
136 133 ]
  @@ -164,7 +161,7 @@ Each entry in the `usage_rules` list can be:
164 161 | Option | Type | Description |
165 162 |--------|------|-------------|
166 163 | `location` | `string` | Output directory for skills (default: `".claude/skills"`) |
167 - | `deps` | `list` | Auto-build a `use-<pkg>` skill per listed dependency. Supports atoms, regexes, and `{spec, :reference}` tuples |
164 + | `deps` | `list` | Auto-build a `use-<pkg>` skill per listed dependency. Supports atoms and regexes |
168 165 | `build` | `keyword` | Define custom composed skills from multiple packages' usage rules |
169 166
170 167 ## Usage Rules
  @@ -257,15 +254,7 @@ defp usage_rules do
257 254 end
258 255 ```
259 256
260 - This generates `.claude/skills/use-ash/SKILL.md` and `.claude/skills/use-req/SKILL.md`, each containing the package's usage rules, available mix tasks, doc search commands, and sub-rule references.
261 -
262 - You can mark deps as `:reference` to have their main rules written as a separate reference file instead of being inlined into the skill body:
263 -
264 - ```elixir
265 - skills: [
266 - deps: [{:ash, :reference}, {~r/^ash_/, :reference}]
267 - ]
268 - ```
257 + This generates `.claude/skills/use-ash/SKILL.md` and `.claude/skills/use-req/SKILL.md`, each with reference links to the package's usage rules, available mix tasks, doc search commands, and sub-rule references. Each package's `usage-rules.md` is written to a `references/<package>.md` file.
269 258
270 259 ### Compose custom skills
271 260
  @@ -282,7 +271,7 @@ skills: [
282 271 ]
283 272 ```
284 273
285 - This generates a single `.claude/skills/ash-framework/SKILL.md` that combines usage rules from all listed packages. Regex is also supported:
274 + This generates a single `.claude/skills/ash-framework/SKILL.md` with reference links to usage rules from all listed packages. Each package's rules are written to `references/<package>.md`. Regex is also supported:
286 275
287 276 ```elixir
288 277 skills: [
  @@ -295,24 +284,6 @@ skills: [
295 284 ]
296 285 ```
297 286
298 - ### Reference mode
299 -
300 - By default, each package's main `usage-rules.md` is inlined directly into the skill body. For skills that combine many packages, this can make the SKILL.md quite large. You can use `{:dep, :reference}` or `{~r/.../, :reference}` to have packages built as separate reference files instead:
301 -
302 - ```elixir
303 - skills: [
304 - build: [
305 - "ash-framework": [
306 - description: "Expert on the Ash Framework ecosystem.",
307 - # Ash core rules are inlined, extensions are reference files
308 - usage_rules: [:ash, {~r/^ash_/, :reference}]
309 - ]
310 - ]
311 - ]
312 - ```
313 -
314 - This inlines `:ash`'s rules into the skill body and writes each matching extension's rules to `references/<package>.md`, linked from the "Additional References" section — the same way sub-rules are handled. This works in both `deps` and `build` configs, and with both atoms and regexes.
315 -
316 287 ### Stale skill cleanup
317 288
318 289 Skills generated by UsageRules include a `managed-by: usage-rules` marker in their YAML frontmatter. When a skill is removed from your config and you re-run `mix usage_rules.sync`, the stale skill files are automatically cleaned up. If you've added custom content to a managed skill, only the managed section is removed — your custom content is preserved.
  @@ -7,7 +7,7 @@
7 7 {<<"GitHub">>,<<"https://github.com/ash-project/usage_rules">>},
8 8 {<<"Website">>,<<"https://ash-hq.org">>}]}.
9 9 {<<"name">>,<<"usage_rules">>}.
10 - {<<"version">>,<<"1.0.0-rc.2">>}.
10 + {<<"version">>,<<"1.0.0-rc.3">>}.
11 11 {<<"description">>,
12 12 <<"A config-driven dev tool for Elixir projects to manage AGENTS.md files and agent skills from dependencies">>}.
13 13 {<<"elixir">>,<<"~> 1.18">>}.
  @@ -255,9 +255,8 @@ if Code.ensure_loaded?(Igniter) do
255 255 |> Enum.filter(fn {_name, path, _mode} ->
256 256 Igniter.exists?(igniter, Path.join(path, "usage-rules.md"))
257 257 end)
258 - |> Enum.map(fn {pkg_name, _path, mode} ->
259 - spec = if mode == :reference, do: {pkg_name, :reference}, else: pkg_name
260 - {:"use-#{pkg_name}", [usage_rules: [spec]]}
258 + |> Enum.map(fn {pkg_name, _path, _mode} ->
259 + {:"use-#{pkg_name}", [usage_rules: [pkg_name]]}
261 260 end)
262 261
263 262 # Merge explicit build specs on top of package-derived ones
  @@ -719,7 +718,8 @@ if Code.ensure_loaded?(Igniter) do
719 718 resolved_packages,
720 719 custom_description
721 720 ) do
722 - skill_md = build_skill_md(igniter, skill_name, resolved_packages, custom_description)
721 + skill_md =
722 + build_skill_md(igniter, skill_name, resolved_packages, custom_description)
723 723
724 724 igniter =
725 725 Igniter.create_or_update_file(
  @@ -733,27 +733,23 @@ if Code.ensure_loaded?(Igniter) do
733 733 end
734 734 )
735 735
736 - # Reference files for sub-rules and reference-mode main rules from all packages
737 - Enum.reduce(resolved_packages, igniter, fn {pkg_name, package_path, mode}, acc ->
738 - # Create reference file for main usage-rules.md if this package is in reference mode
736 + # Reference files for sub-rules and main rules from all packages
737 + Enum.reduce(resolved_packages, igniter, fn {pkg_name, package_path, _mode}, acc ->
738 + # Create reference file for main usage-rules.md
739 739 acc =
740 - if mode == :reference do
741 - main_path = Path.join(package_path, "usage-rules.md")
742 - content = read_dep_content(acc, main_path)
743 - ref_path = Path.join([skill_dir, "references", "#{pkg_name}.md"])
740 + case read_dep_content(acc, Path.join(package_path, "usage-rules.md")) do
741 + "" ->
742 + acc
743 +
744 + content ->
745 + ref_path = Path.join([skill_dir, "references", "#{pkg_name}.md"])
744 746
745 - if content != "" do
746 747 Igniter.create_or_update_file(
747 748 acc,
748 749 ref_path,
749 750 content,
750 751 fn source -> Rewrite.Source.update(source, :content, content) end
751 752 )
752 - else
753 - acc
754 - end
755 - else
756 - acc
757 753 end
758 754
759 755 sub_rules = find_available_sub_rules(acc, package_path)
  @@ -815,23 +811,21 @@ if Code.ensure_loaded?(Igniter) do
815 811 defp build_skill_body(igniter, _skill_name, resolved_packages) do
816 812 sections = []
817 813
818 - # Sub-rules as references (at the top for discoverability)
814 + # Sub-rules as references
819 815 all_sub_rules =
820 816 Enum.flat_map(resolved_packages, fn {_pkg_name, package_path, _mode} ->
821 817 find_available_sub_rules(igniter, package_path)
822 818 end)
823 819
824 - # Main rules from reference-mode packages
825 - reference_main_rules =
826 - resolved_packages
827 - |> Enum.filter(fn {_pkg_name, _path, mode} -> mode == :reference end)
828 - |> Enum.map(fn {pkg_name, _path, _mode} -> pkg_name end)
820 + # All packages are references
821 + all_main_rules =
822 + Enum.map(resolved_packages, fn {pkg_name, _path, _mode} -> pkg_name end)
829 823
830 824 all_references =
831 825 Enum.map(all_sub_rules, fn sub_rule ->
832 826 "- [#{sub_rule}](references/#{sub_rule}.md)"
833 827 end) ++
834 - Enum.map(reference_main_rules, fn pkg_name ->
828 + Enum.map(all_main_rules, fn pkg_name ->
835 829 "- [#{pkg_name}](references/#{pkg_name}.md)"
836 830 end)
837 831
  @@ -843,23 +837,6 @@ if Code.ensure_loaded?(Igniter) do
843 837 sections
844 838 end
845 839
846 - # Usage rules content from inline packages only
847 - sections =
848 - Enum.reduce(resolved_packages, sections, fn {pkg_name, package_path, mode}, acc ->
849 - if mode == :reference do
850 - acc
851 - else
852 - main_path = Path.join(package_path, "usage-rules.md")
853 - content = read_dep_content(igniter, main_path)
854 -
855 - if content != "" do
856 - acc ++ ["## #{pkg_name} usage rules\n\n#{content}"]
857 - else
858 - acc
859 - end
860 - end
861 - end)
862 -
863 840 # Search docs for all packages
864 841 package_names = Enum.map(resolved_packages, &elem(&1, 0))
865 842
  @@ -943,12 +920,24 @@ if Code.ensure_loaded?(Igniter) do
943 920 defp expand_dep_specs(specs, all_deps) do
944 921 Enum.flat_map(specs, fn
945 922 {%Regex{} = regex, :reference} ->
923 + IO.warn(
924 + "{~r/.../, :reference} is deprecated in usage_rules skill config. " <>
925 + "All packages are now automatically written as reference files. " <>
926 + "Use the regex directly instead: ~r/#{Regex.source(regex)}/"
927 + )
928 +
946 929 Enum.filter(all_deps, fn {name, _path} ->
947 930 Regex.match?(regex, to_string(name))
948 931 end)
949 932 |> Enum.map(fn {name, path} -> {name, path, :reference} end)
950 933
951 934 {pkg_name, :reference} when is_atom(pkg_name) ->
935 + IO.warn(
936 + "{:#{pkg_name}, :reference} is deprecated in usage_rules skill config. " <>
937 + "All packages are now automatically written as reference files. " <>
938 + "Use the atom directly instead: :#{pkg_name}"
939 + )
940 +
952 941 case Enum.find(all_deps, fn {name, _path} -> name == pkg_name end) do
953 942 nil -> []
954 943 {name, path} -> [{name, path, :reference}]
  @@ -958,12 +947,12 @@ if Code.ensure_loaded?(Igniter) do
958 947 Enum.filter(all_deps, fn {name, _path} ->
959 948 Regex.match?(regex, to_string(name))
960 949 end)
961 - |> Enum.map(fn {name, path} -> {name, path, :inline} end)
950 + |> Enum.map(fn {name, path} -> {name, path, :reference} end)
962 951
963 952 pkg_name when is_atom(pkg_name) ->
964 953 case Enum.find(all_deps, fn {name, _path} -> name == pkg_name end) do
965 954 nil -> []
966 - {name, path} -> [{name, path, :inline}]
955 + {name, path} -> [{name, path, :reference}]
967 956 end
968 957 end)
969 958 |> Enum.uniq_by(&elem(&1, 0))
  @@ -5,7 +5,7 @@
5 5 defmodule UsageRules.MixProject do
6 6 use Mix.Project
7 7
8 - @version "1.0.0-rc.2"
8 + @version "1.0.0-rc.3"
9 9 @description """
10 10 A config-driven dev tool for Elixir projects to manage AGENTS.md files and agent skills from dependencies
11 11 """