Building Your Own Agentic Development Environment
Chapter 10 introduced the features; this page assembles them into an environment a team can share: custom skills, an MCP server you write yourself, hooks and automation, external tools, project instructions, a plugin to package it all, and the permission and enterprise controls that keep it safe. The MCP server is real code, tested by speaking the protocol to it; the plugin and managed-settings files were validated; the Claude Code wiring is described from the documentation.
jq/YAML validation of the plugin manifest, MCP config, managed-settings file and skill frontmatter. Not executed: connecting the server to Claude Code (that would change your Claude configuration), installing the plugin, deploying managed settings, or any live session. So "Claude Code will call this tool" is documented behaviour, not something observed here.Layers of an Agentic Environment
Treat the environment as layers, from what the whole organisation fixes to what one developer adds. Each layer has a place it lives and a person who owns it.
Anthropic's documentation describes how these combine: CLAUDE.md files are additive; skills and subagents override by name (managed over user over project for skills); MCP servers override by name (local over project over user); hooks merge so every registered hook fires; and managed settings apply above every other level (Source 1, Source 2). Design with that in mind: put non-negotiable rules at the managed layer, shared conventions in the project, and personal taste in your own files.
Custom Skills, Beyond the Basics
Chapter 10 showed a skill with a pre-approved tool and a ! command. The frontmatter has more levers (Source 3):
| Field | What it buys you |
|---|---|
context: fork with agent | Runs the skill in a subagent, so its reads stay out of your conversation |
disable-model-invocation: true | Only you can start it — right for anything with side effects |
user-invocable: false | Hidden from the / menu; Claude can still use it as background knowledge |
paths | Glob patterns limiting when Claude loads it automatically |
argument-hint, $ARGUMENTS | Takes input: /explain-endpoint GET /api/books/{id} |
hooks | Registers hooks only while the skill is active |
What that does and does not prove: the file is syntactically valid and uses only documented fields. It does not prove Claude selects it appropriately. Descriptions drive automatic loading, so write them with the words a request would contain; and keep the count of skills manageable — names always load, and when there are many, some lose their descriptions (Source 4).
Write Your Own MCP Server
A skill teaches Claude how to use something; an MCP server gives it a tool. The protocol is smaller than it looks. In the stdio transport the client launches your server as a subprocess; messages are single-line JSON-RPC 2.0 objects on standard input and output; and the server may log to standard error but must write nothing else to standard output (Source 5).
The spec requires the client to open with initialize (protocol version, capabilities, client info), the server to answer with its own, and the client to follow with a notifications/initialized notification before normal operation. Tools are discovered with tools/list and invoked with tools/call; a result carries content blocks and an isError flag. The spec also says tool execution errors belong in the result with isError: true so a model can self-correct, while unknown tools and malformed requests are JSON-RPC protocol errors (Source 5). Here is a complete server, about 40 lines, with no SDK, exposing one read-only tool backed by Chapter 11's feature_list.json:
You can test a server without any client by piping the protocol into it. This is the same exchange as the diagram, followed by a call to a tool that does not exist:
What it proves: the server follows the message shapes in the specification, including the -32602 "Unknown tool" error the spec itself shows as its example. What it does not prove: that a given Claude Code version can connect to it — I did not register it, because claude mcp add writes to your configuration. To register it for a project, the docs give this shape (stdio servers need no url):
.mcp.json, and approvals committed to a repository do not count until you trust the workspace (Source 6). A local stdio server runs outside Claude Code's Bash sandbox, with your privileges (Source 7). Keep a tool read-only unless writing is the point, validate every argument, and treat what comes back from other servers as untrusted input. The MCP specification itself says there should always be a human in the loop with the ability to deny tool invocations (Source 5).Hooks and Automation
A hook is the right place for anything that must happen without the model's cooperation. Beyond the two in Chapter 10, Anthropic's docs and best-practices page show these patterns (Source 8, Source 9):
| Goal | Event | Shape |
|---|---|---|
| Format every file Claude edits | PostToolUse, matcher Edit|Write | A command that reads tool_input.file_path from the JSON on stdin and runs your formatter |
| Block edits to a protected folder | PreToolUse | Exit code 2 when the path is under that folder |
| Refuse to finish on a failing build | Stop | ./mvnw -B -q test 1>&2 || exit 2 |
| Give a new session its bearings | SessionStart | Text the hook prints to stdout is added to Claude's context |
| Quality gates for teammates | TeammateIdle, TaskCreated, TaskCompleted | Exit 2 to keep a teammate working or to block task creation/completion |
./mvnw will make the agent unusable.- Prefer deterministic handlers (
command,http) for enforcement.promptandagenthooks ask another model to decide and are not deterministic; theagenttype is experimental. AddonFailure: "block"when the action should also be stopped if the hook itself crashes or times out (Source 9). - Hooks run with your privileges and outside the sandbox. Review hook scripts in anything you did not write.
External Tool Integration
| You need… | Prefer | Why |
|---|---|---|
| GitHub, AWS, cloud CLIs | The CLI (gh, aws) | No per-tool listing in context; Claude can run --help on an unfamiliar one (Source 9, Source 10) |
| A system with no CLI (tracker, dashboard, internal API) | An MCP server | Purpose-built tools; connection and auth handled by the server |
| Your own program that drives Claude | The Agent SDK (claude -p, Python, TypeScript) | Same tools and agent loop, with orchestration under your control |
| Typed-language navigation | A code-intelligence plugin | Definitions, references and type errors without scanning files |
One cost note that shapes the choice: connected MCP servers add their tool names and instructions to context even when idle (full schemas are deferred), so disable servers you are not using via /mcp (Source 10).
Project Instructions and Reusable Packaging
When the same setup is needed in several repositories, or you want versioned releases and updates, package it as a plugin: a directory of components that Claude Code installs and loads as one unit, with a manifest at .claude-plugin/plugin.json giving it a name (Source 11). A plugin can hold skills, agents, hooks, MCP servers and more. Here is bookshelf's, assembled from files already on this page and validated:
- Namespacing: plugin skills run as
/plugin-name:skill-name, so they cannot collide with project skills (Source 11). - Scopes: install at user scope (you, every project), project scope (everyone in the repo, through committed
.claude/settings.json; each person still installs it) or local scope. Cloud sessions do not load local plugins. - Cost: an enabled plugin is part of every session: the names and descriptions of its model-invocable skills and agents sit in context each turn, and its MCP servers and hooks run alongside. Check the footprint before installing; the
/plugininterface shows a context-cost estimate for official-marketplace plugins. - Trust: what a plugin runs, it runs as you. Plugins from any marketplace can run code with your privileges, so review them first.
- Not included on purpose: hooks. The plugin docs say plugins can carry hooks, but the path conventions for a plugin's hook scripts were not verified for this page, so the example omits them rather than guess.
Skills in repositories can also be run in CI: check out the repository, then pass the skill as the action's prompt (Chapter 11). Publishing and marketplaces are covered in Anthropic's plugin docs; hosting your own marketplace for a team is a marketplace.json catalogue you control.
Agent Permissions and Isolation
Autonomy needs a boundary the model cannot argue with. Anthropic's docs offer three, and they stack (Source 12, Source 7, Source 13):
- Permission rules (deny → ask → allow, first match wins) are enforced by Claude Code, not the model, and are shareable in
.claude/settings.json. - The sandbox is an OS-enforced boundary around Bash (and PowerShell and Monitor) commands and their subprocesses: macOS uses Seatbelt, Linux and WSL2 use bubblewrap with a proxy relay; native Windows is not sandboxed. It is off by default (
/sandboxor"sandbox": {"enabled": true}). Two gaps matter: reads are allowed across most of the machine by default, including credential files such as~/.sshand~/.aws/credentials, until you restrict them; and failed commands can be retried unsandboxed unlessallowUnsandboxedCommandsis false. - A container or VM puts the whole process behind one boundary. The dev-container page's own warning: with
--dangerously-skip-permissions, a container does not stop a malicious project from exfiltrating anything accessible inside it, including Claude Code credentials in~/.claude; use it only with trusted repositories and avoid mounting host secrets such as~/.ssh.
Enterprise Considerations
Managed settings are what an organisation deploys to every machine; Claude Code applies them above every other level, so no user, project or local value overrides them, apart from a few security-sensitive exceptions where a stricter lower value still counts (Source 14).
| Delivery route | How | When read |
|---|---|---|
| Server-managed settings | claude.ai admin console (or a self-hosted Claude apps gateway) | Fetched at startup, polled hourly |
| MDM / OS policy | macOS configuration profile or Windows HKLM registry value (Jamf, Intune, Group Policy…) | At startup; checked every 30 minutes |
| File-based | managed-settings.json in a system directory | At startup; reloaded on change |
Windows HKCU | User-level registry value | Used only when no admin document is present above it |
File locations: /Library/Application Support/ClaudeCode/managed-settings.json (macOS), /etc/claude-code/managed-settings.json (Linux and WSL) and C:\Program Files\ClaudeCode\managed-settings.json (Windows). By default Claude Code uses one managed source and ignores the others; the page documents the order and an opt-in to combine them. Cloud sessions in Anthropic-hosted environments do not read a device's MDM profile or file, so policy for them must come from server-managed settings.
permissions.disableBypassPermissionsMode: "disable"stops engineers using--dangerously-skip-permissionsat all.forceLoginMethodandforceLoginOrgUUIDrestrict which accounts can sign in;allowedProviderslists which services a managed machine may reach Claude through (the Anthropic API, Amazon Bedrock, an LLM gateway…). With these set, anANTHROPIC_API_KEYenvironment credential is blocked at startup, because organisation membership cannot be verified for it (Source 15).- Policy a repository file can quietly change is not policy. The dev-container page warns that policy placed in a repository Dockerfile can be removed by anyone with write access; for policy engineers cannot bypass, use server-managed settings or MDM.
- Cost and observability: OpenTelemetry export gives per-user metrics on every setup; Teams and Enterprise have spend limits at organisation, group or member level; Console organisations use workspace limits (Source 16).
- Data handling: telemetry and error reporting can be disabled individually (
DISABLE_TELEMETRY,DISABLE_ERROR_REPORTING) or together withCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC(Source 17) — covered in Chapter 13. - Plugins at scale: managed settings can allowlist or block marketplaces, force-install plugins and turn off session-only loading.
The bookshelf Environment, End to End
| Layer | What bookshelf has | Status |
|---|---|---|
| Instructions | CLAUDE.md (commands, conventions, gotchas) | Written (Ch 10) |
| Guardrails | Deny rules; PreToolUse hook (3 tests run); Stop hook; scripts/verify.sh (budget gate run) | Hook and gate executed |
| Procedures | /verify-build, /explain-endpoint skills | Written; frontmatter validated |
| Review | sql-reviewer subagent | Written |
| Tools | Own MCP server (bookshelf-features) | Protocol exchange executed |
| Automation | GitHub Actions test + review workflow | Parsed, not run |
| Packaging | bookshelf-kit plugin (skill, agent, MCP) | Manifest and JSON validated |
| Organisation policy | managed-settings.json sketch | JSON validated; not deployed |
Read the last column as the honest summary of this chapter. The environment is a set of small, inspectable files; the parts that could be exercised without a live Claude session were; the parts that depend on Claude Code's runtime behaviour are as documented, and the first thing to do when adopting any of it is to try it in a throwaway repository and watch it work.
Building the Environment
Key Takeaways, Exercises and Sources
- Think in layers: organisation policy, plugins, project files, personal files, session.
- Skills teach how; MCP servers provide tools. A stdio MCP server is a short program that speaks JSON-RPC.
- Test servers and hooks without a client: pipe in the protocol or the hook JSON and check the output.
- Prefer CLIs for systems that have them; use MCP for those that do not.
- Stack the boundaries: permission rules, sandbox, container — each covers different things.
- Enterprise policy must live outside the repository (server-managed or MDM) to be policy.
Exercise 1 Beginner
Run the MCP protocol test from Section 3. Then change the server so feature_status also reports the count of failing features, and re-run the test to confirm the new text.
Learning outcome: see a tool's whole lifecycle with no client involved.
Exercise 2 Intermediate
Add a second tool, list_failing_features, with an inputSchema that takes an optional limit. Make it return an error result (isError: true) for a negative limit rather than a protocol error, and explain from the spec why that is the right category.
Learning outcome: distinguish tool execution errors from protocol errors.
Exercise 3 Advanced
Write a managed-settings policy for a fictional team of 20 developers: what you deny, how logins are restricted, which providers are allowed, and which delivery route you would use. For each key, name the failure it prevents and how you would verify it is enforced.
Learning outcome: design policy that is enforceable, not merely documented.
- Anthropic, Extend Claude Code — how features layer; context cost.
- Anthropic, Deploy managed settings — precedence, delivery mechanisms, file locations. Read in part (the page is long).
- Anthropic, Skills — frontmatter fields, locations, invocation.
- Anthropic, Monorepos and large codebases — skill discoverability and description truncation.
- Model Context Protocol, specification revision 2025-11-25, Lifecycle, Transports and Tools pages (raw sources in the specification repository). The project's website was not reachable from this environment, so the GitHub sources were read instead; a newer revision may exist.
- Anthropic, MCP — scopes,
.mcp.json, approval, security. - Anthropic, Sandboxing — what is isolated, platforms, limitations, what it does not cover. The last ~7,500 characters of the page were not read.
- Anthropic, Hooks — events, handler types, exit codes.
- Anthropic, Best practices — hook patterns, CLIs versus MCP, deterministic enforcement.
- Anthropic, Manage costs — MCP overhead; prefer CLI tools.
- Anthropic, Plugins overview — components, manifest, scopes, cost, marketplaces.
- Anthropic, Permissions — rule evaluation, enforcement by Claude Code.
- Anthropic, Development containers — setup, warnings, policy in a container.
- Anthropic, Deploy managed settings (as above).
- Anthropic, Authentication —
forceLoginMethod,forceLoginOrgUUID,allowedProvidersbehaviour with API keys. - Anthropic, Manage costs — organisation spend controls and OpenTelemetry.
- Anthropic, Data usage — telemetry opt-outs.
Executed on this machine, 2026-10-30: the MCP protocol exchange with Node v24.15.0 and jq; PyYAML parse of skill frontmatter; jq validation of the plugin manifest, .mcp.json and the managed-settings file. Not executed: connecting the server to Claude Code, installing the plugin, deploying managed settings. The managed-settings keys shown were each named in the cited pages; the file as a whole was not checked against a live deployment.