agent-notes 2.0.4__py3-none-any.whl
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.
- agent_notes/VERSION +1 -0
- agent_notes/__init__.py +1 -0
- agent_notes/__main__.py +4 -0
- agent_notes/cli.py +348 -0
- agent_notes/commands/__init__.py +27 -0
- agent_notes/commands/_install_helpers.py +262 -0
- agent_notes/commands/build.py +170 -0
- agent_notes/commands/doctor.py +112 -0
- agent_notes/commands/info.py +95 -0
- agent_notes/commands/install.py +99 -0
- agent_notes/commands/list.py +169 -0
- agent_notes/commands/memory.py +430 -0
- agent_notes/commands/regenerate.py +152 -0
- agent_notes/commands/set_role.py +143 -0
- agent_notes/commands/uninstall.py +26 -0
- agent_notes/commands/update.py +169 -0
- agent_notes/commands/validate.py +199 -0
- agent_notes/commands/wizard.py +720 -0
- agent_notes/config.py +154 -0
- agent_notes/data/agents/agents.yaml +352 -0
- agent_notes/data/agents/analyst.md +45 -0
- agent_notes/data/agents/api-reviewer.md +47 -0
- agent_notes/data/agents/architect.md +46 -0
- agent_notes/data/agents/coder.md +28 -0
- agent_notes/data/agents/database-specialist.md +45 -0
- agent_notes/data/agents/debugger.md +47 -0
- agent_notes/data/agents/devil.md +47 -0
- agent_notes/data/agents/devops.md +38 -0
- agent_notes/data/agents/explorer.md +23 -0
- agent_notes/data/agents/integrations.md +44 -0
- agent_notes/data/agents/lead.md +216 -0
- agent_notes/data/agents/performance-profiler.md +44 -0
- agent_notes/data/agents/refactorer.md +48 -0
- agent_notes/data/agents/reviewer.md +44 -0
- agent_notes/data/agents/security-auditor.md +44 -0
- agent_notes/data/agents/system-auditor.md +38 -0
- agent_notes/data/agents/tech-writer.md +32 -0
- agent_notes/data/agents/test-runner.md +36 -0
- agent_notes/data/agents/test-writer.md +39 -0
- agent_notes/data/cli/claude.yaml +25 -0
- agent_notes/data/cli/copilot.yaml +18 -0
- agent_notes/data/cli/opencode.yaml +22 -0
- agent_notes/data/commands/brainstorm.md +8 -0
- agent_notes/data/commands/debug.md +9 -0
- agent_notes/data/commands/review.md +10 -0
- agent_notes/data/global-claude.md +290 -0
- agent_notes/data/global-copilot.md +27 -0
- agent_notes/data/global-opencode.md +40 -0
- agent_notes/data/hooks/session-context.md.tpl +19 -0
- agent_notes/data/models/claude-haiku-4-5.yaml +15 -0
- agent_notes/data/models/claude-opus-4-1.yaml +16 -0
- agent_notes/data/models/claude-opus-4-5.yaml +16 -0
- agent_notes/data/models/claude-opus-4-6.yaml +16 -0
- agent_notes/data/models/claude-opus-4-7.yaml +15 -0
- agent_notes/data/models/claude-sonnet-4-5.yaml +16 -0
- agent_notes/data/models/claude-sonnet-4-6.yaml +15 -0
- agent_notes/data/models/claude-sonnet-4.yaml +16 -0
- agent_notes/data/pricing.yaml +33 -0
- agent_notes/data/roles/orchestrator.yaml +5 -0
- agent_notes/data/roles/reasoner.yaml +5 -0
- agent_notes/data/roles/scout.yaml +5 -0
- agent_notes/data/roles/worker.yaml +5 -0
- agent_notes/data/rules/code-quality.md +9 -0
- agent_notes/data/rules/safety.md +10 -0
- agent_notes/data/scripts/cost-report +211 -0
- agent_notes/data/skills/brainstorming/SKILL.md +57 -0
- agent_notes/data/skills/code-review/SKILL.md +64 -0
- agent_notes/data/skills/debugging-protocol/SKILL.md +51 -0
- agent_notes/data/skills/docker-compose/SKILL.md +318 -0
- agent_notes/data/skills/docker-compose-advanced/SKILL.md +575 -0
- agent_notes/data/skills/docker-dockerfile/SKILL.md +385 -0
- agent_notes/data/skills/docker-dockerfile-languages/SKILL.md +293 -0
- agent_notes/data/skills/git/SKILL.md +87 -0
- agent_notes/data/skills/rails-active-storage/SKILL.md +321 -0
- agent_notes/data/skills/rails-broadcasting/SKILL.md +374 -0
- agent_notes/data/skills/rails-concerns/SKILL.md +806 -0
- agent_notes/data/skills/rails-controllers/SKILL.md +510 -0
- agent_notes/data/skills/rails-controllers-advanced/SKILL.md +441 -0
- agent_notes/data/skills/rails-helpers/SKILL.md +677 -0
- agent_notes/data/skills/rails-initializers/SKILL.md +79 -0
- agent_notes/data/skills/rails-javascript/SKILL.md +567 -0
- agent_notes/data/skills/rails-jobs/SKILL.md +700 -0
- agent_notes/data/skills/rails-kamal/SKILL.md +483 -0
- agent_notes/data/skills/rails-lib/SKILL.md +101 -0
- agent_notes/data/skills/rails-mailers/SKILL.md +321 -0
- agent_notes/data/skills/rails-migrations/SKILL.md +268 -0
- agent_notes/data/skills/rails-models/SKILL.md +459 -0
- agent_notes/data/skills/rails-models-advanced/SKILL.md +398 -0
- agent_notes/data/skills/rails-routes/SKILL.md +804 -0
- agent_notes/data/skills/rails-style/SKILL.md +538 -0
- agent_notes/data/skills/rails-testing-controllers/SKILL.md +343 -0
- agent_notes/data/skills/rails-testing-models/SKILL.md +296 -0
- agent_notes/data/skills/rails-testing-system/SKILL.md +375 -0
- agent_notes/data/skills/rails-validations/SKILL.md +108 -0
- agent_notes/data/skills/rails-view-components/SKILL.md +511 -0
- agent_notes/data/skills/rails-view-components-advanced/SKILL.md +376 -0
- agent_notes/data/skills/rails-views/SKILL.md +413 -0
- agent_notes/data/skills/rails-views-advanced/SKILL.md +450 -0
- agent_notes/data/skills/refactoring-protocol/SKILL.md +64 -0
- agent_notes/data/skills/tdd/SKILL.md +57 -0
- agent_notes/data/templates/__init__.py +1 -0
- agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
- agent_notes/data/templates/frontmatter/__init__.py +1 -0
- agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
- agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
- agent_notes/data/templates/frontmatter/__pycache__/cursor.cpython-314.pyc +0 -0
- agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
- agent_notes/data/templates/frontmatter/claude.py +44 -0
- agent_notes/data/templates/frontmatter/opencode.py +104 -0
- agent_notes/doctor_checks.py +189 -0
- agent_notes/domain/__init__.py +17 -0
- agent_notes/domain/agent.py +34 -0
- agent_notes/domain/cli_backend.py +40 -0
- agent_notes/domain/diagnostics.py +29 -0
- agent_notes/domain/diff.py +44 -0
- agent_notes/domain/model.py +27 -0
- agent_notes/domain/role.py +13 -0
- agent_notes/domain/rule.py +13 -0
- agent_notes/domain/skill.py +15 -0
- agent_notes/domain/state.py +46 -0
- agent_notes/install_state.py +11 -0
- agent_notes/registries/__init__.py +16 -0
- agent_notes/registries/_base.py +46 -0
- agent_notes/registries/agent_registry.py +107 -0
- agent_notes/registries/cli_registry.py +89 -0
- agent_notes/registries/model_registry.py +85 -0
- agent_notes/registries/role_registry.py +64 -0
- agent_notes/registries/rule_registry.py +80 -0
- agent_notes/registries/skill_registry.py +141 -0
- agent_notes/services/__init__.py +8 -0
- agent_notes/services/diagnostics/__init__.py +47 -0
- agent_notes/services/diagnostics/_checks.py +272 -0
- agent_notes/services/diagnostics/_display.py +346 -0
- agent_notes/services/diagnostics/_fix.py +169 -0
- agent_notes/services/diff.py +349 -0
- agent_notes/services/fs.py +195 -0
- agent_notes/services/install_state_builder.py +210 -0
- agent_notes/services/installer.py +293 -0
- agent_notes/services/memory_backend.py +155 -0
- agent_notes/services/rendering.py +329 -0
- agent_notes/services/session_context.py +23 -0
- agent_notes/services/settings_writer.py +79 -0
- agent_notes/services/state_store.py +249 -0
- agent_notes/services/ui.py +419 -0
- agent_notes/services/user_config.py +62 -0
- agent_notes/services/validation.py +67 -0
- agent_notes/state.py +21 -0
- agent_notes-2.0.4.dist-info/METADATA +14 -0
- agent_notes-2.0.4.dist-info/RECORD +162 -0
- agent_notes-2.0.4.dist-info/WHEEL +5 -0
- agent_notes-2.0.4.dist-info/entry_points.txt +2 -0
- agent_notes-2.0.4.dist-info/licenses/LICENSE +21 -0
- agent_notes-2.0.4.dist-info/top_level.txt +2 -0
- tests/conftest.py +20 -0
- tests/functional/__init__.py +0 -0
- tests/functional/test_build_commands.py +88 -0
- tests/functional/test_registries.py +128 -0
- tests/integration/__init__.py +0 -0
- tests/integration/test_build_output.py +129 -0
- tests/plugins/__init__.py +0 -0
- tests/plugins/test_agents.py +93 -0
- tests/plugins/test_skills.py +77 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rails-kamal
|
|
3
|
+
description: "Kamal deployment: zero-downtime Docker deploys, accessories, secrets, and configuration"
|
|
4
|
+
group: kamal
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Kamal
|
|
8
|
+
|
|
9
|
+
Deploy web apps anywhere with zero-downtime deployments using Docker.
|
|
10
|
+
|
|
11
|
+
> **Source**: [Kamal Official Documentation](https://kamal-deploy.org/) | [GitHub](https://github.com/basecamp/kamal)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
**Kamal** = "Capistrano for Containers" by 37signals. Default deployment tool for Rails 8.
|
|
18
|
+
|
|
19
|
+
**Key Features:**
|
|
20
|
+
- Zero-downtime deployments via Traefik proxy
|
|
21
|
+
- Deploy anywhere (VPS, bare metal, cloud)
|
|
22
|
+
- Remote builds, asset bridging
|
|
23
|
+
- Accessory management (databases, Redis)
|
|
24
|
+
- Automatic provisioning
|
|
25
|
+
- Docker layer caching
|
|
26
|
+
|
|
27
|
+
**Source**: [Kamal Documentation](https://kamal-deploy.org/)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
### Rails 8+ (Pre-installed)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
rails new myapp
|
|
37
|
+
cd myapp
|
|
38
|
+
# config/deploy.yml already exists
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Manual Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
gem install kamal
|
|
45
|
+
kamal init # Creates config/deploy.yml and .kamal/secrets
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
### Minimal deploy.yml
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
# config/deploy.yml
|
|
56
|
+
service: myapp
|
|
57
|
+
image: username/myapp
|
|
58
|
+
|
|
59
|
+
servers:
|
|
60
|
+
web:
|
|
61
|
+
hosts:
|
|
62
|
+
- 192.168.0.1
|
|
63
|
+
|
|
64
|
+
registry:
|
|
65
|
+
username: your-username
|
|
66
|
+
password:
|
|
67
|
+
- KAMAL_REGISTRY_PASSWORD
|
|
68
|
+
|
|
69
|
+
env:
|
|
70
|
+
secret:
|
|
71
|
+
- RAILS_MASTER_KEY
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Production Configuration
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
service: myapp
|
|
78
|
+
image: username/myapp
|
|
79
|
+
|
|
80
|
+
servers:
|
|
81
|
+
web:
|
|
82
|
+
hosts:
|
|
83
|
+
- 192.168.0.1
|
|
84
|
+
- 192.168.0.2
|
|
85
|
+
labels:
|
|
86
|
+
traefik.http.routers.myapp.rule: Host(`myapp.com`)
|
|
87
|
+
|
|
88
|
+
workers:
|
|
89
|
+
hosts:
|
|
90
|
+
- 192.168.0.3
|
|
91
|
+
cmd: bundle exec sidekiq
|
|
92
|
+
|
|
93
|
+
registry:
|
|
94
|
+
server: ghcr.io
|
|
95
|
+
username: github-username
|
|
96
|
+
password:
|
|
97
|
+
- KAMAL_REGISTRY_PASSWORD
|
|
98
|
+
|
|
99
|
+
proxy:
|
|
100
|
+
ssl: true
|
|
101
|
+
host: myapp.com
|
|
102
|
+
|
|
103
|
+
env:
|
|
104
|
+
clear:
|
|
105
|
+
RAILS_ENV: production
|
|
106
|
+
secret:
|
|
107
|
+
- RAILS_MASTER_KEY
|
|
108
|
+
- DATABASE_URL
|
|
109
|
+
|
|
110
|
+
asset_path: /app/public/assets
|
|
111
|
+
|
|
112
|
+
volumes:
|
|
113
|
+
- "storage:/app/storage"
|
|
114
|
+
|
|
115
|
+
retain_containers: 5
|
|
116
|
+
retain_images: 5
|
|
117
|
+
|
|
118
|
+
healthcheck:
|
|
119
|
+
path: /up
|
|
120
|
+
port: 3000
|
|
121
|
+
interval: 10s
|
|
122
|
+
|
|
123
|
+
ssh:
|
|
124
|
+
user: deploy
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Source**: [Kamal Configuration](https://kamal-deploy.org/docs/configuration/overview/)
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Accessories (Databases, Redis)
|
|
132
|
+
|
|
133
|
+
**Important**: Accessories **do not have zero-downtime deployments**. Managed separately from main app.
|
|
134
|
+
|
|
135
|
+
### PostgreSQL
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
accessories:
|
|
139
|
+
db:
|
|
140
|
+
image: postgres:16
|
|
141
|
+
host: 192.168.0.10
|
|
142
|
+
port: "5432:5432"
|
|
143
|
+
env:
|
|
144
|
+
clear:
|
|
145
|
+
POSTGRES_USER: myapp
|
|
146
|
+
secret:
|
|
147
|
+
- POSTGRES_PASSWORD
|
|
148
|
+
directories:
|
|
149
|
+
- data:/var/lib/postgresql/data
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Redis
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
accessories:
|
|
156
|
+
redis:
|
|
157
|
+
image: redis:7-alpine
|
|
158
|
+
host: 192.168.0.11
|
|
159
|
+
port: "6379:6379"
|
|
160
|
+
cmd: redis-server --appendonly yes
|
|
161
|
+
directories:
|
|
162
|
+
- data:/data
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### MySQL
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
accessories:
|
|
169
|
+
mysql:
|
|
170
|
+
image: mysql:8.0
|
|
171
|
+
host: 192.168.0.12
|
|
172
|
+
port: "3306:3306"
|
|
173
|
+
env:
|
|
174
|
+
clear:
|
|
175
|
+
MYSQL_DATABASE: myapp_production
|
|
176
|
+
secret:
|
|
177
|
+
- MYSQL_ROOT_PASSWORD
|
|
178
|
+
directories:
|
|
179
|
+
- data:/var/lib/mysql
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Source**: [Kamal Accessories](https://kamal-deploy.org/docs/configuration/accessories/)
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Commands
|
|
187
|
+
|
|
188
|
+
### Deployment
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Initial setup
|
|
192
|
+
kamal setup
|
|
193
|
+
|
|
194
|
+
# Deploy
|
|
195
|
+
kamal deploy
|
|
196
|
+
kamal deploy -d staging
|
|
197
|
+
kamal deploy -d production
|
|
198
|
+
|
|
199
|
+
# App management
|
|
200
|
+
kamal app restart
|
|
201
|
+
kamal app logs -f
|
|
202
|
+
kamal app exec 'bin/rails console'
|
|
203
|
+
kamal app exec 'bin/rails db:migrate'
|
|
204
|
+
|
|
205
|
+
# Accessories
|
|
206
|
+
kamal accessory boot all
|
|
207
|
+
kamal accessory boot db
|
|
208
|
+
kamal accessory reboot redis
|
|
209
|
+
kamal accessory logs db
|
|
210
|
+
|
|
211
|
+
# Cleanup
|
|
212
|
+
kamal prune -y
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Destinations (Staging/Production)
|
|
218
|
+
|
|
219
|
+
### Base Config
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
# config/deploy.yml
|
|
223
|
+
service: myapp
|
|
224
|
+
image: username/myapp
|
|
225
|
+
registry:
|
|
226
|
+
username: username
|
|
227
|
+
password:
|
|
228
|
+
- KAMAL_REGISTRY_PASSWORD
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Staging
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
# config/deploy.staging.yml
|
|
235
|
+
servers:
|
|
236
|
+
web:
|
|
237
|
+
hosts:
|
|
238
|
+
- staging.example.com
|
|
239
|
+
|
|
240
|
+
env:
|
|
241
|
+
clear:
|
|
242
|
+
RAILS_ENV: staging
|
|
243
|
+
|
|
244
|
+
proxy:
|
|
245
|
+
host: staging.myapp.com
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Production
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
# config/deploy.production.yml
|
|
252
|
+
servers:
|
|
253
|
+
web:
|
|
254
|
+
hosts:
|
|
255
|
+
- prod1.example.com
|
|
256
|
+
- prod2.example.com
|
|
257
|
+
|
|
258
|
+
env:
|
|
259
|
+
clear:
|
|
260
|
+
RAILS_ENV: production
|
|
261
|
+
|
|
262
|
+
proxy:
|
|
263
|
+
ssl: true
|
|
264
|
+
host: myapp.com
|
|
265
|
+
|
|
266
|
+
require_destination: true # Prevent accidental deploys
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Secrets Management
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# .kamal/secrets
|
|
275
|
+
KAMAL_REGISTRY_PASSWORD=your-password
|
|
276
|
+
RAILS_MASTER_KEY=your-key
|
|
277
|
+
DATABASE_URL=postgresql://user:pass@host:5432/db
|
|
278
|
+
REDIS_URL=redis://host:6379
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
# config/deploy.yml
|
|
283
|
+
registry:
|
|
284
|
+
password:
|
|
285
|
+
- KAMAL_REGISTRY_PASSWORD
|
|
286
|
+
|
|
287
|
+
env:
|
|
288
|
+
secret:
|
|
289
|
+
- RAILS_MASTER_KEY
|
|
290
|
+
- DATABASE_URL
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Important**: Add `.kamal/secrets*` to `.gitignore`!
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Hooks
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
.kamal/hooks/
|
|
301
|
+
├── pre-deploy # Before deploy
|
|
302
|
+
├── post-deploy # After deploy
|
|
303
|
+
└── pre-traefik-reboot # Before proxy restart
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Example: Pre-deploy Hook
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
#!/bin/bash
|
|
310
|
+
# .kamal/hooks/pre-deploy
|
|
311
|
+
kamal app exec 'bin/rails db:migrate'
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Make executable: `chmod +x .kamal/hooks/*`
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Zero-Downtime Flow
|
|
319
|
+
|
|
320
|
+
1. Health check old version (proxy routes traffic)
|
|
321
|
+
2. Build new image
|
|
322
|
+
3. Push to registry
|
|
323
|
+
4. Pull on servers
|
|
324
|
+
5. Start new container alongside old
|
|
325
|
+
6. Health check new version
|
|
326
|
+
7. Proxy gradually shifts traffic
|
|
327
|
+
8. Stop old container
|
|
328
|
+
9. Cleanup based on retention settings
|
|
329
|
+
|
|
330
|
+
**Proxy (Traefik) is key** to zero-downtime.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Rails Patterns
|
|
335
|
+
|
|
336
|
+
### Database Migrations
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Via hook (recommended)
|
|
340
|
+
# .kamal/hooks/pre-deploy
|
|
341
|
+
kamal app exec 'bin/rails db:migrate'
|
|
342
|
+
|
|
343
|
+
# Or manually
|
|
344
|
+
kamal app exec 'bin/rails db:migrate'
|
|
345
|
+
kamal deploy
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Sidekiq Workers
|
|
349
|
+
|
|
350
|
+
```yaml
|
|
351
|
+
servers:
|
|
352
|
+
web:
|
|
353
|
+
hosts:
|
|
354
|
+
- web1.example.com
|
|
355
|
+
|
|
356
|
+
workers:
|
|
357
|
+
hosts:
|
|
358
|
+
- worker1.example.com
|
|
359
|
+
cmd: bundle exec sidekiq
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Console Access
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
kamal app exec 'bin/rails console'
|
|
366
|
+
kamal app exec 'bin/rails dbconsole'
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Best Practices
|
|
372
|
+
|
|
373
|
+
### ✅ DO
|
|
374
|
+
|
|
375
|
+
1. **Use destinations** for staging/production
|
|
376
|
+
```yaml
|
|
377
|
+
require_destination: true
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
2. **Configure health checks**
|
|
381
|
+
```yaml
|
|
382
|
+
healthcheck:
|
|
383
|
+
path: /up
|
|
384
|
+
interval: 10s
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
3. **Set retention limits**
|
|
388
|
+
```yaml
|
|
389
|
+
retain_containers: 5
|
|
390
|
+
retain_images: 5
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
4. **Use secrets file**, add to `.gitignore`
|
|
394
|
+
|
|
395
|
+
5. **Run accessories on separate hosts**
|
|
396
|
+
|
|
397
|
+
6. **Use pre-deploy hooks** for migrations
|
|
398
|
+
|
|
399
|
+
7. **Specific image tags** in production
|
|
400
|
+
```yaml
|
|
401
|
+
image: username/myapp:v1.2.3 # Not :latest
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### ❌ DON'T
|
|
405
|
+
|
|
406
|
+
1. **Don't commit secrets** to git
|
|
407
|
+
2. **Don't expect zero-downtime for accessories**
|
|
408
|
+
3. **Don't skip health checks**
|
|
409
|
+
4. **Don't use :latest tag** in production
|
|
410
|
+
5. **Don't deploy to production without testing staging first**
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Workflow
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
# 1. Initial setup
|
|
418
|
+
kamal setup
|
|
419
|
+
kamal accessory boot all
|
|
420
|
+
|
|
421
|
+
# 2. Development cycle
|
|
422
|
+
git commit -am "Update"
|
|
423
|
+
git push
|
|
424
|
+
kamal deploy -d staging
|
|
425
|
+
# Test staging
|
|
426
|
+
kamal deploy -d production
|
|
427
|
+
|
|
428
|
+
# 3. Monitoring
|
|
429
|
+
kamal app logs -f
|
|
430
|
+
kamal accessory logs db -f
|
|
431
|
+
|
|
432
|
+
# 4. Troubleshooting
|
|
433
|
+
kamal server containers
|
|
434
|
+
kamal app logs --tail 100
|
|
435
|
+
kamal prune -y
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Troubleshooting
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
# Check status
|
|
444
|
+
kamal server containers
|
|
445
|
+
|
|
446
|
+
# View logs
|
|
447
|
+
kamal app logs --tail 100
|
|
448
|
+
kamal accessory logs db
|
|
449
|
+
|
|
450
|
+
# Health check
|
|
451
|
+
curl https://myapp.com/up
|
|
452
|
+
|
|
453
|
+
# Increase timeouts
|
|
454
|
+
# In config/deploy.yml:
|
|
455
|
+
deploy_timeout: 60
|
|
456
|
+
readiness_delay: 10
|
|
457
|
+
|
|
458
|
+
# Cleanup
|
|
459
|
+
kamal prune -y
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## Summary
|
|
465
|
+
|
|
466
|
+
- **Kamal** = Zero-downtime Docker deployments
|
|
467
|
+
- **Default in Rails 8**
|
|
468
|
+
- **Zero-downtime** via Traefik proxy
|
|
469
|
+
- **Accessories** = No zero-downtime (plan maintenance)
|
|
470
|
+
- **Destinations** = Staging/production separation
|
|
471
|
+
- **Secrets** = `.kamal/secrets` (never commit!)
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## References
|
|
476
|
+
|
|
477
|
+
- [Kamal Official Documentation](https://kamal-deploy.org/)
|
|
478
|
+
- [Kamal GitHub](https://github.com/basecamp/kamal)
|
|
479
|
+
- [Configuration](https://kamal-deploy.org/docs/configuration/overview/)
|
|
480
|
+
- [Accessories](https://kamal-deploy.org/docs/configuration/accessories/)
|
|
481
|
+
- [Commands](https://kamal-deploy.org/docs/commands/deploy/)
|
|
482
|
+
|
|
483
|
+
Last updated: December 2025
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rails-lib
|
|
3
|
+
description: "Custom libraries, Rails extensions, and lib/ directory organization"
|
|
4
|
+
group: rails
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Lib Guide
|
|
8
|
+
|
|
9
|
+
Guide for custom libraries and Rails extensions.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## File Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
lib/
|
|
17
|
+
├── my_app.rb # Main library
|
|
18
|
+
├── rails_ext/ # Rails extensions
|
|
19
|
+
│ ├── string.rb
|
|
20
|
+
│ ├── prepend_order.rb
|
|
21
|
+
│ └── active_record_date_arithmetic.rb
|
|
22
|
+
├── services/ # Custom services (if used)
|
|
23
|
+
│ └── payment_processor.rb
|
|
24
|
+
└── tasks/ # Rake tasks
|
|
25
|
+
└── maintenance.rake
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Rails Extensions
|
|
31
|
+
|
|
32
|
+
### Extend ActiveRecord
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# lib/rails_ext/prepend_order.rb
|
|
36
|
+
module ActiveRecordRelationPrependOrder
|
|
37
|
+
extend ActiveSupport::Concern
|
|
38
|
+
|
|
39
|
+
included do
|
|
40
|
+
def prepend_order(*args)
|
|
41
|
+
new_orders = args.flatten.map { |arg| arg.is_a?(String) ? arg : arg.to_sql }
|
|
42
|
+
|
|
43
|
+
spawn.tap do |relation|
|
|
44
|
+
relation.order_values = new_orders + order_values
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
ActiveRecord::Relation.include(ActiveRecordRelationPrependOrder)
|
|
51
|
+
ActiveRecord::AssociationRelation.include(ActiveRecordRelationPrependOrder)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Load Extensions
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
# config/initializers/extensions.rb
|
|
58
|
+
Dir["#{Rails.root}/lib/rails_ext/*"].each { |path|
|
|
59
|
+
require "rails_ext/#{File.basename(path)}"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Custom Libraries
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
# lib/my_app.rb
|
|
69
|
+
module MyApp
|
|
70
|
+
class << self
|
|
71
|
+
def version
|
|
72
|
+
@version ||= File.read(Rails.root.join("VERSION")).strip
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def config
|
|
76
|
+
@config ||= Config.new
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class Config
|
|
81
|
+
attr_accessor :feature_flag
|
|
82
|
+
|
|
83
|
+
def initialize
|
|
84
|
+
@feature_flag = false
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Usage
|
|
90
|
+
MyApp.version
|
|
91
|
+
MyApp.config.feature_flag = true
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Summary
|
|
97
|
+
|
|
98
|
+
- **Rails Extensions**: Extend framework carefully
|
|
99
|
+
- **Custom Libraries**: Reusable code outside app/
|
|
100
|
+
- **Autoload**: Configure in config/application.rb
|
|
101
|
+
- **Load**: Use initializers to require lib files
|