Skip to content

CI/CD Reference

Technical reference for running Agenda Panda inside CI/CD pipelines.

Looking for the acquisition-style walkthrough first? Start with the public CI/CD guide.

  1. Create an API key in Settings
  2. Add it as a secret (AP_API_KEY) in your CI system
  3. Use the GitHub Action or raw CLI
  4. Pass --project and --connection explicitly when your automation should not depend on mutable local defaults
- uses: agendapanda/post-action@v1
with:
api-key: ${{ secrets.AP_API_KEY }}
content: "We just shipped v2.0!"
Terminal window
curl -fsSL https://agendapanda.com/install.sh | bash
AP_API_KEY=$AP_API_KEY ap post "Deployed to production" --project "$AP_PROJECT" --connection linkedin

Keep a calendar.json in your repo and sync on every push:

- uses: agendapanda/post-action@v1
with:
api-key: ${{ secrets.AP_API_KEY }}
calendar-file: "./calendar.json"

With raw CLI commands:

Terminal window
curl -fsSL https://agendapanda.com/install.sh | bash
AP_API_KEY=$AP_API_KEY ap calendar sync --file calendar.json --project "$AP_PROJECT" --dry-run
AP_API_KEY=$AP_API_KEY ap calendar sync --file calendar.json --project "$AP_PROJECT" --delete-missing

See the Calendar as Code guide for the JSON format.

Use GitHub Actions when you want each release to create a reviewable Agenda Panda release packet automatically instead of posting immediately.

  • Runs on release.published or a manual workflow_dispatch
  • Supports release tags that start with cli-v, web-v, or website-v
  • Normalizes both web-v* and website-v* to the website release kind used in the draft payload
  • Creates a release packet in Agenda Panda with social drafts plus internal draft artifacts for review before publishing
  1. Create an API key in Settings
  2. Add these repository secrets in GitHub:
    • AP_API_KEY: API key with access to your workspace
    • AP_PROJECT_ID: target workspace/project ID
    • OPENAI_API_KEY: optional but recommended if you want model-generated release packets instead of deterministic fallback copy
  3. Add these optional GitHub values if you want more control:
    • AP_SOCIAL_CONNECTION_ID (secret): prebind the draft to a specific social connection
    • AP_API_URL (repository variable): defaults to https://agendapanda.com
    • OPENAI_MODEL (repository variable): model used for packet generation, for example gpt-5-mini
    • RELEASE_DOC_PATHS (repository variable): comma-separated repo files to feed into packet generation
    • RELEASE_SOCIAL_CHANNELS (repository variable): comma-separated platforms to generate social drafts for, for example linkedin,x
    • RELEASE_PROMPT_VERSION (repository variable): prompt/template version label for traceability
    • RELEASE_DRAFT_TIME_UTC (repository variable): target UTC time in HH:MM:SSZ, default 14:00:00Z
    • RELEASE_DRAFT_PLATFORM (repository variable): legacy single-platform fallback if RELEASE_SOCIAL_CHANNELS is unset
  4. Add the workflow below to .github/workflows/release-draft.yml in your repo

If you skip AP_SOCIAL_CONNECTION_ID, the packet is still created. Any generated social drafts stay unbound so someone can choose the target connection during review.

This repo uses the same pattern in .github/workflows/release-dogfood-draft.yml:

