AI EngineeringZero to ProductionHome·About·Contact
Anthropic Skills · Project K

Agent workbench (capstone)

Compose Claude Code config, a custom Skill, a subagent, and your own MCP server into one automated, verifiable developer workbench — the whole section in one repo, shipped to the team.

⏱️ ~5 hours🏗️ Capstone project🎯 Beginner→Tech-lead
What you'll buildA developer workbench composing everything in this section: Claude Code steered + configured (K1), automated with hooks + CI (K2), extended with a custom Skill (K4) and a subagent (K5), backed by your own MCP server (K6), used with fluency (K8). One repo where the whole team's Claude works your way, verifiably.

Learning objectives

  • Assemble config, a Skill, a subagent, and an MCP server in one repo.
  • Automate quality with a hook and CI.
  • Apply the 4 Ds across the setup.
  • Ship it so the team inherits the workbench.
▶ Runnable companionCode saved under code/proj-ak-workbench/. Python runs offline; configs are ready to use.

1 · The repo layout essential

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
layout · what lives in the repo
tree.txtyour-project/
├── CLAUDE.md                       # K1: conventions, commands, guardrails
├── .claude/
│   ├── settings.json               # K1/K2: permissions + a Stop hook (tests)
│   ├── commands/review.md          # K2: /review slash command
│   ├── skills/house-style/SKILL.md # K4: team code + doc conventions
│   └── agents/code-reviewer.md     # K5: least-privilege reviewer subagent
├── mcp/server.py                   # K6: MCP server exposing project tools/data
└── .github/workflows/claude-review.yml   # K2: headless review on PRs
▶ How this works

settings.json is where you tell Claude Code the rules of the house. It's plain JSON — a set of "key": value pairs wrapped in curly braces. Two sections matter here: permissions (what's allowed) and hooks (what runs automatically).

  1. "allow" lists actions Claude may take without asking — run pytest or ruff, read any file (Read(*)), and edit files under src/. The patterns in parentheses scope each permission narrowly.
  2. "deny" is the safety rail: it blocks git push and any edit to vendor/. Deny always wins over allow, so risky actions stay in human hands.
  3. The "Stop" hook fires when Claude finishes a turn. "matcher": "*" means "on every stop", and it runs one command.
  4. That command, pytest -q || echo TESTS-FAILED, runs your tests quietly; the || means "if pytest fails, print TESTS-FAILED" so a failure is loud and visible instead of silent.

What the output means: No visible output on its own — this file just configures Claude Code. Its effect is felt later: blocked pushes, and tests running automatically each time Claude stops.

Try this: Add "Bash(git commit:*)" to the allow list and think about whether you want that. The allow/deny split is exactly where you decide what Claude does on its own versus what needs you.

▶ How this works

Before any code, this is a map of the repo you're about to build. Everything Claude reads to behave your way lives in one hidden folder, .claude/, next to your normal project files. A newcomer only needs to know: each file below is one capability, and the capital-K tags (K1, K2, …) point back to the lesson that introduced it.

  1. CLAUDE.md sits at the top — plain-English notes (conventions, common commands, guardrails) that Claude reads automatically every session, like an onboarding doc.
  2. .claude/settings.json holds permissions (what Claude may or may not do) and hooks (commands that fire automatically at certain moments).
  3. commands/, skills/, and agents/ each add one thing: a reusable /review shortcut, a Skill (packaged know-how), and a subagent (a focused helper with its own narrow permissions).
  4. mcp/server.py is your own small server that hands Claude project data and actions; .github/workflows/…yml runs a review automatically on every pull request.

What the output means: This is a directory tree, not a program — nothing runs. The ├── and └── lines just show which files live inside which folders (indentation = nesting).

Try this: Picture cloning this repo fresh: the moment you open it, Claude already knows your rules (CLAUDE.md), your limits (settings.json), and your tools. That inheritance-from-one-git pull is the whole point of the workbench.

2 · Wire the config essential

config · .claude/settings.json
settings.json{
  "permissions": {
    "allow": ["Bash(pytest:*)", "Bash(ruff:*)", "Read(*)", "Edit(src/**)"],
    "deny":  ["Bash(git push:*)", "Edit(vendor/**)"]
  },
  "hooks": {
    "Stop": [ { "matcher": "*", "hooks": [
      { "type": "command", "command": "pytest -q || echo TESTS-FAILED" } ]} ]
  }
}

