Skip to content

Authoring

This guide explains how SwarmForge turns generated or hand-written graph payloads into validated SwarmDefinition objects. It does not explain runtime orchestration or provider setup.

This guide is for developers building graph editors, prompt pipelines, or code generators that emit swarm JSON. It assumes that you already understand the runtime concepts at a high level.

After reading this guide, you should be able to:

  • understand the generated payload contract
  • validate node, edge, and variable data
  • compile JSON payloads into runnable swarm definitions
  • locate the bundled editor skills

The authoring package turns generated, UI-authored, or hand-written graph payloads into validated SwarmDefinition objects for the SwarmForge SDK.

It also provides a promptly-style single-agent prompt-generation workflow via generate_agent_prompt(...) for teams that want research plus staged prompt synthesis directly in the SDK.

Package Responsibilities

  • ship skills.sh-compatible editor skill folders for copy/paste installation
  • validate generated JSON payloads before runtime execution
  • infer variable definitions from edge requirements when variables are omitted
  • compile normalized payloads into runtime graph objects
  • support code-driven and UI-driven graph exports as the integration format
  • provide staged prompt generation helpers for single-agent system instructions
  • provide a full agent-builder SDK flow with readiness, onboarding, confirmation, and generation steps
  • generate one-shot voice-agent prompt artifacts from a typed build spec

Single-agent prompt generation

Use generate_agent_prompt(...) when you already know the assistant you want and do not need the full onboarding lifecycle.

This flow mirrors promptly's single-agent prompt generation path and is the right fit when:

  • your app already collected the key inputs in a form or wizard
  • you want one final system prompt instead of a multi-turn builder conversation
  • you want optional tool schema generation plus a prompt title in the same run

What it does

  • research synthesis for the requested assistant role
  • phased prompt generation across role, rules, workflow, and tools
  • deterministic final prompt composition
  • prompt title generation
  • optional tool schema generation

Usage

GenerateAgentPromptRequest accepts the main topic plus optional structured inputs that shape the prompt.

  • topic: the assistant or workflow you want to generate
  • inputs: user or product context already collected by your app
  • category_label and category_type: optional metadata for specialized prompting
  • generate_tools: include generated tool definitions when true
  • tools_format: output schema dialect such as openai or gemini

Example

python
from swarmforge.authoring import GenerateAgentPromptRequest, generate_agent_prompt

result = generate_agent_prompt(
    GenerateAgentPromptRequest(
        topic="Support assistant for refunds and order status",
        inputs={
            "channel": "chat",
            "tone": "concise and calm",
            "escalation_policy": "Escalate fraud, threats, and chargebacks",
        },
        category_label="Customer Support",
        category_type="persona",
        generate_tools=True,
        tools_format="openai",
    )
)

print(result.prompt_title)
print(result.meta_prompt)
print(result.research_summary)
print(result.json_tools)

Result payload

GenerateAgentPromptResult returns the final prompt plus the intermediate artifacts most apps want to store or inspect.

  • meta_prompt: the final system instruction
  • research_summary: the research synthesis used during generation
  • sources: any linked research sources the workflow captured
  • prompt_title: short human-readable title for the generated prompt
  • json_tools: optional generated tool definitions

One-shot voice-agent prompt build

Use generate_voice_agent_build(...) when your product already has a structured voice-agent configuration and you want one request to produce prompt artifacts without a conversational onboarding loop.

This is prompt building, not agent-code generation. The output is a prompt/tool artifact bundle that your app can store, inspect, or pass into a runtime.

