SuperAPI AI Directory

easyeda-pro-format-skill

Coding & development

View repository

Updated 10-15 21:36

About this skill

EasyEDA Format SKILL Documentation

⚠️ Core Workflow (Must Be Strictly Followed)

Whenever you generate format data,you must immediately call the validation script, and only after validation passes can you return the result.

Mandatory Workflow:

1. 查询资料 → 2. 检查关联图元 → 3. 生成格式 → 4. 验证格式 → 5. 存档
                                                    ↓ 失败
                                              修复并重试(最多3次)

Checklist That Must Be Executed After Each Generation:

  • Have queried types-index.md to find the type name
  • Have entered the documentation layer to understand the domain
  • Have entered the primitive layer to check field definitions and constraints
  • (Optional) Have checked the example layer for reference real data
  • (Optional) Have checked the JSON Schema to understand constraints
  • Have checked whether associated primitives need to be generated
  • Have generated the format data (including associated primitives, if needed)
  • The coordinates and parameters of associated primitives have been automatically inferred (without asking the user)
  • Have called node validate.js to validate all generated primitives
  • Validation result valid: true
  • Have saved the format to a file
  • Return the complete format + validation result

Row Data Format

All data is in row units, and each row consists of outer data and inner data:

{type, id, ticket}||{实际数据}

Row Terminator: Each row ends with | plus a newline (LF,not CRLF).|| is the shell/payload separator, and the | + newline at the end of the row is the actual record end; the payload/shell must not contain "a literal | immediately followed by a literal newline" (JSON serialization already guarantees this will not happen).

Outer Data(eventual consistency framework):

  • type: Primitive type name (such as LINE, PAD, VIA)
  • id: Unique identifier. Ordinary primitives use a 16-digit hexadecimal random string; singleton atoms (META / CANVAS / UNIVERSAL, etc.) directly use the type name; FONT uses the font key, and BLOB uses the content hash
  • ticket: Logical clock (incrementing integer).DOCHEAD rows do not have id, and the outer layer only has type and ticket —— ticket are decided by the writer; the eprj3 save path will write (ProConsistencyManager 's JSON.stringify({ type: DOCHEAD, ticket }), and the parsing side's ProOuterParser will also be read back)

Inner Data: The attribute values of the specific primitive; each primitive has a corresponding field definition.

Eventual Consistency (When the same data appears in multiple rows, which row counts)

Storage isappend-only: additions, deletions, and modifications all write another row to the log, so the same data will have multiple rows. The eventual consistency framework determines the winner, and the rules are:

  1. The arbitration key is "document + normalized id" —— type does not participate incomparison; even if the same id changes type, it still competes along the same chain.
  2. ticket different → keep ticket the row with the larger value。
  3. ticket the same → then comparethe document header's client,keep client the row with the lexicographically larger value。

⚠️ Rule 3'sdirection is "the larger one wins". The old 2.0 document says "client if the identifier is smaller, it is kept",which is opposite to the implementation(the implementation is in lc-protocol 's 3.0/consistency/utils/list.ts 's compareFn and the accompanying unit tests),do not write according to the old document。

There is also a **pending (pend) / revoke** mechanism that temporarily overrides the above conclusions (for the same (client, ticket) when a hit occurs, only the pend flag is flipped, without overwriting with the new value;revoke can make a resolved node with a smaller ticket take effect again). That is internal state for collaborative editing and is not needed when generating static format data.

How deletions are expressed

  • Deleting an atomic data item: write another line, and setthe inner data to an empty string —— {"type":"…","id":"…","ticket":N}||(|| afterward is empty).It is noterasing this line from the log.
  • Deleting a document: write a line {"type":"DELETE_DOC","ticket":N}||{"isDelete":true}. It onlyadds a deletion marker, and the original document data remains in the log, soit can be undone(by overwriting it again with {"isDelete":false} ).
  • ⚠️ The payloads of the two kinds of deletion are not interchangeable, and must be provided separately by type:
    • DELETE_DOC sending an empty string ⇒ it will be judged as "not deleted", reviving the already-deleted documentrevive; what it wants is {"isDelete":true} / {"isDelete":false}。
    • META must neversend an empty string — the consumer will directly take dataObj.title, the empty string parses into null and then throws an exception, aborting the entire batch replay; deleting META via DELETE_DOC。
    • INSTANCE_ATTR with an empty string iscorrectpayload (the semantics are exactly "delete this property").

