Skip to content

edikt for Solo Engineers

You own the full cycle. Requirements, architecture, implementation, testing, shipping. Every decision is yours. And every decision lives in your head — which means Claude doesn't have it next session.

This guide shows the actual workflow. Not summaries. Not feature lists. The conversation between you and Claude, from first init to the moment governance starts compounding.


1. First init — describe the project, get governance

You have a Go backend for a payment processing service. Chi router, PostgreSQL, hexagonal architecture. You've been running Claude Code on it for two weeks with a hand-maintained CLAUDE.md that's already out of date.

Claude Code — payment-service
/edikt:init
[1/3] Scanning project...
Code: Go project, 89 files. Chi framework, PostgreSQL.
Build: make build | Test: make test
Commits: conventional commits detected
[2/3] Configuring...
Rules (✓ = recommended for your stack):
[x] code-quality — naming, correctness guardrails
[x] testing — TDD, tautological test prevention
[x] security — payment surface detected, timing attacks
[x] error-handling — typed errors, context wrapping
[x] architecture — hexagonal layer enforcement
[x] go — error handling, data races, interfaces
[x] chi — thin handlers, middleware
[ ] api, database, frontend, observability, seo...
Agents: architect, backend, dba, qa, security, docs, api, sre
SDLC: conventional commits, PR template
Toggle items by name, or say "looks good" to proceed.
looks good
[3/3] Installing...
✓ Config, project context, 7 rules, 8 agents, 9 behaviors, CLAUDE.md
Start building — describe what you want. Rules and agents are active.

That took 30 seconds. The rules are in .claude/rules/. The agents are in .claude/agents/. The hooks are in .claude/settings.json. Everything Claude needs to follow your standards is installed where Claude actually reads it — not in a wiki, not in a doc you'll forget to update.


2. The moment Claude follows the rules without being told

Next morning. New session. You don't mention your architecture. You don't remind Claude about error handling. You just describe the work.

Claude Code — payment-service
I need a new endpoint to handle Stripe webhook events. POST /webhooks/stripe. It should verify the Stripe signature, parse the event, and route to the right handler based on event type. Start with payment_intent.succeeded and payment_intent.payment_failed.
I'll build the webhook handler following your hexagonal architecture.
Here's my approach:
- Domain: WebhookEvent entity + PaymentEventHandler port
- Application: ProcessWebhookUseCase orchestrates verification → parsing → routing
- Infrastructure: StripeWebhookAdapter (signature verification), Chi handler (HTTP layer only)
The handler won't touch the database directly — it calls through the application layer. Errors will be typed (ErrInvalidSignature, ErrUnknownEventType) with context wrapping per your error-handling rules.
I'll use the raw request body for signature verification, not the parsed JSON — Stripe requires the raw bytes.
Starting with the domain layer.

Stop and read that again.

Claude separated the layers correctly — domain, application, infrastructure. It kept the HTTP handler thin. It used typed errors with context wrapping. It knew about Stripe's raw body requirement. It planned the work from the domain layer outward.

You didn't ask for any of that. The rules in .claude/rules/ told Claude how your project works. The go.md rules told it how you write Go. The architecture.md rules told it about hexagonal layers. The error-handling.md rules told it about typed errors.

This is the moment. Claude read your rules before you asked. No reminding. No re-explaining. The overhead stops here.


3. Writing a PRD through conversation

Two weeks in. You need Stripe webhook delivery with retry logic — not just receiving webhooks, but sending them to your own consumers. Before writing code, you capture the requirements.

