agentic-team-templates 0.11.0 → 0.12.1

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/README.md CHANGED
@@ -147,20 +147,24 @@ npx agentic-team-templates --reset --force
147
147
 
148
148
  | Template | Description |
149
149
  |----------|-------------|
150
- | `web-frontend` | SPAs, SSR, static sites, PWAs |
151
- | `web-backend` | REST, GraphQL, microservices |
152
- | `fullstack` | Full-stack apps (Next.js, Nuxt, etc.) |
153
- | `mobile` | React Native, Flutter, native iOS/Android |
154
- | `cli-tools` | Command-line applications and developer tools |
155
- | `blockchain` | Smart contracts, DeFi, Web3 applications |
156
- | `ml-ai` | Machine learning systems, model development |
157
- | `data-engineering` | Data pipelines, ETL, warehousing |
158
- | `platform-engineering` | Infrastructure as code, Kubernetes, CI/CD |
159
- | `devops-sre` | Incident management, SLOs, observability |
160
- | `product-manager` | Product strategy, discovery, OKRs, PRDs |
161
- | `qa-engineering` | Test strategy, automation, quality gates |
162
- | `utility-agent` | AI agent utilities, context management |
163
- | `documentation` | Technical writing, API docs, ADRs |
150
+ | `blockchain` | Smart contracts, DeFi protocols, and Web3 applications (Solidity, Foundry, Viem) |
151
+ | `cli-tools` | Command-line applications and developer tools (Cobra, Commander, Click) |
152
+ | `data-engineering` | Data platforms and pipelines (ETL, data modeling, data quality) |
153
+ | `devops-sre` | DevOps and SRE practices (incident management, observability, SLOs, chaos engineering) |
154
+ | `documentation` | Technical documentation standards (READMEs, API docs, ADRs, code comments) |
155
+ | `fullstack` | Full-stack web applications (Next.js, Nuxt, SvelteKit, Remix) |
156
+ | `golang-expert` | Principal-level Go engineering (concurrency, stdlib, production patterns, testing) |
157
+ | `javascript-expert` | Principal-level JavaScript engineering across Node.js, React, vanilla JS, and testing |
158
+ | `ml-ai` | Machine learning and AI systems (model development, deployment, monitoring) |
159
+ | `mobile` | Mobile applications (React Native, Flutter, native iOS/Android) |
160
+ | `platform-engineering` | Internal developer platforms, infrastructure automation, reliability engineering |
161
+ | `product-manager` | Product management with customer-centric discovery, prioritization, and execution |
162
+ | `qa-engineering` | Quality assurance programs for confident, rapid software delivery |
163
+ | `rust-expert` | Principal-level Rust engineering (ownership, concurrency, unsafe, traits, async) |
164
+ | `testing` | Comprehensive testing practices (TDD, test design, CI/CD integration, performance testing) |
165
+ | `utility-agent` | AI agent utilities with context management and hallucination prevention |
166
+ | `web-backend` | Backend APIs and services (REST, GraphQL, microservices) |
167
+ | `web-frontend` | Frontend web applications (SPAs, SSR, static sites, PWAs) |
164
168
 
165
169
  ## What Gets Installed
