Portal Community

Address Format

ANCP addresses follow a URI-style format:

{scheme}://{tenantId}/{...entity-path}
PartRoleExample
schemeIdentifies the type of addressable entitynode, agent, service, topic, user
tenantIdTenant scope — must match the envelope tenantIdtenant-acme, tenant-globex
entity-pathHierarchical path identifying the specific endpointflow-42/step-3, octopus/hr-agent
Tenant in the Address

The tenantId appears in both the address URI and the envelope's top-level tenantId field. The router compares them. If they differ, the message is rejected with a 403 and a cross-tenant violation is logged in the audit trail.

Address Schemes

node://

Addresses a specific execution node within a workflow run. Node addresses include the flow ID and, optionally, the step ID.

node://{tenantId}/{flowId}/{nodeId}

# Examples
node://tenant-acme/flow-42/approval-gate
node://tenant-acme/flow-42/send-email
node://tenant-acme/flow-55/data-transform-step-3

agent://

Addresses an AI agent managed by the Octopus framework. The agent path identifies the agent pool and the specific agent instance.

agent://{tenantId}/{agentPool}/{agentId}

# Examples
agent://tenant-acme/octopus/hr-policy-agent
agent://tenant-acme/octopus/expense-classifier
agent://tenant-acme/octopus/document-extractor

service://

Addresses a backend service endpoint (not a workflow node or AI agent). Used for inter-service Commands in the backend layer.

service://{tenantId}/{serviceName}

# Examples
service://tenant-acme/payroll-service
service://tenant-acme/notification-service
service://tenant-acme/audit-log-service

topic://

A pub/sub topic address — used exclusively in the destination field of Event type messages. Not a point-to-point address; the router publishes to all subscribers matching the topic pattern.

topic://{tenantId}/{domain}/{event-name}

# Examples
topic://tenant-acme/expenses/approved
topic://tenant-acme/workflow/completed
topic://tenant-acme/system/health-check

user://

Addresses a specific authenticated user session. Used when an agent or node wants to send a message directly to a user's browser client (e.g., a notification or form render request).

user://{tenantId}/{userId}/{sessionId}

# Examples
user://tenant-acme/user-88/sess-xyz-001
user://tenant-acme/user-42/sess-abc-002

The Role of tenantId

The tenantId segment in every address is the first and strongest isolation boundary in ANCP. Routers evaluate three conditions on every message:

1

Envelope tenantId matches Source address tenantId

The tenantId in the envelope's top-level field must equal the tenantId segment of the source URI.

2

Envelope tenantId matches Destination address tenantId

The tenantId in the envelope must equal the tenantId segment of the destination URI.

3

tenantId matches Authentication claim

The tenantId must match the tenant claim in the bearer JWT (for SignalR) or the API key scope (for HTTP). This prevents a tenant from forging another tenant's ID.

Cross-Tenant Messages Are Silently Dropped

A message that passes authentication but fails tenant consistency is not returned to the sender as an error (to prevent information leakage). It is silently discarded and a CROSS_TENANT_VIOLATION audit event is written to the security log with the offending message ID and source address.

Routing by Address Type

Destination SchemeMessage TypeRouter Behaviour
node://Command, Query, ResponseLooks up the active transport for that node instance. Delivers to the node's message handler.
agent://Command, Query, ResponseDispatches to the Octopus agent pool. The pool manager routes to the specific agent or a free instance.
service://Command, QueryResolves service name to HTTP endpoint. Posts the ANCP envelope as JSON body.
topic://Event onlyPublishes to EdgeStream pub/sub. All subscribers matching the topic pattern receive a copy.
user://Command, EventDelivers to the user's active SignalR connection identified by sessionId.

Address Examples by Context

# Workflow node sending a command to the next step
source:      "node://tenant-acme/flow-42/step-2-validator"
destination: "node://tenant-acme/flow-42/step-3-notifier"

# Node asking an AI agent a question
source:      "node://tenant-acme/flow-42/policy-check"
destination: "agent://tenant-acme/octopus/policy-agent"

# Agent publishing a result event
source:      "agent://tenant-acme/octopus/classifier"
destination: "topic://tenant-acme/classification/completed"

# Backend service sending notification to user
source:      "service://tenant-acme/approval-service"
destination: "user://tenant-acme/user-88/sess-xyz-001"

Programmatic Address Construction

Use the ANCP address builder helpers to construct addresses safely — never concatenate strings manually, as it risks introducing malformed addresses or tenant mismatches.

import { AncpAddress } from '@bizfirst/ancp-sdk';

// Build a node address
const nodeAddr = AncpAddress.node({
  tenantId: 'tenant-acme',
  flowId:   'flow-42',
  nodeId:   'approval-gate'
});
// => "node://tenant-acme/flow-42/approval-gate"

// Build a topic address
const topicAddr = AncpAddress.topic({
  tenantId:  'tenant-acme',
  domain:    'expenses',
  eventName: 'approved'
});
// => "topic://tenant-acme/expenses/approved"

// Parse an address back to components
const parsed = AncpAddress.parse('agent://tenant-acme/octopus/hr-agent');
// => { scheme: 'agent', tenantId: 'tenant-acme', path: ['octopus', 'hr-agent'] }