Claude Code in Production: How to Keep Long Runs Stable


- Premium Results
- Publish articles on SitePoint
- Daily curated jobs
- Learning Paths
- Discounts to dev tools
7 Day Free Trial. Cancel Anytime.
Claude Code handles short, well-scoped tasks reliably. But sessions that stretch beyond roughly 30 minutes, touch 20 or more files, or require sustained reasoning across multiple implementation phases introduce a fundamentally different failure profile. This tutorial delivers a repeatable production workflow built from concrete artifacts: CLAUDE.md configurations, phase-gated prompt templates, git checkpoint strategies, and recovery patterns.
How to Keep Long Claude Code Runs Stable
- Decompose your task into bounded phases with explicit entry criteria, exit criteria, and deliverables.
- Configure a CLAUDE.md file with project architecture, coding conventions, and hard constraints.
- Front-load constraints at the top of every prompt so they survive context compaction.
- Gate each phase with a verification step that forces Claude to restate its plan before writing code.
- Commit to git at every phase boundary so you always have a clean rollback target.
- Monitor for context degradation signals such as repeated file reads or contradicted decisions.
- Restart the session when Claude loses more than one requirement or loops without progress.
- Review all diffs against the merge base and run the full test suite before merging.
Table of Contents
- Why Long-Running Claude Code Sessions Break
- How Claude Code Manages Context (and Where It Falls Apart)
- The Checkpoint Workflow: Structuring Long Runs for Stability
- CLAUDE.md: Your Most Important Production File
- Prompt Hygiene: Writing Instructions That Survive Long Contexts
- Failure Recovery: What to Do When Things Go Wrong
- The Production Stability Checklist
- Putting It All Together: A Sample Production Run
- No Magic Flag Exists
Note: This article was written against a specific version of Claude Code. Behavior around context management, CLAUDE.md resolution, and session commands changes between versions. Verify against the current documentation before relying on version-dependent features.
Why Long-Running Claude Code Sessions Break
Claude Code handles short, well-scoped tasks reliably. Ask it to write a utility function, fix a type error, or scaffold a test file, and the results come back correct without intervention. But sessions that stretch beyond roughly 30 minutes, touch 20 or more files, or require sustained reasoning across multiple implementation phases introduce a fundamentally different failure profile. These thresholds are rough guidelines from my testing, not hard limits. Developers attempting to use Claude Code for production-scale work need strategies that address three distinct breakdown modes: context window exhaustion, goal drift, and compounding errors.
The context window fills up mechanically. Every tool call, file read, command output, and conversation turn eats into a finite token budget. Goal drift works differently: Claude Code gradually shifts its understanding of the task as older instructions fade from effective working memory. Compounding errors do the most damage. A small misunderstanding in phase one becomes a structural problem by phase three, and by the time it surfaces, the cost of correction is high.
This tutorial delivers a repeatable production workflow built from concrete artifacts: CLAUDE.md configurations, phase-gated prompt templates, git checkpoint strategies, and recovery patterns. The target audience is intermediate developers already comfortable with Claude Code who want to scale their usage to non-trivial, multi-file tasks without spending half their time debugging the AI's output.
How Claude Code Manages Context (and Where It Falls Apart)
The Context Window Is a Leaky Bucket
Claude Code operates in an agentic mode where the model does far more than process a single prompt and return a single response. Each action it takes, whether reading a file, executing a shell command, writing to disk, or calling a tool, generates output that occupies space in the context window. The conversation context (what was said between the developer and Claude) competes for space with working memory (the accumulated state from tool calls, file contents, and command results).
When the context window approaches capacity, Claude Code performs auto-compaction. It may summarize or deprioritize older parts of the conversation to make room for new interactions. I observed this behavior empirically; Anthropic does not document the internal mechanism, and the exact strategy may change across versions. The practical result is silent information loss: auto-compaction may compress a constraint from message three into a vague summary or drop it entirely by message forty. The model does not flag this. As of the version tested, it does not warn that it has lost access to earlier instructions. It simply proceeds with whatever information remains in its effective context, which may or may not include the developer's critical requirements.
The practical result is silent information loss: auto-compaction may compress a constraint from message three into a vague summary or drop it entirely by message forty.
Recognizing the Warning Signs of Context Degradation
Context degradation follows observable patterns. Developers who learn to spot these symptoms can intervene before the session produces unusable output:
- Repeated file reads: Claude Code re-opens files it already read earlier in the session, because the contents have been compacted out of context.
- An architectural choice made in phase one gets reversed in phase three without acknowledgment. This is contradicting earlier decisions, and it usually means the original reasoning has fallen out of working memory.
- Forgetting stated requirements: Task constraints from the initial prompt no longer influence Claude's behavior.
- Claude enters cycles of re-examining the same code without making progress, often narrating "Let me check that again" while producing no new output.
Here is what repeated file reads look like in practice:
> Read file: src/middleware/auth.ts
> ...processing...
> Read file: src/routes/users.ts
> ...modifying users.ts...
> Read file: src/middleware/auth.ts
> ...processing...
> Read file: src/middleware/auth.ts
> ...processing...
> "Let me verify the auth middleware signature again..."
> Read file: src/middleware/auth.ts
When Claude Code reads the same file three or more times within a short span, it has likely lost that file's contents from working memory. This is a useful heuristic signal, not a mechanical certainty, that the session is degrading.
The Checkpoint Workflow: Structuring Long Runs for Stability
Break Work into Bounded Phases
The most effective countermeasure against context degradation is keeping each phase small enough that the context does not approach its limit before reaching the phase exit criteria. In my testing, phases that complete in roughly 10 to 15 minutes of wall-clock time work as a starting heuristic, though the right size depends on how file-heavy the phase is. Phases exceeding that range on file-heavy tasks started showing repeated-read symptoms. This means decomposing large tasks into discrete phases, each with explicit entry criteria, exit criteria, and deliverables. This is the "phase-gate" pattern.
At the start of a session, paste a phase plan directly into Claude Code. The plan should be specific enough that each phase could be completed independently:
## Phase Plan: Add Authentication to Express API
### Phase 1: Install Dependencies and Configure JWT
- Entry: Clean main branch, no auth code exists
- Tasks: Install jsonwebtoken, bcryptjs, and @types packages (verify whether @types packages are needed — jsonwebtoken ≥9.0.0 bundles its own types). Create src/config/auth.ts with JWT secret loading from env vars (fail loudly if the env var is missing).
- Exit: Dependencies in package.json, auth config file created, app compiles cleanly.
- Commit message: "feat(auth): add JWT dependencies and auth config"
### Phase 2: Create User Model and Registration Endpoint
- Entry: Phase 1 committed
- Tasks: Create src/models/User.ts with email/password fields. Add POST /api/auth/register in src/routes/auth.ts. Hash passwords with bcryptjs before storage.
- Exit: Registration endpoint returns 201 with user object (no password). Existing routes unaffected.
- Commit message: "feat(auth): add User model and registration endpoint"
### Phase 3: Implement Login and Token Issuance
- Entry: Phase 2 committed
- Tasks: Add POST /api/auth/login. Validate credentials against stored hash. Return signed JWT with 24h expiry. (Note: for production systems, pair long-lived access tokens with refresh token rotation and a revocation mechanism.)
- Exit: Login returns 200 with token for valid credentials, 401 for invalid. Token contains userId and email claims.
- Commit message: "feat(auth): implement login and JWT issuance"
### Phase 4: Add Auth Middleware and Protect Routes
- Entry: Phase 3 committed
- Tasks: Create src/middleware/requireAuth.ts that verifies JWT from Authorization header. Apply to all /api/users routes.
- Exit: Protected routes return 401 without valid token, 200 with valid token. Public routes unchanged.
- Commit message: "feat(auth): add auth middleware and protect user routes"
### Phase 5: Integration Tests
- Entry: Phase 4 committed
- Tasks: Write tests for register, login, protected access, and rejected access in tests/auth.test.ts.
- Exit: All tests pass. No existing tests broken.
- Commit message: "test(auth): add authentication integration tests"
These commit messages follow the Conventional Commits specification.
The specificity matters. "Add authentication" is a task description. The phase plan above is a contract that Claude Code can execute against and that the developer can verify at each boundary.
Use Git as Your Safety Net
Every phase boundary should produce a git commit. Not at the end of the session. Not when things "feel done." After every single phase.
# Before starting, create a feature branch
git checkout -b feat/add-auth
# After completing Phase 1, instruct Claude Code:
Prompt to Claude Code after Phase 1 completes:
Phase 1 is complete. Before moving to Phase 2:
1. Run `npm run build` to verify compilation
2. Run `git status` so I can review what has changed
3. Wait for my approval before staging or committing
After reviewing the output of git status, selectively stage the intended files. Do not proceed to the commit prompt until you have confirmed no unintended files are staged. Use git restore --staged <file> to unstage any files outside scope:
Stage only the files listed in Phase 1's scope, then commit with message "feat(auth): add JWT dependencies and auth config" and show me the output of `git log --oneline -1` to confirm.
This workflow gives the developer a verification point at every boundary. If Phase 3 goes wrong, the rollback target is a clean Phase 2 commit, not an unknown state.
When to Kill a Session and Start Fresh
Two criteria justify terminating a session rather than attempting repair:
- Claude has lost track of more than one requirement from the original phase plan.
- Claude has looped on the same problem for three or more attempts without progress.
To carry context into a new session efficiently, copy the phase plan into the new session with completed phases marked as done, and add a one-paragraph summary of the current state:
Phases 1-3 are complete and committed. Starting fresh for Phase 4.
Current state: User model, registration, and login endpoints are working.
The JWT token includes userId and email claims with 24h expiry.
Branch: feat/add-auth, latest commit: a3f7b2d (replace with the actual output of `git log --oneline -1`).
Proceed with Phase 4 as defined in the plan.
This gives the new session a clean context window with all the information it needs and none of the accumulated noise from the previous session.
CLAUDE.md: Your Most Important Production File
What Belongs in CLAUDE.md
CLAUDE.md is the persistent memory that survives across sessions. Claude Code reads it automatically at session start, making it the single most important file for production stability. It should contain project architecture (concise, not exhaustive), coding conventions you actually enforce, critical file paths, and explicit anti-patterns:
# CLAUDE.md
## Project Overview
Express API with PostgreSQL. TypeScript strict mode. Node 20.
Monolith structure, migrating toward modular services.
## Architecture
- src/routes/ — Route handlers, thin layer, delegate to services
- src/services/ — Business logic, one file per domain entity
- src/models/ — Sequelize models, no raw SQL outside migrations
- src/middleware/ — Express middleware, each file exports one function
- tests/ — Jest integration tests, mirror src/ structure
## Coding Conventions
- All functions must have explicit return types (no inferred returns)
- Use named exports, never default exports
- Error handling: throw AppError from src/utils/errors.ts, never raw Error
- Async routes must be wrapped with asyncHandler middleware (see src/middleware/asyncHandler.ts or a library such as `express-async-errors`)
- Database access only through model methods, never direct queries in routes
## Constraints
- NEVER modify src/config/database.ts — managed by platform team
- NEVER add dependencies without listing them in the commit message
- Always run `npm run lint && npm run test` before suggesting a commit
- Use existing patterns in adjacent files as templates for new code
## Current Task Context
<!-- DO NOT POPULATE — inject via session prompt only -->
Each line serves a purpose. The architecture section prevents Claude from misplacing files. Conventions prevent style drift. Constraints block dangerous modifications. The task context section signals that per-task instructions belong in prompts, not here, and uses a comment to prevent stale entries from a previous session becoming conflicting constraints.
What Does NOT Belong in CLAUDE.md
Three categories of content actively harm CLAUDE.md effectiveness:
- Verbose documentation dumps waste context tokens on information Claude may never need. Pasting an entire API reference into CLAUDE.md is the fastest way to crowd out the constraints that actually matter.
- "Write clean code" or "Follow SOLID principles" is too vague to constrain behavior. These generic style guides give Claude permission to do almost anything. Specify the concrete pattern instead.
- Per-task information changes constantly. Embedding current requirements in CLAUDE.md means the file needs constant editing and risks stale instructions conflicting with fresh prompts.
Layering CLAUDE.md Files for Monorepos
Claude Code resolves CLAUDE.md files hierarchically. A root-level file applies to the entire project. Subdirectory files add to the instructions for specific packages. (Verify the exact merge behavior in the current Claude Code documentation, as the resolution order may change between versions.)
my-monorepo/
├── CLAUDE.md # Root: shared conventions
├── packages/
│ ├── api/
│ │ ├── CLAUDE.md # API-specific: "Use Express patterns.
│ │ │ # All routes must use asyncHandler.
│ │ │ # Test with supertest."
│ │ └── src/
│ ├── web/
│ │ ├── CLAUDE.md # Web-specific: "React 18 with TypeScript.
│ │ │ # Use function components only.
│ │ │ # State management via Zustand.
│ │ │ # Never use CSS-in-JS, use CSS modules."
│ │ └── src/
│ └── shared/
│ ├── CLAUDE.md # Shared: "This package has zero runtime
│ │ # dependencies. All exports must be
│ │ # tree-shakeable. No side effects."
│ └── src/
The root CLAUDE.md holds conventions that apply everywhere (TypeScript strict mode, named exports, error handling patterns). Each package-level file holds constraints specific to that package's technology and boundaries. This prevents the API package's Express conventions from polluting the web package's React context.
Prompt Hygiene: Writing Instructions That Survive Long Contexts
Front-Load Constraints, Back-Load Details
Claude follows constraints at the beginning of a prompt more reliably than those buried in the middle. This is a widely observed heuristic in prompt engineering, not a guaranteed behavior. Structure every prompt accordingly: constraints first, then the goal, then implementation details, then acceptance criteria.
Keep prompts as concise as possible. Longer prompts increase the chance that mid-prompt details get deprioritized. Prefer multiple focused prompts over one long prompt. Structured multi-part prompts (like the phase prompts in this article) may naturally be longer, and that is fine as long as constraints are front-loaded.
Poorly structured prompt:
I need you to refactor the user service. The getUserById function is getting
pretty long and does too many things. It handles caching, database queries,
and permission checks all in one function. Maybe break it into smaller pieces.
Oh, and make sure you don't change the function signature because other parts
of the codebase depend on it. Also keep the existing tests passing.
Well-structured prompt:
CONSTRAINTS: Do not change the getUserById function signature. All existing
tests in tests/services/user.test.ts must continue to pass.
GOAL: Extract getUserById in src/services/userService.ts into three private
functions: checkUserPermissions, fetchUserFromCache, fetchUserFromDb.
DETAILS: getUserById should orchestrate the three extracted functions. Cache
check first, then DB fallback, permission check wraps both.
VERIFY BEFORE EXECUTING: Confirm you understand the three function names and
that the public signature remains unchanged.
The revised version puts the unbreakable constraints first, where they receive maximum attention. The verification step at the end catches misunderstandings before any files are modified.
Use Explicit Verification Steps
Every phase prompt should end with a verification gate. This forces Claude Code to pause and restate its understanding before executing, giving the developer a chance to catch misinterpretation:
## Phase 3: Implement Rate Limiting Middleware
CONSTRAINTS:
- Do not modify any existing middleware files
- Rate limit config must be loaded from environment variables
- Use the existing AppError class for limit-exceeded responses
TASK: Create src/middleware/rateLimit.ts that applies per-IP rate limiting
using a sliding window. Apply it to all routes under /api/ in src/app.ts.
ACCEPTANCE CRITERIA:
- Requests exceeding RATE_LIMIT_MAX (default: 100) per RATE_LIMIT_WINDOW_MS
(e.g., 900000 for a 15-minute window) receive a 429 response with an AppError
- X-RateLimit-Remaining and X-RateLimit-Reset headers are set on every response
- X-RateLimit-Reset must be a Unix epoch timestamp in seconds (not milliseconds)
- Environment variables must be parsed to integers at startup with validation;
invalid or missing values must fail loudly rather than silently disabling limits
- Rate limit state is stored in-memory for now (Note: in-memory state means rate
limits are not shared across multiple server instances. This is suitable for
single-instance development only. Redis integration is Phase 5.)
BEFORE WRITING ANY CODE:
1. List the files you will create or modify
2. Confirm you will NOT modify existing middleware files
3. State how you will read RATE_LIMIT_MAX and RATE_LIMIT_WINDOW_MS
4. Wait for my approval
The "BEFORE WRITING ANY CODE" block is the gate. It transforms Claude Code from an autonomous agent into a plan-then-execute workflow, which produces more predictable output for production work.
The "BEFORE WRITING ANY CODE" block is the gate. It transforms Claude Code from an autonomous agent into a plan-then-execute workflow, which produces more predictable output for production work.
Avoid Open-Ended Instructions in Production Runs
In practice, specificity needs to increase as the session lengthens. Early in a session, Claude can tolerate moderate ambiguity. Deep into a long session, with compacted context and accumulated state, every instruction must be precise.
"Improve the error handling" is an invitation to goal drift. "Replace the try/catch in createOrder (src/services/orderService.ts, line 47) with the asyncHandler wrapper and throw an AppError with code ORDER_CREATION_FAILED instead of logging and returning null" is an instruction that produces predictable output regardless of context state.
Failure Recovery: What to Do When Things Go Wrong
Recovering from a Botched File Edit
When Claude Code makes an incorrect edit, assess the damage before attempting repair:
# See exactly what changed (staged + unstaged) against last commit
git diff HEAD -- src/services/userService.ts
# If multiple files were affected, see the full scope
git diff --stat HEAD
Then use the diff itself as input for a surgical recovery prompt:
The last edit to src/services/userService.ts introduced a regression.
Here is the diff:
[paste the relevant git diff output]
The problem: you removed the null check on line 23 that guards against
missing user records. The cache lookup changes are correct and should
be kept.
Fix ONLY the null check regression. Do not re-modify the cache logic.
This pattern, showing Claude the specific diff and constraining the fix scope, prevents the common failure mode where a "fix" attempt introduces new regressions because Claude re-implements its entire previous change from degraded context.
Recovering from Goal Drift
Goal drift manifests as Claude building something plausible but wrong. The outputs look reasonable in isolation but do not match the original specification. The recovery pattern is direct:
We've drifted from the original requirements. Here is the original spec:
[paste the original phase plan or requirements]
Compare the current implementation against this spec. List each requirement
and whether it is met, partially met, or missing. Do not make any changes
yet — just produce the gap analysis.
The gap analysis forces Claude to re-anchor against the original requirements without the risk of further drift from an immediate fix attempt. If the analysis reveals drift across multiple requirements, starting a new session from the last clean checkpoint is more efficient than attempting in-session repair.
Handling Hung or Stalled Sessions
Claude Code occasionally stalls, spinning on tool calls without producing meaningful progress. Ctrl+C will interrupt the current operation. Verify file state with git status immediately afterward, as an interrupted write may leave files half-written. Escape cancels the current generation. If neither responds, a hard kill of the terminal process is safe for your committed code, but run git status and inspect all modified files before proceeding, as in-progress writes may be incomplete.
Check current Claude Code documentation for session continuation options, as available commands and their behavior vary by version. Treat any resumed session as a new session and re-paste the phase plan with current state.
The Production Stability Checklist
Save this checklist as claude-stability-checklist.md in the project root and reference it before every non-trivial Claude Code session:
# Claude Code Production Stability Checklist
## Pre-Session
- [ ] CLAUDE.md is up-to-date and reviewed for accuracy
- [ ] Phase plan is written with entry/exit criteria for each phase
- [ ] Feature branch is created from latest main
- [ ] Constraints are defined (files not to modify, patterns to follow)
- [ ] Success criteria are stated for the overall task
- [ ] Tests exist or are planned for verifying each phase output
## Mid-Session
- [ ] Committing after every completed phase
- [ ] Watching for repeated file reads (context degradation signal)
- [ ] Verifying Claude's understanding at each phase gate before execution
- [ ] Keeping prompts concise and front-loading constraints
- [ ] Monitoring for goal drift (outputs diverging from phase plan)
- [ ] Using explicit "stop and ask me" triggers for ambiguous decisions
- [ ] Re-pasting requirements if any context degradation symptoms appear
- [ ] Running tests after each phase, not just at the end
## Post-Session
- [ ] Review all diffs with `git diff $(git merge-base main HEAD)..HEAD` for unintended changes
- [ ] Full test suite passes
- [ ] No modifications outside the intended scope (check with `git diff --stat $(git merge-base main HEAD)..HEAD`)
- [ ] Update CLAUDE.md with any lessons learned or new constraints discovered
Putting It All Together: A Sample Production Run
The following constructed transcript illustrates the workflow applied to adding rate limiting to an existing Node.js Express API. Actual Claude Code responses will differ in phrasing; the structure, verification gates, and commit pattern are the reproducible elements.
# Terminal Session
$ git checkout -b feat/rate-limiting
Switched to a new branch 'feat/rate-limiting'
$ claude
> CLAUDE.md is loaded. Starting session.
USER: Here is the phase plan for this session:
Phase 1: Create rate limit middleware with in-memory sliding window store
Phase 2: Apply middleware to /api routes and add response headers
Phase 3: Add integration tests for rate limiting behavior
Constraints: Do not modify existing middleware files. Use AppError from
src/utils/errors.ts for 429 responses. Config from environment variables
RATE_LIMIT_MAX and RATE_LIMIT_WINDOW_MS. Both must be parsed as integers
at startup with validation — invalid values must throw at module load.
Begin with Phase 1. Before writing code, list the files you will create
and confirm you understand the sliding window approach.
CLAUDE: I will create one file: src/middleware/rateLimit.ts
The sliding window approach: I'll track request timestamps per IP in a Map.
On each request, I'll filter out timestamps older than RATE_LIMIT_WINDOW_MS
and count remaining entries. If count exceeds RATE_LIMIT_MAX, I'll call
next(new AppError('Rate limit exceeded', 429)). Environment variables will
be parsed to integers with parseInt() at module load, with validation that
throws if the values are NaN or non-positive. I will NOT modify any existing
middleware files.
Shall I proceed?
USER: Proceed.
CLAUDE: [creates src/middleware/rateLimit.ts]
[runs npm run build — success]
USER: Good. Run `git status` so I can review what changed, then stage only
the files in Phase 1's scope.
CLAUDE: [runs git status]
USER: Looks correct. Commit with message "feat(rate-limit): add sliding window middleware"
CLAUDE: [runs git add src/middleware/rateLimit.ts && git commit -m "feat(rate-limit): add sliding window middleware"]
[runs git log --oneline -1]
Committed: a4b9c1e
USER: Phase 2. Apply the middleware to /api routes in src/app.ts and add
X-RateLimit-Remaining and X-RateLimit-Reset headers to all responses.
X-RateLimit-Reset must be a Unix epoch timestamp in seconds, not milliseconds.
Before writing code, confirm which file you will modify and that you will
only add the middleware import and app.use() call.
CLAUDE: I will modify only src/app.ts. I'll add the import for rateLimit
and add app.use('/api', rateLimit()) before the existing route registrations.
The headers will be set inside rateLimit.ts itself, not in app.ts.
Wait — I need to go back and add the header logic to rateLimit.ts as well.
I'll modify src/middleware/rateLimit.ts to set the headers, and src/app.ts
to mount the middleware.
USER: Correct, the headers should be in the middleware itself. That modification
to rateLimit.ts is within scope. Proceed.
CLAUDE: [modifies src/middleware/rateLimit.ts — adds header logic]
[modifies src/app.ts — adds import and app.use()]
[runs npm run build — success]
[runs npm run test — all existing tests pass]
USER: Commit: "feat(rate-limit): apply to /api routes with response headers"
CLAUDE: [runs git add src/middleware/rateLimit.ts src/app.ts]
[runs git status] # verify exactly two files staged
[runs git commit -m "feat(rate-limit): apply to /api routes with response headers"]
[runs git log --oneline -1]
Committed: b7d2e3f
USER: Phase 3. Write integration tests in tests/middleware/rateLimit.test.ts.
Test three scenarios: request under limit returns 200 with correct headers,
request at limit returns 429, and window reset allows new requests.
CLAUDE: [creates tests/middleware/rateLimit.test.ts]
[runs npm run test — all tests pass including new ones]
USER: Commit: "test(rate-limit): add integration tests"
CLAUDE: [runs git add tests/middleware/rateLimit.test.ts]
[runs git commit -m "test(rate-limit): add integration tests"]
[runs git log --oneline -1]
Committed: c9f1a4d
$ git log --oneline $(git merge-base main HEAD)..HEAD
c9f1a4d test(rate-limit): add integration tests
b7d2e3f feat(rate-limit): apply to /api routes with response headers
a4b9c1e feat(rate-limit): add sliding window middleware
Note the mid-session catch during Phase 2: Claude initially planned to modify only app.ts but then recognized that the header logic belonged in the middleware file. The verification gate (asking Claude to confirm its plan before executing) surfaced this before any code was written, avoiding a potential correction cycle.
No Magic Flag Exists
There is no configuration option that makes Claude Code reliable for long production runs. Stability comes from workflow discipline: phase-gated task decomposition, git checkpoints at every boundary, a well-maintained CLAUDE.md, prompt structures that resist context decay, and recognizing degradation early. Start with CLAUDE.md and the checkpoint workflow on the next non-trivial task. The checklist above encodes these patterns into a repeatable process.
SitePoint TeamSharing our passion for building incredible internet things.