UsageRules
repository·main·Indexed 41 days ago
https://github.com/ash-project/usage_rulesA configuration-driven developer tool for Elixir projects designed to manage AI agent context. It consolidates usage rules from dependencies into files like AGENTS.md or CLAUDE.md, automatically generates agent-readable SKILL.md files, and provides Mix tasks for searching hexdocs and inspecting module documentation.
What's inside UsageRules
- Usage Rules are guidelines and rules provided directly by package authors. You should consult them thoroughly before taking action in a project, as they are the authoritative source for making decisions regarding specific packages and their intended usage patterns.
Handle errors with tuples and the `with` statement
mainFor operations that can fail, return standard result tuples:
{:ok, result}for success and{:error, reason}for failure. Avoid using exceptions for normal control flow.To chain multiple operations that return these result tuples, use the
withstatement to avoid deeply nestedcaseblocks.How to inline main rules and link sub-rules
mainIf a package has many sub-rules and you want to keep the main rules inlined but link to sub-rules instead of inlining them all, use
main: falseto declare the package twice with different options.usage_rules: [ {:ash, sub_rules: []}, # inline main rules only {:ash, sub_rules: :all, main: false, link: :markdown} # link sub-rules only ]Use pattern matching for control flow
mainIn Elixir, prefer pattern matching over conditional logic (
if/elseorcase) whenever possible. A common idiomatic pattern is to use multiple function clauses (matching on function heads) to handle different data shapes instead of complex logic inside a single function body.Important Note on Maps: The pattern
%{}matches any map, not just an empty one. To check if a map is truly empty, use a guard withmap_size(map) == 0.Select appropriate data structures
mainChoose data structures based on the use case:
- Structs: Use
defstructwhen the data shape is known and fixed. - Maps: Use maps for dynamic key-value data.
- Keyword Lists: Use keyword lists (e.g.,
[timeout: 5000, retries: 3]) for passing options to functions. - Lists: When adding elements to a list, always prepend using the cons operator
[new | list]instead of appending withlist ++ [new]for better performance.
- Structs: Use
How agent skills work
mainSkills are
SKILL.mdfiles that agent tools like Claude Code can discover and use. UsageRules generates these files to provide agents with context about your dependencies.- Auto-build (
deps): Creates ause-<package>skill for each dependency. It includes reference links to usage rules, mix tasks, and doc search commands. - Composition (
build): Allows you to group multiple packages into a single specialized skill (e.g., an "Ash Framework" skill that combines:ash,:ash_postgres, etc.). - Discovery: AI agents use the
description:field in the skill to decide when to auto-load it. Providing specific, observable signals (like file paths or error types) in the description improves agent accuracy.
- Auto-build (
Choose between GenServer.call/3 and GenServer.cast/2
mainWhen communicating with a
GenServer, choose the method based on whether you require a response:- Synchronous Requests: Use
GenServer.call/3when you expect a reply. This provides back-pressure and ensures the caller waits for the result. - Fire-and-Forget: Use
GenServer.cast/2for messages where you do not need a response.
Recommendation: When in doubt, use
callovercastto maintain back-pressure. Always set appropriate timeouts forcall/3operations to prevent callers from hanging indefinitely.- Synchronous Requests: Use
Best practices for implementing GenServers
mainWhen implementing
GenServerprocesses, follow these guidelines to ensure stability and maintainability:- State Management: Keep the process state simple and ensure it is serializable.
- Message Handling: Explicitly handle all expected messages in your callback functions.
- Initialization: Use
handle_continue/2to perform heavy or asynchronous work after the initialinit/1call has completed. - Cleanup: Implement the
terminate/2callback to perform necessary cleanup when the process exits.
Ship pre-built skills in your package
mainPackages can provide pre-built skills that users can pull in directly. Skills allow for more structured, modular guidance.
Skill Directory Structure
Place skill files in a
usage-rules/skills/directory. Each skill should have its own subdirectory containing aSKILL.mdfile and optional reference files.usage-rules/skills/ my-skill/ SKILL.md # the skill definition references/ some-ref.md # optional reference filesDefining a Skill
Each
SKILL.mdmust include YAML frontmatter defining thenameanddescription.--- name: my-skill description: "Use this skill when working with MyPackage." --- ## Overview Content describing how to use the package effectively...Enabling Skills
Users enable skills by listing the package in their
mix.exsunder theskillskey:# In mix.exs package: [ skills: [package_skills: [:my_package]] ]When synced, skills are copied to the user's location with a
managed-by: usage-rulesmarker. Companion files inreferences/are copied verbatim.Use Task and Task.Supervisor for concurrent work
mainFor managing asynchronous tasks, follow these patterns:
- Fault Tolerance: Use
Task.Supervisorinstead of raw tasks to improve fault tolerance and supervision. - Failure Handling: Manage task failures using
Task.yield/2orTask.shutdown/2. - Timeouts: Always set appropriate timeouts for tasks.
- Concurrent Enumeration: Use
Task.async_stream/3when you need to process an enumerable concurrently while maintaining back-pressure.
- Fault Tolerance: Use
Install UsageRules
mainYou can install
usage_rulesusingigniterif it is already present in your project, or by adding it manually to yourmix.exsdependencies. It is recommended to include it only for the:devenvironment.# Using igniter mix igniter.install usage_rules# Manual installation in mix.exs defp deps do [ {:usage_rules, "~> 1.1", only: [:dev]}, {:igniter, "~> 0.6", only: [:dev]} ] endConfigure UsageRules in mix.exs
mainUsageRules is configured via a
:usage_ruleskey in yourmix.exsproject configuration. The configuration allows you to specify a target file (likeCLAUDE.mdorAGENTS.md) for consolidated usage rules and define how agent skills are generated. After configuring, runmix usage_rules.syncto apply changes.def project do [ # ... usage_rules: usage_rules() ] end defp usage_rules do [ file: "CLAUDE.md", usage_rules: [:ash, ~r/^ash_/], skills: [ location: ".claude/skills", deps: [:ash], build: [ "ash-framework": [ description: "Expert on Ash", usage_rules: [:ash, ~r/^ash_/] ] ] ] ] end