Build MCP
Build cookbook: Data Pipeline Artifact
Golden example `data-pipeline-artifact` from the Build cookbook: what it builds, the template it starts from and the boundary it keeps.
Data Pipeline Artifact
Use this example when a customer wants to connect a system, keep its data synced, or change what syncs and when. With the Data Sources workspace on, each connector instance (one PestRoutes account, one Five9 tenant, one Google Sheet, one custom API) is one data pipeline artifact in the Data Sources workspace. It holds many tables and many named schedules.
A data pipeline artifact is a built-in artifact type, not an artifact app. It
has no package, routes, runtime, deploy or smoke. Its whole payload is a
pipelineManifest. The platform still owns the connection and its secret
references, checkpoints, the sync handlers, the materialized tables, the
scheduler jobs and run history. The manifest only says which tables exist and
which named schedule runs each one.
Is the workspace on?
Call list_pipeline_artifacts. If it is not offered, or it fails because the
workspace is not enabled, the tenant still uses the classic Data Sources pages:
follow Customer API source pipeline
and stop there. Do not invent artifacts.
The manifest
{
"pipelineManifestVersion": 1,
"connector": "pestroutes",
"sourceId": "<the bound source id; never change it>",
"title": "PestRoutes",
"tables": [
{ "name": "appointments", "label": "Appointments" },
{ "name": "routes", "label": "Routes" },
{ "name": "customers", "label": "Customers" },
{ "name": "tickets", "label": "Tickets" },
{ "name": "employees", "label": "Employees" }
],
"schedules": [
{ "name": "Every 15 minutes", "tables": ["appointments", "routes"], "cron": "*/15 * * * *", "timezone": "America/Denver", "enabled": true },
{ "name": "Hourly", "tables": ["customers", "tickets"], "cron": "0 * * * *", "timezone": "America/Denver", "enabled": true },
{ "name": "Nightly 2:00", "tables": ["employees"], "cron": "0 2 * * *", "timezone": "America/Denver", "enabled": true },
{ "name": "Nightly hard delete", "job": "hard_delete", "tables": ["customers", "appointments", "tickets"], "cron": "0 3 * * *", "timezone": "America/Denver", "enabled": true, "resources": { "memoryMb": 8192 } },
{ "name": "Upcoming appointments and routes", "job": "hard_delete_upcoming", "tables": ["appointments", "routes"], "cron": "*/30 6-20 * * *", "timezone": "America/Denver", "enabled": true }
]
}
Rules the server enforces when a draft is saved:
tablesare the source's own tables. Do not add a table the connector does not sync; the connector's setup adds tables (PestRoutes: add a resource; Five9: schedule a report).- Each table is in at most one schedule per job. A schedule without
jobis a sync.hard_delete(full scan) andhard_delete_upcoming(records dated today or later) exist only on PestRoutes, and only for tables that have that scan installed (read_pipeline_artifactlists them inhardDeleteTables). resourcessets the machine size of each run of a hard-delete schedule:memoryMband optionalcpu(a Fargate pair, the same as an app'sresources.build; omittedcpumeans the smallest that fits). Omittedresourcesmeans 8 GB. Each run gets its own machine, which stops when the check ends. Sync schedules cannot set it. Publishing refuses a size above the account's build limit (resources_above_ceiling, default 8 GB); never lower a size silently. Raise it when a check fails withsized_task_stopped: OutOfMemoryError.cronis five-field cron ornullfor manual only; a manual-only schedule cannot be enabled.timezoneis an IANA name and decides when the cron fires.- Schedule names are unique and are what people see; name them by cadence or purpose ("Every 15 minutes", "Nightly hard delete").
Change a pipeline (the coder's loop)
read_pipeline_artifactwith the artifact id. Noteversion, the live manifest, any existingdraftManifest, each schedule's live job state (enabledJobs,operatorPausedJobs,failingJobs) andreconcile.- Start from
draftManifestwhen there is one (someone is mid-edit), else from the live manifest. Change only what was asked. save_pipeline_artifact_draftwith the complete manifest andexpectedVersion. Fix and resave onpipeline_manifest_invalid; onversion_conflictreread and reapply.- Tell the person what changed and that it is a draft: live schedules keep running unchanged until they press Publish on the pipeline. You cannot publish, pause or resume; those change live jobs and stay with a person.
What publishing does, so you can explain it: each schedule's jobs move to its new cron, timezone or on/off state; schedules that did not change are not touched; a job an operator paused stays paused; nothing reloads data.
Worked examples
Supplied connector, many tables, several schedules (PestRoutes)
"Sync appointments and routes every 15 minutes during business hours, the rest hourly, and check for deleted customers nightly."
read_pipeline_artifact. The live manifest has 22 tables in three adopted schedules plus two hard-delete schedules.- Edit the draft: set "Every 15 minutes" to
*/15 7-18 * * 1-6and rename it "Every 15 minutes, business hours"; move the remaining sync tables into "Hourly"; make surecustomersis in thehard_deleteschedule at0 3 * * *. - Save the draft and tell the person to review the Schedules tab (Sync and Hard delete sub-tabs) and publish.
Offices and the PestRoutes credentials are not in the manifest. Offices live on the pipeline's Offices tab; credentials on its Connection tab.
Custom API
"We have a vendor API; keep its customers and work orders synced hourly."
- Build the source with the chat data-source tools exactly as in
Customer API source pipeline:
secure credential card, table approval card, verified
platform.connector.rest.v1manifest, bounded sample sync, resumable initial load, catalog registration. schedule_pipeline_refreshcreates the first schedule. With the workspace on, the source becomes its data pipeline artifact and the tool returnspipelineArtifactId.- Later cadence changes go through that artifact (draft, then a person
publishes).
schedule_pipeline_refreshrefuses them withpipeline_artifact_owned.
Google Sheets
Each spreadsheet set up is its own artifact; several can share the tenant's
Google access, and deleting one never revokes it. The usual change is a single
schedule's cadence: read, edit that schedule's cron/timezone, save the
draft.
What does not belong in the manifest
- Credentials, secret references, API keys, connection settings.
- Endpoints, pagination, checkpoints, rate limits: those are the connector's.
- Dashboards or tools built on the synced data: build those as ordinary artifact apps that read the cataloged tables.
- Machine size: set by the platform for the connector's handler.
Acceptance evidence
- The draft saved with no validation errors, and
read_pipeline_artifactshows it asdraftManifest. - Live job state is unchanged until a person publishes.
- After publish,
reconcile.upToDateis true and each changed schedule's jobs show the new cadence; operator-paused jobs are still paused.