3 · The MCP server (K6) intermediate

Python · mcp/server.py
server.pyfrom mcp.server.fastmcp import FastMCP
mcp = FastMCP("project-tools")

def query_tracker(**kw): ...       # your ticket-system integration
def read_deploy_log(service): ...  # your deploy-log integration

@mcp.tool()
def open_tickets(component: str) -> list[dict]:
    """List open tickets for a component. Use when triaging or planning."""
    return query_tracker(status="open", component=component)

@mcp.tool()
def last_deploy(service: str) -> dict:
    """Return the last deploy's status and commit for a service."""
    return read_deploy_log(service)

if __name__ == "__main__":
    mcp.run(transport="stdio")
▶ How this works

An MCP server is a small program that exposes your own tools to Claude in a standard way (MCP = Model Context Protocol). Here it's built with FastMCP, a helper that turns ordinary Python functions into tools Claude can call. Once this runs, Claude can look up tickets and deploy status through your systems.

  1. mcp = FastMCP("project-tools") creates the server and names it. That name is how Claude will refer to this bundle of tools.
  2. query_tracker and read_deploy_log are placeholders (the ... means "you fill this in") — they stand for wherever your real ticket system and deploy logs live.
  3. The @mcp.tool() line above a function is a decorator: it registers that function as a callable tool. The docstring right under it ("""List open tickets…""") is not a comment — Claude reads it to decide when to use the tool, so it must describe the purpose plainly.
  4. The -> list[dict] and -> dict type hints tell Claude the shape of the answer. Finally mcp.run(transport="stdio") starts the server, talking over standard input/output so Claude Code can connect to it locally.

What the output means: Run directly, this prints nothing and waits — an MCP server is a background service, not a script that finishes. Claude Code starts it and calls its tools on demand.

Try this: Read each tool's docstring as if you were Claude deciding which to call. A vague docstring means the wrong tool gets picked — clear descriptions are how the model routes to the right tool.

4 · Advanced — Skill + subagent advanced

config · house-style Skill (K4)
house-style.md---
name: house-style
description: >
  Apply our team's code and doc conventions. Use whenever writing or editing
  code, docs, or PR descriptions in this repo.
---
# House style
- Functions: type hints + a one-line docstring stating the contract.
- Errors: raise specific exceptions; never `except: pass`.
- Docs: lead with the "why", then the "how"; examples must be runnable.
- PRs: describe the change, the risk, and how it was verified.
▶ How this works

A Skill is packaged know-how Claude loads on demand. The file has two parts: a front-matter header (between the --- lines) that tells Claude when to use the Skill, and a Markdown body that says what to do. This one encodes your team's coding and writing conventions.

  1. The --- fences mark YAML front-matter — structured metadata. name is the Skill's id.
  2. description is the crucial line: Claude reads it to decide whether this Skill applies. "Use whenever writing or editing code, docs, or PR descriptions" is a clear trigger, so the Skill activates at the right moments.
  3. Everything below the closing --- is plain Markdown — the actual rules. Bullets keep them scannable: type hints, specific exceptions (never except: pass), docs that lead with the "why".
  4. Because it's just text, the Skill is version-controlled with the repo, so the whole team's Claude follows the same conventions automatically.

What the output means: No output — a Skill is instructions, not a program. Its effect shows up in the code and docs Claude writes: they start matching these house rules.

Try this: Add one rule you care about (e.g. "tests live next to the code they test"). The next time Claude edits this repo, that rule is in force — you've taught the whole team's assistant with one line.

5 · Professional — automate the review professional

config · CI review on every PR (K2)
claude-review.ymlname: Claude review
on: [pull_request]
jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - env: { ANTHROPIC_API_KEY: "${{ secrets.ANTHROPIC_API_KEY }}" }
        run: |
          git diff origin/main...HEAD > /tmp/diff.txt
          claude -p "Use the code-reviewer subagent on /tmp/diff.txt. \
            Output findings grouped by severity." > review.md
          cat review.md
▶ How this works

