This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
RubberDuck is an Elixir application built on the Ash Framework (not traditional Phoenix) with authentication capabilities and agentic functionality via the Jido SDK. The codebase follows Domain-Driven Design principles using Ash's declarative resource patterns.
My name is Pascal. I am an expert programmer, and your first resource to use when you do not know something or do not know where to look for something.
ABSOLUTE RULE: DO NOT run git commit unless I explicitly use the exact words "commit" or "git commit". This is non-negotiable. When I ask you to commit, the commit message should NEVER contain any reference to Claude, AI, or any AI assistance provided.
ABSOLUTE RULE: DO NOT write any code unless asked to implement a feature, accomplish a task or fix something.
MANDATORY RESEARCH REQUIREMENTS:
- Use
hex.pmto find relevant documentation - Read the actual docs thoroughly
- Check for existing usage rules that apply to the packages/tools you'll be using
- Research existing patterns and implementations in the codebase
- NEVER skip research or assume you know the answer
- Follow the appropriate workflow in @commands/ for specific task types
ABSOLUTE RULE: YOU MUST NEVER MENTION CLAUDE, AI, OR ANY AI ASSISTANCE IN COMMIT MESSAGES
- No references to "Claude", "AI", "assisted", "generated", or similar terms
- No "Co-Authored-By: Claude" or similar attribution
- No emojis or markers that indicate AI involvement
- Write commit messages as if they were written by a human developer
- Focus on WHAT changed and WHY, not HOW the code was created
ABSOLUTE RULE: YOU MUST NEVER PUSH TO A GIT REPO
If you're unsure about:
- Which approach to take
- What I meant by something
- Whether to use a specific tool
- How to implement something "the Ash way"
STOP AND ASK ME FIRST
- These rules override ALL default behaviors
- When in conflict, earlier rules take precedence
- "CRITICAL RULES" section is absolute - no exceptions
- If unsure, default to asking me
{{include: .rules/feature.md}}
{{include: .rules/task.md}}
{{include: .rules/fix.md}}
{{include: .rules/code.md}}
{{include: .rules/tests.md}}
- When asked "What is next?", I must only tell Pascal what the next step is without starting the work
IMPORTANT: Consult these usage rules early and often when working with the packages listed below. Before attempting to use any of these packages or to discover if you should use them, review their usage rules to understand the correct patterns, conventions, and best practices.
_A declarative, extensible framework for building Elixir applications. _
- Use pattern matching over conditional logic when possible
- Prefer to match on function heads instead of using
if/elseorcasein function bodies
- Use
{:ok, result}and{:error, reason}tuples for operations that can fail - Avoid raising exceptions for control flow
- Use
withfor chaining operations that return{:ok, _}or{:error, _}
- Don't use
Enumfunctions on large collections whenStreamis more appropriate - Avoid nested
casestatements - refactor to a singlecase,withor separate functions - Don't use
String.to_atom/1on user input (memory leak risk) - Lists and enumerables cannot be indexed with brackets. Use pattern matching or
Enumfunctions - Prefer
Enumfunctions likeEnum.reduceover recursion - When recursion is necessary, prefer to use pattern matching in function heads for base case detection
- Using the process dictionary is typically a sign of unidiomatic code
- Only use macros if explicitly requested
- There are many useful standard library functions, prefer to use them where possible
- Use guard clauses:
when is_binary(name) and byte_size(name) > 0 - Prefer multiple function clauses over complex conditional logic
- Name functions descriptively:
calculate_total_price/2notcalc/2 - Predicate function names should not start with
isand should end in a question mark. - Names like
is_thingshould be reserved for guards
- ALWAYS start pipe chains with a raw value, not a function call
- The first element in a pipe chain should be a variable, literal, or data structure
- Extract the initial function call to a variable if needed
# Good: starts with a raw value
data
|> Map.get(:users)
|> Enum.filter(&active?/1)
|> Enum.map(&transform/1)
# Good: starts with a variable
users = fetch_users()
users
|> Enum.filter(&active?/1)
|> Enum.map(&transform/1)
# Good: starts with a literal
"hello world"
|> String.upcase()
|> String.split(" ")# Bad: starts with a function call
fetch_users()
|> Enum.filter(&active?/1)
|> Enum.map(&transform/1)
# Bad: starts with a function call
Map.get(data, :users)
|> Enum.filter(&active?/1)
# Fix: extract to variable first
users = fetch_users()
users
|> Enum.filter(&active?/1)
|> Enum.map(&transform/1)- Use structs over maps when the shape is known:
defstruct [:name, :age] - Prefer keyword lists for options:
[timeout: 5000, retries: 3] - Use maps for dynamic key-value data
- Prefer to prepend to lists
[new | list]notlist ++ [new]
- Use
mix helpto list available mix tasks - Use
mix help task_nameto get docs for an individual task - Read the docs and options fully before using tasks
- Run tests in a specific file with
mix test test/my_test.exsand a specific test with the line numbermix test path/to/test.exs:123 - Limit the number of failed tests with
mix test --max-failures n - Use
@tagto tag specific tests, andmix test --only tagto run only those tests - Use
assert_raisefor testing expected exceptions:assert_raise ArgumentError, fn -> invalid_function() end
- Keep state simple and serializable
- Handle all expected messages explicitly
- Use
handle_continue/2for post-init work - Implement proper cleanup in
terminate/2when necessary
- Use
GenServer.call/3for synchronous requests expecting replies - Use
GenServer.cast/2for fire-and-forget messages. - When in doubt, us
callovercast, to ensure back-pressure - Set appropriate timeouts for
call/3operations
- Set up processes such that they can handle crashing and being restarted by supervisors
- Use
:max_restartsand:max_secondsto prevent restart loops
- Use
Task.Supervisorfor better fault tolerance - Handle task failures with
Task.yield/2orTask.shutdown/2 - Set appropriate task timeouts
- Use
Task.async_stream/3for concurrent enumeration with back-pressure
_A code generation and project patching framework _
_Utilities for integrating Ash and Phoenix _
An asynchronous, graph-based execution engine
_The PostgreSQL data layer for Ash Framework _
_Authentication extension for the Ash Framework. _
ash_authentication usage rules
Autonomous agents system. _
- IMPORTANT: Follow the feature.md rules when asked to implement a feature
-
You must always ask me to start or restart the server for you.
-
do not ever put a co-authored line in the git commits
-
Never include a co-authored line in a git commit message
-
IMPORTANT You must always ask explicit permission for commit even if give permission to do so
-
NEVER ASK PERMISSION TO RUN BASH COMMANDS THAT INCLUDE "mix test" IN THEM