Docs Building Apps

Apps

An App is the unit of repeatable work in Aitroop: the operational guide to creating, running, editing, versioning, and sharing.

The mental model. An App = a form + an ordered list of stages + a declaration of what comes out. The form makes it parametric. The stages make it multi-step. The declared output makes it chainable and shareable. Strip away one and you have something less than an App; strip away all three and you're just chatting.

Creating an App: the 4-phase flow

You create Apps by talking to the agent. The built-in aitroop-app-create skill (the App Builder) follows a structured 4-phase process every time. Understanding the phases helps you guide the conversation and know what to expect.

Phase 0: Understand intent

When your message contains a trigger phrase, the App Builder activates and asks 1-5 clarifying questions:

  1. What should the app do? One-sentence goal.
  2. What inputs does it need? Free text, files, dates, selections?
  3. What should it produce? Report, code file, spreadsheet, structured data?
  4. How many steps / stages? Single agent call, or multi-stage pipeline?
  5. Any specific tools or integrations needed? Web search, file processing, OAuth?
Skip the questions by being specific. If your initial message answers all five already, the App Builder jumps straight to Phase 1. Most experienced users write a paragraph that covers task + inputs + outputs + tools in one go.

Phase 1: Design the App

The App Builder constructs the full AppDef JSON. It picks:

  • Name: based on what the App does. Title-cased.
  • Icon: a single emoji that fits the use case.
  • Tags: searchable keywords.
  • Inputs: picks the right type for each variable. text for short identifiers, textarea for long content, select for fixed options, daterange for time windows, file for uploads.
  • Stages: single by default. Splits into multiple stages only when the work naturally has separable steps.
  • Artifacts: picks markdown for prose, csv for tabular, json for structured, html for rendered pages, image for visuals, code for source files.
  • Resources: adds Skills and Connects the App needs.
  • Timeouts: default 3 min, bumps to 5-10 min for heavy research.

Phase 2: Validate

