claudient 0.1.0

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.
Files changed (283) hide show
  1. package/.claude-plugin/plugin.json +42 -0
  2. package/CONTEXT.md +58 -0
  3. package/README.md +165 -0
  4. package/agents/build-resolvers/de/python-resolver.md +64 -0
  5. package/agents/build-resolvers/de/typescript-resolver.md +65 -0
  6. package/agents/build-resolvers/es/python-resolver.md +64 -0
  7. package/agents/build-resolvers/es/typescript-resolver.md +65 -0
  8. package/agents/build-resolvers/fr/python-resolver.md +64 -0
  9. package/agents/build-resolvers/fr/typescript-resolver.md +65 -0
  10. package/agents/build-resolvers/nl/python-resolver.md +64 -0
  11. package/agents/build-resolvers/nl/typescript-resolver.md +65 -0
  12. package/agents/build-resolvers/python-resolver.md +62 -0
  13. package/agents/build-resolvers/typescript-resolver.md +63 -0
  14. package/agents/core/architect.md +64 -0
  15. package/agents/core/code-reviewer.md +78 -0
  16. package/agents/core/de/architect.md +66 -0
  17. package/agents/core/de/code-reviewer.md +80 -0
  18. package/agents/core/de/planner.md +63 -0
  19. package/agents/core/de/security-reviewer.md +93 -0
  20. package/agents/core/es/architect.md +66 -0
  21. package/agents/core/es/code-reviewer.md +80 -0
  22. package/agents/core/es/planner.md +63 -0
  23. package/agents/core/es/security-reviewer.md +93 -0
  24. package/agents/core/fr/architect.md +66 -0
  25. package/agents/core/fr/code-reviewer.md +80 -0
  26. package/agents/core/fr/planner.md +63 -0
  27. package/agents/core/fr/security-reviewer.md +93 -0
  28. package/agents/core/nl/architect.md +66 -0
  29. package/agents/core/nl/code-reviewer.md +80 -0
  30. package/agents/core/nl/planner.md +63 -0
  31. package/agents/core/nl/security-reviewer.md +93 -0
  32. package/agents/core/planner.md +61 -0
  33. package/agents/core/security-reviewer.md +91 -0
  34. package/guides/agent-orchestration.md +231 -0
  35. package/guides/de/agent-orchestration.md +174 -0
  36. package/guides/de/getting-started.md +164 -0
  37. package/guides/de/hooks-cookbook.md +160 -0
  38. package/guides/de/memory-management.md +153 -0
  39. package/guides/de/security.md +180 -0
  40. package/guides/de/skill-authoring.md +214 -0
  41. package/guides/de/token-optimization.md +156 -0
  42. package/guides/es/agent-orchestration.md +174 -0
  43. package/guides/es/getting-started.md +164 -0
  44. package/guides/es/hooks-cookbook.md +160 -0
  45. package/guides/es/memory-management.md +153 -0
  46. package/guides/es/security.md +180 -0
  47. package/guides/es/skill-authoring.md +214 -0
  48. package/guides/es/token-optimization.md +156 -0
  49. package/guides/fr/agent-orchestration.md +174 -0
  50. package/guides/fr/getting-started.md +164 -0
  51. package/guides/fr/hooks-cookbook.md +227 -0
  52. package/guides/fr/memory-management.md +169 -0
  53. package/guides/fr/security.md +180 -0
  54. package/guides/fr/skill-authoring.md +214 -0
  55. package/guides/fr/token-optimization.md +158 -0
  56. package/guides/getting-started.md +164 -0
  57. package/guides/hooks-cookbook.md +423 -0
  58. package/guides/memory-management.md +192 -0
  59. package/guides/nl/agent-orchestration.md +174 -0
  60. package/guides/nl/getting-started.md +164 -0
  61. package/guides/nl/hooks-cookbook.md +160 -0
  62. package/guides/nl/memory-management.md +153 -0
  63. package/guides/nl/security.md +180 -0
  64. package/guides/nl/skill-authoring.md +214 -0
  65. package/guides/nl/token-optimization.md +156 -0
  66. package/guides/security.md +229 -0
  67. package/guides/skill-authoring.md +226 -0
  68. package/guides/token-optimization.md +169 -0
  69. package/hooks/lifecycle/cost-tracker.md +49 -0
  70. package/hooks/lifecycle/cost-tracker.sh +59 -0
  71. package/hooks/lifecycle/pre-compact-save.md +56 -0
  72. package/hooks/lifecycle/pre-compact-save.sh +37 -0
  73. package/hooks/lifecycle/session-start.md +50 -0
  74. package/hooks/lifecycle/session-start.sh +47 -0
  75. package/hooks/post-tool-use/audit-log.md +53 -0
  76. package/hooks/post-tool-use/audit-log.sh +53 -0
  77. package/hooks/post-tool-use/prettier.md +53 -0
  78. package/hooks/post-tool-use/prettier.sh +49 -0
  79. package/hooks/pre-tool-use/block-dangerous.md +48 -0
  80. package/hooks/pre-tool-use/block-dangerous.sh +76 -0
  81. package/hooks/pre-tool-use/git-push-confirm.md +46 -0
  82. package/hooks/pre-tool-use/git-push-confirm.sh +36 -0
  83. package/mcp/configs/github.json +11 -0
  84. package/mcp/configs/postgres.json +11 -0
  85. package/mcp/de/recommended-servers.md +170 -0
  86. package/mcp/es/recommended-servers.md +170 -0
  87. package/mcp/fr/recommended-servers.md +170 -0
  88. package/mcp/nl/recommended-servers.md +170 -0
  89. package/mcp/recommended-servers.md +168 -0
  90. package/package.json +45 -0
  91. package/prompts/project-starters/de/fastapi-project.md +62 -0
  92. package/prompts/project-starters/de/nextjs-project.md +82 -0
  93. package/prompts/project-starters/es/fastapi-project.md +62 -0
  94. package/prompts/project-starters/es/nextjs-project.md +82 -0
  95. package/prompts/project-starters/fastapi-project.md +60 -0
  96. package/prompts/project-starters/fr/fastapi-project.md +62 -0
  97. package/prompts/project-starters/fr/nextjs-project.md +82 -0
  98. package/prompts/project-starters/nextjs-project.md +80 -0
  99. package/prompts/project-starters/nl/fastapi-project.md +62 -0
  100. package/prompts/project-starters/nl/nextjs-project.md +82 -0
  101. package/prompts/system-prompts/ai-product.md +80 -0
  102. package/prompts/system-prompts/data-pipeline.md +76 -0
  103. package/prompts/system-prompts/de/ai-product.md +82 -0
  104. package/prompts/system-prompts/de/data-pipeline.md +78 -0
  105. package/prompts/system-prompts/de/saas-backend.md +71 -0
  106. package/prompts/system-prompts/es/ai-product.md +82 -0
  107. package/prompts/system-prompts/es/data-pipeline.md +78 -0
  108. package/prompts/system-prompts/es/saas-backend.md +71 -0
  109. package/prompts/system-prompts/fr/ai-product.md +82 -0
  110. package/prompts/system-prompts/fr/data-pipeline.md +78 -0
  111. package/prompts/system-prompts/fr/saas-backend.md +71 -0
  112. package/prompts/system-prompts/nl/ai-product.md +82 -0
  113. package/prompts/system-prompts/nl/data-pipeline.md +78 -0
  114. package/prompts/system-prompts/nl/saas-backend.md +71 -0
  115. package/prompts/system-prompts/saas-backend.md +69 -0
  116. package/prompts/task-specific/changelog.md +81 -0
  117. package/prompts/task-specific/de/changelog.md +83 -0
  118. package/prompts/task-specific/de/debugging.md +78 -0
  119. package/prompts/task-specific/de/pr-description.md +69 -0
  120. package/prompts/task-specific/debugging.md +76 -0
  121. package/prompts/task-specific/es/changelog.md +83 -0
  122. package/prompts/task-specific/es/debugging.md +78 -0
  123. package/prompts/task-specific/es/pr-description.md +69 -0
  124. package/prompts/task-specific/fr/changelog.md +83 -0
  125. package/prompts/task-specific/fr/debugging.md +78 -0
  126. package/prompts/task-specific/fr/pr-description.md +69 -0
  127. package/prompts/task-specific/nl/changelog.md +83 -0
  128. package/prompts/task-specific/nl/debugging.md +78 -0
  129. package/prompts/task-specific/nl/pr-description.md +69 -0
  130. package/prompts/task-specific/pr-description.md +67 -0
  131. package/rules/common/coding-style.md +45 -0
  132. package/rules/common/de/coding-style.md +47 -0
  133. package/rules/common/de/git.md +48 -0
  134. package/rules/common/de/performance.md +40 -0
  135. package/rules/common/de/security.md +45 -0
  136. package/rules/common/de/testing.md +45 -0
  137. package/rules/common/es/coding-style.md +47 -0
  138. package/rules/common/es/git.md +48 -0
  139. package/rules/common/es/performance.md +40 -0
  140. package/rules/common/es/security.md +45 -0
  141. package/rules/common/es/testing.md +45 -0
  142. package/rules/common/fr/coding-style.md +47 -0
  143. package/rules/common/fr/git.md +48 -0
  144. package/rules/common/fr/performance.md +40 -0
  145. package/rules/common/fr/security.md +45 -0
  146. package/rules/common/fr/testing.md +45 -0
  147. package/rules/common/git.md +46 -0
  148. package/rules/common/nl/coding-style.md +47 -0
  149. package/rules/common/nl/git.md +48 -0
  150. package/rules/common/nl/performance.md +40 -0
  151. package/rules/common/nl/security.md +45 -0
  152. package/rules/common/nl/testing.md +45 -0
  153. package/rules/common/performance.md +38 -0
  154. package/rules/common/security.md +43 -0
  155. package/rules/common/testing.md +43 -0
  156. package/rules/language-specific/de/go.md +48 -0
  157. package/rules/language-specific/de/python.md +38 -0
  158. package/rules/language-specific/de/typescript.md +51 -0
  159. package/rules/language-specific/es/go.md +48 -0
  160. package/rules/language-specific/es/python.md +38 -0
  161. package/rules/language-specific/es/typescript.md +51 -0
  162. package/rules/language-specific/fr/go.md +48 -0
  163. package/rules/language-specific/fr/python.md +38 -0
  164. package/rules/language-specific/fr/typescript.md +51 -0
  165. package/rules/language-specific/go.md +46 -0
  166. package/rules/language-specific/nl/go.md +48 -0
  167. package/rules/language-specific/nl/python.md +38 -0
  168. package/rules/language-specific/nl/typescript.md +51 -0
  169. package/rules/language-specific/python.md +36 -0
  170. package/rules/language-specific/typescript.md +49 -0
  171. package/scripts/cli.js +161 -0
  172. package/scripts/link-skills.sh +35 -0
  173. package/scripts/list-skills.sh +34 -0
  174. package/skills/ai-engineering/agent-construction.md +285 -0
  175. package/skills/ai-engineering/claude-api.md +248 -0
  176. package/skills/ai-engineering/de/agent-construction.md +287 -0
  177. package/skills/ai-engineering/de/claude-api.md +250 -0
  178. package/skills/ai-engineering/es/agent-construction.md +287 -0
  179. package/skills/ai-engineering/es/claude-api.md +250 -0
  180. package/skills/ai-engineering/fr/agent-construction.md +287 -0
  181. package/skills/ai-engineering/fr/claude-api.md +250 -0
  182. package/skills/ai-engineering/nl/agent-construction.md +287 -0
  183. package/skills/ai-engineering/nl/claude-api.md +250 -0
  184. package/skills/backend/dotnet/csharp.md +304 -0
  185. package/skills/backend/dotnet/de/csharp.md +306 -0
  186. package/skills/backend/dotnet/es/csharp.md +306 -0
  187. package/skills/backend/dotnet/fr/csharp.md +306 -0
  188. package/skills/backend/dotnet/nl/csharp.md +306 -0
  189. package/skills/backend/go/de/go.md +307 -0
  190. package/skills/backend/go/es/go.md +307 -0
  191. package/skills/backend/go/fr/go.md +307 -0
  192. package/skills/backend/go/go.md +305 -0
  193. package/skills/backend/go/nl/go.md +307 -0
  194. package/skills/backend/nodejs/de/nestjs.md +274 -0
  195. package/skills/backend/nodejs/de/nextjs.md +222 -0
  196. package/skills/backend/nodejs/es/nestjs.md +274 -0
  197. package/skills/backend/nodejs/es/nextjs.md +222 -0
  198. package/skills/backend/nodejs/fr/nestjs.md +274 -0
  199. package/skills/backend/nodejs/fr/nextjs.md +222 -0
  200. package/skills/backend/nodejs/nestjs.md +272 -0
  201. package/skills/backend/nodejs/nextjs.md +220 -0
  202. package/skills/backend/nodejs/nl/nestjs.md +274 -0
  203. package/skills/backend/nodejs/nl/nextjs.md +222 -0
  204. package/skills/backend/python/de/django.md +285 -0
  205. package/skills/backend/python/de/fastapi.md +244 -0
  206. package/skills/backend/python/django.md +283 -0
  207. package/skills/backend/python/es/django.md +285 -0
  208. package/skills/backend/python/es/fastapi.md +244 -0
  209. package/skills/backend/python/fastapi.md +242 -0
  210. package/skills/backend/python/fr/django.md +285 -0
  211. package/skills/backend/python/fr/fastapi.md +244 -0
  212. package/skills/backend/python/nl/django.md +285 -0
  213. package/skills/backend/python/nl/fastapi.md +244 -0
  214. package/skills/data-ml/dbt-data-pipelines.md +155 -0
  215. package/skills/data-ml/de/dbt-data-pipelines.md +157 -0
  216. package/skills/data-ml/de/pandas-polars.md +147 -0
  217. package/skills/data-ml/de/pytorch-tensorflow.md +171 -0
  218. package/skills/data-ml/es/dbt-data-pipelines.md +157 -0
  219. package/skills/data-ml/es/pandas-polars.md +147 -0
  220. package/skills/data-ml/es/pytorch-tensorflow.md +171 -0
  221. package/skills/data-ml/fr/dbt-data-pipelines.md +157 -0
  222. package/skills/data-ml/fr/pandas-polars.md +147 -0
  223. package/skills/data-ml/fr/pytorch-tensorflow.md +171 -0
  224. package/skills/data-ml/nl/dbt-data-pipelines.md +157 -0
  225. package/skills/data-ml/nl/pandas-polars.md +147 -0
  226. package/skills/data-ml/nl/pytorch-tensorflow.md +171 -0
  227. package/skills/data-ml/pandas-polars.md +145 -0
  228. package/skills/data-ml/pytorch-tensorflow.md +169 -0
  229. package/skills/database/de/graphql.md +181 -0
  230. package/skills/database/es/graphql.md +181 -0
  231. package/skills/database/fr/graphql.md +181 -0
  232. package/skills/database/graphql.md +179 -0
  233. package/skills/database/nl/graphql.md +181 -0
  234. package/skills/devops-infra/de/docker.md +133 -0
  235. package/skills/devops-infra/de/github-actions.md +179 -0
  236. package/skills/devops-infra/de/kubernetes.md +129 -0
  237. package/skills/devops-infra/de/terraform.md +130 -0
  238. package/skills/devops-infra/docker.md +131 -0
  239. package/skills/devops-infra/es/docker.md +133 -0
  240. package/skills/devops-infra/es/github-actions.md +179 -0
  241. package/skills/devops-infra/es/kubernetes.md +129 -0
  242. package/skills/devops-infra/es/terraform.md +130 -0
  243. package/skills/devops-infra/fr/docker.md +133 -0
  244. package/skills/devops-infra/fr/github-actions.md +179 -0
  245. package/skills/devops-infra/fr/kubernetes.md +129 -0
  246. package/skills/devops-infra/fr/terraform.md +130 -0
  247. package/skills/devops-infra/github-actions.md +177 -0
  248. package/skills/devops-infra/kubernetes.md +127 -0
  249. package/skills/devops-infra/nl/docker.md +133 -0
  250. package/skills/devops-infra/nl/github-actions.md +179 -0
  251. package/skills/devops-infra/nl/kubernetes.md +129 -0
  252. package/skills/devops-infra/nl/terraform.md +130 -0
  253. package/skills/devops-infra/terraform.md +128 -0
  254. package/skills/finance-payments/de/stripe.md +187 -0
  255. package/skills/finance-payments/es/stripe.md +187 -0
  256. package/skills/finance-payments/fr/stripe.md +187 -0
  257. package/skills/finance-payments/nl/stripe.md +187 -0
  258. package/skills/finance-payments/stripe.md +185 -0
  259. package/workflows/code-review.md +151 -0
  260. package/workflows/de/code-review.md +153 -0
  261. package/workflows/de/debugging-session.md +146 -0
  262. package/workflows/de/feature-development.md +155 -0
  263. package/workflows/de/new-project-bootstrap.md +175 -0
  264. package/workflows/de/refactor-safely.md +150 -0
  265. package/workflows/debugging-session.md +144 -0
  266. package/workflows/es/code-review.md +153 -0
  267. package/workflows/es/debugging-session.md +146 -0
  268. package/workflows/es/feature-development.md +155 -0
  269. package/workflows/es/new-project-bootstrap.md +175 -0
  270. package/workflows/es/refactor-safely.md +150 -0
  271. package/workflows/feature-development.md +153 -0
  272. package/workflows/fr/code-review.md +153 -0
  273. package/workflows/fr/debugging-session.md +146 -0
  274. package/workflows/fr/feature-development.md +155 -0
  275. package/workflows/fr/new-project-bootstrap.md +175 -0
  276. package/workflows/fr/refactor-safely.md +150 -0
  277. package/workflows/new-project-bootstrap.md +173 -0
  278. package/workflows/nl/code-review.md +153 -0
  279. package/workflows/nl/debugging-session.md +146 -0
  280. package/workflows/nl/feature-development.md +155 -0
  281. package/workflows/nl/new-project-bootstrap.md +175 -0
  282. package/workflows/nl/refactor-safely.md +150 -0
  283. package/workflows/refactor-safely.md +148 -0
