# AI Markdown Editing Rules (progFocus)

> **This document is a rule set for AI to parse, edit, and generate progFocus export files (.md).**

---

## Output Format (Highest Priority Rule)

**Raw JSON output is prohibited.** Always output as a complete Markdown file with the following structure.

### Actual File Content (This is what gets saved as the `.md` file)

The file content consists of only these 3 elements. Do NOT include `~~~markdown`.

1. **Frontmatter**: A YAML block starting with `---` and ending with `---` (at the beginning of the file)
2. **Blank line**: One blank line
3. **JSON code block**: Starts with three backticks + `json`, ends with a line containing only three backticks

```
---                          ← First line of the file
format: progfocus.markdown.v1
exportedAt: 2026-01-01T00:00:00.000Z
projectId: my-project
projectName: My Project
mode: direct
nodeCount: 3
connectionCount: 2
---                          ← Frontmatter end
                             ← Blank line (required)
```json                      ← JSON block start
{
  "project": { ... }
}
```                          ← JSON block end (last line of the file)
```

### How to Output in Chat (Display Wrapper)

In chat UIs, inner backticks may be misinterpreted, so **wrap the output with `~~~markdown` ... `~~~`**. This is a display wrapper for the chat UI and is NOT part of the file content.

````
~~~markdown                  ← Display wrapper (NOT part of the file)
---
format: progfocus.markdown.v1
exportedAt: 2026-01-01T00:00:00.000Z
projectId: my-project
projectName: My Project
mode: direct
nodeCount: 3
connectionCount: 2
---

```json
{
  "project": { ... }
}
```
~~~                          ← Display wrapper (NOT part of the file)
````

- The `markdown` language tag allows the chat UI to recognize it as a code block and display a copy button
- Using `~~~` on the outside allows nesting of inner ` ``` ` (backticks) without conflicts
- Do not split the frontmatter and JSON into separate blocks

### ⚠️ When No Copy Button Is Displayed

Some AIs (e.g., Gemini) may not display a copy button on code blocks. In that case:
- When a user manually copies the text, `~~~markdown` and `~~~` may be included in the file content
- **progFocus's parser automatically strips the `~~~markdown` wrapper**, so the import will work correctly even if the wrapper is included
- However, as an AI, it is preferable to output only the file content without the `~~~markdown` wrapper when possible

### Required Checks Before Completing Output

- Do `nodeCount` and `connectionCount` match the actual number of elements in the JSON?
- For chat output: Does the output start with `~~~markdown` and end with `~~~`?
- Is there a line starting with three backticks + `json`?
- Is there a closing line with only three backticks after the JSON closing `}`?
- Is the JSON syntactically valid?

---

## Application Overview

- progFocus is an infinite canvas planning tool that progressively narrows focus from Purpose → Specification → Structure
- **Functions as a data flow diagram**: Arranges the flow of Input → Process → Output from left to right
- Place high-level features (feature-type nodes) directly under the root, with more specific nodes inside them
- The generated Markdown is a "design snapshot." When additional requests come in, append nodes and connections and return the updated file

---

## Node Types

### Atomic Nodes (No Child Hierarchy)

| Type | Purpose | Examples |
|------|---------|----------|
| `input` | External input / data retrieval | Form input, API fetch, sensor signal |
| `process` | Processing / computation / transformation | Validation, PWM calculation, data conversion |
| `output` | Output / storage / display | Screen display, motor drive, notification |

### Container Nodes (Double-click to Enter Child Hierarchy)

| Type | Purpose | Examples |
|------|---------|----------|
| `feature` | General-purpose feature container | Authentication, data management |
| `feature_input` | Input-oriented feature group | Controller input, sensor array |
| `feature_process` | Process-oriented feature group | Movement data processing, control logic |
| `feature_output` | Output-oriented feature group | Motor drive, actuators |

---

## Hierarchy Design

### Basic Pattern: Two-Level Structure

1. **Root level**: Arrange feature-type nodes left → right, and **connect features to each other**
   - Example: `feature_input` (Input) → `feature_process` (Process) → `feature_output` (Output)
   - **Connections at the root level must always be created. Output with isolated features is incomplete.**
2. **Child level**: Place input → process → output inside each feature, and **connect only nodes within the same feature**

### Connection Parent Constraint (Absolute Rule)

**Connections can only be created between nodes with the same `parentId`. Connections between child nodes of different parents are prohibited.**

- Root level: Only nodes with `parentId: null` can be connected to each other
- Child level: Only nodes with the same `parentId` can be connected to each other

Bad: `in-ir` (parentId: "feat-sensor") → `proc-wall` (parentId: "feat-brain") ← Different parents
Good: `feat-sensor` (parentId: null) → `feat-brain` (parentId: null) ← Same parent (null)

### Multi-Line Layout

- When there are multiple independent processing pipelines, arrange them in parallel by varying the y-coordinate
- When branching from a common input source, connect from the input node's `bottom` to the line below

### Representing Feedback Loops

- Return signals from sensors or limit detection are represented with reverse-direction connections
- Route through `bottom` for visual clarity

### Serial Placement of Same-Type Nodes (Vertical Stacking)

When consecutive nodes of the same type appear, **stack them vertically**:
- Align x-coordinates, increment y-coordinates by +220–240px
- Connect with `bottom` → `top`
- From the last node to the next type, use `right` → `left` to go rightward

```
[input]  →  [process1]  →  [output]
 x=200       x=620          x=1100
 y=60        y=60           y=60
                ↓ (bottom→top)
            [process2]
             x=620
             y=300
                ↓ (bottom→top)
            [process3] ─→ (right→left)
             x=620
             y=520
