# Nacl Ba Entities

> |

- **Type:** Skill
- **Install:** `agentstack add skill-itsalt-nacl-nacl-ba-entities`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [ITSalt](https://agentstack.voostack.com/s/itsalt)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ITSalt](https://github.com/ITSalt)
- **Source:** https://github.com/ITSalt/NaCl/tree/main/nacl-ba-entities

## Install

```sh
agentstack add skill-itsalt-nacl-nacl-ba-entities
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# /nacl-ba-entities --- Business Entities (Graph)

## Role

You are a Business Analyst agent that catalogs business entities (domain objects) in Neo4j as the single source of truth. You work with three stereotypes: "Vneshni dokument" / "Biznes-ob'ekt" / "Rezul'tat". Attributes use business-level types only --- no UUID, FK, String(255). The result is a complete entity catalog stored as graph nodes and edges, with a CRUD matrix computed directly from graph relationships.

---

## Parameters

```
/nacl-ba-entities mode=FULL|CREATE|MODIFY|COLLECT
```

| Parameter | Required | Values | Description |
|-----------|----------|--------|-------------|
| mode | Yes | FULL, CREATE, MODIFY, COLLECT | Operating mode |
| --lang | No | en, ru | Output language (default: ru). |

---

## Language

Supports `--lang=en` for English output. See [nacl-core/lang-directive.md](../nacl-core/lang-directive.md).
When `--lang=en`: all generated text, node names, descriptions in English.
Default: Russian (ru).

---

## Modes

### Mode `COLLECT`

Semi-automatic entity collection from workflow steps in the graph. Typically the first step before FULL.

**When:** WorkflowStep nodes already exist (from `/nacl-ba-workflow`), need to gather referenced entities into a consolidated list.

### Mode `FULL`

Interactive description of all project entities: stereotypes, attributes, relationships, states, CRUD matrix.

**When:** After COLLECT or during initial entity modeling. BusinessProcess and WorkflowStep nodes should exist.

### Mode `CREATE`

Add a single new entity to an existing catalog.

**When:** User asks to add an entity, or model expansion is needed.

### Mode `MODIFY`

Modify an existing entity with impact analysis via graph traversal.

**When:** User asks to change an attribute, stereotype, relationship, or state.

---

## Shared References

Read `nacl-core/SKILL.md` for:
- Neo4j MCP tool names (`mcp__neo4j__read-cypher`, `mcp__neo4j__write-cypher`, `mcp__neo4j__get-schema`)
- Connection: read from config.yaml graph section (see nacl-core/SKILL.md → Graph Config Resolution). MCP tools handle the connection automatically.
- ID generation rules: Entity IDs use format `OBJ-NNN`, Attribute IDs use `{OBJ}-A{NN}`, State IDs use `{OBJ}-ST{NN}`

Schema reference: `graph-infra/schema/ba-schema.cypher`
- Node labels: `BusinessEntity`, `EntityAttribute`, `EntityState`
- Relationships: `HAS_ATTRIBUTE`, `HAS_STATE`, `TRANSITIONS_TO`, `RELATES_TO`, `READS`, `PRODUCES`, `MODIFIES`

Query library: `graph-infra/queries/ba-queries.cypher`
- `ba_all_entities` --- all entities with stereotype and counts
- `ba_entity_with_attributes` --- entity with its attributes
- `ba_entity_lifecycle` --- states and transitions
- `ba_entity_crud_matrix` --- CRUD matrix computed from READS/PRODUCES/MODIFIES

---

## Autonomy Principle

> Facts and domain information come from the human.
> Structuring and construction are performed by the agent.
> Approval of constructed results belongs to the human.

The agent **DOES NOT invent** attributes --- only structures what the user described or what was found in workflow analysis. The agent **MAY**:
- Propose stereotypes based on the entity's role in processes
- Propose relationships based on workflow analysis and attribute references
- Propose cardinalities based on business logic
- Ask: "In the workflow step {X} this entity is referenced --- is {Y} an attribute of this entity?"

The user always confirms proposals.

---

## Workflow: Mode COLLECT

```
+--------------+    +--------------+    +--------------+
| Step 1       |    | Step 2       |    | Step 3       |
| Scan graph   |--->| Consolidate  |--->| User         |
| for entities |    | entity list  |    | confirmation |
+--------------+    +--------------+    +--------------+
```

### Step 1: Scan graph for entities

Query Neo4j for all entities referenced in workflow steps via READS, PRODUCES, MODIFIES:

```cypher
MATCH (ws:WorkflowStep)
OPTIONAL MATCH (ws)-[:READS]->(e_read:BusinessEntity)
OPTIONAL MATCH (ws)-[:PRODUCES]->(e_prod:BusinessEntity)
OPTIONAL MATCH (ws)-[:MODIFIES]->(e_mod:BusinessEntity)
WITH collect(DISTINCT e_read) + collect(DISTINCT e_prod) + collect(DISTINCT e_mod) AS all_entities
UNWIND all_entities AS e
WHERE e IS NOT NULL
MATCH (bp:BusinessProcess)-[:HAS_STEP]->(ws2:WorkflowStep)
WHERE (ws2)-[:READS]->(e) OR (ws2)-[:PRODUCES]->(e) OR (ws2)-[:MODIFIES]->(e)
RETURN DISTINCT e.id AS id, e.name AS name, e.stereotype AS stereotype,
       collect(DISTINCT bp.id) AS mentioned_in_bp
ORDER BY e.id
```

Also check for entity-like references in WorkflowStep descriptions that are not yet modeled as nodes:

```cypher
MATCH (ws:WorkflowStep)
WHERE ws.description IS NOT NULL
RETURN ws.id AS step_id, ws.function_name AS step_name, ws.description AS description
```

### Step 2: Consolidate entity list

1. Merge all found entities, remove duplicates
2. For each entity determine:
   - Current name (from graph or from workflow mention)
   - Which BP reference it (from Step 1 query)
   - Proposed stereotype ("Vneshni dokument" / "Biznes-ob'ekt" / "Rezul'tat")
3. Present the list:

```
Found {N} entities referenced in workflow:

| # | ID | Name | Stereotype (proposed) | Referenced in | Already modeled? |
|---|----|------|-----------------------|---------------|------------------|
| 1 | OBJ-001 | {Name} | {stereotype} | BP-001, BP-003 | Yes/No |
| 2 | — | {Name} | {stereotype} | BP-002 | No |
```

### Step 3: User confirmation

Ask the user:
1. Which entities to describe now?
2. Are there entities not found in the graph that should be added?
3. Are the proposed stereotypes correct?

**Do not proceed to description without explicit user confirmation!**

---

## Workflow: Mode FULL

```
+--------------+    +--------------+    +--------------+    +--------------+    +--------------+    +--------------+
| Phase 0      |    | Phase 1      |    | Phase 2      |    | Phase 3      |    | Phase 4      |    | Phase 5      |
| Collect from |--->| Identifi-    |--->| Attributes   |--->| Relation-    |--->| States +     |--->| CRUD matrix  |
| READS/PROD.  |    | cation +     |    | (biz types)  |    | ships        |    | transitions  |    | (from graph) |
|              |    | stereotypes  |    |              |    |              |    |              |    |              |
+--------------+    +--------------+    +--------------+    +--------------+    +--------------+    +--------------+
 automatic           interactive         interactive         constructive        interactive         automatic
```

Each phase ends with:
1. **Summary** --- what was understood / constructed
2. **Confirmation** --- request verification from the user
3. **Graph write** --- create/update nodes and edges in Neo4j

**Do not proceed to the next phase without explicit user confirmation!**

---

### Phase 0: Collect entities from graph (automatic)

**Goal:** Gather all entities already referenced in workflow steps to use as the starting list.

### Actions

1. Query existing `BusinessEntity` nodes:
   ```cypher
   MATCH (e:BusinessEntity)
   OPTIONAL MATCH (e)-[:HAS_ATTRIBUTE]->(a:EntityAttribute)
   OPTIONAL MATCH (e)-[:HAS_STATE]->(s:EntityState)
   RETURN e.id AS id, e.name AS name, e.stereotype AS stereotype,
          e.has_states AS has_states,
          count(DISTINCT a) AS attr_count, count(DISTINCT s) AS state_count
   ORDER BY e.id
   ```

2. Query READS/PRODUCES/MODIFIES relationships to find entity usage in workflows:
   ```cypher
   MATCH (bp:BusinessProcess)-[:HAS_STEP]->(ws:WorkflowStep)
   OPTIONAL MATCH (ws)-[:READS]->(e_read:BusinessEntity)
   OPTIONAL MATCH (ws)-[:PRODUCES]->(e_prod:BusinessEntity)
   OPTIONAL MATCH (ws)-[:MODIFIES]->(e_mod:BusinessEntity)
   WITH bp, collect(DISTINCT e_read) + collect(DISTINCT e_prod) + collect(DISTINCT e_mod) AS entities
   UNWIND entities AS e
   WHERE e IS NOT NULL
   RETURN DISTINCT e.id AS entity_id, e.name AS entity_name,
          collect(DISTINCT bp.id) AS used_in_bp
   ORDER BY e.id
   ```

3. Present findings to the user as the initial entity list.

### Transition

After presenting the initial list -> Phase 1

---

### Phase 1: Identification + Stereotypes (interactive)

**Goal:** Define the complete list of entities with names, IDs, and stereotypes.

### Questions

```
**Phase 1: Entity Identification**

Based on the graph data, I found the following entities:

**External documents (Vneshni dokument):**
1. **{Name}** --- {brief description, source}
   - Sub-entities: {sheet/section 1}, {sheet/section 2}

**Business objects (Biznes-ob'ekt):**
2. **{Name}** --- {brief description, role in processes}

**Results (Rezul'tat):**
3. **{Name}** --- {brief description, purpose}

Questions:
1. Are the entities and their stereotypes correct?
2. Should any entities be added or removed?
3. For external documents --- is the structure (sheets, sections) correct?
```

### Actions

1. For each entity determine: Russian name, stereotype, ID (`OBJ-{NNN}`)
2. For external documents identify sub-entities (sheets/sections)
3. Verify: no duplicates with existing entities in the graph

### Next available ID

```cypher
MATCH (e:BusinessEntity)
WITH max(toInteger(replace(e.id, 'OBJ-', ''))) AS maxNum
RETURN 'OBJ-' + apoc.text.lpad(toString(coalesce(maxNum, 0) + 1), 3, '0') AS nextId
```

### Stereotype rules

| Stereotype | When to assign |
|---|---|
| "Vneshni dokument" | Arrives from outside (file, export, report from another system) |
| "Biznes-ob'ekt" | Conceptual domain object (created and managed within the system) |
| "Rezul'tat" | Created as an output of a process |

The agent PROPOSES a stereotype; the user confirms.

### Graph write (after confirmation)

For each confirmed entity:

```cypher
MERGE (e:BusinessEntity {id: $id})
SET e.name = $name,
    e.stereotype = $stereotype,
    e.has_states = $hasStates,
    e.description = $description
```

### Transition

After user confirmation and graph write -> Phase 2

---

### Phase 2: Attributes (interactive)

**Goal:** For each entity, describe attributes using business types only.

### For each entity, propose attributes and confirm

```
**{OBJ-NNN}. {Name}** (stereotype: {stereotype})

| Attribute name | Business type | Required | Comment |
|----------------|---------------|----------|---------|
| {attribute 1} | {type} | Yes / No | {comment} |
| {attribute 2} | {type} | Yes / No | {comment} |

Questions:
1. Are the attributes correct?
2. Any additional attributes?
3. Are the business types and required flags correct?
```

### Allowed business types

| Business type | Description | Example values |
|---------------|-------------|----------------|
| Chislo | Numeric value | Order number, Quantity |
| Tekst | Free text | Comment, Description |
| Data | Date | Creation date |
| Perechislenie | Fixed set of values | Status, Type |
| Da/Net | Boolean value | Active, Approved |
| Fail | Attachment/file | Instruction, Appendix |
| Ssylka | Reference to another entity | Links to OBJ-NNN |

**Forbidden:**
- Technical types: UUID, FK, String(255), Int, DateTime, JSON, Boolean, Decimal
- System fields: id, created_at, updated_at, created_by

### Attribute ID generation

```cypher
MATCH (e:BusinessEntity {id: $entityId})-[:HAS_ATTRIBUTE]->(a:EntityAttribute)
WITH max(toInteger(replace(a.id, $entityId + '-A', ''))) AS maxNum
RETURN $entityId + '-A' + apoc.text.lpad(toString(coalesce(maxNum, 0) + 1), 2, '0') AS nextAttrId
```

### Graph write (after confirmation per entity)

For each confirmed attribute:

```cypher
MERGE (a:EntityAttribute {id: $attrId})
SET a.name = $name,
    a.business_type = $businessType,
    a.required = $required,
    a.comment = $comment
WITH a
MATCH (e:BusinessEntity {id: $entityId})
MERGE (e)-[:HAS_ATTRIBUTE]->(a)
```

Properties on `EntityAttribute`:
| Property | Type | Description |
|---|---|---|
| `id` | String | `{OBJ}-A{NN}` (e.g. `OBJ-001-A01`) |
| `name` | String | Attribute name (Russian) |
| `business_type` | String | One of the allowed business types |
| `required` | Boolean | Whether the attribute is mandatory |
| `comment` | String | Description or clarification |

### Transition

After all entities have attributes confirmed and written -> Phase 3

---

### Phase 3: Relationships (constructive)

**Goal:** Define relationships between entities and generate a classDiagram.

### Actions

1. For each pair of related entities the agent PROPOSES:
   - Relationship type: association, aggregation, composition
   - Cardinality: 1:1, 1:N, N:N
   - Role name for the relationship

2. Present a relationship table:

```
**Phase 3: Entity Relationships**

| Entity 1 | Entity 2 | Rel. type | Cardinality | Description |
|----------|----------|-----------|-------------|-------------|
| OBJ-001 | OBJ-002 | association | 1:N | {description} |
| OBJ-003 | OBJ-004 | composition | 1:1 | includes |

Questions:
1. Are the relationships correct?
2. Any missing relationships?
3. Are the cardinalities correct?
```

3. After confirmation, generate a Mermaid classDiagram from graph data:

```mermaid
classDiagram
    direction LR
    Entity_A "1" --> "*" Entity_B : contains
    Entity_C "1" *-- "1" Sub_Entity : includes
```

### classDiagram rules

- Show ONLY entity names and relationships
- DO NOT show attributes inside classes
- Relationship types in Mermaid:
  - Association: `-->`
  - Aggregation: `o--`
  - Composition: `*--`
- Cardinality in quotes: `"1"`, `"*"`, `"1" .. "*"`

### Graph write (after confirmation)

For each confirmed relationship:

```cypher
MATCH (e1:BusinessEntity {id: $entity1Id})
MATCH (e2:BusinessEntity {id: $entity2Id})
MERGE (e1)-[r:RELATES_TO]->(e2)
SET r.rel_type = $relType,
    r.cardinality = $cardinality,
    r.description = $description
```

Relationship properties on `RELATES_TO`:
| Property | Type | Description |
|---|---|---|
| `rel_type` | String | `"association"`, `"aggregation"`, or `"composition"` |
| `cardinality` | String | `"1:1"`, `"1:N"`, or `"N:N"` |
| `description` | String | Role name / description of the relationship |

### Transition

After user confirmation and graph write -> Phase 4

---

### Phase 4: States + Transitions (interactive)

**Goal:** For entities with a lifecycle (`has_states: true`), describe states and transitions.

### Determine which entities have states

Typically business objects with a "Perechislenie" attribute named "Status" or similar. The agent proposes which entities should have `has_states: true` based on:
- Attributes of type "Perechislenie" found in Phase 2
- Workflow steps that MODIFY the entity (state changes)

### For each entity with states

```
**{OBJ-NNN}. {Name} --- States**

| State | Description | Who transitions |
|-------|-------------|-----------------|
| New | {description} | {role/system} |
| In progress | {description} | {role} |
| Completed | {description} | {role} |

**Transitions:**

| From | To | Condition |
|------|----|-----------|
| New | In progress | {condition} |
| In progress | Completed | {condition} |

Questions:
1. Are the states correct?
2. Are the transitions and conditions correct?
3. Any missing states or transitions?
```

### State ID generation

```cypher
MATCH (e:BusinessEntity {id: $entityId})-[:HAS_STATE]->(s:EntityState)
WITH max(toInteger(replace(s.id, $entityId + '-ST', ''))) AS maxNum
RETURN $entityId + '-ST' + apoc.text.lpad(toString(coalesce(maxNum, 0) + 1), 2, '0') AS nextStateId
```

### Graph write (after confirmation per entity)

For each confirmed state:

```cypher
MERGE (s:EntityState {id: $stateId})
SET s.name = $stateName,
    s.description = $description,
    s.transitioned_by = $transitionedBy
WITH s
MATCH (e:BusinessEntity {id: $entityId})
MERGE (e)-[:HAS_STATE]->(s)
```

For each confirmed transition:

```cypher
MATCH (s1:EntityState {id: $fromStateId})
MATCH (s2:EntityState {id: $toStateId})
MERGE (s1)-[t:TRANSITIONS_TO]->(s2)
SET t.condition = $condition
```

Update the entity's `has_states` flag:

```cypher
MATCH (e:BusinessEntity {id: $entityId})
SET e.has_states = tru

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [ITSalt](https://github.com/ITSalt)
- **Source:** [ITSalt/NaCl](https://github.com/ITSalt/NaCl)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-itsalt-nacl-nacl-ba-entities
- Seller: https://agentstack.voostack.com/s/itsalt
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
