.claude/skills/ecotone-metadata/SKILL.md
Implements message metadata (headers) in Ecotone: #[Header] and #[Headers] for reading, #[AddHeader]/#[RemoveHeader] for enrichment, changeHeaders in interceptors, automatic propagation from commands to events. Use when passing custom headers, reading message metadata, enriching headers, propagating metadata across handlers, or testing metadata with EcotoneLite.
npx skillsauth add ecotoneframework/ecotone-dev ecotone-metadataInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Every message in Ecotone carries metadata (headers) alongside its payload. Metadata includes framework headers (id, correlationId, timestamp) and custom userland headers (userId, tenant, token, etc.). Userland headers automatically propagate from commands to events.
All bus interfaces accept a $metadata array:
$commandBus->send(new PlaceOrder('1'), metadata: ['userId' => '123']);
$eventBus->publish(new OrderWasPlaced('1'), metadata: ['source' => 'api']);
$queryBus->send(new GetOrder('1'), metadata: ['tenant' => 'acme']);
#[Header]use Ecotone\Messaging\Attribute\Parameter\Header;
#[EventHandler]
public function audit(
OrderWasPlaced $event,
#[Header('userId')] string $userId,
#[Header('tenant')] ?string $tenant = null // nullable = optional
): void {
// Non-nullable throws if missing; nullable returns null if missing
}
#[Headers]use Ecotone\Messaging\Attribute\Parameter\Headers;
#[CommandHandler('logCommand')]
public function log(#[Headers] array $headers): void
{
$userId = $headers['userId'];
}
When a handler has two parameters -- first is payload, second is array -- the second is automatically resolved as all headers:
#[CommandHandler('placeOrder')]
public function handle($command, array $headers, EventBus $eventBus): void
{
$userId = $headers['userId'];
}
use Ecotone\Messaging\Attribute\Endpoint\AddHeader;
use Ecotone\Messaging\Attribute\Endpoint\RemoveHeader;
#[AddHeader('token', '123')]
#[RemoveHeader('sensitiveData')]
#[CommandHandler('process')]
public function process(): void { }
Use changeHeaders: true on #[Before], #[After], or #[Presend]. The interceptor must return an array that gets merged into existing headers.
#[Before(changeHeaders: true, pointcut: CommandHandler::class)]
public function addProcessedAt(#[Headers] array $headers): array
{
return array_merge($headers, ['processedAt' => time()]);
}
Ecotone automatically propagates userland headers from commands to events:
Command (userId=123) -> CommandHandler -> publishes Event -> EventHandler receives (userId=123)
correlationId is always preservedparentId is set to the command's messageId#[PropagateHeaders(false)] on gateway methods#[Header('name')] for single header access, #[Headers] for all headersarray parameter is auto-resolved as headers (no attribute needed)changeHeaders: true only on #[Before], #[After], #[Presend] -- NOT #[Around]changeHeaders: true must return an arraygetRecordedEventHeaders() / getRecordedCommandHeaders() to verify metadata in tests#[Header], #[Headers], #[AddHeader], #[RemoveHeader], #[PropagateHeaders], and the framework headers constants table (MessageHeaders). Load when you need exact parameter names, types, or constant values.changeHeaders, custom attribute-based enrichment (AddMetadata), metadata propagation flow, event-sourced aggregate metadata, and identifierMetadataMapping. Load when you need full, copy-paste-ready class definitions.development
Implements workflows in Ecotone: Sagas (stateful process managers), stateless workflows with InternalHandler and outputChannelName chaining, and Orchestrators (Enterprise) with routing slip pattern. Use when building Sagas, process managers, multi-step workflows, long-running processes, handler chaining, or Orchestrators.
development
Writes and debugs tests for Ecotone using EcotoneLite::bootstrapFlowTesting, aggregate testing, async-tested-synchronously patterns, projections, and common failure diagnosis. Use when writing tests, debugging test failures, adding test coverage, or implementing any new feature that needs tests. Should be co-triggered whenever a new handler, aggregate, saga, projection, or interceptor is being implemented.
testing
Sets up Ecotone in a Symfony project: composer installation, bundle registration, YAML configuration, Doctrine ORM integration, SymfonyConnectionReference for DBAL, Symfony Messenger channels, async consumer commands, and ServiceContext. Use when installing Ecotone in Symfony, configuring Symfony-specific connections, or setting up Symfony async consumers.
development
Implements message resiliency in Ecotone: RetryTemplateBuilder for retry strategies, error channels, ErrorHandlerConfiguration, DBAL dead letter queues, outbox pattern for guaranteed delivery, and FinalFailureStrategy for permanent failures. Use when handling failed messages, configuring retries, setting up dead letter queues, implementing outbox pattern, or managing error channels.