This is a GitHub Actions workflow — a YAML recipe GitHub runs automatically. Its job: every time someone opens a pull request, spin up a fresh machine, run Claude in headless mode (no chat window) to review the change, and save the findings. This is your review, automated for the whole team.

  1. on: [pull_request] is the trigger — the workflow fires on every PR. The runs-on: ubuntu-latest line gives it a clean Linux machine to work on.
  2. actions/checkout@v4 with fetch-depth: 0 downloads the full git history so the diff can be computed against main.
  3. ANTHROPIC_API_KEY is read from repo secrets (${{ secrets.… }}) — the key is never written in the file, so it stays private.
  4. The run: block is shell: save the PR's changes to /tmp/diff.txt, then claude -p "…" runs one prompt non-interactively, asking the code-reviewer subagent to review that diff and group findings by severity, writing the result to review.md.

What the output means: On each PR, a review.md is produced with the subagent's findings grouped by severity, and cat review.md prints it into the CI logs for anyone to read.

Try this: Notice the same subagent used interactively (K5) is reused here headlessly. Write once, run it both in your editor and in CI — that's the leverage of committing your setup.

6 · Professional — the 4 Ds, made concrete professional

The workbench is where AI Fluency becomes concrete: Delegation — the deny-list keeps risky actions human; Description — CLAUDE.md + the Skill carry intent; Discernment — the Stop hook + CI review verify; Diligence — permissions + no-auto-push keep it responsible.

Python · verify the workbench is complete (runs)
workbench_check.pydef workbench_ready(repo):
    required = {
        "claude_md": "CLAUDE.md (K1)",
        "settings_permissions": "permissions (K1)",
        "stop_hook": "test-on-stop hook (K2)",
        "skill": "a house Skill (K4)",
        "subagent": "a subagent (K5)",
        "mcp_server": "an MCP server (K6)",
        "ci_review": "CI review (K2)",
    }
    missing = [desc for key, desc in required.items() if not repo.get(key)]
    return (not missing), missing

full = dict(claude_md=1, settings_permissions=1, stop_hook=1, skill=1,
            subagent=1, mcp_server=1, ci_review=1)
print("ready:", workbench_ready(full))
partial = dict(claude_md=1, settings_permissions=1, skill=1)
print("partial:", workbench_ready(partial))
ready: (True, [])
partial: (False, ['test-on-stop hook (K2)', 'a subagent (K5)', 'an MCP server (K6)', 'CI review (K2)'])
▶ How this works

This little program checks that your workbench is complete — that every piece from the section (CLAUDE.md, permissions, the Stop hook, a Skill, a subagent, an MCP server, CI review) is actually present. It's a self-test you can run to prove the setup is whole, and unlike the configs above, it really runs.

  1. required is a dictionary mapping a short key (like "stop_hook") to a human-readable label. It's the checklist of everything the workbench must have.
  2. repo is expected to be a dictionary describing what's present. repo.get(key) returns the value for that key, or None if it's absent — so not repo.get(key) is true for anything missing.
  3. The line missing = [desc for key, desc in required.items() if not repo.get(key)] is a list comprehension: it walks the checklist and collects the labels of every piece the repo lacks.
  4. return (not missing), missing hands back two things: a True/False "is it ready?" (not missing is True only when the list is empty) and the list of what's still missing. The two calls below test a full repo and a partial one.

What the output means: ready: (True, []) — the full repo passes with nothing missing. partial: (False, [...]) — the partial repo fails and names exactly the four pieces it lacks (the hook, subagent, MCP server, and CI review).

Try this: Delete one key from the full dict and re-run: that piece's label jumps into the missing list and ready flips to False. This is how you'd gate a 'workbench complete' check in CI.

7 · Tech-lead — ship the workbench to the team tech-lead

Commit the whole .claude/ tree + the MCP server. Every teammate who clones the repo inherits your steering, Skills, subagents, and safety — the entire section, working for the whole team from one git pull.

The workbench is institutional leverageOne committed, curated workbench means every engineer's Claude behaves to your standards, uses your tools, and follows your guardrails — automatically. That's the tech-lead endgame: your judgment, encoded once, multiplying across the team.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · Milestone 1 — permissions with allow/deny (deny wins)Beginner

Context: A shared agent workbench is only as safe as its permission model. The foundation is a .claude/settings.json where a deny always beats an allow, so a risky action stays human even under a broad allow.

Your task: Model the allow/deny permission resolution: given an action, decide ALLOW, DENY, or ASK, with deny checked first and unmatched actions defaulting to a human prompt.

Requirements:

  • Parse rules of the form Tool(pattern:*) into a tool name and argument pattern
  • Match an incoming action (tool + argument) against a rule
  • Check the deny list first — a deny wins even if an allow also matches
  • Fall through to ASK when neither list matches
  • Show a safe command allowed, a risky command denied, and an unknown command asking