The build spec is represented by VoiceAgentBuildSpec. It keeps voice-call requirements explicit:

  • template: template identity and voice_call_agent category
  • business: company, industry, market, languages, and tone
  • call: inbound, outbound, or missed-call callback direction plus the call goal
  • use_case: transaction/service types, qualification focus, default locations, and custom context
  • knowledge_base: approved knowledge IDs and cases where search is mandatory
  • integrations: CRM, booking, SMS, calendar, property, order, webhook, or custom API URLs
  • tools: allowed tool types, required logical tools, and custom tool definitions
  • data_collection: required, optional, and custom entities to capture
  • behavior: phone-style behavior defaults such as short turns and one question at a time
  • guardrails: safety rules, refusal rules, forbidden actions, disallowed topics, confirmation requirements, and tool-use limits
  • compliance: consent, recording, PII, prohibited-claim, and regulated-disclaimer rules
  • escalation: human handoff targets and escalation triggers
  • voice_runtime: timezone, locale, opening style, and voice timing hints
  • quality: success criteria and failure conditions
  • outputs: which artifacts to generate

Example

python
from swarmforge.authoring import VoiceAgentBuildSpec, generate_voice_agent_build

spec = VoiceAgentBuildSpec(
    template={"id": "real_estate_voice", "category": "voice_call_agent"},
    business={
        "company_name": "Atlas Realty",
        "industry": "real estate",
        "market": "Casablanca",
        "languages": ["en", "fr", "ar"],
        "brand_tone": "professional and concise",
    },
    call={
        "direction": "inbound",
        "main_goal": "qualify property buyers and book viewings",
        "target_caller": "property buyer",
    },
    knowledge_base={
        "enabled": True,
        "knowledge_base_ids": ["properties"],
        "search_required_for": ["availability", "pricing", "neighborhood facts"],
    },
    tools={
        "generate_tools": True,
        "allowed_tool_types": ["function", "apiRequest", "query", "sms", "endCall", "webhook"],
        "required_logical_tools": ["book_viewing", "send_sms_confirmation"],
        "generate_missing_tools": True,
    },
    data_collection={
        "required_entities": ["name", "phone", "budget", "preferred_location"],
        "optional_entities": ["bedrooms", "move_in_timeline"],
    },
    guardrails={
        "safety_rules": ["Do not provide legal, medical, or financial advice."],
        "refusal_rules": ["Refuse requests to bypass identity, consent, or booking rules."],
        "forbidden_actions": ["Do not promise property availability without checking tools."],
        "confirmation_required_for": ["booking", "sms", "crm_update", "call_transfer"],
        "tool_use_rules": ["Use knowledge search before answering pricing or availability questions."],
        "fallback_response": "I do not have verified information for that, but I can take a note or transfer you.",
    },
)

result = generate_voice_agent_build(spec, tools_format="openai")

print(result.system_prompt)
print(result.tools_schema)
print(result.call_flow)
print(result.summary_schema)
print(result.eval_scenarios)

Result payload

VoiceAgentBuildResult returns only prompt-building artifacts:

  • system_prompt: generated voice-agent system instruction
  • tools_schema: generated or normalized tool definitions
  • call_flow: ordered call-flow steps
  • summary_schema: JSON schema for post-call summary extraction
  • eval_scenarios: baseline scenarios for testing the generated prompt
  • research_summary, sources, and prompt_title

Full agent-builder flow (onboarding plus generation)

If you want a dedicated walkthrough for the chat-style builder lifecycle and the HTTP transport, read Agent Builder.

Use AgentBuilderFlow when you want the SDK to manage the complete lifecycle:

  • readiness analysis
  • onboarding-plan generation
  • conversational or form-based onboarding collection
  • generation confirmation
  • staged prompt generation with step tracking

Repository example: python examples/agent_builder_flow.py

python
from swarmforge.authoring import AgentBuilderFlow

flow = AgentBuilderFlow()

start = flow.start_onboarding("Build me a refund support assistant")
if not start.ready:
    print(start.clarifying_question)
else:
    session = start.session
    turn = flow.process_onboarding_turn(
        session,
        "It should resolve refund requests quickly in customer chat and escalate risky cases.",
    )
    if turn.all_fields_collected:
        confirm = flow.process_confirmation_turn(session, "yes, start")
        if confirm.confirmed:
            result = flow.run_generation(session, generate_tools=True, tools_format="openai")
            print(result.prompt_title)

For form-first apps, call run_full_flow(...) and pass collected onboarding inputs directly.

