I run Claude Code with two separate profiles, one personal and one for work, and each keeps its own memory. In my personal profile, memory is mostly corrections: times I told Claude it got something wrong or did something in a way I didn’t like, saved as a rule so I never have to say it again. My work profile went a different direction. None of its twelve memory files is a correction. Ten are reference notes on the systems that run the network, one records a project constraint, and the last is just a two-line pointer to a skill. That skill started out as a memory.

12memory files
0corrections
6skills
10 reference notes
1 project constraint
1 pointer to a skill
The work profile's twelve memory files. None of them is a correction, and the last is a two-line pointer to a skill that started out as a memory.

That last file is the whole story. Memories and skills look like separate features, but in practice they’re two stages of the same artifact.

What earns a place in memory

The memory index loads into every session, and the files behind it get pulled in whenever a task touches them. Anything in memory pays rent in context. That forces a discipline: memory is for dense, durable facts that change how the agent reasons, not for documentation it could look up on demand.

Context window
Every session
MEMORY.md indexone line per file6 skill descriptionswhat each one is for
When a task touches it
Memory filethe facts themselves
When a description matches
SKILL.mdthe instructions
Never loaded
Scriptsrun in the shell only their output comes back
Everything in memory pays rent in context. The index and the skill descriptions load in every session, and bodies load only on demand. Scripts never enter context; only their output does.

At work, that means the gotchas. The stack is NetBox as the source of truth, Arista’s management platform, a Prometheus-compatible metrics store, Kibana for logs, a flow analytics cluster, and Grafana. Each one has behavior that’s invisible until it bites:

  • Latency in the metrics store is reported in microseconds. Read it as milliseconds and every link looks three orders of magnitude worse than it is.
  • One standard metrics API endpoint always returns empty. The query endpoints work.
  • Some routing state is only exposed through the management platform’s streaming API. The REST path returns an empty result rather than an error, which is worse than failing outright.
  • One of the platform’s query APIs returns a generic “forbidden” to every service token. It isn’t an RBAC problem, and no amount of permission-chasing will fix it.
  • NetBox software version fields drift. For running state, the management platform is authoritative.
  • The flow index is enormous. Aggregations must be bounded by a time window, and raw document pulls are off the table.
  • The hostname is the join key across all of it: NetBox, metric labels, the platform, the logs.

This is tribal knowledge, the kind a senior engineer carries around and a new hire absorbs over months. In memory, every session starts with it.

Silent failures are the real target

The memories that pay off most guard against plausible-looking wrong answers. Loud failures get noticed on their own; quiet ones get reported as findings.

Absence of evidence. An empty log search reads as a healthy device. But one network segment logs to a separate index with a different schema, and some devices don’t ship logs to either. The memory forces a distinction between “no events” and “no telemetry,” so a coverage gap gets reported as a coverage gap instead of a false all-clear.

0 hitsLog search for the device
Does this device log to this index?
Yes
No eventsReport it healthy
No
No telemetryReport a coverage gap
Its segment logs to a separate index, with a different schemaIt doesn't ship logs at all
An empty log search can mean two different things. Without the memory, both come back as an all-clear.

TLS behind an internal CA. The intuitive fix, pointing the Grafana CLI’s own CA option at the internal certificate, corrupts it. The standard command-line TLS check then compounds the confusion with a self-signed error, because it doesn’t consult the OS trust store. The memory short-circuits the loop: trust the CA once at the OS level, leave the CLI option alone, and validate with the CLI’s own check.

Policy as a constraint. This is the only memory that records an actual incident. I tried to add read scopes to our team chat integration, and company policy blocked them. It’s now a project memory: any approach that depends on chat history is out of scope, so use the issue tracker or ask me to paste the thread. Without it, every session proposes the same dead end, because on paper it’s the obvious design.

Explicit escalation boundaries

Two notes exist purely to mark where the agent’s autonomy ends. Chat tokens rotate roughly every 12 hours and raw API calls don’t refresh them, so on expiry Claude asks me for a new one. If the password manager’s CLI can’t see any accounts, a desktop setting is off that only I can change. Without those boundaries, an agent will burn a lot of tokens creatively attacking a problem that needs a human. Encoding the handoff point is cheaper than any amount of retry logic.

Promotion: memory to skill

The pointer file started life as a large memory: the platform’s full API catalog, with packages, services, and the device state tree. That’s the wrong shape for memory twice over. It’s procedural reference rather than a fact, and it’s a hand-copied snapshot of something that changes whenever the vendor ships. In networking terms, it was a cache with no TTL.

So it became a skill. The catalog moved in alongside a script that regenerates it from the live API, and the memory collapsed to a two-line pointer. The rule I took from it: never hand-maintain anything you can derive from the source.

