kodelyth-ecc 1.5.5 → 1.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +47 -0
- package/.github/ISSUE_TEMPLATE/new_agent.md +52 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +53 -0
- package/CHANGELOG.md +35 -0
- package/README.md +4 -4
- package/VERSION +1 -1
- package/agents/kodelyth-advisor.md +0 -1
- package/bin/kodelyth-ecc.js +6 -1
- package/commands/doctor.md +75 -0
- package/commands/update.md +92 -0
- package/install.ps1 +16 -11
- package/install.sh +24 -14
- package/package.json +2 -2
- package/rules/common/agents.md +141 -45
- package/rules/elixir/coding-style.md +46 -0
- package/rules/elixir/hooks.md +26 -0
- package/rules/elixir/patterns.md +67 -0
- package/rules/elixir/security.md +58 -0
- package/rules/elixir/testing.md +64 -0
- package/rules/ruby/coding-style.md +41 -0
- package/rules/ruby/hooks.md +23 -0
- package/rules/ruby/patterns.md +71 -0
- package/rules/ruby/security.md +56 -0
- package/rules/ruby/testing.md +65 -0
package/rules/common/agents.md
CHANGED
|
@@ -1,50 +1,146 @@
|
|
|
1
1
|
# Agent Orchestration
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
| Agent |
|
|
8
|
-
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
3
|
+
62 specialist agents are available. Intent routing is always-on — describe your problem in plain words and the right agent is invoked automatically. You can also invoke explicitly: `use <agent-name>`.
|
|
4
|
+
|
|
5
|
+
## Kodelyth Exclusives
|
|
6
|
+
|
|
7
|
+
| Agent | When to Use |
|
|
8
|
+
|-------|-------------|
|
|
9
|
+
| `kodelyth-advisor` | Not sure where to start — master guide |
|
|
10
|
+
| `pair-programmer` | Before writing code — think through approach first |
|
|
11
|
+
| `debug-detective` | Any bug — evidence-first root cause, never guess-and-check |
|
|
12
|
+
| `silent-failure-hunter` | Bugs that don't throw errors |
|
|
13
|
+
| `incident-commander` | Production incident — P0/P1 triage, contain, postmortem |
|
|
14
|
+
| `load-tester` | Load/stress testing — k6, Locust, Artillery, capacity planning |
|
|
15
|
+
| `kodelyth-memory` | Manage local BM25 memory — recall, capture, review |
|
|
16
|
+
| `image-architect` | AI image generation — Gemini/DALL-E/fal.ai/SVG |
|
|
17
|
+
|
|
18
|
+
## Planning & Architecture
|
|
19
|
+
|
|
20
|
+
| Agent | When to Use |
|
|
21
|
+
|-------|-------------|
|
|
22
|
+
| `planner` | Plan a feature before writing a line of code |
|
|
23
|
+
| `architect` | System-level design, dependency graphs |
|
|
24
|
+
| `code-architect` | Code-level architecture decisions |
|
|
25
|
+
| `chief-of-staff` | Strategic decisions, comms, stakeholder updates |
|
|
26
|
+
| `migration-guide` | Framework/language version upgrades, phase by phase |
|
|
27
|
+
|
|
28
|
+
## Code Review
|
|
29
|
+
|
|
30
|
+
| Agent | When to Use |
|
|
31
|
+
|-------|-------------|
|
|
32
|
+
| `code-reviewer` | General review after writing code |
|
|
33
|
+
| `typescript-reviewer` | TypeScript / React / Next.js |
|
|
34
|
+
| `python-reviewer` | Python |
|
|
35
|
+
| `go-reviewer` | Go |
|
|
36
|
+
| `rust-reviewer` | Rust |
|
|
37
|
+
| `java-reviewer` | Java / Spring Boot |
|
|
38
|
+
| `kotlin-reviewer` | Kotlin / Android / KMP |
|
|
39
|
+
| `cpp-reviewer` | C++ |
|
|
40
|
+
| `csharp-reviewer` | C# / .NET |
|
|
41
|
+
| `flutter-reviewer` | Flutter / Dart |
|
|
42
|
+
| `database-reviewer` | SQL schema, query patterns, indexes |
|
|
43
|
+
| `healthcare-reviewer` | PHI/HIPAA-aware review for healthcare apps |
|
|
44
|
+
|
|
45
|
+
## Build Fixers
|
|
46
|
+
|
|
47
|
+
| Agent | When to Use |
|
|
48
|
+
|-------|-------------|
|
|
49
|
+
| `build-error-resolver` | General build failure |
|
|
50
|
+
| `go-build-resolver` | Go build errors |
|
|
51
|
+
| `rust-build-resolver` | Rust/Cargo build errors |
|
|
52
|
+
| `java-build-resolver` | Java/Maven/Gradle build errors |
|
|
53
|
+
| `kotlin-build-resolver` | Kotlin/Gradle build errors |
|
|
54
|
+
| `cpp-build-resolver` | C++/CMake/Make build errors |
|
|
55
|
+
| `dart-build-resolver` | Dart/Flutter build errors |
|
|
56
|
+
| `pytorch-build-resolver` | PyTorch/CUDA build errors |
|
|
57
|
+
| `dependency-doctor` | npm/pip/cargo/maven dep hell, CVEs, lockfile drift |
|
|
58
|
+
| `env-debugger` | "Works on my machine" — env, config, secrets layers |
|
|
59
|
+
|
|
60
|
+
## Debugging & Testing
|
|
61
|
+
|
|
62
|
+
| Agent | When to Use |
|
|
63
|
+
|-------|-------------|
|
|
64
|
+
| `tdd-guide` | Write tests first — TDD methodology |
|
|
65
|
+
| `e2e-runner` | End-to-end test automation |
|
|
66
|
+
| `pr-test-analyzer` | CI output — root cause failing tests |
|
|
67
|
+
| `flake-hunter` | Flaky test stabilization — never blind retries |
|
|
68
|
+
|
|
69
|
+
## Security & API
|
|
70
|
+
|
|
71
|
+
| Agent | When to Use |
|
|
72
|
+
|-------|-------------|
|
|
73
|
+
| `security-reviewer` | OWASP top 10, secrets, auth, injection vectors |
|
|
74
|
+
| `api-guardian` | Detect breaking API changes before they ship |
|
|
75
|
+
|
|
76
|
+
## Performance & Quality
|
|
77
|
+
|
|
78
|
+
| Agent | When to Use |
|
|
79
|
+
|-------|-------------|
|
|
80
|
+
| `performance-optimizer` | Profiling-first — measure before optimizing |
|
|
81
|
+
| `refactor-cleaner` | Remove code smells, dead code, tech debt |
|
|
82
|
+
| `code-simplifier` | Improve readability without changing behavior |
|
|
83
|
+
| `type-design-analyzer` | TypeScript type system design |
|
|
84
|
+
|
|
85
|
+
## Documentation & Analysis
|
|
86
|
+
|
|
87
|
+
| Agent | When to Use |
|
|
88
|
+
|-------|-------------|
|
|
89
|
+
| `doc-updater` | Update or write documentation |
|
|
90
|
+
| `docs-lookup` | Find docs for a library or API |
|
|
91
|
+
| `comment-analyzer` | Audit code comments for accuracy |
|
|
92
|
+
| `code-explorer` | Explore an unfamiliar codebase |
|
|
93
|
+
| `conversation-analyzer` | Analyze conversation or chat patterns |
|
|
94
|
+
|
|
95
|
+
## Release & Ops
|
|
96
|
+
|
|
97
|
+
| Agent | When to Use |
|
|
98
|
+
|-------|-------------|
|
|
99
|
+
| `release-captain` | Cut a clean release — semver, tagging, rollback plan |
|
|
100
|
+
| `git-rescue` | Broken git state, lost commits, bad rebase — no history loss |
|
|
101
|
+
|
|
102
|
+
## Open Source
|
|
103
|
+
|
|
104
|
+
| Agent | When to Use |
|
|
105
|
+
|-------|-------------|
|
|
106
|
+
| `opensource-forker` | Fork and clean a project for open-source release |
|
|
107
|
+
| `opensource-sanitizer` | Strip secrets, PII, proprietary references |
|
|
108
|
+
| `opensource-packager` | README, license, contribution docs |
|
|
109
|
+
|
|
110
|
+
## Specialized
|
|
111
|
+
|
|
112
|
+
| Agent | When to Use |
|
|
113
|
+
|-------|-------------|
|
|
114
|
+
| `ux-reviewer` | UX behavior + WCAG 2.1 AA accessibility |
|
|
115
|
+
| `seo-specialist` | Technical SEO, structured data, rankings |
|
|
116
|
+
|
|
117
|
+
## GAN Harness (Multi-Agent)
|
|
118
|
+
|
|
119
|
+
| Agent | When to Use |
|
|
120
|
+
|-------|-------------|
|
|
121
|
+
| `gan-planner` | Plan a GAN-style generator/evaluator workflow |
|
|
122
|
+
| `gan-generator` | Generate output in a GAN harness loop |
|
|
123
|
+
| `gan-evaluator` | Evaluate output and provide adversarial feedback |
|
|
124
|
+
| `harness-optimizer` | Optimize agent harness action spaces |
|
|
125
|
+
| `loop-operator` | Operate autonomous agent loops |
|
|
126
|
+
|
|
127
|
+
## Parallel Execution
|
|
128
|
+
|
|
129
|
+
ALWAYS launch independent agents in parallel:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
# GOOD: parallel
|
|
133
|
+
use code-reviewer + security-reviewer + ux-reviewer simultaneously
|
|
134
|
+
|
|
135
|
+
# BAD: sequential when not needed
|
|
136
|
+
code-reviewer → then security-reviewer → then ux-reviewer
|
|
41
137
|
```
|
|
42
138
|
|
|
43
|
-
##
|
|
139
|
+
## Standard Handoff Chains
|
|
44
140
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
141
|
+
| Workflow | Chain |
|
|
142
|
+
|----------|-------|
|
|
143
|
+
| New feature | `pair-programmer` → `tdd-guide` → `code-reviewer` → `security-reviewer` |
|
|
144
|
+
| Bug fix | `debug-detective` → `tdd-guide` → `refactor-cleaner` |
|
|
145
|
+
| Production incident | `incident-commander` → `debug-detective` → `tdd-guide` |
|
|
146
|
+
| Open-source | `opensource-forker` → `opensource-sanitizer` → `opensource-packager` → `release-captain` |
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ex"
|
|
4
|
+
- "**/*.exs"
|
|
5
|
+
---
|
|
6
|
+
# Elixir Coding Style
|
|
7
|
+
|
|
8
|
+
> This file extends [common/coding-style.md](../common/coding-style.md) with Elixir specific content.
|
|
9
|
+
|
|
10
|
+
## Standards
|
|
11
|
+
|
|
12
|
+
- Follow the official **Elixir Style Guide**
|
|
13
|
+
- Use **mix format** — non-negotiable, always auto-format
|
|
14
|
+
- All public functions must have `@spec` type annotations and `@doc` documentation
|
|
15
|
+
|
|
16
|
+
## Immutability
|
|
17
|
+
|
|
18
|
+
Data is immutable by default in Elixir. Embrace it:
|
|
19
|
+
|
|
20
|
+
```elixir
|
|
21
|
+
# Use the pipe operator for data transformations
|
|
22
|
+
result =
|
|
23
|
+
input
|
|
24
|
+
|> validate()
|
|
25
|
+
|> transform()
|
|
26
|
+
|> persist()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Function Heads Over Conditionals
|
|
30
|
+
|
|
31
|
+
```elixir
|
|
32
|
+
# Prefer pattern-matched function heads over cond/case at the top level
|
|
33
|
+
def process(%{status: :active} = user), do: activate(user)
|
|
34
|
+
def process(%{status: :banned} = user), do: reject(user)
|
|
35
|
+
def process(_user), do: {:error, :unknown_status}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Formatting
|
|
39
|
+
|
|
40
|
+
- **mix format** — run on every save
|
|
41
|
+
- **Credo** for code quality and style checks
|
|
42
|
+
- Line length: 98 characters (mix format default)
|
|
43
|
+
|
|
44
|
+
## Reference
|
|
45
|
+
|
|
46
|
+
See skill: `elixir-patterns` for comprehensive GenServer, Phoenix, and OTP patterns.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ex"
|
|
4
|
+
- "**/*.exs"
|
|
5
|
+
---
|
|
6
|
+
# Elixir Hooks
|
|
7
|
+
|
|
8
|
+
> This file extends [common/hooks.md](../common/hooks.md) with Elixir specific content.
|
|
9
|
+
|
|
10
|
+
## PostToolUse Hooks
|
|
11
|
+
|
|
12
|
+
Configure in `~/.claude/settings.json`:
|
|
13
|
+
|
|
14
|
+
- **mix format**: Auto-format `.ex` / `.exs` files after edit
|
|
15
|
+
```bash
|
|
16
|
+
mix format <file>
|
|
17
|
+
```
|
|
18
|
+
- **Credo**: Run on edited files for style warnings
|
|
19
|
+
```bash
|
|
20
|
+
mix credo <file>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Warnings
|
|
24
|
+
|
|
25
|
+
- Warn when `IO.inspect` is left in non-test `.ex` files (use `Logger` instead)
|
|
26
|
+
- Warn when `dbg()` (Elixir 1.14+) is left in production code paths
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ex"
|
|
4
|
+
- "**/*.exs"
|
|
5
|
+
---
|
|
6
|
+
# Elixir Patterns
|
|
7
|
+
|
|
8
|
+
> This file extends [common/patterns.md](../common/patterns.md) with Elixir specific content.
|
|
9
|
+
|
|
10
|
+
## with for Multi-Step Operations
|
|
11
|
+
|
|
12
|
+
```elixir
|
|
13
|
+
def create_user(params) do
|
|
14
|
+
with {:ok, validated} <- validate(params),
|
|
15
|
+
{:ok, user} <- Repo.insert(User.changeset(%User{}, validated)),
|
|
16
|
+
:ok <- send_welcome_email(user) do
|
|
17
|
+
{:ok, user}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## GenServer Pattern
|
|
23
|
+
|
|
24
|
+
```elixir
|
|
25
|
+
defmodule MyApp.Cache do
|
|
26
|
+
use GenServer
|
|
27
|
+
|
|
28
|
+
def start_link(opts), do: GenServer.start_link(__MODULE__, %{}, opts)
|
|
29
|
+
|
|
30
|
+
def get(pid, key), do: GenServer.call(pid, {:get, key})
|
|
31
|
+
def put(pid, key, value), do: GenServer.cast(pid, {:put, key, value})
|
|
32
|
+
|
|
33
|
+
@impl true
|
|
34
|
+
def init(state), do: {:ok, state}
|
|
35
|
+
|
|
36
|
+
@impl true
|
|
37
|
+
def handle_call({:get, key}, _from, state), do: {:reply, Map.get(state, key), state}
|
|
38
|
+
|
|
39
|
+
@impl true
|
|
40
|
+
def handle_cast({:put, key, value}, state), do: {:noreply, Map.put(state, key, value)}
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Context Modules (Phoenix)
|
|
45
|
+
|
|
46
|
+
```elixir
|
|
47
|
+
defmodule MyApp.Accounts do
|
|
48
|
+
alias MyApp.Accounts.User
|
|
49
|
+
alias MyApp.Repo
|
|
50
|
+
|
|
51
|
+
def get_user!(id), do: Repo.get!(User, id)
|
|
52
|
+
|
|
53
|
+
def create_user(attrs) do
|
|
54
|
+
%User{}
|
|
55
|
+
|> User.changeset(attrs)
|
|
56
|
+
|> Repo.insert()
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Tagged Tuples for Errors
|
|
62
|
+
|
|
63
|
+
Always return `{:ok, result}` or `{:error, reason}` — never bare values from functions that can fail.
|
|
64
|
+
|
|
65
|
+
## Reference
|
|
66
|
+
|
|
67
|
+
See skill: `phoenix-patterns` for Phoenix LiveView, contexts, and Ecto query patterns.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ex"
|
|
4
|
+
- "**/*.exs"
|
|
5
|
+
---
|
|
6
|
+
# Elixir Security
|
|
7
|
+
|
|
8
|
+
> This file extends [common/security.md](../common/security.md) with Elixir specific content.
|
|
9
|
+
|
|
10
|
+
## Secret Management
|
|
11
|
+
|
|
12
|
+
```elixir
|
|
13
|
+
# config/runtime.exs — read from environment at runtime, never compile-time
|
|
14
|
+
config :my_app, :stripe_key,
|
|
15
|
+
System.fetch_env!("STRIPE_SECRET_KEY") # raises if missing
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Never put secrets in `config/config.exs` or `config/dev.exs` committed to git.
|
|
19
|
+
|
|
20
|
+
## SQL Injection
|
|
21
|
+
|
|
22
|
+
Always use Ecto parameterized queries:
|
|
23
|
+
|
|
24
|
+
```elixir
|
|
25
|
+
# UNSAFE — never do this
|
|
26
|
+
Repo.query("SELECT * FROM users WHERE email = '#{email}'")
|
|
27
|
+
|
|
28
|
+
# SAFE
|
|
29
|
+
from(u in User, where: u.email == ^email) |> Repo.one()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Atom Exhaustion
|
|
33
|
+
|
|
34
|
+
Never convert untrusted user input to atoms — the atom table is not garbage collected:
|
|
35
|
+
|
|
36
|
+
```elixir
|
|
37
|
+
# UNSAFE
|
|
38
|
+
String.to_atom(user_input)
|
|
39
|
+
|
|
40
|
+
# SAFE
|
|
41
|
+
String.to_existing_atom(user_input) # only if atom must already exist
|
|
42
|
+
# or keep it as a string
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Security Scanning
|
|
46
|
+
|
|
47
|
+
- **Sobelow** for Phoenix/Elixir static security analysis:
|
|
48
|
+
```bash
|
|
49
|
+
mix sobelow --config
|
|
50
|
+
```
|
|
51
|
+
- **mix audit** for dependency vulnerability scanning:
|
|
52
|
+
```bash
|
|
53
|
+
mix hex.audit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Reference
|
|
57
|
+
|
|
58
|
+
See skill: `security-review` for OWASP top 10 and authentication patterns.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ex"
|
|
4
|
+
- "**/*.exs"
|
|
5
|
+
- "**/test/**"
|
|
6
|
+
---
|
|
7
|
+
# Elixir Testing
|
|
8
|
+
|
|
9
|
+
> This file extends [common/testing.md](../common/testing.md) with Elixir specific content.
|
|
10
|
+
|
|
11
|
+
## Framework
|
|
12
|
+
|
|
13
|
+
Use **ExUnit** (built-in). Use **Mox** for behaviour-based mocking.
|
|
14
|
+
|
|
15
|
+
## Structure
|
|
16
|
+
|
|
17
|
+
```elixir
|
|
18
|
+
defmodule MyApp.AccountsTest do
|
|
19
|
+
use MyApp.DataCase
|
|
20
|
+
|
|
21
|
+
alias MyApp.Accounts
|
|
22
|
+
|
|
23
|
+
describe "create_user/1" do
|
|
24
|
+
test "creates a user with valid attrs" do
|
|
25
|
+
attrs = %{name: "Alice", email: "alice@example.com"}
|
|
26
|
+
assert {:ok, user} = Accounts.create_user(attrs)
|
|
27
|
+
assert user.email == "alice@example.com"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test "returns error with invalid attrs" do
|
|
31
|
+
assert {:error, changeset} = Accounts.create_user(%{})
|
|
32
|
+
assert "can't be blank" in errors_on(changeset).email
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Coverage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
mix test --cover
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use **excoveralls** for detailed coverage reports:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
mix coveralls
|
|
48
|
+
mix coveralls.html
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Async Tests
|
|
52
|
+
|
|
53
|
+
Mark tests as `async: true` when they don't share state:
|
|
54
|
+
|
|
55
|
+
```elixir
|
|
56
|
+
defmodule MyApp.PureTest do
|
|
57
|
+
use ExUnit.Case, async: true
|
|
58
|
+
...
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Reference
|
|
63
|
+
|
|
64
|
+
See skill: `elixir-testing` for ExUnit async patterns, Mox setup, and property-based testing with StreamData.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.rb"
|
|
4
|
+
- "**/*.rake"
|
|
5
|
+
- "**/Gemfile"
|
|
6
|
+
- "**/Rakefile"
|
|
7
|
+
---
|
|
8
|
+
# Ruby Coding Style
|
|
9
|
+
|
|
10
|
+
> This file extends [common/coding-style.md](../common/coding-style.md) with Ruby specific content.
|
|
11
|
+
|
|
12
|
+
## Standards
|
|
13
|
+
|
|
14
|
+
- Follow the **Ruby Style Guide** (rubocop default)
|
|
15
|
+
- Use **frozen_string_literal: true** at the top of every file
|
|
16
|
+
- Prefer `do...end` for multi-line blocks, `{ }` for single-line
|
|
17
|
+
|
|
18
|
+
## Immutability
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
# frozen_string_literal: true
|
|
22
|
+
|
|
23
|
+
User = Data.define(:name, :email) # Ruby 3.2+ immutable value object
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Formatting
|
|
27
|
+
|
|
28
|
+
- **RuboCop** for linting and style enforcement
|
|
29
|
+
- **StandardRB** as a zero-config RuboCop config alternative
|
|
30
|
+
- Line length: 120 characters max
|
|
31
|
+
|
|
32
|
+
## Naming
|
|
33
|
+
|
|
34
|
+
- `snake_case` for methods and variables
|
|
35
|
+
- `CamelCase` for classes and modules
|
|
36
|
+
- `SCREAMING_SNAKE_CASE` for constants
|
|
37
|
+
- Predicate methods end with `?`, destructive methods end with `!`
|
|
38
|
+
|
|
39
|
+
## Reference
|
|
40
|
+
|
|
41
|
+
See skill: `ruby-patterns` for comprehensive Ruby idioms, Rails patterns, and concurrency.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.rb"
|
|
4
|
+
- "**/*.rake"
|
|
5
|
+
---
|
|
6
|
+
# Ruby Hooks
|
|
7
|
+
|
|
8
|
+
> This file extends [common/hooks.md](../common/hooks.md) with Ruby specific content.
|
|
9
|
+
|
|
10
|
+
## PostToolUse Hooks
|
|
11
|
+
|
|
12
|
+
Configure in `~/.claude/settings.json`:
|
|
13
|
+
|
|
14
|
+
- **RuboCop**: Auto-lint `.rb` files after edit
|
|
15
|
+
```bash
|
|
16
|
+
rubocop --autocorrect <file>
|
|
17
|
+
```
|
|
18
|
+
- **Syntax check**: Run `ruby -c <file>` after editing
|
|
19
|
+
|
|
20
|
+
## Warnings
|
|
21
|
+
|
|
22
|
+
- Warn about `puts` / `p` statements in non-test `.rb` files (use `Rails.logger` or a logger instead)
|
|
23
|
+
- Warn when `binding.pry` or `byebug` is left in edited files
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.rb"
|
|
4
|
+
- "**/*.rake"
|
|
5
|
+
---
|
|
6
|
+
# Ruby Patterns
|
|
7
|
+
|
|
8
|
+
> This file extends [common/patterns.md](../common/patterns.md) with Ruby specific content.
|
|
9
|
+
|
|
10
|
+
## Service Objects
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
# frozen_string_literal: true
|
|
14
|
+
|
|
15
|
+
class CreateUserService
|
|
16
|
+
def initialize(params)
|
|
17
|
+
@params = params
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call
|
|
21
|
+
user = User.new(@params)
|
|
22
|
+
user.save!
|
|
23
|
+
user
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Usage
|
|
28
|
+
result = CreateUserService.new(params).call
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Value Objects
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
# frozen_string_literal: true
|
|
35
|
+
|
|
36
|
+
Address = Data.define(:street, :city, :country)
|
|
37
|
+
|
|
38
|
+
address = Address.new(street: "123 Main St", city: "London", country: "UK")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Query Objects
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
# frozen_string_literal: true
|
|
45
|
+
|
|
46
|
+
class ActiveUsersQuery
|
|
47
|
+
def initialize(relation = User.all)
|
|
48
|
+
@relation = relation
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def call
|
|
52
|
+
@relation.where(status: :active).order(created_at: :desc)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Modules for Composition
|
|
58
|
+
|
|
59
|
+
Prefer composition over inheritance for shared behavior:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
module Auditable
|
|
63
|
+
def self.included(base)
|
|
64
|
+
base.before_action :track_activity
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Reference
|
|
70
|
+
|
|
71
|
+
See skill: `rails-patterns` for Rails-specific patterns including concerns, callbacks, and ActiveRecord best practices.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.rb"
|
|
4
|
+
- "**/*.rake"
|
|
5
|
+
---
|
|
6
|
+
# Ruby Security
|
|
7
|
+
|
|
8
|
+
> This file extends [common/security.md](../common/security.md) with Ruby specific content.
|
|
9
|
+
|
|
10
|
+
## Secret Management
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
# Never hardcode secrets
|
|
14
|
+
api_key = ENV.fetch("STRIPE_SECRET_KEY") # raises KeyError if missing, not nil
|
|
15
|
+
|
|
16
|
+
# Rails credentials (encrypted)
|
|
17
|
+
Rails.application.credentials.stripe[:secret_key]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## SQL Injection
|
|
21
|
+
|
|
22
|
+
Always use parameterized queries — never string interpolation:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
# UNSAFE
|
|
26
|
+
User.where("email = '#{params[:email]}'")
|
|
27
|
+
|
|
28
|
+
# SAFE
|
|
29
|
+
User.where(email: params[:email])
|
|
30
|
+
User.where("email = ?", params[:email])
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Mass Assignment
|
|
34
|
+
|
|
35
|
+
Use strong parameters in Rails controllers:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
def user_params
|
|
39
|
+
params.require(:user).permit(:name, :email)
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Security Scanning
|
|
44
|
+
|
|
45
|
+
- **Brakeman** for static security analysis of Rails apps:
|
|
46
|
+
```bash
|
|
47
|
+
brakeman -q
|
|
48
|
+
```
|
|
49
|
+
- **bundler-audit** for dependency CVE scanning:
|
|
50
|
+
```bash
|
|
51
|
+
bundle audit check --update
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Reference
|
|
55
|
+
|
|
56
|
+
See skill: `security-review` for OWASP top 10 and auth patterns.
|