> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getthread.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Flows, status automations, and Triage Agent intents

> Build no-code automation in Thread: route tickets with Flows, keep statuses honest with status automations, and teach the Triage Agent with Intents.

export const MarkComplete = ({id, signalDone = false}) => {
  const KEY = "thread-onboarding-completed";
  const read = () => {
    try {
      return JSON.parse(localStorage.getItem(KEY) || "[]");
    } catch (e) {
      return [];
    }
  };
  const [localDone, setLocalDone] = useState(false);
  const done = signalDone || localDone;
  useEffect(() => {
    const sync = () => setLocalDone(read().includes(id));
    sync();
    window.addEventListener("thread-onboarding-updated", sync);
    return () => window.removeEventListener("thread-onboarding-updated", sync);
  }, [id]);
  const toggle = () => {
    if (signalDone) return;
    const list = read();
    const next = list.includes(id) ? list.filter(x => x !== id) : [...list, id];
    try {
      localStorage.setItem(KEY, JSON.stringify(next));
    } catch (e) {}
    setLocalDone(next.includes(id));
    window.dispatchEvent(new Event("thread-onboarding-updated"));
  };
  return <button onClick={toggle} style={{
    width: "100%",
    padding: "0.7rem 1rem",
    marginTop: "1.5rem",
    borderRadius: "8px",
    border: "1px solid " + (done ? "#00B398" : "rgba(128,128,128,0.35)"),
    background: done ? "rgba(0,179,152,0.12)" : "transparent",
    color: done ? "#00B398" : "inherit",
    fontWeight: 600,
    fontSize: "0.95rem",
    cursor: "pointer",
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    gap: "0.5rem"
  }}>
      <span aria-hidden="true">{done ? "✓" : "○"}</span>
      {done ? "Completed" : "Mark as complete"}
    </button>;
};

