<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://me.mostafazh.me/">
  <title>Mostafa Zaher | Blog</title>
  <subtitle>Notes on engineering leadership, team building, and technology.</subtitle>
  <link href="https://me.mostafazh.me/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://me.mostafazh.me/blog/" rel="alternate" type="text/html"/>
  <id>https://me.mostafazh.me/blog/</id>
  <updated>2026-03-22T00:00:00.000Z</updated>
  <author>
    <name>Mostafa Zaher</name>
    <uri>https://me.mostafazh.me/</uri>
  </author>
  <entry>
    <title>Your team isn&#39;t just carrying tech debt. It&#39;s carrying context debt, and that one is harder to pay back</title>
    <link href="https://me.mostafazh.me/blog/context-debt-engineering-teams/" rel="alternate" type="text/html"/>
    <id>https://me.mostafazh.me/blog/context-debt-engineering-teams/</id>
    <published>2026-03-22T00:00:00.000Z</published>
    <updated>2026-03-22T00:00:00.000Z</updated>
    <summary>Tech debt shows up in your linter. Context debt shows up when your best engineer quits. Here&#39;s what the difference is, why AI is making it dramatically worse, and what you can actually do about it as an engineering manager.</summary>
    <category term="Engineering Leadership"/>
    <category term="Team Health"/>
    <category term="AI"/>
    <category term="Technical Excellence"/>
    <content type="html">&lt;p&gt;There&#39;s a conversation that happens in almost every sprint retrospective I&#39;ve ever run. Someone says &amp;quot;we really need to address our technical debt.&amp;quot; Everyone nods. It gets added to the backlog. Three months later, same retro, same nod, nothing changed.&lt;/p&gt;