💡 Hint: Order is the whole lesson: evaluate deny before allow so a broad allow can never re-open something the deny list closed.

Show solution

The permission resolver — deny wins (pure stdlib, mirrors settings.json semantics):

ALLOW = ["Bash(pytest:*)", "Bash(ruff:*)", "Read(*)", "Edit(src/**)"]
DENY  = ["Bash(git push:*)", "Edit(vendor/**)"]

def matches(rule, action):
    tool, pat = rule[:-1].split("(", 1)      # e.g. Bash(pytest:*)
    return action["tool"] == tool and action["arg"].startswith(pat.rstrip("*"))

def decide(action):
    if any(matches(r, action) for r in DENY):   # deny checked first, wins
        return "DENY"
    if any(matches(r, action) for r in ALLOW):
        return "ALLOW"
    return "ASK"                                  # default: prompt the human

print(decide({"tool": "Bash", "arg": "pytest -q"}))       # ALLOW
print(decide({"tool": "Bash", "arg": "git push origin"})) # DENY
print(decide({"tool": "Bash", "arg": "rm -rf /"}))        # ASK

The allow-list grants specific safe actions; the deny-list keeps risky ones (git push, vendor edits) human — and deny beats allow so a broad allow can't accidentally open a dangerous door. Anything unmatched falls through to ASK, the safe default.

Exercise 2 · Milestone 2 — a test-on-stop hook + CLAUDE.mdIntermediate

Context: Quality you rely on a human to remember isn't automated. A Stop hook makes the harness run the tests every time Claude finishes, and a CLAUDE.md makes team conventions travel with the repo instead of in one person's head.

Your task: Define a .claude/settings.json Stop hook that runs the test suite on every finish and a CLAUDE.md carrying conventions, then reason about what the hook guarantees.

Requirements:

  • A Stop hook under the hooks key with a matcher that fires on every stop
  • A command-type hook that runs the tests and surfaces failure loudly
  • A CLAUDE.md holding conventions and common commands in plain Markdown
  • Explain that the harness — not the model — runs the hook, so it can't be skipped
  • State the guarantee: no change quietly completes with failing tests

💡 Hint: Use a * matcher and a command like pytest -q || echo TESTS-FAILED so a failure is visible; the reliability comes from the harness executing it, not the model.

Show solution

The Stop hook as literal config (this is .claude/settings.json, not runnable Python):

{
  "permissions": {
    "allow": ["Bash(pytest:*)", "Read(*)", "Edit(src/**)"],
    "deny":  ["Bash(git push:*)"]
  },
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          { "type": "command", "command": "pytest -q || echo TESTS-FAILED" }
        ]
      }
    ]
  }
}

The Stop hook runs pytest automatically whenever Claude stops, so no change is "done" until the suite is green — the harness executes this, not the model, so it cannot be skipped. CLAUDE.md carries the conventions and commands so intent travels with the repo, not in one person's head.

Exercise 3 · Milestone 3 — an MCP server exposing project tools (needs the lib)Advanced

Context: Claude is far more useful when it can reach your systems. An MCP server exposes your ticket tracker and deploy logs as standard tools, with docstrings acting as the routing hints the model reads to pick the right one.

Your task: Show the correct FastMCP server shape: typed tool functions with docstrings that guide routing, run over stdio so Claude Code can spawn it. Mark this rung as needing the SDK.

Requirements:

  • Create a FastMCP server with a descriptive name
  • Register each tool with the tool decorator on a typed function
  • Write a clear docstring per tool — the model reads it as a routing hint
  • Give return type hints so the model knows the response shape
  • Run over stdio so Claude Code can launch it as a subprocess
  • Label the rung as requiring the MCP SDK

💡 Hint: The docstring is the interface the model routes on — treat it as a spec, not a comment — and return types tell the model what shape comes back.

Show solution

The MCP server — needs pip install mcp (documented FastMCP API):

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("project-tools")

def query_tracker(**kw): ...          # your real integrations
def read_deploy_log(service): ...

@mcp.tool()
def open_tickets(component: str) -> list[dict]:
    """List open tickets for a component. Use when triaging or planning work."""
    return query_tracker(status="open", component=component)

