Getting Started
pip install canvas
Authentication
The CLI authenticates in two ways, and which one a command uses depends on where it sends the request:
| Canvas Platform sign-in | Instance API credentials | |
|---|---|---|
| Set up with | canvas login, in your browser, or a service account token in CANVAS_PLATFORM_TOKEN |
~/.canvas/credentials.ini, written by hand |
| Signs in as | you, as a member of your Canvas Platform organizations, or a service account of one organization | an OAuth client (client_id / client_secret) registered on one instance |
| Reaches | every instance your organizations can deploy to | the instance named by each section of the file |
| Stored in | ~/.canvas/platform-credentials.json, or the CANVAS_PLATFORM_TOKEN environment variable |
credentials.ini, with instance tokens cached in ~/.canvas/tokens.json |
| Used by | login, logout, init, deploy, clone, and config set / config unset / uninstall for a plugin Canvas Platform manages |
install, enable, disable, list, config list, logs, namespace, and config set / config unset / uninstall for a plugin Canvas Platform does not manage |
A machine can hold both at once, and the CLI picks per command and per plugin as described in Which plugins go through Canvas Platform.
Migrating from credentials.ini to Canvas Platform
See Upgrading to Canvas Platform.
Instance API credentials
Create a file ~/.canvas/credentials.ini and add the client_id and client_secret credentials for each of your Canvas instances. You can define your default host with is_default=true. If no default is explicitly defined, the Canvas CLI will use the first instance in the file as the default for each of the CLI commands.
Example:
[my-canvas-instance]
client_id=myclientid
client_secret=myclientsecret
[my-dev-canvas-instance]
client_id=devclientid
client_secret=devclientsecret
is_default=true
[localhost]
client_id=localclientid
client_secret=localclientsecret
Canvas Platform
Canvas Platform hosts a plugin's git repository and deploys it to the instances it manages. Sign in once per machine with canvas login, which opens your browser; the session is stored per platform in ~/.canvas/platform-credentials.json, readable only by you, and refreshes itself. canvas login --platform <url> or CANVAS_PLATFORM_URL points the CLI at a platform other than https://platform.canvasmedical.com, and later commands keep using the platform you last signed in to.
A plugin deployed through Canvas Platform has a publisher-prefixed name, <org prefix>__<package> (for example acme__intake), used for the manifest name, the package folder and its imports. canvas login lists the prefix of each organization you belong to, and the prefix decides which organization publishes the plugin. canvas install and canvas validate accept names with or without a prefix.
Which plugins go through Canvas Platform
canvas config set, canvas config unset and canvas uninstall work for plugins Canvas Platform manages and for plugins installed straight onto an instance, and each decides per plugin:
- A name without a prefix, or a machine that is not signed in, goes straight to the instance, as
canvas installalways has. - Otherwise the CLI asks platform for the plugin. If platform has it, the command goes through platform; if not, it goes to the instance.
--host names an instance for a plugin platform does not manage, and is refused for one it does. When an instance refuses canvas install because platform manages that plugin, the message names canvas deploy.
git signs in to platform's git server through canvas git-credential, a hidden command canvas deploy, canvas init and canvas clone register as the repository's credential helper. It mints a one-hour git token for the plugin named in the repository path, and the repository's configuration keeps any other credential helper, such as macOS's keychain, from answering for that server.
$ canvas login
$ canvas init # scaffolds acme__my_cool_plugin and registers it
$ canvas deploy my-cool-plugin/acme__my_cool_plugin --instance acme-staging
$ canvas config set acme__my_cool_plugin API_URL=https://api.example.com --instance acme-staging
Service accounts for CI/CD
A CI/CD pipeline (GitHub Actions, GitLab CI, and the like) signs in to Canvas Platform as a service account, an identity that belongs to an organization rather than to a person, so the pipeline keeps working when whoever set it up leaves, and Platform's audit log names the account behind each push and deploy. An organization admin, plugin developer or deploy manager creates one on the Credentials page in Canvas Platform. A service account can hold the plugin developer and deploy manager roles, and never more than its creator holds. Its token is shown once and is valid for a year.
Store the token as a CI secret and expose it to the job as CANVAS_PLATFORM_TOKEN; no canvas login is needed:
- run: pip install canvas
- run: canvas deploy my-plugin/acme__my_plugin --instance acme-staging --yes
env:
CANVAS_PLATFORM_TOKEN: ${{ secrets.CANVAS_PLATFORM_TOKEN }}
- When
CANVAS_PLATFORM_TOKENis set, every command uses it in place of acanvas loginsession, including the git pushescanvas deploymakes, and it takes precedence over a session already stored on the machine. - The token does not refresh. Rotating or revoking the service account on the Credentials page ends it, and the CLI's next request says so.
canvas logoutdoes not touch it. --yescommits uncommitted changes without prompting. A deployment that needs consent for another plugin's custom data exits non-zero and lists the requests, since only a person at a terminal answers those.CANVAS_PLATFORM_URLpoints the job at a platform other than https://platform.canvasmedical.com.
Deploying from a monorepo
A plugin inside a larger repository deploys with --snapshot, which works from any depth in that repository and leaves its origin, config and index alone:
$ canvas deploy plugins/acme__intake --snapshot --instance acme-staging
- The package folder as committed at HEAD becomes one new commit on the plugin's
mainin Canvas Platform. Files onmainbeside the package folder are kept, and an unchanged package pushes nothing. - The commit is authored as the signed-in person or service account, and carries
Monorepo-CommitandMonorepo-Pathtrailers naming its source. - Uncommitted changes in the package are refused, even with
--yes. So are submodules, symbolic links and files stored through a filter such as Git LFS or git-crypt, which would not reach an instance as their content. - Deploy refuses when HEAD lacks changes to the package that the commit
mainwas last deployed from made, which would roll the plugin back, and names the files. A branch that was deployed and then squash- or rebase-merged passes, since HEAD carries its changes. - A commit on
main's first-parent history taggedsnapshot-baseline/<anything>, as Canvas Studio tags the commit it startsmainfrom, counts as a snapshot, and deploy starts from the newest snapshot; lightweight and annotated tags both count. A tagged commit without aMonorepo-Committrailer has nothing to roll back. To mark one by hand, push the tag from acanvas clonecheckout (git tag snapshot-baseline/<sha> <sha>, thengit push origin snapshot-baseline/<sha>). - Deploy refuses when
mainhas changes to the package since the last snapshot, such as a catalog listing edited in Canvas Platform, that the snapshot would replace. At a terminal it asks before replacing them. - Deploy warns when HEAD is on no remote branch, since that code has not been through the repository's review.
- The manifest
namedecides which Platform repository a snapshot goes to, so deploys from any checkout or CI job land on the samemain. The CI job needs no git identity. - The rollback check needs the commit
mainwas last deployed from, which a shallow checkout usually lacks, so deploy skips the check there and says so on stderr. Check out full history without file contents to keep it, for examplefetch-depth: 0withfilter: blob:noneinactions/checkout.
Usage:
$ canvas [OPTIONS] COMMAND [ARGS]...
Options:
--version--help: Show this message and exit.
Commands:
login: Sign in to Canvas Platform through your browserlogout: Sign out of Canvas Platformwhoami: Show which Canvas Platform you are signed in to, and as whominit: Create a new plugindeploy: Publish a plugin to Canvas Platform and deploy itclone: Clone a plugin's repository from Canvas Platforminstall: Install a plugin into a Canvas instanceuninstall: Uninstall a pluginconfig: List, set and clear plugin variablesdisable: Disable a plugin from a Canvas instanceenable: Enable a plugin from a Canvas instancelist: List all plugins from a Canvas instancevalidate-manifest: Validate the Canvas Manifest json filelogs: Listen and print log streams from a Canvas instance
canvas login
Sign in to Canvas Platform through your browser (OAuth authorization code with PKCE). The sign-in URL is also printed, for a machine without a browser.
Usage:
$ canvas login [OPTIONS]
Options:
--platform TEXT: Canvas Platform URL--help: Show this message and exit.
canvas logout
Revoke this machine's Canvas Platform session and delete its stored tokens. A service account token in CANVAS_PLATFORM_TOKEN is left alone, and the command says that commands still act as that account.
Usage:
$ canvas logout [OPTIONS]
Options:
--platform TEXT: Canvas Platform URL--help: Show this message and exit.
canvas whoami
Show the platform the CLI uses and where that choice came from (--platform, CANVAS_PLATFORM_URL, your last canvas login, or the default), then the account it signs in as, whether the credential is a canvas login session or CANVAS_PLATFORM_TOKEN, and each organization's plugin prefix and what you can do there. It asks platform, so a revoked or expired credential is reported rather than shown as signed in. No token is printed. Exits non-zero when not signed in.
Usage:
$ canvas whoami [OPTIONS]
Options:
--platform TEXT: Canvas Platform URL--help: Show this message and exit.
canvas init
Create a new plugin. Signed in to Canvas Platform, the package is named <org prefix>__<package>, registered with platform, and given a git repository whose origin is platform. Signed out, it is named from the project name alone, and init says that canvas deploy refuses such a plugin until you run canvas login and canvas init again.
Usage:
$ canvas init [OPTIONS] [PLUGIN_TYPE]
Arguments:
PLUGIN_TYPE:handler(default) orapplication
Options:
--org TEXT: Organization that publishes the plugin, when you can publish in several--help: Show this message and exit.
canvas deploy
Publish a plugin's code to Canvas Platform and deploy it. The manifest name must be publisher-prefixed, and the package folder must have the same name, which deploy checks before committing or pushing. Deploy registers the plugin, points the repository's origin at platform with a credential helper, commits uncommitted changes after you confirm, pushes HEAD to main, deploys that commit and waits for each target's outcome. Consent requests for cross-plugin custom data access are answered inline at a terminal; under --yes or without a terminal, deploy lists them with the deployment id and exits non-zero without answering them. The repository is rooted at the directory containing the package. Without a terminal to confirm at, uncommitted changes are refused rather than committed unless --yes is passed.
Usage:
$ canvas deploy [OPTIONS] PLUGIN_DIR
Arguments:
PLUGIN_DIR: Path to the plugin package [required]
Options:
--instance TEXT: Instance to deploy to, repeatable. Without it, deploy targets the only instance you can deploy to and otherwise lists the choices--ref TEXT: Deploy a pushed branch, tag or commit as-is, without pushing--no-push: Deploy the pushedmainas-is, without pushing--push-only: Push HEAD tomainwithout deploying it to any instance, so the plugin's code and its catalog listing are updated on Canvas Platform and no instance is needed. Takes no--instance,--refor--no-push--snapshot: Push the committed contents of a plugin inside a larger repository, such as a monorepo, as one new commit onmain, leaving that repository's remotes alone. See Deploying from a monorepo. Takes no--refor--no-push-y, --yes: Commit uncommitted changes without prompting, with the default message. Does not approve consent requests: a deployment that needs consent exits non-zero and lists them--help: Show this message and exit.
canvas clone
Clone a plugin's repository from Canvas Platform with origin and the credential helper set, ready for canvas deploy.
Usage:
$ canvas clone [OPTIONS] NAME [DIRECTORY]
Arguments:
NAME: Plugin name, e.g.acme__intake[required]DIRECTORY: Where to clone it, a directory named after the plugin by default
canvas install
Install a plugin into a Canvas instance.
Usage:
$ canvas install [OPTIONS] PLUGIN_NAME
Arguments:
PLUGIN_NAME: Path to plugin to install [required]
Options:
--host TEXT: Canvas instance to connect to--help: Show this message and exit.
canvas uninstall
Uninstall a plugin. A plugin Canvas Platform manages is removed by an uninstall deployment from each --instance, which is required. Any other plugin is removed from the instance directly.
Usage:
$ canvas uninstall [OPTIONS] NAME
Arguments:
NAME: Plugin name to uninstall [required]
Options:
--instance TEXT: Instance to uninstall from, repeatable--host TEXT: Canvas instance to connect to, for a plugin Canvas Platform does not manage--force: Uninstall an enabled plugin from an instance directly--help: Show this message and exit.
canvas config set / canvas config unset
Set or clear a plugin's variable values. For a plugin Canvas Platform manages, values are stored in platform and a configure deployment brings them to the running plugin; without --instance, the only instance it is installed on that you can configure is targeted. A variable's sensitivity comes from the manifest's variables, and --secret / --variable state it for a key no revision declares. For any other plugin, values are written to the instance directly, and unset sets them empty.
Usage:
$ canvas config set [OPTIONS] PLUGIN_NAME [KEY=VALUE]...
$ canvas config unset [OPTIONS] PLUGIN_NAME KEY...
Options:
--instance TEXT: Instance to configure, repeatable--host TEXT: Canvas instance to connect to, for a plugin Canvas Platform does not manage--secret KEY=VALUE,--variable KEY=VALUE: (setonly) a sensitive or non-sensitive value for an undeclared key--help: Show this message and exit.
canvas enable
Enable a plugin from a Canvas instance..
Usage:
$ canvas enable [OPTIONS] NAME
Arguments:
NAME: Plugin name to enable [required]
Options:
--host TEXT: Canvas instance to connect to--help: Show this message and exit.
canvas disable
Disable a plugin from a Canvas instance..
Usage:
$ canvas disable [OPTIONS] NAME
Arguments:
NAME: Plugin name to disable [required]
Options:
--host TEXT: Canvas instance to connect to--help: Show this message and exit.
canvas list
List all plugins from a Canvas instance.
Usage:
$ canvas list [OPTIONS]
Options:
--host TEXT: Canvas instance to connect to--help: Show this message and exit.
canvas validate-manifest
Validate the Canvas Manifest json file.
Usage:
$ canvas validate-manifest [OPTIONS] PACKAGE
Arguments:
PLUGIN_NAME: Path to plugin to install [required]
Options:
--help: Show this message and exit.
canvas logs
Listens and prints log streams from the instance.
Usage:
$ canvas logs [OPTIONS]
Options:
--host TEXT: Canvas instance to connect to--help: Show this message and exit.
Metadata
Release files for canvas 0.263.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| canvas-0.263.0.tar.gz | 2.6 MB | With provenance | Details for canvas-0.263.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| canvas-0.263.0-py3-none-any.whl | Python 3 | none | any | Details for canvas-0.263.0-py3-none-any.whl |
Total release size: 5.5 MB
Release files / canvas-0.263.0.tar.gz
| Download URL | canvas-0.263.0.tar.gz |
|---|---|
| Size | 2.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1eb5036c3e9ce42c83d322e84596c681a22eb8f92ef804bea52d9bfc45eb541a
|
|
BLAKE2b-256 checksum How to use checksums |
0c9690b79fb496e9090b49ec607f9dc6ed6198edc8c5ecf7c59c97dd51b83141
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logRelease files / canvas-0.263.0-py3-none-any.whl
| Download URL | canvas-0.263.0-py3-none-any.whl |
|---|---|
| Size | 2.9 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d39427a130101b404a8c668ac64756ac67f257f67ef7bddaca77142c26138b4
|
|
BLAKE2b-256 checksum How to use checksums |
ab7d570f117737442f3cd4fc34dda234ad89dec43708de0bf5b5b1de43d57511
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logSecurity for canvas 0.263.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for canvas-0.263.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.