Blog
Saved0

Reusable sub-workflows and sub-agents: how to reuse them without hidden risk

A trusted bank-account-change sub-workflow was reused by a second team and paid out twice, for the wrong entity, under a service account. What a reusable component must declare about authority, state, retries, side effects and evidence.

LinkedIn
On this page
  1. The sub-workflow was reusable. Its assumptions weren't.
  2. Why does reuse create hidden coupling?
  3. What should a sub-workflow contract include?
  4. Bind each call, not just the definition
  5. Should a sub-agent inherit the caller's authority?
  6. Who owns the state?
  7. Side effects change what reuse means
  8. Evidence has to compose too
  9. Versions are transitive
  10. Sub-agents need tighter limits
  11. Common anti-patterns
  12. Ten rules for reusing sub-workflows and sub-agents
  13. The result: a component is a promise
  14. Frequently asked questions
  15. How Frozion keeps authority and evidence intact across sub-workflows
  16. Sources
The short answer

A reusable sub-workflow or sub-agent is safe to reuse only when its contract says more than its inputs and outputs. It must declare the authority it needs, who owns its state, how it behaves on timeout and cancellation, which side effects it creates, which operation ID it uses, and what evidence it returns to the parent.

The sub-workflow was reusable. Its assumptions weren't.

A manufacturer's platform team builds a sub-workflow for changing a supplier's bank account. It validates the details, checks supporting documents, evaluates policy, gets approval, updates the ERP and returns a receipt. It was built for supplier onboarding, where the calling workflow always did certain things first: named the legal entity, confirmed the employee had supplier-admin authority, bound a two-person approval to the exact new bank details, and created a stable operation ID before any external call.

The sub-workflow's visible interface has three fields: supplier ID, bank account and approval ID. Everything else arrived by local convention.

Months later, another team reuses it in a supplier self-service app. The mapping is easy, the schema validates and the child starts. But the new parent's approval confirms a supporting document, not the exact bank details. It doesn't pass the legal entity, so the child picks the supplier's primary entity. It calls the child under a broad service account because the user's authority wasn't passed along. The ERP update commits and the acknowledgement is lost. The parent retries the child. The operation ID is generated inside each child call, so the retry looks like a new change.

Every piece did what it was built to do. Yet nobody can prove the exact proposal was approved for the right entity, and nothing recognized the second call as a repeat of the first.

A sub-workflow with three visible inputs, and five hidden assumptions supplied by the original parent but missing in the second parent
Three fields were declared. Five assumptions travelled by convention, and the second caller didn't know about them.

Why does reuse create hidden coupling?

Because calling a shared component makes every caller depend on its meaning, policy assumptions, state, version and side effects, while its interface usually exposes only data fields.

Reuse is valuable. It removes duplicated logic, centralizes hard-won controls and lets specialized capabilities evolve on their own. Process standards have long supported callable reusable activities, and schema systems favor modular definitions over copy and paste.

But reuse changes the risk. Copying a workflow duplicates code. Calling a shared one creates a dependency on everything it does. A reusable function is understood through its inputs, outputs and errors. A reusable AI sub-workflow or sub-agent may also contain model calls, permission-aware retrieval, policy decisions, durable waits, human approvals, API calls, retries and compensation, and evidence that must still belong to the parent's outcome. The more of that a child hides, the more dangerous it is to expose only its data fields.

Where it physically runs doesn't matter: inline, as a durable child run, as a remote service or compiled into the parent. A visual group isn't a reusable sub-workflow. Neither is a copied fragment. The reusable unit isn't the sequence of steps. It's the contract around them.

What should a sub-workflow contract include?

Every assumption that changes whether the component is safe for a caller: identity and version, data meaning, dependencies, authority, policy and approval, state, side effects, budgets, evidence and compatibility.

DimensionWhat to make explicit
Identity and versionOwner, release status, digest, lifecycle and support policy
Data and meaningInput and output schemas, status values, units, invariants, typed failures, abstain outcomes
DependenciesData sources, model and prompt versions, policy, features, external APIs, freshness
AuthorityWho started it, who's acting, delegation, tenant, legal entity, purpose, scope, expiry
Policy and approvalPreconditions, obligations, required approvals, separation of duties, binding to the exact proposal
State and lifecycleWho owns state, correlation, waits and resume, cancellation, timeout, migration
Side effectsRead-only or changing, operation ID, idempotency, reconciliation, compensation, uncertain outcomes
BudgetsTime, cost, tokens, tool calls and depth, plus stop and escalation conditions
EvidenceInput and output digests, decisions, approvals, child record link, receipts, retention
CompatibilitySupported callers, dependency limits, deprecation and migration rules