export const ByRoleProgress = () => {
  useEffect(() => {
    const KEY = "thread-onboarding-completed";
    const TEAL = "#00B398";
    const BASE = "/start-here/roles/";
    const DONE_ICON = '<svg class="thread-rc-doneicon size-4" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#00B398" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">' + '<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>' + '<polyline points="22 4 12 14.01 9 11.01"/></svg>';
    const COURSES = [{
      slug: "technician",
      steps: ["why-thread", "get-around-inbox", "day-one-setup", "daily-workflows", "ai-toolkit", "notifications-and-customers"]
    }, {
      slug: "dispatcher",
      steps: ["why-dispatch-in-thread", "read-the-board", "assign-and-schedule", "ai-for-dispatch"]
    }, {
      slug: "service-ops-manager",
      steps: ["set-up-the-desk", "sla-and-dispatch", "analytics-and-qa", "roll-out-and-adopt"]
    }, {
      slug: "csm-account-manager",
      steps: ["client-intelligence-and-health", "qbrs-and-reporting", "retention-and-expansion"]
    }, {
      slug: "security-compliance-owner",
      steps: ["security-work-in-thread", "data-and-compliance", "security-runbooks"]
    }, {
      slug: "sales-business-development",
      steps: ["the-ai-service-pitch", "quote-and-handoff"]
    }, {
      slug: "msp-owner-leadership",
      steps: ["the-rollout", "outcomes-and-analytics", "scale-ai-service"]
    }, {
      slug: "automation-engineer",
      steps: ["flows-and-intents", "thread-mcp-and-api", "build-with-super-magic"]
    }];
    const COURSE_SLUGS = new Set(COURSES.map(c => c.slug));
    const readLocal = () => {
      try {
        return JSON.parse(localStorage.getItem(KEY) || "[]");
      } catch (e) {
        return [];
      }
    };
    const isDone = (done, id) => done.includes(id);
    const decorate = () => {
      const done = readLocal();
      const scope = document.getElementById("sidebar-content") || document;
      const links = [...scope.querySelectorAll('a[href*="' + BASE + '"]')].filter(a => !a.closest("main"));
      links.forEach(a => {
        const m = (a.getAttribute("href") || "").match(/\/start-here\/roles\/([^/?#]+)\/([^/?#]+)/);
        if (!m) return;
        if (!COURSE_SLUGS.has(m[1])) return;
        const id = m[1] + "/" + m[2];
        const d = isDone(done, id);
        const has = a.querySelector(".thread-rc-check");
        if (d && !has) {
          const s = document.createElement("span");
          s.className = "thread-rc-check";
          s.textContent = "✓ ";
          s.style.color = TEAL;
          s.style.fontWeight = "700";
          a.insertBefore(s, a.firstChild);
        } else if (!d && has) {
          has.remove();
        }
      });
      COURSES.forEach(course => {
        const li = scope.querySelector('li[id="' + BASE + course.slug + '"]');
        if (!li) return;
        const row = li.querySelector(":scope > button") || li.querySelector(":scope > a") || li.firstElementChild;
        if (!row) return;
        const nameSpan = [...row.querySelectorAll("span")].find(s => s.textContent.trim() && !s.classList.contains("thread-rc-coursecheck"));
        if (!nameSpan) return;
        const allDone = course.steps.length > 0 && course.steps.every(s => isDone(done, course.slug + "/" + s));
        const has = nameSpan.querySelector(".thread-rc-coursecheck");
        if (allDone && !has) {
          const s = document.createElement("span");
          s.className = "thread-rc-coursecheck";
          s.setAttribute("aria-hidden", "true");
          s.style.display = "inline-flex";
          s.style.alignItems = "center";
          s.style.verticalAlign = "-0.2em";
          s.style.marginRight = "0.35em";
          s.innerHTML = DONE_ICON;
          nameSpan.insertBefore(s, nameSpan.firstChild);
        } else if (!allDone && has) {
          has.remove();
        }
      });
    };
    decorate();
    const iv = setInterval(decorate, 600);
    window.addEventListener("thread-onboarding-updated", decorate);
    window.addEventListener("storage", decorate);
    return () => {
      clearInterval(iv);
      window.removeEventListener("thread-onboarding-updated", decorate);
      window.removeEventListener("storage", decorate);
    };
  }, []);
  return null;
};

<ByRoleProgress />

Most of the desk's repetitive work never needs code. Thread gives you three in-app layers of automation, and they stack: **Flows** move and update tickets on conditions you define, **status automations** keep the queue's state honest, and **Intents** teach the Triage Agent to handle whole request types conversationally — unattended. Start here before you reach for the API; you'll automate more, faster, with less to maintain.

## Flows: route and update without a human

A [Flow](/inbox/flows) watches for a thread update — a new ticket, a reply, a status change, a board move — checks a condition, and takes an action: reroute the board, set priority, assign an owner, post a note, run a recap. No AI judgment, just deterministic rules that fire the same way every time.

The rhythm that keeps Flows maintainable:

<Steps>
  <Step title="Name the trigger">
    Decide exactly what update should wake the Flow — new thread, a specific board, a status change. Narrow triggers are easier to reason about than catch-all ones.
  </Step>

  <Step title="Write one clear condition">
    Match on the smallest signal that identifies the case. One Flow, one job — chain several small Flows rather than building one that does everything.
  </Step>

  <Step title="Choose the action">
    Route, reassign, set priority, post an internal note, or fire a recap. Actions that write to the PSA sync straight through.
  </Step>

  <Step title="Test on a real thread">
    Flows only evaluate threads updated *after* the Flow exists. Add an internal note to an existing thread to nudge it through and confirm the Flow fires as intended.
  </Step>
</Steps>

<Tip>
  A Flow can fire a Super Magic skill automatically — that's a **Super Magic Agent** (Super Magic + Flows). Prove the skill by hand in the composer first, then wire the Flow to run it unattended. You'll meet skill authoring in [Build with Super Magic](/start-here/roles/automation-engineer/build-with-super-magic).
</Tip>

## Status automations: keep the queue honest

[Status automations](/inbox/status-automations) handle the state transitions your team forgets: flip a thread back to *In Progress* when a client replies to a *Waiting* ticket, move stale *Waiting on Client* threads toward closure, or revert a courtesy reply so it doesn't look resolved. They run on the same update-driven engine as Flows but are scoped to the one job of keeping status accurate — which is what your XLA timers and reporting depend on.

Set these up early. A queue where the status always reflects reality is the foundation every other automation and every analytics number sits on.

## Intents: teach the Triage Agent what to resolve

Where a Flow routes, an **Intent** *understands*. An Intent teaches the Triage Agent to recognize a request type — password reset, VPN issue, status check, new-hire setup — and handle it conversationally: ask the clarifying questions, gather the details, and where it's allowed, resolve and close the ticket in your PSA before a technician ever sees it.

<Steps>
  <Step title="Pick a high-volume, well-scoped request">
    The best first intents are frequent and predictable. [Create your first intents](/ai-agents/create-your-first-intents) walks the anatomy: variations (the ways people phrase the ask), arguments (what to collect), and replies.
  </Step>

  <Step title="Let the assistant draft it">
    The [Intent Creation Assistance intent](/ai-agents/intent-creation-assistance-intent) is a built-in intent that helps you *write* intents — describe the request in plain language and it drafts the variations and arguments for you to refine.
  </Step>

  <Step title="Add custom rules for the edges">
    When default behavior isn't enough — conditional routing, special handling for a VIP or a site — the [custom rules beta partner guide](/ai-agents/custom-rules-beta-partner-guide) shows how to layer rule-based control onto an intent's judgment.
  </Step>
</Steps>

<Note>
  Intents are admin-controlled. If you're building them, you (or the admin you work with) need Triage Agent access — the same gate that governs which agent actions Super Magic and Thread MCP can offer.
</Note>

### Flow or Intent — which one?

| You want to…                                     | Reach for                            | Why                                                                  |
| ------------------------------------------------ | ------------------------------------ | -------------------------------------------------------------------- |
| Reroute every ticket on a board to a new queue   | **Flow**                             | Deterministic condition, no interpretation needed.                   |
| Flip status when a client replies                | **Status automation**                | A scoped, state-only transition.                                     |
| Handle every "I'm locked out" request end-to-end | **Intent**                           | Needs to read the ask, gather details, and respond conversationally. |
| Run a saved Super Magic skill on new escalations | **Super Magic Agent** (Flow + skill) | The Flow is the trigger; the skill is the work.                      |

<MarkComplete id="automation-engineer/flows-and-intents" />

## Next

You've automated inside Thread. Next, put the same tool layer *outside* Thread — in your own AI client, and over the API.

<Card title="Thread MCP, the tool reference, and the API" icon="plug" href="/start-here/roles/automation-engineer/thread-mcp-and-api">
  Connect Thread MCP to an external client, learn the tool reference, and drive Thread over webhooks, APIs, and Rewst.
</Card>


## Related topics

- [Automation Engineer](/start-here/roles/automation-engineer.md)
- [Scheduling Intent Detector](/skill-library/triage-and-routing/scheduling-intent-detector.md)
- [Status Automations: Auto-Update Thread Statuses](/inbox/status-automations.md)