&lt;p&gt;I used to think that was a prioritization problem. Product keeps pushing features, leadership doesn&#39;t see the value of cleanup, the usual. But after inheriting a few systems mid-flight and watching capable engineers struggle with codebases that looked fine on the surface, I started to suspect something else was going on.&lt;/p&gt;
&lt;p&gt;The code wasn&#39;t always the problem. The problem was that nobody could tell me &lt;em&gt;why&lt;/em&gt; the code was the way it was.&lt;/p&gt;
&lt;h2&gt;Two kinds of debt, very different pain&lt;/h2&gt;
&lt;p&gt;Technical debt is the stuff your linter can find. Tangled dependencies. Missing tests. A function that does seven things and is named &lt;code&gt;handleData&lt;/code&gt;. You know it&#39;s there. You know roughly where it lives. On a good team, you can schedule paying it down.&lt;/p&gt;
&lt;p&gt;Context debt is different. It&#39;s the accumulated loss of institutional knowledge about why your system was built the way it was. Not what it does, but why it does it that way and not some other way. The architectural decision that happened after a painful incident. The edge case that&#39;s handled by what looks like arbitrary code but was actually the result of three partner integrations and a compliance audit. The service boundary that exists because of an org change eighteen months ago, not because it was the cleanest technical choice.&lt;/p&gt;
&lt;p&gt;None of that lives in the code. Very little of it lives in documentation, because documentation is something teams aspire to write and rarely maintain. Most of it lives in the heads of the engineers who were in the room when those decisions were made.&lt;/p&gt;
&lt;p&gt;When those engineers leave, that knowledge walks out with them. And they always eventually leave.&lt;/p&gt;
&lt;p&gt;Here&#39;s what I&#39;ve noticed managing engineering teams at a company moving fast: context debt doesn&#39;t hurt until it suddenly really hurts. Technical debt creates friction gradually. You feel it on every sprint: things take longer than they should, estimates are off, PRs need more review rounds. It&#39;s chronic. Context debt is mostly invisible until the moment someone tries to change something load-bearing and discovers they don&#39;t understand why it works the way it does. Then it&#39;s acute.&lt;/p&gt;
&lt;p&gt;The difference matters because you manage them completely differently.&lt;/p&gt;
&lt;h2&gt;Then AI arrived and made this dramatically more complicated&lt;/h2&gt;
&lt;p&gt;I want to be careful here because I think some of the discourse around AI and code quality is overblown in one direction or underblown in another, and I&#39;m not sure which.&lt;/p&gt;
&lt;p&gt;Here&#39;s what I do think is real: AI tools have genuinely shifted the economics of writing code. Generating a working service that passes tests used to be expensive in engineer-hours. Now it&#39;s cheap. That&#39;s a real capability change and I&#39;d be lying if I said it hasn&#39;t changed how my teams work.&lt;/p&gt;
&lt;p&gt;But there&#39;s a paradox in it that took me a while to articulate clearly. Addy Osmani wrote about this recently as &amp;quot;comprehension debt&amp;quot;: the growing gap between how much code exists in your system and how much of it any human actually understands. He put it well: the codebase looks clean, the tests are green, and the reckoning arrives quietly at the worst possible moment.&lt;/p&gt;
&lt;p&gt;I&#39;ve seen this happen on a smaller scale. A junior engineer uses an AI tool to implement something, the code looks clean, it passes review, it ships. Six weeks later something breaks in production in a way that surprises everyone, including the engineer who wrote the code. Not because the AI wrote bad code. Because nobody fully internalized what the code was doing or why it was doing it that way, and so nobody caught the implicit assumption it was making about a downstream system.&lt;/p&gt;
&lt;p&gt;What Osmani is describing as comprehension debt is real. But I think it&#39;s actually a symptom of something deeper, which is context debt at the system level. And AI accelerates context debt in a way that&#39;s worth being specific about.&lt;/p&gt;
&lt;p&gt;When rewriting is cheap, the incentive to understand before replacing drops toward zero. Your AI assistant can regenerate a service in an afternoon. What it cannot regenerate is the institutional knowledge about why that service exists, what edge cases it was patched for over eighteen months, which downstream consumers depend on its specific response shapes. You get code that compiles, passes tests, and handles the happy path. You don&#39;t get the scar tissue.&lt;/p&gt;
&lt;p&gt;I read a framing I thought was sharp from Michael Tuszynski: &amp;quot;AI can regenerate the code layer fast. It cannot regenerate the institutional context that made that code correct.&amp;quot; That&#39;s the line I keep coming back to.&lt;/p&gt;
&lt;h2&gt;What context debt actually looks like on a team&lt;/h2&gt;
&lt;p&gt;Let me be concrete, because &amp;quot;loss of institutional knowledge&amp;quot; is the kind of phrase that sounds meaningful but doesn&#39;t tell you what to do.&lt;/p&gt;
&lt;p&gt;Here are the specific places I&#39;ve seen context debt accumulate:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architectural rationale that nobody wrote down.&lt;/strong&gt; Why is this a separate microservice instead of a module in the monolith? Why is the database schema structured this way? If the answer is &amp;quot;because we decided to do it this way two years ago&amp;quot; and the people who made that decision are gone, you have context debt. The next engineer who touches this will either make a change that conflicts with the original rationale, or they&#39;ll leave the structure alone out of fear, and neither outcome is good.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Boundary knowledge.&lt;/strong&gt; Which partners or internal consumers depend on specific response shapes? Which integrations are fragile in ways that aren&#39;t obvious from the code? This is the knowledge that shows up as &amp;quot;why did you change that field name, three other systems broke&amp;quot; six hours after deploy. It&#39;s invisible until it isn&#39;t.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Failure memory.&lt;/strong&gt; The race condition that an engineer caught after an incident eighteen months ago and quietly patched. The validation logic that exists because of a security audit finding. The retry logic that&#39;s tuned the way it is because the default behavior destroyed a downstream system under load. This code looks redundant if you don&#39;t know the story. An AI tool rewriting the service will likely strip it out. And you won&#39;t know it was wrong until the same failure happens again.&lt;/p&gt;
&lt;p&gt;The uncomfortable thing is that all of this is also exactly what AI coding tools are worst at. They operate within a context window. They see the file you&#39;re working on, the adjacent files, whatever system prompt describes your stack. They don&#39;t see the full topology of your system: every service, every contract, every shared assumption that holds your architecture together. When three engineers independently use AI to build three services that interact, each service can be internally clean and the integration between them can be quietly wrong in ways nobody catches until production.&lt;/p&gt;
&lt;h2&gt;The measurement gap that makes this a leadership problem&lt;/h2&gt;
&lt;p&gt;Here&#39;s what makes context debt particularly difficult to manage: nothing in your current measurement system captures it.&lt;/p&gt;
&lt;p&gt;Your velocity metrics look fine. DORA metrics hold steady. PR counts are up. Code coverage is green. Performance reviews see output volume. The comprehension deficit, the accumulated context loss. None of that appears in any artifact your organization measures.&lt;/p&gt;
&lt;p&gt;This is what makes it a leadership problem and not just a technical one. Technical debt is visible enough that engineers can advocate for paying it down. Context debt is invisible to the tools, the metrics, and often to the engineers themselves. They&#39;ll approve a PR that looks right, because it does look right. The problem is invisible until it compounds into something that isn&#39;t.&lt;/p&gt;
&lt;p&gt;I&#39;ve thought about this a lot in the context of AI adoption. There&#39;s genuine pressure right now to show velocity improvements from AI tooling. That pressure is real and not unreasonable. But if your measurement system only captures what moves fast, you&#39;ll optimize for speed and discover the context you&#39;ve shed when something breaks at scale.&lt;/p&gt;
&lt;h2&gt;What you can actually do about it&lt;/h2&gt;
&lt;p&gt;I want to be direct here: I don&#39;t think this is primarily a culture problem. &amp;quot;Slow down and review more carefully&amp;quot; is advice that sounds reasonable in a blog post and falls apart in a sprint with a deadline. The teams that will manage context debt well are the ones that treat it as an infrastructure problem, not a discipline problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architectural decision records, maintained as living documents.&lt;/strong&gt; ADRs have been around for years. The format is basically Title, Status, Context, Decision, Consequences. What&#39;s changed is the urgency. Before AI-assisted development, context accumulated naturally as engineers wrote code slowly enough to internalize it. Now it dissipates faster than it accumulates unless you deliberately counteract that. An ADR written when a decision is made and living alongside the code is worth ten retrospective explanations after the fact.&lt;/p&gt;
&lt;p&gt;The key word is &amp;quot;living.&amp;quot; A dusty Confluence page nobody updates is not an ADR. It&#39;s archaeology. If your ADRs aren&#39;t being referenced and updated as part of the development workflow, they&#39;re decoration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structured project memory as a first-class artifact.&lt;/strong&gt; Context documents (system descriptions, constraint inventories, edge case catalogs, partner dependency maps) should be versioned and reviewed with the same rigor as code. Not because engineers will read them compulsively (they won&#39;t), but because when an engineer or an AI tool is about to make a change, the context needs to be accessible right there. Embedded in the workflow, not sitting in a separate system someone has to remember to consult.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Explicit integration contracts.&lt;/strong&gt; If your services are generated independently by AI tools without awareness of each other, you will accumulate integration debt. The data formats, error handling conventions, retry semantics, authentication flows: these will diverge. The fix is defining and maintaining explicit contracts that both engineers and AI tools can reference during generation. The contract becomes the source of truth, not the individual engineer&#39;s mental model of how everything connects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Offboarding as a context transfer ritual.&lt;/strong&gt; When a senior engineer leaves (and eventually everyone leaves), their departure is the most expensive context loss event your team will experience. I&#39;ve seen teams do thorough technical offboarding (here&#39;s how the systems work) and nothing about contextual offboarding (here&#39;s why these systems work this way, here are the decisions I&#39;d revisit, here&#39;s the undocumented partner integration that will break if you do X). The latter is what you actually need.&lt;/p&gt;
&lt;p&gt;One thing I&#39;ve started doing: before an engineer leaves, I ask them to record a &amp;quot;walk through the weird parts&amp;quot; session. Not a systems overview. Specifically the things that look wrong but aren&#39;t, the things that need to stay exactly the way they are and why, the decisions they made that they&#39;d make differently now. That&#39;s the institutional knowledge you can&#39;t recover after someone&#39;s gone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Context-aware generation as a deliberate workflow.&lt;/strong&gt; If your engineers are using AI tools to generate code, the tools should be ingesting project context before they generate. This means investing in the scaffolding (the context files, system prompts, reference documents, constraint catalogs) that gives the AI a real understanding of the system it&#39;s working within. The alternative is an amnesiac collaborator that produces clean code in a vacuum. That&#39;s fine for a proof of concept. It&#39;s not fine for production.&lt;/p&gt;
&lt;h2&gt;What I&#39;m still figuring out&lt;/h2&gt;
&lt;p&gt;I&#39;ll be honest about where I don&#39;t have clean answers.&lt;/p&gt;
&lt;p&gt;Measuring context debt is genuinely hard. I can measure test coverage, PR cycle times, defect rates. I cannot tell you with a number how much institutional context my team has lost in the last six months of AI-assisted development. I can observe signals: engineers expressing uncertainty about why something works the way it does, changes that break things in surprising ways, architectural discussions that require me to explain history that should be documented. But I don&#39;t have a dashboard for this.&lt;/p&gt;
&lt;p&gt;I&#39;m also not sure yet how much of this is fundamentally new and how much is the same old context-loss problem that&#39;s always existed, just accelerating. My guess is it&#39;s both, and the acceleration is the part worth treating seriously right now, before the debt compounds further.&lt;/p&gt;
&lt;p&gt;What I&#39;m reasonably confident about: the teams that will do well in the AI era aren&#39;t necessarily the ones that generate code fastest. They&#39;re the ones that maintain the richest context while moving fast. That combination compounds. A year from now, the team that invested in context architecture will be moving quickly and safely. The team that optimized only for velocity will be drowning in debt they can&#39;t see and can&#39;t name.&lt;/p&gt;
&lt;p&gt;The old tech debt conversation was mostly about code quality. This one is about knowledge architecture. And most teams haven&#39;t started having it yet.&lt;/p&gt;
&lt;p&gt;If you&#39;re thinking about this differently on your team, or you&#39;ve found approaches that actually work for maintaining context at pace, I want to hear about it. Reach out on &lt;a href=&quot;https://twitter.com/mostafazaher&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.linkedin.com/in/mostafazh&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Further reading&lt;/h2&gt;
&lt;p&gt;These two talks were valuable references while thinking through these ideas:&lt;/p&gt;
&lt;div class=&quot;video-embed&quot;&gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Tk0hIOAwf6M?si=hC3-BqTaHqV_nQpL&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;video-embed&quot;&gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/eIoohUmYpGI?si=Eed7CwubdNXOqJ-X&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Measuring eNPS on your engineering team (and using AI to actually make sense of it)</title>
    <link href="https://me.mostafazh.me/blog/measuring-enps-engineering-team/" rel="alternate" type="text/html"/>
    <id>https://me.mostafazh.me/blog/measuring-enps-engineering-team/</id>
    <published>2026-03-20T00:00:00.000Z</published>
    <updated>2026-03-20T00:00:00.000Z</updated>
    <summary>A practical guide to running eNPS surveys for engineering teams, from survey design and anonymous collection to AI-powered analysis, plus an open-source AI agent skill that automates the entire workflow end-to-end.</summary>
    <category term="Engineering Leadership"/>
    <category term="Team Health"/>
    <category term="AI"/>
    <category term="Open Source"/>
    <content type="html">&lt;p&gt;By the time someone hands in their resignation, you already missed the moment. The frustration was there three sprints ago. Maybe six. You could feel something was off but you couldn&#39;t name it, couldn&#39;t quantify it, and without numbers you couldn&#39;t justify doing anything about it. That&#39;s the trap most engineering managers fall into: waiting for a signal clear enough to act on, and by then it&#39;s too late.&lt;/p&gt;