@mcp.tool()
def last_deploy(service: str) -> dict:
    """Return the last deploy's status and commit for a service."""
    return read_deploy_log(service)

if __name__ == "__main__":
    mcp.run(transport="stdio")          # host launches this as a subprocess

Each @mcp.tool() registers a typed function whose docstring is the routing hint Claude reads to decide when to call it. Written once and committed, the server lets any teammate's Claude query tickets and deploys through the same standard tools — write-once, reuse-everywhere.

Exercise 4 · Milestone 4 — a least-privilege reviewer subagentExpert

Context: A focused subagent does one job with exactly the access that job needs. A code reviewer that can edit files or run shell commands is a liability; narrowing it to read-only is the entire point.

Your task: Define a code-reviewer subagent spec that is read-only on files and outputs findings grouped by severity, then reason about why narrowing its permissions is the design goal.

Requirements:

  • A Markdown subagent spec with a clear name and a single purpose
  • Behaviour: analyse the diff for correctness and group findings by severity
  • Tooling restricted to read-only — no edits, no shell
  • An explicit, actionable output format (findings grouped critical/warning/note)
  • Explain least-privilege: one job, minimum access, smaller blast radius

💡 Hint: Ask what a reviewer must NOT be able to do — the answer (write files, run commands) is exactly what you leave out of its tool list.

Show solution

The subagent definition (this is .claude/agents/code-reviewer.md — Markdown spec, not code):

# Code Reviewer

A focused subagent for reviewing diffs. Least-privilege: read-only on files.

Behavior:
- Analyze the diff strictly for correctness.
- Group findings by severity: critical (must fix), warning (should fix),
  note (nice-to-have).
- Output markdown with line-by-line references.

Tools: Read only. No Edit, no Bash. It reviews; it does not change code.

A subagent is a narrow specialist with its own least-privilege permissions — read-only here, so a reviewer can never edit or run anything. Scoping it tightly is the safety point: it does exactly one job with exactly the access that job needs, and nothing more.

Exercise 5 · Milestone 5 — automate the review in CI (needs API key)Professional

Context: The same subagent that helps you interactively should guard every pull request headlessly. A GitHub Action runs the reviewer on each PR diff, with the API key coming from secrets — never inlined.

Your task: Show a GitHub Actions workflow that runs the reviewer subagent on every PR's diff via the headless claude -p invocation, reading the API key from secrets. Mark this rung as needing an API key.

Requirements:

  • Trigger the workflow on pull-request events
  • Check out with full history so the PR diff can be computed against main
  • Read the API key from repo secrets — never inline it in the YAML
  • Compute the PR diff and pass it to a headless claude -p run
  • Instruct the run to use the code-reviewer subagent and group findings by severity
  • Emit the findings into the CI logs

💡 Hint: Headless means no chat window: claude -p "..." with the diff as input, and the prompt is what points it at your subagent.

Show solution

Headless review in CI — needs the Claude Code CLI + ANTHROPIC_API_KEY secret (this is a GitHub Actions YAML):

name: Claude review
on: [pull_request]
jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - env:
          ANTHROPIC_API_KEY: "${{ secrets.ANTHROPIC_API_KEY }}"   # never inline
        run: |
          git diff origin/main...HEAD > /tmp/diff.txt
          claude -p "Use the code-reviewer subagent on /tmp/diff.txt. \
            Output findings grouped by severity." > review.md
          cat review.md

The same reviewer subagent runs interactively for a developer and headlessly (claude -p) on every PR — one encoded judgment, two entry points. The key comes from CI secrets, never the file, so the automation stays safe to commit and share.

Exercise 6 · Milestone 6 — ship the workbench and verify the 4 DsIndustry scenario

Context: As tech lead, the leverage is institutional: commit the whole workbench so the team inherits your judgment. This milestone verifies every piece is present and maps each to one of the 4 Ds (Delegation, Description, Discernment, Diligence).

Your task: Write a completeness check that verifies every workbench piece is present and maps each to the 4 D it serves, returning whether the workbench is ready and what's missing.

Requirements:

  • Enumerate the pieces: CLAUDE.md, permissions, Stop hook, Skill, subagent, MCP server, CI review
  • Map each piece to the D it serves (Delegation / Description / Discernment / Diligence)
  • Take a repo-state record and return a ready flag plus a list of missing pieces
  • List missing pieces in human-readable form (piece + the D it serves)
  • Run it on a complete repo and a partial repo to show it catches gaps
  • Explain the leverage: committing .claude/ makes your judgment enforceable team-wide