Conversational UI example

This pattern works well when your app stores a builder session and sends one user reply at a time.

python
from swarmforge.authoring import AgentBuilderFlow

flow = AgentBuilderFlow()
start = flow.start_onboarding("Build me a LinkedIn outbound agent for B2B SaaS demos")

if not start.ready:
    print({"type": "clarification", "question": start.clarifying_question})
else:
    session = start.session
    print({"type": "assistant", "message": start.opening_message})

    turn = flow.process_onboarding_turn(
        session,
        "It should target founders by LinkedIn DM, qualify interest, and book demos for our AE team.",
    )
    print(turn.reply)

    if turn.all_fields_collected:
        confirm = flow.process_confirmation_turn(session, "yes, generate it")
        print(confirm.reply)
        if confirm.confirmed:
            result = flow.run_generation(session, generate_tools=True, tools_format="openai")
            print(result.meta_prompt)

Form-first app example

This pattern is useful when your frontend collects onboarding answers in a form wizard and only needs the SDK for planning plus generation.

python
from swarmforge.authoring import AgentBuilderFlow

flow = AgentBuilderFlow()

run = flow.run_full_flow(
    seed_request="Build me a customer support copilot for refund and shipping issues",
    onboarding_inputs={
        "intent": "Resolve refund and shipping questions quickly",
        "audience_channel": "Existing customers in web chat",
        "constraints": "Escalate fraud, threats, and legal complaints",
    },
    generate_tools=True,
    tools_format="gemini",
)

print(run.generation_result.prompt_title)
print(run.start.session.to_payload())

Persisting builder session state

AgentBuilderSession is serializable, so apps can store it between requests.

python
from swarmforge.authoring import AgentBuilderSession

session_payload = start.session.to_payload()
restored_session = AgentBuilderSession.from_payload(session_payload)

# Save session_payload in your database, cache, browser state, or HTTP client.
# Later, restore the same builder session for another SDK call.

Expose AgentBuilderFlow over HTTP

If your app wants the builder lifecycle over HTTP instead of direct SDK calls, use create_authoring_app(...) from swarmforge.api.

python
from swarmforge.api import create_authoring_app

app = create_authoring_app()

Installed-package server:

bash
uvicorn swarmforge.api.authoring:create_authoring_app --factory --reload

The authoring transport exposes these routes:

  • POST /v1/authoring/agent-builder/start
  • POST /v1/authoring/agent-builder/onboarding-turn
  • POST /v1/authoring/agent-builder/confirm
  • POST /v1/authoring/agent-builder/generate
  • POST /v1/authoring/agent-builder/generate/stream
  • POST /v1/authoring/agent-builder/run
  • POST /v1/authoring/agent-builder/voice/run

Use the serialized session returned from start as the wire format for follow-up onboarding, confirmation, and generation calls.

Progress events for WS or SSE clients

If your frontend wants live progress during generation, call POST /v1/authoring/agent-builder/generate/stream and consume the text/event-stream response.

The streamed event contract is simple and works well directly with SSE or as a payload shape you forward through your own WebSocket layer:

  • start: generation began
  • phase: one generation phase completed, with phase set to values such as research, phase_a, phase_b, phase_c, phase_d, title, or tools
  • generation_result: final prompt payload from GenerateAgentPromptResult
  • session: final serialized AgentBuilderSession
  • done: terminal success event
  • error: terminal failure event with an error message

Example browser usage with fetch stream readers or a server-side WebSocket bridge:

text
event: start
data: {"stage":"generating"}

event: phase
data: {"phase":"research", ...}

event: phase
data: {"phase":"phase_a", ...}

event: generation_result
data: {"prompt_title":"Refund Support Prompt", ...}

event: done
data: {"status":"completed"}

Skills

SwarmForge ships skills.sh-compatible editor skills under skills/ for users who want to copy a skill folder into their editor agent.

Editor Skills

