calm push architecture <file> --namespace <ns> |
POST /calm/namespaces/{ns}/architectures |
Create new; POST …/{id}/versions/{v} for versioned update |
calm pull architecture <id> --namespace <ns> --version <version> |
GET /calm/namespaces/{ns}/architectures/{id}/versions/{version} |
Write to stdout (or --out <file>) |
calm list architectures --namespace <ns> |
GET /calm/namespaces/{ns}/architectures |
Print IDs/versions |
calm create control --domain <domain> --name <name> |
POST /calm/domains/{domain}/controls |
409 shown as friendly error |
calm list controls --domain <domain> |
GET /calm/domains/{domain}/controls |
Print control IDs/names |
calm push control-requirement <file> --domain <domain> --control-id <id> --version <version> |
POST /calm/domains/{domain}/controls/{id}/requirement/versions/{version} |
Publish a requirement version for a control |
calm pull control-requirement --domain <domain> --control-id <id> --version <version> |
GET /calm/domains/{domain}/controls/{id}/requirement/versions/{version} |
Write to stdout (or --out <file>) |
calm push control-config <file> --domain <domain> --control-id <control-id> --config-id <config-id> --version <version> |
POST /calm/domains/{domain}/controls/{controlId}/configurations/{configId}/versions/{version} |
Create or version a control configuration |
calm pull control-config --domain <domain> --control-id <control-id> --config-id <config-id> --version <version> |
GET /calm/domains/{domain}/controls/{controlId}/configurations/{configId}/versions/{version} |
Write to stdout (or --out <file>) |
calm create decorator <file> --namespace <ns> |
POST /calm/namespaces/{ns}/decorators |
JSON body read from <file> |
calm list decorators --namespace <ns> [--target <target>] [--type <type>] |
GET /calm/namespaces/{ns}/decorators |
Optional --target, --type query filters |
calm pull decorator <id> --namespace <ns> |
GET /calm/namespaces/{ns}/decorators/{id} |
No --version flag (decorators are not versioned) |
calm create domain --name <name> |
POST /calm/domains |
409 shown as friendly error |
calm list domains |
GET /calm/domains |
Print domain names |
calm push interface <file> --namespace <ns> |
POST /calm/namespaces/{ns}/interfaces |
Same versioned shape as architectures |
calm pull interface <id> --namespace <ns> --version <version> |
GET /calm/namespaces/{ns}/interfaces/{id}/versions/{version} |
Write to stdout (or --out <file>) |
calm list interfaces --namespace <ns> |
GET /calm/namespaces/{ns}/interfaces |
Print IDs/versions |
calm create namespace --name <name> --description <description> |
POST /calm/namespaces |
409 shown as friendly error |
calm list namespaces |
GET /calm/namespaces |
Print name + description |
calm push pattern <file> --namespace <ns> |
POST /calm/namespaces/{ns}/patterns |
Same versioned shape as architectures |
calm pull pattern <id> --namespace <ns> --version <version> |
GET /calm/namespaces/{ns}/patterns/{id}/versions/{version} |
Write to stdout (or --out <file>) |
calm list patterns --namespace <ns> |
GET /calm/namespaces/{ns}/patterns |
Print IDs/versions |
calm push standard <file> --namespace <ns> |
POST /calm/namespaces/{ns}/standards |
{ name, description, standardJson }; POST …/{id}/versions/{v} for versioned update |
calm pull standard <id> --namespace <ns> --version <version> |
GET /calm/namespaces/{ns}/standards/{id}/versions/{version} |
Write to stdout (or --out <file>) |
calm list standards --namespace <ns> |
GET /calm/namespaces/{ns}/standards |
Print name + description + ID |
Feature Proposal
Target Project:
cli(@finos/calm-cli) — the CALM command-line tool that currently supportsgenerate,validate,template,docify, andinit-aicommands.Description of Feature:
Extend the
calmCLI withpush,pull,list, andcreatecommands that allow users to publish and retrieve CALM documents (architectures, patterns, standards, interfaces) and manage organisational resources (namespaces, domains, controls, decorators) against a CALM Hub instance.This closes the read/write gap: the CLI can already fetch schemas and patterns from a Hub via the
--calm-hub-urlflag, but has no way to publish new documents, retrieve a specific versioned document, or manage the Hub's organisational resources (namespaces, domains, controls, decorators) from the command line.User Stories:
calm push architecture my-arch.json --namespace my-orgso that I can publish a new architecture to our shared CALM Hub without writing raw HTTP calls.calm pull architecture my-arch --version 1.2.0 --out my-arch.jsonso that I can fetch a specific versioned architecture from the Hub and work on it locally.calm push standard my-standard.json --namespace my-orgso that I can publish governance standards to the Hub for teams to reference.calm pull standard my-standard --version 1.0.0 --out my-standard.jsonso that I can fetch the exact version of a standard my architecture must comply with.calm list architectures --namespace my-org) so that I can discover what is already published.calm create namespace --name my-org --description "My org namespace"so that I can provision a new namespace without using the Swagger UI or raw HTTP.calm list namespacesso that I can see all provisioned namespaces in a Hub instance.calm create domain --name paymentsandcalm list domainsso that I can manage top-level domain classifications from the CLI.calm push interface my-interface.json --namespace my-organdcalm pull interface my-interface --version 1.0.0so that I can publish and retrieve reusable interface definitions from the Hub.calm create control --domain payments --name PCI-DSSandcalm list controls --domain paymentsso that I can manage control requirements directly from the CLI.calm create decorator my-decorator.json --namespace my-organdcalm list decorators --namespace my-orgso that I can attach and query metadata decorators on Hub resources without using the Swagger UI.Current Limitations:
generateandvalidatecommands accept--calm-hub-urlto resolvecalm://URIs viaCalmHubDocumentLoader(inshared/), but this only performs HTTP GET requests to fetch schemas/patterns.publish,push,pull,list, orcreatecommands in the CLI.@PermittedScopes) on mutating endpoints (POST/PUT), so publishing requires an authenticated request.curlor Swagger UI) to publish documents (including standards and interfaces), and to manage namespaces, domains, controls, and decorators.POST /calm/namespaces,GET /calm/namespaces) and domains (POST /calm/domains,GET /calm/domains) are top-level Hub resources with no CLI representation today.POST/GET /calm/domains/{domain}/controls) and their versioned requirements and configurations have no CLI representation.POST/GET/PUT /calm/namespaces/{ns}/decorators) — filterable metadata attachments — have no CLI representation.Proposed Implementation:
New commands:
calm push architecture <file> --namespace <ns>POST /calm/namespaces/{ns}/architecturesPOST …/{id}/versions/{v}for versioned updatecalm pull architecture <id> --namespace <ns> --version <version>GET /calm/namespaces/{ns}/architectures/{id}/versions/{version}--out <file>)calm list architectures --namespace <ns>GET /calm/namespaces/{ns}/architecturescalm create control --domain <domain> --name <name>POST /calm/domains/{domain}/controlscalm list controls --domain <domain>GET /calm/domains/{domain}/controlscalm push control-requirement <file> --domain <domain> --control-id <id> --version <version>POST /calm/domains/{domain}/controls/{id}/requirement/versions/{version}calm pull control-requirement --domain <domain> --control-id <id> --version <version>GET /calm/domains/{domain}/controls/{id}/requirement/versions/{version}--out <file>)calm push control-config <file> --domain <domain> --control-id <control-id> --config-id <config-id> --version <version>POST /calm/domains/{domain}/controls/{controlId}/configurations/{configId}/versions/{version}calm pull control-config --domain <domain> --control-id <control-id> --config-id <config-id> --version <version>GET /calm/domains/{domain}/controls/{controlId}/configurations/{configId}/versions/{version}--out <file>)calm create decorator <file> --namespace <ns>POST /calm/namespaces/{ns}/decorators<file>calm list decorators --namespace <ns> [--target <target>] [--type <type>]GET /calm/namespaces/{ns}/decorators--target,--typequery filterscalm pull decorator <id> --namespace <ns>GET /calm/namespaces/{ns}/decorators/{id}--versionflag (decorators are not versioned)calm create domain --name <name>POST /calm/domainscalm list domainsGET /calm/domainscalm push interface <file> --namespace <ns>POST /calm/namespaces/{ns}/interfacescalm pull interface <id> --namespace <ns> --version <version>GET /calm/namespaces/{ns}/interfaces/{id}/versions/{version}--out <file>)calm list interfaces --namespace <ns>GET /calm/namespaces/{ns}/interfacescalm create namespace --name <name> --description <description>POST /calm/namespacescalm list namespacesGET /calm/namespacescalm push pattern <file> --namespace <ns>POST /calm/namespaces/{ns}/patternscalm pull pattern <id> --namespace <ns> --version <version>GET /calm/namespaces/{ns}/patterns/{id}/versions/{version}--out <file>)calm list patterns --namespace <ns>GET /calm/namespaces/{ns}/patternscalm push standard <file> --namespace <ns>POST /calm/namespaces/{ns}/standards{ name, description, standardJson };POST …/{id}/versions/{v}for versioned updatecalm pull standard <id> --namespace <ns> --version <version>GET /calm/namespaces/{ns}/standards/{id}/versions/{version}--out <file>)calm list standards --namespace <ns>GET /calm/namespaces/{ns}/standardsOutput format:
Default output for all commands is JSON to stdout. Intended for scripting and CI/CD pipelines.
--output tableflag (shorthand-o table) renders results as a human-readable table. Intended for interactive terminal inspection.listcommands default to a JSON array of the raw Hub API response values.pullcommands write raw, pretty-printed JSON to stdout by default. When--out <file>is provided the raw JSON is written to disk with no additional formatting. The--outputflag has no effect onpull(output is always JSON).pushandcreatesuccess output defaults to a JSON object. For versioned resources:{ "id": <id>, "version": "<semver>", "location": "<Location URL>" }. For non-versioned resources (namespace, domain, control, decorator):{ "id": <id>, "location": "<Location URL>" }. With--output table, a single-row confirmation is rendered:Error output always goes to stderr as a JSON object:
{ "status": 409, "error": "namespace 'my-org' already exists", "request": "POST /calm/namespaces" }. With--output table, errors print as plain text to stderr instead.Table columns for
listcommands (when--output tableis used):calm list architectures/patterns/interfacesID,NAME,VERSIONScalm list standardsID,NAME,DESCRIPTION,VERSIONScalm list controlsID,NAMEcalm list decoratorsID,TARGET,TYPEcalm list namespacesNAME,DESCRIPTIONcalm list domainsNAMEExit codes:
01Errors are distinguished by the JSON error object written to stderr (
{ "status": <code>, "error": "<message>", "request": "<method> <path>" }), not by the exit code. Scripts should parse stderr for the HTTP status to branch on specific failure conditions.Technical design considerations:
--calm-hub-url/~/.calm.jsonconfiguration mechanism for the Hub base URL.--namespace(default:default) flag for all namespace-scoped commands. Control commands use--domaininstead; the--namespacedefault does not apply to them.--auth-tokenflag (or read fromCALM_HUB_TOKENenv var /~/.calm.json) passed asAuthorization: Bearer <token>header for mutating operations.CalmHubDocumentLoaderinshared/(or introduce aCalmHubClientclass) to support POST/GET for all versioned namespace resource types (architectures, patterns, standards, interfaces) and domain-scoped resources (controls with requirements and configurations) plus decorators.calm pushshould auto-detect the resource type from the document's$schemafield when not specified explicitly.calm pullshould default to writing to stdout; an--out <file>flag writes to disk.calm create namespace,calm create domain,calm create control, andcalm create decoratorfollow the same auth pattern aspush(Bearer token required for mutating operations).calm list namespaces,calm list domains,calm list controls, andcalm list decoratorsare read-only and require no auth token.listsupports optional--targetand--typequery filters mapping to?target=and?type=onGET /calm/namespaces/{ns}/decorators.pullretrieves a single decorator by ID; decorators are not versioned so no--versionflag is needed.--domainflag), not namespace-scoped; requirements and configurations are further nested under a control ID.API changes:
push,pull,list, andcreateincli/src/cli.ts.CalmHubClient(or extension ofCalmHubDocumentLoader) inshared/src/covering: versioned namespace resources (architectures, patterns, standards, interfaces); domain-scoped controls withcreateControl,listControls,publishRequirementVersion,getRequirementVersion,createControlConfig,getControlConfig; decorators withcreateDecorator,listDecorators,pullDecorator; and organisational resourcescreateNamespace,listNamespaces,createDomain,listDomains.Data model changes:
Dependencies:
calm logincommand can be tracked separately).Alternatives Considered:
calm hubsub-command group — cleaner namespacing but adds one extra word to every invocation. Deferred to a follow-up refactor if the command surface grows.calm publish/calm retrieve— longer verb names, inconsistent with common CLI conventions (push/pullalign with git/container-registry mental models).list— could have been omitted in a minimal scope, but included because discoverability is necessary forpullto be useful without knowing exact IDs.--target/--typefilter flags add slight complexity, but decorators are a core metadata mechanism and their absence would force ongoing manual API calls.Testing Strategy:
CalmHubClientHTTP calls; test command flag parsing, file I/O, and error handling (4xx/5xx responses, missing auth token, invalid namespace, 409 conflict on duplicate namespace/domain/control).cli/test_fixtures/; spin up a local CALM Hub (NitriteDB mode, no Docker required) and exercise full round-trips: create namespace → push → list → pull for each namespace-scoped resource type (architecture, pattern, standard, interface); create domain → create control → push requirement → pull requirement; create decorator → list decorators with filters.status: 401orstatus: 403when an invalid or missing token is provided.calm create namespace,calm create domain, andcalm create controlwrite a JSON error object to stderr withstatus: 409on duplicate resource creation.calm list decorators --target my-node --type tagcorrectly passes query parameters and filters results.Documentation Requirements:
cli/README.mdwithpush,pull,list, andcreatecommand reference sections.docs/(Docusaurus site) CLI reference page.~/.calm.jsonschema documentation to includeauthTokenfield.Implementation Checklist:
Additional Context:
/calm/namespaces/{namespace}/{resource-type}. Standards are the exception: they use{ name, description, standardJson }wherestandardJsonis the raw content as a JSON string. Architectures, patterns, and interfaces use the document JSON directly as the request body. All versions are semver-validated./calm/domains/{domain}/controls). Each control has independently versioned requirements (/controls/{id}/requirement/versions/{v}) and configurations (/controls/{id}/configurations/{configId}/versions/{v})./calm/namespaces/{ns}/decorators.GETsupports?target=and?type=filters. A separateGET /decorators/valuesendpoint returns full decorator payloads (vs. IDs only) — this endpoint is not exposed as a CLI command in this proposal (see Out of Scope).POST /calm/namespacesaccepts{ name, description }, returns 201 +Locationor 409.GET/POST /calm/domains— top-level, not namespace-scoped.calm://URI scheme used ingenerate/validatefor reading can be extended or complemented by the newpullcommand.@PermittedScopes). A dedicatedcalm logincommand (storing tokens in~/.calm.json) is a natural follow-on issue.shared/src/document-loader/calm-hub-document-loader.ts,cli/src/cli.ts.Out of Scope:
The following CALM Hub endpoints are intentionally excluded from this proposal. Each is a candidate for a separate follow-on issue.
POST/GET /calm/namespaces/{ns}/adrs, revision management, status transitionsDRAFT→ACCEPTED→ etc.); the UX requires separate design considerationPOST/GET /calm/namespaces/{ns}/user-accessNAMESPACE_ADMINscope; user/permission management is a distinct operational concern better addressed in a dedicatedcalm accesscommand proposalGET/POST /calm/schemas,GET /calm/schemas/{v}/meta,GET /calm/schemas/{v}/meta/{name}POST/GET /calm/namespaces/{ns}/{customId}and versioned variantspush/pullcommands; should be evaluated after the typed commands are stable to avoid conflicting UXGET …/{id}/versionsfor all versioned resourcescalm list <resource> --versions <id>sub-option; can be added as a minor enhancementGET /decorators/values— full decorator payload list for a namespacecalm list decoratorsalready returns IDs; the values endpoint is a convenience optimisation that can be added as a minor enhancementPOST/GET /calm/namespaces/{ns}/flows,GET …/flows/{id}(latest), versioned CRUDPUT …/{id}/versions/{v}for architectures, patterns;PUT /decorators/{id}allow.put.operationsserver flag; mutating published versions is a destructive operation that needs explicit opt-in design in the CLI