⚠️ Type names and document type prefixes (required reading for validation)

Graphic elements with the same name have different schemas under different document types:LINE on a schematic page it is a "wire" (with lineGroup/strokeColor…), while on a PCB it is a "trace" (with netName/layerId/width…). When validating, the validator must know which kind of document it is, otherwise it will take the wrong schema — manifesting as "a bunch of fields you don't need are missing" or "errors that should be reported are not reported".

Method 1 (recommended): when validating, use the <文档类型>_<图元名> prefix name:

node validate.js PCB_LINE '{"netName":"+5V",...}'
node validate.js PANEL_POLY '{...}'
node validate.js BOARD_META '{"title":"Board1",...}'

Method 2: use --doc to explicitly specify the document type (clearer when using bare names):

node validate.js LINE '{"netName":"+5V",...}' --doc PCB

Method 3: directly use the bare name — it will be resolved according to the priority of SCH_PAGE > SCH > SYMBOL > PCB > 其他 , andacross document types the resolution result is not what you want, so it is only reliable under schematic-type documents.

Common comparison (for the full list see validate.js in TYPE_MAP):

Document type Trace / wire Polygon Component Arc Metadata Canvas
SCH_PAGE / SYMBOL SCH_PAGE_LINE SCH_PAGE_POLY SCH_PAGE_COMPONENT SCH_PAGE_ARC SCH_PAGE_META SCH_PAGE_CANVAS
PCB / FOOTPRINT PCB_LINE PCB_POLY PCB_COMPONENT PCB_ARC PCB_META PCB_CANVAS
PANEL / PANEL_LIB PANEL_AUXLINE PANEL_POLY — — PANEL_META PANEL_CANVAS
SIMULATION SIMULATION_LINE SIMULATION_POLY SIMULATION_COMPONENT SIMULATION_ARC SIMULATION_META SIMULATION_CANVAS
BOARD / CONFIG / DEVICE / SCH / SIMULATION_SCH — — — — BOARD_META / CONFIG_META / SCH_META / SIMULATION_SCH_META … —

Required formats: DOCHEAD and CANVAS

Important: when generating any graphic element format,you mustfirst include DOCHEAD; the order is DOCHEAD → CANVAS → other graphic elements.CANVAS exists only for document types that contain a canvas(SCH_PAGE / SYMBOL / SIMULATION / PCB / FOOTPRINT / PANEL / PANEL_LIB, see the corresponding table below); documents such as FONT / BLOB / CONFIG / BOARD / DEVICE / SCH / SIMULATION_SCH do not have CANVAS, so do not add it.

DOCHEAD (document header)

DOCHEAD is the first line of every document, defining the document's type and metadata.

Format:

{"type":"DOCHEAD","ticket":1}||{docType, client, uuid, updateTime, version}

Field descriptions:

Field Type Required Description
docType string ✓ Document type, such as SCH_PAGE、PCB、SYMBOL、FOOTPRINT
client string ✓ Client ID - 16-digit lowercase hexadecimal(such as 1f0f511a4641034c), user-specifiable, otherwise AI-inferred
uuid string ✓ Document unique identifier - 16-digit lowercase hexadecimal, user-specifiable, otherwise AI-inferred
updateTime number - Update timestamp (milliseconds) - user-specifiable, otherwise AI-inferred (current time)
version string - Version number - user-specifiable, otherwise AI-inferred (usually the same as updateTime)