The skills/ folder uses the standard skill layout from the skills.sh ecosystem:

  • one folder per skill
  • one SKILL.md file with name and description frontmatter
  • optional bundled references/ files for deeper SwarmForge context

Available editor skills:

To use one in GitHub Copilot for VS Code, copy the chosen folder into .github/skills/<skill-name>/ in the target workspace.

Generated Payload Contract

Nodes must include:

  • node_key
  • name
  • is_entry_node

Optional node metadata:

  • intent
  • capabilities
  • sub_agents — list of handoff routes declared directly on the source node

Each sub_agents entry must include:

  • sub_agentnode_key of the target node
  • handoff_description
  • required_variables

Optional top-level variables can be supplied explicitly. If omitted, SwarmForge derives them from sub_agents requirements.

This payload shape works well as an integration contract for graph editors such as React Flow or any internal builder that exports JSON.

Build a swarm from generated JSON

python
from swarmforge.authoring import build_swarm_definition

generated = {
    "nodes": [
        {
            "node_key": "triage",
            "name": "Triage",
            "persona": "",
            "is_entry_node": True,
            "sub_agents": [
                {
                    "sub_agent": "billing",
                    "handoff_description": "Transfer only after confirming the request is billing-related.",
                    "required_variables": ["account_id"],
                }
            ],
        },
        {
            "node_key": "billing",
            "name": "Billing",
            "persona": "Direct and calm",
            "is_entry_node": False,
        },
    ],
}

swarm = build_swarm_definition(generated, swarm_id="support", name="Support Swarm")

Validation Rules

  • exactly one node must be the entry node
  • node_key values must be unique
  • node display names must be unique case-insensitively
  • edge endpoints must reference existing nodes
  • self-targeting edges are rejected
  • variable reducer rules must be valid

Validation failures raise ValueError before the graph reaches the runtime layer.

Reference example

The example below shows the core authoring path: generated JSON, graph compilation, and evaluation-ready inspection output.

python
from pprint import pprint

from swarmforge.authoring import (
    build_swarm_definition,
)
from swarmforge.evaluation import (
    build_graph_snapshot,
    build_swarm_scenario_generation_context,
)


generated = {
    "nodes": [
        {
            "node_key": "triage",
            "name": "Triage",
            "persona": "",
            "is_entry_node": True,
            "sub_agents": [
                {
                    "sub_agent": "billing",
                    "handoff_description": "Transfer after confirming the request is about charges, invoices, or payments.",
                    "required_variables": ["account_id"],
                },
                {
                    "sub_agent": "technical",
                    "handoff_description": "Transfer after confirming the request is about app behavior, errors, or device issues.",
                    "required_variables": ["affected_device_model"],
                },
            ],
        },
        {
            "node_key": "billing",
            "name": "Billing",
            "persona": "Calm and direct",
            "is_entry_node": False,
        },
        {
            "node_key": "technical",
            "name": "Technical",
            "persona": "Structured and concise",
            "is_entry_node": False,
        },
    ],
}

swarm = build_swarm_definition(generated, swarm_id="support", name="Support Swarm")
graph_snapshot = build_graph_snapshot(swarm)

print("Runtime snapshot:")
pprint(graph_snapshot)
print()
print("Scenario generation context:")
print(build_swarm_scenario_generation_context(graph_snapshot))

Resulting Artifacts

  • generated stands in for the JSON your application, a React Flow canvas, or an LLM-backed generator would produce.
  • build_swarm_definition(...) validates the payload, normalizes it, and returns a runnable SwarmDefinition.
  • build_graph_snapshot(...) converts that runtime object into a plain inspection artifact that is easier to print, diff, score, or feed into evaluation helpers.
  • build_swarm_scenario_generation_context(...) turns the graph snapshot into a compact text summary for scenario generation and evaluation prompts.

The outputs are useful across different parts of the SDK:

  • The runtime snapshot shows the normalized IDs, variables, and default behavior config that the runtime will actually use.
  • The scenario context gives you a human-readable summary of reachable routes and required variables, which is useful before you run conversations.

Released as open source.