Skip to content
Santekno.com | Level Up Your Engineering Skills
EN
📖 0%
23 Sep 2026 · 22 min read ·Article 51 / 208
Go

Context Files for AI Tools in Golang: CLAUDE.md, .cursorrules, Copilot Instructions Compared

How to write optimal context files for every AI coding tool. CLAUDE.md, .cursorrules, copilot-instructions.md, and .windsurf/rules.md for a production Golang project.

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

Context Files: CLAUDE.md vs .cursorrules vs Copilot Instructions

Context files are the biggest leverage in using AI coding tools for Golang. Our benchmark shows that a good CLAUDE.md raises Claude Code’s score from 62/100 to 94/100 — a jump you can’t get from swapping models or tools. This article is the definitive guide to writing optimal context files for every tool: CLAUDE.md, .cursorrules, copilot-instructions.md, all the way to .windsurf/rules.md.


11.1 Why Context Files Matter So Much

Without a context file, every AI coding tool starts from zero each session. The comparison below shows the difference in output produced for the exact same command.

text
1Without a context file:
2  AI: "Implement error handling"
3  → Generates: return errors.New("failed")
4  Developer edit: 5-10 minutes needed
5
6With a good context file:
7  AI: "Implement error handling"
8  → Generates: return fmt.Errorf("orderRepo.GetByID: %w", err)
9  Developer edit: 30 seconds (review only)

A 5-minute difference per edit looks small, but it compounds: 50 times a day = 250 minutes = 4+ hours a day, or 80+ hours per developer per month. A context file is a multiplier, not a nice-to-have.


11.2 Comparison: All the Context Files

Each tool has its own file name, format, and persistence model. The table below summarizes all six so you know which file to create for the tool you use.

