AI Transformation with Claude · Part 2 · Week 7

Module 7. Claude Code as a delivery engine

Claude Code is how you build client work faster and more safely. This module turns it from a chat in a terminal into a repeatable setup: project memory, permissions, hooks, subagents on cheaper models, and a template repo you reuse on every engagement.

≈ 9 hreading 2 hlab 5 hdeliverable 2 h

By the end of this module you can

7.1 What Claude Code is

Claude Code is an agentic coding tool. You describe a goal; it reads the repository, edits files, runs commands, and shows you what it did. It works with your real tools (git, pytest, ruff, docker, the gh CLI) instead of working in a sandbox of its own. For you it has two uses: building client deliveries faster, and being something you teach the client's developers to use.

SurfaceWhat it isUse it for
Terminal (CLI)The claude command inside a project folder. The most complete surface and the one this module uses.Daily delivery work, scripting, CI
IDE extensionsClaude Code inside VS Code and JetBrains editors, with diffs shown in the editorClient developers who live in their editor
Desktop appClaude Code sessions in the Claude desktop appRunning several sessions side by side, reviewing changes visually
WebSessions run in the cloud against a connected GitHub repository, from a browser or phoneStarting a task away from your machine, longer background jobs

The surfaces share the same ideas: CLAUDE.md, settings, slash commands, subagents, MCP. Feature coverage differs between them and changes often, so check the overview page for the current list and the install steps. Do not write install commands from memory into a client handover.

7.2 The orchestration idea, applied to coding

You already like this pattern: a strong model plans, cheaper models do the legwork. Claude Code supports it directly. The main session runs on the model you picked (Opus or Sonnet). It hands bounded jobs to subagents. Each subagent runs in its own context window, so a long file search does not fill the main conversation, and each can use a cheaper model.

Main session (orchestrator) plans, decides, edits; Opus or Sonnet explorer Haiku, read-only tools finds files, summarizes test-runner Haiku, bash + read runs pytest, reports failures reviewer Sonnet, read-only tools checks the diff, lists risks summaries flow back up; the main context stays small Optional: a local llama.cpp box for tiny tasks via a script or MCP tool
The main session keeps the plan and the decisions. Subagents return short summaries, not whole transcripts.

A local llama.cpp box does not plug into Claude Code as a subagent model. Subagent models are Claude models. If you want the local box in the loop, expose it as a small script or MCP tool (for example "classify this log line", "extract the invoice number") and let a subagent call it. Keep it for tiny, low-risk tasks.

7.3 CLAUDE.md: project memory

CLAUDE.md is a Markdown file that Claude Code loads at the start of a session. It is the cheapest way to improve results: you write the rules once instead of repeating them in every prompt. Put in it what a new developer would need on day one.

Keep it short and specific. Every line is read on every session, so every line costs context. Vague advice ("write clean code") adds cost and no value.

LevelWhereShared withPut here
User~/.claude/CLAUDE.mdOnly you, all projectsYour own habits: "reply concisely", "I use uv", your preferred test style
Project./CLAUDE.md (committed)The whole teamCommands, layout, conventions, hard rules
Local project./CLAUDE.local.md (git-ignored)Only you, this projectYour sandbox URLs, personal notes. Check the memory docs for whether your version still supports this file.
Subfolder./src/api/CLAUDE.mdThe teamRules for one area. Loaded when Claude works on files there.

CLAUDE.md files can also import other files. The syntax and the exact loading order are in the memory docs; read them before you build a deep hierarchy. In session, /memory lets you see and edit what is loaded, and /init drafts a first CLAUDE.md from the codebase. Treat the draft as a starting point and trim it.

7.4 Permissions and settings.json

By default Claude Code asks before it edits files or runs commands. Permissions let you pre-approve the safe things and block the dangerous ones, so the sessions run smoothly without you giving up control.

FileScopeCommitted?
~/.claude/settings.jsonYou, all projectsNo
.claude/settings.jsonThis project, the teamYes
.claude/settings.local.jsonThis project, only youNo (git-ignored)

Settings hold permission rules (allow, ask, deny), hooks, environment variables and more. More specific and local files override broader ones, and a deny rule wins. Rule syntax and the full key list are in the docs, and they change, so look them up when you write a client config.

Rule of thumb for client work: allow read-only and test commands; deny reading .env and secrets; leave anything that writes outside the repo, installs packages or touches the network on "ask". The /permissions command shows what is active. Do not use a "skip all permissions" mode on a client machine.

7.5 Slash commands, hooks, subagents, skills, MCP

Custom slash commands

