Claude Code is most powerful when you build deliberate workflow habits around it — not just asking ad-hoc questions, but structuring every feature, bug fix, and refactor as a repeatable loop. This guide covers the patterns that work best in practice: from daily routines to TDD, git branching, PR review, and CI/CD integration.
The core loop: Plan → Build → Test → Commit. Four steps, repeated. The plan step prevents wasted work. The test step catches regressions. The commit step creates a clean recovery point.
How you open a session determines how effective the whole session will be. Don't just run claude and start typing — prime it first.
cd ~/projects/my-app. Claude reads CLAUDE.md, .git/, and the directory structure automatically.git status and git log --oneline -5. Mention the current branch and your intent in your first message./plan to see Claude's proposed approach before any file is written.I'm working on [branch name].
Goal for this session: [one sentence].
Constraints:
- Don't modify [protected files/directories]
- Tests are in [test directory], run with [test command]
- [Any other context from CLAUDE.md]
First task: [specific task]
TDD with Claude Code is one of the highest-leverage patterns. You write the spec (the test), Claude writes the implementation, and you never merge code that doesn't have a corresponding test.
Write failing tests for a function called parseInvoiceDate(str).
Requirements:
- Parses strings in ISO 8601, US (MM/DD/YYYY), and EU (DD.MM.YYYY) formats
- Returns a Date object
- Throws InvalidDateError for invalid inputs
- Edge cases: empty string, null, Feb 29 on non-leap years
Use Jest. Do NOT write the implementation yet.
Now implement parseInvoiceDate() in src/utils/dates.ts to pass all the tests you just wrote.
Minimum code to pass — no extra features.
Run the tests and iterate until all pass.
The tests are green. Now refactor parseInvoiceDate() for readability:
- Extract the format detection into a private detectFormat() helper
- Replace the nested if-else with a format lookup table
Tests must stay green throughout.
TDD rule: Never ask Claude to implement and write tests in the same message. The test must be red first, then you ask for the implementation. This keeps Claude honest about what the code actually does.
Claude Code works best when you treat git as a first-class part of the workflow — not an afterthought at the end of the session.
# Before starting any task
git checkout -b feat/my-feature
# After Claude builds, review the diff
git diff
# Ask Claude for a conventional commit message
Write a conventional commit message for these staged changes.
Use the format: type(scope): description
Types: feat, fix, refactor, test, docs, chore
Commit frequently — after each logical unit completes, not at end of day. Ask Claude to identify commit boundaries:
We've made several changes. Group them into logical commits:
1. List each commit with: which files, what type (feat/fix/refactor), suggested message
2. Stage and commit each group in order
/pr
# or manually:
Write a PR description for this branch vs main.
Include: summary of changes, motivation, testing approach, and any breaking changes.
Format as markdown with sections.
Effective bug fixing with Claude Code follows a strict sequence: reproduce → isolate → fix → verify → document.
Paste the exact error + stack trace. Ask Claude to write a minimal failing test that reproduces it before touching any source code.
Ask Claude to identify the root cause in the code — not just where the error surfaces, but why it happens.
Fix the actual cause, not the symptom. Ask Claude explicitly: "Fix the root cause, not just the surface error."
Run the new failing test (should now pass) AND the full test suite (no new regressions).
# Step 1 — Reproduce
This error appears in production:
[paste error message and stack trace]
Write a minimal failing test in [test file] that reproduces this exact error.
Do NOT fix anything yet.
# Step 2 — Diagnose
Now identify the root cause. Which line(s) cause this and why?
# Step 3 — Fix
Fix the root cause. The test you wrote must now pass.
Run the full test suite and confirm there are no regressions.
# Step 4 — Commit
Write a fix commit message following conventional commits.
Refactoring with Claude Code requires discipline: never mix refactoring with feature additions, always have tests before you start, and work in small steps.
/plan Refactor [module] to [goal] — do NOT change the public API. Review the plan before approving.# Extract a module
Move all the payment processing logic from orders.ts into a new payments/ module.
Public API must remain identical — callers import from the same path.
Tests must stay green throughout.
# Simplify complex function
The function processOrder() in src/orders.ts is 200 lines.
Break it into smaller functions where each does one thing.
Do NOT change behavior. Tests must stay green.
# Replace pattern
Replace all uses of the old callback pattern in src/api/ with async/await.
Update all call sites. Run tests after each file to catch regressions early.
# Dependency injection
Refactor DatabaseService in src/db/ to accept dependencies as constructor arguments
instead of importing them directly. Update all instantiation sites.
Add a type-safe mock for tests.
Use Claude Code as a pre-PR reviewer to catch issues before human reviewers see them.
Review the staged changes as a senior engineer would in a PR review.
Focus on:
1. Correctness — any logic errors, edge cases missed?
2. Security — any injection risks, auth gaps, secrets in code?
3. Performance — any N+1 queries, missing indexes, unnecessary loops?
4. Readability — any confusing names, missing error handling?
5. Tests — adequate coverage for the new code?
For each issue found: quote the line, describe the problem, suggest a fix.
/review
# or:
Review src/api/auth.ts for security issues.
Assume an attacker can control all query parameters and request bodies.
List each vulnerability with severity (critical / high / medium / low) and a fix.
Claude Code can run headlessly in GitHub Actions for automated code review, test generation, and PR summarization. See the GitHub Actions guide for full YAML examples.
| Workflow | Trigger | What Claude does |
|---|---|---|
| PR Review Bot | pull_request opened | Reviews diff, posts comments via gh CLI |
| Auto-fix Lint | push to any branch | Runs linter, asks Claude to fix violations, commits |
| Test Generation | New file added | Writes tests for new functions, opens a follow-up PR |
| Release Notes | Tag pushed | Summarizes commits since last tag into release notes |
| Dependency Audit | Weekly schedule | Reviews new vulnerabilities, opens fix PRs |
# In GitHub Actions
- name: Claude Code review
run: |
claude --headless \
--print "Review the diff in this PR and comment on any bugs, security issues, or readability problems. Output as GitHub markdown." \
--allowedTools "Bash,Read,Grep,Glob" \
> review.md
gh pr comment $PR_NUMBER --body-file review.md
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
PR_NUMBER: ${{ github.event.number }}
Here's a concrete morning-to-commit routine that most teams find effective:
1. git pull origin main — sync latest.
2. git checkout -b feat/todays-task — fresh branch.
3. Open Claude Code: share today's goal and constraints upfront.
4. /plan [today's main task] — review the plan before writing a line.
5. Execute plan one step at a time. Run tests after each logical unit.
6. Commit early and often — each passing test suite = a commit.
7. If scope creep appears, add it to a backlog note, not the current branch.
8. Ask Claude to review the full diff for issues.
9. Run the complete test suite one final time.
10. Ask Claude to generate the PR description.
11. git push origin feat/todays-task and open the PR.
/plan. The first file it writes may invalidate the approach.--dangerously-skip-permissions in your main working directory. Use it only in throwaway containers or fully sandboxed repos.Start each session with context: branch name, today's goal, what not to touch. Use /plan before any substantial change. Commit every time tests go green. Review your own diff before pushing. This plan-build-test-commit loop prevents most wasted sessions.
Two-phase approach: (1) Ask Claude to write failing tests that specify the behavior — no implementation yet. (2) Ask Claude to implement the minimum code to make those tests pass. Never ask for tests and implementation in the same message. The tests must be red before you ask for the green.
Always work on feature branches, never commit directly to main. Create the branch before opening Claude Code. Ask Claude to generate commit messages in conventional commit format after each logical unit. Ask Claude to write the PR description at the end. Never let Claude push directly to main.
Use /plan for large changes, check the file list before approving. Set permissions in CLAUDE.md to restrict which directories Claude can write to. Work on feature branches so you can reset if needed. See the permissions guide for the full settings reference.
Yes — Claude Code runs headlessly with --headless and --print flags. Common patterns: automated PR review, lint fixing, test generation, and release note drafting. See the GitHub Actions guide for full YAML examples.
Use /compact to compress prior conversation while preserving key decisions. Reference files by path rather than pasting their contents. Use sub-agents for parallel reads so the orchestrator doesn't load all code itself. Keep a focused CLAUDE.md that tells Claude what matters for the current task. See the memory guide for CLAUDE.md best practices.
Review the diff before every commit — not every line interactively, but a quick git diff pass. Claude makes logic errors, misses edge cases, and occasionally misunderstands scope. The test suite catches most errors, but a 30-second diff review catches the rest. The time saved by trusting Claude blindly is quickly lost when you have to debug a production incident.