DEV Community

Taylor Zhu
Taylor Zhu

Posted on

Case Study: An Incident Postmortem Generator on a $0 Budget

Every week, another article promises that AI agents will fix your operations. Most of them describe platforms with enterprise pricing. This is the opposite: a small, boring, useful tool that drafts incident postmortems from a plain timeline, built on a free model and a free server. It cost $0, took one weekend, and now turns a blank page into an editable draft in about two minutes.

The problem

Every on-call rotation ends the same way. You resolve the alert at 2 AM, and someone says "we should write a postmortem." Then the week starts, the backlog grows, and the postmortem becomes a guilt trip instead of a learning tool.

The real blocker is not laziness. It is the blank page. A postmortem needs a summary, a timeline, hypotheses, and action items — and you have to reconstruct all of it from memory and scattered chat logs. That takes 45 minutes on a good day.

I wanted a first draft. Not the truth, not the final verdict. Just a structured starting point I could correct and sign.

The goal

The tool had to meet four constraints:

  • Input: a plain list of timeline events, each with a timestamp, an actor, and an action.
  • Output: a Markdown postmortem draft with a summary, a timeline, three root-cause hypotheses, and action items.
  • Cost: zero. No paid API, no paid hosting.
  • Privacy: no raw logs, no customer data, no secrets. Only sanitized event descriptions.

I chose MonkeyCode, an open-source project that currently offers free model access (the advertised free tier includes 10 million tokens) and a free server option. That combination covers the two things this project needs: an LLM call and something to run the script. Disclosure: This article was prepared as part of MonkeyCode's product outreach.

One note on facts: quotas and model names change. I verified the free tier before building, and I still check the docs before each release. Do the same.

The implementation

The pipeline has three parts.

1. The event list

I keep the timeline in a simple JSON file. One entry per event:

[
  {"time": "2026-08-20T14:02:00Z", "actor": "deploy-bot", "action": "released api v2.4.1"},
  {"time": "2026-08-20T14:09:00Z", "actor": "alertmanager", "action": "paged on-call: 5xx rate above 5%"},
  {"time": "2026-08-20T14:31:00Z", "actor": "taylor", "action": "rolled back to v2.4.0"}
]
Enter fullscreen mode Exit fullscreen mode

That is the only input. If the timeline is messy, the draft will be messy. Garbage in, structured garbage out.

2. The prompt

The prompt is the real code. I ask for a draft, not a verdict:

You are an SRE writing an incident postmortem.
Turn the timeline below into a Markdown draft with:
1. A one-paragraph summary
2. A chronological timeline
3. Three root-cause hypotheses, most likely first
4. Action items with suggested owners

Rules:
- Only use events from the timeline. Do not invent events.
- Mark every hypothesis as a hypothesis.
- Keep the draft under 400 words.
Enter fullscreen mode Exit fullscreen mode

Short, constrained, and explicit about hallucination. That last rule matters.

3. The script

The following is the pattern I used, simplified. It is illustrative, not a copy-paste of any SDK — check the current API docs for the real endpoint and auth.

import os
import requests

API_KEY = os.environ["MC_API_KEY"]

def draft_postmortem(events: list[dict]) -> str:
    timeline = "\n".join(
        f"- {e['time']} | {e['actor']} | {e['action']}" for e in events
    )
    prompt = f"""You are an SRE writing an incident postmortem.
Turn the timeline below into a Markdown draft with:
1. A one-paragraph summary
2. A chronological timeline
3. Three root-cause hypotheses, most likely first
4. Action items with suggested owners

Rules:
- Only use events from the timeline. Do not invent events.
- Mark every hypothesis as a hypothesis.
- Keep the draft under 400 words.

Timeline:
{timeline}
"""
    resp = requests.post(
        "https://api.example.com/v1/chat/completions",  # placeholder
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "model": "free-model",  # placeholder: check the current model name
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0.2,
        },
        timeout=60,
    )
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]
Enter fullscreen mode Exit fullscreen mode

Note the temperature: 0.2. For this task you want boring output, not creative output.

4. The free server

The script runs on a free server via cron, once per incident. It writes the draft to a postmortems/ folder as a Markdown file. A tiny Flask app serves the folder so the team can review drafts in the browser:

from flask import Flask, send_from_directory

app = Flask(__name__)

@app.route("/postmortems/<path:name>")
def show_postmortem(name: str):
    return send_from_directory("postmortems", name)
Enter fullscreen mode Exit fullscreen mode

That is the whole server. No database, no auth, no queue. It is a folder with a web front.

Results

The tool does not write postmortems. It removes the blank page.

The workflow is: paste the timeline, run the script, open the draft. I edit the summary, delete one wrong hypothesis, and add the action items I actually assigned. Total time is minutes instead of the usual hour.

Three things surprised me:

  • The structure is the win. Even a mediocre draft forces the team to discuss the timeline instead of arguing about the narrative.
  • The model never forgets the timeline. Humans do, especially after a 2 AM incident.
  • The free tier is enough. This tool makes a handful of calls per incident, not thousands. 10 million tokens would cover months of this workload.

Limitations

Be honest about what this is not:

  • It is not a root-cause analysis. The model guesses; you verify.
  • It does not know what was not logged. If the timeline is incomplete, the draft is confidently incomplete.
  • It can hallucinate action items. I delete anything I cannot trace to a real event.
  • Do not paste secrets, customer data, or full logs into any hosted API. Sanitize first.

Who should not use this approach: teams with strict data-residency rules (unless you verify where requests go), teams that need legally defensible incident reports, and anyone who expects the model to replace human review. It will not.

Lessons learned

The biggest lesson is that the bottleneck was never the model. It was data capture. The tool is only as good as the timeline, so the real project is teaching the team to write clean event entries.

Second, prompt constraints beat model size. A small free model with a tight prompt produced drafts I could use. A bigger model with a vague prompt would have produced confident nonsense.

Third, a free server is enough for internal tools. Low traffic, one script, one folder — you do not need Kubernetes for a postmortem generator.

If you want to try the same pattern, MonkeyCode's free model access and free server option are enough to run this exact workflow. Start with a real incident from your own history, not a toy example. The draft will be wrong in useful ways, and that is the point.

Top comments (0)