A Markdown file in .claude/commands/ becomes a command. .claude/commands/eval.md is run as /eval. The body is a prompt; $ARGUMENTS is replaced by what you type after the command. A short frontmatter block can set a description and, optionally, allowed tools and a model. Commands are how you turn your own methods ("how we scope a use case") into a one-line habit that every developer on the project uses.

Hooks

A hook is a shell command that Claude Code runs automatically at a defined moment, for example after a file edit or when Claude finishes a turn. Hooks are deterministic: they run every time, which a CLAUDE.md instruction does not guarantee. Typical uses are running ruff after edits, running pytest before Claude says it is done, and blocking edits to protected files. Hooks run with your permissions, so review any hook you copy from somewhere. Event names, matcher syntax and exit-code behaviour are in the hooks reference; verify them there.

Subagents

A subagent is a Markdown file in .claude/agents/ (project) or ~/.claude/agents/ (user). Frontmatter sets its name, a description that tells Claude when to use it, an optional list of tools, and an optional model. The body is its system prompt. Claude delegates to a subagent automatically when the description matches the task, or when you ask by name.

Use a subagent forWhyModel and tools
Exploration: "where is invoice parsing done?"Reading many files floods the main context; you only need the answerHaiku; read-only tools
Running tests and reportingTest output is long; you only need the failures and likely causeHaiku; bash and read
Review of a diffA fresh context judges the change without the author's assumptionsSonnet; read-only tools

Do not make a subagent for work that needs the full conversation history, or for one small edit. Delegation has overhead. See the sub-agents docs for the current frontmatter fields and model values.

Skills in Claude Code

Skills are folders with a SKILL.md and optional scripts that Claude loads when the task matches. In Claude Code they live in .claude/skills/ (project) or ~/.claude/skills/ (user). The difference from CLAUDE.md: a skill loads only when relevant, so it costs nothing the rest of the time. Put always-true rules in CLAUDE.md and task-specific procedures in a skill. Module 8 covers skills in depth.

MCP servers in a project

A .mcp.json file at the repo root declares MCP servers for everyone who works in the project. Claude Code asks each person to approve a project server before using it. This is how the server you built in Module 6 becomes available to the whole team without anyone editing personal settings. Never put secrets in .mcp.json; reference environment variables instead, and check the docs for the expansion syntax.

User: ~/.claude/ CLAUDE.mdsettings.json commands/agents/ skills/ yours, in every project, never committed Project: the repository CLAUDE.md project memory, committed .mcp.json project MCP servers .claude/settings.json permissions + hooks, shared .claude/settings.local.json yours only, git-ignored .claude/commands/ /new-usecase, /eval .claude/agents/ explorer, test-runner, reviewer .claude/skills/ task procedures src/api/CLAUDE.md rules for one folder more specific files add to or override broader ones a deny rule always wins
Commit what the team shares. Keep personal and secret things in the user folder or the local files.

7.6 The working loop: plan, implement, test, review

Most failed Claude Code sessions skip the plan. Plan mode (cycle to it with Shift+Tab, or start the session in it; confirm the current key in the docs) lets Claude read and think but not edit. You read the plan, correct it, and only then approve implementation.

1 Plan plan mode, no edits 2 Implement small steps, ruff hook 3 Test test-runner on Haiku 4 Review reviewer on Sonnet, then you problems found: back to the plan, not to guessing you approve at step 1 and read the result at step 4
A human gate at the plan and at the review. The middle two steps are where the cheap models and hooks do the work.

Habits that make the loop work:

7.7 Git, GitHub and CI

Claude Code runs git and, if installed and authenticated, the GitHub gh CLI. A clean delivery flow:

  1. Create a branch per task (git switch -c feature/phone-normalizer). Never work on main.
  2. Run the plan, implement, test loop. Commit in small steps with clear messages.
  3. Ask Claude to open the pull request with gh pr create and write the description: what changed, how it was tested, what to check.
  4. Review the PR in GitHub like any other. Merge only after your approval.

For automatic review on every pull request, Anthropic provides a Claude Code GitHub Action. It can review PRs and respond when someone mentions Claude in a comment. Setup (the /install-github-app command in a session, or a manual workflow file plus a repository secret) and the current options are in the GitHub Actions docs. Store the API key as a repository secret and never in the workflow file.

Headless use

The -p (print) flag runs Claude Code once, non-interactively, and prints the result. That makes it usable in scripts and CI: summarize a failing build, draft release notes, check a migration. Output can be requested as plain text or JSON. In CI, restrict the tools with allow rules and run with a scoped, low-privilege key. The exact flags (output format, allowed tools, turn limits) are in the CLI reference. Run claude --help and read the docs; do not trust a flag you remember from last month.