💡 Hint: A dict mapping each piece to its D, plus a comprehension that collects pieces the repo lacks, gives you both the verdict and the punch-list in one pass.

Show solution

The completeness gate mapped to the 4 Ds (pure stdlib, runnable):

PIECES = {                       # piece -> which of the 4 Ds it serves
    "claude_md":            "Description  (intent travels with the repo)",
    "settings_permissions": "Delegation   (allow safe, deny risky)",
    "stop_hook":            "Discernment  (tests verify every change)",
    "skill":                "Description  (house conventions encoded)",
    "subagent":             "Delegation   (least-privilege specialist)",
    "mcp_server":           "Delegation   (domain tools, write-once)",
    "ci_review":            "Diligence    (automated, on every PR)",
}
def workbench_ready(repo):
    missing = [f"{k}: {d}" for k, d in PIECES.items() if not repo.get(k)]
    return (not missing), missing

full = {k: 1 for k in PIECES}
print("ready:", workbench_ready(full)[0])          # True
partial = dict(full); partial["ci_review"] = 0
print("missing:", workbench_ready(partial)[1])     # Diligence gap

Industry scenario: ten engineers each configure Claude locally and inconsistently. Committing the .claude/ tree + MCP server makes the workbench institutional leverage: your judgment, encoded once, enforced for everyone. The 4 Ds are the checklist — delegate with scoped permissions, describe intent in CLAUDE.md/Skills, discern quality with hooks, and stay diligent with CI review.

✓ Checkpoint — you can move on when you can…

  • Assemble CLAUDE.md, settings+hook, Skill, subagent, MCP server.
  • Automate verification with a Stop hook and CI review.
  • Explain where each of the 4 Ds shows up.
  • Ship the workbench so the team inherits it.
📋 Grade your workbench — will the whole team inherit it safely?
DimensionMeets the barAbove the bar (staff)
Tooling completenessThe repo has CLAUDE.md, a Skill, a subagent, and an MCP server — each present and doing one clear job.The pieces compose: the subagent uses the Skill and MCP tools, and a fresh git pull gives a teammate the whole working setup.
Permission & safety configsettings.json scopes an allow-list and a deny-list; risky actions (git push, vendor edits) are denied so deny wins over allow.Permissions are genuinely least-privilege, the deny-list is defended against footguns, and dangerous actions stay in human hands by design.
MCP tool qualityThe MCP server exposes project tools with clear docstrings and typed signatures Claude can route to correctly.Docstrings are written as routing hints (a vague one picks the wrong tool), and the tools are scoped to what the workbench actually needs.
CI review automationA CI workflow runs a headless Claude review on every PR with the API key read from secrets, output grouped by severity.The same subagent is reused interactively and headlessly, secrets never touch the file, and the review output is actionable in the PR.
VerifiabilityA completeness check (Stop hook / workbench_check.py) proves every required piece is present.The check is a real gate in CI, so an incomplete workbench fails the build rather than shipping half-configured.
Ship to the team & the 4 DsThe whole .claude/ tree + MCP server is committed so teammates inherit it; you can place each of the 4 Ds (Delegation, Description, Discernment, Diligence).The workbench is institutional leverage: your judgment is encoded once and enforced automatically for every engineer's Claude, verifiably.

Score each dimension 0 (missing), 1 (meets bar), or 2 (above bar). 0–4: keep building. 5–8: a solid, defensible submission. 9–12: staff-level — you could hand this to a reviewer and defend every call. Any dimension at 0 blocks shipping regardless of the total.

Knowledge check check yourself

✓ Knowledge check

Why is git push placed on the deny list in settings.json rather than simply omitted from the allow list?

Show answer
Deny always wins over allow, so an explicit deny guarantees the risky action stays in human hands even if a broader allow pattern would otherwise permit it. It encodes Delegation/Diligence: dangerous actions cannot be taken autonomously by design.
✓ Knowledge check

Why does committing the whole .claude/ tree plus the MCP server give more leverage than each engineer configuring Claude locally?

Show answer
Because a single git pull makes every teammate inherit the same steering (CLAUDE.md), limits (permissions/deny-list), Skills, subagents, and tools — your judgment is encoded once and enforced automatically across the team, instead of relying on each person to set it up.
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in