Trovata built autonomous treasury agents on Amazon Bedrock AgentCore to move corporate cash management from manual spreadsheets to real-time decision-making. The architecture handles bank-branded AI deployment, multi-tenant isolation, and role-based access control across agents that execute financial workflows with immediate consequences.
This is not a proof of concept. Trovata runs production treasury operations for enterprise clients where agent mistakes trigger compliance violations, incorrect cash positioning, or unauthorized transactions. The plumbing exposes how RBAC enforcement works across multiple agents, how orchestration primitives coordinate real-time bank API calls, and how tenant isolation prevents data leakage when banks white-label the same agent infrastructure.
The Treasury Agent Problem
Corporate treasury teams manage cash across hundreds of accounts, forecast liquidity, execute payments, and reconcile transactions. Traditional tools require manual data aggregation, spreadsheet analysis, and human approval chains. Trovata’s agents automate this workflow, but the security boundary is complex:
- Agent scope varies by role: A forecasting agent needs read access to all accounts. A payment agent requires write access to specific accounts only.
- Multi-tenant deployment: Banks want branded AI for their corporate clients, but tenant data cannot cross boundaries.
- Real-time state: Cash positions change constantly. Agents must coordinate without race conditions or stale reads.
- Audit requirements: Every agent action needs a tamper-proof trail for regulatory compliance.
The architecture uses Amazon Bedrock AgentCore for orchestration, Claude 3.5 Sonnet for reasoning, and a custom RBAC layer that enforces permissions before any agent touches bank APIs.
RBAC Enforcement Across Agents
Trovata’s RBAC implementation sits between the agent orchestrator and external tools. When an agent calls a tool (bank API, database query, payment execution), the RBAC layer checks:
- User identity: Which corporate user initiated the workflow?
- Agent identity: Which agent is making the call?
- Resource scope: Does this user-agent pair have permission for this specific account or transaction?
The enforcement happens at tool invocation time, not at agent initialization. This prevents an agent from escalating privileges mid-workflow or accessing resources outside its granted scope.
class RBACToolWrapper:
def __init__(self, tool, rbac_engine):
self.tool = tool
self.rbac_engine = rbac_engine
def invoke(self, agent_id, user_id, params):
# Extract resource identifiers from tool params
resource = self._extract_resource(params)
# Check permission before execution
if not self.rbac_engine.check_permission(
user_id=user_id,
agent_id=agent_id,
resource=resource,
action=self.tool.action_type
):
raise PermissionDenied(
f"Agent {agent_id} cannot {self.tool.action_type} on {resource}"
)
# Execute tool only if permission granted
return self.tool.execute(params)
This pattern prevents a common failure mode: an agent with broad reasoning capabilities but narrow execution permissions trying to access resources outside its scope. The RBAC layer blocks the tool call before it reaches the bank API.
Multi-Agent Orchestration for Treasury Workflows
Trovata’s treasury workflows involve multiple specialized agents:
- Data aggregation agent: Pulls transaction data from bank APIs and normalizes formats.
- Forecasting agent: Analyzes cash flow patterns and predicts liquidity needs.
- Payment agent: Executes approved payments and tracks settlement status.
- Reconciliation agent: Matches transactions across accounts and flags discrepancies.
AgentCore orchestrates these agents using a state machine that tracks workflow progress and coordinates handoffs. The orchestrator maintains a shared context object that agents read from and write to, but each agent only sees the context fields it has permission to access.
Orchestration Flow
- User initiates workflow: “Forecast cash position for next 30 days and execute approved payments.”
- Orchestrator spawns data aggregation agent: Pulls transaction history from all accounts the user can access.
- Forecasting agent receives aggregated data: Generates liquidity forecast and identifies payment timing.
- Payment agent receives approved payment list: Executes payments only if user has write permission on target accounts.
- Reconciliation agent verifies execution: Confirms payments settled and updates cash position.
The orchestrator uses Amazon Bedrock’s agent runtime to manage this flow. Each agent is a separate invocation with its own prompt, tools, and RBAC context. The orchestrator passes state between agents using a structured JSON context object stored in DynamoDB.
Bank-Branded Multi-Tenant Deployment
Banks want to offer Trovata’s agents to corporate clients under their own brand. This requires strict tenant isolation: Bank A’s corporate client cannot see Bank B’s data, even though both use the same agent infrastructure.
Trovata implements tenant isolation at three layers:
| Layer | Isolation Mechanism | Failure Mode |
|---|---|---|
| Data storage | Separate DynamoDB tables per tenant with partition keys | Misconfigured query returns cross-tenant data |
| Agent runtime | Tenant ID injected into every agent invocation context | Agent ignores tenant ID and queries global scope |
| RBAC enforcement | Permissions scoped to tenant-specific resources | RBAC check uses wrong tenant ID from context |
The most critical boundary is RBAC enforcement. Every tool call includes a tenant ID that the RBAC engine validates before checking permissions. If the tenant ID in the tool call does not match the tenant ID in the user’s session, the call fails.
def check_permission(self, user_id, agent_id, resource, action):
# Extract tenant from user session
user_tenant = self.session_store.get_tenant(user_id)
# Extract tenant from resource identifier
resource_tenant = self._parse_tenant_from_resource(resource)
# Fail if tenant mismatch
if user_tenant != resource_tenant:
self.audit_log.record_violation(
user_id=user_id,
agent_id=agent_id,
resource=resource,
reason="tenant_mismatch"
)
return False
# Check role-based permission within tenant
return self._check_role_permission(user_id, resource, action)
This prevents an agent from accidentally (or maliciously) accessing resources in another tenant’s scope, even if the agent has valid credentials.
Real-Time Cash Position Coordination
Treasury agents need accurate cash positions to make decisions. If two agents read stale data and execute conflicting actions (one forecasts surplus, another initiates a payment that creates a deficit), the corporate client faces overdraft fees or compliance violations.
Trovata uses optimistic concurrency control with version stamps. Each cash position record includes a version number. When an agent reads the position, it captures the version. When the agent writes an update (after executing a payment or recording a deposit), it includes the version in the write request. If the version has changed, the write fails and the agent retries with fresh data.
This prevents race conditions without requiring distributed locks, which would slow down real-time workflows. The trade-off is retry overhead when multiple agents update the same account simultaneously, but treasury workflows are not high-frequency enough to make this a bottleneck.
Failure Modes and Audit Trails
Autonomous treasury agents can fail in ways that have immediate financial consequences:
- Permission escalation: Agent attempts to execute a payment without user approval.
- Stale data: Agent makes a decision based on outdated cash position.
- API timeout: Bank API call fails mid-transaction, leaving payment status unknown.
- Tenant leakage: Agent accesses data from wrong tenant due to context corruption.
Trovata’s audit system logs every agent action with:
- User ID and session context
- Agent ID and invocation timestamp
- Tool call parameters and RBAC decision
- Result or error code
- Version stamps for any data read or written
The audit log is append-only and stored in S3 with object lock enabled. This creates a tamper-proof trail for regulatory compliance and incident investigation.
When a failure occurs, the orchestrator halts the workflow and notifies the user. The agent does not retry automatically because retrying a failed payment could result in duplicate transactions. Instead, the user reviews the audit log and decides whether to retry manually.
Architecture Diagram
┌─────────────────────────────────────────────────────────────┐
│ User Request │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Amazon Bedrock AgentCore │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Orchestrator (State Machine) │ │
│ │ - Workflow routing │ │
│ │ - Context management (DynamoDB) │ │
│ │ - Agent invocation │ │
│ └──────────────────┬───────────────────────────────────┘ │
└────────────────────┬┴───────────────────────────────────────┘
│
┌────────────┼────────────┬────────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Data │ │Forecast │ │ Payment │ │Reconcile│
│ Agent │ │ Agent │ │ Agent │ │ Agent │
└────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘
│ │ │ │
└───────────┴───────────┴───────────┘
│
▼
┌────────────────────────────┐
│ RBAC Enforcement Layer │
│ - User/Agent/Resource │
│ - Tenant isolation check │
│ - Audit logging │
└────────────┬───────────────┘
│
┌────────────┼────────────┬────────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Bank │ │Treasury │ │ Payment │ │ Data │
│ API │ │Database │ │ API │ │ Store │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
Technical Verdict
Use Trovata’s pattern when:
- You need autonomous agents in regulated domains where permission violations have legal or financial consequences.
- You deploy multi-tenant agent infrastructure and cannot afford data leakage between tenants.
- Your workflows involve multiple specialized agents that coordinate on shared state with real-time updates.
- You require tamper-proof audit trails for compliance or incident investigation.
Avoid this pattern when:
- Your agents operate in low-stakes environments where permission errors are tolerable.
- You have a single-tenant deployment and can enforce isolation at the infrastructure layer.
- Your workflows are simple enough for a single agent with a monolithic tool set.
- You need sub-second latency and cannot afford the overhead of RBAC checks on every tool call.
The RBAC enforcement layer adds latency (typically 10-50ms per tool call) and complexity. If your agents do not touch sensitive resources or operate in a trusted environment, simpler authorization patterns (API keys, service accounts) may suffice. But for bank-branded treasury agents handling real corporate cash, the trade-off is necessary.