Metadata Format

Identity and properties for anything that takes part in an Itara-managed topology — components, contracts, events, and plugins alike.

A .itara file is a small TOML document shipped alongside every build artifact (a component, an API, a transport, a serializer, an observer, etc). It declares what the artifact is — its identity, the versions it was built against, and (depending on its kind) a handful of kind-specific declarations that other tooling and the agent itself use to wire things up safely.

Unlike the wiring configuration, which is one file describing an entire deployment topology, a .itara file describes exactly one artifact.

This document describes the file format — every section, every field, what’s required, what defaults apply, and which artifact kinds each section is meaningful for.

Wherever a field is described below as a version — artifact.version, api-version, and every version inside a { id, version } entry — it’s a semver string, not an arbitrary one; version-range fields (like [serializers] supported[].version) are semver ranges checked against it.

Forward compatibility

Unknown sections, and unknown fields within known sections, are always silently ignored. This is deliberate: it lets an older agent load an artifact built with a newer version of the metadata schema without failing, simply ignoring whatever it doesn’t understand. Don’t rely on unrecognized fields causing a parse error — they won’t.

Top-level structure

[artifact]
kind = "component"
id = "inventory"
version = "1.0.0"
api-version = "1.x"
 
[runtime]
language = "java"
compiler = "21"
 
[itara]
spec-version = "0.1"
core-version = "0.1+"
SectionRequiredMeaningful forDescription
[artifact]Yesevery kindIdentity: what this artifact is, and its own version.
[runtime]Noevery kindWhat language/compiler built this artifact.
[itara]Noevery kindWhich version of the Itara spec/core this artifact targets.
[methods]NoapiPer-method properties of the contract — currently, which methods are non-idempotent.
[implemented-event-contracts]NocomponentWhich event contracts this component implements.
[contract]Noapi, eventsProperties of the contract as a whole — currently, its message format.
[serializers]NoapiWhich serializers this artifact was compiled with support for.
[serializer]NoserializerWhat this serializer implementation is and can do.
[transport]NotransportWhat this transport implementation is and can do.
[failure-semantics]Nofailure-semanticsWhat this failure-semantics implementation can do.
[authentication]NoauthenticationWhat kind of authentication mechanism this is.
[authorization]NoauthorizationWhat kind of authorization mechanism this is.
[api-dependencies]NocomponentWhich API contracts this component calls, and at what version.

Every section beyond [artifact] is optional at the parser level. The “meaningful for” column describes intent, not an enforced restriction — nothing about the format itself rejects a [transport] section on a component artifact, for instance.

[artifact] (required)

[artifact]
kind = "component"
id = "inventory"
version = "1.0.0"
api-version = "1.x"
FieldTypeRequiredDefaultDescription
kindstringYes—The artifact’s kind: component, api, events, transport, serializer, observer, failure-semantics, authentication, authorization, context-handler.
idstringYes—Component id for component/api/events artifacts (e.g. "inventory"); SPI implementation name for transport/serializer/observer/failure-semantics/authentication/authorization artifacts (e.g. "http").
versionstringNo""This artifact’s own version.
api-versionstringNo""The API version this artifact exposes (for api/component producing an API) or was compiled against.

.itara files are named without an embedded version — identity comes purely from (kind, id).

[runtime] (optional)

[runtime]
language = "java"
compiler = "21"
FieldTypeRequiredDefaultDescription
languagestringNo""Implementation language, e.g. "java", "rust".
compilerstringNo""Compiler/language version used to build the artifact, e.g. "21", "1.78+".

[itara] (optional)

[itara]
spec-version = "0.1"
core-version = "0.1+"
FieldTypeRequiredDefaultDescription
spec-versionstringNo""Version of the Itara spec this artifact was built against.
core-versionstringNo""Version of the Itara core this artifact was built against.

[methods] (optional — api artifacts)

[methods]
non-idempotent = ["divide", "transfer", "placeOrder"]
FieldTypeRequiredDefaultDescription
non-idempotentarray of stringsNo[]Names of contract methods that are not safe to retry automatically.

Absence of this section (or of a given method name within it) means the method is treated as idempotent — the safe default for retry purposes.

[implemented-event-contracts] (optional — component artifacts)

[implemented-event-contracts]
contracts = [
  { id = "order-events/order-placed",    version = "1.0.0" },
  { id = "order-events/order-cancelled", version = "1.0.0" },
]
FieldTypeRequiredDefaultDescription
contractsarray of { id, version }No[]Event contracts this component implements.

Each entry:

FieldTypeRequiredDescription
idstringYesFull contract reference: <events-artifact-id>/<contract-id>, e.g. "order-events/order-placed".
versionstringYesVersion of the events artifact this implementation was written against.

Present only on component artifacts that consume event contracts.

[contract] (optional — api and events artifacts)

[contract]
message-format = "protobuf"
FieldTypeRequiredDefaultDescription
message-formatstringNo""The message format the contract’s method parameter/return types (for api) or event payload types (for events) are generated from, e.g. "protobuf". An empty string is treated identically to the section being absent entirely — both mean the contract uses plain, hand-written types rather than a generated structural format.

This is a structural property of the contract’s own types — it’s unrelated to which serializer ids an artifact is compatible with (that’s [serializers], below); message format and serializer choice vary independently.

[serializers] (optional — api artifacts)

[serializers]
supported = [
  { id = "json", version = "1.x" },
  { id = "protobuf", version = "1.x" },
]
FieldTypeRequiredDefaultDescription
supportedarray of { id, version }No[]Serializers this API artifact was compiled with support for.

Each entry:

FieldTypeRequiredDescription
idstringYesMatches a serializer’s artifact.id, e.g. "json", "protobuf".
versionstringYesA semver range checked against that serializer’s own artifact.version.

Not every language needs this section populated. Java loads serializers as runtime plugins, so an API artifact can work with a serializer it never declared here. Rust has no equivalent runtime plugin mechanism — a Rust API artifact must be compiled with support for whichever serializers it will use, so [serializers] supported is how that compiled-in support gets declared and checked.

[serializer] (optional — serializer artifacts)

[serializer]
type = "protobuf"
 
[serializer.capabilities]
message-formats = ["protobuf"]
FieldTypeRequiredDefaultDescription
typestringNoabsent/nullThe serialization category this implementation handles — e.g. "json", "protobuf". Distinct from artifact.id, which is the unique identifier of the specific implementation.
capabilitiesSerializerCapabilitiesNosee belowSee below.

SerializerCapabilities

FieldTypeRequiredDefaultDescription
message-formatsarray of stringsNo[]Structural message formats this serializer implementation can handle generically, beyond plain hand-written types — e.g. a protobuf serializer declares ["protobuf"] here, meaning it can handle proto-generated types via reflection.

Defaults to an empty list when the [serializer.capabilities] section is absent — a serializer is assumed to handle plain types only, until it explicitly declares a structural format it supports. This has no bearing on error-payload handling, which every serializer supports unconditionally regardless of its declared message-formats.

[transport] (optional — transport artifacts)

[transport]
type = "http"
 
[transport.capabilities]
native-call-timeout = true
externally-interruptible = true
FieldTypeRequiredDefaultDescription
typestringNoabsent/nullThe transport category / communication protocol, e.g. "http", "kafka", "amqp". Two implementations sharing the same type are considered compatible caller/callee pairs. Distinct from artifact.id.
capabilitiesTransportCapabilitiesNosee belowSee below.

TransportCapabilities

FieldTypeRequiredDefaultDescription
native-call-timeoutbooleanNotrueWhether the transport can abort an in-flight call natively when the per-call timeout expires. If false, the failure-semantics layer is responsible for enforcing the timeout externally instead.
externally-interruptiblebooleanNotrueWhether it’s safe to externally interrupt the thread blocked on this transport’s send call — i.e. doing so won’t leave the transport in a broken state.

Both fields default to true when the [transport.capabilities] section is absent entirely — a transport is assumed capable unless it explicitly declares otherwise. This is the opposite default from SerializerCapabilities and FailureSemanticsCapabilities, both of which default to the unsupported/empty case.

[failure-semantics] (optional — failure-semantics artifacts)

[failure-semantics]
 
[failure-semantics.capabilities]
supports-external-timeout = true
FieldTypeRequiredDefaultDescription
capabilitiesFailureSemanticsCapabilitiesNosee belowSee below.

FailureSemanticsCapabilities

FieldTypeRequiredDefaultDescription
supports-external-timeoutbooleanNofalseWhether this failure-semantics implementation can enforce the per-attempt timeout by externally interrupting the transport thread. Implementations must opt in explicitly.

[authentication] (optional — authentication artifacts)

[authentication]
type = "mtls"
FieldTypeRequiredDefaultDescription
typestringNoabsent/nullThe authentication mechanism category, e.g. "shared-secret", "mtls", "jwt". Distinct from artifact.id.

[authorization] (optional — authorization artifacts)

[authorization]
type = "rbac"
FieldTypeRequiredDefaultDescription
typestringNoabsent/nullThe authorization mechanism category, e.g. "rbac", "rule-table", "opa". Distinct from artifact.id.

[api-dependencies] (optional — component artifacts)

[api-dependencies]
calls = [
  { id = "calculator", version = "1.0.0" },
  { id = "inventory",  version = "2.1.0" },
]
FieldTypeRequiredDefaultDescription
callsarray of { id, version }No[]Synchronous API contracts this component calls.

Each entry:

FieldTypeRequiredDescription
idstringYesMatches the artifact.id of the callee’s kind = "api" metadata file.
versionstringYesThe exact version this component was compiled against — used to check compatibility against the callee’s declared api-version.

Absence of the section (rather than an empty calls list) means the same thing: the component declares no outbound API calls. This is valid, and expected, for leaf components.

Full example

A component that calls one API and implements two event contracts:

[artifact]
kind = "component"
id = "order-service"
version = "1.4.0"
api-version = "1.x"
 
[runtime]
language = "java"
compiler = "21"
 
[itara]
spec-version = "0.1"
core-version = "0.2"
 
[api-dependencies]
calls = [
  { id = "pricing", version = "2.0.1" },
]
 
[implemented-event-contracts]
contracts = [
  { id = "order-events/order-placed",    version = "1.0.0" },
  { id = "order-events/order-cancelled", version = "1.0.0" },
]

An API artifact declaring one non-idempotent method:

[artifact]
kind = "api"
id = "order-service"
version = "1.4.0"

[methods]
non-idempotent = ["placeOrder"]

An HTTP transport artifact:

[artifact]
kind = "transport"
id = "http"
version = "0.3.0"
 
[runtime]
language = "rust"
compiler = "1.78+"
 
[transport]
type = "http"
 
[transport.capabilities]
native-call-timeout = true
externally-interruptible = true