Changelog
All notable changes to crm are documented in this file.
The format is loosely based on Keep a Changelog, and this project adheres to Semantic Versioning. Releases from 0.12.0 on are cut automatically by python-semantic-release from Conventional Commit messages; new version sections are inserted below this line.
v1.71.0 (2026-07-19)
Documentation
-
Address review round 1 — ADR front matter, wording, harden admin-merge guidance (#902,
b22ed41) -
Promote agent-memory knowledge into ADRs and contributor docs (#902,
b22ed41) -
Promote memory knowledge into repo — ADRs 0029/0030, CI traps, D365 Web API quirks (#902,
b22ed41) -
Record on-prem-priority stance in CLAUDE.md (
f33bcbf) -
research: Pilot task harvest — community sourcing validates demand-weighted corpus (#885,
9bf00b5) -
skill sync: Sync matt pocock skills (
450092b)
Features
Refactoring
-
Give check_self_containment an explicit (router, references) signature (#901,
f54dfb6) -
Retire skill-bundle checks now owned by the lint gate (#901,
f54dfb6)
Testing
v1.70.0 (2026-07-17)
Bug Fixes
Documentation
-
Document method-aware self-update; type + guard fixes (#873,
7384b70) -
Qualify self-update skill-refresh guarantee (failed upgrade leaves skills untouched) (#873,
7384b70)
Features
v1.69.5 (2026-07-17)
Bug Fixes
-
skill: Hide internal dev skills from bare npx skills add (#869,
8bbb323) -
skill: Make npx skills install banner actually install the crm skill (#869,
8bbb323) -
skill: Make the npx skills install banner actually install the crm skill (#869,
8bbb323) -
skill: Normalize any existing metadata.internal instead of duplicating (#869,
8bbb323)
Chores
- Share Claude skills with Codex
(
0ce22f7)
Code Style
Documentation
Testing
v1.69.4 (2026-07-13)
Bug Fixes
- plugin: Default plugintypes.name to type name so workflow activities get a designer label
(#867,
ee80d50)
Chores
v1.69.3 (2026-07-11)
Bug Fixes
Chores
-
Adopt semgrep CE with dry-run-contract house rule (#856,
58532fc) -
Adopt tooling-sweep quick wins — actionlint, codespell, coverage artifact (#859,
1370d28) -
review: Wire post-trial review lanes — Copilot round 1 only, CodeRabbit owns iteration (#863,
b22bbae)
v1.69.2 (2026-07-11)
Bug Fixes
Chores
v1.69.1 (2026-07-11)
Bug Fixes
Chores
-
Address CodeRabbit review on cloud-ship gh->MCP override (#850,
c110f1b) -
Defer fire polling bound to ship's copilot-loop spec (#850,
c110f1b) -
Extend cloud-ship gh->MCP override to repo docs (phase-1 claim) (#850,
c110f1b) -
Make fire poll-ceiling defer to step-4/5, not "proceed" (#850,
c110f1b) -
Reword blocked-hand-off label transform as plain prose (#850,
c110f1b) -
Route cloud-ship GitHub ops through MCP connector (#850,
c110f1b)
v1.69.0 (2026-07-11)
Chores
Documentation
- review: Pin --pythonversion in CLAUDE.md lint cmd; note click 8.4.1 raise in ADR 0026
(#852,
653ee85)
Features
v1.68.3 (2026-07-11)
Bug Fixes
-
Re-anchor type-ignore comments detached by the reformat (#844,
31a9aa3) -
Repair autofix-removed re-exports, apply UP unsafe fixes, scoped ignores (#844,
31a9aa3) -
Resolve remaining ruff findings (E501, B904, B023, F841, D41x, E741, F402) (#844,
31a9aa3)
Chores
-
Add ruff config, dev deps, pre-commit hook, CI lint steps (#844,
31a9aa3) -
Adopt ruff lint + format with pre-commit hook and CI gate (#844,
31a9aa3) -
review: Derive all reviewers from the canonical coding-standards doc (#842,
d45a0e7)
Code Style
Documentation
-
Record D205 adoption debt in the canonical standards doc (#844,
31a9aa3) -
contributing: Add canonical coding-standards.md (#836,
fa821c4)
v1.68.2 (2026-07-11)
Bug Fixes
-
Address Copilot review on safe_xml messaging (#841,
7f9def7) -
Harden org-supplied XML parsing against entity-expansion bombs (#841,
7f9def7) -
Wrap corrupt-export zip errors in _rewrite_customizations (#841,
7f9def7)
Chores
Documentation
v1.68.1 (2026-07-11)
Bug Fixes
- metadata: Add --behavior to update-attribute for the one-time datetime behavior change
(#834,
4bd894c)
v1.68.0 (2026-07-11)
Bug Fixes
-
cli: Honor trailing --json/--jq in the passive update-check guard (#835,
f654de9) -
cli: Skip --fields/--jq values in the JSON-mode argv scan (#835,
f654de9)
Chores
- skills: Strip model-invocation flag in user-dir source too
(
1096124)
Documentation
-
Add customizations-as-code golden-workflow guide + skill spine (#815,
95ca069) -
Address Copilot round 2 — crm prefix in spine, unsplit code spans (#815,
95ca069) -
Fix stale-plan anchor + clarify plug-in projection in customizations-as-code guide (#815,
95ca069) -
Make convergence-verify steps read-only (--dry-run) (#815,
95ca069) -
Pass doc-example + skill-bundle gates; tighten skill spine (#815,
95ca069) -
research: CodeQL evaluation — go on default setup + security-extended (#822,
1eca9d3) -
research: CodeRabbit OSS plan eligibility + PR-level surface (#820,
19f94ff) -
skills: Address Copilot round 1 on audit-crm-skill snippets (#816,
94a1f4f) -
skills: Fix stale claims, add D365 best-practice gotchas, trim --help restatements (#816,
94a1f4f) -
skills: Register-image --step matches name or GUID, not name only (#816,
94a1f4f)
Features
v1.67.0 (2026-07-10)
Documentation
Features
-
apply: Plan artifact + prune cover UI kinds (closes PRD #791) (#813,
20f60ef) -
apply: Record UI-kind changed-field set in the plan artifact (#813,
20f60ef)
v1.66.1 (2026-07-10)
Bug Fixes
- apply: App-publish and read back model-driven apps so apply-created apps are visible
(#812,
fba9953)
v1.66.0 (2026-07-10)
Bug Fixes
Features
-
export-spec: Project model-driven apps + sitemap (#811,
02f3bf9) -
export-spec: Project model-driven apps + sitemap (#797) (#811,
02f3bf9)
Performance Improvements
v1.65.0 (2026-07-10)
Features
v1.64.0 (2026-07-10)
Bug Fixes
Documentation
Features
-
apply: Apps: spec create path — model-driven app + sitemap (#808,
97ec6a1) -
apply: Model-driven app + sitemap spec create path (#808,
97ec6a1)
Refactoring
Testing
v1.63.0 (2026-07-10)
Bug Fixes
Features
-
apply: Converge or refuse drift in spec forms: blocks (#807,
b83e9aa) -
apply: Converge or refuse drift in spec forms: blocks (#793) (#807,
b83e9aa)
Refactoring
Testing
-
apply: Fix pyright reportOptionalMemberAccess in forms reconcile test (#807,
b83e9aa) -
apply: Live e2e + section-order coverage; docs-sync for forms reconcile (#807,
b83e9aa) -
apply: Make forms-refuse e2e spec validation-valid (#807,
b83e9aa)
v1.62.0 (2026-07-10)
Documentation
Features
v1.61.0 (2026-07-10)
Bug Fixes
-
apply: Reject non-mapping form sub-blocks with a clean usage error (#805,
562ce27) -
apply: Report resolved form name/formid, not the placeholder (#805,
562ce27) -
apply: Tighten forms: spec validation up front (#805,
562ce27) -
apply: Treat
columns: nullas absent in form convergence (#805,562ce27) -
tests: Type-clean forms-phase test helper for CI pyright (#805,
562ce27)
Documentation
Features
Testing
v1.60.0 (2026-07-10)
Bug Fixes
-
Honest totals + None-safe human rendering in org brief (#804,
553f706) -
Make org brief request budget truly constant + generic docs placeholders (#804,
553f706)
Documentation
-
Clarify export-gap docstrings + sharpen completeness diagnostic (#789,
09cc3ed) -
Tighten export-gap contract comments to modelled surface (#789,
09cc3ed)
Features
Performance Improvements
Testing
-
Prove EXPORTED_KEYS emit via maximal-payload roundtrip (#799,
f3dc245) -
Prove EXPORTED_KEYS emit via maximal-payload roundtrip (#788) (#799,
f3dc245) -
Reify export-spec adapter gaps as data + contract test (#789,
09cc3ed) -
Reify export-spec adapter gaps as data + contract test (#787) (#789,
09cc3ed) -
Report both directions in roundtrip-coverage guard message (#799,
f3dc245)
v1.59.1 (2026-07-10)
Bug Fixes
-
forms: Address review — placeholder GUIDs, case-insensitive preserve (#786,
1bd2a65) -
forms: Clone forms with a custom-control subgrid descriptor (#786,
1bd2a65)
Documentation
v1.59.0 (2026-07-09)
Documentation
Features
Testing
v1.58.1 (2026-07-09)
Bug Fixes
-
Exit 2 for a half-supplied disassociate flag pair (#783,
66d1e90) -
Reject invalid input and harden edge cases across nine commands (#783,
66d1e90)
Documentation
-
Explain the true/false-label compare-to-default guard rationale (#783,
66d1e90) -
Sync plugin image-type and auto-number-format guards with #693 (#783,
66d1e90)
v1.58.0 (2026-07-09)
Bug Fixes
Features
Testing
-
Add # pyright: basic header to marker guard test (#782,
55e80fd) -
Mark shared e2e fixtures with a greppable E2E_MARKER (#782,
55e80fd) -
Mark shared e2e fixtures with a greppable E2E_MARKER (#769) (#782,
55e80fd) -
Satisfy pyright strict in the marker guard test (#782,
55e80fd) -
Self-seed contacts in odata cursor e2e test so it runs on a bare org (#768) (#780,
a6b4841) -
Sharpen _marker_prefix wording (self-review) (#782,
55e80fd)
v1.57.0 (2026-07-09)
Bug Fixes
Features
Refactoring
v1.56.1 (2026-07-09)
Bug Fixes
Chores
v1.56.0 (2026-07-09)
Bug Fixes
Chores
- Color-code e2e_all.py live output by test outcome
(
89f2279)
Documentation
Features
v1.55.0 (2026-07-09)
Features
v1.54.0 (2026-07-09)
Features
- Add ribbon button icon support (add-button flags + set-icon verb)
(
97b791c)
v1.53.3 (2026-07-09)
Bug Fixes
-
Retry CustomizationLockException on all customization writes (#774,
a8064eb) -
Ribbon set-label/set-rules guide to publish when staged diff is empty (#766,
05926ea)
v1.53.2 (2026-07-09)
Bug Fixes
-
Convert validation-before-backend bad-argument sites to usage errors (exit 2) (#770,
8a502d8) -
Keep empty --file/--xml-file as exit-1 content error, not a usage error (#770,
8a502d8)
Documentation
-
Align exit-code contract notes with the usage-error reclassification (#770,
8a502d8) -
adr: Reopen ADR 0012 — free durable cloud e2e org (#760,
dca1c4f)
v1.53.1 (2026-07-09)
Bug Fixes
v1.53.0 (2026-07-09)
Bug Fixes
-
Bulk-detect reports flagged records, not pairs (#761,
f823283) -
Fail fast on malformed FetchXML; narrow dry-run test comment (#761,
f823283) -
Follow paging in bulk-detect result read; placeholder test GUID (#761,
f823283) -
Wrap app set-sitemap --xml-file read in clean error envelope (#755,
f8f92ff)
Documentation
Features
v1.52.1 (2026-07-09)
Bug Fixes
-
Address Copilot review — presence-based alias precedence, docstring (#763,
69e7d08) -
Canonical --order-by for OData ordering with hidden aliases (#763,
69e7d08)
Chores
Documentation
- merge-gate: Harden review-skill invocation, e2e completion, issues section
(
99989bf)
v1.52.0 (2026-07-09)
Features
v1.51.24 (2026-07-09)
Bug Fixes
Documentation
v1.51.23 (2026-07-09)
Bug Fixes
v1.51.22 (2026-07-08)
Bug Fixes
-
--publish parity on ribbon add-button/remove and app set-sitemap (#754,
edda0a3) -
Add --skip-dependency-check and --formatted to solution stage-and-upgrade (#756,
de5e239)
v1.51.21 (2026-07-08)
Performance Improvements
Testing
v1.51.20 (2026-07-08)
Bug Fixes
Documentation
Performance Improvements
v1.51.19 (2026-07-08)
Bug Fixes
- Harden apply spec-read + alt-key name-map seam + orphaned temp-file reap (#744 #743 #740 #739)
(
43ee3ae)
v1.51.18 (2026-07-08)
Performance Improvements
v1.51.17 (2026-07-08)
Bug Fixes
v1.51.16 (2026-07-08)
Bug Fixes
Documentation
-
ADR 0022 plan artifact (approval-gated apply) + glossary terms (
5aadace) -
Clarify optionset description is applied on create, not update-reconciled (#745,
dba87c8)
v1.51.15 (2026-07-08)
Bug Fixes
-
Export Customer columns as the customer kind (#742,
5a7fa62) -
Truth-pass discoverability surfaces (catalogue, error text, docstring, skill) (#738,
b6bd23a)
Documentation
- Note workflow-run + >5000-row seeds and the count-cache caveat
(
8ec3754)
v1.51.14 (2026-07-08)
Bug Fixes
-
Create profile secret files 0600 and make atomic writes collision-safe (#733,
4688d5f) -
Make atomic-write temp name independent of target name length (#733,
4688d5f)
Documentation
Testing
v1.51.13 (2026-07-08)
Bug Fixes
-
Degrade alt-key column-type lookup gracefully; use explicit BOM escapes in tests (#731,
a8f1a9a) -
Make file-boundary reads UTF-8/BOM-tolerant and alt-key CSV values type-correct (#731,
a8f1a9a) -
Resolve alt-key column types through the cached name-map seam (#731,
a8f1a9a)
Documentation
- Note durable on-demand workflow seed unblocking activate/clone e2e
(
d25dc4c)
v1.51.12 (2026-07-08)
Bug Fixes
Documentation
v1.51.11 (2026-07-08)
Bug Fixes
Chores
-
agents: Add blindspot + quiz-before-merge skills, .agent symlink tree (#729,
df85958) -
agents: Restructure CLAUDE.md, add blindspot + quiz-before-merge skills, .agent symlinks (#729,
df85958)
Documentation
-
Add assert-under-optimize house rule to copilot instructions (#729,
df85958) -
Add assert-under-optimize house rule to copilot instructions (
d678151) -
Restructure CLAUDE.md walls into scannable lists (#729,
df85958)
v1.51.10 (2026-07-08)
Bug Fixes
v1.51.9 (2026-07-08)
Bug Fixes
v1.51.8 (2026-07-08)
Bug Fixes
- Prevent repl completion backend construction
(
4480495)
Documentation
- Restructure CLAUDE.md walls into scannable lists
(
dd8e19b)
v1.51.7 (2026-07-08)
Bug Fixes
-
Guard solution publish --xml-file read; parametrize the IO sweep (#722,
5d5d7a9) -
Wrap unguarded file IO in the OSError→domain-error idiom (#722,
5d5d7a9) -
Wrap unguarded file IO in the OSError→domain-error idiom (#699) (#722,
5d5d7a9)
Chores
Testing
-
Assert the operation (read/write), not just the path, in the IO sweep (#722,
5d5d7a9) -
Isolate CRM_HOME in the file-IO sweep so CLI runs stay hermetic (#722,
5d5d7a9)
v1.51.6 (2026-07-08)
Bug Fixes
Chores
- agents: Align workflow skills, complete cloud-env skill closure
(
5e29c43)
v1.51.5 (2026-07-07)
Bug Fixes
v1.51.4 (2026-07-07)
Bug Fixes
v1.51.3 (2026-07-07)
Bug Fixes
Chores
- Inject crm memory index into codex sessions
(
eedd279)
v1.51.2 (2026-07-06)
Bug Fixes
- Normalize update write payloads
(
12f4793)
Documentation
v1.51.1 (2026-07-05)
Bug Fixes
Chores
-
Add codex migration adapters (
5a021ed) -
agents: Extract live-e2e skill; gate commits for secrets + git discipline (#674,
8751873)
Refactoring
v1.51.0 (2026-07-03)
Bug Fixes
-
profile: Address Copilot review — report enforced flag, clearer clear-refusal (#672,
2f6b43f) -
profile: Scope read-safe exemption to POST (Copilot round 2) (#672,
2f6b43f)
Documentation
Features
Testing
v1.50.2 (2026-07-03)
Bug Fixes
Testing
-
examples: Guards accept Click's --flag=value form too (#671,
fd58531) -
examples: Robust metadata-write guard + accurate failure-mode comment (#671,
fd58531)
v1.50.1 (2026-07-03)
Bug Fixes
-
completion: Also complete target_set/related_set positionals (#670,
87bc38e) -
completion: Honor --session in shell entity-set profile resolution (#670,
87bc38e) -
completion: REPL attribute-name + OS-shell entity-set completion (#670,
87bc38e)
Documentation
v1.50.0 (2026-07-03)
Bug Fixes
-
Gate examples picker on stdout TTY and relax gallery floor (#669,
d8b180b) -
Generic placeholders in examples + resolver handles leading globals (#669,
d8b180b)
Features
v1.49.5 (2026-07-03)
Bug Fixes
-
Harden next-step hints per review — presence-based CRM_NO_HINTS, non-fatal store write (#668,
4d46e97) -
Show-once next-step hints for new human users (#668,
4d46e97)
Documentation
v1.49.4 (2026-07-03)
Bug Fixes
-
Address Copilot review — clearer picker-disabled message, test cleanups (#667,
0bc09a6) -
Interactive solution picker for no-arg solution export (#667,
0bc09a6)
Refactoring
-
apply: Migrate optionset, web resource, security role onto the component-kind adapter (#666,
6fb59cc) -
apply: Reconcile on a security-role create race instead of replacing (#666,
6fb59cc)
v1.49.3 (2026-07-02)
Bug Fixes
- Mask secret prompts with asterisks and add no-arg profile pickers
(
cd5a717)
Documentation
Refactoring
v1.49.2 (2026-07-02)
Bug Fixes
-
ribbon: Route core ribbon errors through the D365Error contract (#662,
b1fedb3) -
ribbon: Translate malformed-response errors in the two core helpers (#662,
b1fedb3)
v1.49.1 (2026-07-02)
Bug Fixes
v1.49.0 (2026-07-02)
Bug Fixes
-
repl: Extend tab-completion to commands, flags, choices, profiles (
e7a85e3) -
repl: Harden completion against internal errors, tighten docs (
e7a85e3) -
session: Make list_profiles() read-only, no mkdir side effect (
e7a85e3)
Chores
Documentation
-
Address Copilot round-1 nits (link style, key-1 grammar) (#648,
5173bbe) -
Align frontmatter with step 2 (oldest open issue) (#649,
632c2c5) -
Dedup crm skill invariants, split customizations ref, docs-sync anti-drift gates (#650,
2d7877c) -
Tighten cloud-ship skill; document sandbox subagent absence (#649,
632c2c5) -
completion: Document REPL's built-in tab-completion (
e7a85e3) -
completion: Mention OS-shell --profile dynamic completion (
e7a85e3) -
skill: Split metadata reference into read + write-gotchas files (#651,
5b93abb)
Features
- repl: Extend tab-completion to commands, flags, choices, profiles
(
e7a85e3)
v1.48.2 (2026-07-02)
Bug Fixes
v1.48.1 (2026-07-02)
Bug Fixes
Chores
-
Drop stale --default-solution flag from cloud-ship bootstrap (#640,
f2f43f8) -
Pin pyright to exact 1.1.411 so local lint matches CI (#640,
f2f43f8)
v1.48.0 (2026-07-02)
Features
v1.47.0 (2026-07-01)
Features
v1.46.1 (2026-07-01)
Bug Fixes
v1.46.0 (2026-07-01)
Features
v1.45.2 (2026-07-01)
Bug Fixes
Chores
-
Add multi-target e2e runner (scripts/e2e_all.py) (#622,
4b4760d) -
Multi-target e2e runner (scripts/e2e_all.py) (#622,
4b4760d)
Documentation
Testing
-
Update solution components JSON-mode test for componenttypename (#629,
7de5e4d) -
e2e: Self-seed query saved/user skips; document workflow-activate fallback (#621,
767d2e5)
v1.45.1 (2026-06-28)
Bug Fixes
v1.45.0 (2026-06-28)
Documentation
-
Address self-review — README/ADR-0019 surface, BU/dispatch doc notes (#614,
4858f24) -
Export-spec projects roles + web resources; apply accepts inline content (#614,
4858f24)
Features
Testing
- Isolate CRM_HOME in scaffold tests (fixes #616)
(
b5a3bac)
v1.44.0 (2026-06-28)
Documentation
- skill: On-prem CI deploy spine recipe
(
c58f251)
Features
Refactoring
v1.43.0 (2026-06-28)
Features
v1.42.0 (2026-06-28)
Documentation
Features
v1.41.0 (2026-06-28)
Bug Fixes
-
apply: Export-spec emits relationship lookup_description too (#604,
7d22dd0) -
apply: Keep export-spec menu output apply-valid; correct datetime caveat (#604,
7d22dd0) -
apply: Scope view fetchxml parse to the root entity; complete docs (#604,
7d22dd0)
Documentation
-
metadata: Correct remaining stale export-spec round-trip claims (#604,
7d22dd0) -
metadata: Document the wider export-spec round-trip surface (#604,
7d22dd0)
Features
Testing
v1.40.0 (2026-06-28)
Chores
-
evals: Address Copilot round 1 — active-leg progress key + env restore (#587,
dcc6cc3) -
evals: Address Copilot round 2 — robust host parse, graceful leg, target guard (#587,
dcc6cc3) -
evals: Default result.json + run.log into the run dir (
51289b2) -
evals: Live stderr progress + python -m evals.skill run front door (#587,
dcc6cc3) -
evals: Record 2026-06-26 baseline — cloud 100%, onprem 100% (
4cbf83e) -
evals: Reject --update-baseline for a single target; drop dead return (#587,
dcc6cc3) -
evals: Skill-efficacy review — persist traces, judge skill help/efficiency post-hoc (#589,
b609486) -
evals: Use host_of() in the prod-host guard for parser consistency (#587,
dcc6cc3)
Documentation
Features
- apply: Let specs reach the full builder surface (attribute/relationship/entity/view)
(#603,
a023108)
Refactoring
-
metadata: Explicit quoting in reorder ParamType error (Copilot) (#600,
5a33012) -
metadata: Sink command-body rules to core predicates + usage_guard (#600,
5a33012)
Testing
-
Audit & prune offline suite — remove 54 low-value tests, fix 6 drifted (#591,
d89b10b) -
Backfill offline coverage for testable blind spots (#592) (#594,
973dbc1) -
Cover repl_skin pure layout helpers (_strip_ansi, _visible_len, _display_home_path) (
1290908) -
Prune round-2 audit findings — collapse redundancy, delete low-value tests (#590) (#593,
4380d87) -
repl_skin: Make outside-home path test platform-independent (#600,
5a33012)
v1.39.2 (2026-06-26)
Bug Fixes
-
evals: Harden row_suffix against absent keys and non-mapping rows (#586,
8f5d199) -
evals: Make skill-eval predicates org-agnostic to stop false on-prem fails (#586,
8f5d199)
Chores
-
evals: Add Machine B tracer — isolated single-task skill eval harness (#576,
b116fde) -
evals: Add opt-in Claude --analyze pass to Machine B harness (#579,
6c96209) -
evals: Add opt-in Claude --analyze pass to the Machine B eval harness (#579,
6c96209) -
evals: Add workflow-per-domain skill-eval task set + set runner (#577,
b96eb52) -
evals: Address Copilot round-1 — generic prefixes, stronger predicates (#577,
b96eb52) -
evals: Address Copilot round-2 — accurate scored-vs-demonstrated comments (#577,
b96eb52) -
evals: Address Copilot round-3 — test name + accurate prefix note (#577,
b96eb52) -
evals: Address review round 2 — fix probe docstring + README wording (#582,
a65a4ee) -
evals: Address review — prod-host guard on probe, utf-8 I/O, validate repeat (#582,
a65a4ee) -
evals: Address review — reject empty end_state.query, assert task shape (#579,
6c96209) -
evals: Both-targets union runner + periodic baseline trend (#582,
a65a4ee) -
evals: Both-targets union runner + periodic baseline trend (#573) (#582,
a65a4ee) -
evals: Document --dangerously-skip-permissions for headless agent cmd (#581,
c2ae98f) -
evals: Enforce task target gate, capture agent exit, review polish (#576,
b116fde) -
evals: Harden isolation env, task parsing, and cleanup (review round 1) (#576,
b116fde) -
evals: Pass Claude subscription auth into skill-eval sandbox (#580,
0e3762d) -
evals: Record 2026-06-26 baseline — cloud 100%, onprem 67% (2 harness fails, #584) (
50a9a2a) -
evals: Run subprocesses from sandbox, validate expect shape (review round 2) (#576,
b116fde) -
evals: Score diagnostic tasks from the analyzer verdict (#579,
6c96209) -
evals: Self-review polish — typing idiom, cleanup-limitation honesty (#577,
b96eb52) -
evals: Skip diagnostic tasks in the set runner (#579,
6c96209) -
evals: Strip only delimiter newlines so prompt body stays verbatim (review round 3) (#576,
b116fde)
Documentation
-
evals: Document the --analyze pass and diagnostic tasks (#579,
6c96209) -
evals: Note diagnostic VERDICT scoring in the analyze section (#579,
6c96209)
v1.39.1 (2026-06-25)
Bug Fixes
Documentation
-
adr: Record skill-evaluation design (static gate + behavioral eval) (
53d1484) -
skill: Add workflow-xaml composition reference (#567,
57cc4d2)
Performance Improvements
Testing
-
Add offline skill-coverage gate reconciling skill tree vs CLI catalogue (#575,
399f914) -
Assert top-level names strictly superset groups in coverage gate (#575,
399f914)
v1.39.0 (2026-06-25)
Features
v1.38.0 (2026-06-25)
Bug Fixes
-
Reject --strict/--no-rollback without --xaml-file (#565,
ccd0406) -
Route workflow XAML warnings via emit channel, guard file read (#565,
ccd0406)
Documentation
-
Workflow update --xaml-file logic path (README, how-to, skill) (#565,
ccd0406) -
test: Note workflow update --xaml-file target-divergent e2e pair (#565,
ccd0406)
Features
Refactoring
Testing
v1.37.0 (2026-06-25)
Bug Fixes
Documentation
Features
Testing
v1.36.0 (2026-06-25)
Bug Fixes
-
Address review — NCName-safe prefix scan; drop dead mxswa URI loop (#557,
83a1991) -
Address review — skip mxswa property-elements; drop dead constants; tidy prefix scan (#557,
83a1991) -
Report the real undeclared XAML namespace prefix, not 'xmlns' (#557,
83a1991)
Documentation
Features
-
Add validate_workflow_xaml pure reference-validator (#557,
83a1991) -
Validate_workflow_xaml - pure XAML reference-validator (#557,
83a1991)
Testing
v1.35.0 (2026-06-25)
Features
v1.34.0 (2026-06-25)
Documentation
Features
v1.33.0 (2026-06-25)
Bug Fixes
-
apply: Fail-fast spec validation + accurate publish/convergence docs (review round 2) (#559,
8025d9e) -
apply: Harden spec validation and dry-run contract (review round 1) (#559,
8025d9e)
Documentation
Features
v1.32.0 (2026-06-25)
Features
- apply: --dry-run emits a full drift report
(
b1fe805)
v1.31.0 (2026-06-25)
Chores
- Relicense under PolyForm Noncommercial 1.0.0
(
5963212)
Documentation
- adr: Record 0004 reconsideration — codegen stays external
(
e2c17f8)
Features
v1.30.1 (2026-06-24)
Bug Fixes
- Note .NET SDK prereq in pac install hint
(
1de97dd)
Refactoring
-
De-duplicate four byte-identical helpers (#543) (#546,
4f1a1a3) -
Remove dead TypedDicts, REPL skin cruft, metadata leftovers (#545,
f88f0be)
v1.30.0 (2026-06-24)
Documentation
-
Add ADR 0013 + Provenance wall term for on-prem workflow xaml editing (
73189b5) -
Add workflow create/update feasibility spec (
bb63a73) -
Enrich workflow feasibility spec with deep-research findings (
0153878) -
context: Add Failure enrichment term to the CLI contract (
218a5fd)
Features
Refactoring
Testing
-
Add live e2e coverage for workflow clone/import/delete (#534,
39c16e9) -
Add offline gate validating doc CLI examples against describe (#532,
b87f2d7)
v1.29.0 (2026-06-23)
Documentation
- Fix e2e worktree-CLI note — cwd beats PYTHONPATH, not the editable finder
(
329ae1e)
Features
- plugin: Add register-type verb; correct auto-created-plugintype docstrings
(
e94956e)
Testing
v1.28.0 (2026-06-23)
Documentation
- Fix non-working CLI examples in quickstart/index/agent
(
41ba0ba)
Features
v1.27.6 (2026-06-23)
Bug Fixes
-
Bump-guard messages reflect title-or-body breaking change (#526,
fc3ec66) -
Stop bump-guard stalling agent feat PRs; only major is label-gated (#526,
fc3ec66)
Testing
v1.27.5 (2026-06-22)
Bug Fixes
Testing
-
e2e: Assert persisted cancreate is not allowed (#522,
bb6a42f) -
e2e: Cover fieldsec add-permission on a secured custom column (#522,
bb6a42f) -
e2e: Cover workflow run dispatch-only vs seeded on-demand workflow (
1cde24b)
v1.27.4 (2026-06-22)
Bug Fixes
Continuous Integration
Documentation
-
Clarify CS-trial profile wording + workflow provisioning step (#515,
26e4505) -
Record 2026-06-22 e2e live run (on-prem + cloud) in TEST.md (
d08407f) -
adr: Dedicated CS Dataverse sandbox as the cloud e2e target (
4b42fae)
Testing
-
e2e: Assert seed filter matches zero rows before submit (#513,
791f30e) -
e2e: Correct the 5 keep-skipped E2E_SKIP reasons + refresh TEST.md (#516,
e58728f) -
e2e: Cover async cancel + solution job-cancel via future-dated BulkDelete (#513,
791f30e) -
e2e: Cover audit detail by generating an audit row inline (#519,
e99ed3a) -
e2e: Cover plugin assembly register/unregister lifecycle (build signed .dll from C# source) (
41b4349) -
e2e: Cover theme publish (capture -> publish throwaway -> restore) (#520,
6433923) -
e2e: Poll audits table before skipping audit-detail test (#519,
e99ed3a)
v1.27.3 (2026-06-22)
Bug Fixes
v1.27.2 (2026-06-22)
Bug Fixes
v1.27.1 (2026-06-22)
Bug Fixes
- Sitemap add-subarea --pass-params + validate --dashboard exists
(
a38f1c0)
v1.27.0 (2026-06-22)
Features
v1.26.0 (2026-06-22)
Bug Fixes
-
view: Cascade-prune emptied parent filters on remove-filter (#493,
c9a1295) -
view: Harden remove-filter multi-condition path (#493,
c9a1295)
Features
v1.25.0 (2026-06-21)
Documentation
Features
-
Add sitemap move-node to reorder a navigation node (#491,
408d7ab) -
Add sitemap move-node to reorder a navigation node (B12) (#491,
408d7ab)
Refactoring
v1.24.0 (2026-06-21)
Bug Fixes
-
Harden dashboard web-resource warning and correct skill JSON contract (#490,
f5b6d66) -
Reject blank --url / --webresource in the command layer (#490,
f5b6d66) -
Validate remove-component selectors in the command layer (#490,
f5b6d66)
Documentation
Features
Testing
v1.23.0 (2026-06-21)
Bug Fixes
Documentation
Features
Refactoring
Testing
v1.22.0 (2026-06-21)
Bug Fixes
-
Address review — usage-error for exclusive flags, cleaner JSON keys (#486,
f6d6fe2) -
Uniform global node-id uniqueness + parent-aware sitemap T3 (#486,
f6d6fe2) -
Warn against chaining --no-publish sitemap edits; strip subarea flags (#486,
f6d6fe2)
Documentation
Features
-
Add sitemap live-edit verbs (add-area/group/subarea, remove-node) (#486,
f6d6fe2) -
Sitemap live-edit verbs (add-area/group/subarea, remove-node) (B6) (#486,
f6d6fe2)
Refactoring
v1.21.0 (2026-06-21)
Documentation
-
Clarify set-label solution requirement; e2e selects provisioned LCID (#484,
267129c) -
Sync set-label docs + strengthen e2e LocLabel/tooltip assertions (#484,
267129c)
Features
-
Add
ribbon set-labelto set custom-button labels/tooltips (#484,267129c) -
Add
ribbon set-labelto set custom-button labels/tooltips (B11) (#484,267129c)
Testing
v1.20.1 (2026-06-21)
Bug Fixes
Documentation
Testing
v1.20.0 (2026-06-21)
Features
- Author custom security roles —
security create-role+security set-role-privileges(3018c65)
v1.19.0 (2026-06-21)
Bug Fixes
-
Harden ribbon validate_rule_ids against invalid kind; clarify docs (#481,
6934f34) -
Reject mis-cased Mscrm.* ribbon rule ids (case-insensitive prefix guard) (#481,
6934f34)
Documentation
Features
Testing
-
Assert ElementTree.find results non-None in ribbon rule tests (pyright) (#481,
6934f34) -
Assert ribbon rule set by parsed value in e2e T3 (no drop/reorder) (#481,
6934f34)
v1.18.0 (2026-06-21)
Documentation
Features
Testing
v1.17.0 (2026-06-21)
Features
v1.16.0 (2026-06-21)
Bug Fixes
-
Harden dashboard tile add per review (guard, occupied section, input ranges) (#477,
ba23f43) -
Top-align dashboard tile placement; clarify --section is empty-only (#477,
ba23f43)
Documentation
-
Explain why dashboard tile commit skips the in-process T3 read-back (#477,
ba23f43) -
Sync dashboard add-chart / add-view tile editors (#477,
ba23f43)
Features
Testing
-
Satisfy pyright on dashboard tile tests (assert Element non-None) (#477,
ba23f43) -
Use valid placeholder GUIDs for existing dashboard cells (#477,
ba23f43)
v1.15.0 (2026-06-21)
Features
v1.14.0 (2026-06-21)
Documentation
Features
Testing
v1.13.0 (2026-06-21)
Documentation
-
Clarify assert_external_guids_intact compares a multiset (#473,
6c1357e) -
research: Safe customization-XML editors feasibility study (
e46f05e) -
triage: Document kind label axis (refactor, chore) (
f05c757) -
triage: Record SOAP-only messages as out-of-scope (#453,
f5e3928)
Features
Refactoring
-
Enforce publish-before-read-back in commit_xml_patch (#473,
6c1357e) -
Extract shared xml_edit primitives + generalized direct-PATCH commit (#473,
6c1357e) -
Extract shared xml_edit primitives and generalize the direct-PATCH commit (#473,
6c1357e)
v1.12.0 (2026-06-20)
Features
v1.11.0 (2026-06-20)
Bug Fixes
Chores
Documentation
Features
Refactoring
v1.10.0 (2026-06-20)
Features
v1.8.1 (2026-06-20)
Bug Fixes
- solution: Add help string to 'solution info' command
(
468de62)
Documentation
- Audit crm skill CLI coverage + slim router; add skill-authoring tooling
(
b7fe5ec)
v1.3.1 (2026-06-20)
Bug Fixes
v1.0.0 (2026-06-18)
- Initial Release
Pre-1.0 development history
The sections below (v0.12.0 → v4.31.1) record crm's pre-launch development.
Before its first public release the project reset its version to 1.0.0 to shed
the misleading inflated number (see
ADR 0011);
this history is kept for the record. Releases from 1.0.0 on are inserted above
this line by python-semantic-release.
v4.31.1 (2026-06-18)
Bug Fixes
v4.31.0 (2026-06-18)
Bug Fixes
-
translation: Add --publish to translation import (#377) (#413,
6f2af59) -
translation: Restore publish-all warning when --publish skipped by dry-run (#413,
6f2af59)
Documentation
Features
v4.30.1 (2026-06-18)
Bug Fixes
v4.30.0 (2026-06-18)
Features
- async: Async list --order-by/--filter
(
153f279)
v4.29.0 (2026-06-18)
Features
v4.28.0 (2026-06-18)
Documentation
-
ship: Instruct phase 6 to fill the repo PR template (#407,
2631c23) -
ship: Trim SKILL.md, add Claude+Gemini model tiers (#407,
2631c23) -
skill: Note plugin set-step-state in automation reference (#409,
250f7cc)
Features
v4.27.1 (2026-06-18)
Bug Fixes
Chores
v4.27.0 (2026-06-18)
Features
v4.26.1 (2026-06-18)
Bug Fixes
- docs: Correct phrasing in documentation regarding docs-sync subagent usage
(
fd653fd)
v4.26.0 (2026-06-18)
Features
- security: Add --name-contains filter to list-roles, document direct-only scope on
list-user-roles
(
75a4235)
v4.25.1 (2026-06-18)
Bug Fixes
Documentation
v4.25.0 (2026-06-18)
Documentation
- Add AGENTS.md pointing agents to CLAUDE.md
(
db08c31)
Features
v4.24.0 (2026-06-18)
Documentation
- Clarify version bump discipline (feat=minor for real features only)
(
95a829d)
Features
Refactoring
v4.23.0 (2026-06-18)
Features
v4.22.0 (2026-06-18)
Features
v4.21.0 (2026-06-18)
Features
v4.20.0 (2026-06-18)
Features
v4.19.0 (2026-06-18)
Features
v4.18.0 (2026-06-18)
Features
Testing
v4.17.0 (2026-06-18)
Documentation
Features
v4.16.1 (2026-06-18)
Bug Fixes
v4.16.0 (2026-06-18)
Features
v4.15.0 (2026-06-17)
Features
v4.14.0 (2026-06-17)
Features
v4.13.0 (2026-06-17)
Features
v4.12.0 (2026-06-17)
Documentation
- metadata: Document is_bound/return_type/is_composable on list-actions/list-functions
(#385,
a2ff49c)
Features
v4.11.0 (2026-06-17)
Features
v4.10.0 (2026-06-17)
Features
v4.9.0 (2026-06-17)
Features
v4.8.2 (2026-06-17)
Bug Fixes
v4.8.1 (2026-06-17)
Bug Fixes
- cli: Guard entity disassociate/clear-lookup and workflow deactivate behind the destructive
confirm (#380,
d9f3c72)
v4.8.0 (2026-06-17)
Bug Fixes
Continuous Integration
Documentation
-
Add section on subagents for code exploration using the Explore agent (
ed5b4df) -
adr: Correct 0010 required-checks list + record PSR admin bypass (
d8f9de8) -
adr: Record build-once, trust-PR CI/CD pipeline decision (0010) (
c097b14)
Features
v4.7.0 (2026-06-16)
Documentation
Features
v4.6.1 (2026-06-16)
Bug Fixes
v4.6.0 (2026-06-16)
Bug Fixes
Documentation
Features
v4.5.2 (2026-06-16)
Bug Fixes
v4.5.1 (2026-06-16)
Bug Fixes
-
Data import reports per-record failures, not just counts (#339,
54712d1) -
Human-mode import failure line always leads with row index (#339,
54712d1)
v4.5.0 (2026-06-16)
Features
v4.4.0 (2026-06-15)
Features
v4.3.0 (2026-06-15)
Documentation
Features
v4.2.0 (2026-06-15)
Features
v4.1.1 (2026-06-15)
Bug Fixes
-
App create --if-exists skip survives publish-before-read duplicate fault (#328,
6aa21c6) -
Default max_length for string/memo attributes when omitted (#327,
fcf4bc1)
Documentation
v4.1.0 (2026-06-15)
Chores
Documentation
-
docs-sync: Update model from opus to sonnet (
f8ca3fd) -
ship-skill: Add context-discipline guidance for long runs (
f4fc41e)
Features
v4.0.0 (2026-06-15)
Features
Breaking Changes
- output:
query odata--jsonrows move fromdata.valueto a bare array indata, and@odata.context/@odata.nextLinkleavedataformeta.entity delete--jsonrenamesidto_entity_id. Single-record--jsondatahas@odata.*stripped. Pre-1.0, permitted.
v3.12.9 (2026-06-15)
Bug Fixes
v3.12.8 (2026-06-15)
Bug Fixes
v3.12.7 (2026-06-15)
Bug Fixes
Documentation
- cloud-ship-routine: Force Skill-tool invocation + task-tool fallback
(
6fca0fe)
v3.12.6 (2026-06-15)
Bug Fixes
Testing
v3.12.5 (2026-06-15)
Bug Fixes
v3.12.4 (2026-06-14)
Bug Fixes
-
cli: Clarify --profile help points at profiles/ under CRM_HOME (#311,
6fc5d83) -
cli: Root help reflects cloud + on-prem; drop hardcoded --profile path (#311,
6fc5d83)
v3.12.3 (2026-06-14)
Bug Fixes
v3.12.2 (2026-06-14)
Bug Fixes
Chores
-
agents: Cloud ship routine (vendored skills + bootstrap + runbook) (
8f1ce23) -
agents: Install gh in cloud routine + branch/merge-gate fixes (
b1c3ff7) -
metadata: Drop unused _admin_header_options/_admin_kwargs imports (
20b0668)
Documentation
-
adr: Record CLI output contract + glossary terms (ADR 0008) (
e0d366d) -
claude: Note zsh output-capture traps when driving the CLI (
3fcb54e)
v3.12.1 (2026-06-14)
Bug Fixes
Documentation
-
Purge real test-org GUIDs from published docs (#259,
5ab576a) -
claude: Note single-test command and pytest e2e default (
34c008e) -
metadata: Align --update-option help with parser error wording (#296,
2eb4102)
Refactoring
-
commands: Composable seams for per-verb boilerplate (#264,
aeee16f) -
commands: Split _helpers grab-bag into a package (#271,
8cdacce) -
core: Single seam for metadata constraint vocabularies (#295,
3cca964) -
core: Split solution.py into lifecycle / components / transfer (#265,
8e88986)
v3.12.0 (2026-06-14)
Bug Fixes
Features
v3.11.0 (2026-06-14)
Documentation
- skill: Add customization-lifecycle reference + query count example
(
ac87ece)
Features
Refactoring
-
Consolidate entity-name resolution into one cache-backed seam (#261,
95e1d84) -
Deepen the OData response surface on D365Backend (#280,
509f564)
Testing
-
Finish shared-conftest dedup — drop remaining fixture shadows (#285,
4930753) -
Shared unit-suite conftest + canonical FakeBackend adapter (#283,
2714a06)
v3.10.0 (2026-06-13)
Features
v3.9.4 (2026-06-13)
Bug Fixes
v3.9.3 (2026-06-13)
Bug Fixes
Documentation
- Name agent-on-prem/agent-cloud as the live profiles, document Copilot auto-review
(
6e67adc)
v3.9.2 (2026-06-13)
Bug Fixes
Documentation
- Add worktree-e2e, host-guard, and test-target rules to CLAUDE.md
(
25a77e1)
v3.9.1 (2026-06-13)
Bug Fixes
Documentation
-
agents: Document priority + effort label axes (#272,
30f6384) -
plans: E2e test completeness implementation plan (
44a69b4) -
specs: E2e test completeness design (
143aa5d) -
specs: Harden e2e design after review (
3b440fa)
Testing
-
e2e: Complete live coverage + offline enforcement gate (#270,
75f4ae7) -
e2e: Profile-based target + credential selection for live suite (#274,
df08be8) -
form: Use obvious placeholder GUIDs for external-ref constants (#275,
7477088)
v3.9.0 (2026-06-12)
Features
v3.8.0 (2026-06-11)
Features
v3.7.0 (2026-06-11)
Bug Fixes
-
entity: Narrow children $select; validate --filter-entities at CLI boundary (#254,
9a9cdd0) -
entity: Run children counts under --dry-run; validate regex + chunk size (#254,
9a9cdd0)
Documentation
Features
-
entity: Add children — per-1:N related-record counts via $batch (#254,
9a9cdd0) -
entity: Add children — per-1:N related-record counts via $batch (#234) (#254,
9a9cdd0)
Testing
v3.6.1 (2026-06-11)
Performance Improvements
- Lazy-load the HTTP-transport stack so local commands skip the import tax
(
d88c754)
v3.6.0 (2026-06-11)
Chores
Features
-
query: Make ENTITY_SET optional on fetchxml — derive from XML (#250,
0d70d73) -
query: Make ENTITY_SET optional on fetchxml — derive from XML (#202) (#250,
0d70d73)
Refactoring
Testing
v3.5.0 (2026-06-11)
Features
v3.4.0 (2026-06-11)
Bug Fixes
Features
v3.3.0 (2026-06-11)
Features
v3.2.0 (2026-06-11)
Bug Fixes
-
emit: Print warnings before error in human mode (#244,
f093b4f) -
entity: Thread validate warnings through create D365Error path; simplify payload check (#244,
f093b4f) -
entity: Tighten human-mode warning test; annotate payload type (#244,
f093b4f)
Documentation
Features
-
entity: Warn when create payload contains the primary id (#244,
f093b4f) -
entity: Warn when create payload contains the primary id (#233) (#244,
f093b4f)
v3.1.5 (2026-06-11)
Bug Fixes
-
self-update: Fall back to current_version() when frozen install is up-to-date (#245,
b809468) -
self-update: Progress messages, clear version labels, expanded skills output (#245,
b809468) -
self-update: Show progress, fix misleading version label, expand skills output (#245,
b809468)
v3.1.4 (2026-06-11)
Bug Fixes
Code Style
Documentation
v3.1.3 (2026-06-11)
Bug Fixes
v3.1.2 (2026-06-11)
Bug Fixes
v3.1.1 (2026-06-11)
Bug Fixes
Documentation
- claude: Mandate worktree-per-feature for shared checkout
(
59a7d97)
v3.1.0 (2026-06-11)
Documentation
Features
v3.0.0 (2026-06-11)
Documentation
Features
Breaking Changes
- Read verbs under --dry-run (query odata, entity get, action function, …) now execute the real GET and return live data instead of returning the {_dry_run, method, url, …} request echo. The envelope still carries meta.dry_run: true. The root --dry-run help ("Preview HTTP request without issuing it") was a documented contract, so this is a breaking change.
v2.12.0 (2026-06-11)
Features
- skill: Default install to claude, confirm-overwrite, refresh on self-update
(
3f12923)
v2.11.1 (2026-06-11)
Bug Fixes
- self-update: Suppress upgrade notice after self-update runs
(
c63890f)
v2.11.0 (2026-06-11)
Build System
- docs: Cap mkdocs deps below 2.0 to keep strict build reproducible
(
2b38ee9)
Documentation
-
adr: Record self-update refreshes installed skills (#225,
902a03a) -
adr: Record stay-on-Material-9x, ProperDocs when forced (#224,
f8bf24f)
Features
v2.10.0 (2026-06-11)
Features
v2.9.0 (2026-06-10)
Features
v2.8.1 (2026-06-10)
Bug Fixes
v2.8.0 (2026-06-10)
Documentation
Features
v2.7.0 (2026-06-10)
Documentation
-
skill: Add
crm batchstandalone section to records.md (#189,bc4cd98) -
skill: Add edit-existing-view recipe to authoring.md (#188,
0d1ea0c) -
skill: Add plug-in trace-log debugging recipe to automation.md (
2770f1d) -
skill: Teach early-bound codegen toolchain + ADR no-wrapper (#194,
2664786) -
skill: Teach role component-type + managed-import privilege strip (#190,
caa0326) -
skill: Validate-first default + on-prem business-rule deactivate caveat (
b6c91a3)
Features
v2.6.2 (2026-06-10)
Bug Fixes
v2.6.1 (2026-06-10)
Bug Fixes
v2.6.0 (2026-06-10)
Features
v2.5.0 (2026-06-10)
Documentation
-
skill: Add failed-import investigation recipe to solutions reference (#183,
c72f4d4) -
skill: Add records-verb router to command discovery (#184,
7153e53)
Features
v2.4.4 (2026-06-10)
Bug Fixes
v2.4.3 (2026-06-10)
Bug Fixes
v2.4.2 (2026-06-10)
Bug Fixes
v2.4.1 (2026-06-10)
Bug Fixes
Documentation
-
research: Backlog filed — issue numbers recorded (
3d597e3) -
research: Cleanup confirmation and final criteria check (
336a2a4) -
research: Coverage matrix (Phase 2 complete) (
177903e) -
research: CRM developer scenarios report (Phase 4 report) (
ca8a142) -
research: Draft enhancement backlog for review (
2bee836) -
research: Harvest scenario candidates from five source families (
acb5566) -
research: Ingest prior art into scenario harvest (
510fa70) -
research: Minimal repros for trial-discovered CLI bugs (
2777245) -
research: Scenario catalogue (Phase 1 complete) (
d5738f4) -
research: Skill trial log (Phase 3 complete) (
3d18a8c) -
research: Trial plan and environment readiness (
e7dc7b7)
v2.4.0 (2026-06-10)
Documentation
- copilot: Add custom instructions for Copilot code review
(
f50598c)
Features
- sla: Add sla activate orchestrating backing workflows with structured compile-error reporting
(#168,
9c010f1)
v2.3.0 (2026-06-10)
Documentation
-
plans: CRM developer scenarios research implementation plan (
694cd59) -
specs: Add CRM developer scenarios research design (
68f45fc) -
workflow: Add duplicate-definition detection recipe (#165,
ecde5ce)
Features
v2.2.0 (2026-06-10)
Documentation
- Add ADR 0003 (Web API only, no SOAP) + workflow record glossary
(
1ab94e1)
Features
v2.1.2 (2026-06-09)
Bug Fixes
- solution: Validate --against-org detects BPF stage GUID collisions in Workflows XAML
(#163,
7059231)
Documentation
v2.1.1 (2026-06-09)
Bug Fixes
Documentation
v2.1.0 (2026-06-09)
Features
-
Entity delete emits deactivate-parent hint on workflow activation-record GUID (#173,
009732c) -
Entity delete emits deactivate-parent hint on workflow activation-record GUID (#161) (#173,
009732c)
Refactoring
-
Gate workflow import on exact code; fix overpromising delete-hint doc (#173,
009732c) -
Lazy-import workflow module on entity delete error path (#173,
009732c)
v2.0.2 (2026-06-09)
Bug Fixes
v2.0.1 (2026-06-09)
Bug Fixes
- Register_step binds sdkmessageprocessingstep lookups with lowercase nav-property names
(#159,
768231b)
v2.0.0 (2026-06-09)
Documentation
-
plan: Profile & credential UX revamp implementation plan (
ebf862b) -
spec: Crm update command + startup update nudge design (
93b4281) -
spec: Profile & credential UX revamp design (v2.0.0) (
1beca81)
Features
Breaking Changes
crm initandcrm connection connect(plus the migrated/removedprofiles/disconnect/set-password/delete-passwordverbs underconnection) are removed — usecrm profile add|use|list|edit|rm|set-password|delete-password..envautoload and everyD365_*/CRM_*credential env var (and theCRM_AUTH_SCHEMEoverride) are no longer read.CRM_HOMEis the only retained env knob.
v1.9.0 (2026-06-09)
Features
v1.8.0 (2026-06-09)
Bug Fixes
Documentation
Features
v1.7.0 (2026-06-09)
Documentation
- plans: Add export-spec and cli-robustness implementation plan
(
473d5a7)
Features
v1.6.1 (2026-06-09)
Bug Fixes
- Export-spec warns on dropped columns; Windows UTF-8 output; metadata-update hint; apply adds
referenced option sets
(
4816f97)
v1.6.0 (2026-06-08)
Chores
- Add .worktrees/ to .gitignore
(
2a01d5d)
Features
v1.5.0 (2026-06-08)
Bug Fixes
Documentation
-
plan: Implementation plan for crm workflow clone/export/import (#152,
a4f9fcd) -
spec: Design for crm workflow clone/export/import (#152,
a4f9fcd) -
spec: Link clone-entity spec to follow-up #151 (#152,
a4f9fcd) -
spec: Sequence #144 before #143; --with-workflows back in scope (#152,
a4f9fcd)
Features
-
workflow: Add 'workflow export' and 'workflow import' commands (#152,
a4f9fcd) -
workflow: Add clone, export, and import commands (#144) (#152,
a4f9fcd) -
workflow: Add export_workflow/import_workflow round-trip (#152,
a4f9fcd) -
workflow: Add get_workflow definition retrieval (#152,
a4f9fcd) -
workflow: Add retarget_xaml transform for clone (#152,
a4f9fcd) -
workflow: Clone_workflow_to_entity with tiered category guard (#152,
a4f9fcd)
Testing
v1.4.0 (2026-06-08)
Bug Fixes
-
ribbon: Add dry-run support, fix pyright basic pragma in tests (#150,
2f20ed3) -
ribbon: Fix remaining pyright errors in test_ribbon.py (#150,
2f20ed3) -
ribbon: Guard empty slugify, replace assert with if-guard, remove unused code (#150,
2f20ed3) -
ribbon: Guard None solution before _load_solution_ribbon_diff (#150,
2f20ed3) -
ribbon: Harden ZIP decode, improve error messages, fix bundler spec (#150,
2f20ed3)
Documentation
-
plan: Implementation plan for crm ribbon command group (#150,
2f20ed3) -
ribbon: How-to, README capability, SKILL entry (#150,
2f20ed3) -
spec: Verify ribbon decode + group ids against live org (#150,
2f20ed3)
Features
-
ribbon: Add_custom_action injects button + command nodes (#150,
2f20ed3) -
ribbon: Apply_ribbon_change export->validate->import->publish (#150,
2f20ed3) -
ribbon: Customizations.xml entity + RibbonDiffXml navigation (#150,
2f20ed3) -
ribbon: Decode RetrieveEntityRibbon CompressedEntityXml zip (#150,
2f20ed3) -
ribbon: Group mapping + deterministic button id helpers (#150,
2f20ed3) -
ribbon: Parse custom buttons from RibbonDiffXml (#150,
2f20ed3) -
ribbon: Remove_custom_action drops action + orphaned command (#150,
2f20ed3) -
ribbon: Retrieve_entity_ribbon via inline-literal RetrieveEntityRibbon (#150,
2f20ed3) -
ribbon: Ribbon add-button with webresource pre-flight (#150,
2f20ed3) -
ribbon: Ribbon export command + group registration (#150,
2f20ed3) -
ribbon: Ribbon list reads custom buttons from solution (#150,
2f20ed3) -
ribbon: Ribbon remove with destructive confirm (#150,
2f20ed3)
v1.3.0 (2026-06-08)
Chores
- plan: Add the plan file for issue 140
(
a7c26ec)
Documentation
Features
v1.2.0 (2026-06-08)
Features
- keyring: Promote keyring to core dependency
(
3500745)
v1.1.1 (2026-06-08)
Bug Fixes
-
solution: Omit ImportJobId on on-prem; recover server-assigned id from asyncop (
2870969) -
solution: Suppress false Pyright unused-function warning on _import_job_id_rejected (
ec37686)
Documentation
- install: Add uv tool install option for ASR-blocked machines
(
bed9523)
v1.1.0 (2026-06-07)
Documentation
-
connection: Document 'set-password' for storing profile secrets (#139,
1dc7387) -
plan: Add set-password (#137) implementation plan (#139,
1dc7387)
Features
-
connection: Add 'set-password' to store a secret for any profile (#139,
1dc7387) -
connection: Add 'set-password' to store a secret for any profile (#137) (#139,
1dc7387)
v1.0.0 (2026-06-07)
Documentation
- claude: CHANGELOG is PSR-owned, don't hand-edit
(
68b3101)
Features
Breaking Changes
- release: Secrets can now be persisted (opt-in keyring/plaintext); profile resolution restores the session active_profile when no --profile is given. Flips allow_zero_version so PSR cuts v1.0.0.
v0.13.1 (2026-06-06)
Bug Fixes
v0.13.0 (2026-06-06)
Features
[0.12.0] — 2026-06-07
Security
- Profile and session names are now validated as single path components at creation/load, preventing path traversal in on-disk profile/session/cache paths. (#126)
Fixed
crm --profile <missing>now emits the standard{ok:false, ...}error envelope (exit 1) instead of a rawFileNotFoundErrortraceback (#109).async:list_async_operations/list_all_async_operationsnow normalize theowner_idGUID filter to canonical form (braced/uppercase/urn inputs were sent to Dataverse verbatim). (#120)
Added
metadata export-spec <logical_name> [--with-views] [--with-relationships] [-o FILE]— project a live entity into thecrm apply -fdesired-state spec (round-trip: export-spec → apply re-creates the entity). Pure GETs. Without-othe spec is emitted under the standard JSON envelope; with-othe bare YAML is written directly to FILE. The projection is always re-appliable: a string column whose live format isJson/RichText(whichapplycannot create) is exported withoutformat_nameand re-created asText, and a string/decimal column whose deep read lacks the mandatorymax_length/precision(sparse reads) is skipped rather than emitted unappliable (#92).solution importresult (real and dry-run) now includes amanagedfield (true= managed solution,false= unmanaged,nullwhen undeterminable) sniffed fromsolution.xmlinside the zip. The sniff is best-effort and never blocks the import (#91).
[0.11.0] — 2026-06-06
Added
- crm scaffold table DISPLAY --column 'DISPLAY:KIND[:opts]' ... — create an
entity + N columns in a single publish by building a one-entity in-memory spec
and running it through the apply engine. Column shorthand: KIND is one of
string, memo, integer, bigint, decimal, double, money, boolean,
datetime, picklist, multiselect, lookup, image, file; each resource
is created with if_exists=skip (re-running is a no-op); honors global
--dry-run and --stage-only; requires a publisher_prefix on the active
profile (#90).
- Append-only JSONL audit journal of every mutating command. On success, each
mutating CLI verb (entity create/update/upsert/delete/associate/disassociate/
set-lookup/clear-lookup; all metadata create/update/delete-*; solution create/
create-publisher/set-version/add-component/remove-component/publish/publish-all/
import/job-cancel; batch; workflow activate/deactivate/run; action invoke;
webresource create/update; app create/add-components/build-sitemap/set-sitemap;
view create; data import; plugin register-assembly/register-step/
unregister-assembly/unregister-step; security assign-role; async cancel; apply)
appends one JSON line to
${CRM_HOME:-~/.crm}/audit/<session>.jsonl. Each line carries: ts (ISO-8601
UTC), profile, command, target, solution, staged, dry_run, ok, and
result_id. Read/query/get/list/export verbs never write to the journal.
--dry-run previews are journaled with dry_run: true so they are never
mistaken for real changes. The request payload is never stored (#89).
- crm session audit [--tail N] [--session NAME] prints the current (or a named)
session's audit journal; honors --json (#89).
- Opt-in, persistent, read-only on-disk cache of entity definitions, per connection
profile, to speed up repeated one-shot agent invocations. Enable with
--cache-metadata (global flag) or CRM_CACHE_METADATA=1 (truthy: 1/true/yes/on).
Force a one-shot refresh with --refresh-metadata. When the cache is active,
crm metadata entities emits meta.cache = "hit" | "miss" | "refreshed" in
both --json and human output. Cache-mode caveat: with --cache-metadata the
command returns only the 2-field rows (LogicalName / EntitySetName); the full
5-field listing is unchanged when the flag is absent. --custom-only is
incompatible with --cache-metadata (the cache lacks the custom flag) and errors
(exit 2). --top works (client-side slice). Cache files live at
<CRM_HOME or ~/.crm>/cache/<profile-name>/entitydefs.json. The cache stores
the {logical, set_name} list plus the source url, api_version, and
cached_at timestamp; a url/api_version mismatch is treated as a miss.
Invalidation: any successful metadata write (entity/attribute/optionset/relationship
create/update/delete, and publish-all/publish-xml) deletes the profile's cache
file so a stale cache cannot outlive a schema change; a ~15-minute TTL backstop
also forces a refresh. Cache misses and read errors degrade gracefully (fall back to
a live fetch). Read-only schema only — records and secrets are never cached.
When launched with --cache-metadata, the REPL's entity-name completion is
served from the same on-disk cache. crm metadata cache-clear deletes the active
profile's cache file; emits {"cleared": true|false} (#88).
- crm entity get and crm metadata attribute gain a repeatable --expect
ATTR=VALUE flag — a field-comparison verify primitive. Each pair is split on
the FIRST = (so a VALUE may itself contain =); every pair must match
str(record[ATTR]) == VALUE (AND-gate, a missing key never matches). The first
mismatch (CLI order) exits 1 with {ok:false, error:"Expectation failed: …",
meta:{attr, expected, actual}} (actual is the raw value); all match passes
through unchanged as ok:true (exit 0). For entity get the check runs against
the full record before any --minimal projection. A malformed --expect (no
=, or empty attr) is a usage error (exit 2) raised before any server call.
Enables a create→publish→verify loop, e.g. metadata add-attribute … &&
solution publish-all && metadata attribute <entity> <attr> --expect
AttributeType=String (#86).
- --minimal on crm query odata / fetchxml / saved / user and
crm entity get strips OData annotation keys (any key containing @:
@odata.etag, *@OData.Community.Display.V1.FormattedValue,
*@Microsoft.Dynamics.CRM.lookuplogicalname) from each record in --json
output, keeping business fields, _*_value lookup GUIDs, and the primary id.
Shallow prune (top-level record keys only; expanded records under --expand
are untouched), and the value-list envelope (@odata.count / @odata.nextLink
/ @odata.context) is preserved. No-op in human/table mode. Raw output remains
the default (non-breaking) — a token-efficient projection for agents (#85).
- --retry-on-ambiguous root flag (env: CRM_RETRY_ON_AMBIGUOUS) re-enables
auto-retry of non-idempotent POST creates on transport error / 429 / 503,
opting back into the duplicate-create risk (#84).
- crm solution components <name> --save <path> writes a normalized component
inventory (a bare JSON list, each entry {"componenttype": int, "objectid": str,
"rootcomponentbehavior": int|null}) to <path>, creating parent dirs as needed.
Emits {"saved": "<path>", "count": N}. --diff <expected.json> fetches live
components and compares them against the saved file; exits non-zero (1) on drift.
Components are keyed on the tuple (componenttype, objectid, rootcomponentbehavior)
after normalisation — missing = in expected but not live, unexpected = in live
but not expected. The two flags are mutually exclusive; bare components <name> is
unchanged. The round-trip --save then --diff against the same org reports no
drift (#82).
- crm metadata picklist and crm metadata get-optionset now emit a flattened
meta.options list ([{value, label}]) in --json mode, so agents need not
dig through Label.UserLocalizedLabel.Label. The raw data is unchanged (no
contract break). Labels resolve via UserLocalizedLabel then LocalizedLabels.
Boolean attributes have no Options array (TrueOption / FalseOption
instead), so meta.options is empty for them — read those raw fields directly (#76).
- crm security command group: list and assign Dynamics 365 security roles.
list-roles lists all security roles (optionally filtered to a business unit
via --business-unit GUID). list-user-roles USER_ID and
list-team-roles TEAM_ID return the roles currently assigned to a system user
or team (both positional args are GUIDs). assign-role ROLE_ID assigns a
security role to a user (--to-user GUID) or a team (--to-team GUID) —
exactly one target flag is required. Assignment is cumulative and not cleanly
reversible, so the command is gated by an interactive confirmation prompt
(bypass with --yes) and the destructive-op PreToolUse hook. Standard
admin-header options (--as-user, --as-user-object-id,
--suppress-dup-detection, --bypass-plugins) are available on assign-role
(#83).
- crm metadata dependencies <target> is a new read-only command that returns
can_delete (bool) plus a blockers[] list for any metadata component. --kind
selects the component type (entity / attribute / optionset / relationship;
default entity); attribute targets use dotted notation (entity.attribute).
--for delete (default) calls RetrieveDependenciesForDelete and lists what
would block deletion; --for dependents calls RetrieveDependentComponents and
lists what currently depends on the target (#81).
- --check-dependencies flag (default off) on metadata delete-entity,
delete-attribute, delete-relationship, and delete-optionset: folds
can_delete and blockers[] into the result via a pre-delete
RetrieveDependenciesForDelete call. Pair with --dry-run for a non-destructive
dependency preview without issuing the DELETE (#81).
Changed
- Extracted the destructive-verb classification (DESTRUCTIVE, ROLE_VERBS,
is_destructive()) into a new dependency-free crm/core/destructive.py. The
PreToolUse destructive-op gate (.claude/hooks/destructive_op_gate.py) keeps
its standalone stdlib copy so it stays import-free and offline on every Bash
call; a new crm/tests/test_destructive_sync.py asserts the two copies stay
aligned (#87).
- Non-idempotent POST record-creates (and actions) are no longer auto-retried on
transport error / 429 / 503 by default — a lost response may have already
committed the record, so a blind re-send risks a duplicate (#84). Idempotent verbs
(GET/PUT/PATCH/DELETE) are unchanged, and $batch keeps its own independent
retry loop. Pass --retry-on-ambiguous (or set CRM_RETRY_ON_AMBIGUOUS) to restore
the old behavior when the re-send risk is acceptable.
Fixed
- crm metadata delete-entity, delete-attribute, delete-relationship, and
delete-optionset under --dry-run now return
{"_dry_run": true, "would_delete": true, ...} instead of falsely reporting
{"deleted": true, ...} (#81).
- crm metadata picklist (human/table mode) now resolves option labels via the
full UserLocalizedLabel → LocalizedLabels fallback, matching --json
meta.options. Previously the table read UserLocalizedLabel only, so an
option whose label is carried solely via LocalizedLabels rendered blank (#76).
[0.10.0] — 2026-06-05
Added
- crm plugin command group: register and manage Dynamics 365 plug-in assemblies
and processing steps via the pluginassemblies / plugintypes /
sdkmessageprocessingsteps Web API entity sets.
register-assembly PATH uploads a .dll as a plug-in assembly (base64-encoded
into content); --update re-uploads the binary of an existing assembly by name
without touching its identity metadata. list-types lists platform-generated
plug-in types (typename, friendlyname, plugintypeid), optionally filtered
by --assembly NAME. register-step registers an sdkmessageprocessingstep
bound to a message (--message Create/Update/…) and a fully qualified type
(--plugin-type); stage (prevalidation/preoperation/postoperation) and
mode (sync/async) are configurable — async forces postoperation (other
combinations are rejected). The step name is auto-derived as
<typename>: <message> of <entity> (pass --name when the derived string would
exceed 256 chars). unregister-assembly ASSEMBLY cascades — it deletes dependent
steps first, then the assembly. unregister-step STEP deletes a step by name or
GUID; an ambiguous name errors. --solution sends MSCRM.SolutionUniqueName on
the writes. --dry-run skips all writes (resolution GETs still fire). --json
mode returns the standard {ok, data, meta} envelope (#80).
- crm app build-sitemap <SITEMAP_NAME> builds a valid SiteMapXml from
structured input and creates the sitemap. Three repeatable options describe the
tree: --area 'id[:Title]' (at least one required), --group 'areaId/groupId[:Title]'
(nested under an area), and --subarea 'areaId/groupId:entity=<logical>[:Title]',
where a SubArea binds a table via the SiteMapXml Entity= attribute (Title
optional — omit it and the platform derives the label from the entity). SubArea
Ids are auto-allocated from the entity logical name to stay unique across the
document, and every attribute value is XML-escaped; Area/Group Ids and the
references between them are validated, so broken references or duplicate Ids
fail with an error. After building the XML it delegates to the set-sitemap
path so the POST body is byte-identical, then optionally publishes. --unique-name
sets sitemapnameunique to auto-associate the sitemap with that app (same as
set-sitemap); --publish/--no-publish (default: publish) runs PublishAllXml
after creation. crm --dry-run app build-sitemap ... prints the generated
SiteMapXml and issues no POST. Complements set-sitemap, which uploads a
pre-built XML file (#79).
- crm webresource create / update / get / list manage web resources
(webresourceset). create base64-encodes the --file bytes into the
content column and infers the webresourcetype from the file extension
(.html=1, .css=2, .js=3, .xml=4, .png=5, .jpg=6, .gif=7,
.xap=8, .xsl=9, .ico=10, .svg=11, .resx=12 — the real D365
webresource_webresourcetype option set, so CSS=2 and 8 is Silverlight, not
the other way around); --type <int> overrides inference and an unknown
extension without it is rejected. --display-name defaults to the name.
update <name> resolves the resource by name and issues a plain PATCH of only
the sent fields (content from --file and/or --display-name; at least one
required) — not retrieve-merge-write. Both honor --solution (sent as
MSCRM.SolutionUniqueName) and publish after the write (--no-publish /
--stage-only suppress it). list --custom-only keeps unmanaged resources;
get <name> prints a record (#78).
- crm app create --icon-webresource <name|guid> sets the app icon to a web
resource: a GUID is used directly, a name is resolved to its id, and omitting
the flag keeps the platform default icon (#78).
- crm data import <ENTITY_SET> <INPUT_FILE> bulk-imports records via the
Dataverse $batch endpoint — the only on-prem bulk mechanism (CreateMultiple
/ UpsertMultiple are cloud-only). Supports JSONL and CSV input (format
inferred from the file suffix; override with --format). Two modes:
--mode create (POST, default) and --mode upsert (PATCH by GUID via
--id-column). Records are sent in chunks of --chunk-size (default 100);
each chunk is a transactional changeset (atomic, all-or-nothing) by default.
--no-transaction sends each operation as a top-level batch operation instead.
--continue-on-error sends Prefer: odata.continue-on-error to skip past
individual failures — it requires --no-transaction (a changeset is itself
all-or-nothing; combining the two is rejected with a usage error). CSV values
are coerced best-effort (empty→null, true/false→bool, integers, floats);
non-finite tokens (NaN/inf) and integer-looking strings ("007") are not
preserved — use JSONL for IDs, postal codes, and lookup binds. Dry-run via the
global crm --dry-run data import ... produces zero writes; the summary carries
dry_run: true. Output: {imported, failed, chunks, entity_set, mode, dry_run,
format}; failed > 0 surfaces a meta.warnings advisory; exit code is 0 on
partial failure, consistent with crm batch (#75).
- crm connection doctor (also exposed as the top-level alias crm doctor)
runs a live, ordered connection probe and renders a five-line checklist:
dns_tcp, tls, version (the configured api_version), auth, and an
informational rate_limit. Each layer's failure is classified distinctly
(DNS vs TCP vs TLS vs wrong api_version vs 401/403) with an actionable hint.
It is a read-only diagnostic — it never negotiates or mutates the profile, and
the raw GETs run regardless of --dry-run. --json emits
{ok, data:{checks:[{check,ok,detail,hint}]}}; overall ok (and the exit
code) is the AND of the four diagnostic checks, rate_limit never affects it
(#74).
- crm solution extract and crm solution pack bridge the CoreTools
SolutionPackager.exe to turn an exported solution zip into a source-controllable
folder tree and back (git diff on the extracted tree is the solution diff).
These are offline local-file transforms: no connection, profile, or backend
is required. --package-type selects Unmanaged (default) / Managed / Both;
the executable is resolved via --solutionpackager-path → CRM_SOLUTIONPACKAGER
env → PATH, and an absent binary fails with an actionable error naming the
Microsoft.CrmSdk.CoreTools NuGet package (no bundling or auto-download). The
subprocess honors --timeout and the emitted envelope carries
{action, exit_code, folder, zipfile, stdout_tail}; a non-zero SolutionPackager
exit fails the command (#73).
- crm entity create and crm entity update accept an opt-in --validate flag
that field-name-checks the payload before the write. It runs 1-3 read-only
metadata GETs (resolve entity-set → logical name, the entity's attribute names,
and the ManyToOne navigation-property names), then flags any payload key absent
from the union with a did_you_mean suggestion. <nav>@odata.bind deep-link
keys validate against the nav-name union, so a bound lookup is not a false
positive. On a miss the write is blocked with
{ok:false, meta:{unknown_fields, did_you_mean}}. Composable with --dry-run
(the validation GETs run for real even under dry-run). Scope is field-NAME only;
option-set values are not checked (#72).
- crm solution add-component and crm solution remove-component add or remove
an existing component to/from an unmanaged solution via the AddSolutionComponent
/ RemoveSolutionComponent Web API actions. --type accepts a componenttype
integer or a friendly name (entity, attribute, relationship, optionset,
webresource, … — names are case- and separator-insensitive; pass a raw int for
any type not in the map). Both pre-flight solution_info and refuse a managed
target client-side. add-component is non-destructive and supports
--no-add-required (AddRequiredComponents: false) and --no-subcomponents
(DoNotIncludeSubcomponents: true). remove-component is gated as a destructive
operation: it prompts for confirmation (aborting cleanly in a non-TTY context
unless --yes), and the verb-name PreToolUse hook blocks it without --yes (#71).
- crm solution import now parses the import job's data column into a
solution-level result (success/warning/failure) plus a components
list ({name, type, result, errorcode?, errortext?} per imported component).
Any non-success component adds a meta.warnings note, so a partial failure
under an overall-succeeded async op (status: succeeded) is no longer masked.
crm solution import-result <import_job_id> re-fetches a completed job and
runs the same parser to verify a prior import without re-importing. Both accept
--formatted to also attach the Excel-format RetrieveFormattedImportJobResults
report verbatim under formatted_results (opt-in, a separate round-trip) (#70).
- crm metadata delete-attribute <entity> <attribute> and
crm metadata delete-relationship <schema-name> delete a custom column or a
custom relationship (1:N or N:N). Both pre-flight against the metadata to refuse
managed and non-custom targets client-side; delete-attribute additionally
refuses primary (id/name) and sub-attribute (AttributeOf-set) columns. Each
honors --solution (sent as MSCRM.SolutionUniqueName) and is gated as a
destructive operation: each prompts for confirmation, aborting cleanly in a
non-TTY context unless --yes is passed, and the verb-name PreToolUse hook
blocks them without --yes. Remaining-dependency conflicts are left to the
server's 4xx (#69).
- crm metadata describe <entity> returns a one-shot, read-only write-readiness
brief: the entity set name, primary id/name, and every writable attribute with
its required level. Lookups carry bind_key (<Nav>@odata.bind, self-derived
from ManyToOne relationship metadata) plus targets[] with both the logical
name and the EntitySetName so the bind VALUE is usable; picklist / state /
status attributes carry inline {value, label} options, and a picklist bound to
a global option set also carries its global_optionset_id GUID (which on-prem
9.1 needs to bind on create). Built from pure GETs, gated so only the attribute
kinds an entity actually uses cost a round-trip (#68).
- crm solution import is now gated as a destructive operation: an overwrite
import (the default) clobbers unmanaged customizations in the target org, so it
prompts for confirmation and, in a non-TTY context, aborts cleanly (exit 1;
under --json the body is the standard {"ok": false, "error": "aborted by
user"} envelope, otherwise a human-formatted error) unless --yes is passed.
The PreToolUse destructive-op gate also blocks any crm solution import without
--yes (verb-only, so a --no-overwrite import is gated too — any import
mutates the org). Default import semantics are unchanged (#67).
- crm solution set-version <unique_name> updates an unmanaged solution's
version / friendlyname / description in place. At least one field is
required and --version is validated as 4-part dotted numeric before any HTTP;
managed solutions and patches are rejected client-side (the server returns
CannotUpdateSolutionPatch for a patch). Delegates to the shared record-update
path, so If-Match:* and --dry-run are reused with no new HTTP path (#66).
- Non-interactive REPL guard: bare crm (no subcommand) now fails fast with
exit 2 and a usage message pointing at crm --help whenever the caller is
non-interactive — under --json, with CRM_NO_REPL set (1/true/yes/on),
or when stdin is not a TTY (piped/redirected, as agents and CI invoke it). Under
--json the message is the standard {ok:false,error} envelope; otherwise it
goes to stderr. An interactive human and explicit crm repl still launch the
REPL. A proactive isatty probe so an agent invocation never hangs (#65).
- Structured warnings channel: the JSON envelope now carries a meta.warnings
array — the single place to scan for advisories (staged-but-unpublished,
created-but-read-back-failed, partial-optionset). *_lookup_error read-back
keys are mirrored into it (and left in data for back-compat), and a
non-transactional optionset update that fails mid-stage surfaces
meta.completed_steps / meta.failed_stage on the error envelope so a partial
mutation is observable. Every other error site is unchanged (#64).
Changed
- Breaking (envelope): the singular meta.warning scalar is replaced by the
meta.warnings array, so multiple advisories no longer clobber each other (#64).
Fixed
- crm metadata update-optionset --dry-run previously returned {"updated": true, ...},
incorrectly signalling a completed write. Under dry-run it now returns
{"_dry_run": true, "name": ..., "diff": {...}, "actions": [...]} (#77).
The diff classifies each pending change as inserts / updates (with
old_label / new_label looked up from the live option set) / deletes (with
old_label) / reorder ({old, new} value lists). The live GET fires for real
to build the diff; no POSTs are issued.
[0.9.0] — 2026-06-04
Added
- crm describe [GROUP]: machine-readable command/option/choice discovery. Walks
the live Click tree (no live D365 connection, no mkdocs-click dependency) and in
--json mode emits {ok, data:{root_options, commands:[{name, path, help,
is_group, args, params}]}}. Each option carries name, opts, secondary_opts,
type, required, is_flag, multiple, choices, default, envvar (secondary_opts
holds the off-form of a flag-pair, e.g. --no-publish); Choice enums (ownership, the 14
attribute kinds, if-exists, cascade behaviors, …) are surfaced verbatim. Root
sticky globals (--json, --dry-run, --profile, --auth-scheme,
--log-level, --stage-only, --session, …) are listed under root_options.
The interactive repl leaf is excluded. describe <group> scopes to one
subtree, importing just that module (a lazy win over the full walk) (#63).
- Agent-readable docs surface: the docs site now publishes llms.txt (curated
index, per llmstxt.org) and llms-full.txt (every page
concatenated into one fetch) at the site root, generated at build time by the
mkdocs-llmstxt plugin from the existing docs/ tree. Any agent with web
access — not just skill-aware harnesses loading crm/skills/SKILL.md — can pull
the full CLI reference and how-tos from <site>/llms-full.txt. Adds a docs-only
dependency on mkdocs-llmstxt.
- crm apply -f spec.yaml: declarative desired-state from a single YAML/JSON
spec. Orchestrates the existing metadata cores in dependency order (publisher →
solution → entities → option sets → attributes → relationships → views), each
with if_exists=skip, and runs PublishAllXml once at the end, so re-applying
an unchanged spec is a no-op. Emits {ok, data:{applied, skipped, planned,
failed}, meta:{staged}}. Honors --dry-run (greenfield specs report
dependents as planned-create instead of erroring) and --stage-only (create
without publishing). Metadata POSTs are non-transactional, so a failure
aborts-and-reports, leaving staged-but-unpublished residue. The spec is
validated up front. Adds a runtime dependency on PyYAML (#60).
- Machine-readable error taxonomy: in --json mode the error envelope now carries
meta.category (a closed enum: not_found, auth_failed, forbidden,
concurrency_conflict, duplicate_detected, validation, throttled,
server_error, transport_error) and meta.retryable, alongside the existing
meta.status / meta.code. Classification is status-first, with two D365 error
codes (0x80040217 → not_found, 0x80040237 → duplicate_detected) honored
regardless of status; retryable is true only for the transient classes. The
backend auto-retries the transport_error / throttled (429) / server_error
(5xx) classes, so for those retryable is a post-exhaustion hint;
concurrency_conflict (412) is not auto-retried — the caller refetches a fresh
ETag and retries. The status-less transport path now carries a transport_error
signal, and the fragile MissingPrivilege message-substring synthesis is
subsumed (403 → forbidden) (#62).
- Canonical meta.dry_run signal: in --json mode every dry-run invocation now
carries meta.dry_run: true in the envelope. It is keyed off the invocation-level
--dry-run flag (not by sniffing the data for the _dry_run sentinel), so
list-shaped batch previews and poll previews are covered uniformly and forced-real
existence-probe GETs do not false-positive. Existing meta keys (e.g. staged)
are preserved; the in-data _dry_run sentinel is retained for back-compat (#61).
Changed
- Bundled agent skill (crm/skills/SKILL.md) is now fully standalone — it reads
correctly once crm skill install drops it into a harness skill dir, with no
references to files that don't ship alongside it. Install section shows the
per-host one-liners (install.ps1 / install.sh) instead of pip install -e .;
removed repo-only pointers (D365.md, crm/tests/TEST.md, README.md,
docs/adr/…, docs/how-to/apply.md, the .claude/hooks gate) in favor of
in-CLI discovery (crm describe, crm <group> --help); broadened the
frontmatter description to cover both on-prem (NTLM) and Dataverse online (OAuth).
- Docs examples and test fixtures now use a neutral contoso org/publisher prefix
(contoso_, host internalcrm.contoso.local) instead of an internal org name,
so the published docs and shipped SKILL.md carry no environment-specific names.
[0.8.0] — 2026-06-04
Added
- Installer SHA-256 integrity verification: install.sh / install.ps1 verify the
downloaded archive against a published SHA256SUMS (uploaded per release to
<tag>/ and latest/ in R2) before extracting, and abort on a mismatch or if it
can't be fetched. CRM_SHA256 / $env:CRM_SHA256 pins a hash out-of-band (#46).
- Cloud impersonation by Entra ID object id via the CallerObjectId header:
new --as-user-object-id <guid> flag (alongside --as-user) and
CRM_AS_USER_OBJECT_ID env default, on every command that already carries
--as-user. Header selection is by which input you supply, independent of
auth_scheme; --as-user (MSCRMCallerID) and --as-user-object-id
(CallerObjectId) are mutually exclusive per request (#54).
- CHANGELOG is now published on the docs site at /changelog/, rendered
from this file via mkdocs-include-markdown-plugin.
0.7.0 — Fast startup + R2 install
Performance
- CLI subcommands and the D365 backend stack now load lazily: crm --version and
direct command invocations no longer import every command module (and their
requests/NTLM/prompt_toolkit dependencies), cutting cold startup substantially.
crm --help still loads all modules (accepted trade-off).
Changed
- PyInstaller builds switched from --onefile to --onedir (dist/crm/),
eliminating per-launch self-extraction overhead.
- Install is now a one-line script served from a public Cloudflare R2 bucket
(irm …/install.ps1 | iex on Windows, curl …/install.sh | sh on Linux),
replacing the private-repo GitHub release URL that 404'd for users.
Added
- scripts/install.ps1 (Windows) and scripts/install.sh (Linux): download the
prebuilt onedir bundle from R2, install to a user dir, wire up PATH / a symlink,
and support uninstall.
0.6.0 — Spec E: DX Polish
Refactor
- Split crm/cli.py (2098 lines) into focused modules under crm/commands/
(one Click group per file). Pure refactor — zero behavior change.
Added
- --log-level debug|info|warning|error + --log-format text|json-line on
the root CLI group (env: CRM_LOG_LEVEL, CRM_LOG_FORMAT).
- --verbose flag (alias for --log-level debug).
- --auth-scheme ntlm|kerberos|negotiate on the root CLI group
(env: CRM_AUTH_SCHEME). Kerberos/Negotiate via requests_negotiate_sspi
(install with pip install crm[kerberos]).
- crm init command: --template writes .env.example; no args runs an
interactive profile wizard.
- query count <entity> — calls RetrieveTotalRecordCount.
- metadata list-actions — parses $metadata and lists OData actions.
- metadata list-functions — parses $metadata and lists OData functions.
- REPL tab completion for entity-name argument slots, backed by a lazy
in-memory MetadataCache.
Changed
- ConnectionProfile gains an auth_scheme field (default "ntlm",
backward compatible).
- crm/utils/repl_skin.py::create_prompt_session accepts an optional
completer argument.
[0.5.0] — 2026-05-25
Added
metadata add-attribute— add columns to existing entities. Supports 14 attribute kinds: string, memo, integer, bigint, decimal, double, money, boolean, datetime, picklist, multiselect, lookup, image, file.metadata create-one-to-many+metadata create-many-to-many— create 1:N and N:N relationships via the dedicated Dataverse actions.- Global option set CRUD:
metadata list-optionsets,get-optionset,create-optionset,update-optionset,delete-optionset.updateis granular:--insert-option/--update-option/--delete-option/--reorderflags map to the matching bound actions. metadata delete-entity— drop a custom table, guarded by interactive confirm +--yesskip + client-sideIsCustomEntity+IsManagedpre-flight check.
All new write verbs accept --solution <uniquename> (header
MSCRM.SolutionUniqueName) and --publish/--no-publish (default ON),
matching metadata create-entity. Delete verbs skip publish.
0.4.0 — 2026-05-25
This release lands Spec C from the post-code-review roadmap: $batch
support, on-prem-correct impersonation via MSCRMCallerID, two admin
headers for write paths, an asyncoperations browse surface, and
explicit optimistic concurrency via If-Match. See
docs/superpowers/specs/2026-05-24-spec-c-throughput-admin-design.md
for the full design.
Added
D365Backend.batch(operations, *, transactional=True, continue_on_error=False, timeout=None)— execute a list of operations via POST$batch. Consecutive writes are auto-grouped into one changeset; GETs go as top-level operations.crm batch <file.json>CLI command with--no-transaction,--continue-on-error,--output,--timeoutflags.- Backend typed kwargs on every verb:
caller_id,suppress_duplicate_detection,bypass_custom_plugin_execution,etag. Env defaults:CRM_AS_USER,CRM_SUPPRESS_DUP,CRM_BYPASS_PLUGINS. - Per-command CLI flags on every write/action verb:
--as-user <guid>,--suppress-dup-detection,--bypass-plugins.--if-match <etag>onentity updateandentity delete. crm async list/get/cancelpluscrm solution job-status / job-cancelaliases.- New TypedDicts:
BatchOperation,BatchResult,AsyncOperationRow.
Changed
- HTTP
412responses now map toD365Error(code="PreconditionFailed"). - HTTP
403responses whose body referencesprvBypassCustomPluginExecutionmap toD365Error(code="MissingPrivilege").
Deferred
CreateMultiple/UpdateMultiple/UpsertMultiple— Dataverse cloud only; not present on Contoso 9.1.x on-prem.CallerObjectIdimpersonation header — requires Microsoft Entra ID; on-prem AD users useMSCRMCallerID.- Server-side
$batchsize limits (typical Dataverse: 100 changesets per batch; 1000 ops per changeset) are not enforced client-side; the server'sMaxBatchSize/MaxChangesetSizeerror surfaces verbatim.
Notes for callers
POST $batchis retried only on429and503(Spec B conservative-POST policy). A retried batch re-sends the assembled body verbatim — idempotency is the caller's responsibility.
0.3.0 — 2026-05-24
This release lands Spec B from the post-code-review roadmap: a retry
layer on every HTTP call plus a switch to the asynchronous variants of
ImportSolution and ExportSolution. See
docs/superpowers/specs/2026-05-24-spec-b-resilience-design.md for the
full design.
Breaking
crm.core.solution.import_solutionreturn shape changes. Now returns{import_job_id, async_operation_id, status, progress, started_on, completed_on, duration_ms}. Any caller reading the old ImportSolution response keys (ImportJobKey, etc.) must switch.crm.core.solution.export_solutionreturn shape gains keys. New fields:async_operation_id,export_job_id,duration_ms. The existingoutput,bytes,managed,solutionkeys are preserved.- Both functions can now block for up to
CRM_ASYNC_TIMEOUTseconds (default 1800). The sync versions blocked for up toprofile.timeoutseconds per HTTP call (default 120) with no client-side polling.
Added
D365Backend.requestnow retries on429, idempotent5xx(502/503/504onGET/PUT/PATCH/DELETE;503only onPOST), and retryable transport errors (ConnectionError,Timeout,ChunkedEncodingError). HonorsRetry-After; falls back to capped exponential backoff with full jitter.D365Backend.poll_async_operation(async_operation_id, *, timeout, import_job_id, on_progress)— blocks until anasyncoperations(<id>)row reachesstatecode=3. RaisesD365Erroron failure (statuscode=31), cancellation (32), or timeout.ConnectionProfilegains seven new fields:retry_max,retry_base_delay,retry_max_delay,retry_jitter,async_poll_initial,async_poll_max,async_timeout.- Env overrides:
CRM_RETRY_MAX,CRM_RETRY_BASE_DELAY,CRM_RETRY_MAX_DELAY,CRM_RETRY_JITTER,CRM_ASYNC_TIMEOUT,CRM_NO_RETRY. Env wins over profile. - New CLI flags on
crm solution exportandcrm solution import:--timeout N(overrideasync_timeoutfor this call),--no-retry(setCRM_NO_RETRY=1for this call).crm solution importalso gets--quiet/-qto suppress per-tick progress lines. x-ms-ratelimit-*headers are logged to stderr on every retried 429, and on every response underCRM_VERBOSE=1.
Changed
crm solution importandcrm solution exportnow block until the async operation reports completion, emitting per-tick progress to stderr (import only; suppress with--quiet).
0.2.0 — 2026-05-24
This release lands Spec A from the post-code-review roadmap: nine correctness
fixes plus pyright strict (zone-scoped) across crm/core/* and
crm/utils/d365_backend.py. See
docs/superpowers/specs/2026-05-24-spec-a-correctness-pyright-design.md for
the full design.
Breaking
- Error envelope
meta.statusandmeta.codenow emit JSONnullwhen absent, instead of the literal string"n/a". Scripts that string-match"n/a"must switch to a null check. (§3.5)
Added
--export-setting <name>flag oncrm solution export, repeatable. Accepted names:autonumbering,calendar,customizations,email-tracking,general,isv-config,marketing,outlook-sync,relationship-roles,sales. (§3.6)crm/utils/d365_types.py—TypedDictshapes for Web API responses.pyright(>=1.1.380) as a dev dependency and a CI step in.github/workflows/build.yml. Strict mode oncrm/core/*+crm/utils/d365_backend.py; basic mode (via file-level# pyright: basicpragma) oncrm/cli.py,crm/utils/repl_skin.py, andcrm/tests/*.
Changed
metadata create-entitynow readsEntitySetNameback from the server instead of guessing it via English pluralisation. Adds one round-trip per create call. On read-back failure the entity is still reported as created, withentity_set_name: nulland a diagnosticentity_set_lookup_errorfield. (§3.3)- REPL keeps a single
D365Backendper session instead of rebuilding on every command. Invalidated byconnection connect/connection disconnect. (§3.7) $countqueries parsetext/plaindirectly in one HTTP call on the happy path. Falls back to?$count=trueif the body is missing or non-numeric. (§3.9)fetchxml_querypasses the FetchXML viaparams=instead of manual URL concatenation. No on-wire change. (§3.4)
Fixed
entity createno longer sends the non-specIf-None-Match: nullheader on POST. (§3.1)data exportCSV no longer leaks_valuelookup columns and@odata.*annotations into headers —_ordered_keysboolean precedence bug. (§3.2).envvalue parser is now pair-aware:KEY="foo's bar"resolves tofoo's bar, notfoos bar. (§3.8)