User field specification rules:

  • If the user provides client、uuid、updateTime、versionin the request, use the user-specified value (client / uuid must still satisfy 16-digit lowercase hexadecimal)
  • If the user does not provide it, the AI infers a reasonable default value:
    • client: generate a 16-digit lowercase hexadecimal string
    • uuid: generate a 16-digit lowercase hexadecimal string
    • updateTime: use the current timestamp (milliseconds)
    • version: same as updateTime : same as

Example (SCH_PAGE):

{"type":"DOCHEAD","ticket":1}||{"docType":"SCH_PAGE","client":"1f0f511a4641034c","uuid":"81ace96648894616","updateTime":1777537222142,"version":"1777537222142"}|

Example (user-specified client, which must also be 16-digit lowercase hexadecimal):

{"type":"DOCHEAD","ticket":1}||{"docType":"SCH_PAGE","client":"a1b2c3d4e5f60718","uuid":"81ace96648894616","updateTime":1777537222142,"version":"1777537222142"}|

Example (PCB):

{"type":"DOCHEAD","ticket":1}||{"docType":"PCB","client":"1f0f511a4641034c","uuid":"81ace96648894616","updateTime":1777537222142,"version":"1777537222142"}|

CANVAS (canvas configuration)

CANVAS is the second line of each document, defining the canvas origin and configuration information. Depending on the document type, the CANVAS format differs.

SCH_PAGE / SYMBOL canvas (simplified version)

Format:

{"type":"CANVAS","ticket":1,"id":"CANVAS"}||{originX, originY}

Field description:

Field Type Required Description
originX number ✓ Canvas origin X
originY number ✓ Canvas origin Y

Example:

{"type":"CANVAS","ticket":1,"id":"CANVAS"}||{"originX":0,"originY":0}

PCB / FOOTPRINT canvas (full version)

Format:

{"type":"CANVAS","ticket":1,"id":"CANVAS"}||{originX, originY, unit, gridXSize, gridYSize, ...}

Field description:

Field Type Required Description
originX number ✓ Canvas origin X
originY number ✓ Canvas origin Y
unit string ✓ Display unit (such as "mm", "mil")
gridXSize number ✓ Grid size X
gridYSize number ✓ Grid size Y
snapXSize number ✓ Raster size X
snapYSize number ✓ Raster size Y
altSnapXSize number ✓ Alt raster size X
altSnapYSize number ✓ Alt raster size Y
gridType EGridType ✓ Grid type (such as "GRID")
multiGridType EGridType ✓ Bold grid type
multiGridRatio number ✓ Bold grid multiple
highlightValue number ✓ Highlight brightness value
layerBrightness ELayerBrightness ✓ Layer brightness (such as "NORMAL")

Example (PCB / FOOTPRINT):

{"type":"CANVAS","ticket":1,"id":"CANVAS"}||{"originX":0,"originY":0,"unit":"mm","gridXSize":10,"gridYSize":10,"snapXSize":1,"snapYSize":1,"altSnapXSize":0.1,"altSnapYSize":0.1,"gridType":"NONE","multiGridType":"NONE","multiGridRatio":10,"highlightValue":0.5,"layerBrightness":"NORMAL"}

Example (PANEL / PANEL_LIB, fields are completely different from the grid canvas above):

{"type":"CANVAS","ticket":1,"id":"CANVAS"}||{"material":"acrylic","thickness":"0.8mm","print":"Bottom Side","craft":"Transparent","desc":"","coverColor":"white","width":"393mm","height":"579mm","originX":0,"originY":0,"orderWidth":"393mm","orderHeight":"579mm","backgroundColor":""}

Generation order and rules

Generation order:

  1. DOCHEAD (line 1) - fixed type is "DOCHEAD"
  2. CANVAS (line 2,only present for the document types listed below) - fixed ticket is 1, id is "CANVAS"
  3. Other primitives (starting from line 3) - ticket increments starting from 2

Document type and CANVAS type correspondence table:

Document type CANVAS type CANVAS format Type name for validation
SCH_PAGE TSchCanvas Simplified version (only originX, originY) SCH_PAGE_CANVAS
SYMBOL TSchCanvas Simplified version (only originX, originY) SYMBOL_CANVAS
SIMULATION TSchCanvas Simplified version (only originX, originY) SIMULATION_CANVAS
PCB TCanvas Full version PCB_CANVAS
FOOTPRINT TCanvas Full version FOOTPRINT_CANVAS
PANEL TPanelCanvas Panel canvas (material/thickness/printing/color…) PANEL_CANVAS
PANEL_LIB TPanelCanvas Panel canvas (material/thickness/printing/color…) PANEL_LIB_CANVAS

Document types without CANVAS: FONT, BLOB, CONFIG, BOARD, DEVICE, SCH, SIMULATION_SCH — these documents only have DOCHEAD + primitives, do not insert CANVAS lines.

LLM Workflow

Generation task reception

When receiving a format generation request (such as "generate the format for a via", "create a resistor component", "draw a wire"):

  1. Understand the request: Identify the primitive type the user wants to generate (such as via/component/wire) and the specific parameter requirements
  2. Find the type(first step, must be performed):
    • Search in types-index.md based on the user's Chinese description (such as "via", "component", "wire")
    • Find the corresponding type name (such as TPcbVia, TSchComponent, TSchLine) and document layer path
  3. Progressive loading of materials(load on demand, avoid reading too many files at once):
    • Enter the document layer: read the document for the corresponding domain (such as documents/PCB.md) → The document layer contains an index of all primitives in that domain
    • Enter the primitive layer: select a specific primitive from the index and read its definition (such as primitives/PCB/via.md) → The primitive layer contains field definitions, JSON Schema constraints, and related primitive descriptions
    • (Optional) Enter the example layer: if real data is needed for reference, read it via the link provided by the primitive layer (such as examples/PCB/t-pcb-via.md)
    • (Optional) View the Schema: the primitive layer provides a JSON Schema link, read it on demand
  4. Check related primitives:
    • View the "related primitives" section of the primitive layer (parent-child primitives, container members, embedded structures, reference associations)
    • If there are related primitive descriptions, related primitives must be generated
    • The values of related fields must correctly point to the main primitive
    • ⚠️ Do not ask the user: automatically infer related primitives based on the main primitive's coordinates and attributes
  5. Generate the format:
    • Prefer field values provided by the user
    • If the user did not provide them but the fields have default values, use the default values
    • If there are no default values, infer reasonable values based on the document constraints
    • At the same time, validate the attribute values provided by the user (adjust if there are conflicts)
    • If needed, also generate related primitives (one primitive format per line)
    • ⚠️ The coordinates and parameters of related primitives are automatically inferred by the AI, do not ask the user
  6. Validate the format:
    • Call the validation script to validate each generated primitive
    • The main primitive and all related primitives must pass validation
  7. Archive:
    • After validation passes, save all formats to files
    • Save each line of format as one file, or save multiple formats as one file

⚠️ Important:

  • Do not skip the step of querying materials; you must first collect enough information before generating the format!
  • When there are associated primitives, they must be generated together; you cannot generate only the main primitive!
  • The coordinates and parameters of associated primitives are automatically generated by AI; do not ask the user!

Example of associated primitives (DOCHEAD + CANVAS + TBus + LINE + ATTR)

Below is a complete SCH_PAGE file example (each line inside the code block can be copied directly):

Includes the file header, canvas, BUS primitive, and its associated primitives (4 LINEs and 1 ATTR):