# Example shape only: confirm every flag with `claude --help` and the CLI reference
claude -p "List functions in src/ that have no tests" --output-format json

7.8 Cost discipline

Claude Code cost follows tokens, and tokens follow context. Four habits matter more than any setting:

Use /cost or the usage views to see where tokens go, and look at the pricing page and the plan's usage rules before you tell a client what a Claude Code rollout will cost. Do not quote numbers from memory.

7.9 Teaching client developers

Many of your clients have one to five developers and no process for AI-assisted coding. Your template repo is the teaching tool. A good first session runs 90 minutes:

  1. Show the loop on a real, small ticket from their backlog, live, including a mistake Claude makes and how plan mode and tests catch it.
  2. Walk through CLAUDE.md. Have them add two rules from their own codebase.
  3. Let each developer do one ticket alone with you watching. Give feedback on prompts, not on code style.
  4. Agree three rules: always branch, always read the diff, never paste client secrets into prompts.

Their security person will ask what data leaves the machine, so prepare the answer from current Anthropic documentation and Trust Center pages, with the date you checked.

7.10 Check the docs for exact flags

Claude Code changes fast: commands, settings keys, hook events and model aliases are added and renamed. Treat this page as the map and the docs as the ground truth. Before you commit a config to a client repo, verify each key in the docs, start a session, and run /permissions, /agents, /hooks and /mcp to see that your files are actually loaded. If something does not load, the config is usually silently wrong, not broken.

Lab 7. The client-engagement template repo

Goal: one repository you clone at the start of every engagement, so each project begins with memory, guardrails, cheap subagents and a test loop already in place. Then prove it by building a tiny feature with plan mode.

The files below are complete. Config key names were correct when this course was written; verify each against the docs from section 7.10 and adjust. Model aliases in subagent files (haiku, sonnet) are shorthand; the docs list the accepted values.

Setup

mkdir client-engagement-template && cd client-engagement-template
git init -b main
mkdir -p .claude/commands .claude/agents src/app tests
python -m venv .venv && source .venv/bin/activate
pip install ruff pytest

CLAUDE.md

# Project: CLIENT_NAME engagement

Python service built by Vastama Ltd for CLIENT_NAME. Replace this paragraph
with two lines on what the system does and who uses it.

## Commands
- Install: `pip install -e ".[dev]"`
- Test: `pytest -q`
- Lint: `ruff check .`
- Format: `ruff format .`

## Layout
- `src/app/` application code
- `tests/` pytest tests, mirror the `src/app/` structure
- `docs/` decisions and use-case briefs

## Conventions
- Python 3.11+, type hints on all public functions
- Small functions, no global state, no print in library code (use logging)
- Comments and docstrings in English. User-facing strings may be Hebrew,
  Russian or English; keep them in one place so they can be translated.
- Model IDs live in one config module. Add a "check current IDs" comment.

## Hard rules
- Never read or edit `.env` or anything under `secrets/`.
- Tests must not call the Claude API or touch client data. Use fixtures.
- Ask before adding a dependency.
- Work on a branch, never on `main`.

## Definition of done
1. `pytest -q` passes
2. `ruff check .` is clean
3. New behaviour has a test
4. README or docs updated if usage changed

## Working style
- For any change over ~20 lines, propose a plan first and wait for approval.
- Use the `explorer` subagent to find code, `test-runner` to run tests,
  `reviewer` before suggesting a commit.

.claude/settings.json (permissions and hooks)

{
  "permissions": {
    "allow": [
      "Bash(pytest:*)",
      "Bash(ruff check:*)",
      "Bash(ruff format:*)",
      "Bash(git status)",
      "Bash(git diff:*)",
      "Bash(git log:*)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./secrets/**)",
      "Bash(git push --force:*)"
    ]
  },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "ruff check --fix --quiet . ; ruff format --quiet ."
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "pytest -q 1>&2 || exit 2"
          }
        ]
      }
    ]
  }
}

The first hook formats and lints after every edit. The second runs the tests when Claude finishes a turn; exit code 2 is how a hook feeds a failure back to Claude so it keeps working. Confirm that behaviour for the Stop event in the hooks reference. If it differs in your version, move the pytest hook to PostToolUse with a narrower matcher, or drop it and rely on the test-runner subagent.

.claude/commands/new-usecase.md

---
description: Scope a new AI use case and create its brief
argument-hint: short name of the use case
---

Create a brief for a new use case called: $ARGUMENTS