text
1Tool              File Name                    Format      Persistence
2────────────────────────────────────────────────────────────────────
3Claude Code       CLAUDE.md                    Markdown    Per-session + CLAUDE.md
4Cursor            .cursorrules                 Text        Per-session + file
5GitHub Copilot    .github/copilot-instructions Markdown    Per-query + file
6AWS Kiro          .kiro/steering/*.md          Markdown    Always-on
7Windsurf          .windsurf/rules.md           Markdown    Per-session + Cascade
8Gemini            STYLE_GUIDE.md (implicit)    Markdown    Per-query (implicit)

Notice the Persistence column: only Kiro is “always-on,” the rest are read per-session or per-query — this is why a CLAUDE.md read explicitly at the start of a session is the most powerful.


11.3 CLAUDE.md: The Optimal Structure

CLAUDE.md is the most powerful because Claude Code reads it explicitly at the start of every session. The full template below is a skeleton you can adapt directly for a production Go project.

text
  1# CLAUDE.md — Optimal Template for a Go Project
  2
  3## Identity & Purpose (REQUIRED)
  4This project is [short description].
  5Go version: [exact version].
  6A production service with [traffic scale].
  7
  8## Architecture (CRITICAL — violating this = production bug)
  9
 10### Layer Structure
 11delivery/http/handler/    ← HTTP request/response only
 12internal/usecase/         ← business logic only
 13internal/repository/      ← data access only
 14internal/domain/          ← entities, interfaces, errors (pure Go)
 15
 16### Import Rules (STRICT)
 17- handler: ONLY import usecase interfaces (never impl)
 18- usecase: ONLY import domain types + repository INTERFACES
 19- repository impl: ONLY import domain + database drivers
 20- domain: ZERO external imports (stdlib only)
 21
 22VIOLATION EXAMPLE (NEVER do this):
 23  // in usecase — WRONG
 24  import "github.com/jackc/pgx/v5"  // infrastructure in usecase
 25
 26CORRECT:
 27  // usecase only sees interface
 28  type OrderRepository interface {
 29      GetByIDAndUserID(ctx context.Context, orderID, userID uuid.UUID) (*domain.Order, error)
 30  }
 31
 32## Error Handling (CRITICAL)
 33
 34### Repository Layer
 35// NOT FOUND — return (nil, nil) ALWAYS, never error
 36if errors.Is(err, pgx.ErrNoRows) {
 37    return nil, nil
 38}
 39// DB ERROR — wrap with exact format
 40return nil, fmt.Errorf("orderRepository.GetByIDAndUserID: %w", err)
 41
 42### Usecase Layer
 43// Check nil from repo (= not found case)
 44order, err := uc.repo.GetByIDAndUserID(ctx, input.OrderID, input.UserID)
 45if err != nil {
 46    return fmt.Errorf("cancelOrder.Execute: %w", err)
 47}
 48if order == nil {
 49    return domain.ErrOrderNotFound  // domain error type
 50}
 51// Business rule error
 52if !order.CanBeCancelled() {
 53    return &domain.OrderNotCancellableError{Status: order.Status}
 54}
 55
 56### Handler Layer
 57// Map domain errors to HTTP
 58if errors.Is(err, domain.ErrOrderNotFound) {
 59    return c.JSON(http.StatusNotFound, map[string]string{
 60        "error": "ORDER_NOT_FOUND",  // UPPERCASE_SNAKE_CASE always
 61    })
 62}
 63
 64## Type Rules (ABSOLUTE)
 65- Monetary: ALWAYS int64 cents
 66  WRONG: Price float64 = 50000.0
 67  RIGHT: PriceIDR int64 = 5000000  // Rp 50,000 = 5,000,000 cents
 68- IDs: ALWAYS uuid.UUID (github.com/google/uuid)
 69- Never use: float32, float64 for money
 70
 71## Context Propagation
 72- ctx is ALWAYS first parameter: func(ctx context.Context, ...)
 73- ALWAYS pass ctx to all downstream calls (repo, cache, kafka)
 74- For background operations: context.Background() with timeout
 75  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 76  defer cancel()
 77
 78## Testing
 79Framework: testify/suite (github.com/stretchr/testify/suite)
 80Mocking: gomock (go.uber.org/mock/gomock)
 81
 82// REQUIRED pattern for usecase tests:
 83type CancelOrderSuite struct {
 84    suite.Suite
 85    ctrl     *gomock.Controller
 86    mockRepo *mock.MockOrderRepository
 87    uc       *CancelOrderUseCase
 88}
 89
 90func (s *CancelOrderSuite) SetupTest() {
 91    s.ctrl = gomock.NewController(s.T())
 92    s.mockRepo = mock.NewMockOrderRepository(s.ctrl)
 93    s.uc = NewCancelOrderUseCase(s.mockRepo)
 94}
 95
 96func (s *CancelOrderSuite) TearDownTest() {
 97    s.ctrl.Finish()
 98}
 99
100func TestCancelOrderSuite(t *testing.T) {
101    suite.Run(t, new(CancelOrderSuite))
102}
103
104Test naming: Test[Subject]_[Scenario]_[ExpectedResult]
105Example: TestCancelOrder_PendingStatus_ReturnSuccess
106
107## Go Version Constraints
108Go 1.22 ONLY. DO NOT USE:
109- range-over-func (Go 1.23)
110- slices.Collect (Go 1.23)
111- iter.Seq (Go 1.23)
112
113## Exact Package Imports
114// Always use these exact paths:
115"github.com/jackc/pgx/v5"           // NOT pgx/v4
116"github.com/redis/go-redis/v9"       // NOT v8
117"github.com/labstack/echo/v4"
118"github.com/confluentinc/confluent-kafka-go/v2"
119"github.com/google/uuid"
120"github.com/rs/zerolog"
121"go.uber.org/mock/gomock"            // NOT github.com/golang/mock
122
123## HTTP Response Format
124// Success 200/201:
125{"id": "uuid", "status": "PENDING", ...}
126
127// Error 4xx/5xx:
128{"error": "UPPERCASE_SNAKE_CASE_CODE"}
129
130// Error codes: ORDER_NOT_FOUND, ORDER_NOT_CANCELLABLE,
131//              CANCEL_WINDOW_EXPIRED, UNAUTHORIZED,
132//              FORBIDDEN, INVALID_REQUEST, INTERNAL_ERROR
133
134## What NOT to do (ABSOLUTE)
1351. NEVER float64/float32 for money
1362. NEVER ignore errors with _  (except explicitly tested)
1373. NEVER return DB-specific error from repository (expose nil, nil or wrapped)
1384. NEVER create an interface > 5 methods (split into smaller interfaces)
1395. NEVER import infrastructure from domain
1406. NEVER hardcode config values (use env vars via a config struct)
1417. NEVER use global mutable state (use DI via constructor)

What makes this template effective isn’t its length, but that every rule comes with a WRONG vs CORRECT pair and a concrete code example — this is what makes the AI follow the project’s conventions from the very first generation.


11.4 .cursorrules: Different Style, Same Content

.cursorrules is most effective with a conversational style plus examples. The version below carries the same rules as CLAUDE.md, but written as instructions to a senior-developer persona.

text
 1# .cursorrules — Santekno Shop Go Project
 2
 3You are a senior Go developer working on Santekno Shop, a production 
 4e-commerce platform. Always follow these rules:
 5
 6## Architecture
 7Clean Architecture with strict layer separation:
 8  delivery/http/handler → usecase → repository → domain
 9
10The HANDLER layer only speaks to usecases (via interface).
11The USECASE layer only speaks to repositories (via interface) and domain.
12The REPOSITORY layer only speaks to databases and domain types.
13The DOMAIN layer has ZERO external dependencies.
14
15If you violate this, the code will not compile OR will create 
16circular dependencies that are hard to debug.
17
18## Error Handling — Follow This EXACTLY
19
20When writing repository code:
21  - If record not found: return nil, nil — NEVER return an error
22  - If database error: return nil, fmt.Errorf("repoName.MethodName: %w", err)
23
24Example (CORRECT):
25  if errors.Is(err, pgx.ErrNoRows) {
26      return nil, nil  // correct: not found is not an error
27  }
28  return nil, fmt.Errorf("orderRepository.GetByID: %w", err)
29
30When writing usecase code:
31  - Check for nil (= not found from repo) BEFORE business logic
32  - Use domain error types, not raw errors
33
34Example (CORRECT):
35  order, err := uc.repo.GetByID(ctx, id)
36  if err != nil {
37      return fmt.Errorf("cancelOrder.Execute: %w", err)
38  }
39  if order == nil {
40      return domain.ErrOrderNotFound  // this is a domain error
41  }
42
43## Money — CRITICAL
44NEVER use float64 or float32 for monetary values.
45ALWAYS use int64 representing cents.
46
47WRONG: Price float64 = 50000.0
48RIGHT: PriceIDR int64 = 5000000  // 50000 rupiah = 5000000 cents
49
50## Testing Pattern
51Always use this structure for usecase tests:
52  type [Name]Suite struct {
53      suite.Suite
54      ctrl *gomock.Controller
55      mock[Repo] *mock.Mock[Interface]
56      uc *[UseCase]
57  }
58  func (s *[Name]Suite) SetupTest() {
59      s.ctrl = gomock.NewController(s.T())
60      // setup mocks
61  }
62  func (s *[Name]Suite) TearDownTest() { s.ctrl.Finish() }
63  func Test[Name]Suite(t *testing.T) { suite.Run(t, new([Name]Suite)) }
64
65## Go Version
66This is Go 1.22. Do NOT use Go 1.23 features.
67Do not use: range-over-func, slices.Collect, iter.Seq.
68
69## Package Imports
70Use exact versions:
71  - DB: github.com/jackc/pgx/v5
72  - Cache: github.com/redis/go-redis/v9
73  - HTTP: github.com/labstack/echo/v4
74  - Mocking: go.uber.org/mock/gomock

Notice the opening “You are a senior Go developer…” — this persona style plus imperatives (“NEVER”, “ALWAYS”) is what makes Cursor more obedient than a flat list of rules.


11.5 copilot-instructions.md: The Format for Copilot

GitHub Copilot reads .github/copilot-instructions.md. The version below compresses the same rules into a structured format with “violation = production incident” markers.

text
 1# .github/copilot-instructions.md
 2# Santekno Shop — Copilot Instructions
 3
 4## Overview
 5Production Go 1.22 e-commerce service. High-traffic, Clean Architecture.
 6Every suggestion must match these standards or it creates production bugs.
 7
 8## CRITICAL RULES (violation = production incident)
 9
10### 1. Error Handling
11Repository not-found: MUST return (nil, nil)
12// CORRECT:
13if errors.Is(err, pgx.ErrNoRows) {
14    return nil, nil
15}
16// INCORRECT:
17return nil, pgx.ErrNoRows
18return nil, errors.New("not found")
19
20### 2. Monetary Types
21MUST use int64 cents. NEVER float64.
22// CORRECT: PriceIDR int64 = 5000000 (Rp 50,000)
23// INCORRECT: Price float64 = 50000.0
24
25### 3. Error Wrapping
26MUST wrap with function context:
27// CORRECT:
28return fmt.Errorf("orderRepository.GetByID: %w", err)
29// INCORRECT:
30return err
31return errors.New("database error")
32
33### 4. Context
34MUST pass ctx as the first parameter to ALL functions.
35MUST propagate ctx to all downstream calls (repo, cache, kafka).
36
37### 5. HTTP Response Format
38MUST use: {"error": "UPPERCASE_SNAKE_CASE_CODE"}
39NEVER use: {"message": "..."} or {"error": "lowercase"}
40
41## Architecture
42Clean Architecture. Layers: handler → usecase → repository → domain.
43No cross-layer imports. Domain has zero external dependencies.
44
45## Testing
46testify/suite + gomock pattern ALWAYS.
47No real database in unit tests.
48
49## Packages
50pgx/v5, go-redis/v9, echo/v4, confluent-kafka-go/v2, uuid, zerolog.
51
52## Go: 1.22 only. No 1.23+ features.

Because Copilot reads per-query (not per-full-session), this compact format with the CRITICAL RULES up top ensures the most important rules are always caught even when the context is trimmed.


11.6 .windsurf/rules.md: The Format for Windsurf

Windsurf reads .windsurf/rules.md separately and relies on Cascade for cross-session retention. The format below is deliberately the most compact of all the tools.

text
 1# .windsurf/rules.md
 2# Santekno Shop — Windsurf Rules
 3
 4## Project
 5Go 1.22 production e-commerce. Echo v4, pgx/v5, Redis, Kafka.
 6Clean Architecture (handler → usecase → repository → domain).
 7
 8## Architecture Rules
 9- handler: only import usecase interfaces
10- usecase: only import domain + repository interfaces
11- repository: only import domain + database drivers
12- domain: ZERO external imports
13
14## Error Handling
15Repository layer:
16  - Not found: return nil, nil  (this is correct, not a bug)
17  - DB error: return nil, fmt.Errorf("repoName.Method: %w", err)
18
19Usecase layer:
20  - Check nil from repo → return domain error type
21  - Wrap upstream errors: fmt.Errorf("usecase.Method: %w", err)
22
23Handler layer:
24  - Map domain errors to HTTP codes
25  - Response: {"error": "UPPERCASE_ERROR_CODE"}
26
27## Types
28Money: int64 cents ONLY (50000 Rp = 5000000 int64)
29IDs: uuid.UUID from github.com/google/uuid
30
31## Testing
32testify/suite + gomock. No real DB in unit tests.
33Pattern: Suite struct → SetupTest → TearDownTest → Suite.Run
34
35## Imports
36Use exactly: pgx/v5, go-redis/v9, echo/v4, kafka-go/v2
37
38## Go 1.22 only
39No: range-over-func, slices.Collect, iter.Seq

Because Cascade already handles context retention across sessions, you can write Windsurf’s rules more concisely than CLAUDE.md without losing effectiveness.


11.7 Sync: One Source, Multiple Formats

A team using many tools has to keep many context files in sync. The script below derives all the tool files from a single CLAUDE.md source.

bash
 1#!/bin/bash
 2# scripts/sync-context-files.sh
 3# Sync from CLAUDE.md to all tools
 4
 5# 1. Extract sections from CLAUDE.md
 6ARCH=$(sed -n '/^## Architecture/,/^## /p' CLAUDE.md | head -n -2)
 7ERRORS=$(sed -n '/^## Error Handling/,/^## /p' CLAUDE.md | head -n -2)
 8TYPES=$(sed -n '/^## Type Rules/,/^## /p' CLAUDE.md | head -n -2)
 9TESTING=$(sed -n '/^## Testing/,/^## /p' CLAUDE.md | head -n -2)
10IMPORTS=$(sed -n '/^## Exact Package/,/^## /p' CLAUDE.md | head -n -2)
11
12# 2. Update .cursorrules (convert headers to conversational)
13python3 scripts/convert_to_cursorrules.py CLAUDE.md > .cursorrules
14
15# 3. Update .github/copilot-instructions.md
16python3 scripts/convert_to_copilot.py CLAUDE.md > .github/copilot-instructions.md
17
18# 4. Update .windsurf/rules.md
19python3 scripts/convert_to_windsurf.py CLAUDE.md > .windsurf/rules.md
20
21# 5. Update .kiro/steering/
22python3 scripts/convert_to_kiro.py CLAUDE.md > .kiro/steering/project.md
23
24echo "✅ All context files synced from CLAUDE.md"

If you don’t want to maintain conversion scripts, the practical approach: make CLAUDE.md the single source of truth, copy the relevant sections manually when setting up a new tool, and review consistency every quarter.


11.8 Context File Quality: A Checklist

A good context file meets measurable criteria, not just “complete.” The checklist below separates what’s required, what’s good to have, and what to avoid — including guidance on optimal length.

text
 1A good context file meets this checklist:
 2
 3MUST HAVE:
 4□ Exact Go version (1.22, not "recent Go")
 5□ Architecture rules with WRONG vs CORRECT examples
 6□ Error handling rules with code examples
 7□ Money type rules (int64 cents)
 8□ Exact package import paths
 9□ Testing framework and pattern
10□ A "What NOT to do" list
11
12GOOD TO HAVE:
13□ Project context (not generic)
14□ HTTP response format
15□ Context propagation rules
16□ Naming conventions
17□ Comment style (godoc format)
18
19AVOID:
20□ Rules without code examples
21□ A context file that's too long (> 300 lines starts to be counter-productive)
22□ Generic rules that are already obvious (e.g., "write clean code")
23□ Outdated information (package v4 when it's already v5)
24□ Sensitive information (API keys, passwords)
25
26LENGTH GUIDE:
27  Minimum viable: 50-80 lines (basic rules)
28  Recommended: 150-200 lines (with examples)
29  Maximum effective: 300 lines
30  > 300 lines: diminishing returns, the model can "forget" early sections

Note the key numbers: 150-200 lines is the sweet spot, and above 300 lines it becomes counter-productive because the model starts to “forget” the rules in the early part of the file.


11.9 Context Files for Specific Go Patterns

Some Go patterns deserve a place in the context file but are often forgotten. The collection below adds interface design, constructors, concurrency, and middleware ordering to CLAUDE.md.

text
 1## Golang-specific Patterns (add to CLAUDE.md)
 2
 3### Interface Design (Go Proverbs: accept interfaces, return structs)
 4Define interfaces on the consumer side, NOT the producer side:
 5// CORRECT: interface on the consumer (usecase)
 6type OrderRepository interface {
 7    GetByIDAndUserID(ctx context.Context, orderID, userID uuid.UUID) (*domain.Order, error)
 8    CancelWithStockRestore(ctx context.Context, orderID uuid.UUID) error
 9}
10
11// INCORRECT: interface on the producer (repository)
12// Don't put the interface in the repository package itself
13
14### Constructor Pattern
15Always use a New[Name] constructor:
16// CORRECT:
17func NewCancelOrderUseCase(repo OrderRepository) *CancelOrderUseCase {
18    return &CancelOrderUseCase{repo: repo}
19}
20// INCORRECT:
21uc := &CancelOrderUseCase{}  // direct struct init without interface
22uc.repo = &postgresOrderRepository{...}  // direct impl, not interface
23
24### Goroutine and Concurrency
25Always handle goroutine lifecycle:
26// CORRECT:
27g, ctx := errgroup.WithContext(ctx)
28g.Go(func() error {
29    return processOrder(ctx, order)
30})
31if err := g.Wait(); err != nil {
32    return fmt.Errorf("worker group: %w", err)
33}
34
35// INCORRECT:
36go processOrder(ctx, order)  // fire and forget, no error handling
37
38### HTTP Middleware Order
39Echo middleware order matters (add to CLAUDE.md):
40// CORRECT order:
41e.Use(middleware.Recover())   // 1. panic recovery first
42e.Use(middleware.Logger())    // 2. then logging
43e.Use(middleware.CORS())      // 3. then CORS
44// Auth middleware: per-route, not global

Patterns like “accept interfaces, return structs” and goroutine lifecycle handling are often ignored by AI unless written explicitly — including them in the context file prevents an expensive class of concurrency bugs.


11.10 The Context File as an Onboarding Tool

A good CLAUDE.md doubles as an onboarding document for new developers. The section below shows the onboarding-instruction format you can add to the file.

text
 1## Developer Onboarding (add to CLAUDE.md)
 2
 3### For New Developers
 4
 5Read this first before writing any code:
 6
 71. READ the architecture (Architecture section)
 82. READ error handling (Error Handling section) — this is very important
 93. RUN the existing tests: make test
104. IMPLEMENT the smallest feature first:
11   Look at the existing [simple feature] as a reference
125. ASK if anything is unclear:
13   Architecture violations are the most common mistake
14
15### Example Features to Use as Reference
16- Simple CRUD: [link to existing feature]
17- Feature with Kafka: [link to existing feature]
18- Feature with Redis cache: [link to existing feature]
19
20### Common Mistakes (the most frequent)
211. Returning an error from a repository for not-found (should be nil, nil)
222. Float64 for price (should be int64 cents)
233. Importing repository impl from the usecase (architecture violation)
244. Forgetting a context timeout for external calls

This double benefit is real: the same file aligns both AI and humans — a new developer and the AI tool read identical rules, so there’s no divergence in conventions.


11.11 Tools to Maintain Context Files

A context file can become stale without you noticing. The three commands below help validate syntax and detect package paths that no longer match go.mod.

bash
 1# Tool 1: Validate CLAUDE.md syntax
 2npx markdownlint CLAUDE.md
 3
 4# Tool 2: Check the context file isn't outdated
 5# Check whether the package paths in CLAUDE.md still match go.mod:
 6grep -oP 'github\.com/\S+' CLAUDE.md | while read pkg; do
 7    if ! grep -q "$pkg" go.mod; then
 8        echo "WARNING: $pkg in CLAUDE.md but not in go.mod"
 9    fi
10done
11
12# Tool 3: Check CLAUDE.md covers all domain packages
13for domain_pkg in $(find internal/domain -name "*.go" | head -5); do
14    pkg_name=$(grep "^package" $domain_pkg | awk '{print $2}')
15    echo "Checking if $pkg_name is mentioned in CLAUDE.md..."
16    grep -q "$pkg_name" CLAUDE.md && echo "✅ Found" || echo "⚠️ Not found"
17done

This small automation closes the most common gap: a context file mentioning pgx/v4 when go.mod is already on pgx/v5 will mislead the AI — validating against go.mod prevents it.


11.12 Context File Anti-Patterns to Avoid

Just as important as knowing what to write is knowing what to avoid. The five anti-patterns below come with BAD vs GOOD pairs so they’re easy to recognize.

text
 1Anti-pattern 1: Too Generic
 2BAD:
 3  "Write clean, maintainable Go code"
 4  "Follow best practices"
 5
 6GOOD:
 7  "Use fmt.Errorf('package.Method: %w', err) for ALL error wrapping"
 8  "Return (nil, nil) for not-found from repository — never error"
 9
10Anti-pattern 2: No Code Examples
11BAD:
12  "Handle errors properly in the repository"
13
14GOOD:
15  if errors.Is(err, pgx.ErrNoRows) {
16      return nil, nil
17  }
18  return nil, fmt.Errorf("repo.Method: %w", err)
19
20Anti-pattern 3: Outdated Rules
21BAD:
22  "Use github.com/golang/mock" (deprecated)
23
24GOOD:
25  "Use go.uber.org/mock/gomock (replaces golang/mock)"
26
27Anti-pattern 4: Too Long (>300 lines)
28  - Model attention dilutes for the rules at the start of the file
29  - Prioritize what's most often violated
30  - Split into multiple files if needed (CLAUDE.md can reference other files)
31
32Anti-pattern 5: Conflicting Rules
33BAD:
34  "Always return an error for not-found" (in one section)
35  "Repository: return nil, nil for not-found" (in another section)
36
37Review the context file for consistency before committing.

The most dangerous anti-pattern is number 5 (conflicting rules): rules that contradict each other make AI output unpredictable — always review for consistency before committing.


11.13 Context File Evolution: How to Maintain It

A context file is a living document, not write-once-and-forget. The review cadence below keeps the file relevant from sprint level to quarter.

text
 1Sprint-based evolution:
 2
 3Sprint end review:
 4  "Which AI output did we most often have to edit this week?"
 5  → That's what needs to be added to the context file
 6
 7Monthly review:
 8  □ Are all package paths still correct against go.mod?
 9  □ Are there new patterns established this month?
10  □ Is there a rule that's no longer relevant?
11  □ Is the context file still under 300 lines?
12  □ Are there inconsistencies between tools (CLAUDE.md vs .cursorrules)?
13
14Quarterly review:
15  □ Go version update that requires updating CLAUDE.md?
16  □ An architecture decision that changed?
17  □ New patterns worth documenting?
18
19PR workflow for CLAUDE.md updates:
20  → Changes to CLAUDE.md need PR approval from the tech lead
21  → Not because of bureaucracy, but because CLAUDE.md affects every developer
22  → Treat it like an ADR — a documented decision

The most valuable signal is in the sprint review: whatever you repeatedly have to edit out of the AI’s output is a direct candidate to add to the context file.


11.14 Advanced: CLAUDE.md with Multiple Tool Support

A single CLAUDE.md can carry tool-specific notes so a multi-tool team stays consistent. The advanced section below shows how to embed per-tool instructions inside a single file.

text
 1# CLAUDE.md — Advanced Section
 2
 3## Tool-Specific Notes
 4
 5### If using Claude Code
 6This session is assumed to use the Claude Code CLI.
 7You can run bash commands directly:
 8  go build ./...
 9  go test -race ./...
10  go generate ./...
11Do this after every implementation step.
12
13### If using Cursor
14Use @file to reference specific files when context is needed:
15  @file internal/usecase/order/cancel_order.go
16Cursor Agent Mode: use it for bulk implementation but always review the diff.
17
18### If using Copilot
19Reference @workspace for project-level context.
20/tests to generate tests from a selected function.
21/explain to understand complex code.
22
23### If using Windsurf
24Windsurf reads rules.md separately in .windsurf/rules.md.
25Cascade will maintain context across sessions.

This pattern keeps the core rules single while documenting each tool’s nuance (e.g., @file for Cursor, /tests for Copilot) in the same place — no knowledge scattered in each developer’s head.


11.15 Context File ROI Calculator

The investment of writing a context file is easy to justify with numbers. The calculation below shows the break-even point and the annual value per developer.

text
 1Calculate the ROI of the time invested in setting up a context file:
 2
 3Setup time:
 4  Basic context file (100 lines): 1 hour
 5  Comprehensive (200 lines): 2-3 hours
 6  Full (300 lines with code examples): 4-5 hours
 7
 8Value per edit saved:
 9  Without context file: 5-10 minutes editing AI output
10  With context file: 30-60 seconds review
11  Saving per edit: 4-9 minutes
12
13Break-even calculation (comprehensive, 3-hour setup):
14  3 hours = 180 minutes
15  Saving per edit: 5 minutes average
16  Break-even: 180/5 = 36 edits
17
18Typical daily edits: 20-50 (a coding day with heavy AI)
19Break-even: within 1-2 working days!
20
21After break-even: pure savings.
22  20 edits/day × 5 minutes × 250 working days/year = 25,000 minutes = 416 hours/year
23
24If hourly rate = Rp 150,000/hour:
25  Value = 416 × 150,000 = Rp 62,400,000/year/developer
26  vs Setup cost = 3 hours × 150,000 = Rp 450,000
27
28ROI = 62,400,000 / 450,000 = 13,867%

The numbers are extreme but honest: break-even within 1-2 working days, then the rest is pure saving — this is why a context file is one of the highest-ROI engineering investments you can make this week.


11.16 Template Repository: Context Files

For teams, creating a template repository speeds up setting up a new project. The structure below gathers all the context-file templates in a single repo.

bash
 1# Create a template repository for context files
 2# github.com/santekno/ai-context-templates
 3
 4├── golang/
 5│   ├── CLAUDE.md.template
 6│   ├── .cursorrules.template
 7│   ├── copilot-instructions.template.md
 8│   ├── windsurf-rules.template.md
 9│   └── kiro-steering.template.md
10├── scripts/
11│   ├── sync-context-files.sh
12│   └── validate-context-files.sh
13└── README.md
14
15# Usage:
16# 1. Copy a template into the project
17cp ai-context-templates/golang/CLAUDE.md.template ./CLAUDE.md
18# 2. Customize with project-specific details
19# 3. Run the sync script to generate tool-specific files

With a centralized template repo, every new project immediately inherits the team’s battle-tested conventions — no more CLAUDE.md rewritten from scratch with inconsistent quality.


11.17 Tips & Gotchas

💡 Tip 1: Code examples > prose for every rule. “Return nil, nil for not-found” + a code example = 2× more effective than prose alone.

💡 Tip 2: WRONG vs CORRECT pairs. Show explicitly what’s wrong and what’s right. The AI is better at avoiding a pattern explicitly marked as wrong.

💡 Tip 3: Update the context file when there’s tech debt. If the AI keeps generating something you have to edit, that’s a signal the context file needs an update.

⚠️ Gotcha 1: Sensitive info. Don’t put API keys, database passwords, or internal URLs in the context file. This file is committed to the repo, so it’s visible to everyone with access.

⚠️ Gotcha 2: Tool-specific syntax. A good CLAUDE.md doesn’t automatically mean a good .cursorrules — the format is different and needs adaptation.


11.18 Context Files for Open Source Go Projects

Open source projects have an extra consideration because their context file is public. The points below explain how to leverage it as a contribution guide.

text
 1Special considerations for open source:
 2
 31. The context file can be public (safe)
 4   CLAUDE.md committed to a public repo
 5   → Contributors can see the conventions
 6   → The AI tools contributors use will also follow the rules
 7
 82. Use it as a CONTRIBUTION GUIDE
 9   CLAUDE.md + CONTRIBUTING.md can overlap
10   AI tools will follow CLAUDE.md
11   Humans can read CONTRIBUTING.md
12
133. Versioning in CLAUDE.md
14   Like documentation, the context file needs a version
15   # CLAUDE.md v2.1 — last updated: 2026-07
16
174. Community-driven evolution
18   Contributors can PR updates to CLAUDE.md
19   Maintain it as a living document

For an open source project, a public CLAUDE.md becomes an asset: contributors and their AI tools follow the same conventions, so external PRs are more consistent with the project’s style.


11.19 Checklist: Before a Context File Is “Production Ready”

Before marking a context file ready to use, do a final verification. The checklist below ensures every rule has been tested, not just written.

text
 1□ All package paths verified against go.mod
 2□ All code examples are valid Go syntax (test compile)
 3□ Architecture rules tested: try a violation, does the AI catch it?
 4□ Error handling rules tested: try generating a repo, does it return nil, nil?
 5□ Money type rules tested: try generating a struct with a price, float64 or int64?
 6□ Testing pattern tested: generate a test, does it use testify/suite?
 7□ File contains no sensitive information
 8□ File < 300 lines (if more, prioritize or split)
 9□ Reviewed by at least 1 other senior developer
10□ Committed to the repo and mentioned in the README

The most often-missed point is “tested”: don’t just write the rules — try to trigger their violation and confirm the AI actually catches them before considering the context file production ready.


11.20 Summary

Context files are the best investment for a team using AI coding tools. Their ROI is extraordinary — break-even in 1-2 days, then purely productivity gain.

Key takeaways:

  • CLAUDE.md: the most powerful, read explicitly at the start of a session
  • .cursorrules: conversational style with code examples
  • copilot-instructions.md: structured, code examples per rule
  • .windsurf/rules.md: concise, Cascade handles retention
  • STYLE_GUIDE.md: Gemini reads it implicitly

Universal recommendation: Create a comprehensive CLAUDE.md as the single source of truth, then derive the other tools from it. In the next article we level up: using this context file within a Test-Driven AI Development workflow.

Related Articles

💬 Comments