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

# Apps & Missions

> Apps are built from the platform's primitives and deployed as content. Missions is the first.

export const Carousel = ({slides}) => {
  const dwell = 6000;
  const count = slides.length;
  const [index, setIndex] = useState(0);
  const [stopped, setStopped] = useState(false);
  const [reduced, setReduced] = useState(false);
  const [hovered, setHovered] = useState(false);
  const [focused, setFocused] = useState(false);
  const rotating = !stopped && !reduced && count > 1;
  const paused = hovered || focused;
  useEffect(() => {
    const query = window.matchMedia('(prefers-reduced-motion: reduce)');
    const update = () => setReduced(query.matches);
    update();
    query.addEventListener('change', update);
    return () => query.removeEventListener('change', update);
  }, []);
  useEffect(() => {
    if (!rotating || paused) return undefined;
    const timer = setTimeout(() => setIndex(current => (current + 1) % count), dwell);
    return () => clearTimeout(timer);
  }, [index, rotating, paused, count]);
  const choose = next => {
    setStopped(true);
    setIndex((next + count) % count);
  };
  const onKeyDown = event => {
    if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;
    if (event.target.closest('[data-rmiz-modal]')) return;
    if (event.key === 'ArrowLeft') {
      event.preventDefault();
      choose(index - 1);
    } else if (event.key === 'ArrowRight') {
      event.preventDefault();
      choose(index + 1);
    }
  };
  return <div className="my-6 rounded-2xl outline-none focus-visible:ring-2 focus-visible:ring-primary" role="region" aria-roledescription="carousel" aria-label="Screenshots" tabIndex={0} onKeyDown={onKeyDown} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} onFocus={() => setFocused(true)} onBlur={event => {
    if (!event.currentTarget.contains(event.relatedTarget)) setFocused(false);
  }}>
      <Frame>
        <div className="relative aspect-[16/10] w-full overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-800">
          {slides.map((slide, i) => <div key={slide.src} className="absolute inset-0" role="group" aria-roledescription="slide" aria-label={`${i + 1} of ${count}`} inert={i !== index} style={{
    opacity: i === index ? 1 : 0,
    visibility: i === index ? 'visible' : 'hidden',
    pointerEvents: i === index ? 'auto' : 'none',
    transition: reduced ? 'none' : 'opacity 450ms ease, visibility 450ms'
  }}>
              <img className="block h-full w-full object-cover object-left-top dark:hidden" loading={i === 0 ? 'eager' : 'lazy'} src={slide.src} alt={slide.alt} />
              <img className="hidden h-full w-full object-cover object-left-top dark:block" loading={i === 0 ? 'eager' : 'lazy'} src={slide.src.replace(/\.(png|svg)$/, '.dark.$1')} alt={slide.alt} />
            </div>)}
          {count > 1 && <button type="button" aria-label="Previous picture" className="absolute left-2 top-1/2 flex h-9 w-9 -translate-y-1/2 items-center justify-center
                rounded-full border border-gray-300 bg-white/90 text-gray-900
                dark:border-gray-600 dark:bg-gray-900/90 dark:text-gray-100" onClick={() => choose(index - 1)}>
              <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <path d="M10 3 5 8l5 5" />
              </svg>
            </button>}
          {count > 1 && <button type="button" aria-label="Next picture" className="absolute right-2 top-1/2 flex h-9 w-9 -translate-y-1/2 items-center justify-center
                rounded-full border border-gray-300 bg-white/90 text-gray-900
                dark:border-gray-600 dark:bg-gray-900/90 dark:text-gray-100" onClick={() => choose(index + 1)}>
              <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <path d="M6 3l5 5-5 5" />
              </svg>
            </button>}
        </div>
      </Frame>
      <div className="flex items-center gap-3 px-1 pt-1">
        <div className="flex-1 text-sm text-gray-600 dark:text-gray-400" aria-live={rotating && !paused ? 'off' : 'polite'} aria-atomic="true">
          {slides[index].caption}
        </div>
        {count > 1 && <div className="flex items-center">
            {slides.map((slide, i) => <button key={slide.src} type="button" aria-label={`Picture ${i + 1}`} aria-current={i === index ? 'true' : undefined} className="flex h-6 w-8 items-center justify-center" onClick={() => choose(i)}>
                <span className={i === index ? 'block h-1.5 w-6 rounded-full bg-primary' : 'block h-1.5 w-6 rounded-full bg-gray-300 dark:bg-gray-600'} />
              </button>)}
          </div>}
      </div>
    </div>;
};

