feat: full nanoflow support — CREATE, DROP, SHOW, DESCRIBE, DIFF, MERMAID, security, and agentic skill#301
Conversation
1c71d9f to
5b17c36
Compare
AI Code ReviewWhat Looks GoodThe PR implements comprehensive nanoflow support, bringing it to full feature parity with microflows. Key strengths:
The implementation follows all MDL syntax design guidelines:
RecommendationApprove the PR. The implementation is complete, well-tested, and follows all project conventions. The nanoflow support addresses a significant gap in the feature set and enables agentic workflows for nanoflow management as intended. No blocking issues were identified. The PR is ready to merge. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
74e5ea1 to
8b23f02
Compare
AI Code ReviewReview SummaryThis PR implements full nanoflow support in mxcli, closing a significant gap in the MDL feature matrix. The changes are thorough and follow the established patterns for MDL feature implementation. Critical IssuesNone found. Moderate IssuesNone found. Minor Issues
What Looks Good
RecommendationApprove the PR. The changes are high-quality, thoroughly tested, and fully address the nanoflow support gap. The minor test coverage gap for diff output is acknowledged in the test plan and covered by manual validation; it does not block merging given the overall strength of the implementation. No blocker issues were identified. The PR successfully enables agentic workflows to scaffold, refactor, Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
8b23f02 to
d680f33
Compare
AI Code ReviewWhat Looks GoodThe PR successfully implements full nanoflow support with excellent attention to detail:
The implementation follows all MDL syntax design guidelines:
RecommendationApprove - The PR is production-ready with comprehensive test coverage, proper architectural implementation, and excellent documentation. All checklist items have been satisfactorily addressed. The nanoflow support brings the CLI to feature parity with microflows as intended. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
c4e4ebe to
6c0dad8
Compare
ako
left a comment
There was a problem hiding this comment.
PR #301 Review — feat: full nanoflow support
Overview
Very comprehensive PR bringing nanoflows to feature parity with microflows: CREATE/DROP/GRANT/REVOKE/MOVE/RENAME, JavaScript action support, association retrieve roundtrip fix, empty-then optimization, Mermaid/ELK diagram parity, and VS Code extension nanoflow context menus. Full-stack pipeline coverage with good test counts (33 integration + 36 mock unit + 5 BSON roundtrip).
Pipeline checklist
| Layer | Status |
|---|---|
| Grammar (createNanoflowStatement, grantNanoflowAccess, etc.) | ✓ |
| Parser regenerated | ✓ |
| AST nodes (CallNanoflowStmt, CallJavaScriptActionStmt, etc.) | ✓ |
| Visitor | ✓ |
| Builder (addCallNanoflowAction, addCallJavaScriptActionAction) | ✓ |
| Formatter (NanoflowCallAction, JavaScriptActionCallAction cases) | ✓ |
| Parser BSON (AllowedModuleRoles, ObjectCollection, ReturnType) | ✓ |
| Writer BSON (serializeNanoflow fully rewritten) | ✓ |
| Security (grant/revoke/show access) | ✓ |
| Validation (21-action denylist, binary return type check) | ✓ |
| ELK/Mermaid/Diff | ✓ |
| VS Code extension | ✓ |
Issues
1. DownloadFileStmt missing from nanoflow denylist
The bson-mapping doc added in this PR explicitly lists Microflows as a server-side-only action that cannot be used in nanoflows. But checkDisallowedNanoflowAction in nanoflow_validation.go does not include a case *ast.DownloadFileStmt entry. The denylist comment says "when adding new action AST types, check whether they are available in nanoflows" — DownloadFileStmt (added in PR #333) needs that case:
case *ast.DownloadFileStmt:
return "download file is not allowed in nanoflows"Without it, create nanoflow will silently accept and write a DownloadFileAction that Studio Pro will reject with CE6007 (or similar).
2. AllowedModuleRoles type mismatch in grant/revoke
In execGrantNanoflowAccess, the existing roles from the parsed nanoflow are model.ID values (UUIDs from BSON) but the new roles from the MDL statement are qualified-name strings ("Module.Role"):
for _, r := range nf.AllowedModuleRoles { // model.ID — UUID strings
merged = append(merged, string(r))
}
for _, role := range s.Roles {
qn := role.Module + "." + role.Name // qualified name strings
merged = append(merged, qn)
}
ctx.Backend.UpdateAllowedRoles(nf.ID, merged) // mix of IDs and namesIf UpdateAllowedRoles writes the slice as-is to BSON, the next parseNanoflow round will have a mix of real UUIDs and unresolvable role names. This is the same pattern used in the microflow grant/revoke, so either the backend resolves them or both commands have the same bug — but it's worth verifying that UpdateAllowedRoles normalises to IDs before writing.
3. lookupNanoflowReturnType calls ListNanoflows() per invocation
For each call nanoflow statement encountered during flow graph build, lookupNanoflowReturnType calls fb.backend.ListNanoflows() (a backend read) and then fb.backend.GetModuleByName(). For a microflow that calls N nanoflows this is 2N backend reads. The microflow equivalent lookupMicroflowReturnType has the same pattern, so it's consistent, but caching the nanoflow list in flowBuilder (like fb.nanoflows) would make this O(1) amortised. Flag for a follow-up if performance becomes visible on large projects.
Correctness notes (positive)
int32(2) for parameter mapping arrays confirmed correct — The writer uses int32(2) as the BSON array sentinel for NanoflowCallParameterMapping and JavaScriptActionParameterMapping. This is consistent with the existing microflow call parameter mapping serialization and is the correct Mendix sentinel for arrays of mapping documents (distinct from int32(3) for object collection arrays).
Association retrieve simplification is sound — Removing the reverse-traversal XPath rewrite in favour of always using AssociationRetrieveSource is the correct fix. Studio Pro resolves traversal direction from association metadata at runtime; the old XPath rewrite was fragile and broke DESCRIBE roundtrip.
negateIfCondition double-negation guard is correct — The paren-depth tracker in the not(x) unwrap path correctly rejects unbalanced inputs (e.g., not() or )) and the test cases cover the edge cases.
Empty-then swap applied in both traversal functions — The optimization is correctly duplicated in both traverseFlow and traverseFlowUntilMerge. Note that the second location also removes the empty else block after the swap; the first does not. This asymmetry is harmless (the first location's empty else is pruned naturally by the outer loop) but worth confirming.
Nit
The getErrorHandling function in nanoflow_validation.go includes cases for disallowed action types (CallJavaActionStmt, RestCallStmt, etc.). The comment explains this is safe because the denylist is checked first (via continue). That ordering guarantee holds today, but is fragile — if the loop order in validateNanoflowStatements ever changes (e.g., recursion before denylist check), unreachable error handlers on disallowed actions would be silently traversed. Consider removing the disallowed types from getErrorHandling since their error handlers can never be reached after the denylist blocks them.
Summary
Item 1 (DownloadFileStmt in denylist) is the only blocking issue — it's a one-line fix that prevents silent Studio Pro rejection. Item 2 (ID/name mix in UpdateAllowedRoles) should be verified against the backend implementation. Everything else is solid. The BSON roundtrip tests and the explicit denylist maintenance warning in the comment are exactly the right defensive patterns for a feature of this scope.
ako
left a comment
There was a problem hiding this comment.
PR #301 — Supplemental Review (Checklist Pass)
Following a full walk of the CLAUDE.md PR checklist, here are findings not covered in the first review.
Documentation gaps
1. CLAUDE.md skill table does not list write-nanoflows.md — Moderate
The "IMPORTANT: Before Writing MDL Scripts" section in CLAUDE.md lists every skill agents should read before writing MDL (write-microflows.md, create-page.md, etc.). write-nanoflows.md is absent. Without this entry, agents working on nanoflow tasks won't know the skill exists.
Fix: add one line to the skill table in CLAUDE.md:
- `.claude/skills/write-nanoflows.md` - **READ before writing nanoflows** - Nanoflow syntax, restrictions, security management
2. docs-site/src/ not updated — Moderate
No changes to the docs site are in the diff. The CLAUDE.md checklist says: "Site docs — docs-site/src/ pages added or updated for user-facing features." CREATE/DROP/GRANT nanoflow are all user-facing. This may be intentional if the docs site is published separately, but it should be confirmed or a follow-up issue filed.
LSP completions — Minor
lsp_completions_gen.go is not in the diff. NANOFLOW / NANOFLOWS were already present as bare keywords from before this PR. The new statement forms (call javascript action, grant/revoke execute on nanoflow, create or modify nanoflow) do not have snippet-level completions. This is consistent with how other new statement types have been handled (completions are added separately), but worth tracking.
DESCRIBE roundtrip for call javascript action not explicitly tested — Minor
The formatter emits the JS action's qualified name from a.JavaScriptAction directly. There is no test that takes the formatted output, feeds it back through the parser, and confirms no error (checklist finding #4). Given the existing grammar rule is correct, this is low risk, but a single visitor-level roundtrip test would close the gap.
Mock backend nanoflow stubs — Minor
The checklist requires: "every new backend method has a Func-field stub with a descriptive "MockBackend.X not configured" error default (not nil, nil)." The diff shows ListNanoflowsFunc, DeleteNanoflowFunc, MoveNanoflowFunc in test setup but the zero-value defaults in the mock definition file should be verified to emit the required error string rather than nil, nil. Worth a quick grep of mdl/backend/mock/ to confirm.
|
Thanks for the thorough review, Ako! Pushed a commit addressing your feedback: Addressed
AllowedModuleRoles — not a bugI investigated this one carefully.
The Deferred
All tests pass. Let me know if anything else needs attention! |
|
Update: Also added the LSP snippet completions in a follow-up commit:
These show up in the general completion context for both microflow and nanoflow bodies. |
8b6af58 to
e7098cf
Compare
Manual QA Results — Nanoflow Feature ParityBinary: All sections pass — zero regressions
Roundtrip diff categories (all pre-existing, not from this PR)
Automated tests
|
QA Session 5 — Parser Fixes Verified (c35c589)Binary: Parser fixes — all 5 previously-unparseable nanoflows now pass
Full regression test — all sections pass
Known pre-existing issue (not from this PR)
Automated
|
- SHOW ACCESS ON NANOFLOW — query nanoflow security grants - DESCRIBE MERMAID for nanoflows via CLI --format mermaid - Nanoflow diff support — unified diff output for modified nanoflows - JavaScript action BSON parsing (read path) - NanoflowCallAction formatter for DESCRIBE output - Hard-code nanoflow $Type to "Microflows$Nanoflow" - Preserve AllowedModuleRoles through drop/recreate cycles - Validate module existence, numeric return types, empty names - Normalize empty-then branches in DESCRIBE for readable if/else - Expression spacing fix (not() parenthesization)
- Document intentional behaviors in nanoflow test plan - Add nanoflow references to ARCHITECTURE, CLAUDE, CHANGELOG - Update MDL_FEATURE_MATRIX, MDL_QUICK_REFERENCE, language reference - Add nanoflow examples to agentic skills (security, pages, validation) - Add nanoflow MDL examples to doctype-tests
- Propagate describeNanoflow errors in diff command - Match create-or-modify pattern in diff output - Add nanoflow-specific fields (@excluded, folder, comment) to MDL output - Guard empty-then swap edge case in if/else normalization - Handle missing JS action references gracefully in formatter - Harden negation expression rendering
…e fix Full pipeline for `call javascript action` syntax: - Grammar rule, AST node, visitor, builder, validator, BSON serializer - JavaScript actions allowed in nanoflows (client-side), disallowed check skips them correctly - Separate JS action reference validation from Java action validation Association retrieve roundtrip fix: - Preserve AssociationRetrieveSource on roundtrip instead of converting to DatabaseRetrieveSource with XPath for reverse traversals
…ixes
- Add Nanoflow Mapping section to BSON mapping documentation
- Add create_nanoflow Go example with 4 nanoflow patterns
- Update CHANGELOG with JS action syntax and association retrieve entries
- Add nanoflow datasource option to create-page skill
- Update SDK_EQUIVALENCE nanoflow feature list
- Exhaustive nanoflow denylist test (21 disallowed + JS action allowed)
- Document denylist ordering dependency in error handling
- Fix isNumericLiteral: reject trailing dot ("5." → false)
Add nanoflow visualization via --format elk. Backend: refactor buildMicroflowELK into generic buildFlowELK with flowELKInput struct, add nanoflowELK() + describeNanoflowToString(), parameterize renderMicroflowMDL with flowType. Frontend: add nanoflow to diagram context menus and preview title handling. Fix swallowed ListDomainModels error in both microflowELK and nanoflowELK.
- Propagate ListDomainModels error in describeNanoflowToString - Use shared buildEntityNames() in both microflow and nanoflow ELK paths - Remove Commit/Rollback from BSON mapping disallowed list (allowed by implementation) - Fix example: add missing 'in' keyword in show nanoflows - Fix proposal: CREATE OR REPLACE to CREATE OR MODIFY, correct nanoflow count - Add clarifying comments for best-effort errors, Rollback default, BSON key asymmetry
…s, improve mocks/docs - Add DownloadFileStmt to nanoflow denylist - Remove unreachable cases from getErrorHandling - Cache ListNanoflows/ListMicroflows in flowBuilder (bool flag for empty-slice safety) - Mock nanoflow stubs return descriptive errors - Add roundtrip test for CallJavaScriptAction (with t.Skip guard) - Add write-nanoflows.md skill file + CLAUDE.md entry - Add security cross-reference in docs-site nanoflows.md
- CREATE NANOFLOW (with params) snippet - CALL MICROFLOW, CALL NANOFLOW, CALL JAVASCRIPT ACTION, CALL JAVA ACTION snippets
…cates, embedded JSON, if-in-loop - Remove leading -? from NUMBER_LITERAL lexer rule; negation handled by unaryExpression - Split multi-predicate XPath constraints at ][ boundaries in retrieve formatter - Escape newlines inside string literal regions in expression values - Add ExclusiveSplit handling to traverseLoopBody for if/else inside while/loop
….' placeholder Empty parameter values (nil, empty string) in JavaScript and Java action calls are now omitted from the argument list. Previously they were emitted as 'Param = ...' which is not valid MDL syntax. Fixes LatoBikesUI.ACT_Login (UseAuthToken with empty value).
135b741 to
ae49ce7
Compare
Full Manual QA Report — Session 6 (2026-04-29)Branch: Results Summary
Totals: 268 tests executed, 268 pass, 0 failures. Roundtrip DetailsAll 223 nanoflows across 3 projects pass
Key Verifications Since Last Report
Known Issues (unchanged, pre-existing)
|
…e flow body checks - Add nanoflows to allNames() for forward-reference detection in validate - Add ValidateNanoflowBody call for semantic checks (undeclared vars, missing returns) - Extract shared validateFlowBody helper from ValidateMicroflowBody/ValidateNanoflowBody - Add GetRawUnitByName fast-path to lookupNanoflowReturnType (mirrors microflow pattern) - Collapse 11 individual workflow stmt cases into multi-type case in nanoflow denylist - Fix doc comment on addTransformJsonAction (was copy-pasted from addExportToMappingAction)
ae49ce7 to
3954e54
Compare
373fc8b to
9ac9dbb
Compare
AI Code ReviewReview SummaryThis PR implements full nanoflow support in mxcli, bringing it to parity with microflows across the entire stack. The changes are comprehensive and well-executed. What Looks Good
Moderate Issues
Minor Issues
RecommendationApprove the PR. The implementation is thorough, follows all architectural guidelines, and includes proper testing and documentation. The maintenance concern about disallowed actions is common in such projects and doesn't block merging given the comprehensive test coverage that would catch regressions. The PR successfully closes the nanoflow feature gap mentioned in the feature matrix and enables agentic workflows for nanoflow scaffolding, refactoring, and security management. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
- Move JS action call and ELK layout from Future Work to Completed in proposal - Fix stale action counts in proposal (25/32+ → actual ~16 case branches) - Expand disallowed activities list in docs-site nanoflows.md (add DOWNLOAD FILE, REST, workflow, etc.) - Add CALL JAVASCRIPT ACTION to docs-site calling examples - Add CHANGELOG entries: LSP snippets, parser fixes, validation parity, DownloadFileStmt, flow cache, empty params - Update feature matrix: nanoflow Tests column N → Y - Document ValidateNanoflowBody/validateFlowBody and flow builder cache in parser architecture - Add CALL JAVASCRIPT/JAVA ACTION and nanoflow restrictions to quick reference - Update CLAUDE.md implementation status line
9ac9dbb to
f914d3d
Compare
Addressing AI Review Moderate IssuesDisallowed actions maintenanceThe denylist in An allowlist approach was considered but rejected: nanoflows share the microflow AST, and new action types should default to allowed (client-side) unless explicitly flagged as server-side-only. The denylist approach matches Mendix's own model where nanoflows are "microflows minus server-side actions." Changelog wordingRenamed "Nanoflow bug fixes" → "Flow bug fixes" since the fixes (module validation, empty names, numeric returns) genuinely apply to both microflows and nanoflows. Expanded the slash notation to be clearer. Documentation self-reviewRan 7 rounds of doc self-review (26 total findings fixed):
|
AI Code ReviewReview SummaryAfter reviewing this PR against the CLAUDE.md checklist, I find it implements nanoflow support comprehensively while adhering to project guidelines. The changes span the full pipeline from grammar to VS Code extension with proper test coverage. Critical Issues
Moderate Issues
Minor Issues
What Looks Good
Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
Why
Nanoflows are a core Mendix document type for mobile and offline-first apps. Until this PR, mxcli had read-only nanoflow support (SHOW, DESCRIBE) but could not create, modify, or manage nanoflows — blocking agentic workflows that need to scaffold, refactor, or secure nanoflow logic.
This gap was visible in the feature matrix: nanoflows lagged far behind microflows in every dimension. This PR brings nanoflows to full feature parity with microflows across grammar, executor, SDK, validation, visualization, and security management.
Proposal: docs/11-proposals/PROPOSAL_nanoflow_support.md
Test plan: docs/15-testing/nanoflow-test-cases.md (19 sections, 126 test cases)
What Changed
New MDL commands
CREATE [OR MODIFY] NANOFLOWDROP NANOFLOWCALL NANOFLOWCALL JAVASCRIPT ACTIONGRANT EXECUTE ON NANOFLOWREVOKE EXECUTE ON NANOFLOWSHOW ACCESS ON NANOFLOWMOVE NANOFLOWRENAME NANOFLOWDIFF(nanoflow support).mprversionsCLI enhancements
describe nanoflow --format mermaid— generates Mermaid flowchart diagrams for nanoflowsdescribe nanoflow --format elk— generates ELK JSON layout data for nanoflow visualization in VS CodeCREATE NANOFLOW (with params),CALL MICROFLOW,CALL NANOFLOW,CALL JAVASCRIPT ACTION,CALL JAVA ACTIONsnippets in the language serverVS Code extension
Show DiagramandShow Diagram with Source) — uses the same ELK.js renderer as microflows, with bidirectional source-map syncValidation
Type-switch validation rejects 21 action types that Mendix does not allow in nanoflows (Java actions, REST calls, workflow actions, import/export mappings, file downloads, etc.). Entity resolver errors propagate upfront — no silent failures on invalid parameter or return types.
ValidateNanoflowBodyprovides the same semantic checks (undeclared variables, missing returns, branch scoping) asValidateMicroflowBodyvia sharedvalidateFlowBodyhelper.Parser and formatter fixes
-?fromNUMBER_LITERALlexer rule — negation now handled byunaryExpression, fixing expressions like$var -2that were incorrectly tokenized.[pred1][pred2]XPath constraints instead of stripping only outermost brackets.escapeExpressionValue()to escape\n/\r/\tinside single-quoted string regions (e.g. embedded JSON in change object actions).ExclusiveSplithandling totraverseLoopBody— if/else blocks inside while/loop bodies now emit correctly withend if;....or bare= ).lookupNanoflowReturnTypeandlookupMicroflowReturnTypelazily cache results with bool flags (handles empty-slice-from-backend correctly). Both includeGetRawUnitByNamefast-path before module walk.allNames()in validator now includes nanoflows.Bug fixes and improvements
call javascript action Module.ActionName(params)— grammar rule, parser, AST node, visitor, builder, validation, serializer. JS actions roundtrip correctly through describe → drop → create cycle.retrieve $X from $Y/Module.Associationsyntax preserved on roundtrip. Previously, the builder converted association retrieves to database retrieves with XPath constraints on reverse traversals.serializeNanoflow()was incomplete — missing ReturnType, ObjectCollection, and Flows. Created nanoflows lost their body when written to.mpr.NanoflowCallActionBSON field corrected fromResultVariableNametoOutputVariableName.$prefix.NanoflowCallActionerror handling type resolved correctly.not()expression spacing preserved on roundtrip.NanoflowCallAction.AllowedModuleRolespreserved through drop/recreate cycle.ListDomainModelserrors now propagated in all ELK and describe paths (previously swallowed).buildFlowELKextracted as generic flow renderer withflowELKInputstruct, replacing microflow-specificbuildMicroflowELK.nil, nil.Agentic skill
New Claude Code skill at
.claude/skills/mendix/write-nanoflows.md— guides AI agents through nanoflow creation with MDL syntax, parameter types, body actions, security management, and validation rules.Shared helpers
buildEntityNamesextracted to eliminate duplication between microflow and nanoflow ELK and Mermaid rendering.serializeNanoflow()fully rewritten to serialize body, flows, return type, and parameters.renderMicroflowMDLparameterized withflowTypeto support both microflow and nanoflow MDL source generation.describeNanoflowToStringwraps nanoflow as Microflow struct for shared MDL rendering pipeline.validateFlowBodyextracted fromValidateMicroflowBody/ValidateNanoflowBodyto eliminate duplication.Testing
Automated tests (all pass with
make build && make test):roundtrip_nanoflow_test.go) — CREATE, DROP, CALL, GRANT/REVOKE, SHOW, MOVE, RENAME, MERMAID, validation, error pathscmd_nanoflows_mock_test.go) — not-connected guards, duplicate handling, idempotent grant/revoke, all 21 disallowed actions, nested body validationroundtrip_test.go) — parse→serialize→parse cycle with activities, flows, and rolescmd_microflows_format_action_test.go) — empty/nil/mixed param handlingManual testing: 19-section test plan executed across 6 sessions against 3 App Gallery demo projects (223 nanoflows total). Final session (2026-04-29, commit
ae49ce7): 268 tests executed, 268 pass, 0 failures. Full roundtrip (describe→check) passes for all 223 nanoflows across all 3 projects.Known limitations
on error rollbackappended. Does not affect describe→check validation.Documentation updated
MDL_FEATURE_MATRIX.md— nanoflow row reflects implemented stateMDL_QUICK_REFERENCE.md— added CREATE, MOVE, GRANT/REVOKE, SHOW ACCESS nanoflow syntax01-language-reference.md— added CREATE/DROP/GRANT/REVOKE nanoflow sectionsgrammar-reference.md— addedcreateNanoflowStatement,dropNanoflowStatement,callJavaScriptActionStatementPROPOSAL_nanoflow_support.md— rewritten from proposal to feature descriptionnanoflow-test-cases.md— comprehensive QA test plan (19 sections, 126 test cases)10-bson-mapping.md— added Nanoflow Mapping section with type differences, allowed actions, JS action field mappingexamples/create_nanoflow/— new Go example with 4 nanoflow patternsCHANGELOG.md— unreleased entries for all nanoflow featuresSDK_EQUIVALENCE.md— updated nanoflow CRUD feature listdocs-site/src/language/nanoflows.md— added Security section with cross-referencesCLAUDE.md— addedwrite-nanoflows.mdto skill tableStats
92 files changed, +19,287 / −10,947, 16 commits
Grammar → AST → Visitor → Executor → SDK → Tests → Docs → VS Code — full pipeline coverage.