> ## 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.

# Set up the desk

> How a service manager structures Thread: the service team model, Inbox teams and pods, and the Views technicians work from — no shared firehose queue.

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 />

Everything downstream — routing, XLAs, analytics, coaching — keys off how your desk is structured. Get the shape right first and the rest of your job gets easier. This lesson sets up three things in order: your **service team model**, your **Inbox teams and pods**, and the **Views** each technician opens to.

## Decide your service team model

Before you create anything in Thread, decide how the desk is organized. Most MSPs land on one of a few shapes:

* **Tiered** — Tier 1 triage and quick fixes, Tier 2/3 for escalations and projects. Clean for coverage and career paths.
* **Pod-based** — small cross-tier squads, each owning a set of clients end-to-end. Strong on client relationships and context.
* **Blended** — a triage pod up front feeding specialist teams behind it. Common once a desk grows past a handful of techs.

There's no single right answer — but decide it deliberately, because your Thread teams, dispatch, and Views should all mirror it. The [service team structure guide](/inbox/service-team-structure) walks through the trade-offs and how each model maps onto Thread.

<Tip>
  Structure Thread to match how you *actually* run the desk, not an org chart you aspire to. You can restructure later, but every technician builds muscle memory around the shape you ship — so ship the real one.
</Tip>

## Build your Inbox teams and pods

Once you know the model, build it in Thread. [Inbox teams](/inbox/inbox-teams) are the groups you route work to and report on — a team can be a tier, a pod, an after-hours crew, or a specialist squad. Members can belong to more than one team, so a Tier 2 engineer who also covers a key client can sit in both.

Teams do three jobs for you at once:

| Teams give you…                    | Why it matters as a manager                                                                                     |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| A routing target                   | Auto-dispatch and Flows can send work to a **team**, not just a person — so coverage survives PTO and turnover. |
| A reporting boundary               | Magic Analytics and View insights roll up by team, so you can compare pods and spot the overloaded one.         |
| A permissions and visibility scope | Teams shape what each group sees and can act on, keeping techs focused on their own board.                      |

Set up the teams that mirror your model, assign members, and name them the way your desk talks — "Tier 1", "Healthcare Pod", "After Hours" — so routing rules and reports read plainly later.

<Note>
  Newly synced members from your PSA aren't automatically added to teams or Views. Adding a new hire is a two-step habit: put them on the right **team**, then add them to the **Views** that team works from.
</Note>

## Set up the Views your techs live in

A [View](/inbox/views-and-insights) is a saved, filtered slice of the queue — the lens each technician opens Inbox to. This is the single biggest quality-of-life lever you control: a good View is a focused, prioritized worklist; a bad one is an undifferentiated firehose that buries urgent work.

Build Views around how each team works, not around every field in the PSA. A few that most desks want:

* **My open work** — assigned to me, not closed, sorted by priority or XLA risk.
* **Team unassigned** — the pod's incoming work waiting for a first touch. This is your dispatch surface.
* **Breaching soon** — anything with an XLA timer about to trip, across the team.
* **Waiting on client** — parked tickets, so nothing goes silent for days unnoticed.

Every View carries **insights** — live counts and trends for that slice — so a View isn't only a worklist, it's a readout. Keep an eye on the unassigned and breaching-soon Views throughout the day; they're your earliest warning that the desk is falling behind.

<Warning>
  Don't over-build Views. Five sharp Views a technician actually uses beat twenty they ignore. Start each team with the handful above, then add a View only when someone hits a real, repeated filtering need.
</Warning>

## Wire technicians in

With teams and Views in place, onboarding a technician is quick and repeatable:

<Steps>
  <Step title="Confirm the PSA sync">
    Make sure the member exists in Thread. New members arrive from your PSA sync — if someone's missing, run a sync before you try to place them.
  </Step>

  <Step title="Add them to their team(s)">
    Place them on the [Inbox team](/inbox/inbox-teams) that matches their tier or pod. This is what makes team routing and reporting include them.
  </Step>

  <Step title="Add them to the right Views">
    Add them to the Views their team works from — Views don't inherit automatically. Without this step, a new tech opens Inbox to nothing.
  </Step>

  <Step title="Spot-check their first day">
    Have them open Inbox and confirm they land on a focused View of their own work, not the whole desk. If it's a firehose, the View or team assignment needs a tweak.
  </Step>
</Steps>

<MarkComplete id="service-ops-manager/set-up-the-desk" />

## Next

Your desk has structure. Now put the clock and the routing on top of it — so the right work reaches the right pod, on time.

<Card title="XLAs & dispatch" icon="gauge-high" href="/start-here/roles/service-ops-manager/sla-and-dispatch">
  Response timers, auto-dispatch profiles, available-for-dispatch, and business hours.
</Card>


## Related topics

- [Service & Ops Manager](/start-here/roles/service-ops-manager.md)
- [Set Up Thread Inbox by Service Team Structure](/inbox/service-team-structure.md)
- [Set Up the Autotask PSA Ticketing Integration](/integrations/creating-a-autotask-api-user.md)