{"type":"DOCHEAD","ticket":1}||{"docType":"SCH_PAGE","client":"1f0f511a4641034c","uuid":"81ace96648894616","updateTime":1777537222142,"version":"1777537222142"}|
{"type":"CANVAS","ticket":1,"id":"CANVAS"}||{"originX":0,"originY":0}|
{"type":"BUS","ticket":35,"id":"917cf8401f113481"}||{"busEntry":{},"zIndex":6,"groupId":"","locked":false}|
{"type":"LINE","ticket":36,"id":"899f254f57c290ca"}||{"fillColor":null,"fillStyle":null,"strokeColor":null,"strokeStyle":null,"strokeWidth":null,"startX":600,"startY":-570,"endX":680,"endY":-570,"lineGroup":"917cf8401f113481"}|
{"type":"LINE","ticket":37,"id":"0cbf6fa91e809769"}||{"fillColor":null,"fillStyle":null,"strokeColor":null,"strokeStyle":null,"strokeWidth":null,"startX":680,"startY":-570,"endX":680,"endY":-500,"lineGroup":"917cf8401f113481"}|
{"type":"LINE","ticket":38,"id":"133a0ef467701da4"}||{"fillColor":null,"fillStyle":null,"strokeColor":null,"strokeStyle":null,"strokeWidth":null,"startX":680,"startY":-500,"endX":505,"endY":-500,"lineGroup":"917cf8401f113481"}|
{"type":"LINE","ticket":39,"id":"e7c73f80b9a41723"}||{"fillColor":null,"fillStyle":null,"strokeColor":null,"strokeStyle":null,"strokeWidth":null,"startX":505,"startY":-500,"endX":505,"endY":-565,"lineGroup":"917cf8401f113481"}|
{"type":"ATTR","ticket":40,"id":"fd36cf31312bbfcd"}||{"x":592.5,"y":-500,"rotation":0,"color":null,"fontFamily":null,"fontSize":null,"fontWeight":null,"italic":null,"underline":null,"align":"LEFT_BOTTOM","value":"BUS[0:5]","keyVisible":false,"valueVisible":true,"key":"NET","fillColor":null,"parentId":"917cf8401f113481","zIndex":4,"groupId":"","locked":false,"strikeout":null}

In the code block above, the | at the end of each line is the line separator: every line except the last one must have it, and the last line must not.

Key points:

  • DOCHEAD defines the document type and metadata
  • CANVAS defines the canvas origin coordinates
  • Primitives in the same group reference each other by id: the LINE's lineGroup, the ATTR's parentId both point to the BUS's id
  • Primitives generated later have larger tickets
  • The end of each line format requires a | separator (except for the last line)

🔍 Verification steps (core process)

After generating the formatverification must be executed immediately:

Step 1: Call the verification script

# 用「文档类型_图元名」前缀名(推荐,跨文档类型的同名图元必须这样写)
node ./validate.js PCB_LINE '{"netName":"+5V",...}'
# 或用 --doc 指定文档类型
node ./validate.js LINE '{"netName":"+5V",...}' --doc PCB

Step 2: Check the verification result

{
  "valid": true,
  "errors": []
}
  • If valid: true and errors: [] → verification passed, save the format to a file
  • If valid: false → verification failed, needs to be fixed

Step 3: Save the format to a file (must be executed after verification passes)

# 保存到 format 目录
# 格式:{外层JSON}||{内层JSON}
# 示例:{"type":"LINE","id":"abc123","ticket":0}||{"startX":100,"startY":200}

Saving rules:

  • Save directory:./format(same directory as SKILL.md)
  • File name format:{type}_{timestamp}.txt
  • File content: separate multiple primitive formats with newlines, with a |at the end of each line format (except for the last line)
  • Note: The file format is text format

Important format rules:

  • The end of each primitive format string requires adding a | separator (except for the last primitive)
  • For example: the format string wrapped in backticks requires adding a | separator at the end
  • The end of the last primitive format stringdoes not needto add |

Step 4: If verification fails

  1. Parse errors the error information in the array
  2. According to field and message fix the corresponding fields
  3. Call the verification script again
  4. Retry at most 3 times

⚠️ Important: Do not skip the verification and saving steps, and do not assume the generated result is correct!

Verification command example:

node ./validate.js FONT '{"width":50,"height":40,"path":[[2,5,"L",2,35,48,35,48,5,2,5]]}'

JSON Schemas

  • schemas/ - Verify the schemas directory