1. Ask me up to five questions you need answered. Stop and wait for answers.
2. Then write `docs/usecase-$ARGUMENTS.md` with these sections:
   - Problem and who has it
   - Input and output (examples, in the real language of the data)
   - Success metric and how we measure it
   - Risks and what a human must approve
   - Proposed model tier and why
   - First test cases (at least five, including two hard ones)
3. Do not write application code yet. End with a suggested plan to implement
   the first slice.

.claude/commands/eval.md

---
description: Run the test suite and summarize results
argument-hint: optional pytest path or -k expression
---

Use the `test-runner` subagent to run `pytest -q $ARGUMENTS`.

Report:
- number passed, failed, skipped
- for each failure: test name, one-line cause, the file and line to look at
- whether the failures look like a code bug or a bad test

Do not edit any files. Wait for my instruction before fixing anything.

.claude/agents/explorer.md

---
name: explorer
description: Finds code and explains how a part of the codebase works. Use for "where is X", "how does Y flow" and any search across many files. Read-only.
tools: Read, Grep, Glob
model: haiku
---

You explore the repository and answer questions about it.

- Search first, read second. Read only the files you need.
- Answer in under 200 words: the relevant file paths with line numbers, and
  a short description of how they connect.
- If you are not sure, say what you checked and what you did not find.
- Never suggest edits and never invent paths.

.claude/agents/test-runner.md

---
name: test-runner
description: Runs the test suite and reports failures concisely. Use after code changes and before suggesting a commit.
tools: Bash, Read, Grep
model: haiku
---

You run tests and report results. You do not fix code.

1. Run `pytest -q` (or the path or expression you were given).
2. If everything passes, reply with the counts and nothing else.
3. If something fails, reply with, for each failure: test name, the assertion
   or error in one line, and the most likely file and line responsible.
4. Do not paste full tracebacks unless asked.

.claude/agents/reviewer.md

---
name: reviewer
description: Reviews the current uncommitted diff for bugs, missing tests, security problems and convention violations. Use before every commit or PR.
tools: Read, Grep, Glob, Bash
model: sonnet
---

You are a careful code reviewer. Run `git diff` and `git status` to see the
change, then read surrounding code where needed.

Check, in this order:
1. Correctness: edge cases, wrong assumptions, off-by-one, None handling
2. Tests: is the new behaviour covered, including a failure case?
3. Security and data: secrets, client data in logs or fixtures, unsafe input
4. Conventions from CLAUDE.md
5. Simplicity: anything that can be removed

Reply with a short list grouped as Must fix, Should fix, Nice to have. Each
item has the file, line and a one-sentence reason. If there is nothing to
fix, say so. Do not edit files.

.mcp.json (the Module 6 server)

{
  "mcpServers": {
    "client-data": {
      "command": "python",
      "args": ["-m", "client_data_mcp"],
      "env": {
        "CLIENT_DATA_DIR": "${CLIENT_DATA_DIR}"
      }
    }
  }
}

Replace client-data, the module name and the variable with the real names from your Module 6 server, and use the uv or pip install you chose there. Confirm the environment variable expansion syntax in the MCP section of the Claude Code docs. No secrets go in this file.

pyproject.toml

[project]
name = "client-engagement"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = []

[project.optional-dependencies]
dev = ["pytest", "ruff"]

[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]

[tool.ruff]
line-length = 100
src = ["src", "tests"]

[tool.ruff.lint]
select = ["E", "F", "I", "B", "UP"]

src/app/__init__.py

"""Application package."""

src/app/core.py

"""Core helpers. Replace with the first real slice of the engagement."""

import logging

logger = logging.getLogger(__name__)


def clean_text(value: str) -> str:
    """Trim whitespace and collapse internal runs of spaces."""
    return " ".join(value.split())

tests/test_core.py

from app.core import clean_text


def test_clean_text_trims_and_collapses():
    assert clean_text("  שלום   עולם  ") == "שלום עולם"


def test_clean_text_empty():
    assert clean_text("") == ""

.gitignore

.venv/
__pycache__/
*.egg-info/
.pytest_cache/
.ruff_cache/
.env
secrets/
.claude/settings.local.json
CLAUDE.local.md

README.md

# Client engagement template

Starting point for Vastama client projects built with Claude Code.

## Start a new engagement
1. Click "Use this template" on GitHub (or clone and delete `.git`).
2. Edit `CLAUDE.md`: client name, what the system does, any extra rules.
3. Edit `.mcp.json` to point at the client's MCP server, or remove it.
4. `python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]"`
5. Run `claude` in the folder. Check `/agents`, `/hooks`, `/mcp` and
   `/permissions` show what you expect.

