case studies

An AI Agent Changed a Cache Setting and XKV Kept the Tool Call Behind It

An operations agent watches the product catalog. Its metrics show 4.1% of reads returning stale data, above the 2% target, so it shortens the catalog cache’s time-to-live from 300 seconds to 30. That’s a reasonable move. An hour later the catalog database is at 91% CPU, because the cache now sends ten times as many reads its way. An engineer puts the TTL back.

The next morning the team wants to know what happened. The questions are the usual ones, with a new twist: which change did the agent make, what was it looking at, and which of its tool calls did it? Agents act fast and often, so their changes need a trail at least as good as a person’s.

In XKV an agent writes the same way any other writer does. It gives its reason, names the observation it acted on as the cause, and puts its tool call id in the ref:

The why tree for the catalog cache TTL: 300s again, reverted by dana@platform because the 30s TTL tripled catalog database load, ref INC-4512; caused by the agent’s change to 30s, made by ops-agent because stale reads were above the 2% target, ref toolcall_01J9ZK4T3M, which was caused by the stale-reads observation; and caused by the database CPU observation of 91%.

What the Agent Writes

The metrics job records what it saw. The agent acts on it and says so:

agent := xkv.WithActor(ctx, "ops-agent")
change, err := db.Put(agent, "cache:catalog:ttl", []byte("30s"),
	xkv.Reason("stale reads above the 2% target; shorter TTL"),
	xkv.Ref("toolcall_01J9ZK4T3M"),
	xkv.Cause(stale.Key, stale.Rev))

The ref ties the store to the agent’s own log. Whoever reviews the change can open that tool call and see the agent’s full reasoning, while the store keeps the short version next to the value.

What the Engineer Writes

The revert points at both things the engineer weighed: the agent’s change, and the CPU reading it caused.

eng := xkv.WithActor(ctx, "dana@platform")
_, err = db.Put(eng, "cache:catalog:ttl", []byte("300s"),
	xkv.Reason("revert: 30s TTL tripled catalog DB load"),
	xkv.Ref("INC-4512"),
	xkv.Cause(change.Key, change.Rev), xkv.Cause(load.Key, load.Rev))

The Morning After

cache:catalog:ttl = 300s   r5
│ was 30s · by dana@platform · revert: 30s TTL tripled catalog DB load · ref INC-4512
├─ cache:catalog:ttl = 30s   r3
│  │ was 300s · by ops-agent · stale reads above the 2% target; shorter TTL · ref toolcall_01J9ZK4T3M
│  └─ observed:catalog:stale-reads = 4.1% over the last hour   r2
│       by metrics-collector · hourly sample
└─ observed:catalog-db:cpu = 91% average   r4
     by metrics-collector · hourly sample

The tree tells the whole story without anyone reconstructing it. The agent saw stale reads and shortened the TTL. That raised database load, and a person reverted it, citing both. The team now has a concrete lesson to give the agent: weigh database load before shortening a cache TTL.

People and agents leave the same kind of trail here, with the same checks. An agent can’t cite an observation that doesn’t exist, and strict mode refuses its writes without a reason, just as it refuses a person’s.

Run It Yourself

git clone https://github.com/explainable-kv/xkv
cd xkv
go run ./examples/agent-setting

The agent’s change is one of the stories in the live demo.