App
The shippable unit of Triform — an app assembles elements you already built into one deployable thing, carries it across dev, demo, and live tiers, and gives it a URL the world can reach.
Working with it
Opening a App drills into its contents on the canvas rather than opening a dedicated workbench.
How it appears
The same element type rendered as a definition, a circle instance, and a live workspace card.
When to use / not
When to use
- Bundling a handful of elements — a function, a database, a frontend — into a single thing you can deploy and put behind a URL.
- Shipping the same assembly through dev → demo → live, where each promotion freezes member versions into an immutable, pinned snapshot.
- Serving a frontend (spa, ssr, view, three-d) at /{circle}/{app}/live, optionally on your own custom domain with managed DNS and SSL.
- Giving end-users or anonymous visitors access to a running app without exposing the underlying library elements.
When not to use
- Orchestrating a sequence of steps with branches, loops, and waits — that is what an automation is for; an app deploys it, it doesn't run the flow.
- Just grouping related elements for tidiness inside a circle — elements sit flat, so no manifest wrapper is needed until you actually want to deploy.
- Holding the tenant, schema, or git repo itself — that is the circle the app lives inside.
Topology
A structural container: it holds and organises other elements inside it on the canvas.
Properties
versionstring- Current semantic version (SemVer)
iconstring- Icon identifier or URL
membersarray- Elements referenced from repositories. Items can be slug strings or full member objects.
entrypointsobject- Discriminated entry points into the app, keyed by kind. Each entry binds the app to a member element. Supported kinds: - frontend (spa, ssr, view, three-d) — served at /{circle}/{app}/live - automation (apps/automation) — main automation invoked on deploy/trigger - schedule (io/schedule) — cron-driven trigger - webhook (io/http) — external webhook ingress Set/unset via the polymorphic set_entrypoint / unset_entrypoint ops, or the legacy set_index / unset_index aliases (which target kind:frontend).
Capabilities
Defined for this element
- Observe
Operations
- activityGET
- attachPOST
- attachmentsGET
- batch_statsGET
- buildPOST
- composePOST
- contextGET
- createPOST
- deleteDELETE
- demotePOST
- deployPOST
- detachPOST
- disablePOST
- dnsGET
- dns_setPUT
- domainsGET
- domains_addPOST
- domains_removeDELETE
- domains_verifyPOST
- enablePOST
- envGET
- env_deleteDELETE
- env_setPUT
- export_bundleGET
- getGET
- import_bundlePOST
- intentionGET
- promotePOST
- readmeGET
- readme_updatePOST
- referencePOST
- releasesGET
- remove-modifierPOST
- restorePOST
- rollbackPOST
- schemaGET
- set_entrypointPOST
- set_indexPOST
- sourceGET
- source_branchesGET
- source_promotePOST
- source_repairPOST
- source_statusGET
- source_validatePOST
- statsGET
- treeGET
- unreferencePOST
- unset_entrypointPOST
- unset_indexPOST
- updatePATCH
- update_metaPATCH
- versionGET
Composition
Validation rules
- Project has no members — nothing will be deployed
- Auto-scaling is disabled — project won't scale under load
App (app)
Category: apps | Form: | Symbol: Co
Deployable manifest of elements with environment-specific configuration
A deployable assembly that references elements from your repositories without owning them. Add elements with the “reference” operation (e.g., ref: “actions/python/my-fn”). Apps support environments: dev, demo, and live. Promote from dev→demo→live to create immutable snapshots with pinned versions. Deleting an app only removes references — the library elements remain. Max 500 members. Note: spec.connections holds canvas diagram edges for visualization only and is not enforced at runtime — elements must be wired via their own API contracts. Common mistake: editing spec.members directly instead of using the reference/unreference operations — direct edits bypass validation and version pinning.
Guide
Deployable manifest that assembles library elements into a runnable unit
What It Does
An app references elements from your repositories without owning them. Add elements with the reference operation, declare data flow connections between them (source:port → target:port), and manage environment-specific configuration across dev, demo, and live tiers. Promote from dev → demo → live to create immutable snapshots with pinned versions. Deleting an app only removes references — the library elements remain.
Element Definition
| Property | Value |
|---|---|
| Type | app |
| Category | apps |
| Form | manifest |
| Symbol | layers / #8B5CF6 |
| Residence | structural |
Quick Start
# Create an app
POST /api/my-circle/ {"element_type": "app", "slug": "my-app", "name": "My App"}
# Reference elements into the app
POST /api/my-circle/my-app/ops/reference {"ref": "actions/python/my-fn"}
POST /api/my-circle/my-app/ops/reference {"ref": "data/sql/my-db"}
# Deploy
POST /api/my-circle/my-app/ops/deploy
Environments
Apps manage three tiers:
- dev — auto-updates when referenced elements change
- demo — promoted from dev, version-pinned snapshot
- live — promoted from demo, immutable production snapshot
POST /api/my-circle/my-app/ops/promote {"from": "dev", "to": "demo"}
Common Mistakes
- Editing
spec.membersdirectly instead of usingreference/unreferenceoperations — direct edits bypass validation and version pinning - Max 500 members per app
Workflows
build-ai-app
Build an AI-powered app with an agent, function, and database
- Create a function - Library element — write handler code, then reference from this app
triform_element(action: "create", element_type: "python", name: "handler", intention: "process requests") - Create a database - The function can read/write via attached data source
triform_element(action: "create", element_type: "sql", name: "app-db", intention: "store application data") - Create an agent - Attach platform tools and set a brain
triform_element(action: "create", element_type: "triformer", name: "assistant", intention: "AI assistant for this app") - Wire them together - Reference library elements into the app
triform_ops(action: "call", slug: "{slug}", operation: "reference", input: { ref: "actions/python/handler" }) - Deploy
triform_ops(action: "call", slug: "{slug}", operation: "deploy")
build-api
Build an API with HTTP endpoint, function, and database
- Create an HTTP connector
triform_element(action: "create", element_type: "http", name: "api-endpoint", intention: "receive HTTP requests") - Create a handler function
triform_element(action: "create", element_type: "python", name: "api-handler", intention: "process API requests") - Create a database
triform_element(action: "create", element_type: "sql", name: "api-db", intention: "store API data") - Wire HTTP → Function → DB - Reference all elements into the app
triform_ops(action: "call", slug: "{slug}", operation: "reference", input: { ref: "io/http/api-endpoint" })
Error Recovery
| Error | Recovery guidance | Next actions |
|---|---|---|
connection | Connection diagram edge failed validation. Check that the format is ‘source-slug:port → target-slug:port’. Note: connections are visualization-only and do not wire runtime data paths. | |
deployment | Deployment failed. Check that all referenced elements are in a valid state. | Check member states: triform_ops(action: "call", slug: "{slug}", operation: "get") |
reference | Element reference failed. The element may not exist or may not be a containable type. | List available elements: triform_element(action: "list") |
validation | App validation failed. Check that all members are valid. |
Relationships
- Attaches to: api-token, variable, prompt, rate-limit, auth-policy, validation, alert, evaluator, brand, view, spa, ssr, three-d
Capabilities
- assembly: References library elements without owning them (manifest form)
- environment-tiers: Supports dev/demo/live environment tiers with promotion
- app-transparent-create: Auto-routes element creation to typed repositories
- activity-scope-members: Activity queries scope to app members
- container: Contains referenced agents, functions, data, frontend, and integrations
- deploy: Deploy to environments (dev/demo/live)
- rollback: Rollback to previous versions
- domains: Custom domains with SSL
- environments: Automatic dev/demo/live environment routing
- promote: Promote configuration between environments
Properties
| Property | Type | Default | Description |
|---|---|---|---|
version | string | "0.1.0" | Current semantic version (SemVer) |
icon | string | — | Icon identifier or URL |
members | array | — | Elements referenced from repositories. Items can be slug strings or full member objects. |
connections | array | — | Canvas diagram edges between referenced elements. Visualization-only — not enforced at runtime. Declaring a connection here does not wire any data path between elements; members must be connected manually via their own API or invocation contracts. |
attachments | object | — | Per-element modifier and resource attachments |
environments | object | — | Per-environment configuration overrides |
entrypoints | object | — | Discriminated entry points into the app, keyed by kind. Each entry binds the app to a member element. Supported kinds: - frontend (spa, ssr, view, three-d) — served at /{circle}/{app}/live - automation (apps/automation) — main automation invoked on deploy/trigger - schedule (io/schedule) — cron-driven trigger - webhook (io/http) — external webhook ingress Set/unset via the polymorphic set_entrypoint / unset_entrypoint ops, or the legacy set_index / unset_index aliases (which target kind:frontend). |
deployment | object | — | |
scaling | object | — | |
resources | object | — | |
routing | object | — | |
input_schema | object | — | JSON Schema describing expected input data shape. Used for port compatibility and runtime validation. |
output_schema | object | — | JSON Schema describing output data shape. Used for port compatibility and runtime validation. |
Operations
activity
Get /ops/activity | Auth: Read
Get activity events for this element
Scope depends on element capabilities: individual elements query by element_id, project-form elements with activity-scope-members include member activities, circle-level elements with activity-scope-all query the entire circle. Gracefully returns empty list if activities table is missing (old circles).
attach
Post /ops/attach | Auth: Write
Add an element as a member of this app
Adds an element to this app’s members list. Accepts element slug or element_id (UUID). Validates topology (compound bond rules), detects circular references, and persists the updated members list to git. Optionally pin to a version (@v1, @latest) or set an alias for use in connections. Prefer this operation over direct spec.members edits — PATCH on spec.members is not persisted and will not appear in the tree.
attachments
Get /ops/attachments | Auth: Read
List all modifiers and resources attached to this element
Returns both modifiers (policy enforcement) and resources (data injection) with is_modifier flag to distinguish. Items in the generated MODIFIER_TYPES list are modifiers; everything else is a resource. Includes cascade_policy and version pin info.
batch_stats
Get /ops/batch_stats | Auth: Read
Get per-element statistics for all children of this element
Returns per-child stats plus an aggregate. Most meaningful on compound or manifest form elements (repositories, circles, projects); atoms have no children so the result is an empty children array with a zeroed aggregate. Uses efficient GROUP BY SQL. Weighted averages for eval scores.
build
Post /ops/build | Auth: Admin
Build a new release
Async operation — creates a new versioned release. Version tag is auto-generated if not provided. For frontend members (spa, ssr, view, three-d), triggers the build pipeline. Include a message for release notes. Returns build_id for status polling.
compose
Post /ops/compose | Auth: Execute
Batch add and remove modifiers on this element in a single call
Declarative composition: add modifiers by ref path (slug or path@version) and remove by attachment ID, all in one atomic call on the target element. Each ‘add’ entry resolves the source element, validates topology, attaches with optional priority and cascade policy. Each ‘remove’ entry deletes the attachment row. Returns a summary of what was added and removed. Example: compose({ add: [{ref: “my-prompt”}, {ref: “rate-limit/api@v2”, priority: 50}], remove: [{attachment_id: “uuid”}] })
context
Get /ops/context | Auth: Read
Get connected elements (graph traversal)
Graph traversal showing all connected elements with their relationship type (contains, contained_by, references, referenced_by, attaches, etc.). Use ?depth=N to control traversal depth (default 1) and ?types=actor,data to filter by element types.
create
Post /ops/create | Auth: Write
Create child element
POST to the parent path — element_type goes in the request body, NOT the URL. Both element_type and slug are required and must be non-empty. Name is derived from slug if omitted. Writes to both Git and PostgreSQL. All elements are stored flat under the circle — no intermediate library wrapper rows.
delete
Delete /ops/delete | Auth: Admin
Delete element (soft delete)
Soft delete — sets state to ‘deleted’ but retains the record. Cannot delete elements that have children (has_no_bond precondition) or active runs. Requires admin auth and confirmation.
demote
Post /ops/demote | Auth: Admin
Suspend an environment so its URL stops serving
Sets the target environment’s
statustoinactive. The /live URL for a suspended environment returns 404 (handle_live honors status). Data is preserved — re-promote (or set status back toactive) restores service. Use when you need to take an env offline without losing the pinned snapshot. dev→demo→live precedence still applies; demotinglivedoes not affectdemo. Authorization: admin (mirrors promote).
deploy
Post /ops/deploy | Auth: Admin
Deploy project to an environment
Async operation — returns deployment_id immediately, poll status via run_get. Defaults to dev environment if not specified. Optionally deploy a specific version tag (from releases). Resolves all member elements, applies health checks and scaling policies. Requires admin auth.
detach
Post /ops/detach | Auth: Write
Remove a member element from this app
Removes an element from this app’s members list. Accepts element slug or element_id (UUID). Does not delete the element — only removes it from the app’s membership. Updates the members list in git. Any connections referencing this member should be cleaned up separately.
disable
Post /ops/disable | Auth: Admin
Disable element (hides and prevents use)
Idempotent — safe to call on already-disabled elements. Optionally pass a reason string. Disabled elements cannot be invoked or executed. Inverse of enable.
dns
Get /ops/dns | Auth: Read
List DNS records for managed domains
dns_set
Put /ops/dns/{domain} | Auth: Admin
Set DNS records for a domain
domains
Get /ops/domains | Auth: Read
List custom domains
domains_add
Post /ops/domains | Auth: Admin
Add a custom domain
Associates a custom domain with this project. Returns DNS verification instructions (CNAME or TXT record). Domain must be verified via domains_verify before SSL is provisioned. Set primary:true for the main domain. Each domain is scoped to an environment (default: live).
domains_remove
Delete /ops/domains/{domain} | Auth: Admin
Remove a custom domain
domains_verify
Post /ops/domains/{domain}/verify | Auth: Admin
Verify domain ownership
enable
Post /ops/enable | Auth: Admin
Enable element (makes usable and visible)
Idempotent — safe to call on already-enabled elements. Transitions element to ready/enabled state. Cannot enable deleted elements. Inverse of disable.
env
Get /ops/env | Auth: Admin
List environment variables
env_delete
Delete /ops/env/{key} | Auth: Admin
Delete an environment variable
env_set
Put /ops/env | Auth: Admin
Set environment variables
Sets environment variables as key-value pairs. Scope to a specific environment (dev/demo/live) or use “all” (default) to apply everywhere. Variables are available to all project members at runtime. Secret values are masked in env list responses.
export_bundle
Get /ops/export/bundle | Auth: Read
Export element as downloadable git bundle
On non-root-namespace elements, returns a binary git bundle. On root-namespace (circle) elements, dispatch hands off to the circle’s own export_bundle op, which returns a multi-element JSON envelope with one base64 bundle per child element — this is intentional, not an error.
get
Get /ops/get | Auth: Read
Get element details
Element is already resolved by the routing layer — this returns the cached element, not a fresh DB query. Use the path /api/{circle}/{slug} to address elements.
import_bundle
Post /ops/import/bundle | Auth: Write
Import git bundle into element
Accepts a base64-encoded git bundle in the JSON bundle_base64 field. Use overwrite=true to replace existing elements with same slug (default skips duplicates). Imported elements get new UUIDs. Returns counts of imported/skipped elements and any errors.
intention
Get /ops/intention | Auth: Read
Get element intention with full inheritance chain
Returns three levels: direct (this element’s intention), inherited (from category and root), and resolved (final merged intention). Useful for understanding an element’s purpose in context of its hierarchy.
promote
Post /ops/promote | Auth: Write
Promote project from one environment to another
One-way environment progression: dev→demo or demo→live. Creates an immutable snapshot of all member element versions at promotion time, freezing member commits and auto-pinning @latest modifier refs to prevent config drift. Creates a git version tag (promote-{target}-{timestamp}) for rollback. Authorization: dev→demo requires member+ role, demo→live requires admin. Source environment defaults to the tier before target. Returns snapshot array with all promoted elements.
readme
Get /ops/readme | Auth: Read
Get element README.md content
Reads README.md from the element’s git repository. Returns empty content (not an error) if no README exists. Always returns markdown format.
readme_update
Post /ops/readme_update | Auth: Write
Update element README.md content
Creates or overwrites README.md in the element’s git repo. Commits to the draft branch. Content must be provided as a markdown string.
reference
Post /ops/reference | Auth: Write
Add an element reference to this project
Adds an element from a repository to this project’s members list. Use ref as a path (e.g., “actions/python/my-fn”) or provide target_id as UUID. Validates topology (can_reference check), detects circular references, and supports cross-circle refs via published_elements. Optionally pin to a version (“@v4”) or set an alias. Persists the updated members list to git. Prefer this operation over direct spec.members edits.
releases
Get /ops/releases | Auth: Read
List all releases/versions
remove-modifier
Post /ops/remove-modifier | Auth: Execute
Remove an attached modifier from this element by attachment ID
Removes a modifier/resource attachment by its row ID. The ID comes from the attachments or context API. This is the reverse of attach — called on the target element, not the source.
restore
Post /ops/restore | Auth: Admin
Restore element to a specific version
Automatically snapshots the current state before restoring (creates a ‘Before restore to vN’ version entry). Writes restored spec to git as .triform/spec.yaml. Git failures warn but don’t fail the operation — DB state is authoritative. Cannot restore deleted elements.
rollback
Post /ops/rollback | Auth: Admin
Rollback to a previous version
Restores a specific environment to the state captured in a previous git version tag (from promote or build operations). Both environment and version are required. Reads the project spec from the tagged commit and restores member versions to their pinned commits. Creates a new rollback-{env}-{timestamp} tag for audit trail.
schema
Get /ops/schema | Auth: Read
Get element input/output schema (MCP tools/list compatible)
Returns type-level port schemas from the TypeRegistry — not instance-specific overrides. Includes direction (input/output), required flag, and JSON schema per port. Useful for understanding what data an element accepts and produces.
set_entrypoint
Post /ops/set-entrypoint | Auth: Write
Set an entrypoint of any supported kind for this app
Binds the app to a member element by kind. Kinds:
- frontend → must be a frontend element (spa, ssr, view, three-d); served at /{circle}/{app}/live (same surface as set_index).
- automation → must be an apps/automation element; the app’s “main” automation invoked on deploy/trigger (runtime wiring is a follow-up).
- schedule → must be an io/schedule element; cron firing handled by the existing schedule element.
- webhook → must be an io/http element; external ingress surface.
The runtime validates the bound element’s category matches the kind and writes to spec.entrypoints.{kind}. To clear, use unset_entrypoint with the same kind. set_index / unset_index are back-compat aliases that target kind:frontend.
set_index
Post /ops/set-index | Auth: Write
Set the index frontend for this app
Designates a frontend member as the app’s default — the frontend served when navigating to /{circle}/{app}/live directly. Sets entrypoints.frontend.element to the given member slug. The element must be a frontend type (spa, ssr, view, three-d) and a current member of the app. Use unset_index to clear.
source
Get /ops/source | Auth: Read
Get any file’s content from the element’s git repository
Reads an arbitrary file from the element’s CAS-backed git tree by its relative path. Same store as
readme, just generalized. Path safety: rejects..traversal, leading/, and null bytes. Use this to viewmain.pyfor action elements, asset files for SPAs, etc. Returns empty content (not an error) if the file doesn’t exist.
source_branches
Get /ops/source/branches | Auth: Read
List Source branches for this element
Returns the standard draft/demo/live Source branches, their current commits, and promotion relationships. Use GET /api/{element_path}/ops/source/branches.
source_promote
Post /ops/source/promote | Auth: Write
Promote Source branch forward
Promotes draft to demo or demo to live through the generated element op path. Direct Git pushes to demo/live are blocked by Source policy.
source_repair
Post /ops/source/repair | Auth: Write
Inspect or repair the element Source index
Runs Source repair through the element operation path. Defaults to dry_run=true; set dry_run=false only after reviewing a dry-run report.
source_status
Get /ops/source/status | Auth: Read
Get Source control status for this element
Returns the branch-aware clone URL, checkout commands, current draft commit, child source-link count, portable export summary, Source health, warnings, and auth hints for the addressed element. Use the element-first path: GET /api/{element_path}/ops/source/status.
source_validate
Post /ops/source/validate | Auth: Read
Validate Source branch contents
Validates a Source branch before accepting local Git workflow changes or promotion. Defaults to branch=draft and rejects runtime data, generated output, secret material, and unreadable CAS refs.
stats
Get /ops/stats | Auth: Read
Get aggregate statistics for this element
Health status is computed: error if errors_per_day > 5 or success_rate < 0.8, warning if errors_per_day > 0 or success_rate < 0.95. Firing alerts escalate health to error/warning. Default period is ‘day’. Returns runs_per_day, success_rate, avg_duration_ms, and more.
tree
Get /ops/tree | Auth: Read
Get the element’s position in the graph — ancestors, children, references, and subtree statistics
Uses per-circle ElementGraph cache for O(1) lookups. Returns ancestors (containment chain), children (direct), members (references), referenced_by (reverse refs), attachments, and subtree stats. Default depth is 3, max is 10. Pass ?include_metadata=true for name/state on each node.
unreference
Post /ops/unreference | Auth: Write
Remove an element reference from this project
Removes an element reference from this project’s members. Accepts ref (path) or target_id (UUID). Does not delete the library element — only removes the project’s reference to it. Updates the members list in git. Any connections or attachments referencing this element should be cleaned up separately.
unset_entrypoint
Post /ops/unset-entrypoint | Auth: Write
Remove an entrypoint of any supported kind from this app
Clears spec.entrypoints.{kind} so the app no longer has an entrypoint of that kind. Symmetric inverse of set_entrypoint. unset_index is the back-compat alias for kind:frontend.
unset_index
Post /ops/unset-index | Auth: Write
Remove the index frontend from this app
Clears the entrypoints.frontend entry so the app no longer has a default frontend. Navigating to /{circle}/{app}/live will return 404 until a new frontend is set. Back-compat alias for
unset_entrypoint kind:frontend— kept so existing callers don’t break when the polymorphic op is preferred.
update
Patch /ops/update | Auth: Write
Update element
Partial update — send only the fields you want to change.
spec,name, andintentionare all independently optional.specMUST be a JSON object when present; deep-merged into the existing spec by default. Empty{"spec":{}}preserves existing spec content but still records a new version (no-op for content, not for version state). To clear/replace the entire spec wholesale send{"spec":{...},"deep":false}. List-typed spec fields use replace semantics (the patch list replaces the existing list, no array merging). Coordinates Git + DB writes. Slug cannot be changed after creation.
update_meta
Patch /ops/update_meta | Auth: Write
Update element metadata (lightweight merge — does NOT bump version or snapshot spec)
Shallow JSONB merge into element.meta. Top-level keys in the provided value replace existing meta values; other keys are preserved. Used for UI metadata like canvas positions, panel state, viewer preferences. Wire-shape op_name is
update_meta(distinct fromupdate) so SSE subscribers + the cache auto-invalidator can distinguish lightweight metadata changes from spec edits without inspecting the payload. The MutatingElementStore wrapper stamps this op_name on the lifecycle event emitted byupdate_element_metastorage calls.
version
Get /ops/version | Auth: Read
Get current version or full history
Returns current version by default. Pass ?history=true for full version history (up to ?limit=N, default 50). Versions are backed by the element_versions table. Every spec update creates a new version entry.
Error Codes
| Code | Class | Retryable | Description |
|---|---|---|---|
APP_DEPLOY_FAILED | internal | yes | App deployment failed |
APP_PROMOTE_FAILED | internal | yes | Environment promotion failed |
APP_REFERENCE_NOT_FOUND | not_found | no | Referenced element not found in library |
APP_CIRCULAR_REFERENCE | validation | no | Circular reference detected in app graph |
APP_PORT_MISMATCH | validation | no | Connection port types are incompatible |
Observability
Defined for this element
Metrics
- member_count
- element_count
- storage_bytes
- deploy_count
- promote_count
- promote_duration_seconds
- cascade_resolution_duration_seconds
- environment_access_total
Events
- project.created
- project.updated
- project.deleted
- project.deployed
- project.promoted
- project.rolled_back
- project.referenced
- project.unreferenced
Pricing / cost
Platform default
Operation costs
- create: free
- update: free
- delete: free
- get: free
- list: free
- invoke: 10000 micro-AU
- tool_use: free