Skip to main content
Job: let an agent or job run GTM workflows without babysitting. Examples:
Background jobPlay pattern
Refresh account signals dailycron binding
Enrich inbound demo requestswebhook binding
Clean CRM job changes weeklyscheduled play
Process new CSV dropsagent watches folder, runs play

Pin credentials in .env.deepline

cd ~/gtm-workflows/customers/acme
cat >.env.deepline <<'ENV'
DEEPLINE_HOST_URL=https://code.deepline.com
DEEPLINE_API_KEY=dl_acme_workspace_key
ENV

deepline plays run account-refresh --watch --json
Do not rely on deepline org switch in unattended jobs, and do not prefix individual Deepline commands with ad hoc API keys. Use customer-specific output paths:
cd ~/gtm-workflows/customers/acme
deepline plays check account-refresh.play.ts

deepline plays run plays/customers/acme/account-refresh.play.ts \
  --csv customers/acme/input/accounts.csv \
  --watch

deepline runs export <run-id> --out output/accounts-refreshed-2026-05-11.csv

Name agents like operators

deepline auth register \
  --org-name "Acme" \
  --agent-name "acme-nightly-enrichment"
When support looks at runs later, this name should explain who did the work.

Watch status

deepline runs list --play account-refresh --json
deepline runs tail <run-id> --json
Use these in runbooks and incident notes.

Add small brakes

import { definePlay } from 'deepline';

type Account = {
  domain: string;
};

export default definePlay('account-refresh', async (ctx, input: { accounts: Account[] }) => {
  const rows = await ctx
    .dataset('account_refresh', input.accounts)
    .withColumn('company_signal', (account, rowCtx) =>
      rowCtx.tools.execute({
        id: 'company_signal',
        tool: 'test_rate_limit',
        input: { key: account.domain },
        description: 'Refresh one account signal.',
      }),
    )
    .run({ key: 'domain' });

  return { rows };
}, {
  billing: { maxCreditsPerRun: 25 },
});
For a new workflow, pilot a few rows first. Then raise the cap when the output looks right.