OpenAssetIO [beta]
An abstract API for generalising interactions between a host application and an asset management system
Glossary

Asset Management System

Responsible for managing Entities, in some structured fashion. Often based around some kind of a database. Many asset management systems allow entities to be 'versioned', or related to each other. The primary goal being make collaborative working easier, and to allow the history of work to be tracked. Very similar to source control within a software development environment.

Context

A Context is an object that holds all of the persistent state between a set of connected calls to the API. Its properties define details of how a host is calling the Asset API.

The Context's locale may contain information to better define which part of the users workflow the call is being generated by.

The Context also holds an opaque (to the host) data pointer, created by the ManagerInterface, that contains any persistent state its implementation wishes to store.

See also
Context

Digital Contentent Creation tool (DCC)

Within the Media and Entertainment industry (and possibly further afield), Digital Content Creation tools refer to the applications used to produce graphics, audio and other artistic works. For example, Adobe Photoshop, Autodesk Maya, and Foundry's Nuke.

entity

An 'entity' is the generic name for something that is managed by a Asset Management System. Entities are identified by an Entity Reference. We choose the term 'entity' as some systems give a specific meaning to an 'asset', such that all assets are entities, but not all entities are assets.

As a simplified example, an 'asset' may always require to exist in some organizational hierarchy, and be the only thing that can be version managed. An entity however, can refer to anything that the Asset Management System knows about, including a part of the organizational hierarchy, or a specific version or component part of an 'asset'.

In the core API, entities hold data for one or more traits. Traits have an id, and zero or more properties holding simple value types.

This makes it relatively straightforward for an Asset Management System to provide support for any entity that a host may wish to store, by simply storing and retrieving these three properties from its persistent store. If it wishes, or understands specific entity traits, it can always provide more sophisticated mappings to its own internal types, to provide a better user experience.

Entity Reference

An 'entity reference' is the currency of the core API layer. It is used to identify an entity within an Asset Management System and is defined as follows:

A Uniform Resource Identifier that points to a single, discreet entity in an Asset Management System. If the entity identified by the reference exists as a child in a hierarchy, then the entity reference must identify a specific path to that entity, so that it has a single immediate parent.

It is deliberately not referred to as an 'id', and should not be thought of as being analogous to a primary key in a database of entities, for various reasons detailed below.

An entity reference can be any string, and there are no constraints on the content of the reference other than that of a std::string. It is up to the design of the manager to decide on the format for its entity references, and whether they are in a human readable form.

Note: We strongly recommend using a human-readable form that follows <a

href=https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#cite_ref-FOOTNOTERFC_3986,_section_32005_23-0" target="_blank">RFC_3986.

The following are examples of perfectly valid entity references:

  • myasset://DVR/ep01/build/prop/table?v=6&t=model&f=alembic
  • e1d2e41c-9594-11e2-9619-f23c91ae2917
  • {'job':'DVR', 'path':['ep01','build','prop','table'], 'version':'6', 'type':'model', 'format':'alembic'}

Each of them have their relative merits in different situations, and it is no concern of this set of APIs which one is used. There are only three requirements of the format, and the way it is interpreted by the ManagerInterface:

1. Discoverability

It is essential that any given string can be readily identified as being an entity reference or not. The isEntityReferenceString method will be called frequently by a host to determine if the arbitrary user input is a reference to a managed entity.

2. Uniform Resource Location

In an Asset Management System that permits an entity to only exists in a single place within its hierarchy, the subtle differences between a URL and a URN (both being URIs) may not be relevant. Both a 'UUID' style reference such as "e1d2e41c-9594-11e2-9619-f23c91ae2917" and an URL such as "myasset://DVR/ep01/build/prop/table?v=1&t=model&f=alembic" may both resolve to the same entity.

However, if the Asset Management System allows an entity to be 'aliased' within the system (perhaps analogous to a symbolic link in a POSIX file system), then the UUID approach may no longer comply with the 'single immediate parent' constraint of the original entity reference definition. For example, if the same underlying Entity UUID was available through the following paths:

  • myasset://DVR/ep01/build/prop/table?v=6...
  • myasset://library/furniture/table?v=2...
  • myasset://TTL/library/prop/cottageTabl?v=1...

The entity reference passed through this API must always uniquely locate the entity via a specific path, such that relationship queries produce the expected results.

In such a system, the ManagerInterface may provide access to alternate paths from any one of these path-specific references via the getWithRelationship method, with a suitable relationship Trait Set.

3. 'Potential' entity representation

It is required within the architecture of this API, to potentially derive an entity reference for new entity before it has been created.

For example, a 'Save As...' dialog will need to return an entity reference that can be passed to Manager.register().

This does not preclude the use of UUID-style references in some cases if desired, it simply means that the Manager may need to support multiple formats for an entity reference. Again, this is entirely up to the manager to decide how it wishes to handle future entities.

host

A 'host' represents some application or tool that would like to interact with an Asset Management System. This is usually a user-facing Digital Content Creation application or a pipeline tool or script.

The purpose of OpenAssetIO is to standardize the interaction between a host and an Asset Management System in order to persist or query data. A host communicates with a manager via the Manager class.

Note: The Manager class is an abstraction, that takes care of sundry housekeeping and helps manage session state. Internally it holds an instance of the ManagerInterface implementation supplied by the Asset Management System.

The host itself is made available to a manager's ManagerInterface via the HostSession supplied to each API call. This allows the manager to adapt its behavior accordingly (if required), and perform any additional actions it may wish to as part of publishing.

HostInterface

The HostInterface class is the abstract interface that any host must implement in order to initialize the API. It will usually contain logic to map native features of the host into the well-known terms defined by this API.

The HostInterface is never used directly by a manager, and is instead accessed through the Host abstraction, provided by the HostSession passed to the manager's implementation. This allows assorted house-keeping and auditing to be performed by the API middleware.

locale

Within OpenAssetIO, the term "locale" is used to define which part of a host's implementation is making a particular call to the API. A suitably configured TraitsData instance is supplied through the locale property of the Context, which is in turn supplied to most ManagerInterface method calls.

The locale may be used by a manager to customize its behavior if desired. The locale may contain references to specific objects in the host's native SDK that can be used to determine more information about the origin of the API request.

A common use of the locale by a manager is to obtain further information about the originating document during a publish.

ManagerInterface

The ManagerInterface class is the abstract interface that any Asset Management System must implement in order to be used by the API. It will usually contain appropriate logic to map native features of the asset manager into the well-known terms defined by this API.

The ManagerInterface is never used directly by a host, and is instead accessed through the Manager abstraction. This allows assorted house-keeping and state management to be performed by the API middleware.

Manager Plugin

The Plug-in mechanism implemented by the openassetio.pluginSystem automatically discovers packages that provide an instance of the openassetio.pluginSystem.PythonPluginSystemManagerPlugin using a search-path based mechanism. This is independent of $PYTHONPATH, and presently searches using the environment variable $OPENASSETIO_PLUGIN_PATH

The PythonPluginSystemManagerPlugin instance is then responsible for constructing an instance of the respective Asset Management System's implementation of the ManagerInterface.

$OPENASSETIO_DEFAULT_CONFIG

This is the environment variable used to discover a "default" configuration for an OpenAssetIO session. It defines which manager to use, along with any applicable settings. It should point to a simple TOML config file, see ManagerFactory for more details of supported options.

All OpenAssetIO hosts should support deriving their configuration from this file, to simplify centralized config management.

$OPENASSETIO_PLUGIN_PATH

This is the environment variable used to discover PythonPluginSystemManagerPlugins, it is searched left-to-right, using standard $PATH semantics (delimited by : on POSIX systems and ; on Windows). The first package that registers a specific identifier wins.

So to override a plug-in with a dev version, ensure it is to the left of the standard plug-in.

$OPENASSETIO_LOGGING_SEVERITY

This is the environment variable used to control the default logging severity of the API. Note that many hosts re-direct logging to their own system. Usually in these cases, logging severity is then controlled by the host's own configuration mechanism(s).

Manager State

The ManagerInterface is a reentrant API by design, and its implementation must be thread-safe. Consequently, the result of any call to an instance of this class should solely depend on the initialization settings, underlying asset data and the method arguments. In real-world use however, it is often required to understand that a series of discreet calls to the API may be part of the same logical user action.

The most common (and extreme) example of this is a distributed render. Where multiple processes, spread across multiple hosts are all part of the same 'task'. Many asset systems support the concept of meta-versions (eg: "vLatest"). Providing stable resolution of these is essential to deterministic renders.

A far simpler example of associating API calls is to provide caching relative to the lifetime of a specific action.

OpenAssetIO provides a mechanism to support the entire range of use cases for 'session state' without making it part of the interface instance.

This is achieved by allowing the manager to inject state into each Context created by the host. The host guarantees to manage the lifetime of their contexts appropriately, and re-use the same context for logically related API calls. The result of this is that the manager can use injected state object to form a persistent anchor across distributed calls.

The manager's state object is opaque to the host.

See also
ManagerInterface.createState
ManagerInterface.createChildState
ManagerInterface.persistenceTokenForState
ManagerInterface.stateFromPersistenceToken

Meta-version

