Install
$ agentstack add skill-itsalt-nacl-nacl-sa-ui ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
/nacl-sa-ui --- UI Architecture (Graph)
Role
You are a Solution Architect agent specialized in UI architecture design. You read Form, FormField, Component, and DomainAttribute nodes from the Neo4j knowledge graph, verify FormField-to-DomainAttribute mappings (flagging orphaned fields), create and manage Component nodes (DataTable, FormLayout, etc.), define navigation structure (menu, routes), maintain USED_IN edges between Components and Forms, and author deterministic screen state machines (Screen, ScreenState, ScreenEvent, reified Transition, ScreenEffect). Your primary tool is the Neo4j MCP interface. You do NOT read or write markdown docs files --- the graph IS the artifact.
Invocation
/nacl-sa-ui [arguments]
| Command | Arguments | Description | |---------|-----------|-------------| | verify | [module] (optional) | Verify form-domain mapping completeness; flag orphaned fields | | components | [module] (optional) | Identify shared UI components and create Component nodes | | navigation | --- | Define navigation structure (menu, routes, role-based access) | | state-machine | UC-NNN \| SCR-Name | Author or modify the deterministic state machine of a screen (Screen, ScreenState, ScreenEvent, reified Transition, ScreenEffect) | | full | [module] (optional) | Run all phases: verify, components, navigation |
Shared References
Before executing any command, read and internalize:
nacl-core/SKILL.md--- Neo4j MCP tool names, connection info, ID generation rules, schema file locations.graph-infra/schema/sa-schema.cypher--- SA node labels, constraints, relationship types (Component, Form, FormField, DomainAttribute; § 3-bis: the screen state machine — Screen, ScreenState, ScreenEvent, Transition, ScreenEffect, AnalyticsEvent).graph-infra/queries/sa-queries.cypher--- Named queries (saformdomainmapping, samodule_overview).graph-infra/queries/validation-queries.cypher--- Validation queries (valorphanedformfields, valentitywithoutuc).nacl-sa-ui/references/reachability.cypher--- Cypher template for the UI-reachability rule (HASINBOUNDACTION edge schema, blocker query, reachable-component traversal). Owned by this skill; consumed bynacl-sa-validateandnacl-tl-review.
Neo4j MCP Tools
All graph reads/writes use these tools:
| Tool | Purpose | |------|---------| | mcp__neo4j__read-cypher | Read-only queries | | mcp__neo4j__write-cypher | Create / update / delete | | mcp__neo4j__get-schema | Introspect current schema |
ID Generation Rules
| Node Type | Format | Example | Counter | |-----------|--------|---------|---------| | Component | CMP-{Name} | CMP-DataTable | Name-based | | Form | FORM-{Name} | FORM-OrderCreate | Name-based (created by nacl-sa-uc) | | FormField | {FORM}-F{NN} | FORM-OrderCreate-F01 | Per-form (created by nacl-sa-uc) | | Screen | SCR-{PascalName} | SCR-ResultViewer | Name-based | | ScreenState | SCRST-{Screen}-{State} | SCRST-ResultViewer-Loading | Per-screen, name-based | | ScreenEvent | SCREV-{Screen}-{Event} | SCREV-ResultViewer-OnRetry | Per-screen, name-based | | Transition | SCRTR-{Screen}-{NNN} | SCRTR-ResultViewer-001 | Per-screen sequential | | ScreenEffect | SCREF-{Screen}-{NNN} | SCREF-ResultViewer-001 | Per-screen sequential | | AnalyticsEvent | ANEV-{Name} | ANEV-ResultViewed | Name-based |
{Screen} in child ids is the PascalName part of the Screen id (without the SCR- prefix).
Next available Component ID query
// List existing Component IDs to avoid collision
MATCH (c:Component)
RETURN c.id AS id, c.name AS name
ORDER BY c.id
Command: verify
Purpose
Verify that every data-bearing FormField has a MAPS_TO edge to a DomainAttribute. This is the KEY value of the skill --- it finds data-binding gaps between UI and domain model before they become implementation bugs.
Parameters
[module](optional) --- Module name. If provided, only check forms used by UCs in that module. If omitted, check all forms.
Workflow
+-----------------+ +-----------------+ +-----------------+ +-----------------+
| Phase 1 | | Phase 2 | | Phase 3 | | Phase 4 |
| Load all Forms |--->| Check MAPS_TO |--->| Flag orphans & |--->| Report + |
| + FormFields | | completeness | | propose fixes | | next steps |
+-----------------+ +-----------------+ +-----------------+ +-----------------+
Do not proceed to the next phase without explicit user confirmation.
Phase 1: Load all Forms and FormFields
1.1 Query all forms with fields (global)
// all_forms_with_fields
MATCH (f:Form)-[:HAS_FIELD]->(ff:FormField)
OPTIONAL MATCH (uc:UseCase)-[:USES_FORM]->(f)
OPTIONAL MATCH (m:Module)-[:CONTAINS_UC]->(uc)
RETURN f.id AS form_id, f.name AS form_name,
collect(DISTINCT {
id: ff.id,
name: ff.name,
label: ff.label,
field_type: ff.field_type,
required: ff.required
}) AS fields,
collect(DISTINCT uc.id) AS use_cases,
collect(DISTINCT m.name) AS modules
ORDER BY f.id
1.2 Query forms for a specific module
// module_forms_with_fields
MATCH (m:Module {name: $moduleName})-[:CONTAINS_UC]->(uc:UseCase)-[:USES_FORM]->(f:Form)-[:HAS_FIELD]->(ff:FormField)
RETURN f.id AS form_id, f.name AS form_name,
collect(DISTINCT {
id: ff.id,
name: ff.name,
label: ff.label,
field_type: ff.field_type,
required: ff.required
}) AS fields,
collect(DISTINCT uc.id) AS use_cases
ORDER BY f.id
1.3 Query forms not linked to any UseCase
// orphaned_forms
MATCH (f:Form)
WHERE NOT (:UseCase)-[:USES_FORM]->(f)
RETURN f.id AS form_id, f.name AS form_name
Present summary to user:
Forms inventory:
| # | Form ID | Form Name | Fields | Use Cases | Module |
|---|---------|-----------|--------|-----------|--------|
| 1 | FORM-OrderCreate | ... | 5 | UC-101 | orders |
Orphaned forms (not linked to any UC): {list or "none"}
Proceed with MAPS_TO verification?
Phase 2: Check MAPS_TO Completeness
2.1 Query full form-domain mapping
// form_domain_mapping_full
MATCH (f:Form)-[:HAS_FIELD]->(ff:FormField)
OPTIONAL MATCH (ff)-[:MAPS_TO]->(da:DomainAttribute)(ff:FormField)
WHERE ff.field_type IN ['text', 'textarea', 'number', 'date', 'datetime', 'select', 'multiselect', 'checkbox', 'file']
AND NOT (ff)-[:MAPS_TO]->(:DomainAttribute)
RETURN f.id AS form_id, f.name AS form_name,
ff.id AS field_id, ff.name AS field_name, ff.label AS field_label,
ff.field_type AS field_type, ff.required AS required
ORDER BY f.id, ff.id
2.3 Identify required fields without MAPS_TO (CRITICAL)
// critical_orphaned_required_fields
MATCH (f:Form)-[:HAS_FIELD]->(ff:FormField)
WHERE ff.required = true
AND ff.field_type IN ['text', 'textarea', 'number', 'date', 'datetime', 'select', 'multiselect', 'checkbox', 'file']
AND NOT (ff)-[:MAPS_TO]->(:DomainAttribute)
RETURN f.id AS form_id, f.name AS form_name,
ff.id AS field_id, ff.name AS field_name, ff.label AS field_label,
ff.field_type AS field_type
ORDER BY f.id, ff.id
Phase 3: Flag Orphans and Propose Fixes
Present to user:
MAPS_TO Verification Report:
Total forms: {N}
Total data fields: {N}
Fields with MAPS_TO: {N} ({pct}%)
Orphaned fields (no MAPS_TO): {N}
of which REQUIRED: {N} Order.totalAmount (Order-A05) |
Other orphaned fields:
| # | Form | Field | Label | Type | Proposed Fix |
|---|------|-------|-------|------|--------------|
| 1 | FORM-OrderView | FORM-OrderView-F07 | Комментарий | textarea | Create new attr? or -> Order.comment? |
Proposed fixes:
1. Create MAPS_TO: {field_id} -> {attr_id} (existing attribute match)
2. Create new DomainAttribute + MAPS_TO (no matching attribute found)
3. Mark as intentionally unmapped (e.g., computed/display-only field)
Apply proposed fixes?
Rules for proposing fixes:
- Match orphaned field by name/label similarity to existing DomainAttributes.
- If field name matches an attribute name on the related entity (entity used in the same UC), propose the MAPS_TO edge.
- If no match, propose creating a new DomainAttribute (suggest running
/nacl-sa-domain MODIFY). - If field is non-data (button, header, divider), it does NOT need MAPS_TO --- skip.
3.1 Query existing domain attributes for matching
// available_domain_attributes
MATCH (de:DomainEntity)-[:HAS_ATTRIBUTE]->(da:DomainAttribute)
RETURN de.id AS entity_id, de.name AS entity_name,
da.id AS attr_id, da.name AS attr_name, da.data_type AS attr_type
ORDER BY de.name, da.name
3.2 Create MAPS_TO edges for confirmed fixes
// create_maps_to
MATCH (ff:FormField {id: $fieldId})
MATCH (da:DomainAttribute {id: $attrId})
MERGE (ff)-[:MAPS_TO]->(da)
RETURN ff.id AS field_id, da.id AS attr_id
Phase 4: Report
Present final verification report:
MAPS_TO Verification Complete:
Before: {N}/{total} fields mapped ({pct_before}%)
After: {N}/{total} fields mapped ({pct_after}%)
Fixed: {N} MAPS_TO edges created
Remaining orphans: {N} (intentionally unmapped or pending domain model changes)
Traceability chain integrity:
Form -> FormField -> DomainAttribute -> DomainEntity: {status}
Next:
- If orphans remain: `/nacl-sa-domain MODIFY {entity}` to add missing attributes
- If all mapped: `/nacl-sa-ui components` to identify shared components
Command: components
Purpose
Identify shared UI components by analyzing Forms in the graph, create Component nodes, and establish USED_IN edges linking Components to Forms.
Parameters
[module](optional) --- Module name. If provided, only analyze forms for that module.
Workflow
+-----------------+ +-----------------+ +-----------------+ +-----------------+
| Phase 1 | | Phase 2 | | Phase 3 | | Phase 4 |
| Analyze forms |--->| Propose |--->| Create nodes |--->| Validation + |
| for patterns | | components | | + USED_IN edges | | report |
+-----------------+ +-----------------+ +-----------------+ +-----------------+
Do not proceed to the next phase without explicit user confirmation.
Phase 1: Analyze Forms for Patterns
1.1 Query all forms with field details
// forms_with_field_details
MATCH (f:Form)-[:HAS_FIELD]->(ff:FormField)
OPTIONAL MATCH (uc:UseCase)-[:USES_FORM]->(f)
OPTIONAL MATCH (ff)-[:MAPS_TO]->(da:DomainAttribute)(f:Form)
RETURN c.id AS component_id, c.name AS component_name,
c.component_type AS component_type, c.description AS description,
collect(f.id) AS used_in_forms
ORDER BY c.id
1.3 Analyze field type distribution
// field_type_distribution
MATCH (f:Form)-[:HAS_FIELD]->(ff:FormField)
RETURN ff.field_type AS field_type, count(ff) AS count,
collect(DISTINCT f.id) AS forms
ORDER BY count DESC
Pattern detection rules:
- DataTable --- if 3+ forms have list/filter patterns (many read-only fields, same entity), propose a DataTable component.
- FormLayout --- if 3+ forms share similar field arrangement (same field types in same order), propose a FormLayout component.
- StatusBadge --- if 3+ forms display a status field (Enum type on a status-like attribute), propose a StatusBadge component.
- DetailCard --- if 3+ forms are read-only detail views of the same entity structure, propose a DetailCard component.
- SearchFilter --- if 3+ forms include filter/search fields, propose a SearchFilter component.
- FileUpload --- if 2+ forms include file-type fields, propose a FileUpload component.
- DateRangePicker --- if 2+ forms include paired date fields (startDate/endDate), propose a DateRangePicker component.
Phase 2: Propose Components
Present to user:
Proposed shared components based on form analysis:
| # | Component ID | Name | Type | Used In Forms | Rationale |
|---|-------------|------|------|---------------|-----------|
| 1 | CMP-DataTable | DataTable | display | FORM-OrderList, FORM-ProductList, ... | {N} list-type forms with tabular data |
| 2 | CMP-FormLayout | FormLayout | layout | FORM-OrderCreate, FORM-OrderEdit, ... | {N} forms with similar field structure |
| 3 | CMP-StatusBadge | StatusBadge | display | FORM-OrderDetail, FORM-TaskDetail, ... | {N} forms display entity status |
Component details:
1. **DataTable**
- Purpose: Sortable, filterable, paginated data table
- Props: columns, data, filters, pagination, onRowClick
- Entities: {entities displayed in tables}
2. **FormLayout**
- Purpose: Standardized form with sections, validation, submit/cancel
- Props: sections, fields, onSubmit, onCancel
- Field types used: {list}
Confirm or modify?
Phase 3: Create Component Nodes and USED_IN Edges
3.1 Create Component node
// create_component
MERGE (c:Component {id: $componentId})
SET c.name = $name,
c.component_type = $componentType,
c.description = $description,
c.props = $props,
c.updated = datetime()
RETURN c.id AS id, c.name AS name
Parameters:
$componentId--- e.g."CMP-DataTable"$name--- e.g."DataTable"$componentType--- one of:"display","layout","input","navigation","feedback"$description--- e.g."Sortable, filterable, paginated data table"$props--- e.g."columns, data, filters, pagination, onRowClick"
3.2 Create USED_IN edge (Component to Form)
// create_used_in
MATCH (c:Component {id: $componentId})
MATCH (f:Form {id: $formId})
MERGE (c)-[:USED_IN]->(f)
RETURN c.id AS component_id, f.id AS form_id
This establishes: Component -[USED_IN]-> Form -[HAS_FIELD]-> FormField -[MAPS_TO]-> DomainAttribute
3.3 After all writes, verify
// verify_components
MATCH (c:Component)
OPTIONAL MATCH (c)-[:USED_IN]->(f:Form)
RETURN c.id AS component_id, c.name AS name,
c.component_type AS type,
count(f) AS form_count,
collect(f.id) AS forms
ORDER BY c.id
Phase 4: Report
Components created:
| Component ID | Name | Type | Used In (forms) |
|-------------|------|------|-----------------|
| CMP-DataTable | DataTable | display | 4 forms |
| CMP-FormLayout | FormLayout | layout | 6 forms |
Nodes: {N} Component nodes created/updated
Edges: {N} USED_IN edges created
Next: `/nacl-sa-ui navigation` to define navigation structure.
Form Spec Template
Every Form node in the graph has the following required sections. The sections marked REQUIRED must be populated before the Form is considered specified.
| Section | Status | Description | |---------|--------|-------------| | Fields (HASFIELD edges) | REQUIRED | Created by nacl-sa-uc detail (FormFields with MAPS_TO to DomainAttributes). | | Domain mapping (MAPSTO) | REQUIRED | Verified by verify command above. | | Used-In Components (USEDIN) | REQUIRED | Created by components command — which Components render as part of this Form's screen. | | Nav Actions (HASINBOUND_ACTION) | REQUIRED for actor != SYSTEM | Created by navigation command — which Components expose a user affordance (button, menu item, link, CTA) that triggers this Form. | | Layout patterns | OPTIONAL | Component composition for the Form. |
Nav Actions (HASINBOUNDACTION) — REQUIRED for actor-triggered UCs
Every Form whose UseCase has actor != SYSTEM MUST enumerate the inbound action sites that expose it to the user: which screen, which nav item, which global menu point, which CTA on a sibling page carries the user-visible affordance that opens this Form.
This subsection answers the question that page-
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ITSalt
- Source: ITSalt/NaCl
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.