Q

Inspired by Otacon and the comms device design from the Metal Gear Solid games.

active ·

Q

A Slack-native Claude agent that triages inbound, files Jira tickets, and learns across sessions.

Managed Agents Memory (preview) TypeScript Slack Atlassian MCP Cloud Run

Q is a Slack-native AI agent I built for my team. It reads our inbound bug channels, triages tickets, files them into Jira with context and proposed priority, classifies reactions on messages into follow-up actions, and talks back to us in thread. Around thirty people use it now, mostly product managers running it against their own backlogs. It’s been live for a couple months.

What follows is how Q is put together.

What Q does

The core loop is triage. When someone drops a bug or request in one of Q’s channels, it reads the message, checks our issue tracker for duplicates, pulls surrounding context from the thread, proposes a priority based on our routing rules, and files a Jira ticket. It posts back a link and a one-line summary. If someone drops an emoji reaction on a message, Q classifies what the reaction means and takes a corresponding action.

Beyond triage, Q has a handful of commands. !reflect runs a self-improvement cycle: Q reads recent sessions, notices where it was corrected, and proposes updates to its own knowledge base. !long kicks off autonomous longer-running work under a different flow. A couple of other commands I keep adding as I find seams where the manual version was eating my team’s time.

About thirty people use Q on the triage side, including other product managers running it against their own backlogs. It wasn’t designed for cross-team use. It just kept being useful and people kept pointing it at their channels.

The docs layer

Q’s knowledge base lives as plain markdown files. The canonical docs are:

  • Golden principles. The identity document. How Q should behave, what it should refuse to do, what kinds of questions it should ask.
  • Triage routing. The rules for which team owns which kind of work, and the jargon that signals “this is actually about X, not Y.”
  • Triage process. How Q handles a ticket from inbound to filed.
  • Product context. A running product-level summary Q uses to write ticket descriptions in a register engineers recognize.
  • Repo docs. Per-repo notes about what each codebase does, who owns it, how it fits into the platform.

I update those docs by editing them and letting Q pick them up on the next session. For a while, !reflect would open a pull request with its proposed changes and I’d review the diff. That part worked but added latency. A session would learn something useful and the correction would wait two days until I got around to the PR.

The memory layer

Until recently, everything Q figured out mid-session evaporated when the session ended. If Q noticed that a specific phrase routed to a specific team, that learning lived only as long as the Slack thread did. Next thread, Q started over.

I gave Q a pair of memory stores on top of Anthropic’s Managed Agents memory preview. Both stores are attached to every session Q runs.

q-knowledge is the canonical layer. It holds the docs I just described (golden principles, routing, product context, repo notes) in a read-write store seeded from the markdown files at setup time.

q-learnings is the runtime layer. Everything Q observes on the job: corrections from me, jargon that routes in non-obvious ways, user and team patterns. Entries land at /tags/{tag}/{slug}.md with YAML frontmatter: subject, predicate, object, type (correction / preference / jargon / pattern / fact), status, source (a Slack deep link), observed, tags, and a supersedes array. The schema lives in Q’s system prompt, so every write goes through the same template.

Supersession is what makes the split worth it. When a new entry contradicts an existing one, Q marks the old entry status: superseded and references its id from the new entry’s supersedes list. Nothing gets deleted. The old claim, when it was observed, and which Slack thread provoked the change are all still there to inspect, which matters for debugging a wrong routing decision three months later.

The reason to split the stores is that the canon and the runtime learnings have different lifecycles. Canon gets revised deliberately, mostly by me editing the source docs. Learnings accrete in the background as Q runs. Putting them in separate stores lets me reason about them separately without building that separation into the retrieval layer.

No custom retrieval infrastructure yet. Q reads via the built-in memory_search tool before every routing decision. If that stops being precise enough at scale, I’ll add something embedding-backed later. I’d rather ship with the simpler version and let scale tell me what to fix.

One thing still on the list: !reflect currently updates Q’s canonical docs by opening a pull request on the repo. Now that q-knowledge is a live read-write store, reflect should edit memory directly and skip the PR hop. That’s the next piece.

Jira and Confluence

Q talks to Jira through the Atlassian MCP server. That part is boring in the best way. The MCP handles the schema, I just describe what I want Q to do, and Q fills in the right fields. Ticket descriptions come out in a consistent voice because Q’s system prompt and product context are consistent.

Confluence works the same way. Q reads Confluence pages when a thread references a doc that exists there, and writes to Confluence when I ask it to publish something. A triage summary, a weekly roundup, a draft spec I want shared. The MCP turned both of those from “multi-week engineering integration” into “point at the endpoint and go.”

The runtime

The first version of Q ran on the Claude Agent SDK locally on my laptop. Every sleep, Wi-Fi blip, or closed terminal took it down. I migrated it to Anthropic’s Managed Agents API and stood up the Slack webhook gateway on Google Cloud Run. It has been running untouched since.

Memory followed the same direction. The old version kept session state in SQLite on my laptop, which tied every learning to that machine’s uptime. Moving to managed memory stores decouples Q’s state from my hardware entirely.

Two more agents

Q wasn’t alone for long. An engineer I work with watched what Q was doing for my PM work and built two more: Scancy, which investigates production incidents end-to-end, and Percy, which writes the code change to fix them. (Q is short for Quincy. Yes, the other two were named to rhyme. I admit I find this funny.) The shape of his agents differs from Q (different inputs, different surfaces, different judgment calls), but the instinct underneath is the same. Notice the part of the job that’s repetitive and predictable, then give an agent enough context to handle it. Each of us, automating our own corners.

I don’t know yet how much of this generalizes. What I do know is that the second and third agents didn’t need me to write them. They needed me to demonstrate that the first one was worth the effort.

A coordination layer

Today the three agents work in parallel but don’t talk to each other. When a production alert fires, the choreography is four manual @-mentions in Slack: someone pings Scancy to investigate, pings Q to file the ticket, pings Percy to write the fix, pings a reviewer to approve the PR. Four handoffs per incident, all coordinated by humans typing into a thread.

I’m building a coordination layer where Q becomes the first line of defense. Every Datadog alert comes in through a webhook, Q classifies it into one of five buckets (Noise, Acknowledge, Investigate, Engineer, Escalate), and either silences it, routes to the right downstream agent, or pages on-call. The Slack thread becomes the live status surface for the whole workflow.

I haven’t shipped any of it yet. Full writeup once it’s live.

Summary

  • A Slack-native agent for a team’s triage workflow. Reads inbound, dedupes, files, classifies reactions, talks back in thread. Thirty users across several teams.
  • A knowledge base as structured docs. Golden principles, routing rules, product context, repo notes. Q reads them on every session. Reflect cycles update them.
  • A memory layer split into canon and learnings. Canonical docs in one store, observed learnings in another. Structured entries, supersession discipline, no custom retrieval infrastructure in v1.
  • Jira and Confluence via MCP. Schema work lives in the MCP. Q’s side is conversational.
  • A managed-runtime deployment. Migrated from a laptop-resident SDK to Anthropic’s Managed Agents API with a Slack webhook gateway on Cloud Run.