The rest of the reference notes followed. Each one had held connection details and example calls, and every session rebuilt the same plumbing from them: auth, token handling, pagination, the quirks. That’s exactly the work that should be deterministic. I promoted all of them to script-backed skills in a single day, and each memory is now a pointer plus the handful of facts that still shape reasoning. The scripts own the plumbing; the model owns intent and synthesis. The management platform skill also absorbed a set of standalone scripts I’d been running by hand, now with token retrieval and hostname resolution built in.

Before
memory file
Facts that shape reasoningstays
Connection details→ scripts
Example calls→ scripts
API catalog, hand-copied→ derived
Rebuilt into plumbing every session. The catalog is a cache with no TTL.
After
memory file
Pointer to the skill
Facts that shape reasoning
skill
SKILL.mddescription + instructions
Scriptsauth, tokens, pagination, quirks
API catalog↻ regenerated from the live API
Scripts own the plumbing. The model owns intent and synthesis.
One promotion. Facts that shape reasoning stay in memory, the plumbing every session used to rebuild becomes scripts, and the hand-copied catalog becomes one a script regenerates from the live API.
Skill Scope
Source of truth (NetBox) Device location, cabling, IP ownership, prefix, VLAN, and VRF membership
Management platform (Arista) Inventory, software versions, events and change history, live routing and multicast state
Log search (Kibana) Device syslog, logins, and security events, routed to the right index per device
Flow analytics Top talkers, peer relationships, conversations by port, traffic over time, anomaly detection
Metrics (Prometheus-compatible) Reachability, latency, interface throughput and utilization, errors and discards
Device report All of the above for one device, verdict first

Composition

The device report is the payoff. It takes a single hostname and fans out across the other five: the NetBox record, health metrics, the running software version from the platform, recent logs and logins, and optionally flows. It leads with a verdict (healthy, degraded, or down) and then the supporting detail.

hostnamejoin key, defined in memory
Device report
NetBoxthe record: location, cabling, IPs
Metricshealth: reachability, latency, errors
Arista platformthe running software version
Kibanarecent logs and logins
Flow analyticsflowsoptional
Verdict firsthealthydegradeddownthen the supporting detail
The device report is a federated query keyed on hostname. It works because the join key was written into memory before any of these skills existed.

It’s effectively a federated query keyed on hostname, and it only works because the join key was written down in memory before any of the skills existed. The memory layer defined the data model; the skill layer executes against it.

Negative routing

Skills are progressively disclosed: only the description sits in context until a task matches, which makes the description a routing function. A description that only says what a skill does is tuned for recall. With six skills that all key on the same devices, I want precision, and that means explicit exclusions. None of mine have them yet. That’s the next pass:

Task“How much traffic is this switch pushing?”
Log searchdescription
RecallSearch device syslog, login records, and security events.
PrecisionDo NOT trigger for traffic-volume questions or interface metrics; those belong to the flow and metrics skills.
Skips it: traffic volume is excluded
Flow analyticsdescription
RecallAnswer who-talks-to-whom and traffic-volume questions from flow data.
PrecisionDo NOT trigger for up/down or latency questions, and never widen past a short time window unless I ask.
Takes it: traffic volume is in scope
The next pass. The first sentence of each description is tuned for recall; the exclusion supplies the precision, so a traffic question about a switch stays out of log search even though both skills key on the same device.

The rules I’d keep

  • Memory holds facts that change reasoning. If it reads like a runbook, it’s a skill.
  • Derive, don’t copy. Anything a live API can regenerate shouldn’t be maintained by hand.
  • Capture the join key early. Composition depends on it.
  • Prioritize memories that prevent silent failures over ones that prevent loud ones.
  • Define where autonomy ends.
  • Route by exclusion, not just inclusion.

And now for the part of the blog where I vent about sports, because some traditions must be maintained.

In July I called optimism the most dangerous emotion in sports. I hadn’t accounted for Jameis Winston.

Jaxson Dart went down for the season with a knee injury in Week 2, which should have been the end of the optimism. Instead the Giants are 3-1-1, and Sunday in Washington was peak Jameis. He walked into the stadium in a blue raincoat and sunglasses, looking, as one fan put it, like he was about to perform surgery. Then the Giants fell behind by 13 in the fourth quarter, in the rain, and he brought them all the way back by feeding Malik Nabers and Isaiah Likely until each had 11 catches, 90-plus yards, and a touchdown. Only one other receiver and tight end pair in NFL history has done that in the same game. After all that, overtime ended 27-27. A tie. Not a win, not a loss, just an empty result set.

FinalOT
NYG3-1-127
WAS27
Nabers WR11 rec90+ yds1 TD
Likely TE11 rec90+ yds1 TD
Sunday in Washington. Down 13 in the fourth, in the rain, and the comeback returned an empty result set.

Watching Jameis is a lot like working with an LLM. This is a quarterback who once threw 33 touchdowns and 30 interceptions in the same season: all confidence, all creativity, capable of something brilliant and something baffling on back-to-back plays. You don’t fix that by making him less Jameis. You give him the right context and a couple of targets he trusts, and you let him cook. He called Nabers and Likely “world class at what they do.” On Sunday, he wasn’t wrong.