Sitemap
Ankithanalla

Ankithanalla

Title : Runbook Truth

5 min readSep 29, 2026

Runbook Truth - Agent logic

I Used Hindsight to Turn Incident Memory Into Recommendations

I didn’t want our incident-response agent to stop at "I found a similar incident." That is useful, but it still leaves the engineer to

interpret the history and decide what to try next. I wanted the agent to use previous outcomes as evidence: which fixes worked,

which failed, and how certain the recommendation should be.

That became the core of my work on Runbook Truth.

I built the recommendation layer around recalled incident memories. Hindsight provides the memory layer, while my logic analyzes

those memories, compares outcomes, produces a recommendation, assigns a confidence level, explains the reasoning, and stores the

result of a newly resolved incident for future use.

The important distinction is simple: remembering an incident is not the same as learning from it.

What the system does

The incident flow starts with a new error. The system asks the memory layer for similar past incidents. Hindsight is responsible for

retaining and recalling that experience; my part begins when those memories reach the recommendation layer.

The flow is:

New incident

↓

Hindsight recall

↓

Similar past incidents

↓

Analyze success / failure

↓

Recommend a fix

↓

Calculate confidence

↓

Explain the recommendation

↓

Resolve the incident

↓

Store the outcome

I used Hindsight on GitHub as the memory component and designed the recommendation logic around the outcomes contained in

recalled incidents. The broader idea is consistent with Hindsight’s documentation: memory should help an agent use previous

experience rather than simply retrieve old text.

The first useful step was counting outcomes

A recalled incident is only useful to my recommendation logic if I can determine what was tried and what happened afterward.

I represented the useful part of an incident as three fields:

{

"error": "Redis connection timeout",

"fix": "Increase Redis timeout",

"result": "success"

}

Then I grouped memories by the fix and counted successes and failures:
def analyze_memories(memories):

stats = {}

for memory in memories:

fix = memory["fix"]

result = memory["result"]

Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size

if fix not in stats:

stats[fix] = {"success": 0, "failure": 0}

stats[fix][result] += 1

return stats

For the Redis timeout case, my test memories produced a result like:

Restart Redis

Success: 0

Failure: 2

Increase Redis timeout

Success: 2

Failure: 0

This small transformation is important. Instead of treating recalled incidents as a list of unrelated text entries, the recommendation

layer turns them into evidence that can be compared.

Get Ankithanalla’s stories in your inbox

Join Medium for free to get updates from this writer.

Choosing the recommendation

Once the outcomes are grouped, the next question is straightforward: which previous fix has the strongest successful history?

My current recommendation function deliberately stays simple:

def recommend_fix(memories):

if not memories:

return None

stats = analyze_memories(memories)

best_fix = None

best_score = -1

for fix, result in stats.items():

if result["success"] > best_score:

best_score = result["success"]

best_fix = fix

return best_fix

For example, if restarting Redis failed twice while increasing the Redis timeout succeeded twice, the recommendation becomes:

Recommended Fix: Increase Redis timeout

I intentionally kept this layer understandable. The recommendation is not a mysterious model-generated sentence. It is traceable to

the outcomes that were recalled.

That makes debugging much easier. If an engineer disagrees with the recommendation, I can inspect the underlying memories and see

why the logic selected it.

Confidence is separate from the recommendation

A recommendation without uncertainty can be misleading.

Suppose a fix succeeded once. I can technically recommend it, but I don’t want the system to communicate that result with the same
confidence as a fix that succeeded repeatedly.

I therefore calculate a success rate for the selected fix:

success_rate = success / total

if success_rate >= 0.75:

return "HIGH"

elif success_rate >= 0.50:

return "MEDIUM"

else:

return "LOW"

In the Redis example, two successes and zero failures produce:

Confidence: HIGH

The confidence value is intentionally simple. It is not a statistical guarantee and it is not a prediction of how the next incident will

behave. It is a compact representation of the evidence available in similar past incidents.

That distinction matters in incident response. A system should be able to say "this worked before" without pretending that the same

action is guaranteed to work again.

The explanation comes from the same evidence

I also wanted the agent to explain its recommendation.

Returning only this:

Increase Redis timeout

forces the engineer to ask another question: why?

The explanation function uses the same outcome counts:

def explain_recommendation(memories, recommended):

stats = analyze_memories(memories)

result = stats[recommended]

return (

f"Recommend '{recommended}' because it succeeded "

f"{result[’success’]} times and failed "

f"{result[’failure’]} times."

)

That produces an explanation such as:

Recommend 'Increase Redis timeout' because it succeeded

2 times and failed 0 times in similar past incidents.

This is one of the design decisions I found useful: the recommendation and explanation share the same source of truth. I don’t need a

separate explanation system to invent a reason after the recommendation has already been made.

Connecting the recommendation layer to Hindsight

The recommendation logic becomes useful when it is connected to actual recalled memory.

The integrated flow starts by calling the memory layer:

raw_memories = recall_similar_incidents(error, limit=8)

memories = convert_hindsight_memories(raw_memories)

recommended = recommend_fix(memories)

The recalled information is converted into the structured form expected by the recommendation functions. From there, the flow is

deterministic: analyze the outcomes, select a fix, calculate confidence, and build the explanation.

This separation keeps responsibilities clear.

Hindsight answers:

> What similar experience do I remember?

My recommendation layer answers:

> Given that experience, what should I recommend?

That separation is closely related to the broader idea of agent memory. Memory becomes more useful when an agent has a clear

mechanism for turning recalled experience into its next action.

No memory is a valid result

One of the easiest mistakes in an incident-response system is to assume that there will always be a useful previous incident.

There won’t.

If no similar memory exists, my code returns an explicit response:

def handle_no_memory(memories):

if not memories:

return {

"recommendation": "No known fix from past incidents",

"confidence": "LOW",

"explanation":

"No similar past incident was found. "

"Follow the standard runbook.",

"past_incidents_used": []

}

The important behavior here is not the wording. It is the decision not to manufacture certainty.

No relevant history means no evidence-based recommendation from memory. The system falls back to the standard runbook instead.

Conflicting outcomes need a different response

Past incidents can also disagree with each other.

For example:

Restart database

Success: 2

Failure: 2

In this situation, recommending the fix without qualification would hide useful information.

I handle that case explicitly:

if result["success"] > 0 and result["failure"] > 0:

return {

"recommendation": recommended,

"confidence": "LOW",

"explanation": (

f"’{recommended}' has mixed results: "

f"{result[’success’]} success and "

f"{result[’failure’]} failure."

)

}

The resulting response makes the uncertainty visible:

--

--