StoryCADApi Class

The main entry point for StoryCADLib API operations.

namespace StoryCADLib.Services.API

public class StoryCADApi : IStoryCADAPI
# In Python, the API is the StoryCAD object itself.
from storycad import StoryCAD

Overview

StoryCADApi provides methods for creating, reading, updating, and deleting story elements. All methods are decorated with [KernelFunction] for Semantic Kernel integration, but can also be called directly.

Key Concepts:

  • All methods return OperationResult<T> - check IsSuccess before using Payload
  • The API maintains a CurrentModel property holding the active story
  • Set CurrentModel via CreateEmptyOutline() or OpenOutline() before other operations

Getting an Instance

using StoryCADLib.Services.IoC;
using StoryCADLib.Services.API;
using CommunityToolkit.Mvvm.DependencyInjection;

// Initialize (once at startup)
BootStrapper.Initialise(headless: true);

// Get the API instance
var api = Ioc.Default.GetRequiredService<StoryCADApi>();
from storycad import StoryCAD

# Initialize (once at startup): the sc object is the API instance
sc = StoryCAD(headless=True)

Outline Operations

CreateEmptyOutline

Creates a new empty story outline based on a template.

public async Task<OperationResult<List<Guid>>> CreateEmptyOutline(
    string name,
    string author,
    string templateIndex)
def create_empty_outline(title, author, template_index="0"):
    ...  # returns a list of element handles; [0] is the Story Overview

Parameters: | Name | Type | Description | |——|——|————-| | name | string | Title of the story | | author | string | Author name | | templateIndex | string | Starter template as a string, "0" to "5": "0" Blank, "1" Overview + Story Problem, "2" Folders, "3" External + Internal Problems, "4" Protagonist + Antagonist, "5" Problems + Characters |

Returns: OperationResult<List<Guid>> - GUIDs of created elements

Example:

var result = await api.CreateEmptyOutline("My Story", "Jane Doe", "0");
if (result.IsSuccess)
{
    Console.WriteLine($"Created {result.Payload.Count} elements");
}
elements = sc.create_empty_outline("My Story", "Jane Doe", template_index="0")
print(f"Created {len(elements)} elements")

OpenOutline

Opens an existing story outline from disk.

public async Task<OperationResult<bool>> OpenOutline(string path)
def open_outline(path):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | path | string | Full path to the .stbx file |

Returns: OperationResult<bool> - true on success

Example:

var result = await api.OpenOutline("C:/Stories/my-story.stbx");
if (result.IsSuccess)
{
    var elements = api.GetAllElements();
}
sc.open_outline("C:/Stories/my-story.stbx")
elements = sc.get_all_elements()

WriteOutline

Saves the current outline to disk.

public async Task<OperationResult<string>> WriteOutline(string filePath)
def write_outline(path):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | filePath | string | Full path for the .stbx file |

Returns: OperationResult<string> - Success message

Example:

var result = await api.WriteOutline("C:/Stories/my-story.stbx");
if (!result.IsSuccess)
{
    Console.WriteLine($"Save failed: {result.ErrorMessage}");
}
try:
    sc.write_outline("C:/Stories/my-story.stbx")
except Exception as error:
    print(f"Save failed: {error}")  # the wrapper raises instead of returning a result

Element Operations

GetAllElements

Returns all elements in the current model.

public OperationResult<ObservableCollection<StoryElement>> GetAllElements()
def get_all_elements():
    ...  # iterable of element handles

Returns: OperationResult<ObservableCollection<StoryElement>> - All story elements


GetElementsByType

Gets all elements of a specific type.

public OperationResult<List<StoryElement>> GetElementsByType(StoryItemType elementType)
def get_elements_by_type(item_type):
    ...  # iterable of element handles

Parameters: | Name | Type | Description | |——|——|————-| | elementType | StoryItemType | The type to filter by |

Valid Types: Problem, Character, Setting, Scene, Folder, Section, Web, Notes, StoryWorld. StoryOverview is also accepted and returns the singleton overview element.

Example:

var result = api.GetElementsByType(StoryItemType.Character);
if (result.IsSuccess)
{
    foreach (var character in result.Payload)
    {
        Console.WriteLine(character.Name);
    }
}
for character in sc.get_elements_by_type(sc.item_type.Character):
    print(character.name)

GetStoryElement

Gets a specific element by its GUID.

public OperationResult<StoryElement> GetStoryElement(Guid guid)
def get_element(element):
    ...  # returns the element's full state as a JSON string

Parameters: | Name | Type | Description | |——|——|————-| | guid | Guid | The element’s unique identifier |

Returns: OperationResult<StoryElement> - The requested element


AddElement

Creates a new story element.

public OperationResult<Guid> AddElement(
    StoryItemType typeToAdd,
    string parentGUID,
    string name,
    string description = "")
def add_element(item_type, parent, name):
    ...  # returns an element handle

