npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@camunda/app-integration-cli

v2.0.0

Published

CLI tool for building Camunda app integrations for Microsoft Teams and Slack

Readme

@camunda/app-integration-cli

CLI tool for building and deploying Camunda app integrations for chat platforms.

c8-teams scaffolds a new Microsoft Teams application project, builds the deployable package from templates, provisions it to your Microsoft 365 tenant via the M365 Agents Toolkit, and outputs the configuration snippet needed by the App Integrations backend.

c8-slack does the same for Slack: it renders a Slack app manifest, publishes it through the Slack app-configuration API, installs it into your workspace and hands you the two credentials the backend needs.

Both binaries share one project directory, one configuration section and one set of commands.

Upgrading from @camunda/teams-app-integration-cli (v1)? See Migrating from v1. Nothing is required of you beyond installing this package — the first command you run migrates the project.

Prerequisites

  • Node.js ≥ 20.0.0
  • For Teams: a Microsoft 365 tenant with access for app provisioning
  • For Slack: a Slack workspace you can install apps into, and a backend reachable from the internet over HTTPS (Slack calls it directly; there is no Socket Mode)

Installation

npm install -g @camunda/app-integration-cli

Or use it as a project-local dependency:

npm install @camunda/app-integration-cli

Quick Start

# 1. Scaffold a new project
c8-teams create my-teams-app

# 2. Install dependencies
cd my-teams-app
npm install

# 3. Build the deployable package
npm run build

# 4. Deploy to your Microsoft 365 tenant
npm run deploy

Commands

c8-teams create [DIRECTORY]

Scaffolds a new Camunda Teams application project via an interactive wizard.

The wizard will prompt you for:

  • Project directory and package name
  • App Integrations backend URL — shared by every integration, so it is only asked once per project
  • Application short name and full name (displayed in Teams)
  • User registration URL (optional)
  • Teams app configuration — create a new one or provide existing IDs
  • Entra (Azure AD) app configuration — create a new one or provide existing IDs

The result is a directory containing a package.json with a c8-appint configuration section, default app icon assets under assets/teams/, and a .gitignore.

Run in a directory that is already an app-integration project, create adds the integration to it rather than overwriting it, reusing the backend URL already on file. If that project was made by an older version of the CLI, it is brought up to date first and you are told what changed — the update is never silent.

c8-teams create
c8-teams create my-teams-app

c8-slack create [DIRECTORY]

Scaffolds a new Camunda Slack application project via an interactive wizard.

The wizard prompts for the project directory, package name and App Integrations backend URL as above, then for the fields that end up in the Slack app manifest:

| Question | Default | Limit | | ----------------- | --------------------------------------- | -------------------------------------- | | App name | Camunda | 35 characters | | Bot display name | the app name | 80 characters | | Short description | Your perfect integration with Camunda | 140 characters | | Background colour | #000000 | 3- or 6-digit hex | | Slash command | /camunda | 32 characters, leading /, no spaces | | Slack app | create a new one | or provide an existing app and team ID |

Accepting every default reproduces the app Camunda ships in SaaS.

Slack's four request URLs (events, slash command, interactivity, options load) are not asked for: they are all <backend URL>/api/slack/events and are derived from the backend URL you already gave. Slack only calls https URLs, so a plain-http backend is rejected.

c8-slack create
c8-slack create my-slack-app

c8-slack build

Renders the Slack app manifest from the project's configuration.

Reads and validates the c8-appint.slack section, then writes artifacts/slack/manifest.yaml (paste this into the Slack UI), artifacts/slack/manifest.json (what the Slack API wants) and a copy of assets/slack/icon.png. The JSON is a re-serialisation of the YAML, so the two can never disagree.

Only the app name, bot display name, description, background colour, slash command and the derived request URL come from your configuration. Scopes, bot events, the agent-view prompts and the settings flags are fixed — they are a contract with the App Integrations backend, and changing them produces an app that installs but does not work.

After a successful build you will be prompted to deploy immediately.

| Option | Description | | ----------------- | -------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) |

c8-slack build
c8-slack build -p ./my-slack-app

c8-slack deploy

Publishes the app to Slack: creates it from the built manifest (or updates it, if this project has been deployed before), installs it into the workspace, uploads the icon, writes the Slack-issued app and workspace IDs back into package.json, and stores the credentials Slack issued.