## What is in the box
| Path | Purpose |
| --- | --- |
| `CLAUDE.md` | Project memory: commands, layout, rules, definition of done |
| `.claude/settings.json` | Permissions and hooks (ruff after edits, pytest on stop) |
| `.claude/commands/` | `/new-usecase`, `/eval` |
| `.claude/agents/` | `explorer` (Haiku), `test-runner` (Haiku), `reviewer` (Sonnet) |
| `.mcp.json` | Project MCP server |
| `src/app/`, `tests/` | Skeleton with one passing test |

## Daily flow
Branch, plan mode, implement, test, review, pull request. See
"How we build with Claude Code" in `docs/`.

## Rules
Never commit `.env`. Tests never call external APIs. Always read the diff.

Commit and push

pytest -q && ruff check .
git add -A && git commit -m "Client engagement template"
gh repo create client-engagement-template --private --source . --push
# On GitHub: Settings, then tick "Template repository"

Use it: a tiny feature with plan mode

Feature: normalize Israeli mobile phone numbers (050-123-4567, +972 50 123 4567, 0501234567) to +972501234567, and return None for anything invalid.

  1. Create a repo from the template. Run git switch -c feature/phone-normalizer.
  2. Start claude, switch to plan mode, and run /new-usecase phone-normalizer. Answer its questions, then read docs/usecase-phone-normalizer.md.
  3. Still in plan mode, prompt: "Plan the phone normalizer from the brief. List files, tests first, and risks." Reject the plan once on purpose with a correction (for example "no new dependencies") and check it revises.
  4. Approve. Let Claude write the tests, then the code in src/app/phones.py. Watch the ruff hook run after each edit.
  5. Run /eval. Confirm the test-runner subagent was used and the summary is short.
  6. Ask: "Use the reviewer subagent on the current diff." Fix every Must-fix item.
  7. Commit, then ask Claude to push and run gh pr create with a description. Review the PR page yourself and merge.
  8. Write down: how many turns, what you corrected, and which subagent saved you the most reading.

Stretch (1 h): add the Claude Code GitHub Action to the template using the current docs, open a PR with a deliberate bug, and see whether the review catches it. Then run one headless claude -p command from a shell script and save the output.

Deliverable: the template repo and "How we build with Claude Code"

Two things you can hand to any client:

  1. The template repository on GitHub, marked as a template, with a README that a stranger can follow in ten minutes. Share the link.
  2. A one-page client note, "How we build with Claude Code", saved as docs/how-we-build.md in the repo and as a PDF. Suggested structure:
    • Our loop: plan, implement, test, review, with a human approving the plan and the merge
    • What AI does and what people do: Claude drafts and runs checks; a named engineer owns every change
    • Guardrails: branch-only work, permission rules, secrets never read, tests never use client data
    • Quality evidence: tests, lint, review notes and PR history you can inspect
    • Data handling: what is sent to Anthropic when we work, with a link to the current terms and the date checked
    • What we hand over: the repo, CLAUDE.md, the template, and a training session for your developers

Self-check

  1. Your CLAUDE.md says "always run ruff after editing", but Claude sometimes forgets. What do you change, and why?
    Model answerMove the rule into a hook (a PostToolUse hook on edits). CLAUDE.md is guidance the model may miss; a hook is a command that runs every time. Keep the CLAUDE.md line only as explanation.
  2. Which three subagents does the template include, which model does each use, and why those?
    Model answerexplorer (Haiku, read-only) for searching many files, test-runner (Haiku) for running tests and returning only failures, reviewer (Sonnet, read-only) for judging the diff. Cheap models do high-volume reading and running; a stronger model does the judgment. Each keeps noisy output out of the main context.
  3. Where would you put each: your personal habit of terse replies; the test command for the project; a rule only for the src/api/ folder?
    Model answerTerse replies in the user file ~/.claude/CLAUDE.md. The test command in the project ./CLAUDE.md, committed. The API rule in src/api/CLAUDE.md, loaded when Claude works there.
  4. A developer wants to run Claude Code in CI to summarize failing builds. What do you tell them about how, and what must they check first?
    Model answerUse headless mode (the -p flag) with a restricted set of allowed tools and a scoped key stored as a CI secret. Before writing the pipeline, check the CLI reference for the exact flags and output formats, because they change. Review what the job can read and write.
  5. A session has become slow and expensive after three unrelated tasks. List three actions that reduce cost, in order.
    Model answerUse /clear when switching to an unrelated task, or /compact with instructions when you must continue the same task. Push searching and test running to Haiku subagents. Name files in prompts and trim CLAUDE.md. Optionally switch the main model for the next step with /model.

Further reading