When you develop rules locally — for example with the VS Code extension or directly in a text editor — you can upload them to the portal with codecharter push. The command scans a directory for .cgr files, uploads them as rule drafts, and creates a profile draft in the portal without touching the currently published version. If a rule or the profile already has an open draft in the portal, the push stops with a conflict instead of overwriting it.
Prerequisites
You need:
- A CodeCharter CLI that includes the
pushcommand — runcodecharter --versionto check. If you need to upgrade, see Downloads. - A valid API key passed via the required
--api-keyoption (you can keep the key in an environment variable and pass it on the command line, as in the examples below) - One
.cgrfile per rule, optionally a.spec.mdfile with the same base name next to it
Directory layout
codecharter push operates on a directory and scans it recursively for .cgr files:
rules/
no-async-void.cgr
no-async-void.spec.md
max-method-length.cgr
Canonical usage
codecharter push ./rules \
--profile my-team-rules \
--version 1.0.0 \
--portal-url https://codecharter.tools \
--api-key $CODECHARTER_API_KEY
This scans ./rules recursively for .cgr files. Each rule's slug is derived from the filename (without the .cgr extension), so no-async-void.cgr becomes the slug no-async-void. A sibling .spec.md with the same base name is uploaded automatically. The run creates the profile draft [email protected] from those rules; if the profile already has an open draft, the push fails with a conflict so it cannot overwrite work in progress.
On success the CLI prints a summary line you can verify against:
Pushed 2 rule(s); profile draft '[email protected]' created.
There is no rule: or severity: declaration block — the slug comes from the filename, and the severity comes from the @severity directive inside the rule file (default: warn if the directive is absent). codecharter push uploads the file content as-is; the directive takes effect when the rule is loaded.
Dry run
codecharter push ./rules \
--profile my-team-rules \
--version 1.0.0 \
--portal-url https://codecharter.tools \
--api-key $CODECHARTER_API_KEY \
--dry-run
--dry-run lists the rules and the profile draft that would be pushed, without uploading anything. Useful to verify the plan before opening real drafts.
Options
| Option | Required | Description |
|---|---|---|
--profile <slug> |
yes | The profile slug to create or update. |
--version <semver> |
yes | The semantic version for the profile draft (e.g. 1.0.0). |
--portal-url <url> |
yes | URL of the CodeCharter portal. |
--api-key <key> |
yes | API key used to authenticate against the portal. |
--dry-run |
no | Show planned actions without uploading. |
Exit codes
| Code | Meaning |
|---|---|
0 |
All drafts created successfully (or dry run completed). |
1 |
A rule or the profile already has a conflicting draft. |
2 |
Usage error, I/O error, or network error. |
After the push
After a successful push the rule appears in the portal under /rules with the Draft badge. From there you can:
- run the spec in the portal (Run specs)
- use the live trial to test the rule against real C# code
- publish a new version (Publish)
A push never publishes on its own — that remains a deliberate manual step in the portal.
If a pushed rule has no published version yet, the profile draft references the rule draft and the CLI warns:
warning: rule 'no-async-void' has no published version yet; profile references the draft.
Common errors
Conflicting draft
error: Rule 'no-async-void' already has a draft. Discard or publish it first.
error: Profile 'my-team-rules' already has a draft. Discard or publish it first.
A rule or the profile already has an open draft in the portal. Discard or publish that draft in the portal, then push again. The command exits with code 1.
API key missing
error: --api-key is required.
Pass the key with --api-key. The command exits with code 2.
No rule files found
error: no .cgr files found in './rules'.
The directory does not contain any .cgr files (the scan is recursive). Check the path you passed. The command exits with code 2.
Portal rejects the request
error: portal returned 401 Unauthorized for rule 'no-async-void'.
The portal refused the upload. Check that the API key is valid and not expired, and that --portal-url points to the right portal. The command exits with code 2.