A contract doesn't need to expose internals. It must expose every assumption that can change whether the component is safe and correct for the caller.

Bind each call, not just the definition

The contract is the static promise. Each call also needs its own binding: parent workflow and version, parent run and child call IDs, the stable operation ID, the full authority context, the proposal ID and digest, policy obligations and approval references, context references, deadlines and budgets, and correlation IDs. Where stakes require it, bind these tightly to the business payload, so a child can't combine one proposal's data with another proposal's approval.

Should a sub-agent inherit the caller's authority?

It should receive the same or narrower authority, explicitly scoped to the resource and purpose at hand, never a broad worker or service credential.

A parent can't reduce authorization to authorized=true and expect every descendant to stay safe. The child needs the underlying facts to enforce its own boundary, and if it calls something else, the same limits continue. Zero-trust guidance favors granular, least-privilege, per-request access over trust based on location or past sign-in. Token exchange standards already separate delegation from impersonation.

The runtime should be able to tell apart the person whose intent started the work, the human or machine acting now, the delegated scope, the tenant, entity, resource and purpose it applies to, and the obligations that must hold before any change. A grandchild shouldn't have to trust that the parent "already checked". (More in AI agent identity and delegated authority.)

Who owns the state?

A sub-workflow can look like a function in the designer and behave like a long-running application at runtime. It may wait for a person, receive an event, retry a provider or continue after the parent restarts. Each composition needs one declared state model.

State modelWhat it meansMinimum requirements
Inline, statelessA bounded transformation inside the parent's stepNo durable state, safe retry, no hidden side effects
Parent-ownedChild returns a proposal; parent owns all commitsTyped results; parent's operation ID; child stops after returning
Child-owned durableChild runs as its own durable caseCorrelation, completion contract, cancellation and timeout rules, version binding
CoordinatedEach owns distinct state and they exchange eventsOne owner per fact, event IDs, reconciliation, no shared mutable state
Human-boundChild pauses for approval of an exact proposalProposal digest, approver authority, expiry, change detection, re-approval

Cancellation needs precision. A parent can ask a child to stop. That doesn't prove it stopped before an external change committed. The contract should say whether cancellation is guaranteed before the change, best-effort after it, or unavailable. When completion is uncertain, the runtime should enter an explicit reconciliation state rather than treating silence as success or failure.

Side effects change what reuse means

A read-only calculation can be retried freely. A component that moves money, changes identity, modifies a contract or posts a message can't.

The operation ID should come from the business intent that owns the consequence and survive every parent-child boundary. If each child call mints a fresh ID, a parent retry becomes a second business action even when each call looks idempotent on its own. (See retries and idempotency.)

The child's result should distinguish: not started; committed, with a receipt; not committed, with a reason; unknown, with the operation ID and reconciliation required; and compensation required, with the original receipt. Retry, de-duplication, reconciliation and compensation are separate mechanisms, and the contract says which side owns each.

Comparison of an operation ID created inside each child call versus one created by the parent and carried into every child attempt
Create the operation ID where the business intent starts, and carry it through every child call and retry.

Evidence has to compose too

Encapsulation is good because callers shouldn't depend on internals. It becomes dangerous when it erases accountability. The parent's record should link to the child's run, not flatten it into one "sub-workflow completed" line. The child keeps detailed internal evidence and returns a summary: resolved versions, input and output digests, policy decisions, approvals and what they were bound to, actual external calls, receipts and reconciliation outcomes, and a permission-aware link into its own record. Trace context and provenance standards help stitch nested runs together, but you still need decision and side-effect evidence on top.

Versions are transitive

A reusable sub-workflow is a dependency that carries behavior, and it has dependencies of its own: schemas, mappings, policies, models, prompts, queries, APIs and other sub-workflows. Recording "bank-change v2" isn't enough if that label resolves differently across environments or over time.

At publication, resolve the exact child release and every consequential dependency underneath it. Running cases stay on what they started with; a new child release applies to new parent publications, and moves a live case only through deliberate migration (see versioning AI workflows). Before accepting a new child release, check more than whether the schema still parses: does it change meaning, authority, approval, state or cancellation behavior, side-effect class, model applicability, evidence or budgets?

Sub-agents need tighter limits

An agentic child may break down tasks, search, revise its plan or pick among tools. Reuse doesn't give it the right to redefine the parent's controls. Its contract should declare its allowed tools and data, its authority and purpose, maximum depth, iterations, tool calls, cost and time, its stop, abstain and escalation conditions, which outputs are only advisory, and whether it may make changes at all or only return a proposal. OWASP's guidance on excessive agency points the same way: limit functionality, permissions and autonomy in the component boundary, not only in the prompt.