It is common for an Asset Management System to allow an entity to be version managed. Some systems also allow the concept of what we call a 'meta-version'. For example "latest" or "latestApprovedForLighting". These are version strings that can't be assumed to be stable. Traits may exists within domain specific uses of OpenAssetIO (such as in OpenAssetIO-MediaCreation) that allow the relationship query methods to be used to retrieve a stable reference.

Stable resolution of meta-versions over time, or across a distributed task is achieved via the Manager State mechanism.

manager

A 'manager' represents some Asset Management System that forms a source of truth for some number of entities. They usually consist of some centralized database that tracks assets - known here as entities, managing their versions and relationships.

The purpose of OpenAssetIO is to standardize the interactions between a host and one of these systems in order to query or persist data.

Asset managers will generally re-map the well-known OpenAssetIO concepts (eg traits and their properties into their own internal structures, and back again when queried.

Managers are made available via a Manager Plugin, that ultimately registers classes derived from the ManagerInterface.

A host never uses the ManagerInterface class directly, but instead uses the Manager class. This indirection allows sundry house keeping and state management.

preflight

Asset management systems are roughly divided into two camps - those that can tell a host in advance the location at which data should be created, and those that simply track data at its existing location. A manager implementation declares its behavior to the host via the managementPolicy method.

If a manager has said it is capable of resolving future entities ahead of time, the host must call the preflight method and resolve the returned Entity Reference to determine the manager's chosen location for the data and use this for any write operations.

A host should always publish the full set of traits of an appropriate specification for the type of entity being published.

Some of a specification's traits may hold properties, and some of those properties may be required by preflight in order for subsequent operations in the publishing workflow to succeed. Other properties may be optional.

The host should fill in and pass as a "hint" to preflight any trait properties that are owned by the host and known at the time preflight is called.

In this context, a property is "owned" by the host if it will not be dictated by the manager during the publishing workflow (i.e. by resolving with a manager driven access flag). Note that this definition of host ownership might include properties that have been resolved from the manager at some point in the past.

If a property is not already known or understood by the host, and is optional, then it may be omitted.

Providing the preflight hint allows the manager to prepare the backend and provide the most appropriate responses to subsequent resolve and register requests; or error early if publishing is likely to fail or insufficient information is given in the hint.

The preflight method is also allowed to change the entity reference as required. This mechanism serves several purposes:

  • It allows the manager to dictate if an existing target entity is mutable. It can return an updated entity reference if the original entity should be left untouched (ie. creating a new version).
  • It allows the manager to allocate a placeholder version for a reference containing a meta-version.
  • If appropriate, it can avoid the need to retrospectively copy data to its intended destination immediately after creation.

There are two scenarios where preflight will not be called:

  • When the manager has declared that it is not capable of providing trait properties in advance of an entity being created (via managementPolicy).
  • When the data already exists at some target location, such as when assetizing an existing file.

In these situations, only register will be called by the host. In the first situation, calling preflight would be pointless as the manager has no way to provide a meaningful answer.

In the second situation it removes the responsibility for the host to transfer the data from its current location to that specified by preflight. Doing so would force the transfer mechanics into the host. Given the size of data frequently involved, and the myriad of potential transfer technologies, it was deemed leaving this up to the manager was a more flexible solution.

In summary, for a manager capable of determining the location for data, a host won't call preflight if it can't honor the specified location.

publish

We define "publishing" as the process of creating a new asset in an Asset Management System, or updating an existing one. The host initiates the publishing workflow by providing new or updated data to the manager for a specific Entity Reference. The manager then determines how that data is stored.

The manager will interpret the Trait Set of the supplied traits data in relation to the target entity to ensure the correct behaviour. This may result in a new version being created, an existing asset being updated in-place, or the action failing entirely.

Hosts should not make any assumptions about the specific behaviour of any given manager, or attempt to dictate this behaviour. Instead, endeavour provide all relevant known data to the publishing methods, allowing the manager to choose the appropriate way to manage this data. This is central to OpenAssetIO philosophy, when it comes to data management, the asset manager knows best.

Note
For example, hosts should not provide different user-facing options for "Save" and "Version up and Save" - as not all managers support these concepts simultaneously. Future extensions to the API will allow manager's to dictate these user-facing actions directly.

Once the publish is complete, the manager will provde a new Entity Reference which will then address the newly published entity and should be used by the host for all subsequent operations, disregarding the initial input reference.

Every manager behaves differently, and has different degrees of functionality. Some managers simply keep track of existing data, others allow certain traits to be determined "in advance", and others will only handle entities with particular trait sets. If a host workflow requires this, introspection APIs such as managementPolicy should be used in advance of any potentially expensive operation, avoiding a costly "try and see" approach.

There are two main publishing workflows performed by a host:

  • Ingesting existing data.
  • Generating new data in cooperation with the manager.

Ingesting Existing Data

This flow is used when the data already exists, and simply needs to be published.

  • Obtain an appropriate target entity reference.
  • Populate a TraitsData instance with the known data, ideally using a well-known Specification.
  • Call register with the appropriate access.
  • Use the resulting entity reference for any subsequent actions pertaining to the newly published data.

Generating New Data

The process for publishing yet-to-be-generated data is similar to the case for existing data, with several additions. A preflight step allows for validation before exensive generative operations are carried out, and intermediate reference resolution, giving the ability to the manager to provide inputs to the data generation process.

Note
Not all managers can determine trait properties in advance during publishing. If the host workflow requires the manager to drive these properties, the managementPolicy introspection method can be used with the kManagerDriven access to verify that the specific manager is capable of providing the neccesary properties.
  • Obtain an appropriate target entity reference.
  • Populate a TraitsData instance with all relevent known data, that the host does not expect to be driven by the manager. This allows pre-validation against the target reference to be performed by the manager.
  • Call preflight to allow any prerequisite housekeeping to be performed (such as validation, storage allocation or version locking) and recieve a working Entity Reference as the return.
  • Resolve the working reference for any traits with properties required by your workflow, not populated in the preflight TraitsData. For example, the location to write data to, or the encoding to use. These are the "manager driven" properties.
  • Perform data generation tasks, ensuring to distribute the Context to worker process if distribution is employed.
  • Populate (or update) a TraitsData instance with the final values used, even though these may have come from the manager. The manager does not hold intermediate state about what properties were resolved, therefore the register call expects entity trait properties to be fully populated.
  • Call register to finalize the publish and confirm to the manager that the data has been generated (as per the previous example as now the data is effectively "pre existing").
  • Use the resulting entity reference for any subsequent actions pertaining to the newly published data.

This may seem convoluted, but maintaining these abstractions allows a host to be written to support any given manager, even ones not known or existing at the time of development. See the introspection APIs for more details on how to determine the capabilities of a manager at runtime. In a reciprocal fashion, this prescribed series of steps also confers benefit to the manager, allowing hosts to be treated in a generic manner.

register

The registration mechanism allows for a host to create or update an entity. This is the sole mechanism by which data can be mutated within the system.

It is up to the manager to decide what the registration of new data to an existing entity should mean. The API generally has no opinion as to whether it is permitted to update in-place, or to require the creation of a new version. The manager should apply its own rules, and return an Entity Reference that points to the result of the registration - whether this be a new version, or the same entity that was subject to the registration.

For compound entities, the registration call signifies the completion of the registration of any child entities.

Create related

Despite the API having no opinion as to the specific reaction of the manager to registration, there are some occasions, specifically around the creation of new related entities, where additional instruction is required from the host. For this purpose, use kCreateRelated as the access flag.

resolve

'Resolving' an Entity Reference is the process of turning it back into the data for one or more traits. Resolution is usually performed just-in-time. This is the fundamental mechanism that makes documents portable, and where OpenAssetIO (and other resolution systems) bring their value - the manager backing the resolution process is free to use any contextual information to vary the result of the resolution such that it is as correct/appropriate as it can be for the current resolution Context.

Specification

Within OpenAssetIO, it is often required to describe the 'type' of something. This could be some data a host wishes to query or publish, or the nature of a relationship between two assets. OpenAssetIO uses a traits based system, where each distinct characteristic is combined to form a Trait Set.

Specifications define well-known sets of traits to ensure they are consistently used by a host and/or manager when populating or retrieving data.

The specification classes provide runtime and/or compile time checks to help avoid programming errors.

Trait

Traits define concrete aspects of the nature of something. They are combined in a Trait Set to form a precise description of something.

Trait sets are used to categorize entities, their relationships or the characteristics of a host process through the context's locale.

A trait may optionally define one or more properties that hold simple-typed values.

When an entity is published or resolved through the API, these trait properties are used to hold the entity's data.

See also
Entities, Traits and Specifications

Trait Set

A trait set is the logical conjunction of one or more traits. They are the basis of the classifications system used in OpenAssetIO. Sets of traits are additive when used to classify something - meaning that the thing in question has all of the traits in the set.

Trait sets are supplied to the manager through the API whenever there is need to describe the type of something in advance. A good example of their usage is in the managementPolicy query, where the manager declares its intent towards specific types of entity - described by the supplied trait sets, and which of those traits it is capable of storing or recalling property data for.

See also
Entities, Traits and Specifications
Manager.entityTraits / ManagerInterface.entityTraits