Onboarding Claude Code Harness: The Hard Way
Documentation discipline done right

Search for a command to run...
Documentation discipline done right

No comments yet. Be the first to comment.
A 502 Bad Gateway tells you that one proxy failed to get a valid response from another system. It does not tell you which layer failed, whether the application ever saw the request, or which timeout a

Cilium eBPF connection tracking, and how SNAT quietly turns stateless traffic into stateful

In Part 1 we got a verified ETCD snapshot back onto an Ansible control host, even with the cluster fully down. I've come across many a blog posts describing ETCD restoration process on a single node,
Part 1: Notes on taking frequent ETCD snapshots, and setting up an automated workflow to getting one back when the control plane is down and kubectl returns nothing but errors.
Notes From The Platform Layer
17 posts
Notes from the platform layer - distributed systems, production K8s, and the architecture decisions and trade-offs learnt the hard way. Increasingly at intersection of platform engineering and agentic AI: building real agents focused on reducing toil, increasing productivity and faster turnaround times.
I've been running Claude Code daily for exploratory and experimental work driver for a little while now, and the single biggest realization I've had is this:
Claude model is not the product. The harness is.
The model you get is the same as everyone else. What possibly makes it feel like a _seasoned_ senior colleague is the machinery config. around the model: what loads into context - always or as-required, when it loads, and what gets enforced rather than merely suggested.
The best mental model I've found is onboarding. You can't drop a new hire into a codebase with zero docs. and expect them to be productive from day one.
This post is my WIP notes on how to onboard it properly, written partly so I could come back and refresh my own memory, and possibly for other enggineers who are new and are looking for technical hygiene before they start.
A lot of content out there incorrectly (personally) describes memory files as "the system prompt" for your agent. According to the docs, CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. This matters -
it explains why compliance is probabilistic. Claude reads your CLAUDE.md and tries to follow it, but there is no guarantee of strict adherence, especially for vague or contradictory instructions. Claude's own docs are blunt about this. For example -
Second, it tells you where the real system prompt hook is. If you genuinely need instructions at the system prompt level, pass them at startup.
So CLAUDE.md is essentially context that shapes behavior.
I've done my best - as of June 2026 - to arrange up-to-date info., but it may get out-dated by the time you're reading this blog.
Claude Code reads memory files from several locations, each with a different scope:
| Scope | Location | Purpose | Use case examples | Shared with |
|---|---|---|---|---|
| Managed policy | • macOS: /Library/Application Support/ClaudeCode/CLAUDE.md,• Linux and WSL: /etc/claude-code/CLAUDE.md |
|||
• Windows: C:\Program Files\ClaudeCode\CLAUDE.md |
Organization-wide instructions managed by IT/DevOps | Company coding standards, security policies, compliance requirements | All users in organization | |
| User instructions | ~/.claude/CLAUDE.md |
Personal preferences for all projects | Code styling preferences, personal tooling shortcuts | Just you (all projects) |
| Project instructions | ./CLAUDE.md or ./.claude/CLAUDE.md |
Team-shared instructions for the project | Project architecture, coding standards, common workflows | Team members via source control |
| Local instructions | ./CLAUDE.local.md |
Personal project-specific preferences; add to .gitignore |
Your sandbox URLs, preferred test data | Just you (current project) |
The two-tier "global plus project" advice I've seen in YT videos is a tad-bit over-simplification.
Your user-level file at ~/.claude/CLAUDE.md is where personal preferences live:
formatting quirks you hate,
tooling shortcuts,
style opinions that follow you across every repo.
The project file is where the team's collective knowledge lives: build commands, architecture, terminology, testing conventions.
The official guidance gives you the actual target size for CLAUDE.md: keep under 200 lines. Longer files consume more context on every single request and, more importantly, potentially reduce adherence.
A bloated memory file doesn't just cost tokens; it makes the model worse at following rules - instructions may get lost in the noise.
Claude Code discovers memory files by walking up the directory tree from your working directory to the fs root, collecting every CLAUDE.md and CLAUDE.local.md along the way, and that gets loaded in full at launch.
What I really found interesting was to learn that the files don't override each other, instead they are concatenated into context, ordered from the root down to your working directory.
so the instructions "closest" to you are the last thing the model reads.
Within your project dir., CLAUDE.local.md is appended after CLAUDE.md. This also suggest lower-level instructions like CLAUDE.local.md might get dropped first it the context fills up.
Files in subdirs. below the working directory behave differently: they load lazily, only when Claude actually reads a file in that subdirectory consuming 0 tokens before the agent walks into it.
Between "always loaded" CLAUDE.md and "loaded on demand" skills sits .claude/rules/, and I personally didn't find a lot of content on them as of June 2026. For example -
---
paths:
- "src/api/**/*.{ts,tsx}"
---
# API rules
- All endpoints must include input validation
- Use the standard error response format
A rule with paths loads only when Claude reads files matching the glob.
So the way I've understood is that a fact that is needed every session goes in CLAUDE.md. Where as a convention tied to a file type or directory goes in a path-scoped rule. A multi-step procedure goes in a skill.
Treat the project CLAUDE.md as the teams' accumulated corrections.
Add an entry when Claude makes the same mistake a second time
For example, when code review catches something it should have known about this codebase, or when you notice yourself typing the same clarification you typed last session.
Every correction you document is a mistake the whole team stops paying for.
Newer Claude Code versions also close this loop automatically. Auto memory lets Claude write notes to itself in ~/.claude/projects/<project>/memory/, keyed to the git repo so all worktrees share it.
Long sessions eventually hit auto-compaction so knowing what survives is worth a lot of debugging time: your project-root CLAUDE.md is re-read from disk and re-injected after /compact. Nested CLAUDE.md files are not; they reload only the next time Claude touches a file in their subdir.
Instructions given purely in conversation are the most fragile thing you have. If something mattered enough to say twice, it belongs in a file.
Everything in CLAUDE.md is a tax on every request, whether or not it's relevant to the task. For example, an e2e testing protocol is 100 lines that matter in maybe 1 session out 20. Skills solve this with progressive disclosure.
A skill is a directory containing a SKILL.md with YAML frontmatter and markdown instructions:
---
description: Run the full e2e suite against a staging deploy. Use when the
user asks to verify a release candidate or run end-to-end tests.
---
1. Build with `pnpm build:staging`
2. Deploy the preview with `./scripts/preview.sh`
3. Run `pnpm e2e --env staging`, retry flaky tags once
4. Post the summary; never mark green with skipped suites
At session start, only the description of each skill enters context so Claude knows what's available.. The full body loads only if/when required - Claude matched your request to the description or you invoked it directly as /skill-name.
Anthropic's guideline is to keep SKILL.md under 500 lines and push heavy reference material into supporting files in the same directory, which Claude reads on demand with its normal file tools.
Skills live in ~/.claude/skills/<name>/SKILL.md for personal ones and .claude/skills/<name>/SKILL.md for project ones, with plugin and enterprise tiers above that.
A handful of fields turn skills from "saved prompts" into real workflow machinery.
disable-model-invocation: true makes a skill user-only. Claude can't trigger it, and its description doesn't even load into context, so it costs zero tokens until you type the slash command.
allowed-tools pre-approves specific tools while the skill is active which kills the permission-prompt friction for well-scoped workflows. context: fork runs the skill in a forked subagent context.
Once invoked, a skill's content enters the conversation as a message and stays there, so mid-session edits to an already-loaded skill don't take effect until you re-invoke it. Under auto-compaction, Claude Code re-attaches the most recent invocation of each skill after the summary.
It helps to see the whole extension surface priced in context terms, because the features form a spectrum from always-on to zero-cost:
| Feature | Loads | Steady-state cost |
|---|---|---|
| CLAUDE.md | Session start, full content | Every request |
| Rules (path-scoped) | When matching files are read | Only in relevant sessions |
| Skills | Descriptions at start, body on use | Low until invoked |
| MCP servers | Tool names at start, schemas deferred | Low until a tool is used |
| Subagents | Spawned with fresh context | Isolated from your window |
| Hooks | Run externally on events | Zero unless they return output |
My key takeaway - when a side task will read bunch of files and you only care about the conclusion, route it through a subagent so the research happens in a disposable context window and only the summary lands in yours.
Skill registries have exploded. The npx skills CLI is the one referenced in most talks, but to some this may set off some alarms due to the spectre of supply chain attacks.
The dynamic injection syntax means shell commands in a SKILL.md execute on your machine the moment the skill loads, before the model sees anything potentially leading to bad things.
So a SKILL.md is short. Read it, and read every script it ships, before it ever loads in a session.
There's a second, quieter failure mode: performance. More starts signals nothing about quality, and some widely-shared skills might make your agent worse, padding context with verbose instructions that dilute your own conventions while producing no better output - overlapping descriptions make claude load the wrong skill or miss the right one.
So my standing rule, which I happily borrowed from some of the YT talks: never install a skill that hasn't published evidence it works, and when in doubt, write your own after taking inspiration from a 3rd paty one, if required.
If you're worried about what any skill, or the model itself, might do, don't encode the boundary in prose. A "never do X" line in CLAUDE.md is a request. A PreToolUse hook that blocks the tool call, or a permissions.deny rule in settings, is a guarantee, enforced by the harness.
Prose for guidance, hooks and permissions for guardrails.
If I compress everything above into a ramp-up procedure for a new repo, it looks like this.
Run /init and let it draft a project CLAUDE.md, then prune it toward the 200-line target, keeping only facts every session needs.
Keep your ~/.claude/CLAUDE.md short and purely personal.
When corrections recur, write them down: repeated mistakes go into CLAUDE.md, file-type conventions into path-scoped rules, and any section that has grown into a procedure gets extracted into a skill.
Mark side-effecting skills disable-model-invocation: true.
Move hard boundaries out of prose and into hooks and permission rules.
Audit context occasionally with /memory and /context, and
treat every third-party skill as unreviewed code running with your creds.
None of this is glamorous. Documentation hygiene done right to a colleague who forgets everything overnight but reads at superhuman speed every morning!
References: