Portable definitions
The definition files that describe each object in a Package.
Each object the manifest lists has a definition file: YAML in your project, which build
converts to canonical JSON inside the .pkg. A definition describes what the object is and how it
behaves, with nothing that identifies an Organization:
- other objects are referenced by manifest-local name (
agents.intake,tools.calendar), never by id, - models, credentials, documents, speech providers and trunks are referenced by Slot id
(
llm.slot: reasoning,credentialSlot: calendar-access), - nothing is personal or secret.
build refuses a definition that would carry an Organization identifier
(PORTABLE_ORG_IDENTIFIER_LEAK) or personal data such as an email address
(PORTABLE_PERSONAL_DATA_LEAK).
Carried text
validate, and so build, scans every string in every definition file for two things, and refuses
the Package when it finds either, with the exceptions below:
- an email address, refused with
PORTABLE_PERSONAL_DATA_LEAK. A Package travels by email, file share and USB, so a sticky note, prompt or description must not name a person. A{{ }}expression that resolves to an address at run time, such as{{ trigger.email }}, is not an address and passes. The check is loose: a file name likelogo@2x.pngmatches it too, so rename anything that isn't an address. - a secret reference: a value that starts with
vault:, or contains{{secret.…}}. It is refused withPORTABLE_ORG_IDENTIFIER_LEAK, orPORTABLE_DEFINITION_INVALIDin a Tool file (see Tools). A reference points into the author's own vault, so it never travels. Use acredentialSlot.
Every hit is reported. The path names the collection, the object and the field, such as
agents.support.config.instructions or workflows.triage.graph.nodes[2].data.text, and the
message names the definition file.
The scan covers the agents, teams, workflows, tools, skills, knowledgeBases and
dataTables definitions and the voice and sip files. Three exceptions:
- Machine content — a Tool's embedded OpenAPI
spec, and a Workflow Code node's source (data.code, on acodenode only). An address-shaped match there is aPORTABLE_MACHINE_CONTENT_EMAILwarning at the same path, such astools.orders.spec.info.contact.emailorworkflows.triage.graph.nodes[3].data.code, and the Package still builds. A third-party spec's vendor contact, or Python likex@self.weights, may stay; a person's address must still go. A secret reference there is refused as anywhere else, and every other field of a Tool or Code node (an action description, a header value, a Code node'sinputExpression) is scanned as usual. - A Workflow's people fields (a human-review
assignedTo, a Send Emailto,cc,bccorreplyTo) holding a literal address are stripped bybuildwith a warning, not refused. A human-reviewfallbackAssignedTois always stripped, whatever it holds. See People fields. - A Skill's files (the
SKILL.mdbody, reference files and scripts) are the Skill's content, not definition fields, and are not scanned. Its frontmattername,descriptionandallowed-toolsare.
| Object | Manifest entry | Page |
|---|---|---|
| Agent | agents: [{ name, ref }] | Agents |
| Team | teams: [{ name, ref }] | Teams |
| Workflow | workflows: [{ name, ref }] | Workflows |
| Tool | tools: [{ name, ref }] | Tools |
| Skill | skills: [{ name, ref: ./skills/x/ }] | Skills |
| Knowledge Base | knowledgeBases: [{ name, ref }] | Knowledge Bases |
| Data Table | dataTables: [{ name, ref }] | Data Tables |
| Voice, SIP | voice: { ref }, sip: { ref } | Voice and SIP |
Where to start
The quickest way to get correct definition files is to start from one: every
init starter and every
demo Package contains valid, commented
definitions. Edit from there, and run validate after each change: it checks every definition file
against its schema and reports the exact path of anything wrong.
Keep definitions in step with the platform
Definitions mirror the settings the corresponding Studio editor offers. When a field's meaning isn't obvious, open the same object type in Studio and look at the equivalent setting.