@@ -0,0 +1,307 @@
1
+ > 🇫🇷 This is the French translation. [English version](../go.md).
2
+
3
+ # Compétence Go
4
+
5
+ ## Quand activer
6
+ - Construire un service HTTP Go ou un outil CLI
7
+ - Structurer un projet Go avec `cmd/`, `internal/`, `pkg/`
8
+ - Rédiger des handlers HTTP avec `net/http`, chi, ou gin
9
+ - Implémenter des interfaces, de l'embedding et des patterns de composition
10
+ - Rédiger du code concurrent avec des goroutines, des channels et des primitives `sync`
11
+ - Gestion des erreurs, wrapping et erreurs sentinelles
12
+ - Rédiger des tests table-driven
13
+
14
+ ## Quand NE PAS utiliser
15
+ - Services Node.js, Python ou autres langages — écosystèmes différents
16
+ - Services Protobuf/gRPC sans contexte de configuration gRPC préalable
17
+ - Tâches de scripting pur — shell ou Python sont de meilleurs choix
18
+
19
+ ## Instructions
20
+
21
+ ### Structure du projet
22
+ ```
23
+ myapp/
24
+ ├── cmd/
25
+ │ └── server/
26
+ │ └── main.go # Point d'entrée — minimal, câble et démarre seulement
27
+ ├── internal/ # Packages privés — non importables de l'extérieur
28
+ │ ├── config/
29
+ │ ├── handler/
30
+ │ ├── service/
31
+ │ └── store/
32
+ ├── pkg/ # Packages publics — importables par d'autres modules
33
+ │ └── apierr/
34
+ ├── go.mod
35
+ └── go.sum
36
+ ```
37
+
38
+ ### main.go — câblage uniquement
39
+ ```go
40
+ // cmd/server/main.go
41
+ package main
42
+
43
+ import (
44
+ "context"
45
+ "log/slog"
46
+ "net/http"
47
+ "os"
48
+ "os/signal"
49
+ "syscall"
50
+ "time"
51
+
52
+ "myapp/internal/config"
53
+ "myapp/internal/handler"
54
+ "myapp/internal/store"
55
+ )
56
+
57
+ func main() {
58
+ cfg := config.MustLoad()
59
+ db := store.MustConnect(cfg.DatabaseURL)
60
+ defer db.Close()
61
+
62
+ mux := handler.NewMux(db, cfg)
63
+
64
+ srv := &http.Server{
65
+ Addr: ":" + cfg.Port,
66
+ Handler: mux,
67
+ ReadTimeout: 10 * time.Second,
68
+ WriteTimeout: 30 * time.Second,
69
+ IdleTimeout: 60 * time.Second,
70
+ }
71
+
72
+ go func() {
73
+ slog.Info("server starting", "addr", srv.Addr)
74
+ if err := srv.ListenAndServe(); err != http.ErrServerClosed {
75
+ slog.Error("server error", "err", err)
76
+ os.Exit(1)
77
+ }
78
+ }()
79
+
80
+ quit := make(chan os.Signal, 1)
81
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
82
+ <-quit
83
+
84
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
85
+ defer cancel()
86
+ srv.Shutdown(ctx)
87
+ }
88
+ ```
89
+
90
+ ### Gestion des erreurs
91
+ ```go
92
+ // Définir des erreurs sentinelles pour les conditions attendues
93
+ var (
94
+ ErrNotFound = errors.New("not found")
95
+ ErrDuplicate = errors.New("duplicate entry")
96
+ ErrForbidden = errors.New("forbidden")
97
+ )
98
+
99
+ // Envelopper les erreurs avec du contexte — utiliser %w pour préserver le désenveloppement
100
+ func (s *UserStore) GetByID(ctx context.Context, id string) (*User, error) {
101
+ var u User
102
+ err := s.db.QueryRowContext(ctx, `SELECT id, email FROM users WHERE id = $1`, id).
103
+ Scan(&u.ID, &u.Email)
104
+ if errors.Is(err, sql.ErrNoRows) {
105
+ return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
106
+ }
107
+ if err != nil {
108
+ return nil, fmt.Errorf("user store get: %w", err)
109
+ }
110
+ return &u, nil
111
+ }
112
+
113
+ // L'appelant vérifie le comportement, pas les chaînes de message
114
+ user, err := store.GetByID(ctx, id)
115
+ if errors.Is(err, ErrNotFound) {
116
+ http.Error(w, "not found", http.StatusNotFound)
117
+ return
118
+ }
119
+ ```
120
+
121
+ ### Handlers HTTP avec chi
122
+ ```go
123
+ // internal/handler/users.go
124
+ type UserHandler struct {
125
+ svc UserService
126
+ }
127
+
128
+ func (h *UserHandler) Register(r chi.Router) {
129
+ r.Get("/users/{id}", h.GetUser)
130
+ r.Post("/users", h.CreateUser)
131
+ }
132
+
133
+ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
134
+ id := chi.URLParam(r, "id")
135
+ user, err := h.svc.GetUser(r.Context(), id)
136
+ if err != nil {
137
+ renderError(w, err)
138
+ return
139
+ }
140
+ renderJSON(w, http.StatusOK, user)
141
+ }
142
+
143
+ func renderJSON(w http.ResponseWriter, code int, v any) {
144
+ w.Header().Set("Content-Type", "application/json")
145
+ w.WriteHeader(code)
146
+ json.NewEncoder(w).Encode(v)
147
+ }
148
+
149
+ func renderError(w http.ResponseWriter, err error) {
150
+ switch {
151
+ case errors.Is(err, ErrNotFound):
152
+ http.Error(w, "not found", http.StatusNotFound)
153
+ case errors.Is(err, ErrForbidden):
154
+ http.Error(w, "forbidden", http.StatusForbidden)
155
+ default:
156
+ slog.Error("internal error", "err", err)
157
+ http.Error(w, "internal server error", http.StatusInternalServerError)
158
+ }
159
+ }
160
+ ```
161
+
162
+ ### Interfaces
163
+ ```go
164
+ // Définir les interfaces là où elles sont utilisées (côté consommateur), pas là où elles sont implémentées
165
+ // internal/handler/users.go
166
+ type UserService interface {
167
+ GetUser(ctx context.Context, id string) (*User, error)
168
+ CreateUser(ctx context.Context, req CreateUserRequest) (*User, error)
169
+ }
170
+
171
+ // Garder les interfaces petites — 1-3 méthodes préférées
172
+ // io.Reader, io.Writer sont les exemples canoniques
173
+
174
+ // Embedding pour la composition
175
+ type ReadWriter interface {
176
+ io.Reader
177
+ io.Writer
178
+ }
179
+ ```
180
+
181
+ ### Patterns de concurrence
182
+ ```go
183
+ // Fan-out avec errgroup
184
+ import "golang.org/x/sync/errgroup"
185
+
186
+ func fetchAll(ctx context.Context, ids []string) ([]*User, error) {
187
+ g, ctx := errgroup.WithContext(ctx)
188
+ results := make([]*User, len(ids))
189
+
190
+ for i, id := range ids {
191
+ i, id := i, id // capturer les variables de boucle
192
+ g.Go(func() error {
193
+ u, err := store.GetByID(ctx, id)
194
+ if err != nil {
195
+ return err
196
+ }
197
+ results[i] = u
198
+ return nil
199
+ })
200
+ }
201
+
202
+ if err := g.Wait(); err != nil {
203
+ return nil, err
204
+ }
205
+ return results, nil
206
+ }
207
+
208
+ // Pool de workers
209
+ func processJobs(ctx context.Context, jobs <-chan Job) {
210
+ const workers = 10
211
+ var wg sync.WaitGroup
212
+ for range workers {
213
+ wg.Add(1)
214
+ go func() {
215
+ defer wg.Done()
216
+ for job := range jobs {
217
+ if err := process(ctx, job); err != nil {
218
+ slog.Error("job failed", "id", job.ID, "err", err)
219
+ }
220
+ }
221
+ }()
222
+ }
223
+ wg.Wait()
224
+ }
225
+ ```
226
+
227
+ ### Propagation du contexte
228
+ ```go
229
+ // Toujours propaguer le contexte comme premier argument
230
+ func (s *Service) DoWork(ctx context.Context, id string) error {
231
+ // Passer ctx à tous les appels en aval
232
+ user, err := s.store.GetByID(ctx, id)
233
+ if err != nil {
234
+ return err
235
+ }
236
+ return s.notifier.Send(ctx, user.Email)
237
+ }
238
+
239
+ // Stocker les valeurs de portée de requête dans le contexte uniquement pour les préoccupations transversales
240
+ // (IDs de traçage, informations d'auth) — jamais pour des paramètres de fonction optionnels
241
+ type contextKey string
242
+ const requestIDKey contextKey = "request_id"
243
+
244
+ func WithRequestID(ctx context.Context, id string) context.Context {
245
+ return context.WithValue(ctx, requestIDKey, id)
246
+ }
247
+ func GetRequestID(ctx context.Context) string {
248
+ id, _ := ctx.Value(requestIDKey).(string)
249
+ return id
250
+ }
251
+ ```
252
+
253
+ ### Tests table-driven
254
+ ```go
255
+ func TestGetUser(t *testing.T) {
256
+ tests := []struct {
257
+ name string
258
+ id string
259
+ want *User
260
+ wantErr error
261
+ }{
262
+ {"found", "123", &User{ID: "123", Email: "a@b.com"}, nil},
263
+ {"not found", "999", nil, ErrNotFound},
264
+ {"empty id", "", nil, ErrNotFound},
265
+ }
266
+
267
+ for _, tt := range tests {
268
+ t.Run(tt.name, func(t *testing.T) {
269
+ svc := newTestService(t)
270
+ got, err := svc.GetUser(context.Background(), tt.id)
271
+ if !errors.Is(err, tt.wantErr) {
272
+ t.Fatalf("err = %v, want %v", err, tt.wantErr)
273
+ }
274
+ if diff := cmp.Diff(tt.want, got); diff != "" {
275
+ t.Errorf("mismatch (-want +got):\n%s", diff)
276
+ }
277
+ })
278
+ }
279
+ }
280
+ ```
281
+
282
+ ### Logging avec slog
283
+ ```go
284
+ // Logging structuré — jamais fmt.Println dans le code de production
285
+ slog.Info("request completed", "method", r.Method, "path", r.URL.Path, "status", 200, "duration_ms", elapsed.Milliseconds())
286
+ slog.Error("db query failed", "query", "getUserByID", "err", err)
287
+
288
+ // Configurer le logger JSON dans main
289
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
290
+ Level: slog.LevelInfo,
291
+ }))
292
+ slog.SetDefault(logger)
293
+ ```
294
+
295
+ ## Exemple
296
+
297
+ **Utilisateur :** Construire une API HTTP Go pour une liste de tâches : créer, lister et compléter des tâches. Backend PostgreSQL, router chi, logging structuré, arrêt gracieux.
298
+
299
+ **Sortie attendue :**
300
+ - `cmd/server/main.go` — câble le store, le handler, démarre le serveur avec arrêt gracieux
301
+ - `internal/store/task.go` — `TaskStore` avec méthodes `Create`, `List`, `Complete` utilisant `database/sql`
302
+ - `internal/handler/tasks.go` — `TaskHandler` avec `Register(r chi.Router)`, réponses JSON
303
+ - `internal/handler/tasks_test.go` — tests table-driven avec un mock store
304
+
305
+ ---
306
+
307
+ > **Travaillez avec nous :** Claudient est soutenu par [Uitbreiden](https://uitbreiden.com/) — nous construisons des produits IA et des solutions B2B avec des communautés de développeurs. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,305 @@
1
+ # Go Skill
2
+
3
+ ## When to activate
4
+ - Building a Go HTTP service or CLI tool
5
+ - Structuring a Go project with `cmd/`, `internal/`, `pkg/`
6
+ - Writing HTTP handlers with `net/http`, chi, or gin
7
+ - Implementing interfaces, embedding, and composition patterns
8
+ - Writing concurrent code with goroutines, channels, and `sync` primitives
9
+ - Error handling, wrapping, and sentinel errors
10
+ - Writing table-driven tests
11
+
12
+ ## When NOT to use
13
+ - Node.js, Python, or other language services — different ecosystems
14
+ - Protobuf/gRPC services without prior gRPC setup context
15
+ - Pure scripting tasks — shell or Python are better fits
16
+
17
+ ## Instructions
18
+
19
+ ### Project layout
20
+ ```
21
+ myapp/
22
+ ├── cmd/
23
+ │ └── server/
24
+ │ └── main.go # Entry point — thin, just wires and starts
25
+ ├── internal/ # Private packages — not importable externally
26
+ │ ├── config/
27
+ │ ├── handler/
28
+ │ ├── service/
29
+ │ └── store/
30
+ ├── pkg/ # Public packages — importable by other modules
31
+ │ └── apierr/
32
+ ├── go.mod
33
+ └── go.sum
34
+ ```
35
+
36
+ ### main.go — wiring only
37
+ ```go
38
+ // cmd/server/main.go
39
+ package main
40
+
41
+ import (
42
+ "context"
43
+ "log/slog"
44
+ "net/http"
45
+ "os"
46
+ "os/signal"
47
+ "syscall"
48
+ "time"
49
+
50
+ "myapp/internal/config"
51
+ "myapp/internal/handler"
52
+ "myapp/internal/store"
53
+ )
54
+
55
+ func main() {
56
+ cfg := config.MustLoad()
57
+ db := store.MustConnect(cfg.DatabaseURL)
58
+ defer db.Close()
59
+
60
+ mux := handler.NewMux(db, cfg)
61
+
62
+ srv := &http.Server{
63
+ Addr: ":" + cfg.Port,
64
+ Handler: mux,
65
+ ReadTimeout: 10 * time.Second,
66
+ WriteTimeout: 30 * time.Second,
67
+ IdleTimeout: 60 * time.Second,
68
+ }
69
+
70
+ go func() {
71
+ slog.Info("server starting", "addr", srv.Addr)
72
+ if err := srv.ListenAndServe(); err != http.ErrServerClosed {
73
+ slog.Error("server error", "err", err)
74
+ os.Exit(1)
75
+ }
76
+ }()
77
+
78
+ quit := make(chan os.Signal, 1)
79
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
80
+ <-quit
81
+
82
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
83
+ defer cancel()
84
+ srv.Shutdown(ctx)
85
+ }
86
+ ```
87
+
88
+ ### Error handling
89
+ ```go
90
+ // Define sentinel errors for expected conditions
91
+ var (
92
+ ErrNotFound = errors.New("not found")
93
+ ErrDuplicate = errors.New("duplicate entry")
94
+ ErrForbidden = errors.New("forbidden")
95
+ )
96
+
97
+ // Wrap errors with context — use %w to preserve unwrapping
98
+ func (s *UserStore) GetByID(ctx context.Context, id string) (*User, error) {
99
+ var u User
100
+ err := s.db.QueryRowContext(ctx, `SELECT id, email FROM users WHERE id = $1`, id).
101
+ Scan(&u.ID, &u.Email)
102
+ if errors.Is(err, sql.ErrNoRows) {
103
+ return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
104
+ }
105
+ if err != nil {
106
+ return nil, fmt.Errorf("user store get: %w", err)
107
+ }
108
+ return &u, nil
109
+ }
110
+
111
+ // Caller checks behavior, not message strings
112
+ user, err := store.GetByID(ctx, id)
113
+ if errors.Is(err, ErrNotFound) {
114
+ http.Error(w, "not found", http.StatusNotFound)
115
+ return
116
+ }
117
+ ```
118
+
119
+ ### HTTP handlers with chi
120
+ ```go
121
+ // internal/handler/users.go
122
+ type UserHandler struct {
123
+ svc UserService
124
+ }
125
+
126
+ func (h *UserHandler) Register(r chi.Router) {
127
+ r.Get("/users/{id}", h.GetUser)
128
+ r.Post("/users", h.CreateUser)
129
+ }
130
+
131
+ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
132
+ id := chi.URLParam(r, "id")
133
+ user, err := h.svc.GetUser(r.Context(), id)
134
+ if err != nil {
135
+ renderError(w, err)
136
+ return
137
+ }
138
+ renderJSON(w, http.StatusOK, user)
139
+ }
140
+
141
+ func renderJSON(w http.ResponseWriter, code int, v any) {
142
+ w.Header().Set("Content-Type", "application/json")
143
+ w.WriteHeader(code)
144
+ json.NewEncoder(w).Encode(v)
145
+ }
146
+
147
+ func renderError(w http.ResponseWriter, err error) {
148
+ switch {
149
+ case errors.Is(err, ErrNotFound):
150
+ http.Error(w, "not found", http.StatusNotFound)
151
+ case errors.Is(err, ErrForbidden):
152
+ http.Error(w, "forbidden", http.StatusForbidden)
153
+ default:
154
+ slog.Error("internal error", "err", err)
155
+ http.Error(w, "internal server error", http.StatusInternalServerError)
156
+ }
157
+ }
158
+ ```
159
+
160
+ ### Interfaces
161
+ ```go
162
+ // Define interfaces where they're used (consumer side), not where implemented
163
+ // internal/handler/users.go
164
+ type UserService interface {
165
+ GetUser(ctx context.Context, id string) (*User, error)
166
+ CreateUser(ctx context.Context, req CreateUserRequest) (*User, error)
167
+ }
168
+
169
+ // Keep interfaces small — 1-3 methods preferred
170
+ // io.Reader, io.Writer are the canonical examples
171
+
172
+ // Embedding for composition
173
+ type ReadWriter interface {
174
+ io.Reader
175
+ io.Writer
176
+ }
177
+ ```
178
+
179
+ ### Concurrency patterns
180
+ ```go
181
+ // Fan-out with errgroup
182
+ import "golang.org/x/sync/errgroup"
183
+
184
+ func fetchAll(ctx context.Context, ids []string) ([]*User, error) {
185
+ g, ctx := errgroup.WithContext(ctx)
186
+ results := make([]*User, len(ids))
187
+
188
+ for i, id := range ids {
189
+ i, id := i, id // capture loop vars
190
+ g.Go(func() error {
191
+ u, err := store.GetByID(ctx, id)
192
+ if err != nil {
193
+ return err
194
+ }
195
+ results[i] = u
196
+ return nil
197
+ })
198
+ }
199
+
200
+ if err := g.Wait(); err != nil {
201
+ return nil, err
202
+ }
203
+ return results, nil
204
+ }
205
+
206
+ // Worker pool
207
+ func processJobs(ctx context.Context, jobs <-chan Job) {
208
+ const workers = 10
209
+ var wg sync.WaitGroup
210
+ for range workers {
211
+ wg.Add(1)
212
+ go func() {
213
+ defer wg.Done()
214
+ for job := range jobs {
215
+ if err := process(ctx, job); err != nil {
216
+ slog.Error("job failed", "id", job.ID, "err", err)
217
+ }
218
+ }
219
+ }()
220
+ }
221
+ wg.Wait()
222
+ }
223
+ ```
224
+
225
+ ### Context propagation
226
+ ```go
227
+ // Always propagate context as first argument
228
+ func (s *Service) DoWork(ctx context.Context, id string) error {
229
+ // Pass ctx to all downstream calls
230
+ user, err := s.store.GetByID(ctx, id)
231
+ if err != nil {
232
+ return err
233
+ }
234
+ return s.notifier.Send(ctx, user.Email)
235
+ }
236
+
237
+ // Store request-scoped values in context only for cross-cutting concerns
238
+ // (tracing IDs, auth info) — never for optional function parameters
239
+ type contextKey string
240
+ const requestIDKey contextKey = "request_id"
241
+
242
+ func WithRequestID(ctx context.Context, id string) context.Context {
243
+ return context.WithValue(ctx, requestIDKey, id)
244
+ }
245
+ func GetRequestID(ctx context.Context) string {
246
+ id, _ := ctx.Value(requestIDKey).(string)
247
+ return id
248
+ }
249
+ ```
250
+
251
+ ### Table-driven tests
252
+ ```go
253
+ func TestGetUser(t *testing.T) {
254
+ tests := []struct {
255
+ name string
256
+ id string
257
+ want *User
258
+ wantErr error
259
+ }{
260
+ {"found", "123", &User{ID: "123", Email: "a@b.com"}, nil},
261
+ {"not found", "999", nil, ErrNotFound},
262
+ {"empty id", "", nil, ErrNotFound},
263
+ }
264
+
265
+ for _, tt := range tests {
266
+ t.Run(tt.name, func(t *testing.T) {
267
+ svc := newTestService(t)
268
+ got, err := svc.GetUser(context.Background(), tt.id)
269
+ if !errors.Is(err, tt.wantErr) {
270
+ t.Fatalf("err = %v, want %v", err, tt.wantErr)
271
+ }
272
+ if diff := cmp.Diff(tt.want, got); diff != "" {
273
+ t.Errorf("mismatch (-want +got):\n%s", diff)
274
+ }
275
+ })
276
+ }
277
+ }
278
+ ```
279
+
280
+ ### Logging with slog
281
+ ```go
282
+ // Structured logging — never fmt.Println in production code
283
+ slog.Info("request completed", "method", r.Method, "path", r.URL.Path, "status", 200, "duration_ms", elapsed.Milliseconds())
284
+ slog.Error("db query failed", "query", "getUserByID", "err", err)
285
+
286
+ // Set up JSON logger in main
287
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
288
+ Level: slog.LevelInfo,
289
+ }))
290
+ slog.SetDefault(logger)
291
+ ```
292
+
293
+ ## Example
294
+
295
+ **User:** Build a Go HTTP API for a to-do list: create, list, and complete tasks. PostgreSQL backend, chi router, structured logging, graceful shutdown.
296
+
297
+ **Expected output:**
298
+ - `cmd/server/main.go` — wires store, handler, starts server with graceful shutdown
299
+ - `internal/store/task.go` — `TaskStore` with `Create`, `List`, `Complete` methods using `database/sql`
300
+ - `internal/handler/tasks.go` — `TaskHandler` with `Register(r chi.Router)`, JSON responses
301
+ - `internal/handler/tasks_test.go` — table-driven tests with a mock store
302
+
303
+ ---
304
+
305
+ > **Work with us:** Claudient is backed by [Uitbreiden](https://uitbreiden.com/) — we build AI products and B2B solutions with developer communities. [uitbreiden.com](https://uitbreiden.com/)