```

---

## Layout Guidelines

### Basic Principles

- **Left → Right flow**: Input (left) → Process (center) → Output (right)
- **Standard dimensions**: `width=256`, `height=160`
- **Grid**: Align coordinates to multiples of 20px
- **Recommended spacing**: At least 80px horizontal, at least 60px vertical
- **Height is variable**: For long titles or multi-line memos, add +40–80px vertical padding

### X-Coordinate Placement

| Role | Root Level | Child Level |
|------|-----------|-------------|
| Input | x=100 | x=40–140 |
| Process | x=520–620 | x=440–620 |
| Output | x=1000–1100 | x=880–1100 |

### Y-Coordinate (For Multi-Line Layouts)

| Line | Y-Coordinate | Spacing |
|------|-------------|---------|
| Row 1 | y=140–180 | - |
| Row 2 | y=400–440 | ~260px |
| Row 3 | y=660–700 | ~260px |

### Child Node Placement Guidelines

- Layout within a parent feature also follows the left → right principle
- Spacing between child nodes: 260–520px horizontal, 200–260px vertical

---

## Connection (Arrow) Specification

### Direction Principles

| Pattern | fromSide | toSide | Usage |
|---------|----------|--------|-------|
| Forward | `right` | `left` | Data flow (default) |
| Branch | `bottom` | `left` | Connect to line below |
| Serial | `bottom` | `top` | Vertical connection of same-type nodes |
| Feedback | `bottom` | `bottom` | Return connection |

### Labels

- Default value is an empty string `""`
- When adding content, prefix with `• ` (e.g., `"• Data"`, `"• PWM Signal"`)
- `labelPosition` can be omitted (default `{"x":0,"y":0}`). Adjust by ±20/±40 only when crowded
- `labelHidden` is normally omitted (set to `true` only when you want to hide it)

---

## File Format Details

- Format ID: `progfocus.markdown.v1` (do not change)
- Required frontmatter keys: `format`, `exportedAt` (ISO8601), `projectId`, `projectName`, `mode` (`direct` | `interactive`), `nodeCount`, `connectionCount`
- JSON structure: `{ "project": Project }`
  - `project`: `id`, `name`, `mode`, `createdAt`, `updatedAt`, `rootNodeIds`, `nodes`, `connections`, `definitionRegistry`
  - `nodes[<id>]`: `id`, `type`, `title`, `memo`, `x`, `y`, `width`, `height`, `parentId`, `programDef` (optional), `createdAt`, `updatedAt`
  - `connections[<id>]`: `id`, `fromNodeId`, `fromSide`, `toNodeId`, `toSide`, `label`, `labelPosition`, `labelHidden`

---

## programDef Specification

Nodes can have a `programDef` field to define programming elements (optional).

### Type List

| Type | elementType | Main Fields |
|------|-------------|-------------|
| Class | `class` | className, methods, properties, description |
| Method | `method` | className, methodName, args, returnValue, visibility |
| Interface | `interface` | interfaceName, methods, properties |
| Function | `function` | functionName, args, returnValue |
| Variable | `variable` | variableName, variableType, initialValue |
| Struct | `struct` | structName, fields |
| Enum | `enum` | enumName, values |
| Module | `module` | moduleName, exports |
| None | `none` | (none) |

All types have `fileName` and `description` fields.

### Example

```json
"programDef": {
  "elementType": "class",
  "fileName": "auth.ts",
  "className": "AuthService",
  "methods": "login\nlogout\nverifyToken",
  "properties": "token: string\nuser: User",
  "description": "Handles authentication"
}
```

### definitionRegistry

`project.definitionRegistry` holds a registry of all names used across the project.

```json
"definitionRegistry": {
  "fileNames": ["auth.ts"],
  "classNames": ["AuthService"],
  "methodNames": ["login"],
  "interfaceNames": [],
  "functionNames": [],
  "variableNames": [],
  "structNames": [],
  "enumNames": [],
  "moduleNames": []
}
```

- Names used in nodes must always be included in the registry
- When adding new names, add them to the registry simultaneously

---

## Editing Checklist

1. Do not change `format`
2. Ensure `nodeCount` and `connectionCount` match the actual number of elements
3. Include all nodes with `parentId=null` in `rootNodeIds`
4. Align coordinates to the 20px grid. Standard size is `256x160`
5. `createdAt` does not need to be changed. Update `updatedAt` only for edited elements
6. **Verify that both endpoints of a connection have the same `parentId`**
7. **Create connections between root-level features (isolated features are incomplete)**
8. **Wrap with `~~~markdown` ... `~~~` for chat output (not needed when saving as file; parser strips it automatically)**

---

## Complete Output Example

Below is an example of a "User Authentication" feature. You can copy it all at once using the chat UI copy button and save it as an `.md` file.

````
~~~markdown
---
format: progfocus.markdown.v1
exportedAt: 2026-01-17T00:00:00.000Z
projectId: auth-sample
projectName: User Authentication
mode: direct
nodeCount: 7
connectionCount: 6
---

```json
{
  "project": {
    "id": "auth-sample",
    "name": "User Authentication",
    "mode": "direct",
    "createdAt": 1705017600000,
    "updatedAt": 1705017600000,
    "rootNodeIds": ["input-form", "process-validate", "process-auth", "process-session", "output-result", "input-db", "output-log"],
    "nodes": {
      "input-form": {
        "id": "input-form",
        "type": "input",
        "title": "Login Form",
        "memo": "Email address\nPassword",
        "x": 100, "y": 60, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      },
      "process-validate": {
        "id": "process-validate",
        "type": "process",
        "title": "Input Validation",
        "memo": "Format check\nEmpty field check",
        "x": 520, "y": 60, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      },
      "process-auth": {
        "id": "process-auth",
        "type": "process",
        "title": "Authentication",
        "memo": "DB lookup\nPassword verification",
        "x": 520, "y": 280, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      },
      "process-session": {
        "id": "process-session",
        "type": "process",
        "title": "Session Generation",
        "memo": "Token issuance\nCookie configuration",
        "x": 520, "y": 500, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      },
      "output-result": {
        "id": "output-result",
        "type": "output",
        "title": "Auth Result",
        "memo": "Success: Redirect to dashboard\nFailure: Show error",
        "x": 1000, "y": 60, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      },
      "input-db": {
        "id": "input-db",
        "type": "input",
        "title": "User DB",
        "memo": "",
        "x": 100, "y": 280, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      },
      "output-log": {
        "id": "output-log",
        "type": "output",
        "title": "Auth Log",
        "memo": "Record success/failure",
        "x": 1000, "y": 280, "width": 256, "height": 160,
        "parentId": null,
        "createdAt": 1705017600000, "updatedAt": 1705017600000
      }
    },
    "connections": {
      "conn-1": {
        "id": "conn-1",
        "fromNodeId": "input-form", "fromSide": "right",
        "toNodeId": "process-validate", "toSide": "left",
        "label": "• Input data"
      },
      "conn-2": {
        "id": "conn-2",
        "fromNodeId": "process-validate", "fromSide": "bottom",
        "toNodeId": "process-auth", "toSide": "top",
        "label": ""
      },
      "conn-3": {
        "id": "conn-3",
        "fromNodeId": "process-auth", "fromSide": "bottom",
        "toNodeId": "process-session", "toSide": "top",
        "label": ""
      },
      "conn-4": {
        "id": "conn-4",
        "fromNodeId": "process-session", "fromSide": "right",
        "toNodeId": "output-result", "toSide": "left",
        "label": "• Auth token"
      },
      "conn-5": {
        "id": "conn-5",
        "fromNodeId": "input-db", "fromSide": "right",
        "toNodeId": "process-auth", "toSide": "left",
        "label": "• User info"
      },
      "conn-6": {
        "id": "conn-6",
        "fromNodeId": "process-auth", "fromSide": "right",
        "toNodeId": "output-log", "toSide": "left",
        "label": "• Log output"
      }
    },
    "definitionRegistry": {
      "fileNames": [], "classNames": [], "methodNames": [],
      "interfaceNames": [], "functionNames": [], "variableNames": [],
      "structNames": [], "enumNames": [], "moduleNames": []
    }
  }
}
```
~~~
````

### Structure Explanation

```
[Login Form]  →  [Input Validation]  →  [Auth Result]
   (input)          (process)             (output)
   x=100             x=520                x=1000
   y=60              y=60                 y=60
                        ↓ (bottom→top)
