Skip to content

Documentation navigation

Studio Authoring and Debugging

Prepare apps for Studio, change run settings, and investigate execution problems.

#Studio Authoring and Debugging

Studio works best when your apps tell it a little about themselves: what prompts to suggest, how to run, and which variant to start with. This guide shows how to author apps so they behave cleanly in Studio, and how to track down problems fast once they are running.

#Authoring Studio-Friendly Apps

For reliable Studio behavior, each app module should expose:

  • at least one top-level Agent or Swarm
  • APP_PROMPTS (recommended)
  • optional APP_NAME and APP_DESCRIPTION
  • optional APP_INVOCATION
  • optional APP_CAPABILITIES
  • optional configure_variant(variant: str | None)

#Name and Description

Studio names an app after its file (hardware_diagnostics.py shows as "Hardware Diagnostics") and describes it with the first line of the module docstring. Set APP_NAME and APP_DESCRIPTION when you want to say it better. Both must be plain string literals, because the catalog is built by reading the file, not by importing it:

Python
"""Hardware diagnostics demo."""

APP_NAME = "Hardware Diagnostics Assistant"
APP_DESCRIPTION = "Reads a sensor dump and explains which part is failing."

The app id and route stay derived from the file name, so renaming the display name never breaks a bookmark. An entry in maivn_studio.json still overrides both, which is the place for a name or description you cannot put in the code.

To see the catalog exactly as Studio will show it, without starting the server or needing an API key:

Shell
uv run python -m maivn_studio --list-apps

#Prompt Metadata

APP_PROMPTS entries support:

  • name
  • content
  • description
  • is_default
  • structured_output (tool name)
  • message_type (human or redacted)
  • variant (pre-select an app variant)
Python
APP_PROMPTS = [
    {
        "name": "Seed Memory",
        "content": "Store this deployment runbook...",
        "description": "Seed turn for memory lifecycle",
        "is_default": True,
        "message_type": "human",
        "variant": "focus",
    }
]

#Invocation Defaults

APP_INVOCATION lets Studio prefill execution options:

Python
APP_INVOCATION = {
    "model": "balanced",
    "reasoning": "medium",
    "memory_config": {
        "enabled": True,
        "level": "focus",
        "summarization_enabled": True,
    },
}

Studio treats repeated deployments of the same agent as separate invocations. UI code should key cards by invocation, assignment, or action ID rather than agent_name alone.

Supported keys:

  • model
  • reasoning
  • force_final_tool
  • targeted_tools
  • metadata
  • memory_config
  • system_tools_config
  • orchestration_config (accepted for compatibility, but the current SDK does not send it to the runtime)
  • allow_private_in_system_tools

#Conversation and History Capabilities

Interactive Agent and Swarm apps default to conversational behavior with message-history restoration. Authors normally omit APP_CAPABILITIES; Studio then accepts live follow-ups and can offer Continue for an eligible completed session in History.

Declare a single-turn app when a second message would be misleading or unsafe:

Python
APP_CAPABILITIES = {
    "interaction_mode": "single_turn",
}

Studio then explains that the app allows single-turn runs only and withholds both live follow-up and History Continue. An explicit declaration is authoritative. Invalid interaction modes, restore modes, or value shapes are reported as app configuration errors rather than being replaced with permissive defaults.

A conversational app can also disallow reconstruction from persisted messages while still accepting follow-ups in its current live session:

Python
APP_CAPABILITIES = {
    "interaction_mode": "conversation",
    "restore_modes": [],
}

Use "restore_modes": ["message_history"] to declare that History may reconstruct the conversation. Omitting restore_modes for a conversational app selects that same message-history default. "checkpoint" is also a valid declared restore mode, but it does not by itself authorize Studio's message-history Continue path.

The user-visible paths have different boundaries:

PathWhat Studio startsWhen it is available
Live follow-upA new executor invocation with the live session's message contextConversational interactive Agent or Swarm sessions; never a Batch Matrix turn
History ContinueA new execution reconstructed from persisted messages on the same threadThe app allows message_history, the source is a completed reconstructible turn owned by the current user, the app and matching executor still load, and the source is the current thread tip
Batch or triggered runAn immutable execution snapshotIt is inspected as that run; start another batch or trigger execution for new work

A continuation is not replay or resume. Studio does not rerun prior actions, revive the old Python runtime, or treat an earlier approval as authorization for a new action. Message history supplies conversational context. Separately, an SDK tool dependency may opt one stable producer result into same-thread reuse with result_scope='conversation'; see Dependencies.

#Variant Hook

Use configure_variant when your module must switch runtime wiring:

Python
def configure_variant(variant: str | None) -> None:
    if variant == "focus":
        ...
    elif variant == "clarity":
        ...

#Discovery Workflow

When you add a new app, point Studio's discovery at the directory that holds it. Studio rescans on demand from the Scan Repo action in the catalog and merges the result with apps you have already approved.

This keeps config aligned with actual modules and avoids drift in id/module/category.

#Introspection Workflow

Open an app in Studio's catalog and click into the Config tab to confirm how Studio resolved your module:

  • resolved agents and swarms
  • tool inventory and dependencies
  • discovered prompts
  • private-data schema
  • default invocation (from APP_INVOCATION)

This is the fastest way to confirm that Studio is reading your module as expected.

#Session Debugging Workflow

  1. Pick the app, optionally choose a variant, send a controlled test message.
  2. Watch the Inspect tab for the live SSE stream. (The Inspector also surfaces the Recall tab for memory state, Config for the active invocation config, and Schedule for upcoming scheduled fires.)
  3. Resolve any interrupt_required prompts inline.
  4. Send follow-ups in the same session to keep thread_id continuity.
  5. Use the per-event detail view for replayable event history.

Studio runs locally for the developer who owns the data, so it keeps full bridge visibility for debugging. If you reuse the same event patterns in a customer-facing app, switch your backend bridge to EventBridge(..., audience="frontend_safe") to apply the safe redaction layer.

If you are debugging duplicate activity in Studio, separate transport replay from logical duplicate delivery:

  • replay duplicates usually indicate a reconnect/history issue
  • repeated interrupts or adjacent identical status messages usually indicate overlapping producer paths in your own emission code

#Batch Matrix Debugging

Use Studio's Batch Matrix when you need to compare prompts, variants, models, or targeted tools in one grouped turn. Each matrix row becomes one batch item and can override variant, model, reasoning, system_message, and targeted_tools without changing the app module. Uniform batches reuse the top-level invocation settings for every item.

The batch SSE sequence is:

  • batch_start: pending row metadata
  • batch_item_complete: one completed row payload
  • batch_complete: aggregate status and all item results

#Runtime Patching Without Restart

Studio supports live edits to a loaded app's prompts, descriptions, tags, limits, and per-agent / per-swarm settings while a session is running. Use this for rapid iteration while diagnosing behavior. Saved prompt and description edits persist in maivn_studio.json, and runtime agent/swarm patches apply only to the live loaded instance for the rest of the session.

#Memory-Specific Debugging Tips

For memory apps:

  • reuse the same thread_id across turns
  • verify enrichment events: memory_retrieving, memory_retrieved, memory_indexing
  • expect some memory/document extraction phases after final
  • validate recall using a follow-up query and check hit counts in enrichment payloads

If retrieval appears empty:

  1. confirm memory_config.level is at least glimpse
  2. confirm thread continuity (thread_id)
  3. allow short delay for async post-finalize indexing