166
170
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-team-templates",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "AI coding assistant templates for Cursor IDE. Pre-configured rules and guidelines that help AI assistants write better code. - use at your own risk",
5
5
  "keywords": [
6
6
  "cursor",
package/src/index.js CHANGED
@@ -44,6 +44,10 @@ const TEMPLATES = {
44
44
  description: 'Full-stack web applications (Next.js, Nuxt, SvelteKit, Remix)',
45
45
  rules: ['api-contracts.md', 'architecture.md', 'overview.md', 'shared-types.md', 'testing.md']
46
46
  },
47
+ 'golang-expert': {
48
+ description: 'Principal-level Go engineering (concurrency, stdlib, production patterns, testing)',
49
+ rules: ['concurrency.md', 'error-handling.md', 'interfaces-and-types.md', 'overview.md', 'performance.md', 'production-patterns.md', 'stdlib-and-tooling.md', 'testing.md']
50
+ },
47
51
  'javascript-expert': {
48
52
  description: 'Principal-level JavaScript engineering across Node.js, React, vanilla JS, and testing',
49
53
  rules: ['language-deep-dive.md', 'node-patterns.md', 'overview.md', 'performance.md', 'react-patterns.md', 'testing.md', 'tooling.md']
package/src/index.test.js CHANGED
@@ -79,6 +79,7 @@ describe('Constants', () => {
79
79
  'devops-sre',
80
80
  'documentation',
81
81
  'fullstack',
82
+ 'golang-expert',
82
83
  'javascript-expert',
83
84
  'ml-ai',
84
85
  'mobile',
@@ -0,0 +1,290 @@
1
+ # Go Concurrency
2
+
3
+ Concurrency is Go's defining feature. It is also the easiest way to write bugs that are impossible to reproduce. Use it deliberately, not by default.
4
+
5
+ ## Fundamental Rules
6
+
7
+ ### 1. Don't Start a Goroutine You Can't Stop
8
+
9
+ ```go
10
+ // Good: Goroutine respects context cancellation
11
+ func (w *Worker) Run(ctx context.Context) error {
12
+ for {
13
+ select {
14
+ case <-ctx.Done():
15
+ return ctx.Err()
16
+ case job := <-w.jobs:
17
+ if err := w.process(ctx, job); err != nil {
18
+ return fmt.Errorf("processing job: %w", err)
19
+ }
20
+ }
21
+ }
22
+ }
23
+
24
+ // Bad: Goroutine runs forever with no way to stop it
25
+ go func() {
26
+ for {
27
+ doWork() // No context, no signal, no way out
28
+ }
29
+ }()
30
+ ```
31
+
32
+ ### 2. The Caller Decides Concurrency
33
+
34
+ ```go
35
+ // Good: Synchronous function — caller decides whether to use goroutine
36
+ func FetchUser(ctx context.Context, id string) (*User, error) {
37
+ // ...
38
+ }
39
+
40
+ // Caller makes it concurrent when needed
41
+ go func() {
42
+ user, err := FetchUser(ctx, id)
43
+ results <- result{user, err}
44
+ }()
45
+
46
+ // Bad: Function that forces concurrency on the caller
47
+ func FetchUserAsync(id string) <-chan *User {
48
+ ch := make(chan *User)
49
+ go func() {
50
+ // Caller can't pass context, can't handle errors properly
51
+ }()
52
+ return ch
53
+ }
54
+ ```
55
+
56
+ ### 3. Share Memory by Communicating
57
+
58
+ ```go
59
+ // Good: Channels for ownership transfer
60
+ func generator(ctx context.Context) <-chan int {
61
+ ch := make(chan int)
62
+ go func() {
63
+ defer close(ch)
64
+ for i := 0; ; i++ {
65
+ select {
66
+ case <-ctx.Done():
67
+ return
68
+ case ch <- i:
69
+ }
70
+ }
71
+ }()
72
+ return ch
73
+ }
74
+
75
+ // Good: Mutex when protecting shared state with simple access patterns
76
+ type SafeCounter struct {
77
+ mu sync.Mutex
78
+ v map[string]int
79
+ }
80
+
81
+ func (c *SafeCounter) Inc(key string) {
82
+ c.mu.Lock()
83
+ defer c.mu.Unlock()
84
+ c.v[key]++
85
+ }
86
+ ```
87
+
88
+ ## Channel Patterns
89
+
90
+ ### Pipeline
91
+
92
+ ```go
93
+ func pipeline(ctx context.Context, input <-chan int) <-chan int {
94
+ out := make(chan int)
95
+ go func() {
96
+ defer close(out)
97
+ for v := range input {
98
+ select {
99
+ case <-ctx.Done():
100
+ return
101
+ case out <- v * 2:
102
+ }
103
+ }
104
+ }()
105
+ return out
106
+ }
107
+ ```
108
+
109
+ ### Fan-Out, Fan-In
110
+
111
+ ```go
112
+ func fanOut(ctx context.Context, input <-chan Job, workers int) <-chan Result {
113
+ results := make(chan Result)
114
+ var wg sync.WaitGroup
115
+
116
+ for range workers {
117
+ wg.Add(1)
118
+ go func() {
119
+ defer wg.Done()
120
+ for job := range input {
121
+ select {
122
+ case <-ctx.Done():
123
+ return
124
+ case results <- process(job):
125
+ }
126
+ }
127
+ }()
128
+ }
129
+
130
+ go func() {
131
+ wg.Wait()
132
+ close(results)
133
+ }()
134
+
135
+ return results
136
+ }
137
+ ```
138
+
139
+ ### Bounded Concurrency with Semaphore
140
+
141
+ ```go
142
+ func processAll(ctx context.Context, items []Item, maxConcurrent int) error {
143
+ sem := make(chan struct{}, maxConcurrent)
144
+ g, ctx := errgroup.WithContext(ctx)
145
+
146
+ for _, item := range items {
147
+ g.Go(func() error {
148
+ select {
149
+ case sem <- struct{}{}:
150
+ defer func() { <-sem }()
151
+ case <-ctx.Done():
152
+ return ctx.Err()
153
+ }
154
+ return process(ctx, item)
155
+ })
156
+ }
157
+
158
+ return g.Wait()
159
+ }
160
+ ```
161
+
162
+ ## sync Package
163
+
164
+ ### sync.WaitGroup
165
+
166
+ ```go
167
+ // Always Add before launching the goroutine
168
+ var wg sync.WaitGroup
169
+ for _, item := range items {
170
+ wg.Add(1)
171
+ go func() {
172
+ defer wg.Done()
173
+ process(item)
174
+ }()
175
+ }
176
+ wg.Wait()
177
+ ```
178
+
179
+ ### sync.Once
180
+
181
+ ```go
182
+ // For lazy, thread-safe initialization
183
+ type Client struct {
184
+ initOnce sync.Once
185
+ conn *grpc.ClientConn
186
+ }
187
+
188
+ func (c *Client) getConn() *grpc.ClientConn {
189
+ c.initOnce.Do(func() {
190
+ c.conn = dial() // Only called once, even from many goroutines
191
+ })
192
+ return c.conn
193
+ }
194
+ ```
195
+
196
+ ### sync.Map
197
+
198
+ ```go
199
+ // Use sync.Map ONLY when:
200
+ // 1. Keys are stable (write-once, read-many)
201
+ // 2. Disjoint goroutines access disjoint key sets
202
+ // Otherwise, a regular map with sync.Mutex is simpler and often faster.
203
+ ```
204
+
205
+ ## errgroup
206
+
207
+ ```go
208
+ import "golang.org/x/sync/errgroup"
209
+
210
+ func fetchAll(ctx context.Context, urls []string) ([]Response, error) {
211
+ g, ctx := errgroup.WithContext(ctx)
212
+ responses := make([]Response, len(urls))
213
+
214
+ for i, url := range urls {
215
+ g.Go(func() error {
216
+ resp, err := fetch(ctx, url)
217
+ if err != nil {
218
+ return fmt.Errorf("fetching %s: %w", url, err)
219
+ }
220
+ responses[i] = resp // Safe: each goroutine writes to its own index
221
+ return nil
222
+ })
223
+ }
224
+
225
+ if err := g.Wait(); err != nil {
226
+ return nil, err
227
+ }
228
+ return responses, nil
229
+ }
230
+ ```
231
+
232
+ ## Context
233
+
234
+ ```go
235
+ // Context is the first parameter, always
236
+ func DoWork(ctx context.Context, id string) error { ... }
237
+
238
+ // Never store context in a struct
239
+ // Bad:
240
+ type Server struct {
241
+ ctx context.Context // Don't do this
242
+ }
243
+
244
+ // Derive child contexts for scoped deadlines
245
+ ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
246
+ defer cancel() // Always defer cancel to avoid leaks
247
+
248
+ // Use context values sparingly — only for request-scoped data
249
+ // that transits process boundaries (trace IDs, auth tokens)
250
+ // Never use context for passing optional parameters
251
+ ```
252
+
253
+ ## Race Condition Prevention
254
+
255
+ ```go
256
+ // Always run tests with -race
257
+ // go test -race ./...
258
+
259
+ // Common race: closing over loop variable (fixed in Go 1.22+)
260
+ // Pre-1.22, you needed:
261
+ for _, item := range items {
262
+ item := item // Shadow the loop variable
263
+ go process(item)
264
+ }
265
+ // Go 1.22+ loop variables are per-iteration — no shadowing needed
266
+
267
+ // Common race: reading and writing a map concurrently
268
+ // Maps are NOT safe for concurrent use — use sync.Mutex or sync.Map
269
+ ```
270
+
271
+ ## Anti-Patterns
272
+
273
+ ```go
274
+ // Never: Goroutine without ownership
275
+ go doSomething() // Who waits for this? Who handles the error?
276
+
277
+ // Never: time.Sleep for synchronization
278
+ time.Sleep(100 * time.Millisecond) // Hoping goroutine finishes — use sync primitives
279
+
280
+ // Never: Unbounded goroutine spawning
281
+ for _, item := range millionItems {
282
+ go process(item) // OOM or file descriptor exhaustion
283
+ }
284
+
285
+ // Never: Closing a channel from the receiver side
286
+ // Only the sender closes. Receivers check with range or ok idiom.
287
+
288
+ // Never: Sending on a closed channel (panics)
289
+ // Design your channel lifecycle so ownership is clear
290
+ ```
@@ -0,0 +1,199 @@
1
+ # Go Error Handling
2
+
3
+ Errors in Go are values. They are the primary control flow mechanism for failure cases. Treat them with the same rigor as your business logic.
4
+
5
+ ## Fundamental Rules
6
+
7
+ ### Always Handle Errors
8
+
9
+ ```go
10
+ // Good: Every error is handled
11
+ f, err := os.Open(filename)
12
+ if err != nil {
13
+ return fmt.Errorf("opening config file: %w", err)
14
+ }
15
+ defer f.Close()
16
+
17
+ // Bad: Silently discarding errors
18
+ f, _ := os.Open(filename) // What happens when this fails?
19
+
20
+ // Bad: Logging and continuing as if nothing happened
21
+ f, err := os.Open(filename)
22
+ if err != nil {
23
+ log.Println(err) // Then what? f is nil. You'll panic below.
24
+ }
25
+ ```
26
+
27
+ ### Wrap With Context Using %w
28
+
29
+ ```go
30
+ // Good: Each layer adds context about what it was doing
31
+ func (s *UserService) GetByEmail(ctx context.Context, email string) (*User, error) {
32
+ user, err := s.repo.FindByEmail(ctx, email)
33
+ if err != nil {
34
+ return nil, fmt.Errorf("getting user by email %q: %w", email, err)
35
+ }
36
+ return user, nil
37
+ }
38
+
39
+ // The error chain reads like a stack trace:
40
+ // "getting user by email "bob@example.com": querying users table: sql: connection refused"
41
+
42
+ // Bad: Wrapping without adding useful context
43
+ if err != nil {
44
+ return fmt.Errorf("error: %w", err) // "error:" adds nothing
45
+ }
46
+
47
+ // Bad: Wrapping with redundant "failed to" prefix
48
+ if err != nil {
49
+ return fmt.Errorf("failed to get user: %w", err) // "failed to" is implied — it's an error
50
+ }
51
+ ```
52
+
53
+ ### Sentinel Errors and Custom Types
54
+
55
+ ```go
56
+ // Use sentinel errors for conditions callers need to check
57
+ var (
58
+ ErrNotFound = errors.New("not found")
59
+ ErrAlreadyExists = errors.New("already exists")
60
+ ErrUnauthorized = errors.New("unauthorized")
61
+ )
62
+
63
+ // Check with errors.Is
64
+ if errors.Is(err, ErrNotFound) {
65
+ http.Error(w, "not found", http.StatusNotFound)
66
+ return
67
+ }
68
+
69
+ // Use custom error types when you need to carry structured data
70
+ type ValidationError struct {
71
+ Field string
72
+ Message string
73
+ }
74
+
75
+ func (e *ValidationError) Error() string {
76
+ return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
77
+ }
78
+
79
+ // Check with errors.As
80
+ var ve *ValidationError
81
+ if errors.As(err, &ve) {
82
+ // Access ve.Field, ve.Message
83
+ }
84
+ ```
85
+
86
+ ### When to Use %w vs %v
87
+
88
+ ```go
89
+ // Use %w when callers should be able to unwrap and inspect the cause
90
+ return fmt.Errorf("querying database: %w", err)
91
+
92
+ // Use %v when you want to break the error chain
93
+ // (hide implementation details across API boundaries)
94
+ return fmt.Errorf("internal error: %v", err)
95
+ ```
96
+
97
+ ## Error Handling Patterns
98
+
99
+ ### Errors in Main
100
+
101
+ ```go
102
+ func main() {
103
+ if err := run(); err != nil {
104
+ fmt.Fprintf(os.Stderr, "error: %v\n", err)
105
+ os.Exit(1)
106
+ }
107
+ }
108
+
109
+ func run() error {
110
+ cfg, err := loadConfig()
111
+ if err != nil {
112
+ return fmt.Errorf("loading config: %w", err)
113
+ }
114
+ // ...
115
+ return nil
116
+ }
117
+ ```
118
+
119
+ ### Errors in HTTP Handlers
120
+
121
+ ```go
122
+ // Define an application handler that returns errors
123
+ type appHandler func(w http.ResponseWriter, r *http.Request) error
124
+
125
+ func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
126
+ if err := fn(w, r); err != nil {
127
+ var ve *ValidationError
128
+ switch {
129
+ case errors.As(err, &ve):
130
+ http.Error(w, ve.Message, http.StatusBadRequest)
131
+ case errors.Is(err, ErrNotFound):
132
+ http.Error(w, "not found", http.StatusNotFound)
133
+ case errors.Is(err, ErrUnauthorized):
134
+ http.Error(w, "unauthorized", http.StatusUnauthorized)
135
+ default:
136
+ // Log the full error, return generic message to client
137
+ slog.Error("internal error", "error", err, "path", r.URL.Path)
138
+ http.Error(w, "internal server error", http.StatusInternalServerError)
139
+ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ ### Deferred Cleanup Errors
145
+
146
+ ```go
147
+ // Capture close errors from deferred calls
148
+ func writeFile(path string, data []byte) (err error) {
149
+ f, err := os.Create(path)
150
+ if err != nil {
151
+ return fmt.Errorf("creating file: %w", err)
152
+ }
153
+ defer func() {
154
+ if closeErr := f.Close(); closeErr != nil && err == nil {
155
+ err = fmt.Errorf("closing file: %w", closeErr)
156
+ }
157
+ }()
158
+
159
+ if _, err := f.Write(data); err != nil {
160
+ return fmt.Errorf("writing data: %w", err)
161
+ }
162
+ return nil
163
+ }
164
+ ```
165
+
166
+ ### Multi-Error Collection
167
+
168
+ ```go
169
+ // Collect multiple errors (Go 1.20+ with errors.Join)
170
+ func validateUser(u User) error {
171
+ var errs []error
172
+ if u.Name == "" {
173
+ errs = append(errs, &ValidationError{Field: "name", Message: "required"})
174
+ }
175
+ if u.Email == "" {
176
+ errs = append(errs, &ValidationError{Field: "email", Message: "required"})
177
+ }
178
+ return errors.Join(errs...)
179
+ }
180
+ ```
181
+
182
+ ## Anti-Patterns
183
+
184
+ ```go
185
+ // Never: panic for expected error conditions
186
+ func MustParse(s string) Config {
187
+ // Only acceptable in init() or test helpers, never in request paths
188
+ panic("don't do this in production code paths")
189
+ }
190
+
191
+ // Never: Checking error strings
192
+ if err.Error() == "not found" { } // Fragile — use errors.Is or errors.As
193
+
194
+ // Never: Returning both a value and an error that are both valid
195
+ // If err != nil, the other return values should be zero values
196
+
197
+ // Never: Using naked returns in functions with error handling
198
+ // Named returns for error capture in defer is the one acceptable use
199
+ ```