[User DB]  →  [Authentication]  →  [Auth Log]
  (input)       (process)           (output)
  x=100         x=520               x=1000
  y=280         y=280               y=280
                    ↓ (bottom→top)
              [Session Generation] ─→ (right→left to output-result)
                  (process)
                  x=520, y=500
```

- **Serial processes are stacked vertically**: validate → auth → session at y=60, 280, 500
- **Multiple input sources are aligned on the left**: form and DB aligned at x=100, separated by y
- **Secondary outputs branch sideways**: Auth log branches right from process-auth

---

## Design Example: Robot Control System

### Root Level Structure

```
[Controller Input]  →  [Movement Data Processing]  →  [Motor Drive]
  (feature_input)        (feature_process)             (feature_output)
      x=100                  x=620                        x=1080
      y=180                  y=180                        y=180
         │
         └──────→  [Gripper Control]  →  [Gripper Arm]
                    (feature_process)     (feature_output)
                        x=620               x=1080
                        y=440               y=440
                          ↑____Feedback____│
```

### Internal Structure Examples

**Inside "Movement Data Processing":**
```
[Stick Input Data]  →  [PWM Calculation]  →  [PWM Signal Output]
     (input)              (process)             (output)
     x=40                 x=560                 x=1000
```

**Inside "Gripper Arm":**
```
[PWM/GPIO Signal]  →  [Servo Motor Drive]  →  [Servo Motor]
    (input)              (process)              (output)
                            ↑
                     [Limit Sensor] (feedback input)
```

### Design Points

1. **Root is divided by functional units**: Split into feature types based on "what it does"
2. **Children are divided by processing steps**: Split into input/process/output based on "how it processes"
3. **Multiple pipelines are separated vertically**: Main pipeline (y=180) and sub-pipeline (y=440)
4. **Feedback routes through the bottom**: Use `bottom` → `bottom` for visual distinction

---

## Final Check (Read Before Every Output)

1. Output format: `~~~markdown` → Frontmatter (`---` ... `---`) → Blank line → JSON block (` ``` ` + `json` ... ` ``` `) → `~~~`
2. Wrap the entire output with `~~~markdown` ... `~~~` to make it a single code block in the chat UI
3. **Never omit** the closing three backticks of the JSON block
4. The closing `~~~` line must be the **last line of output** (do not add anything after it)
5. Connections are only between nodes with the same `parentId`
6. `nodeCount` / `connectionCount` match the actual counts
7. Include all nodes with `parentId=null` in `rootNodeIds`