Parameters: | Name | Type | Description | |——|——|————-| | typeToAdd | StoryItemType | Type of element to create | | parentGUID | string | GUID of parent element (as string) | | name | string | Name for the new element | | description | string | Optional description |

Returns: OperationResult<Guid> - GUID of created element

Example:

// Get the story overview (root) GUID
var overview = api.GetElementsByType(StoryItemType.StoryOverview);
var rootGuid = overview.Payload.First().Uuid.ToString();

// Add a character
var result = api.AddElement(
    StoryItemType.Character,
    rootGuid,
    "Alex",
    "The protagonist");

if (result.IsSuccess)
{
    Console.WriteLine($"Created character with GUID: {result.Payload}");
}
# Get the story overview (root)
overview = next(iter(sc.get_elements_by_type(sc.item_type.StoryOverview)))

# Add a character
character = sc.add_element(sc.item_type.Character, overview, "Alex")
print(f"Created character with GUID: {character.uuid}")

AddElementWithProperties

Creates a new story element with initial properties and an optional GUID override.

Semantic Kernel name: This method is registered as AddElementWithProperties via [KernelFunction("AddElementWithProperties")] to distinguish it from the basic AddElement overload in SK plugin registration.

public OperationResult<Guid> AddElement(
    StoryItemType typeToAdd,
    string parentGUID,
    string name,
    Dictionary<string, object> properties,
    string GUIDOverride = "")
# Add the element, then set its initial properties.
element = sc.add_element(item_type, parent, name)
sc.update_element_properties(element, {"Role": "Protagonist"})

Parameters: | Name | Type | Description | |——|——|————-| | typeToAdd | StoryItemType | Type of element to create | | parentGUID | string | GUID of parent element (as string) | | name | string | Name for the new element | | properties | Dictionary | Initial property values to set | | GUIDOverride | string | Optional: specify a GUID for the new element (must be unique) |

Returns: OperationResult<Guid> - GUID of created element

Example:

var props = new Dictionary<string, object>
{
    { "Role", "Protagonist" },
    { "Age", "28" },
    { "Archetype", "The Hero" }
};

var result = api.AddElement(
    StoryItemType.Character,
    rootGuid,
    "Elena",
    props);
elena = sc.add_element(sc.item_type.Character, overview, "Elena")
sc.update_element_properties(
    elena,
    {"Role": "Protagonist", "Age": "28", "Archetype": "The Hero"},
)

UpdateElementProperty

Updates a single property on an element.

public OperationResult<StoryElement> UpdateElementProperty(
    Guid elementUuid,
    string propertyName,
    object value)
def update_element_property(element, property_name, value):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | elementUuid | Guid | The element’s GUID | | propertyName | string | Name of the property to update | | value | object | New value for the property |

Returns: OperationResult<StoryElement> - Updated element

Example:

var result = api.UpdateElementProperty(
    characterGuid,
    "Role",
    "Protagonist");
sc.update_element_property(character, "Role", "Protagonist")

UpdateElementProperties

Updates multiple properties on an element.

public OperationResult<bool> UpdateElementProperties(
    Guid elementGuid,
    Dictionary<string, object> properties)
def update_element_properties(element, properties):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | elementGuid | Guid | The element’s GUID | | properties | Dictionary | Property names and values |

Example:

var props = new Dictionary<string, object>
{
    { "Name", "Alex" },
    { "Role", "Protagonist" },
    { "Age", "32" }
};
api.UpdateElementProperties(characterGuid, props);
sc.update_element_properties(
    character,
    {"Name": "Alex", "Role": "Protagonist", "Age": "32"},
)

DeleteElement

Moves an element to the trash.

public Task<OperationResult<bool>> DeleteElement(Guid elementToDelete)
def delete_element(element):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | elementToDelete | Guid | The element’s GUID |

Returns: OperationResult<bool> - true on success


GetElement

Returns a single element with all its fields as a serialized object. Unlike GetStoryElement which returns a typed StoryElement, this returns the full serialized representation including all fields.

public OperationResult<object> GetElement(Guid guid)
def get_element(element):
    ...  # returns the full serialized element as a JSON string

Parameters: | Name | Type | Description | |——|——|————-| | guid | Guid | The element’s unique identifier |

Returns: OperationResult<object> - Serialized element with all fields

Example:

var result = api.GetElement(characterGuid);
if (result.IsSuccess)
{
    Console.WriteLine(result.Payload); // Full serialized element
}
import json

detail = json.loads(sc.get_element(character))
print(detail)  # Full serialized element

UpdateStoryElement

Replaces an entire story element by deserializing a new element and updating it in the model. For updating individual properties, prefer UpdateElementProperty or UpdateElementProperties.

public OperationResult<bool> UpdateStoryElement(object newElement, Guid guid)
# Prefer update_element_property / update_element_properties for individual fields.
sc.update_element_properties(element, {"Name": "Alex"})

