Skip to content

bifrost Module Reference

Complete API reference for decorators, context, and SDK modules

# Decorators and context
from bifrost import workflow, param, data_provider, ExecutionContext
# SDK modules (all async except files)
from bifrost import config, secrets, oauth, files
# Types (optional)
from bifrost import Organization

Registers an async function as an executable workflow.

@workflow(name: str, description: str, **options)
@workflow(
name="create_user",
description="Create new user"
)
async def create_user(context: ExecutionContext, email: str):
return {"user_id": "123"}

Parameters:

ParameterTypeDefaultDescription
namestrRequiredUnique identifier (snake_case)
descriptionstrRequiredUser-facing description
categorystr”General”Workflow category
tagslist[str][]Tags for filtering
execution_modestr”sync”"sync" or "async"
timeout_secondsint300Max execution time
schedulestrNoneCron expression
endpoint_enabledboolFalseExpose as HTTP endpoint
allowed_methodslist[str][“POST”]Allowed HTTP methods
public_endpointboolFalseSkip authentication

Defines a workflow parameter.

@param(name: str, type: str, **options)

Parameters:

ParameterTypeDefaultDescription
namestrRequiredParameter name (must match function arg)
typestrRequiredParameter type (see types below)
labelstrTitlecased nameDisplay label
requiredboolFalseIs required
default_valueAnyNoneDefault value
help_textstrNoneHelp tooltip
validationdictNoneValidation rules
data_providerstrNoneData provider name

Available Types:

  • string - Text input
  • email - Email with validation
  • textarea - Multi-line text

Validation Rules:

RuleApplies ToDescription
min_lengthstringMinimum length
max_lengthstringMaximum length
patternstringRegex pattern
minnumberMinimum value
maxnumberMaximum value
enumstringAllowed values

Example:

