Extend the platform
You extend the platform by implementing a port — the ports are the extension surface. Ports live in packages/platform-domain/**/ports/ (infrastructure-free); your adapter lives in apps/api/**/adapters/.
Decide generic vs consumer-specific
Section titled “Decide generic vs consumer-specific”- Generic (any future consumer would want it) → goes in
packages/platform-ingestion/. Example: a new source reader, a new port. - Consumer-specific (only one app cares) → goes in the consumer’s directory. Example: classifieds-listing parsing, bookmark-tag derivation.
Add a pipeline step
Section titled “Add a pipeline step”Implement INode — or extend SelfSourcingNode when the node selects its own work rather than reading the items handed to it — and register it in the NodeRegistry with a NodeDescriptor. Most nodes register unconditionally and resolve their credential (an LLM, Gmail, Notion, … Connector) per run, failing clearly at that point when the owning user has no connected channel of that scheme; a node whose integration this deployment cannot wire at all is left unregistered, so it is absent from the palette rather than present and permanently red.
Add a dispatch destination
Section titled “Add a dispatch destination”Implement IDispatchTarget (packages/platform-domain/src/dispatch/ports/IDispatchTarget.ts) and add its scheme to DESTINATION_SCHEMES (packages/platform-domain/src/connector/Destination.ts — the canonical vocabulary shared by the workflow templates and buildWork). The dispatch step (DispatchStep) routes by config.destination’s URI scheme, threading context.metadata.userId/orgId into the destination config for owner-scoping.
Add an ingestion source
Section titled “Add an ingestion source”Implement ISourceReader in packages/platform-ingestion/. The consumer seam is IContentHandler — a consumer app implements it to translate BaseContent into its own entity.
Add an LLM provider
Section titled “Add an LLM provider”Implement ILlmClient and add the models to the catalog. Every AI consumer reaches the model through the AI gateway, which resolves the channel, applies the default, meters the call and fails it over — so adding a provider is an adapter plus a catalog entry, not a code change in any step. Anthropic (default) and Cline (fallback) are the two today.
Conventions
Section titled “Conventions”- TypeScript + Bun; checks are
bun run typecheck/bun run lint/bun run test:unit. - Keep the domain package infrastructure-free (no
drizzle-orm,pg-boss,fs,http). - Import from the
@viite-ai/platform-domainbarrel, not deep relative paths.