Deploying needs an app configuration token, which is a short-lived (12 hour) personal credential. It is never written to package.json. The command looks for one in this order:

  1. --token
  2. the SLACK_CONFIG_TOKEN environment variable
  3. signing in to Slack — the command prints a /slackauthticket … slash command, you paste it into any Slack conversation, approve the modal and paste the code back. This needs no admin rights.
  4. slack auth token, if the Slack CLI happens to be installed
  5. pasting a token generated at api.slack.com/appsYour App Configuration Tokens

Option 3 requires a workspace that is eligible for Slack's next-generation platform. Free and scratch workspaces are not, and Slack only says so in the reply to the slash command — leave the code prompt empty and the command falls through to option 5.

One project publishes to exactly one workspace. If the token belongs to a different workspace than the one recorded in package.json, the command stops rather than creating a duplicate app somewhere else.

| Option | Description | | ----------------- | -------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) | | --token TOKEN | App configuration token (or set SLACK_CONFIG_TOKEN) |

c8-slack deploy
c8-slack deploy --token xoxe.xoxp-…
SLACK_CONFIG_TOKEN=xoxe.xoxp-… c8-slack deploy

Note: You must run c8-slack build before deploying.

If your workspace requires an admin to approve new apps, the app is still created and its ID and signing secret are saved — get it approved, then run c8-slack deploy again to finish the install. The credential store is merged rather than rewritten, so a deploy that fails half-way never erases a bot token an earlier one obtained.

If c8-slack deploy fails on the call that creates the app, the app may still exist in Slack. The command says so rather than retrying, because a second attempt would publish a second app whose signing secret can never be reissued — check api.slack.com/apps and, if the app is there, put its ID in c8-appint.slack.slack.appId before re-running.

c8-slack show-config

Prints the slack: block for your App Integrations backend configuration plus the two secrets to mount as environment variables, SLACK_BOT_TOKEN and SLACK_BOT_SIGNING_SECRET.

The values are read back from the encrypted store deploy wrote. If that file is gone, the block is printed with ${{ }} placeholders and a pointer at where to find the values by hand.

Secret values are only printed when the output is a terminal. When it is redirected — a CI job log, a pipe, a file — the names and the rest of the configuration are still printed, but each value is withheld; re-run the command interactively to read it.

| Option | Description | | ----------------- | -------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) |

c8-slack show-config

c8-teams build

Builds the deployable package from the project's template files and configuration.

Reads the c8-appint section from package.json, validates it against the config schema, renders the M365 Agents Toolkit manifest templates (Teams manifest, AAD manifest, agent config), copies the icons from assets/teams/, and writes everything to artifacts/teams/.

After a successful build you will be prompted to deploy immediately.

| Option | Description | | ----------------- | -------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) |

c8-teams build
c8-teams build -p ./my-teams-app

c8-teams deploy

Deploys the built package to your Microsoft 365 tenant.

Runs atk provision --env prod inside artifacts/teams/ using the M365 Agents Toolkit CLI bundled with this package (no global installation required). After provisioning, the command writes the resulting Teams and Entra IDs back into package.json and prints the backend configuration snippet.

| Option | Description | | ----------------- | -------------------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) | | --auth | Authenticate with M365 before deploying (runs atk auth login m365) |

c8-teams deploy
c8-teams deploy --auth
c8-teams deploy -p ./my-teams-app

Note: You must run c8-teams build before deploying. The deploy command expects artifacts/teams/ to exist.

c8-teams show-config

Displays the YAML configuration snippet to add to your App Integrations backend, along with the client secret that must be mounted as the AAD_APP_CLIENT_SECRET environment variable.

As with c8-slack show-config, the secret value is only printed when the output is a terminal.

| Option | Description | | ----------------- | -------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) |

c8-teams show-config
c8-teams show-config -p ./my-teams-app

c8-teams migrate

Brings package.json up to the current configuration version. Every other command does this automatically on load; this command exists so you can inspect the change first or run it in CI.

A migration copies the project to .backup/<timestamp>/ before it writes anything. --dry-run writes nothing at all, backup included.

| Option | Description | | ----------------- | -------------------------------------------------------- | | -p, --path PATH | Root path of the project (defaults to current directory) | | --dry-run | Print what would change without writing anything |

