speckit.constitution: The Project Constitution You Must Not Violate
A complete guide to writing constitution.md for GitHub Spec Kit on a Golang project. All the mandatory components, real Santekno Shop examples, and techniques for a constitution the AI enforces consistently.
The constitution is the most important document in the entire .specify/ folder. It’s read by every Spec Kit command — the foundation that ensures the AI always generates code consistent with your project’s architecture and conventions.
The analogy: if spec.md is a law that changes per feature, constitution.md is the constitution — the ground rules that must never be broken. This article shows how to write a speckit constitution golang project document that the AI actually enforces.
05.1 Running specify constitution init
Creating a constitution starts with a single interactive command that interviews you about the project. The command below kicks off that Q&A from the project root.
1specify constitution initSpec Kit walks through questions about project identity, tech stack with versions, architecture pattern, must-always rules, must-never rules, and testing conventions — then writes the answers to .specify/constitution.md. Answer these once and every future command inherits the context.
05.2 Anatomy of a Good Constitution
A strong constitution follows a predictable section order so both humans and the AI can navigate it. The outline below is the canonical Santekno Shop structure.
1Section 1: Project Identity — name, type, Go module path
2Section 2: Tech Stack — table with package names and exact versions
3Section 3: Architecture — dependency direction, layer responsibilities, package layout
4Section 4: Must Always — error wrapping, context-first, uuid.UUID IDs, int64 money
5Section 5: Must Never — no ORM, no direct DB from handler, no circular imports
6Section 6: Testing Standards — suite structure, naming format, coverage targetsThe most load-bearing sections are 4 and 5, so those deserve concrete code. Here is how the “Must Always” error-handling and ID rules look when written with real Go examples rather than prose.
1// Must Always — error wrapping with function context
2return fmt.Errorf("CreateOrder: validateCart: %w", err)
3
4// Must Always — context.Context is the first parameter everywhere
5func (uc *productUseCase) CreateProduct(ctx context.Context, in CreateProductInput) (*Product, error)
6
7// Must Always — uuid.UUID for entity IDs, never string or int
8type Product struct {
9 ID uuid.UUID `json:"id"`
10 SellerID uuid.UUID `json:"seller_id"`
11 // Must Always — money in the smallest unit as int64, never float64
12 PriceCents int64 `json:"price_cents"`
13}The takeaway: rules paired with a canonical code example are the ones the AI reproduces faithfully. A rule stated only in prose (“wrap your errors”) is far more likely to be interpreted loosely than one anchored to fmt.Errorf("func: %w", err).
05.3 Required vs Optional Components
Not every section carries equal weight, so it helps to know the non-negotiable core versus the nice-to-haves. The list below separates the two.
1REQUIRED in every constitution:
2 - Project identity (name, type, Go module)
3 - Tech stack with specific versions
4 - Architecture rules with dependency direction
5 - Must Always rules (at minimum: error handling and context)
6 - Must Never rules
7 - Testing conventions
8
9OPTIONAL but recommended:
10 - Database conventions
11 - API response format
12 - Spec-first rule (strongly recommended)
13 - Domain glossaryThe rule to remember: ship the required six first, then grow the optional sections as real inconsistencies surface in code review. A lean constitution that is followed beats an exhaustive one that is skimmed.
05.4 Common Constitution Mistakes
The difference between a rule that works and one that gets ignored usually comes down to specificity. The before/after pairs below show the three most common failure modes.
1❌ "Write clean and maintainable code" ← too vague
2✅ "Use fmt.Errorf('func: %w', err) for all error wrapping"
3
4❌ "Use structured logging" ← no example
5✅ "Use log/slog: slog.InfoContext(ctx, 'msg', 'key', value)"
6
7❌ "Use pgx" ← no version
8✅ "Use github.com/jackc/pgx/v5 (v5.x.x)"The pattern is consistent: vague rules with no example and no version are the ones the AI cannot follow precisely. Every rule that matters should be measurable, exemplified, and versioned.
05.5 Constitution and Context Window
The constitution is read on every command, so its length is a recurring cost, not a one-time one. The note below quantifies why brevity matters.
1Target length: 150-300 lines.
2Every token in the constitution is consumed by every specify command.
3500-token constitution × 100 commands = 50,000 extra tokens of cost.
4
5Keep: rules most frequently violated, rules that need code examples,
6 rules that can't be inferred from general Go best practices.So the discipline is ruthless focus: keep only the rules that are frequently broken or genuinely non-obvious, and let gofmt/go vet enforce the rest. Length is a budget you spend on every single AI call.
05.6 Automated Constitution Testing
A constitution is only as good as your ability to detect violations, and much of that can be scripted with plain grep. The check below fails CI when forbidden patterns appear in the codebase.
1# Test that existing code complies with constitution
2if grep -r "gorm" internal/ --include="*.go" > /dev/null; then
3 echo "❌ CONSTITUTION VIOLATION: ORM detected"; exit 1
4fi
5
6if grep -r "pgxpool\|db\.Query" internal/*/handler/ --include="*.go"; then
7 echo "❌ CONSTITUTION VIOLATION: Direct DB call from handler"; exit 1
8fi
9
10echo "✅ Constitution compliance checks passed"The value here is turning subjective rules into an objective gate: “no ORM” and “no direct DB from handler” become failing exit codes rather than review comments someone might miss.
05.7 Updating the Constitution
A constitution is a living document that must change when your engineering reality changes. The commands below show the two update paths and the changelog discipline that accompanies them.
1specify constitution update
2# or
3vim .specify/constitution.md
4git commit -m "docs(constitution): add Redis caching pattern
5
6Added Redis caching conventions:
7- Cache key format: {domain}:{entity}:{id}
8- TTL: 5 minutes for read-heavy endpoints
9- Cache-aside pattern only"Update whenever a new library is added, a new pattern is agreed, or a new architectural decision is made — and always record why in the commit, because a rule without a rationale gets removed by the next engineer who disagrees with it.
05.8 Constitution as Onboarding Document
A well-written constitution doubles as the fastest onboarding path a new engineer can take. The snippet below shows what a ten-minute read conveys.
1cat .specify/constitution.md # 10 minutes
2# New developer immediately knows:
3# - What tech stack to use (with exact versions)
4# - How to structure packages
5# - How to handle errors
6# - How to write tests
7# - What is absolutely forbiddenThe result is no more lengthy knowledge-transfer sessions: everything a new hire needs to be productive on day one is captured in one reviewed, version-controlled file.
05.9 Syncing with CLAUDE.md
The constitution serves Spec Kit while CLAUDE.md serves interactive Claude Code sessions — keeping them consistent avoids contradictory guidance. The commands below sync one from the other.
1specify claude-md sync # Preview diff
2specify claude-md sync --apply # Apply
3git add CLAUDE.md && git commit -m "docs: sync CLAUDE.md from constitution v1.1"Treat the constitution as the source of truth and CLAUDE.md as its projection: sync after every constitution change so the two tools never pull the AI in different directions.
05.10 Constitution Changelog Pattern
Because a constitution changes over time, a compact changelog makes its evolution auditable. The table below is the recommended format.
1## Changelog
2| Date | Version | By | Change |
3|------|---------|-----|--------|
4| 2025-07-15 | 1.2 | @andi | Add Redis caching conventions |
5| 2025-07-08 | 1.1 | @budi | Add database conventions |
6| 2025-07-01 | 1.0 | @budi | Initial constitution |Keeping this table current lets anyone answer “when did this rule appear and why” in seconds — the same audit value a good git history provides, but centralized in the document that governs the whole project.
05.11 Constitution Governance for Larger Teams
Once a team grows past a handful of engineers, changing the constitution needs explicit governance so it doesn’t drift by accident. The section below defines who can propose and approve changes.
1## 9. Constitution Governance
2
3### Who Can Propose Changes
4Any team member can propose via PR.
5
6### Who Can Approve
7Tech Lead required for all changes.
8PM required for business rule changes.
9
10### Review Timeline
1148-hour minimum review window.The principle: treat constitution changes with the same rigor as architectural changes, because that is exactly what they are. A required approver and a review window prevent one person from silently reshaping how the entire team writes code.
05.12 Probe Testing the Constitution
After writing a constitution, the fastest way to confirm it “takes” is to generate a throwaway plan and inspect it against your rules. The probe below does exactly that.
1specify plan test-feature --dry-run
2
3# Verify the generated plan:
4# ✅ Uses pgx/v5, not database/sql or GORM
5# ✅ Interfaces defined in usecase package
6# ✅ Error wrapping: fmt.Errorf("func: %w", err)
7# ✅ IDs use uuid.UUID
8# ✅ Prices use int64 with Cents suffixIf the dry-run plan already honors every checked rule, your constitution is being read and enforced. If it doesn’t, that’s your signal to tighten the offending rule with a clearer example before you write real features.
05.13 Constitution for Different Architecture Styles
The constitution format is architecture-agnostic — the sections stay the same, only the rules change. The example below adapts it to Hexagonal (Ports and Adapters).
1## Architecture: Hexagonal (Ports and Adapters)
2
3### Core Concept
4Business logic in center, adapters on outside
5
6### Port Naming Convention
7Driving ports: [Name]UseCase (e.g., CreateOrderUseCase)
8Driven ports: [Name]Port (e.g., OrderRepositoryPort)
9
10### Adapter Naming Convention
11[Technology][Port]Adapter (e.g., PostgresOrderRepositoryAdapter)The takeaway: whether you use Clean Architecture, Hexagonal, or something else, the constitution’s job is unchanged — encode the dependency direction and naming rules explicitly so the AI never has to guess your style.
05.14 Real-World Lessons
Some rules earn their place because production taught you the hard way. The list below is the short list of rules that repeatedly prevent real bugs.
11. Error wrapping format — most frequently violated; needs a very explicit example.
22. UUID vs string ID — biggest source of bugs; show WRONG vs RIGHT.
33. Float for prices — causes rounding errors; state emphatically (int64 cents).
44. Interface placement — new developers always confused; be very explicit.If your constitution nails only these four, you have already eliminated the majority of the inconsistencies that AI-generated Go tends to introduce. Everything else is refinement.
05.15 Length Optimization
When a constitution creeps past 300 lines, it starts costing more than it teaches. The playbook below trims it back without losing signal.
1If the constitution exceeds 300 lines:
2 1. Remove rules already enforced by Go tooling (gofmt, go vet)
3 2. Combine related rules
4 3. Move the domain glossary to a separate file
5 4. Remove redundant examples — keep only the canonical oneApply these in order and you’ll usually reclaim a third of the length while keeping every rule that matters — a leaner constitution is both cheaper per call and more likely to be read end to end.
05.16 Constitution Review Checklist
Before merging any new or updated constitution, a quick checklist catches the common gaps. The list below is the pre-merge gate.
1✅ All required sections present?
2✅ Tech stack has specific versions?
3✅ Architecture dependency direction explicit?
4✅ Error handling has code example?
5✅ Testing conventions specific?
6✅ No contradictory rules?
7✅ Length < 300 lines?
8✅ Tech lead reviewed?
9✅ CLAUDE.md synced?
10✅ Team notified of changes?Running this list every time keeps the constitution trustworthy — the moment it contains contradictory or outdated rules, the AI starts generating code that is confidently wrong.
05.17 Environment-Specific Rules
Some conventions legitimately differ between development and production, and the constitution can encode both. The section below splits rules by environment.
1## Environment-Specific Rules
2
3### Development
4- Use testcontainers for integration tests
5- Log level: DEBUG acceptable
6
7### Production
8- Log level: INFO minimum
9- All secrets via environment variables
10- Enable Prometheus metrics endpointBeing explicit here prevents a whole class of mistakes — like DEBUG logging leaking into production — by making the environment boundary a written rule rather than tribal knowledge.
05.18 Tips & Gotchas
A few principles separate constitutions that stay useful from those that rot. The list below captures the highest-leverage ones.
1💡 Tip 1: Start minimal, expand over time — 100 lines followed beats 500 half-ignored.
2💡 Tip 2: Review the constitution at sprint retrospectives.
3💡 Tip 3: Give constitution changes the same review rigor as architectural changes.
4💡 Tip 4: Run probe tests monthly to verify the AI still follows it.
5⚠️ Gotcha 1: An outdated constitution is worse than none — the AI generates wrong code.
6⚠️ Gotcha 2: Too long = too expensive — every token is consumed on every command.
7⚠️ Gotcha 3: Don't include business rules — those belong in spec.md.
8⚠️ Gotcha 4: The constitution doesn't replace code review — human judgment still required.Gotcha 1 is the one to fear most: a stale rule pointing at a library you no longer use will actively steer the AI wrong, which is far more dangerous than the absence of any rule at all.
05.19 Constitution for Microservice Teams
Teams running multiple services usually want shared engineering conventions with room for service-specific overrides. The layout and config below show how to compose a base and a local constitution.
1// order-service/specify.config.json
2{
3 "constitution": {
4 "base": "../../.specify/constitution.md",
5 "local": ".specify/constitution-local.md"
6 }
7}This layering gives you the best of both worlds: shared rules (Go version, error patterns, testing standards) live in one place, while each service keeps only its genuinely local conventions — no copy-paste drift across repositories.
05.20 Summary
The constitution is the foundation of everything Spec Kit does. Every command — from specify plan to specify implement — starts by reading the constitution and ensuring output is consistent with the principles it contains.
Required components: project identity, tech stack with versions, architecture rules with dependency direction, must-always rules with code examples, must-never rules, testing conventions.
Update ritual: whenever a new library, pattern, or architectural decision appears, update the constitution in a separate PR with a clear changelog.
Length target: 150-300 lines. Enough for clear guidance, not so long it wastes the context window on every call.
In the next article, we cover speckit.specify — how to write business requirements that become the foundation for all technical decisions, without naming a single library.