Your GTM belongs in gitRegister
Cookbooks
Operations

Standup

Every evening the GTM day is recapped into the cadence log and a digest is posted to Slack, as one reviewable pull request against your GTM repo.

Installation
Set up the standup cookbook in this project. 1. If the Cargo CLI is not installed yet, follow every step in https://api.getcargo.io/INSTALL.md 2. From the Cargo project, run: cargo-ai cdk add cookbook/standup 3. Then follow .claude/skills/standup/SKILL.md. Stop for my approval before any paid call, and stop at "cargo-ai project plan" before deploying anything.
Paste it into Claude Code, Cursor, Codex, Gemini CLI, Devin or Replicas.

Say this to your agent

Every weekday at 6pm, recap what moved on our GTM initiatives into the repo and post the digest to #gtm-daily.

Illustrative output #

Fictional records, to show the shape of what comes back.

text
:racing_car: *GTM - Tue Oct 6*
_Mid-market expansion moved; EU outbound is still not sending._

:dart: *Expansion into mid-market*
• Northwind signed, closed two weeks ahead of the forecast date (#318)
• Five Fabrikam dossiers drafted; Dana sends them Thursday

:dart: *EU outbound*
• Blocked: the sourcing play has not run since Friday (#312)

:zzz: *No movement:* Partner channel

:raising_hand: *Needs a human*
• Dana: approve the EU sourcing budget so the play can resume
Full log: https://github.com/northwind/gtm/pull/320

The team reads the day in fifteen seconds in Slack, while cadence/log/2026-10-06.md lands through the “[cadence] log 2026-10-06” pull request for a human to merge.

What you will be asked #

InputWhy
channelId (infra/agents/standup.ts)AskedLocked on postMessage so the agent cannot pick a customer shared channel. A name (#general) collides; an empty lock posts nowhere useful and looks like success.
STANDUP_TITLE (infra/agents/standup.ts)AskedTwo standups in the same channel are told apart from the first line. A repo name here reads as infrastructure, not as the GTM day.

Done when #

  • --dry-run printed the dump, and the run without it wrote cadence/log/raw/standup/<date>.md; running it twice that evening overwrote the same file
  • node --import tsx evals/contract.mjs passes: harness is claudeCode bound to an Anthropic connector, no capability is wired, postMessage is on uses with channelId locked, and no tool wraps it
  • cargo-ai cdk plan reports the agent, the two connectors and the folder, and does not run git or gh while planning
  • the first scheduled run opened one pull request titled [cadence] log <date> whose diff contains the raw dump and the three log sections, and whose body carries ## Slack digest plus a posted-or-not line
  • the digest landed once in the locked channel, with Full log: <PR URL> as the last line
  • a re-run the same evening opened no second pull request and posted no second message
  • every status: active initiative appears in the log and in the digest, either in its own section or on the No movement line, and anything that big outside the initiatives leads the post as Outside the plan
  • a quiet day still produced an entry that says so
  • no number in the digest is absent from the raw dump, a metrics file dated that day, or a cargo-ai read the agent actually ran. A CLI read that errors is a note on the PR, not a made-up count

What it costs #

The collector talks to git and, when gh is installed, to GitHub from the harness environment. Those calls are not Cargo connector actions.

The Slack post is slack.postMessage on the bound connector. Immediately before the plan, run cargo-ai orchestration action list postMessage --kind connector --integration-slug slack and read the current cost. Say that number out loud as a per-post cost; the run posts once.

The recurring cost is the harness run itself, once a day, billed as LLM tokens through the bound Anthropic connector, and it scales with how much the agent reads — the dump, the day’s cadence files, a short window of git history, and the read-only cargo-ai calls in §1b (whoami, run counts, usage, what is deployed). Those reads are API calls, not connector actions, so they bill nothing. There is no per-record fan-out, and the recap never runs a command that spends.

Turn the GTM day the team already lived into things a repository and a Slack channel can hold: a raw evidence dump, a log entry a teammate can read on Monday, and a digest posted through Cargo. Collected by a committed script, recapped by a Claude Code harness agent, delivered as one pull request plus one Slack post.

What it does #

  • Collects. scripts/collect/day.ts dumps git commits, pull requests, and cadence files named for the timezone’s current date into cadence/log/raw/standup/. Deterministic, no LLM anywhere near it.
  • Recaps. The agent reads the dump, the workspace through read-only cargo-ai calls (runs, usage, what is deployed), and whatever cadence/ already holds, then writes cadence/log/<date>.md: what moved, what is stuck, what is worth remembering.
  • Posts. The same recap, cut to a fifteen-second Slack digest, through slack.postMessage on a bound Slack connector. The channel is locked on the use.
  • Stops. One pull request, never merged. Slack goes out from the run; the log waits for a human merge.

How it works #

  1. The cron trigger fires at 05:00 UTC (10pm PT during PDT), at the end of the timezone day.
  2. The agent clones the repository — the project’s own, resolved from the checkout’s git origin at deploy rather than written down.
  3. It runs the collector — npx tsx scripts/standup/collect/day.ts — which reads STANDUP_TIMEZONE from the harness environment. The agent is told not to fetch the day itself.
  4. It reads the workspace with Cargo’s own CLI, which the checkout already has: whoami, the day’s run counts and failures, usage, what is deployed. Read-only, and no capability is wired on the agent. If cargo-ai whoami fails, the sandbox has no session: it notes that on the pull request and continues from the dump.
  5. It writes the log, then opens one pull request titled [cadence] log <date>.
  6. It posts the digest by calling slack.postMessage (body only; channel, format and unfurling are locked), appending Full log: <PR URL>.
  7. A human merges the log. The Slack post has already landed.

Adds 5 resources plus a script bundle.

FileResourceRole
infra/agents/standup.tsdefineAgent (claudeCode)schedule, repository binding, locked Slack use
infra/agents/standup.prompt.ts(not a resource)the recap contract: window, digest shape, limits
infra/connectors/git.tsdefineConnector (github)the clone, branch, push and PR path, resolved by binding
infra/connectors/slack.tsdefineConnector (slack)the post path; OAuth, bound rather than created
infra/connectors/anthropic.tsdefineConnector (anthropic)the model the harness runs on, billed and metered
infra/folders/index.tsdefineFolderthe workspace folder this cookbook’s resources are filed in
scripts/collect/day.ts(not a resource)the entrypoint: dump git / gh / cadence files for the day

The two halves, and where they land #

This cookbook has one directory per layer it touches, and the install mirrors each into its namesake in the project:

text
standup/infra/     ->  infra/standup/      what is declared and deployed
standup/scripts/   ->  scripts/standup/    what the agent runs

Those are the layers cargo-ai cdk init already scaffolds — infra/ is the CDK project, scripts/ is “imperative glue for runtime surfaces the CDK cannot declare yet” — so a cookbook that needs both contributes to both under its own name rather than inventing a third place.

scripts/package.json is belt and braces. In a Manifest repo the CDK project root is infra/, so nothing under scripts/ is ever imported as a resource. In a project whose CDK root is the repo root, the loader imports every .ts it finds except directories carrying a package.json — without that file, cargo-ai cdk plan would import the collector and run git/gh on every plan.

Why the split #

The collection and the judgement are different jobs, and the failure modes for mixing them are not symmetric.

A fetch loop an agent re-derives every evening is a fetch loop that silently changes shape: a window that drifts, a gh flag that quietly widens. Nothing downstream can tell, because the dump is what everything downstream is diffed against. So the fetch is a committed script and the agent is told not to improvise it.

The recap is the opposite. It is judgement — what actually moved, whether a quiet day is signal, who owns the stuck item — and it produces a diff across markdown files plus one Slack post. That is what harness: "claudeCode" buys: a working tree, the git history to read before writing, and a pull request. It does not buy its own model: the harness runs against Cargo’s LLM proxy, so connector and languageModel are required here exactly as they are on a streamText agent, and they are what the run is billed and metered against.

Why Slack is a connector action, not a script #

Cargo already has slack.postMessage. Putting a SLACK_TOKEN in the harness environment and curling chat.postMessage would work, and it is exactly how this job used to ship outside Cargo: a GitHub Action, a hosted agent, a bot token. Three moving parts, no run to inspect, and a token that posts anywhere.

The channel lock is the safety property that token never had. channelId sits in the action’s config, the same way mailboxUuid is locked on sendEmail. The agent fills body. Wrapping that one action in a tool is ceremony this repo refuses.

Cargo does not ship a conversations-history action, so duplicate detection is the log file: if today’s three sections are already there, this run has already happened. That is also the more honest key. Matching on the Slack channel is how a sibling post, or a missed history call, made an earlier version of this job skip silently for nights at a time.

Placeholders (edit before deploy) #

  1. channelId — infra/agents/standup.ts: a Slack channel id (C…) the bound connector can post to. Invite the bot.
  2. STANDUP_TITLE — infra/agents/standup.ts: the short name in the Slack header.
  3. STANDUP_TIMEZONE — same file: IANA timezone the recapped calendar day is computed in. Change it together with cron.
  4. languageModel — same file: any Anthropic model the workspace’s connector can reach. claudeCode pairs with the anthropic integration and nothing else.

What it does not do #

It does not contact customers, write to a CRM, merge its own pull request, run a CLI command that spends or deploys, edit or delete a raw dump or an existing log section, promote first-occurrence claims into context/, or touch plan/ and infra/. It reports the day; it does not change the strategy or the deployed engine.

Give your agents a runtime

Bring the agents you have.Start free, deploy in one command.