Claude Code — payment-service
Write a PRD for webhook delivery to our consumers. We need to send events when payments succeed, fail, or get refunded. Retry logic with backoff. Idempotency so consumers can safely receive the same event twice.
Before I draft this, a few questions to ground the requirements in your project:
1. Delivery target — are consumers external HTTP endpoints (like Stripe's model) or internal services via a message queue?
2. Retry budget — how many attempts before marking delivery failed? And what's the max delay you'd accept between first failure and final attempt?
3. Idempotency scope — should idempotency be per-consumer (same event delivered to consumer A twice is deduplicated) or global (same event ID is never processed twice, period)?
4. Ordering — do consumers need events in order (payment_intent.succeeded always after payment_intent.created) or is out-of-order acceptable with idempotency handling it?
5. I see your existing PaymentEventHandler port in the domain layer. Should webhook delivery extend this port or be a separate bounded context?

Notice question 5. Claude read your codebase. It found the existing port and asked whether to extend it or create something new. It's not generating from a template — it's grounding the requirements in what already exists.

Claude Code — payment-service
External HTTP endpoints, like Stripe's model. 5 retries max, exponential backoff with jitter, max delay 4 hours. Idempotency per-consumer. Out-of-order is fine. Separate bounded context — delivery is its own domain.
Got it. Drafting now.
PRD-003: Webhook Delivery System
Status: draft
Domain: Webhook Delivery (new bounded context)
Problem:
Consumers of our payment platform have no way to receive real-time notifications when payment events occur. They must poll the API, which increases latency and load.
Solution:
HTTP webhook delivery system. Consumers register endpoints. The platform delivers events with retry logic and idempotency guarantees.
Acceptance Criteria:
1. Deliver payment_intent.succeeded, payment_intent.payment_failed, charge.refunded events to registered consumer endpoints
2. Retry failed deliveries: exponential backoff with jitter, 5 attempts max, 4-hour ceiling
3. Per-consumer idempotency: same event + same consumer = deduplicated (consumer receives it at most once after success)
4. Delivery status tracking: pending → delivering → delivered / failed
5. Consumer endpoint registration via API
6. Signature verification so consumers can authenticate the source
7. Separate bounded context from payment processing
Saved: docs/product/prds/PRD-003-webhook-delivery.md
Review and tell me what to change, or accept it and we'll move to the spec.
Accept it.
PRD-003 accepted. Ready for spec when you are.

The requirements survive context compaction. They're in docs/product/prds/. Tomorrow's session can reference them without you re-explaining what you're building.

Command reference: /edikt:prd


4. Spec interview — Claude asks codebase-aware questions

Claude Code — payment-service
Write a spec for PRD-003
Routing to architect for spec generation.
Before I write the spec, I've scanned your codebase and have questions:
1. Your existing migrations use goose with sequential numbering. I'll follow that convention for the delivery tables. Any reason to change?
2. I see you're using pgx for database access in the infrastructure layer. The delivery system will need a transactional outbox to guarantee event delivery — should I use pgx transactions for the outbox pattern, or do you want a separate approach?
3. ADR-001 established typed errors with context wrapping. For delivery failures, I'll create DeliveryError with cause chaining (network timeout, HTTP 5xx, signature mismatch). That consistent with your intent?
4. Your Chi middleware stack includes request ID propagation. Should delivery attempts carry the originating request ID for traceability, or generate their own?
5. Testing: your existing test setup uses testcontainers-go for PostgreSQL integration tests. I'll follow that for delivery tests. Confirm?

Every question references something real in your codebase. The migration tool. The database driver. An existing ADR. The middleware stack. The test setup. Claude isn't guessing — it read the project before asking.

Claude Code — payment-service
Yes to all. Use pgx transactions for the outbox. Delivery attempts should carry the originating request ID.
Spec generated.
SPEC-003: Webhook Delivery System
Source PRD: PRD-003
Status: draft
References: ADR-001 (error handling), ADR-002 (database conventions)
Architecture:
New bounded context: delivery/
Domain: DeliveryEvent, ConsumerEndpoint, DeliveryAttempt
Application: ScheduleDeliveryUseCase, RetryDeliveryUseCase
Infrastructure: HTTPDeliverer, PostgresOutbox, ConsumerRepository
Key decisions:
- Transactional outbox pattern via pgx — events written to outbox table in same transaction as domain events
- Exponential backoff: base 30s, factor 2, jitter ±20%, cap 4h
- Per-consumer idempotency via (event_id, consumer_id) unique constraint
- HMAC-SHA256 signatures using per-consumer secrets
Database:
3 tables: consumer_endpoints, delivery_outbox, delivery_attempts
Migrations: goose sequential, following existing convention
Saved: docs/product/specs/SPEC-003-webhook-delivery/spec.md
Review it. I'll generate artifacts once you accept.
Accept.
SPEC-003 accepted.

Command reference: /edikt:spec PRD-003


5. Pre-flight review — specialist agents catch what you'd miss

Claude Code — payment-service
Create a plan for SPEC-003
Breaking SPEC-003 into implementation phases.
PLAN-003: Webhook Delivery System
Phase 1: Domain layer — entities, value objects, ports
Phase 2: Database — migrations, outbox table, repositories
Phase 3: Application layer — use cases, retry scheduling
Phase 4: Infrastructure — HTTP deliverer, signature generation
Phase 5: API — consumer registration endpoints, Chi handlers
Phase 6: Integration tests
Running pre-flight review with specialist agents...
PRE-FLIGHT REVIEW
DBA
CRITICAL Migration 007_create_delivery_outbox has no DOWN migration — add rollback before executing
WARNING No index on delivery_outbox.status — queried in every retry poll cycle, will degrade at volume
WARNING delivery_attempts.created_at missing — needed for backoff calculation
SECURITY
WARNING Consumer webhook secrets must be generated server-side with crypto/rand, not accepted as user input
PASS HMAC-SHA256 signature scheme is sound
API
PASS Consumer registration endpoint contract is stable
INFO Consider pagination on GET /consumers/{id}/deliveries — could return thousands of rows
QA
WARNING No test case for jitter bounds — backoff with jitter should be tested for min/max range
SRE
INFO Consider circuit breaker for consumer endpoints that fail repeatedly — avoid retry storms
3 findings require attention before execution.
Fix now, or proceed with known gaps?

The DBA caught the missing rollback migration. The security agent caught a secret generation issue. The QA agent caught a missing test case. These are the things you'd catch in code review — except they were caught before a single line was written.

Claude Code — payment-service
Fix the migration rollback, add the index, add the created_at column, and generate secrets server-side. The rest I'll address during implementation.
Updated. Plan ready for execution.
Phase 1 is active. Start when ready.

Five minutes to catch a migration without a rollback. After implementation, that's an hour of work and a risky production deploy.

Command reference: /edikt:plan SPEC-003


6. The drift check — does the implementation match what was decided?

Three days later. All six phases are complete. The webhook delivery system is built. Before you open a PR, you verify.

Claude Code — payment-service
Does the implementation match the spec for SPEC-003?
Running drift detection against the full governance chain.
Comparing: PRD-003 → SPEC-003 → artifacts → implementation
DRIFT REPORT — SPEC-003
SUMMARY
14 compliant 2 likely compliant
1 diverged 0 unknown
PRD ACCEPTANCE CRITERIA
[compliant] Deliver payment events to registered endpoints
[compliant] Retry with exponential backoff, 5 attempts, 4h cap
[compliant] Per-consumer idempotency
[compliant] Delivery status tracking
[compliant] Consumer endpoint registration
[compliant] Signature verification
SPEC REQUIREMENTS
[compliant] Transactional outbox with pgx
[compliant] HMAC-SHA256 signatures
[compliant] Goose sequential migrations with rollbacks
[compliant] Typed errors with context wrapping (per ADR-001)
[diverged] Retry backoff — spec requires jitter
expected: exponential backoff with jitter, +/-20% (spec 3.2)
found: fixed exponential backoff, no jitter
file: delivery/infrastructure/retry_scheduler.go:47
action: Add jitter to calculateBackoff()
ADR COMPLIANCE
[compliant] ADR-001: typed errors with context wrapping
[compliant] ADR-002: database conventions followed
INVARIANT COMPLIANCE
[compliant] All invariants respected
1 divergence. 1 action required.

One divergence. The retry scheduler uses exponential backoff but forgot the jitter. The spec said jitter. The implementation doesn't have it. File path, line number, clear action.

Claude Code — payment-service
Fix the jitter.
Updated delivery/infrastructure/retry_scheduler.go — added +/-20% jitter to calculateBackoff() using crypto/rand for uniform distribution.
Re-running drift check...
DRIFT REPORT — SPEC-003
SUMMARY
15 compliant 2 likely compliant
0 diverged 0 unknown
Full compliance. Implementation matches the governance chain.

Zero drift. What was decided is what got built.

Command reference: /edikt:drift SPEC-003


7. Decision capture — governance that compiles itself

During implementation, you made a choice: transactional outbox over event-driven messaging. Claude's Stop hook noticed.

Claude Code — payment-service
Decision signal detected:
You chose transactional outbox pattern over event-driven messaging (Kafka/NATS) for webhook delivery reliability.
Rationale detected:
- Eliminates message broker dependency
- Guarantees delivery atomicity with domain writes
- Simpler operational model for current scale
Save this as an ADR? (y/n)
Yes.
ADR-003: Transactional Outbox for Webhook Delivery
Status: accepted
Saved: docs/architecture/decisions/ADR-003-transactional-outbox.md
Compile governance.
Reading all accepted ADRs and active invariants...
Governance compiled: .claude/rules/governance.md
3 ADRs -> 4 directives
1 invariant -> 1 directive
5 total directives
Directives:
1. Use typed errors with context wrapping (ADR-001)
2. Follow goose sequential migration conventions (ADR-002)
3. Use transactional outbox for async event delivery (ADR-003)
4. Hexagonal architecture: no domain imports from infrastructure (ADR-001)
5. All database schema changes require DOWN migrations (INV-001)
Claude will follow these directives automatically in every session.

The decision you made today is now enforcement tomorrow. Not a doc someone might read. A directive Claude loads automatically, every session, before writing code.

Command references: /edikt:adr, /edikt:compile


8. Next session — Claude already knows everything

Thursday morning. New session. You haven't opened this project since Tuesday.

Claude Code — payment-service
[SessionStart] Loading project context...
Payment Processing Service — Go + Chi + PostgreSQL
Last session: Tue Mar 18 — completed webhook delivery system
Active governance:
7 rules, 7 agents, 5 compiled directives
3 ADRs (error handling, DB conventions, transactional outbox)
1 invariant (migration rollbacks required)
Governance chain:
PRD-003 accepted -> SPEC-003 accepted -> implemented (0 drift)
No active plan. What would you like to work on?
I need to add a dead letter queue for webhook deliveries that exhaust all retries.
Good addition. A few things I'll account for based on your existing governance:
- ADR-003 established the transactional outbox pattern — the DLQ will be a table in the same database, not a separate message broker
- Per your error-handling rules, failed deliveries will use typed errors (DeliveryExhaustedError) with the full attempt history
- Migration will include a DOWN migration per INV-001
Want me to write a PRD for this, or is it small enough to go straight to implementation?

Claude referenced ADR-003 (which you captured two days ago), your error handling rules, and your migration invariant. Without being asked. Without being reminded. The governance is working.

This is the compound effect. The first session after /edikt:init is better. The tenth session is substantially better. Each ADR compounds into enforcement. Each spec becomes a drift detection baseline. Each decision you capture makes the next session smarter.

A hand-maintained CLAUDE.md decays the moment you forget to update it. edikt's governance accumulates. You still make every call. edikt makes sure Claude remembers them.

Command reference: /edikt:status

Released under the Elastic License 2.0. Free to use, not for resale.