name: Release Draft to Agenda Panda
on:
release:
types: [published]
workflow_dispatch:
inputs:
release_kind:
description: 'Release kind'
type: choice
options:
- cli
- website
required: true
release_version:
description: 'Version label to include (for example 1.2.3)'
required: true
release_name:
description: 'Optional release title override'
required: false
release_notes:
description: 'Optional release notes or highlights override'
required: false
release_url:
description: 'Optional release URL override'
required: false
schedule_days_ahead:
description: 'How many days ahead to schedule (0 = same day, 1 = next day)'
required: false
default: '1'
jobs:
create-draft:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'cli-v') || startsWith(github.event.release.tag_name, 'web-v') || startsWith(github.event.release.tag_name, 'website-v') }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Resolve release metadata
id: release
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "kind=${{ inputs.release_kind }}" >> "$GITHUB_OUTPUT"
echo "version=${{ inputs.release_version }}" >> "$GITHUB_OUTPUT"
echo "name=${{ inputs.release_name }}" >> "$GITHUB_OUTPUT"
echo "notes<<EOF" >> "$GITHUB_OUTPUT"
echo "${{ inputs.release_notes }}" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "url=${{ inputs.release_url }}" >> "$GITHUB_OUTPUT"
echo "tag=" >> "$GITHUB_OUTPUT"
echo "days=${{ inputs.schedule_days_ahead }}" >> "$GITHUB_OUTPUT"
exit 0
fi
TAG="${{ github.event.release.tag_name }}"
NAME="${{ github.event.release.name }}"
NOTES="${{ github.event.release.body }}"
URL="${{ github.event.release.html_url }}"
if [[ "$TAG" == cli-v* ]]; then
KIND="cli"
VERSION="${TAG#cli-v}"
elif [[ "$TAG" == web-v* ]]; then
KIND="website"
VERSION="${TAG#web-v}"
elif [[ "$TAG" == website-v* ]]; then
KIND="website"
VERSION="${TAG#website-v}"
else
echo "Unsupported release tag: $TAG"
exit 1
fi
echo "kind=$KIND" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "name=$NAME" >> "$GITHUB_OUTPUT"
echo "notes<<EOF" >> "$GITHUB_OUTPUT"
echo "$NOTES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "url=$URL" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "days=1" >> "$GITHUB_OUTPUT"
- name: Create release packet in Agenda Panda
env:
AP_API_URL: ${{ vars.AP_API_URL }}
AP_API_KEY: ${{ secrets.AP_API_KEY }}
AP_PROJECT_ID: ${{ secrets.AP_PROJECT_ID }}
AP_SOCIAL_CONNECTION_ID: ${{ secrets.AP_SOCIAL_CONNECTION_ID }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_MODEL: ${{ vars.OPENAI_MODEL }}
RELEASE_KIND: ${{ steps.release.outputs.kind }}
RELEASE_VERSION: ${{ steps.release.outputs.version }}
RELEASE_NAME: ${{ steps.release.outputs.name }}
RELEASE_NOTES: ${{ steps.release.outputs.notes }}
RELEASE_URL: ${{ steps.release.outputs.url }}
RELEASE_TAG: ${{ steps.release.outputs.tag }}
RELEASE_DOC_PATHS: ${{ vars.RELEASE_DOC_PATHS }}
RELEASE_SOCIAL_CHANNELS: ${{ vars.RELEASE_SOCIAL_CHANNELS }}
RELEASE_PROMPT_VERSION: ${{ vars.RELEASE_PROMPT_VERSION }}
SCHEDULE_DAYS_AHEAD: ${{ steps.release.outputs.days }}
SCHEDULE_TIME_UTC: ${{ vars.RELEASE_DRAFT_TIME_UTC }}
POST_PLATFORM: ${{ vars.RELEASE_DRAFT_PLATFORM }}
POST_SOURCE: github_release_intelligence
run: node scripts/create-release-packet.mjs
  • release_kind: use cli or website for manual runs
  • release_version: the version label that appears in the draft copy
  • release_name, release_notes, and release_url: optional overrides for the generated release packet
  • schedule_days_ahead: 0 for same-day drafts, 1 for next-day drafts, default 1
  • RELEASE_SOCIAL_CHANNELS: preferred way to generate multiple social drafts, such as linkedin,x
  • RELEASE_DRAFT_TIME_UTC: GitHub repository variable for the target UTC publish time
  • RELEASE_DRAFT_PLATFORM: single-platform fallback for older setups
  • RELEASE_DOC_PATHS: repo files that provide product and positioning context to the packet generator

If you run the helper script directly outside GitHub Actions, it also accepts SCHEDULE_TIME_UTC and POST_PLATFORM as equivalent environment variables.

  • The workflow creates a release packet in Agenda Panda. It does not auto-publish.
  • Social artifacts are also synced into scheduled social drafts when possible so they can move through the existing review and publish flow.
  • Open the packet or the linked drafts in Agenda Panda, confirm the copy and target connection, then publish when ready.