c8-teams migrate --dry-run
c8-teams migrate

Global Options

| Option | Description | | --------------- | ------------------------------------------------------------------------------------ | | -h, --help | Show help. Use with a command (e.g. c8-teams deploy -h) for command-specific help. | | -v, --version | Show the CLI version number |

Project Structure

One directory can carry both integrations. Everything you edit lives under assets/, everything generated lives under artifacts/, split by integration:

my-app/
├── assets/                     # committed — replace these with your own icons
│   ├── teams/
│   │   ├── color.png           # App icon (colour version)
│   │   └── outline.png         # App icon (outline version)
│   └── slack/
│       └── icon.png            # App icon (512×512 or larger)
├── artifacts/                  # generated — gitignored as a whole
│   ├── teams/                  # written by `c8-teams build`
│   │   ├── env/
│   │   │   ├── .env.prod
│   │   │   └── .env.prod.user  # secret from `c8-teams deploy` (encrypted)
│   │   ├── aad.manifest.json
│   │   ├── m365agents.yml
│   │   ├── manifest.json
│   │   ├── color.png
│   │   └── outline.png
│   └── slack/                  # written by `c8-slack build`
│       ├── manifest.yaml       # paste this into the Slack UI
│       ├── manifest.json       # sent to the Slack API
│       ├── .env.user           # credentials from `c8-slack deploy` (encrypted)
│       └── icon.png
├── .gitignore
└── package.json                # holds the `c8-appint` configuration section

A project with one integration has only that integration's subdirectories.

Both build commands regenerate their output from package.json and assets/, so artifacts/ is disposable — with one exception. The secrets deploy writes (artifacts/teams/env/.env.prod.user, artifacts/slack/.env.user) cannot be regenerated: Microsoft and Slack issue those values once. Delete them and you have to re-provision. They are encrypted at rest, but the key is derived from your project ID, so treat the files as secrets and keep the real values in your secret manager.

The .gitignore written by create covers node_modules, artifacts and .backup. If the directory already had a .gitignore, your rules are kept underneath the managed block and stay in force.

Scripts

create adds a script pair per integration, plus an aggregate over every integration the project has:

| Script | Runs | | ----------------------------- | ------------------------------------- | | build:teams, deploy:teams | Teams only | | build:slack, deploy:slack | Slack only | | build, deploy | every configured integration, in turn |

Adding a second integration to an existing project rewrites the aggregates, so npm run build keeps meaning "build everything" rather than quietly building only the first integration. You are told when this happens. If you have edited build or deploy yourself, they are left alone and the CLI warns instead of overwriting your version.

Configuration

All configuration lives in the c8-appint section of package.json. It is populated by the create wizard and updated automatically by deploy after provisioning.

shared holds the settings every integration needs; each integration has its own block, so one project directory can carry more than one.

{
  "c8-appint": {
    "version": 2,
    "shared": {
      "endpoints": {
        "appIntegrationsBackend": "https://your-backend.example.com"
      }
    },
    "teams": {
      "app": {
        "shortName": "Camunda",
        "fullName": "Camunda",
        "projectId": "<uuid>"
      },
      "endpoints": {
        "userRegistration": "https://signup.example.com"
      },
      "teams": {
        "appId": "<uuid>",
        "tenantId": "<uuid>"
      },
      "aad": {
        "clientId": "<uuid>",
        "objectId": "<uuid>",
        "accessAsUserPermissionId": "<uuid>",
        "authorityHost": "https://login.microsoftonline.com",
        "authority": "https://login.microsoftonline.com/<tenant-id>"
      }
    }
  }
}

| Field | Required | Description | | ----------------------------------------- | -------- | ---------------------------------------------------------------- | | version | Yes | Configuration schema version, managed by the CLI | | shared.endpoints.appIntegrationsBackend | Yes | URL of your App Integrations backend | | shared.projectId | No | Generated on first deploy; keys the encrypted credential store | | teams.app.shortName | Yes | Short display name in Teams (2–30 characters) | | teams.app.fullName | Yes | Full display name in Teams (2–30 characters) | | teams.app.projectId | Yes | Auto-generated UUID identifying the project | | teams.endpoints.userRegistration | No | Optional user registration URL | | teams.teams | No | Populated after deployment with the Teams app and tenant IDs | | teams.aad | No | Populated after deployment with the Entra (Azure AD) app details |

A Slack integration adds its own block alongside teams:

{
  "c8-appint": {
    "slack": {
      "app": {
        "name": "Camunda",
        "botDisplayName": "Camunda",
        "description": "Your perfect integration with Camunda",
        "backgroundColor": "#000000"
      },
      "slack": {
        "command": "/camunda",
        "appId": "A01234ABCDE",
        "teamId": "T01234ABCDE"
      }
    }
  }
}

| Field | Required | Description | | --------------------------- | -------- | -------------------------------------------------------------------------------- | | slack.app.name | Yes | App name shown in Slack (≤ 35 characters) | | slack.app.botDisplayName | Yes | Name messages are posted under (≤ 80 characters) | | slack.app.description | Yes | Short description (≤ 140 characters) | | slack.app.backgroundColor | Yes | Hex colour shown behind the app icon | | slack.slack.command | Yes | Slash command, e.g. /camunda. Must match slack.command in the backend config | | slack.slack.appId | No | Populated once the app exists in Slack | | slack.slack.teamId | No | Workspace the app belongs to; one deployment serves exactly one workspace |

Migrating from v1

Projects created by @camunda/[email protected] use a c8teams section (configuration version 1). You do not need to do anything: the first command you run from this package migrates the project in place and prints a summary of what moved.

Before anything is written — the rewritten package.json included — the project is copied to .backup/<timestamp>/, everything except node_modules. Nothing is deleted, so if the result is not what you expected, the original is still there. Once you are happy, delete .backup/.

The migration rewrites the whole package.json, not just the config section:

| v1 | v2 | | ------------------------------------------ | --------------------------------------------------- | | c8teams.app | c8-appint.teams.app | | c8teams.endpoints.appIntegrationsBackend | c8-appint.shared.endpoints.appIntegrationsBackend | | c8teams.endpoints.userRegistration | c8-appint.teams.endpoints.userRegistration | | c8teams.teams / c8teams.aad | c8-appint.teams.teams / c8-appint.teams.aad | | scripts.build = c8teams build | scripts.build = c8-teams build | | @camunda/teams-app-integration-cli | @camunda/app-integration-cli |

It also moves the project onto the layout above:

| v1 | v2 | | -------------- | -------------------- | | build/ | artifacts/teams/ | | assets/*.png | assets/teams/*.png |

The build directory is moved wholesale rather than regenerated, so env/.env.prod.user — which holds a client secret nothing can reissue — comes across with it. Files the CLI does not recognise are moved too, not dropped. A build/ that belongs to some other toolchain is left alone.

The .gitignore is replaced with the managed one and your previous rules are kept underneath it, still in force.

Keys the CLI does not recognise are carried across untouched, and running the migration twice is a no-op.

Because the dependency changes, re-run your package manager's install afterwards.

The old c8teams binary still ships, but only as a one-way on-ramp: it runs against a project still on configuration version 1 — which is exactly the case where your own scripts.build still calls it — and then errors, pointing at c8-teams. Use c8-teams from then on.

Typical Workflow

  1. c8-teams create my-app — scaffold the project and fill in your configuration.
  2. cd my-app && npm install — install dependencies (including this CLI).
  3. npm run build — build the deployable package into artifacts/teams/.
  4. npm run deploy (or c8-teams deploy --auth) — authenticate and provision the app to your M365 tenant.
  5. c8-teams show-config — copy the output YAML into your App Integrations backend configuration and set the AAD_APP_CLIENT_SECRET environment variable.
  6. After an admin approves the app in the Teams Admin Center, it becomes available to your organization.

For Slack:

  1. c8-slack create my-app — scaffold the project and fill in your configuration.
  2. cd my-app && npm install
  3. npm run build — render the manifest into artifacts/slack/.
  4. npm run deploy — sign in to Slack, publish the app, install it and collect its credentials.
  5. c8-slack show-config — copy the output into your App Integrations backend configuration, set SLACK_BOT_TOKEN and SLACK_BOT_SIGNING_SECRET, and restart the backend.
  6. Run your slash command in Slack to check. If Slack reports it cannot reach your app, open the app's Event Subscriptions page and click Verify once — the request URL can only be verified after the backend is live.

License

Apache 2.0