&lt;p&gt;eNPS (Employee Net Promoter Score) doesn&#39;t solve this problem completely, but it does give you a repeatable, low-overhead signal that keeps you honest. And when you pair it with an LLM doing qualitative analysis on the open-ended responses, it goes from &amp;quot;we have a vague sense of morale&amp;quot; to &amp;quot;here&#39;s exactly what&#39;s bothering the team and here&#39;s how it compared to last quarter.&amp;quot;&lt;/p&gt;
&lt;p&gt;I&#39;ve run this across a few team configurations now. Here&#39;s what I actually learned, not just what the framework says.&lt;/p&gt;
&lt;h2&gt;What eNPS is (and isn&#39;t)&lt;/h2&gt;
&lt;p&gt;The concept borrows from customer NPS. One core question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;On a scale of 0–10, how likely are you to recommend this team as a great place to work?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Responses fall into three groups: Promoters (9–10), Passives (7–8), and Detractors (0–6). The score is:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;eNPS = % Promoters − % Detractors&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It ranges from −100 to +100. Above 0 is acceptable. Above +20 is genuinely healthy. Above +50 is rare in engineering.&lt;/p&gt;
&lt;p&gt;Here&#39;s the part most guides skip: the number itself is almost meaningless in isolation. I&#39;ve seen teams with a +35 that were quietly miserable in ways the score didn&#39;t capture, and teams with a +10 that were actually in a good place given the chaos they were navigating. What matters is the trajectory across quarters, and what the open-ended responses say about why.&lt;/p&gt;
&lt;p&gt;eNPS is not a diagnostic tool. It&#39;s an early warning system. It tells you something shifted. The actual diagnosis comes from everything else.&lt;/p&gt;
&lt;h2&gt;Why it works for engineering specifically&lt;/h2&gt;
&lt;p&gt;Generic engagement surveys miss what engineers actually care about. A 60-question annual survey asking about cafeteria quality and office amenities tells you nothing about whether your team trusts the technical direction, whether they have enough uninterrupted time to think, or whether the deployment process is so painful that shipping feels like punishment.&lt;/p&gt;
&lt;p&gt;Engineers are also unusually resistant to performative feedback tools. If they don&#39;t trust that responses are truly anonymous, they&#39;ll all score 7 and write nothing in the open-ended fields. Your data becomes noise. The survey design has to earn that trust before it can generate any useful signal.&lt;/p&gt;
&lt;p&gt;The other thing eNPS has going for it: it takes two minutes. High response rates from engineers are not a given. Short surveys get answered; long ones get abandoned or half-heartedly completed.&lt;/p&gt;
&lt;h2&gt;How to run it&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Cadence:&lt;/strong&gt; quarterly. Monthly creates fatigue and the scores become too noisy to trend. Annually is too slow to catch anything while you can still act on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Questions:&lt;/strong&gt; three, maximum.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;quot;On a scale of 0–10, how likely are you to recommend this team as a great place to work?&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;What&#39;s the primary reason for your score?&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;What&#39;s one thing we could change that would make the biggest difference for you?&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Anonymity:&lt;/strong&gt; non-negotiable, and engineers will know if you&#39;re not serious about it. Use Google Forms with no email collection enabled. Don&#39;t restrict responses by Google account unless you have a strong reason to. Don&#39;t use a tool that ties response timestamps to Slack activity or calendar data. Engineers will notice and they will talk.&lt;/p&gt;
&lt;p&gt;Send the survey at the start of a sprint, keep it open for five days, send one reminder on day three with the current response count (not individual results), then close it. Calculate the score. Export the open-ended responses. That&#39;s your raw material.&lt;/p&gt;
&lt;h2&gt;Interpreting the score&lt;/h2&gt;
&lt;p&gt;A rough guide:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Score range&lt;/th&gt;
&lt;th&gt;What it probably means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;+50 to +100&lt;/td&gt;
&lt;td&gt;Something is working well. Figure out what and protect it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+20 to +49&lt;/td&gt;
&lt;td&gt;Healthy baseline. Keep iterating.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 to +19&lt;/td&gt;
&lt;td&gt;Worth digging into. Not a crisis but not comfortable either.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Below 0&lt;/td&gt;
&lt;td&gt;Structural problems. Act fast.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A 10-point drop after a reorg or a brutal quarter is normal. I&#39;ve lived through that. A sustained decline over two or three consecutive quarters is the signal you can&#39;t ignore.&lt;/p&gt;
&lt;p&gt;When the score drops, the instinct is to figure out what you did wrong. That&#39;s sometimes the right question. But sometimes the team is going through something difficult and the score reflects reality accurately: a painful migration, a product direction that isn&#39;t landing, organizational uncertainty above your level. Understanding the context matters as much as the number itself.&lt;/p&gt;
&lt;h2&gt;Where AI actually earns its place here&lt;/h2&gt;
&lt;p&gt;The quantitative score is table stakes. The real value is in the open-ended responses, and that&#39;s also where most managers quietly give up. Reading 40 free-text responses and trying to synthesize them into something coherent, while keeping your own biases out of the interpretation, is harder than it sounds.&lt;/p&gt;
&lt;p&gt;This is the problem LLMs are genuinely good at.&lt;/p&gt;
&lt;h3&gt;Theme clustering&lt;/h3&gt;
&lt;p&gt;Paste your open-ended responses into an LLM with this prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Below are anonymous survey responses from an engineering team. Group them into 3–5 themes. For each theme, provide a label, the number of responses related to it, and one representative quote that captures the theme. Do not identify or speculate about individual people.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The output is faster and more consistent than manual synthesis, and it surfaces themes you might unconsciously deprioritize because they&#39;re uncomfortable. I&#39;ve had the model surface a career growth concern that I had mentally filed under &amp;quot;individual ambition&amp;quot;. When I looked at how many responses touched on it, it was clearly a team-wide pattern, not a personal thing.&lt;/p&gt;
&lt;h3&gt;Sentiment tracking over time&lt;/h3&gt;
&lt;p&gt;Run the same prompt every quarter and log the results in a simple table:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quarter&lt;/th&gt;
&lt;th&gt;Theme&lt;/th&gt;
&lt;th&gt;Sentiment&lt;/th&gt;
&lt;th&gt;Mentions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Q1&lt;/td&gt;
&lt;td&gt;Technical debt&lt;/td&gt;
&lt;td&gt;Negative&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q2&lt;/td&gt;
&lt;td&gt;Technical debt&lt;/td&gt;
&lt;td&gt;Mixed&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q3&lt;/td&gt;
&lt;td&gt;Technical debt&lt;/td&gt;
&lt;td&gt;Mostly positive&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you committed sprint capacity to reducing technical debt in Q2, and by Q3 the mention count dropped and the sentiment shifted, that&#39;s real feedback that the change landed. Teams rarely tell you directly that something you did worked. This is one way to see it.&lt;/p&gt;
&lt;h3&gt;Early warning detection&lt;/h3&gt;
&lt;p&gt;This one is the most sensitive to get right. The prompt is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;From the following survey responses, identify any that suggest the respondent may be considering leaving or is highly disengaged. Do not identify individuals. Summarize the systemic concerns that appear across multiple responses.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The important framing there is systemic. You&#39;re not trying to identify who wrote what. You&#39;re trying to spot whether five different people independently described the same structural problem. That&#39;s a different thing from surveillance, and how you talk about this internally matters. If your team thinks you&#39;re using eNPS to identify the disgruntled people, you&#39;ve already lost.&lt;/p&gt;
&lt;h3&gt;Quarter-over-quarter comparison&lt;/h3&gt;
&lt;p&gt;Once you have data from two quarters, run this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Compare the themes from Q1 and Q2 survey responses below. What got better? What got worse? What&#39;s new this quarter that wasn&#39;t there before?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This gives you a narrative. &amp;quot;Last quarter, meeting load was the loudest concern. We cut three recurring syncs. This quarter it&#39;s not in the top themes.&amp;quot; That&#39;s a story you can tell the team, and closing that loop is the part that actually makes people keep participating.&lt;/p&gt;
&lt;h2&gt;A workflow that doesn&#39;t take over your life&lt;/h2&gt;
&lt;p&gt;Here&#39;s the full sequence, realistically:&lt;/p&gt;
&lt;p&gt;Quarter starts. Send the survey on Monday of sprint one. Keep it open until Friday. Send a reminder Wednesday. Close it, calculate the score, export the responses as a text file. Run the AI analysis (ten minutes, maybe fifteen if you want to iterate on the prompts). Log the score, themes, sentiment, and three to five action items. Share the results with the team that week: score, what you heard, and one concrete thing you&#39;re committing to. Do the thing before the next survey goes out.&lt;/p&gt;
&lt;p&gt;The last step is the one that determines whether this works. If the team sees feedback going into a void, participation drops. Not dramatically at first (people give it one more cycle), but it hollows out. The survey becomes a ritual without a point.&lt;/p&gt;
&lt;h2&gt;The AI agent skill: what it actually does and how to use it&lt;/h2&gt;
&lt;p&gt;I built a reusable skill file for MCP-compatible AI agents that automates this entire workflow. If you&#39;ve used Claude or any agent that supports the Model Context Protocol, you can drop these files in and run the full eNPS cycle from a single prompt.&lt;/p&gt;
&lt;p&gt;The skill is two files: &lt;code&gt;SKILL.md&lt;/code&gt; (the main workflow) and &lt;code&gt;reference/prompts.md&lt;/code&gt; (the AI analysis prompt templates with worked examples). Here&#39;s what&#39;s in each.&lt;/p&gt;
&lt;h3&gt;SKILL.md: the full workflow&lt;/h3&gt;
&lt;p&gt;The skill file opens with a metadata block that tells the agent when and how to activate:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;---
name: team-health
description: Run quarterly eNPS surveys to measure engineering team health.
  Creates anonymous surveys via Google Forms, distributes via Slack, collects
  responses, and uses AI to analyze themes and track sentiment over time.
triggers:
  - &amp;quot;run eNPS survey&amp;quot;
  - &amp;quot;team health check&amp;quot;
  - &amp;quot;quarterly survey&amp;quot;
  - &amp;quot;measure team morale&amp;quot;
integrations:
  - slack-mcp
  - google-workspace-mcp
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The trigger phrases matter. A well-defined skill file tells the agent not just what to do, but when to activate without you having to explain the context every time.&lt;/p&gt;
&lt;p&gt;The workflow then breaks into seven steps, each with explicit success criteria so the agent knows when a step is genuinely complete before moving on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: configuration check&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before creating anything, the agent asks for four variables:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;slack_channel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where to post announcements&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#engineering&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;survey_title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name for this cycle (e.g., &amp;quot;Q1 2026 Team Health&amp;quot;)&lt;/td&gt;
&lt;td&gt;Derived from current quarter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;engineer_emails&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional list to restrict form access&lt;/td&gt;
&lt;td&gt;Empty (open access)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;collection_window_days&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How long the survey stays open&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The agent won&#39;t proceed without &lt;code&gt;slack_channel&lt;/code&gt; and &lt;code&gt;survey_title&lt;/code&gt;. The others have sensible defaults. This matters because a poorly configured survey (wrong channel, wrong anonymity settings) produces bad data that takes a quarter to detect and correct.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: create the Google Form&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The skill specifies exact form configuration, not just &amp;quot;create a form&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Form title: {survey_title}
Collect email addresses: OFF
Limit to 1 response: ON (if engineer_emails is set, else OFF)
Require sign-in: OFF

Question 1:
  Type: Linear scale
  Label: &amp;quot;On a scale of 0–10, how likely are you to recommend this team as a great place to work?&amp;quot;
  Scale: 0 to 10
  Low label: &amp;quot;Not at all likely&amp;quot;
  High label: &amp;quot;Extremely likely&amp;quot;

Question 2:
  Type: Paragraph text
  Label: &amp;quot;What&#39;s the main reason for your score?&amp;quot;
  Required: false

Question 3:
  Type: Paragraph text
  Label: &amp;quot;What&#39;s one thing that would make the biggest difference for you right now?&amp;quot;
  Required: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &amp;quot;Required: false&amp;quot; on the open-ended questions is intentional. Forcing text input when someone doesn&#39;t have anything to say produces garbage. Better to get a clean 0–10 score with no commentary than a score plus a placeholder response.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: launch announcement to Slack&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The skill includes the exact Slack message template, not a generic &amp;quot;post to Slack&amp;quot; instruction:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:bar_chart: *Q1 2026 Team Health Check*

Quick survey, takes about 2 minutes.

This is fully anonymous. I don&#39;t see individual responses, only aggregated themes. No email collection.

Link: {form_url}

Open until {close_date}. I&#39;ll share results and what I&#39;m doing about them the week after.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The transparency line (&amp;quot;I don&#39;t see individual responses&amp;quot;) is not optional. It directly affects response quality and honesty.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: three-day reminder&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The reminder includes the current response count, which creates low-key social proof without pressure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:reminder_ribbon: Reminder: Team Health Survey is still open ({response_count} responses so far)

Closes {close_date}. Two minutes: {form_url}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&#39;t send a second reminder after this. Two Slack messages is the limit before it starts feeling like pressure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: close and collect&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The agent closes the form at end of business on day five, exports responses in two formats: a CSV with the raw 0–10 scores for eNPS calculation, and a plain text file with the open-ended responses formatted for LLM input.&lt;/p&gt;
&lt;p&gt;The text file format matters for prompt reliability:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;=== Q2: Primary reason for score ===
[Response 1] I feel like we ship fast but never slow down to fix things properly.
[Response 2] My manager actually listens. That&#39;s rarer than it should be.
[Response 3] No clear path to senior. I&#39;ve been here 18 months and don&#39;t know what I&#39;m being evaluated on.
...

=== Q3: One thing that would make the biggest difference ===
[Response 1] 20% time that&#39;s actually protected, not just promised.
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The [Response N] prefix keeps responses visually separated without leaking any identifying metadata.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6: calculate eNPS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The agent runs this calculation and logs the components, not just the final score:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Total responses: N
Promoters (9–10): P  →  P/N × 100 = P%
Passives (7–8):   A  →  A/N × 100 = A%
Detractors (0–6): D  →  D/N × 100 = D%

eNPS = P% − D% = {score}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Logging the breakdown matters. A +20 from 60% Promoters / 40% Passives / 0% Detractors is a very different situation from a +20 from 40% Promoters / 40% Passives / 20% Detractors. The score is the same. The underlying health is not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 7: AI analysis&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The agent runs all four prompt templates sequentially against the exported responses and assembles the output into a structured report (see the prompt details in the next section).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 8: results post to Slack&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The results message template is designed to close the loop, not just report numbers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:bar_chart: *Q1 2026 Team Health Results*

*eNPS: {score}* ({interpretation})
{total_responses} responses · {response_rate}% of the team

*What I heard most:*
• {theme_1}: {theme_1_summary}
• {theme_2}: {theme_2_summary}
• {theme_3}: {theme_3_summary}

*What I&#39;m doing about it:*
{action_item_1}
{action_item_2}

Full analysis posted to {confluence_link or notion_link}.

Next survey: {next_quarter_date}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &amp;quot;What I&#39;m doing about it&amp;quot; section is the point. It&#39;s the reason people respond next time.&lt;/p&gt;
&lt;h3&gt;reference/prompts.md: the four AI templates&lt;/h3&gt;
&lt;p&gt;This file is the most portable part of the skill. Even if you never use an AI agent, these prompts work standalone in any LLM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt 1: theme clustering&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;You will receive anonymous survey responses from an engineering team.
Your task is to group them into 3–5 themes.

For each theme:
- Give it a short, specific label (not &amp;quot;Communication&amp;quot;, but something like &amp;quot;Unclear priorities at the team level&amp;quot;)
- Count how many responses relate to it
- Select one representative quote that captures the theme without identifying anyone
- Note whether the theme is about something structural (process, tooling, org design) or interpersonal (manager relationship, team dynamics)

Do not speculate about individuals. Do not infer who wrote what based on writing style or context.

Responses:
{paste responses here}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The instruction to distinguish structural from interpersonal is something I added after a few cycles. It changes how you prioritize the actions. Structural problems need system changes. Interpersonal ones often need different conversations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt 2: sentiment scoring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;For each of the following themes identified in the survey analysis, rate the overall sentiment expressed across the related responses.

Use one of four ratings:
- Positive: team members feel good about this area
- Mixed: roughly split between positive and negative
- Negative: team members are frustrated or disengaged here
- Neutral: factual observations without strong emotional signal

Also provide a one-sentence characterization of the specific flavor of the sentiment (e.g., not just &amp;quot;Negative&amp;quot; but &amp;quot;Frustrated with slow progress rather than opposed to the goal itself&amp;quot;).

Themes: {paste themes here}
Responses: {paste responses here}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The one-sentence flavor note is the useful part. &amp;quot;Negative&amp;quot; tells you something is wrong. &amp;quot;The team is frustrated that the reorg happened, not that the new structure is bad&amp;quot; tells you whether to address the change or the change management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt 3: early warning detection&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Review the following survey responses for signals of attrition risk or significant disengagement.

Categorize signals as:
- High risk: language suggesting the person is actively considering leaving or has mentally checked out
- Medium risk: language suggesting disengagement, unfulfilled expectations, or feeling stuck
- Systemic: patterns appearing across multiple responses that suggest a team-wide issue rather than individual circumstances

For each category, summarize the concern in general terms. Do not quote directly in ways that could identify individuals. Do not attempt to guess who wrote what.

If no clear signals are present, say so plainly. Do not manufacture risk signals that aren&#39;t in the data.

Responses:
{paste responses here}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last instruction (&amp;quot;do not manufacture risk signals&amp;quot;) matters. LLMs have a tendency to find patterns when prompted to look for them, even in clean data. Explicitly telling it to say &amp;quot;nothing significant here&amp;quot; when that&#39;s true reduces false positives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt 4: quarter-over-quarter comparison&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Below are theme summaries from two consecutive quarterly eNPS surveys for the same engineering team.

Compare them:
1. What improved between Q{N-1} and Q{N}? Be specific about what changed.
2. What got worse or didn&#39;t improve despite being flagged last quarter?
3. What is new this quarter that wasn&#39;t present before?
4. Is there anything in Q{N} that contradicts what Q{N-1} suggested?

Be direct. If something got worse, say it got worse. If an action the manager took seems to have had no effect, note that.

Q{N-1} themes:
{paste previous quarter themes}

Q{N} themes:
{paste current quarter themes}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The instruction to note when an action had no apparent effect is important and uncomfortable. It&#39;s also the most useful feedback a manager can get. If you dedicated sprint capacity to tech debt last quarter and this quarter&#39;s responses still mention it as the top frustration, something is off. Either the effort wasn&#39;t visible, wasn&#39;t enough, or wasn&#39;t addressing the actual problem.&lt;/p&gt;
&lt;h3&gt;how to install it&lt;/h3&gt;
&lt;p&gt;For Claude or any MCP-compatible agent, place the files at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.agents/skills/team-health/SKILL.md
.agents/skills/team-health/reference/prompts.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Slack MCP and Google Workspace MCP need to be connected for the automated steps to work. If they&#39;re not available, the skill degrades gracefully: the agent walks you through each step manually with the exact configuration to use.&lt;/p&gt;
&lt;p&gt;The prompts in &lt;code&gt;reference/prompts.md&lt;/code&gt; work standalone regardless. Copy them, paste your responses, run them in whatever LLM you use. That&#39;s the minimum viable version and it&#39;s where I&#39;d start before connecting any integrations.&lt;/p&gt;
&lt;h2&gt;The thing that actually determines whether this works&lt;/h2&gt;
&lt;p&gt;I&#39;ve seen eNPS programs that ran for a year and produced nothing. Not because the questions were wrong or the cadence was off, but because the results went into a document that nobody referenced until the next survey went out.&lt;/p&gt;
&lt;p&gt;The feedback loop only works if people believe it works. That means two things: the survey has to be genuinely anonymous (not just said to be), and the actions have to be visible before the next survey lands. One concrete change, clearly connected to what the team said, is worth more than five action items that quietly drop.&lt;/p&gt;
&lt;p&gt;If you&#39;ve run eNPS on your team, or you&#39;ve tried a different approach to measuring morale, I&#39;d actually like to hear what you found. What signals were you watching that the survey missed? Reach out on &lt;a href=&quot;https://www.linkedin.com/in/mostafazh&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
</feed>