Parameters: | Name | Type | Description | |——|——|————-| | newElement | object | Serialized element data (will be deserialized via StoryElement.Deserialize) | | guid | Guid | The GUID of the element to replace |

Returns: OperationResult<bool> - true on success


MoveElement

Moves an element to a new parent in the outline’s ExplorerView tree. Validates against circular references, moving the root element, and moving the TrashCan.

public OperationResult<bool> MoveElement(Guid elementGuid, Guid newParentGuid)
def move_element(element, new_parent, index=None):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | elementGuid | Guid | GUID of the element to move | | newParentGuid | Guid | GUID of the new parent element |

Returns: OperationResult<bool> - true on success

Validation:

  • Cannot move an element to itself
  • Cannot move the root element
  • Cannot move the TrashCan
  • Cannot move an element to one of its own descendants (circular reference check)

Example:

// Move a scene under a different folder
var result = api.MoveElement(sceneGuid, newFolderGuid);
if (result.IsSuccess)
{
    Console.WriteLine("Element moved successfully");
    await api.WriteOutline("my-story.stbx"); // Save changes
}
# Move a scene under a different folder
sc.move_element(scene, new_folder)
print("Element moved successfully")
sc.write_outline("my-story.stbx")  # Save changes

Search Operations

SearchForText

Searches for text across all elements.

public OperationResult<List<Dictionary<string, object>>> SearchForText(string searchText)
def search_for_text(text):
    ...

Returns: List of dictionaries containing matching elements and properties.


SearchForReferences

Finds elements that reference a target element.

public OperationResult<List<Dictionary<string, object>>> SearchForReferences(Guid targetUuid)
def search_for_references(element):
    ...

SearchInSubtree

Searches within a subtree of the outline.

public OperationResult<List<Dictionary<string, object>>> SearchInSubtree(
    Guid rootNodeGuid,
    string searchText)
def search_in_subtree(element, text):
    ...

RemoveReferences

Removes all references to a target element from other elements in the outline.

public OperationResult<int> RemoveReferences(Guid targetUuid)
def remove_references(element):
    ...  # returns the number of references removed

Parameters: | Name | Type | Description | |——|——|————-| | targetUuid | Guid | GUID of the element whose references should be removed |

Returns: OperationResult<int> - Number of references removed


Relationship Operations

AddCastMember

Adds a character to a scene’s cast.

public OperationResult<bool> AddCastMember(Guid scene, Guid character)
def add_cast_member(scene, character):
    ...

AddRelationship

Creates a relationship between two characters.

public OperationResult<bool> AddRelationship(
    Guid source,
    Guid recipient,
    string desc,
    bool mirror = false)
def add_relationship(a, b, desc, mirror=False):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | source | Guid | First character’s GUID | | recipient | Guid | Second character’s GUID | | desc | string | Description of relationship | | mirror | bool | If true, creates reciprocal relationship |


Trash Operations

RestoreFromTrash

Restores a deleted element from the trash.

public Task<OperationResult<bool>> RestoreFromTrash(Guid elementToRestore)
def restore_from_trash(element):
    ...

EmptyTrash

Permanently deletes all trashed elements.

public Task<OperationResult<bool>> EmptyTrash()
def empty_trash():
    ...

Resource Data Methods

These methods provide access to StoryCAD’s built-in reference data.

GetExamples

Gets example values for a property.

public OperationResult<IEnumerable<string>> GetExamples(string propertyName)
def get_examples(property_name):
    ...

GetConflictCategories

Gets available conflict type categories.

public OperationResult<IEnumerable<string>> GetConflictCategories()
def get_conflict_categories():
    ...

GetKeyQuestionElements

Gets key question prompts for story development.

public OperationResult<IEnumerable<string>> GetKeyQuestionElements()
def get_key_question_elements():
    ...

Internal / Advanced Methods

These methods are used internally by StoryCAD and the Collaborator plugin. They are available in the public API but most consumers should use the standard methods above.

SetCurrentModel

Sets the active StoryModel. Used by the Collaborator plugin to synchronize the API with StoryCAD’s active outline.

public void SetCurrentModel(StoryModel model)
# (no direct Python equivalent: this is a .NET Collaborator-plugin
# synchronization hook used internally by StoryCAD)

Parameters: | Name | Type | Description | |——|——|————-| | model | StoryModel | The active StoryModel from ShellViewModel |

Note: This is one of the few API methods that does not return OperationResult<T>.


DeleteStoryElement

Moves an element to the trash. This is an older variant that accepts a string GUID. Prefer DeleteElement(Guid) for new code.

public OperationResult<bool> DeleteStoryElement(string uuid)
# Older string-GUID variant; prefer delete_element(element) for new code.
def delete_element(element):
    ...

Parameters: | Name | Type | Description | |——|——|————-| | uuid | string | The element’s GUID as a string |

Returns: OperationResult<bool> - true on success