Common anti-patterns

Anti-patternWhy it failsWhat to do instead
Interface lists only data fieldsEntity, authority, approval and ID arrive by conventionPut every safety assumption in the contract
Child runs under a broad service accountPermission silently widensPass narrowed, purpose-bound authority each call
Child mints its own operation IDA parent retry becomes a second changeCreate the ID at the business intent and carry it through
Parent retries whenever the child times outThe child may already have committedReconcile with the same ID before any retry
Shared release updates every caller at onceRunning cases change meaning mid-flightPin child versions at publication; migrate deliberately
Child evidence flattened to "completed"No way to see what the child decided or changedLink the child's record into the parent's
Universal component with a huge context surfaceEvery caller depends on volatile assumptionsReuse only where the contract is stable and shared

Ten rules for reusing sub-workflows and sub-agents

  1. Reuse governed capabilities, not anonymous step sequences.
  2. Put every consequential assumption in the contract.
  3. Bind each call to its proposal, authority, purpose and correlation IDs.
  4. Let authority stay the same or narrow at every hop, never widen.
  5. Give every piece of durable state exactly one owner.
  6. Carry one operation ID across every side-effecting child call.
  7. Make timeout, cancellation, uncertain outcomes and compensation explicit.
  8. Pin transitive dependencies at publication.
  9. Link parent and child evidence into one inspectable record.
  10. Optimize how it runs only after the contract and evidence boundary are preserved.

The result: a component is a promise

Reusable sub-workflows and sub-agents are among the highest-leverage pieces of an enterprise AI platform. They let teams centralize integrations, retrieval, approvals, verification and long-running processes instead of rebuilding them in every app.

But a sequence of reusable steps isn't yet a reusable capability. The caller has to know what it means, what authority it needs, who owns its state, what it can change, which versions it binds and what evidence it returns. Make those answers part of the contract, and parent and child stay modular while their relationship becomes typed, versioned, enforceable and inspectable.


Frequently asked questions

What makes a sub-workflow safe to reuse?

A sub-workflow is safe to reuse when every assumption that affects safety is in its contract: required authority, legal entity and purpose, approval binding, state ownership, timeout and cancellation behavior, side-effect class, operation ID, dependencies and the evidence it returns. Inputs and outputs alone aren't enough.

Should a sub-agent inherit the parent agent's permissions?

A sub-agent gets the same or narrower authority, never broader. Pass who started the work, who is acting, for which tenant, entity and purpose, and let the child enforce its own boundary. A broad service account in between silently widens permission.

Who should retry when a sub-workflow times out?

One owner, declared in the contract. A timeout doesn't prove the child did nothing, so the parent should reconcile using the same operation ID it created at the start, rather than calling the child again and minting a new ID.

How does this work for agents we already run?

Route the agent's tool calls through a governed runtime over MCP or HTTPS. Each reusable workflow is exposed as an endpoint or MCP tool, carries the caller's narrowed authority, and returns its outcome and evidence to the parent's record.

With Frozion

How Frozion keeps authority and evidence intact across sub-workflows

In Frozion, every workflow is exposed as an endpoint, and any tool or workflow is exposed as an MCP tool, so a reusable step has one governed interface. Agent Delegation carries the person's role into each call, and authority narrows at each hop and is rechecked right before the change. Durable Execution reconciles uncertain writes before any retry. The dependency view shows every workflow that uses a component, and Provenance & Evidence keeps one tamper-evident record per decision.


Sources

  1. OMG BPMN 2.0.2Reusable callable activities in process models.
  2. JSON SchemaModular, reusable schema definitions.
  3. NIST SP 800-207, Zero Trust ArchitectureLeast-privilege, per-request access instead of implicit trust.
  4. RFC 8693, OAuth 2.0 Token ExchangeDistinguishes delegation from impersonation.
  5. W3C Trace ContextCorrelation across nested calls and services.
  6. W3C PROV-ORelating activities, entities and responsible agents across nested runs.
  7. NIST SP 800-218, Secure Software Development FrameworkIntegrity and provenance for reused components.
  8. OWASP LLM06:2025 Excessive AgencyLimit functionality, permissions and autonomy of agentic components.
More in Work that finishes

Work that finishes

Retries & side effects 2
Durable & event-driven 1
Contracts & routing 3
APIs & integration 1

Other topics

Pick up where you left off: