ConnectMyApps Canvas for VS Code
Build, debug, and manage ConnectMyApps Canvas workflows locally using VS Code's full development environment. This extension provides a headless iPaaS experience — leveraging Canvas's cloud infrastructure while giving you local editing, debugging, diffing, and API testing tools.
Compatible with VS Code and forks such as Cursor and Kiro.
Features
- Download workflows and edit block code locally with full IntelliSense
- Debug workflows block-by-block or end-to-end in VS Code's debugger
- Push code and configuration changes back to Canvas
- Compare local code against Canvas using the native diff editor
- Test application connector APIs without managing workflows
- Read and write workflow and account vaults directly, and import vault CSV exports
- Write local one-off scripts against real account apps, with an optional linked workflow vault
- Load run results and webhook data from Canvas for local inspection
- Search across workflow data (outputs, logs, sessions)
- Scaffold AI coding assistant instructions for your preferred tool (Copilot, Cursor, Claude Code, etc.)
Prerequisites
Node.js 22.14.0 or higher is required for debugging and running block scripts.
node -v
If you need to install or upgrade, download the latest version from nodejs.org.
Installation
Install ConnectMyApps from the VS Code Marketplace:
- Open the Extensions view (
Ctrl+Shift+X)
- Search for "ConnectMyApps"
- Click Install
Alternatively, install from a .vsix file: Extensions menu > ... > "Install from VSIX".
Getting Started
- Log in — Open the command palette (
Ctrl+Shift+P) and run cma: Log In. Enter your Canvas consumer key and secret key. Credentials are stored securely in your OS keychain.
- Initialize workspace — Run
cma: Init Workspace. Choose a folder (recommended: inside your user home directory to avoid permission issues). This creates the workspace structure, config files, and package.json.
- Install dependencies — Open a terminal in your workspace root and run:
npm install
- Download a workflow — Run
cma: Get Workflow, select an account and workflow. Local files are created for all blocks.
- Debug — Open a block
.mjs file and press F5 to launch the VS Code debugger.
Workspace Structure
After initialization your workspace contains:
workspace/
workflows/ — Workflows downloaded from Canvas accounts
scripts/ — Local one-off scripts (scripts/<account>/<name>/), formerly blocks/
requests/ — REST API request/response files for app connectors
proxy_modules/ — Runtime modules that emulate Canvas functions locally (do not edit)
.vault-audit/ — Local log of vault writes made from this workspace (gitignored)
package.json — Dependencies managed by the extension
.workspace-config.json — Configuration (see below)
.gitignore — Pre-configured ignore patterns
Workspaces created before v1.9.0 have a blocks/ folder. Init Workspace (and the update check after an extension update) renames it to scripts/ automatically; blocks/ and templates/ are reserved for future template management.
The package.json includes managed dependencies required for local execution: @cma/prism, @cma/util, axios, date-fns, jose, underscore, utf8, uuid, and xml-js. You can add your own dependencies — the extension will never remove them.
Commands
All commands are prefixed with cma: in the command palette (Ctrl+Shift+P / Cmd+Shift+P).
Setup & Authentication
| Command |
Description |
cma: Init Workspace |
Creates or upgrades the workspace. Safe to re-run: updates proxy modules, config, and dependencies without overwriting your code. Prompts for AI agent tool setup on first run. |
cma: Log In |
Authenticates with Canvas using your consumer key and secret key. |
cma: Log Out |
Removes stored credentials from the OS keychain. Does not delete workspace files. |
cma: Set Port Number |
Sets the port for the local credentials bridge server. Run Init Workspace after changing. |
cma: Help |
Opens this README in a read-only editor. |
Workflows
| Command |
Description |
cma: Get Workflow |
Downloads a workflow from Canvas. Select account and workflow from a picker. |
cma: Get Workflow (This Account) |
Same as above but auto-detects the account from the current file's path. |
cma: Get Workflows by Tag |
Searches Canvas for workflows with a tag, then offers the normal download picker. |
cma: Refresh Workflow |
Re-downloads the current workflow without account/workflow selection. Uses ID-based matching to handle renames. |
cma: Run Workflow |
Runs all or selected blocks in sequence locally. Right-click a manifest.json to access. |
cma: Cancel Workflow |
Stops the currently running local workflow execution. |
cma: Deploy Workflow |
Deploys an in-development workflow to Canvas (requires workflowState: "inDevelopment" in manifest). |
cma: Clear Workflows |
Deletes all files from the workflows folder. |
Pushing Changes to Canvas
| Command |
Description |
cma: Push Block Code |
Pushes the current block's user code to Canvas. Only code within the user-code markers is sent. Mapper blocks are rejected. |
cma: Push Block Config |
Pushes block metadata (name, variables, input links) to Canvas without affecting code. |
cma: Push Workflow Code |
Pushes code for all or selected blocks in a workflow to Canvas in one operation. |
cma: Push Workflow Config |
Pushes workflow metadata (name, description, workflow-level variables) to Canvas. |
Comparing with Canvas
| Command |
Description |
cma: Compare Block with Canvas |
Opens a diff view comparing local block code against the Canvas version. |
cma: Compare Workflow with Canvas |
Compares all blocks in a workflow, shows a status summary, and can open all diffs at once. |
cma: Compare Canvas Workflow at Run |
Compares the Canvas configuration at a run number with the current Canvas configuration in a read-only diff. |
cma: Add Workflow Tag and cma: Remove Workflow Tag change tags on the live
Canvas workflow after confirming the account, workflow, and exact tag. Tags are
case-sensitive. If Canvas does not return a list of tags on the workflow, enter
the exact value to remove; Canvas does not report an error for a missing tag.
These commands do not manage tags on accounts, applications, or templates.
Blocks
| Command |
Description |
cma: Set Block Inputs |
Configure which preceding blocks feed into the current block's Datasource. |
cma: Copy My Code |
Copies user code from the current block to the clipboard, ready to paste into Canvas. |
Scripts
| Command |
Description |
cma: New Script |
Creates a local one-off script for an account (pick apps, a name and optionally a workflow vault). Replaces cma: New Block. |
cma: Configure Script Apps |
Adds/removes registered apps in the active script's meta/credentials.json without creating another script. Only one registration per appCode is allowed. |
cma: Link Script to Workflow Vault |
Links the active script to a workflow vault, or unlinks it (global vault only). |
cma: Clear Scripts |
Deletes all scripts from the workspace. Replaces cma: Clear Blocks. |
Vault
| Command |
Description |
cma: Vault: Get Value |
Shows a vault value in a read-only editor. Tells "key not found" apart from "key exists without a value". |
cma: Vault: Set Value |
Stores a value after a confirmation that shows the current and new value. |
cma: Vault: Remove Key |
Removes a key after a confirmation. |
cma: Vault: Check Key Exists |
Checks whether a key exists. |
cma: Vault: Import from CSV |
Imports a DevOps vault export into one workflow or global vault. |
Requests (API Testing)
| Command |
Description |
Shortcut |
cma: New Request |
Creates a new API request file for an application connector. |
|
cma: Execute Request |
Runs the current request file against the application API. |
Ctrl+Enter |
cma: Duplicate Request |
Creates a copy of the current request file. |
Ctrl+Alt+D |
cma: Clear Requests |
Deletes all files from the requests folder. |
|
Email and Secure Share
cma: Send Email or Secure Share asks for recipient email addresses, a subject,
a single-line plain-text message, and optional local files. It sends using your
signed-in Canvas profile; you do not need to select an account.
For a longer or multi-line message, load a UTF-8 text file instead. Separate
multiple recipients with commas or semicolons. cma: Send Email or Secure Share (This Account) addresses the account of the active workflow,
script, or request file. If no account can be detected, enter recipients manually.
Each secure-share upload gets a random six-digit code unless the email module
supplies one explicitly. Canvas includes the code in the notification email,
so it is not a separately delivered authentication factor. When files and
multiple recipients are selected, choose either separate secure shares (one
upload per recipient) or one shared secure share. For a shared
share, the first recipient is addressed directly and the rest are passed as a
comma-separated CC list, as in the existing email proxy module. Recipients can
see one another. The API documentation describes a CC address but does not
confirm multi-address CC support; the upload API does not confirm individual
delivery.
The message is included as a note in the notification email. Without files,
the command sends a regular email, not a secure share. The command shows the
recipients and filenames for confirmation before sending.
If some requests cannot be confirmed, check before retrying: a request may have
succeeded even if its response was lost.
Webhooks
| Command |
Description |
cma: Browse Webhooks |
Opens a picker to select from available webhooks for the current workflow. |
cma: Fetch Webhook by ID or Number |
Fetches a specific webhook by its ID or run number. |
cma: Fetch Last Processed Webhook |
Fetches the most recently processed webhook for the current workflow. |
cma: Refresh Pinned Webhook |
Re-fetches the pinned webhook data and updates the local webhook.json. |
Run Results & History
| Command |
Description |
cma: Load Last Run Result (All Blocks) |
Fetches the latest run result for all blocks from Canvas. |
cma: Load Last Run Result (This Block) |
Fetches the latest run result for the current block only. |
cma: Load Run Result by Number (All Blocks) |
Fetches a specific run result by number for all blocks. |
cma: Load Run Result by Number (This Block) |
Fetches a specific run result by number for the current block. |
cma: Save Run to History |
Archives a workflow run result to local history. |
cma: Save Block Run to History |
Archives a single block's run result to local history. |
cma: Save Run Range to History |
Archives a range of run results to local history (max 50 runs). |
cma: Browse Canvas Run History |
Browse and filter paged Canvas run records, then load or save a selected run. |
cma: Search Canvas Run History |
Create a server-side content search across selected blocks, outputs, logs, errors, webhooks and sessions. |
cma: Manage Canvas Run Searches |
Reopen, cancel, or delete Canvas search tasks, or clear all tasks for a workflow. |
The Canvas Run History Explorer view shows the selected workflow's run
records, search progress, and grouped match counts. Its toolbar refreshes or
filters the list and opens search-task management. Click a run for details,
result download, local-history storage, or a historical configuration diff.
Download actions can overwrite the selected local output/history files and ask
for confirmation. Opening a workflow from the local workspace, or selecting an
already-downloaded workflow, supplies the account and workflow context.
For a completed content search, choose Save matching runs to history… in
the view. The extension collects every matching page using the current view
filters, then saves only those runs under history/run-<number>/. Choose all
blocks or specific blocks, and either skip existing run folders or overwrite
their matching files. The download is cancellable and stops after approximately
1 GB; incomplete runs are reported so they can be retried. Results are fetched
using the current local manifest and the workspace's run-result settings.
Search terms and tasks are stored on Canvas. Creating, cancelling, and
deleting tasks requires confirmation; clearing all tasks can affect other users.
Hiding the view stops local progress polling but does not cancel or delete the
server task. The server reports matching runs and grouped counts, not exact
matching lines. cma: Search Workflow Data is separate: it searches downloaded
local files and supports regular expressions.
Canvas content searches require a non-empty text term; saving search matches
does not itself test whether a block ran or its response was non-empty.
Right-click a file and open Canvas for actions relevant to that file:
workflow block actions and block results in block files; workflow, run-history,
webhook and tag actions within workflows; script and vault actions within
scripts; request actions on request files; and workspace tools on root files and
proxy modules. Deploy Workflow remains available from the command palette.
Search & Utilities
| Command |
Description |
cma: Search Workflow Data |
Searches across workflow outputs, logs, and sessions. Results appear in the Explorer sidebar. |
cma: Update FX Functions |
Re-fetches all fx functions from Canvas and regenerates the local fx.js. |
cma: Pin/Unpin Account |
Toggles pinned state for an account (pinned accounts appear first in pickers). |
cma: Configure AI Agent Tools |
Scaffolds instructions and type definitions for AI coding assistants. |
cma: Restore Config Defaults |
Resets .workspace-config.json to defaults (preserves initialized timestamp). |
Workspace Configuration
The .workspace-config.json file in your workspace root controls extension behavior. It is created automatically during initialization and can be edited manually.
{
"version": "1.3.1",
"initialized": "2026-07-01T10:00:00.000Z",
"request": {
"defaultNamingMode": "smart",
"defaultBaseUrl": "https://canvas.connectmyapps.com/api/ApiSend",
"defaultResponseCodes": [200, 201, 404],
"requestBodyOverride": {},
"smartNaming": {
"maxPathLength": 20,
"preserveNumericIds": true
},
"archiveOrphanedFiles": true
},
"runtime": {
"outputCleanup": "canvas",
"sessionCleanup": "canvas",
"updateLocalDateLastRun": true,
"runResults": {
"onWorkflowGet": "prompt",
"includeOutput": true,
"includeLog": true,
"includeSession": true,
"archiveOnCleanup": true
}
},
"diff": {
"viewMode": "active"
},
"vault": {
"importConcurrency": 4
}
}
Request Settings
| Setting |
Description |
Default |
request.defaultNamingMode |
Naming mode for new requests: single, new, or smart |
smart |
request.defaultBaseUrl |
Base URL for API requests |
Canvas API URL |
request.defaultResponseCodes |
Accepted HTTP response codes |
[200, 201, 404] |
request.requestBodyOverride |
Override default request body properties |
{} |
request.smartNaming.maxPathLength |
Maximum characters for URL path in filenames |
20 |
request.smartNaming.preserveNumericIds |
Keep numeric IDs in path or replace with "id" |
true |
request.archiveOrphanedFiles |
Archive orphaned responses (true) or delete them (false) |
true |
Runtime Settings
| Setting |
Description |
Default |
runtime.outputCleanup |
How to handle output files: canvas, none, or all |
canvas |
runtime.sessionCleanup |
How to handle session files: canvas, none, or all |
canvas |
runtime.updateLocalDateLastRun |
Whether local runs update dateLastRun in the workflow's local manifest.json (see dateLastRun). Set to false to keep the value from the last pull. |
true |
runtime.runResults.onWorkflowGet |
Fetch run results on Get Workflow: none, prompt, or all |
prompt |
runtime.runResults.includeOutput |
Include block output in fetched results |
true |
runtime.runResults.includeLog |
Include block logs in fetched results |
true |
runtime.runResults.includeSession |
Include session data in fetched results |
true |
runtime.runResults.archiveOnCleanup |
Archive results before cleanup vs delete |
true |
Diff Settings
| Setting |
Description |
Default |
diff.viewMode |
Where diff tabs open: active (current group) or split (side-by-side group) |
active |
Vault Settings
| Setting |
Description |
Default |
vault.importConcurrency |
Parallel requests during cma: Vault: Import from CSV (and the CLI vault import) |
4 |
Other Settings
| Setting |
Description |
canvasApiBaseUrl |
Optional override to point at a different Canvas environment (e.g. test server) |
aiAgents |
Managed by the Configure AI Agent Tools command. Do not edit manually. |
Smart Request Naming
When using "resultsPage": "smart" in request files, the extension generates descriptive filenames based on request content.
{APP}_{verb}_{urlPath}_{hash}_req.json
{APP}_{verb}_{urlPath}_{hash}_res.json
Examples:
QUIN_get_employees_a1b2_req.json
MYST_post_orders_c3d4_res.json
FTP_get_files_documents_e5f6_req.json
How It Works
- On execute: The extension generates a filename from the request content (verb, URL path). If it differs from the current filename, the request file is renamed and any orphaned responses are archived.
- Duplicate detection: If the generated filename matches an existing file, the existing file is replaced and your editor tab stays open with the renamed file.
- Archiving: Orphaned responses are combined with their originating request into an
archive/ subfolder as a single { request, response } JSON file. A hidden archive/.pending/ record captures the request at execution time so pairing is always correct. Set archiveOrphanedFiles: false to delete instead.
URL Path Truncation
Long URL paths are intelligently truncated to fit within maxPathLength:
- First and last path segments are prioritized
- Middle segments are removed if needed
- Numeric IDs can be preserved or replaced with "id" based on settings
Important Concepts
dateLastRun
The dateLastRun variable represents the timestamp of the last successful workflow execution.
Local behavior:
- Loaded from the workflow's
manifest.json into the global dateLastRun variable when blocks execute, enabling incremental sync patterns. Get/Refresh Workflow sets it to the Canvas value at the time of the pull.
- A local run "completes" when the last block finishes, or when a block calls
fx.stopAfterThisBlock(true). By default this updates dateLastRun in the local manifest.json to the run's time, like a completed Canvas run.
- Set
runtime.updateLocalDateLastRun to false in .workspace-config.json to keep the value from the last pull (or your manual edit), so you can re-run the same delta window. The setting covers both triggers: with false, neither the last block nor fx.stopAfterThisBlock(true) writes dateLastRun; with true, both do.
fx.stopAfterThisBlock() / fx.stopAfterThisBlock(false) stops the run without advancing dateLastRun.
- You can manually edit the value in
manifest.json for testing.
- Local changes to
manifest.json never reach the Canvas server's dateLastRun.
Canvas sync (optional):
- By default, local runs do NOT update
dateLastRun on Canvas (prevents local debugging from affecting production).
- Set
"syncDateLastRun": true in manifest.json to set the Canvas dateLastRun to the current time after each completed local run (same two triggers). This is independent of runtime.updateLocalDateLastRun: it syncs even when the local value is not updated.
Local Webhook Testing
Webhook batch behavior is configured locally in a workflow's manifest.json and does not change Canvas settings:
{
"isBatch": true,
"batchSize": 5,
"archiveProcessedWebhooks": true
}
isBatch defaults to false when Canvas settings are unavailable. When available, the downloaded Canvas batch settings initialize isBatch and batchSize; later manual edits are preserved on refresh.
batchSize defaults to 1. Use cma: Configure Local Webhook Batch to edit these values, or edit the manifest directly.
cma: Load Webhook Batch downloads up to batchSize payloads from the Canvas queue, history, or sandbox. Queue/history downloads paginate automatically and are stored in deterministic order under webhooks/batch/.
- In batch mode, blocks receive the selected payloads as
webhooks, and webhook is the first selected value (webhooks[0]). Singular mode continues to read webhooks/webhook.json directly.
- With
archiveProcessedWebhooks: true, successful local workflow completion moves consumed queue/history batch files to webhooks/history/, simulating Canvas queue consumption without altering remote data. Sandbox snapshots remain pinned across runs.
- Saving a remote workflow run to
history/run-{number}/ also downloads its matching webhook-history payload when the run was webhook-triggered. The payload is saved as webhook.json with webhook-meta.json beside the block artifacts.
Vault
myVault is a key-value store per workflow (get, set, contains, remove, setOnComplete) and per account (the *Global variants). The vault commands read and write it directly, so you don't need to add a block to a production workflow and run it.
Everything is live. Local runs, the vault commands and the CLI all read and write the real Canvas vault. Set and Remove always show the account, vault, key, current value and new value in a confirmation first.
Which vault a command uses is worked out from the active file every time; nothing is remembered between commands:
| Active file |
Vault |
| Inside a downloaded workflow |
That workflow's vault |
| Inside a script linked to a workflow vault |
The linked workflow vault |
| Inside an unlinked script |
The account's global vault |
An account folder (workflows/<email>/, scripts/<email>/, requests/<email>/) |
You pick the vault for that account |
| Anything else |
You pick the account, then the vault |
The prompt title always names the vault, and title-bar buttons switch between the workflow and global vault or choose another one.
Values: type JSON (123 is a number, "123" with quotes is text, {"a":1} an object); anything that isn't valid JSON is stored as text. Values keep their exact type. null, undefined and '' never blank a value: Canvas keeps an existing value (and set returns false), and a missing key is created without a value (contains is true, get is null). The commands reject empty values for that reason; to blank a value store {}, [] or a marker value, or remove the key.
Key suggestions in the key prompt are only typing aids: keys recently used from this workspace and string keys referenced in local code. There is no way to list a vault's keys (the platform has no list endpoint).
Audit log: every write made from this workspace (extension or CLI) is appended to .vault-audit/audit.jsonl, including the previous value. The log only covers operations performed from this workspace and does not reflect vault contents: production flows write to vaults all the time. It is gitignored because it may contain vault values.
CSV import (cma: Vault: Import from CSV, canvas-cli vault import) imports a DevOps vault export ("Id","Tag","Value") into one vault, for example when migrating a flow:
- Copy values from source vault (exact), the default when the source vault still exists: the CSV only supplies the key list, and every value and type is read from the source.
- Use CSV values when the source is gone. Exports unwrap one JSON layer, so a cell like
123 or true can be a typed value or text; you choose per kind (numbers, booleans, objects, arrays), optionally after checking a sample against the source.
- Raw export (exact) when every cell is the stored JSON text.
- Empty cells create missing keys without a value; they never blank an existing value. You can also import only keys that don't exist yet.
- You confirm by typing the target name. Imports show progress, can be cancelled and resumed, failed rows can be retried, and each run is logged in
.vault-audit/imports/ (without values).
Scripts
Scripts (scripts/<account>/<name>/, created with cma: New Script) are local one-off .mjs files for testing, probing, reporting, data fixes and vault maintenance against an account's real apps. They are not workflow blocks and are never pushed.
- Globals:
api, fx, logger, myVault, email, Datasource, dateFNS, utf8, xmlJS, jose, uuid, prism, util. Workflow-only globals (getVariables, getWorkflowVariables, session, webhook(s), dateLastRun) are not available; hardcode configuration or read it from input/.
input/ → Datasource: every file in the script's input/ folder (alphabetical, no dotfiles) becomes one Datasource entry; .json files are parsed, other files are passed as text.
- Vault linking:
myVault.*Global uses the account's global vault. get/set/contains/remove/setOnComplete use the workflow vault linked in the script's manifest.json (choose one when creating the script, or run cma: Link Script to Workflow Vault). Without a link they throw an error that explains this. Each run starts by logging which vaults it uses.
setOnComplete writes are saved when the script finishes without an error. Scripts don't write run history, session.json or dateLastRun, and fx.stopAfterThisBlock has no effect.
- The script's return value is written to
output/output.json, and logs to output/logger.json.
Renaming Blocks and Workflows
Edit names directly in manifest.json:
- Block name: Edit the
name property of the block in the blocks array.
- Workflow name: Edit the
name property at the root level.
When you push code or config, updated names are sent to Canvas and local folders are automatically renamed (sanitized for filesystem-safe characters).
Changing Block Order
Add or reorder blocks in the Canvas web UI, then use cma: Get Workflow to re-download. Local block order changes are not synced.
Known Limitations
Workflows
- Schedule management: No commands for changing or toggling a workflow's schedule. Use the Canvas web UI.
Workflow and Block Templates (Workbench)
- Workflow and block templates cannot be fetched or updated via the extension. Only registered (deployed) workflows are accessible.
- Pushing code to a block created from a workbench template will mark it as "customized" and it will no longer receive template updates.
Functions (fx)
- Functions cannot be created or modified through the extension. Use
cma: Update FX Functions to pull the latest function definitions from Canvas into your local fx.js.
Webhooks
- The extension cannot actively listen for incoming webhooks — they must be fetched manually.
- Local webhook archiving never moves remote Canvas queue items to history.
Feedback
Send feedback and feature requests to support@connectmyapps.com.