Before saving, the App Builder runs internal checks:

  • Every id in inputs, stages, and artifacts is unique.
  • Every {{field_id}} reference in stage goals matches a real input.
  • Inter-stage references (Stage 2 reading Stage 1's artifact) are correctly wired.
  • At least one stage produces an artifact if the App should have visible output.
  • required: true is only on inputs that genuinely block the run.
  • Goals are specific enough; vague goals get rewritten.

If validation fails, the App Builder fixes the issue itself rather than asking you. You'll only see Phase 3 if validation passes.

Phase 3: Create or update via API

The App Builder calls the platform's REST API:

# New App
POST https://app.aitroop.net/api/apps
Authorization: Bearer <AT_USER_TOKEN>
Content-Type: application/json

# Existing App
PUT https://app.aitroop.net/api/apps/<appId>
Authorization: Bearer <AT_USER_TOKEN>
Content-Type: application/json

The body is the full AppDef JSON. The platform persists it, assigns a version number, and returns the App ID. You don't see this happen; it's behind the scenes.

Phase 4: Present to user

The App Builder reports back with:

  • App name and what it does.
  • List of inputs with types.
  • List of stages with descriptions.
  • What artifacts it produces.
  • App ID, so you can find it.
  • An offer to refine.

At this point the App is live, runnable, and in your library.

Example: three Apps at three complexity levels

Simple: one input, one stage

You: Create an app that explains a technical term
in plain English for a non-technical audience. Input is
the term. Output is a 200-word explanation.

Agent: <designs the App, no clarifying questions
needed since you gave inputs+output+length up front>

 App: Plain English Explainer 📖
 Input:  term (text, required)
 Stage:  Explain {{term}} in ~200 words for a
       non-technical audience...
 Output: explanation.md (markdown)

Medium: multiple inputs, one stage, requires a Connect

You: Create an app that summarizes my unread Gmail
from the last N days into a priority-ranked list.

Agent: Two questions:
 1. Default for N (number of days)?
 2. How many emails should the summary cover?

You: Default N=3. Top 20 emails.

Agent: <designs the App>

 App: Email Triage 📧
 Inputs:
   days_back (number, default 3)
   max_emails (number, default 20)
 Stage: Read the last {{days_back}} days of unread Gmail.
       Rank top {{max_emails}} by urgency...
 Output: triage.md (markdown)
 Resources: skills=[], connects=[google]

Notice google in connects. The first time you run this App, you'll be prompted to authorize Gmail access. After that, it runs without prompting.

Complex: multi-stage with a human review step

You: Create an outreach pipeline. Stage 1: find
companies matching an ICP description. Stage 2: enrich
each with public info. Stage 3: I review and remove
rows. Stage 4: draft personalized emails for survivors.

Agent: <asks 3 questions, you answer>

 App: Outreach Pipeline 🎯
 Inputs:
   icp (textarea, required)
   target_count (number, default 30)
 Stages:
   1. find (agent) to leads.csv
   2. enrich (agent) to enriched.csv
   3. review (human, paused until you approve)
   4. draft (agent) to drafts.md
 Resources: skills=[web-search], connects=[]

When you run this App, the platform executes stages 1 and 2 automatically. Stage 3 pauses and shows enriched.csv in a review pane. You remove rows you don't want, then click Approve and continue. Stage 4 runs with the approved subset.

Running an App

From the App library

  1. Click Apps in the sidebar.
  2. Click the App you want to run.
  3. The App page opens, with the form on the left and a placeholder for output on the right.
  4. Fill required fields (marked with a red asterisk).
  5. Optional fields show placeholders or pre-filled defaults.
  6. Click Run (large button at the bottom of the form).

What you see during the run

The page splits and the right pane fills with:

  • Stage indicator at top: "Stage 1 of 3: research_and_write".
  • Reasoning trace: the agent's plan, tool calls (web searches, Skill invocations), partial outputs.
  • Live artifact preview: as the agent writes the artifact, you see it appear in real time.
  • Run controls: a Cancel button is available while the run is in progress.

What happens after the run completes

The artifacts are saved to the run's history. From the artifact preview:

  • Download: pick a format (the artifact's native format, or PDF/DOCX for renderables).
  • Copy: copy raw content to clipboard.
  • Edit in chat: opens a new chat scoped to this artifact for quick tweaks.
  • Share: generates a link to the artifact (visibility depends on App settings).

Inputs that haven't changed

The next time you visit the App page, the form pre-fills with the last inputs you used. Click the reset icon (🔄 next to a field) to clear it back to the default.

Re-running with the same inputs

On any past run, click Re-run. This duplicates the run with identical inputs. Useful for: refreshing time-sensitive data (e.g., a "latest news" App), confirming consistency, A/B-testing prompt changes between versions.

Editing an App

Conversational edit (recommended for non-trivial changes)

  1. On the App page, click Edit in chat (sometimes labeled "Chat with this App").
  2. A chat opens with the App's design loaded as context.
  3. Tell the agent what to change in natural language. Examples:
    • "Add a select for output language with English / Chinese / Spanish."
    • "Split the stage into 'research' and 'write'. Pass the research notes as context to the write stage."
    • "Change the timeout to 10 minutes."
    • "Remove the company_url input."
  4. The agent shows you a diff: what changed, what stayed the same.
  5. Approve. The agent calls PUT /api/apps/{id}. New version saved.

Direct field edit (for quick changes)

  1. On the App page, click Edit.
  2. The editor opens with all fields visible: name, icon, tags, inputs, stages, artifacts, resources.
  3. Change any field directly:
    • Click an input's type dropdown to swap text → textarea.
    • Click an option to rename it.
    • Type into the goal field to edit the agent's instruction.
    • Drag inputs to reorder them.
  4. Click Save. New version saved.

Editing the goal: common patterns

The stage goal is where most of the App's behavior lives. Common edits:

  • Add structure: "Output as: Section A (one paragraph) / Section B (bullet list)…"
  • Add constraints: "Maximum 500 words." "Use only sources from the last 12 months."
  • Add personalization hooks: "Match the tone of the audience in {{tone}}."
  • Improve specificity: replace vague verbs ("review") with concrete ones ("score 1-10 with rationale").

Versioning

Every save creates a new version. Versions are numbered (v1, v2, v3…). The App page has a Versions tab listing all of them.

From the Versions tab you can

  • See history: when each version was saved, who saved it, the change summary.
  • View a version's full AppDef: click any version to see its full configuration.
  • Compare two versions: pick two and see a side-by-side diff.
  • Roll back: promote any older version to "current" with one click. The current behavior reverts; the version you rolled back from is preserved in history.

Schedules and versioning

Schedules use the current version of the App by default. So if you fix a bug in the App on Sunday, Monday's scheduled run uses the fix.

For stability (a customer-facing report that should not change unexpectedly), pin a Schedule to a specific version. Pinned Schedules ignore future App edits.

Sharing and access

Three visibility levels per App:

  • Private: only you can see and run it. Default.
  • Team: visible to everyone in your workspace. Best for shared internal Apps.
  • Public link: anyone with the link can run it (depending on plan). Inputs and outputs are still sandboxed per run.

Per-user Connects under team Apps

When a teammate runs a Team App, the run uses their Connects, not yours. A shared "Daily inbox triage" App reads your Gmail when you run it, your colleague's when they run it. Each user authorizes their own Connects.

Forking

Anyone with view access to a Team App can fork it: creates a private copy with its own version history. Useful for "I want this app but with my modifications" without affecting the shared version.

Multi-stage Apps in detail

When to use multiple stages

Reach for multi-stage when:

  • The work naturally breaks into "do X, then with the result of X do Y".
  • You want to re-run just the last step without re-running the expensive earlier steps.
  • You need a human approval checkpoint in the middle.
  • One step needs deterministic transformation (a script stage between two agent stages).

How stages share data

Each stage's artifact is automatically available to the next stage. Refer to it in the next stage's goal with the template syntax:

# Stage 2 goal referencing Stage 1's artifact
Take the CSV produced by Stage 1 ({{ stages.find.leads }})
and enrich each row with the company's funding history.
Output the same CSV with three new columns:
total_funding, last_round, last_round_date.

The 3 stage types in practice

agent: the default

The agent reads the inputs (and any prior artifacts), uses installed Skills and authorized Connects, and produces the declared artifacts. Best for: reasoning, summarization, drafting, research.

script: deterministic transformations

A Python or Node script that runs in the sandbox without invoking a language model. Best for: filtering CSVs, deduplication, format conversion, exact arithmetic. Fast and predictable.

human: pause for review

The run pauses. The platform shows the goal text and any prior artifacts to the user. The user modifies, approves, or rejects. The next stage runs with the human's output. Best for: approval checkpoints, "pick the best N", "fix anything that looks wrong before sending".

Operational example: re-running just the last stage

Suppose your 3-stage App ran successfully but the final stage's draft is off. To avoid re-doing stages 1 and 2:

  1. Open the run from the App's Runs tab.
  2. Click Re-run from stage.
  3. Pick Stage 3.
  4. Stages 1 and 2's artifacts are reused. Stage 3 runs again with whatever you fixed.

From the API the same thing looks like:

POST /api/apps/<appId>/run
Content-Type: application/json

{
  "input": { ...same form values as the prior run... },
  "start_from_stage_index": 2,
  "prior_execution_id": "exec_8f4c2e1b"
}

See Executions for the full execution lifecycle, cancel, gates, and SSE streaming.

Calling Apps from the API

Everything you can do in the UI is also available over REST. Useful when you want an App invoked from a webhook, a CI job, another agent, or a teammate's own script.

Authentication

Get a token from Settings to API Tokens to Create. Treat it like a password: scope it tightly, rotate it, never commit it. All endpoints expect:

Authorization: Bearer $AT_USER_TOKEN

The core endpoints

Method & PathWhat it does
GET /api/appsList your Apps.
POST /api/appsCreate an App. Body is the full AppDef JSON.
GET /api/apps/:appIdGet an App's current definition.
PUT /api/apps/:appIdUpdate; saves a new version.
DELETE /api/apps/:appIdArchive the App (recoverable for 30 days).
POST /api/apps/:appId/runTrigger an execution. Body has input, optional is_test, start_from_stage_index, prior_execution_id.
GET /api/app-executions/:execIdPoll for status / artifacts.
GET /api/app-executions/:execId/streamSSE stream of live events.
POST /api/app-executions/:execId/cancelStop a running execution.

End-to-end example: trigger an App, wait for it, download the artifact

# 1. Trigger the run
EXEC=$(curl -s -X POST \
  https://app.aitroop.net/api/apps/app_8f4c2e1b/run \
  -H "Authorization: Bearer $AT_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "input": { "company_name": "Stripe" } }' \
  | jq -r .id)

# 2. Wait until done (poll, or use SSE)
while true; do
  STATUS=$(curl -s \
    -H "Authorization: Bearer $AT_USER_TOKEN" \
    https://app.aitroop.net/api/app-executions/$EXEC \
    | jq -r .status)
  echo "status: $STATUS"
  [[ "$STATUS" == "completed" || "$STATUS" == "failed" ]] && break
  sleep 5
done

# 3. Download the artifact
ART=$(curl -s -H "Authorization: Bearer $AT_USER_TOKEN" \
  https://app.aitroop.net/api/app-executions/$EXEC/artifacts \
  | jq -r '.[0].id')
curl -s -H "Authorization: Bearer $AT_USER_TOKEN" \
  https://app.aitroop.net/api/artifacts/$ART/download \
  -o brief.md

When an App fails

Common failure modes and how to diagnose them:

SymptomLikely causeFix
TimeoutStage exceeded timeout_msBump timeout, or split into two stages
"Connect not authorized"Required Connect was revokedRe-authorize in Settings to Connects
"Required input missing"The form was submitted with a blank required fieldMark less aggressively as required, or fix form
Vague or generic outputGoal not specific enoughEdit goal; add structure, constraints, examples
Wrong formatStage goal asked for one format, declared anotherAlign goal and artifact_defs.format

The "Debug in chat" workflow

  1. Open the failed run.
  2. Click Debug in chat.
  3. A new chat opens with the run's full context: inputs, partial artifacts, agent's reasoning trace, error.
  4. Talk to the agent: "Why did this fail? What should I change?"
  5. The agent diagnoses, suggests a fix, and (often) directly edits the App to apply it.
  6. Re-run.

Common mistakes to avoid

  • Vague goals. "Do research" is too vague. Name the sources, the depth, the output structure.
  • Missing artifacts. A stage with no artifact_defs produces nothing visible.
  • Too many required inputs. Default everything you can. Long forms get abandoned.
  • Undersized timeout. Heavy research needs 5-10 min (timeout_ms: 600000).
  • Wrong input type. textarea for long text, not text. select for fixed options.
  • Over-decomposing. If a single conversation feels like one thought, one stage is enough. Don't pre-split.
  • Goal too short. A two-line goal often underperforms a 10-line goal with structure and constraints.

FAQ & troubleshooting

My App produces inconsistent output across runs. How do I tighten it?

Two levers, in order:

  1. Tighten the goal. Add a numbered output structure, a word-count target, examples of acceptable output. The agent matches more closely when the spec is more precise.
  2. Lower the model's freedom. Add to the goal: "If you are unsure about any section, say 'insufficient data' rather than guessing." The agent prefers a hedged answer over a confident one when given permission.

For truly deterministic transforms (parsing, filtering, formatting), replace the agent stage with a script stage.

Can a stage skip itself based on input?

Yes; use show_if on the input that controls it (e.g. "show_if": "include_competitors == true"), and use a conditional block in the goal: {{#if include_competitors}} ... {{/if}}. The agent reads the unrendered goal, so the conditional is what tells it whether to do the work.

How do I pass the output of one App into another App?

Two patterns:

  • Schedule + webhook. Have App A's Schedule POST to App B's /run endpoint. Pass the artifact URL as input.
  • Chain via a script stage. Stage 1 calls App A via the API and reads the artifact. Stages 2+ continue in the same App.

A native "App composition" feature is on the roadmap.

Can two people edit the same App at once?

Soft yes: each save is a new version, so two people editing in parallel won't overwrite each other. But last-saved wins for the "current" pointer. For team Apps under active development, agree on an owner or use the conversational edit (which is serialized through the agent).

How do I get an export of an App's definition?

curl https://app.aitroop.net/api/apps/<appId> \
  -H "Authorization: Bearer $AT_USER_TOKEN" \
  -o my-app.json

Save the JSON to git, share with a teammate, or paste into a new workspace via POST /api/apps.

Can I import an App someone else exported?

Yes. Open Apps → New → Import JSON, paste the AppDef, and click Save. The platform validates and creates the App in your workspace. Required Skills and Connects are listed; you'll be prompted to authorize Connects on first run.

My App's goal references a Connect that the user hasn't authorized; what happens?

The platform detects this before launching the sandbox. The run transitions to failed with connect_unauthorized, naming the missing provider. The user is prompted inline to authorize, then can retry. Scheduled runs alert the schedule owner.

Can I limit who can run an App?

Three controls:

  • Visibility: private / team / public link.
  • Role-gated runs: restrict by org role (admins-only, members-only). Configured under Apps to Settings.
  • Per-user Connects: even if a teammate can run the App, the run uses their tokens, not yours.