@param(
"email",
type="email",
required=True,
help_text="User's email address",
validation={"pattern": r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"}
)

Registers a function that provides dynamic options.

@data_provider(name: str, description: str, **options)

Parameters:

ParameterTypeDefaultDescription
namestrRequiredUnique identifier
descriptionstrRequiredWhat it provides
categorystr”General”Category
cache_ttl_secondsint300Cache duration (0 = no cache)

Return Format:

[
{
"label": "Display Text",
"value": "actual_value",
"metadata": {} # Optional
}
]

Example:

@data_provider(
name="get_departments",
description="List departments",
cache_ttl_seconds=600
)
async def get_departments(context: ExecutionContext):
return [
{"label": "Engineering", "value": "eng"},
{"label": "Sales", "value": "sales"}
]

Access to organization, user, and execution metadata.

Properties:

PropertyTypeDescription
user_idstrCurrent user ID
emailstrUser email
namestrUser display name
org_idstr | NoneOrganization ID
org_namestr | NoneOrganization name
organizationOrganization | NoneFull org object
scopestr”GLOBAL” or org ID
execution_idstrUnique execution ID
is_platform_adminboolIs platform admin
is_function_keyboolCalled via API key
is_global_scopeboolExecuting in global scope

Example:

async def my_workflow(context: ExecutionContext):
org_id = context.org_id
user_email = context.email
is_admin = context.is_platform_admin

See ExecutionContext API for complete reference.

Configuration management with org scoping.

Functions:

FunctionParametersReturnsDescription
get(key, default=None)key: str, default: AnyAnyGet config value
set(key, value)key: str, value: AnyNoneSet config value
list()-dict[str, Any]List all configs
delete(key)key: strboolDelete config (returns success)
from bifrost import config
# Get with default
api_url = await config.get("api_url", default="https://api.example.com")
# Check if exists first
if await config.get("api_key"):
api_key = await config.get("api_key")

Azure Key Vault secret management.

Functions:

FunctionParametersReturnsDescription
get(key)key: strstr | NoneGet secret value
set(key, value)key: str, value: strNoneStore secret
list()-list[str]List secret keys (not values)
delete(key)key: strboolDelete secret (returns success)

Scoping: Secrets automatically scoped as {org_id}--{key} in Key Vault.

from bifrost import secrets
# Get secret from Key Vault
api_key = await secrets.get("api_key")
if api_key:
# Use in API call
headers = {"Authorization": f"Bearer {api_key}"}

OAuth token management.

Functions:

FunctionParametersReturnsDescription
get_token(provider)provider: strdict | NoneGet OAuth token data
set_token(provider, token_data)provider: str, token_data: dictNoneStore token
list_providers()-list[str]List provider names
delete_token(provider)provider: strboolDelete token (returns success)
refresh_token(provider)provider: strdictRefresh and return new token

Token Data Structure:

The get_token() method returns a dictionary with:

{
"access_token": str, # Current access token
"refresh_token": str, # Refresh token (if available)
"expires_at": int, # Unix timestamp
"token_type": str, # Usually "Bearer"
"scope": str # Granted scopes
}
from bifrost import oauth
import aiohttp
# Get OAuth token
token_data = await oauth.get_token("microsoft")
if not token_data:
raise ValueError("Microsoft OAuth not configured")
# Use in API call
url = "https://graph.microsoft.com/v1.0/me"
headers = {"Authorization": f"Bearer {token_data['access_token']}"}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as resp:
return await resp.json()

File operations (synchronous).

Functions:

FunctionParametersReturnsDescription
read(path)path: strstrRead file as text
read_bytes(path)path: strbytesRead file as bytes
write(path, content)path: str, content: strNoneWrite text file
write_bytes(path, content)path: str, content: bytesNoneWrite binary file
list(directory)directory: strlist[str]List directory contents
delete(path)path: strNoneDelete file
exists(path)path: strboolCheck if file exists

Location Parameter:

All functions accept optional location parameter:

  • "workspace" (default) - Persistent workspace files
  • "temp" - Temporary files cleared after execution
from bifrost import files
# Read text file (no await!)
content = files.read("data/config.json")
# Read binary file
image_bytes = files.read_bytes("images/logo.png")
from bifrost import (
workflow, param, data_provider, ExecutionContext,
config, secrets, oauth, files
)
import aiohttp
import logging
logger = logging.getLogger(__name__)
# Data provider
@data_provider(
name="get_departments",
description="List departments",
cache_ttl_seconds=600
)
async def get_departments(context: ExecutionContext):
return [
{"label": "Engineering", "value": "eng"},
{"label": "Sales", "value": "sales"}
]
# Workflow
@workflow(
name="create_user",
description="Create user in system",
category="User Management",
timeout_seconds=60
)
@param("email", type="email", required=True)
@param("name", type="string", required=True)
@param("department", type="string", data_provider="get_departments")
async def create_user(
context: ExecutionContext,
email: str,
name: str,
department: str
):
"""Create a new user with department assignment."""
logger.info("Creating user", extra={
"email": email,
"department": department
})
try:
# Get config and secrets (both async!)
api_url = await config.get("api_url")
api_key = await secrets.get("api_key")
# Call external API
headers = {"Authorization": f"Bearer {api_key}"}
payload = {"email": email, "name": name, "department": department}
async with aiohttp.ClientSession() as session:
async with session.post(
f"{api_url}/users",
headers=headers,
json=payload
) as resp:
if resp.status == 201:
user = await resp.json()
# Write to file (synchronous!)
files.write(
f"users/{user['id']}.json",
json.dumps(user, indent=2)
)
logger.info(f"User created: {user['id']}")
return {"success": True, "user_id": user["id"]}
else:
error = await resp.text()
logger.error(f"API error: {error}")
return {"success": False, "error": error}
except Exception as e:
logger.error(f"Failed: {str(e)}", exc_info=True)
return {"success": False, "error": str(e)}
@dataclass
class Organization:
id: str
name: str
is_active: bool

ExecutionStatus:

  • PENDING - Queued for execution
  • RUNNING - Currently executing
  • SUCCESS - Completed successfully
  • FAILED - Failed with error
  1. Type Hints: Always use ExecutionContext type hint
  2. Async/Await: Remember config, secrets, and oauth are async
  3. Files Are Sync: No await for files module
  4. Logging: Use logging.getLogger(__name__)
  5. Error Handling: Return error states, log with context
  6. Secrets: Never log or return secret values
  7. Caching: Set appropriate cache TTL for data providers