An **app** is something built on BlobHub from its building blocks and deployed as content, with no platform code of
its own. It is made of the same sessions, threads, workflows and schedules you build with, so its runs, messages and
approvals land on the same record, under the same access rules. Missions, engineering work delegated to coding agents
as missions made of cells, is the one app built so far, and [the catalog](#the-catalog) lists it beside apps from other
domains.

## What an app is

An app is a directory of content, kept in a repository and reviewed like source code. It holds workflow definitions,
such as an orchestrator written as ordinary Python that the CLI compiles into a `logic.code` component; palettes, the
templates and settings the app picks from as it runs; a playground layout, the screen a person works the app through;
and manifests naming the workflows and schedulers it deploys into. Every definition, palette, layout and manifest is in
BlobHub's own formats, so what the repository holds for each is exactly what the platform runs.

The platform has no notion of an app. Deploying one uses the CLI's ordinary per-blob deploys,
[`blobhub workflow deploy`](/cli/workflow/overview) and `blobhub scheduler deploy`, and the app carries an install
tool of its own that runs them in order and sets up the rest: the session the app lives in, the service accounts it
runs as, and its palettes. Running that tool again updates what it set up. The CLI has no single command that deploys
a whole app.

## Missions

Missions delegates engineering work to coding agents. A mission is a graph of cells, each a bounded piece of work,
wired by `depends_on` edges from a cell to the cells it waits on, and a cell becomes ready only once every cell it
depends on is completed. A cell in `draft` or `inactive` is never picked up, so a mission can be shaped or paused
before anything in it runs.

Each cell runs a procedure, chosen from a palette of templates: a small graph of two kinds of step. A `worker_task`
step hands work to a coding agent, and an `external_input` step waits for a person's answer. Each step's outcome picks
the next one, so a procedure can loop, from a review back to the implementation, until it reaches its end.

An orchestrator advances every mission. It is a workflow written as `logic.code`, started once a minute by a recurring
[schedule](/general/schedules), and each run ticks every few seconds: it reads the missions and their cells, decides
what each active cell needs next, does it, and sleeps until the next tick. It keeps no position of its own between
ticks, so when a run crashes, the next one reads the same state and carries on from there.

A `worker_task` step reaches its agent through [blobhub-worker](/general/agents-and-workers). The orchestrator opens a
thread for the step that names its agent, Claude Code, Codex or Antigravity, and the cell's workspace, a folder on the
worker's machine that every step of the cell shares. In the Acme demo organization, one worker runs the missions'
Claude Code, Codex and Antigravity cells. The shipped agents run `guarded`, so each step's agent answers to a
[policy](/general/policies-and-approvals): the `standard` policy asks a person before a `git push` and refuses
force-pushes, hard resets and writes outside the work folder, and `read_only`, for reviewers, refuses writes. Like
every policy, these are a guardrail against mistakes, not a sandbox. The orchestrator and the worker each run as a
service account of their own, so a cell's record shows which of them did what.

## Mission Control

Mission Control is the screen Missions is worked through: a widget, `app.missions.control`, on the app's
[playground](/general/playgrounds). The missions rail down the left lists every mission with its id, cell count and
status, and can be hidden. The board in the middle shows the selected mission as **Graph**, its cells and their
`depends_on` edges with each cell showing its status, or as **Board**, the same cells in status lanes with each
prerequisite shown as an `↳ after` chip. **New Mission** and **New Cell** create an untitled record at once, named in
place.

Opening a cell brings up its dock on the right: its brief, its current step, its dependencies and its activity feed,
one entry per run outcome, decision, artifact and change of state, oldest first, styled by who produced it. A blocked
cell shows what it is waiting for, a step's options or an agent's question, and answering it there is how the cell
moves again. Mission Control writes only missions, cells, their dependencies and a person's requests; dispatching work
and advancing a cell are the orchestrator's alone.

<Carousel
  slides={[
{
  src: "/general/images/apps/graph.png",
  alt:
    "Mission Control's Graph view zoomed in: two cells waiting for a person, the cells behind them and one done",
  caption: "Two cells wait for a person, and the rollout waits on both.",
},
{
  src: "/general/images/apps/board.png",
  alt: "Mission Control's Board view: the mission's 22 cells in lanes by stage, from Draft to Done",
  caption: "The same mission by stage, from draft to done.",
},
{
  src: "/general/images/apps/mission-control.png",
  alt: "Mission Control's Graph view fitted to the whole mission, each cell showing its status",
  caption: "The whole mission at once, every cell showing its status.",
},
{
  src: "/general/images/apps/cell.png",
  alt: "Mission Control's cell dock with a cell's brief and activity feed",
  caption:
    "One cell opened: its brief, its workflow, and the thread of what was asked and the answer a person gave.",
},
]}
/>

## The catalog

The same platform holds very different work, so apps are listed across domains, each with its status. Only Missions
is built and running; each other row's status says where it stands, and an example is an app a team could build from
the same primitives. Deep Research is a public workflow in the [Gallery](https://blobhub.io/gallery) today, without
the sign-off its row names. Govern is the rule that matters while an app runs, and Audit the question someone will ask
afterwards; outside Missions, both describe a design, not something that exists.

| Domain | App | Status | Govern | Audit |
| - | - | - | - | - |
| Engineering | Missions | live | Each cell runs under a policy and a permission posture; a push stops for a person, and force-pushes and hard resets are refused. | Who or what moved this cell, and what did the agent do in every turn? |
| Finance | Day Trader | in build | Allocations and loss limits decide what goes through; one switch stops everything. | For this order: what did it see, which version of the strategy ran, and who changed it? |
| Research | Deep Research | a Gallery workflow | A person signs off before a report is published. | Which source produced this claim? |
| Customer support | Support Desk | example | Refunds above a limit wait for a person. | Why did this customer get this answer? |
| Legal and compliance | Contract Review | example | Agents propose, counsel approves. | Which playbook version, and who accepted each deviation? |
| Security and IT | Alert Triage | example | Containment needs a second person. | What was checked before this alert was closed? |
| Sales and marketing | Account Research | example | Nothing is sent unapproved. | What was sent to whom, on what basis? |
| Supply chain | Replenishment Planner | example | Orders off the supplier list need a buyer. | Why this quantity, from which forecast? |

The [Apps page](https://blobhub.io/apps) on blobhub.io lists the same apps.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.