From ccf16e8cfffa32995d18b4313f0b0a7360ae3507 Mon Sep 17 00:00:00 2001 From: Cliff Brake Date: Sat, 25 Oct 2025 17:27:50 -0400 Subject: [PATCH 1/4] fix harper errors --- .harper-dictionary.txt | 6 +++ CHANGELOG.md | 6 +-- README.md | 109 ++++++++++++++++++++++++----------------- 3 files changed, 73 insertions(+), 48 deletions(-) create mode 100644 .harper-dictionary.txt diff --git a/.harper-dictionary.txt b/.harper-dictionary.txt new file mode 100644 index 0000000..73105ff --- /dev/null +++ b/.harper-dictionary.txt @@ -0,0 +1,6 @@ +GitPLM +IPN +MCUs +MPN +PLM +partmaster diff --git a/CHANGELOG.md b/CHANGELOG.md index fc51d32..558de41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ For more details or to discuss releases, please visit the ## [[0.7.1] - 2025-07-11](https://github.com/git-plm/gitplm/releases/tag/v0.7.1) -- rename release to more friendly names +- Rename release to more friendly names ## [[0.7.0] - 2025-07-11](https://github.com/git-plm/gitplm/releases/tag/v0.7.0) @@ -45,8 +45,8 @@ For more details or to discuss releases, please visit the ## [[0.6.1] - 2025-06-26](https://github.com/git-plm/gitplm/releases/tag/v0.6.1) -- add `-pmDir` command line parameter to specify parts database directory -- add support for loading multiple partmaster CSV files from a directory +- Add `-pmDir` command line parameter to specify parts database directory +- Add support for loading multiple partmaster CSV files from a directory - **breaking changes** - changed CSV column heading "qnty" to "qty" - breaking change: switched to using ',' in CSV files for delimiter instead of diff --git a/README.md b/README.md index 2e370c1..c5f40ab 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,31 @@ ![code stats](https://tokei.rs/b1/github/git-plm/gitplm?category=code) [![Go Report Card](https://goreportcard.com/badge/github.com/git-plm/gitplm)](https://goreportcard.com/report/github.com/git-plm/gitplm) -## Product Lifecycle Management (PLM) in Git. + + +- [Product Life cycle Management (PLM) in Git.](#product-life-cycle-management-plm-in-git) +- [Video overview](#video-overview) +- [Installation](#installation) +- [Usage](#usage) +- [Configuration](#configuration) +- [Part Numbers](#part-numbers) +- [Partmaster](#partmaster) +- [Components you manufacture](#components-you-manufacture) +- [Source and Release directories](#source-and-release-directories) +- [Special Files](#special-files) +- [Release configuration](#release-configuration) +- [Examples](#examples) +- [Principles](#principles) +- [Additional notes](#additional-notes) +- [Reference Information](#reference-information) + + +## Product Life cycle Management (PLM) in Git. Additional documents: - [Part numbers](https://github.com/git-plm/parts/blob/main/partnumbers.md) -- [Changelog](CHANGELOG.md) +- [Changelog](/CHANGELOG.md) - [Windows notes](windows.md) GitPLM is a tool and a collection of best practices for managing information @@ -22,11 +41,11 @@ solves.** GitPLM does several things: -- combines source BOMs with the partmaster to generate BOMs with manufacturing +- Combines source BOMs with the partmaster to generate BOMs with manufacturing information. -- automate the generation of release/manufacturing information -- create combined BOMs that include parts from all sub-assemblies -- gathers release data for all custom components in the design into one +- Automate the generation of release/manufacturing information +- Create combined BOMs that include parts from all sub-assemblies +- Gathers release data for all custom components in the design into one directory for release to manufacturing. An example output is shown below: @@ -52,11 +71,11 @@ Alternatively, you can: or -- clone the Git repo and run: `go run .` +- Clone the Git repo and run: `go run .` ## Usage -Type `gitplm` from a shell to see commandline options: +Type `gitplm` from a shell to see command line options: ``` Usage of gitplm: @@ -86,11 +105,11 @@ Available configuration options: ## Part Numbers -Each part used to make a product is defined by a +Each part used to make a product is defined by an [IPN (Internal Part Number)](https://github.com/git-plm/parts/blob/main/partnumbers.md). The convention used by GitPLM is: `CCC-NNN-VVVV` -- `CCC`: major category (RES, CAP, DIO, etc) +- `CCC`: major category (`RES`, `CAP`, `DIO`, etc.) - `NNN`: incrementing sequential number for each part - `VVVV`: variation to code variations of a parts typically with the **same datasheet** (resistance, capacitance, regulator voltage, IC package, etc.) @@ -105,7 +124,7 @@ manufacturer part number (MPN) is also included. If multiple sources are available for a part, these can be entered on additional lines with the same IPN, and different Manufacturer/MPN specified. GitPLM will -merge other fields like Description, Value, etc so these only need to be +merge other fields like Description, Value, etc. so these only need to be specified on one of the lines. The `Priority` column is used to select the preferred part (lowest number wins). If no `Priority` is set, it defaults to 0 (highest priority). Currently, GitPLM picks the highest priority part and @@ -113,10 +132,10 @@ populates that in the output BOM. In the future, we could add additional columns for multiple sources. CAD tool libraries should contain IPNs, not MPNs. _Why not just put MPNs in the -CAD database?_ The fundamental reason is that a single part may be used in 100's -of different places and dozens of assemblies. If you need to change a supplier -for a part, you don't want to manually modify a dozen designs, generate new -BOMs, etc. This is manual, tedious, and error prone. What you want to do is +CAD database?_ The fundamental reason is that a single part may be used in +hundreds of different places and dozens of assemblies. If you need to change a +supplier for a part, you don't want to manually modify a dozen designs, generate +new BOMs, etc. This is manual, tedious, and error prone. What you want to do is change the manufacturer information in the partmaster and then automatically generate new BOMs for all affected products. Because the BOMs are stored in Git, it is easy to review what changed. @@ -125,18 +144,18 @@ it is easy to review what changed. A product is typically a collection of custom parts you manufacture and off-the-shelf parts you purchase. Custom parts are identified by the following -`CCC`s: - -| Code | Description | -| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| PCA | Printed Circuit Assembly. The version is incremented any time the BOM for the assembly changes. | -| PCB | Printed Circuit board. This category identifies the bare PCB board. | -| ASY | Assembly (can be mechanical or top level subassembly -- typically represented by BOM and documentation). Again, the variation is incremented any time a BOM line item changes. You can also use product specific prefixes such as GTW (gateway). | -| DOC | standalone documents | -| DFW | data -- firmware to be loaded on MCUs, etc | -| DSW | data -- software (images for embedded Linux systems, applications, programming utilities, etc) | -| DCL | data -- calibration data for a design | -| FIX | manufacturing fixtures | +`CCC` codes: + +| Code | Description | +| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `PCA` | Printed Circuit Assembly. The version is incremented any time the BOM for the assembly changes. | +| `PCB` | Printed Circuit board. This category identifies the bare PCB board. | +| `ASY` | Assembly (can be mechanical or top level subassembly - typically represented by BOM and documentation). Again, the variation is incremented any time a BOM line item changes. You can also use product specific prefixes such as `GTW` (gateway). | +| `DOC` | standalone documents | +| `DFW` | Data - firmware to be loaded on MCUs, etc. | +| `DSW` | Data - software (images for embedded Linux systems, applications, programming utilities, etc.) | +| `DCL` | Data - calibration data for a design | +| `FIX` | manufacturing fixtures | If IPN with the above category codes are found in a BOM, GitPLM looks for release directory that matches the IPN and then soft-links from the release @@ -148,8 +167,8 @@ hierarchy of release directories for the entire product. For parts you produce, GitPLM scans the directory tree looking for source directories which are identified by one or both of the following files: -- an input BOM. Ex: `ASY-023.csv` or `ASY-023-01.csv` -- a release configuration file. Ex: `PCB-019.yml` or `PCB-019-02.yml` +- An input BOM. Ex: `ASY-023.csv` or `ASY-023-01.csv` +- A release configuration file. Ex: `PCB-019.yml` or `PCB-019-02.yml` GitPLM supports two file naming patterns for source files: @@ -179,7 +198,7 @@ A source directory might contain: - Mechanical design files - Test procedures - User documentation -- Test Fixures/Procedures +- Test Fixtures/Procedures Release directories are identified by a full IPN. Examples: @@ -236,9 +255,9 @@ Supported operations: - `remove`: remove a part from a BOM - `add`: add a part to a BOM -- `copy`: copy a file or dir to the release directory -- `hooks`: run shell scripts (currently Linux/MacOS only). Can be used to build - software, generate PDFs, etc. +- `copy`: copy a file or directory to the release directory +- `hooks`: run shell scripts (currently Linux and MacOS only). Can be used to + build software, generate PDFs, etc. - `required`: looks for required files in the release directory and stops with an error if they are not found. This is used to check that manually generated files have been populated. @@ -258,40 +277,40 @@ with `gitplm` if you have it installed. ## Principles -- manual operations/tweaks to machine generated files are bad. If changes are +- Manual operations/tweaks to machine generated files are bad. If changes are made (example a BOM line item add/removed/changed), this needs to be defined declaratively and then this change applied by a program. Ideally this mechanism is also idempotent, so we describe where we want to end up, not steps to get there. The program can determine how to get there. -- the number of parts used in a product is bounded, and can easily fit in +- The number of parts used in a product is bounded, and can easily fit in computer memory (IE, we probably don't need a database for small/mid sized companies) -- the total number of parts a company may use (partmaster) is also bounded, and +- The total number of parts a company may use (partmaster) is also bounded, and will likely fit in memory for most small/mid sized companies. - tracking changes is important - review is important, thus Git workflow is beneficial - ASCII (text) files are preferred as they can be manually edited and changes easily review in Git workflows. -- versions are cheap -- `VVVV` should be incremented liberally. +- Versions are cheap - `VVVV` should be incremented liberally. - PLM software should not be tied to any one CAD tool, but should be flexible enough to work with any CAD output. ## Additional notes -- use CSV files for partmaster and all BOMs. - - _rational: can be read and written by excel, libreoffice, or by machine_ - - _rational: easy to get started_ -- versions in part numbers are sequential numbers: (0, 1, 2, 3, 4) - - _rational: easy to use in programs, sorting, etc_ +- Use CSV files for partmaster and all BOMs. + - _Rational: can be read and written by excel, LibreOffice, or by machine_ + - _Rational: easy to get started_ +- Versions in part numbers are sequential numbers: (0, 1, 2, 3, 4) + - _rational: easy to use in programs, sorting, etc._ - CAD BOMs are never manually "scrubbed". If additional parts are needed in the assembly, create a higher level BOM that includes the CAD generated BOM, or create a `*.yml` file to declaratively describe modifications to the BOM. - - _rational: since the CAD program generates the BOM in the first place, any + - _Rational: since the CAD program generates the BOM in the first place, any manual processing of this BOM will only lead to mistakes._ - CSV files should be delimited with ';' instead of ','. - - _rational: comma is useful in lists, descriptions, etc._ + - _Rational: comma is useful in lists, descriptions, etc._ - Tooling is written in Go. - - _rational:_ + - _Rational:_ - _Go programs are reasonably [reliable](http://bec-systems.com/site/1625/why-are-go-applications-so-reliable)_ - _it is easy to generate standalone binaries for most platforms with no From 09aac842e8f0921391c0aed3bdb08dbb86b8a7c6 Mon Sep 17 00:00:00 2001 From: Cliff Brake Date: Sat, 25 Oct 2025 17:36:38 -0400 Subject: [PATCH 2/4] add claude commands --- .claude/commands/implement.md | 5 +++++ .claude/commands/plan.md | 7 +++++++ .claude/commands/update-docs.md | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 .claude/commands/implement.md create mode 100644 .claude/commands/plan.md create mode 100644 .claude/commands/update-docs.md diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md new file mode 100644 index 0000000..86289fb --- /dev/null +++ b/.claude/commands/implement.md @@ -0,0 +1,5 @@ +Implement any code changes described in the documentation (\*.md) changes (git +diff) and `plans/` directory. + +Note for this command, the documentation is driving the code changes, not the +other way around. diff --git a/.claude/commands/plan.md b/.claude/commands/plan.md new file mode 100644 index 0000000..329f688 --- /dev/null +++ b/.claude/commands/plan.md @@ -0,0 +1,7 @@ +Create a plan file named `plans/-"$ARGUMENTS".md`. Replace spaces +with '-' in the filename. + +Then switch to plan mode and create a plan for coding the current changes +described in the README.md and other documentation files. Note, in this phase, +we are using documentation to drive the code, not the other way around. When the +plan is complete, write it to the plan file. diff --git a/.claude/commands/update-docs.md b/.claude/commands/update-docs.md new file mode 100644 index 0000000..86a227c --- /dev/null +++ b/.claude/commands/update-docs.md @@ -0,0 +1,4 @@ +Update any relevant documentation for the current code changes (git diff) + +The changelog should describe changes as benefits to the user. It should not +include technical details of the change, that is what git log is for. From c50c98fea23dcb311c12df2d91f25b3bac6ff097 Mon Sep 17 00:00:00 2001 From: Cliff Brake Date: Sat, 25 Oct 2025 20:08:43 -0400 Subject: [PATCH 3/4] KiCad HTTP API working --- README.md | 69 +++++++++ config.go | 9 +- gitplm.kicad_httplib | 15 ++ kicad_api.go | 70 ++++++--- main.go | 13 +- plans/2025-10-25-kicad-http-library.md | 200 +++++++++++++++++++++++++ 6 files changed, 353 insertions(+), 23 deletions(-) create mode 100644 gitplm.kicad_httplib create mode 100644 plans/2025-10-25-kicad-http-library.md diff --git a/README.md b/README.md index c5f40ab..e55e8c4 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,75 @@ Supported operations: The release process should be automated as much as possible to process the source files and generate the release information with no manual steps. +## KiCad HTTP Libraries support + +GitPLM can serve a parts database to KiCad using the +[KiCad HTTP Libraries feature](https://dev-docs.kicad.org/en/apis-and-binding/http-libraries/). + +### Starting the HTTP Server + +Start the server using the `-http` flag: + +```bash +# Start with default settings (port 7654) +gitplm -http -pmDir /path/to/partmaster + +# Start with custom port +gitplm -http -port 8080 -pmDir /path/to/partmaster + +# Start with authentication token +gitplm -http -token mysecrettoken -pmDir /path/to/partmaster +``` + +Alternatively, configure the server in `gitplm.yml`: + +```yaml +pmDir: /path/to/partmaster/directory + +http: + enabled: true + port: 7654 + token: "" # Optional authentication token +``` + +Then simply run `gitplm` to start the server with configured settings. + +### Configuring KiCad + +To use GitPLM as a parts library in KiCad: + +1. Open KiCad and go to **Preferences → Configure Paths** +2. Add a new HTTP library with the URL: `http://localhost:7654/v1/` +3. If you configured an authentication token, add it in the library settings +4. The parts will now be available in the Symbol Chooser + +### API Endpoints + +The server exposes the following endpoints: + +- `GET /v1/` - API discovery (returns links to categories and parts) +- `GET /v1/categories.json` - List all part categories (CAP, RES, etc.) +- `GET /v1/parts/category/{category_id}.json` - List parts in a category +- `GET /v1/parts/{part_id}.json` - Get detailed information for a specific part +- `GET /health` - Health check endpoint + +Examples: + +- [http://localhost:7654/v1/categories.json](http://localhost:7654/v1/categories.json) +- [http://localhost:7654/v1/parts/category/CAP.json](http://localhost:7654/v1/parts/category/CAP.json) - + Lists all capacitor parts +- [http://localhost:7654/v1/parts/category/RES.json](http://localhost:7654/v1/parts/category/RES.json) - + Lists all resistor parts + +### How It Works + +GitPLM automatically: + +- Loads all CSV files from the partmaster directory +- Extracts categories from filenames and IPNs +- Maps parts to appropriate KiCad symbols +- Serves part data with all fields from the CSV (Description, Value, MPN, etc.) + ## Examples See the examples folder. You can run commands like to exercise GitPLM: diff --git a/config.go b/config.go index f24ad7c..800b54d 100644 --- a/config.go +++ b/config.go @@ -7,8 +7,15 @@ import ( "gopkg.in/yaml.v2" ) +type HTTPConfig struct { + Enabled bool `yaml:"enabled"` + Port int `yaml:"port"` + Token string `yaml:"token"` +} + type Config struct { - PMDir string `yaml:"pmDir"` + PMDir string `yaml:"pmDir"` + HTTP HTTPConfig `yaml:"http"` } func loadConfig() (*Config, error) { diff --git a/gitplm.kicad_httplib b/gitplm.kicad_httplib new file mode 100644 index 0000000..0e966a1 --- /dev/null +++ b/gitplm.kicad_httplib @@ -0,0 +1,15 @@ +{ + "meta": { + "version": 1.0 + }, + "name": "GitPLM KiCad HTTP Library", + "description": "Verifiable parts database and KiCad Libraries", + "source": { + "type": "REST_API", + "api_version": "v1", + "root_url": "http://localhost:7654/", + "token": "", + "timeout_parts_seconds": 15, + "timeout_categories_seconds": 15 + } +} diff --git a/kicad_api.go b/kicad_api.go index fcdf394..d500d8f 100644 --- a/kicad_api.go +++ b/kicad_api.go @@ -101,14 +101,9 @@ func (s *KiCadServer) authenticate(r *http.Request) bool { func (s *KiCadServer) getCategories() []KiCadCategory { categoryMap := make(map[string]bool) - // Extract categories from CSV files and IPNs + // Extract categories from CSV files - use IPNs from each file for _, file := range s.csvCollection.Files { - // Try to extract category from filename (e.g., cap.csv -> CAP) - if fileName := strings.TrimSuffix(strings.ToUpper(file.Name), ".CSV"); fileName != "" && len(fileName) == 3 { - categoryMap[fileName] = true - } - - // Also extract from IPNs if they exist + // Extract from IPNs if they exist if ipnIdx := s.findColumnIndex(file, "IPN"); ipnIdx >= 0 { for _, row := range file.Rows { if len(row) > ipnIdx && row[ipnIdx] != "" { @@ -149,8 +144,8 @@ func (s *KiCadServer) findColumnIndex(file *CSVFile, columnName string) int { // extractCategory extracts the CCC component from an IPN func (s *KiCadServer) extractCategory(ipnStr string) string { - // IPN format: CCC-NNN-VVVV - re := regexp.MustCompile(`^([A-Z][A-Z][A-Z])-(\d\d\d)-(\d\d\d\d)$`) + // IPN format: CCC-NNNN-VVVV (also supports CCC-NNN-VVVV for legacy) + re := regexp.MustCompile(`^([A-Z][A-Z][A-Z])-(\d{3,4})-(\d{4})$`) matches := re.FindStringSubmatch(ipnStr) if len(matches) >= 2 { return matches[1] @@ -161,9 +156,24 @@ func (s *KiCadServer) extractCategory(ipnStr string) string { // getCategoryDisplayName returns a human-readable name for a category func (s *KiCadServer) getCategoryDisplayName(category string) string { displayNames := map[string]string{ + "ANA": "Analog ICs", + "ART": "Artwork", "CAP": "Capacitors", - "RES": "Resistors", + "CON": "Connectors", + "CPD": "Compound Components", "DIO": "Diodes", + "ICS": "Integrated Circuits", + "IND": "Inductors", + "MCU": "Microcontrollers", + "MPU": "Microprocessors", + "OPT": "Optical Components", + "OSC": "Oscillators", + "PWR": "Power Components", + "REG": "Regulators", + "RES": "Resistors", + "RFM": "RF Modules", + "SWI": "Switches", + "XTR": "Transceivers", "LED": "LEDs", "SCR": "Screws", "MCH": "Mechanical", @@ -177,9 +187,7 @@ func (s *KiCadServer) getCategoryDisplayName(category string) string { "FIX": "Fixtures", "CNT": "Connectors", "IC": "Integrated Circuits", - "OSC": "Oscillators", "XTL": "Crystals", - "IND": "Inductors", "FER": "Ferrites", "FUS": "Fuses", "SW": "Switches", @@ -202,9 +210,24 @@ func (s *KiCadServer) getCategoryDisplayName(category string) string { // getCategoryDescription returns a description for a category func (s *KiCadServer) getCategoryDescription(category string) string { descriptions := map[string]string{ + "ANA": "Analog integrated circuits", + "ART": "Artwork and graphics components", "CAP": "Capacitor components", - "RES": "Resistor components", + "CON": "Connector components", + "CPD": "Compound and complex components", "DIO": "Diode components", + "ICS": "Integrated circuit components", + "IND": "Inductor components", + "MCU": "Microcontroller components", + "MPU": "Microprocessor components", + "OPT": "Optical components", + "OSC": "Oscillator components", + "PWR": "Power supply and management components", + "REG": "Voltage regulator components", + "RES": "Resistor components", + "RFM": "RF module components", + "SWI": "Switch components", + "XTR": "Transceiver components", "LED": "Light emitting diode components", "SCR": "Screw and fastener components", "MCH": "Mechanical components", @@ -218,9 +241,7 @@ func (s *KiCadServer) getCategoryDescription(category string) string { "FIX": "Fixture components", "CNT": "Connector components", "IC": "Integrated circuit components", - "OSC": "Oscillator components", "XTL": "Crystal components", - "IND": "Inductor components", "FER": "Ferrite components", "FUS": "Fuse components", "SW": "Switch components", @@ -319,24 +340,35 @@ func (s *KiCadServer) getPartDetail(partID string) *KiCadPartDetail { if rowPartID == partID { fields := make(map[string]KiCadPartField) partName := "" - category := s.extractCategory(partID) + symbolID := "" // Add all fields from the CSV dynamically for i, header := range file.Headers { if i < len(row) && row[i] != "" && header != "" { - fields[header] = KiCadPartField{Value: row[i]} - // Set name from Description field if header == "Description" { partName = row[i] } + + // Set symbol from Symbol field + if header == "Symbol" { + symbolID = row[i] + } else { + // Add field to fields map (exclude Symbol as it goes in symbolIdStr) + fields[header] = KiCadPartField{Value: row[i]} + } } } + // Error if no Symbol field found + if symbolID == "" { + log.Printf("ERROR: Part %s has no Symbol field defined", partID) + } + return &KiCadPartDetail{ ID: partID, Name: partName, - SymbolIDStr: s.getSymbolIDFromCategory(category), + SymbolIDStr: symbolID, ExcludeFromBOM: "false", // Default to include in BOM Fields: fields, } diff --git a/main.go b/main.go index 36efcac..975b233 100644 --- a/main.go +++ b/main.go @@ -22,15 +22,22 @@ func main() { os.Exit(-1) } + // Set defaults from config + defaultPort := 7654 + if config.HTTP.Port > 0 { + defaultPort = config.HTTP.Port + } + defaultToken := config.HTTP.Token + flagRelease := flag.String("release", "", "Process release for IPN (ex: PCB-056-0005, ASY-002-0023)") flagVersion := flag.Bool("version", false, "display version of this application") flagSimplify := flag.String("simplify", "", "simplify a BOM file, combine lines with common MPN") flagOutput := flag.String("out", "", "output file") flagCombine := flag.String("combine", "", "adds BOM to output bom") flagPMDir := flag.String("pmDir", config.PMDir, "specify location of partmaster CSV files") - flagHTTPServer := flag.Bool("http", false, "start KiCad HTTP Library API server") - flagHTTPPort := flag.Int("port", 8080, "HTTP server port") - flagHTTPToken := flag.String("token", "", "authentication token for HTTP API") + flagHTTPServer := flag.Bool("http", config.HTTP.Enabled, "start KiCad HTTP Library API server") + flagHTTPPort := flag.Int("port", defaultPort, "HTTP server port (default: 7654)") + flagHTTPToken := flag.String("token", defaultToken, "authentication token for HTTP API") flag.Parse() if *flagVersion { diff --git a/plans/2025-10-25-kicad-http-library.md b/plans/2025-10-25-kicad-http-library.md new file mode 100644 index 0000000..cbd467f --- /dev/null +++ b/plans/2025-10-25-kicad-http-library.md @@ -0,0 +1,200 @@ +# Plan: KiCad HTTP Library Implementation + +**Date:** 2025-10-25 +**Status:** Draft +**Goal:** Complete implementation of KiCad HTTP Libraries API support for GitPLM + +## Context + +Based on the README.md changes, GitPLM now includes support for serving a parts database to KiCad using the KiCad HTTP Libraries feature. The implementation is already substantially complete in `kicad_api.go`, but this plan documents the current state and any remaining work needed. + +## Current State Analysis + +### What's Already Implemented + +The codebase already has a working KiCad HTTP library server implementation: + +1. **Core Server (`kicad_api.go`):** + - `KiCadServer` struct with partmaster directory and CSV collection loading + - Authentication via token (optional) + - Four main HTTP endpoints: + - Root endpoint (`/v1/`) - returns API discovery + - Categories endpoint (`/v1/categories.json`) - lists part categories + - Parts by category (`/v1/parts/category/{id}.json`) - lists parts in a category + - Part detail (`/v1/parts/{id}.json`) - returns detailed part information + - Category extraction from CSV filenames and IPNs + - Display names and descriptions for common categories (CAP, RES, DIO, etc.) + - Symbol mapping to KiCad standard library symbols + - Health check endpoint (`/health`) + +2. **Main Program Integration (`main.go`):** + - Command-line flags for HTTP server mode: + - `-http`: Start HTTP server + - `-port`: Server port (default 8080) + - `-token`: Authentication token (optional) + - Server starts on configured port (README says 7654, but default is 8080) + +3. **CSV Data Loading (`csv_data.go`):** + - `CSVFileCollection` for loading multiple CSV files + - `loadAllCSVFiles()` to scan directory for CSV files + - Partmaster parsing with IPN validation + - Support for multiple CSV files in partmaster directory + +### Issues and Improvements Needed + +1. **Port Mismatch:** + - README.md states "The HTTP server is started on port 7654" + - But `main.go` has default port 8080 + - Need to align these (probably change default to 7654) + +2. **Documentation Gaps:** + - No usage examples in README for how to start the server + - No configuration examples for KiCad to connect to the server + - Missing information about what URL to configure in KiCad + +3. **Testing:** + - No automated tests for the HTTP API + - No example curl commands or integration tests + +4. **Configuration:** + - Server settings (port, token) not available in YAML config + - Only available as command-line flags + +5. **Feature Completeness:** + - CHANGELOG marks this as "WIP" (Work in Progress) + - May need validation against actual KiCad HTTP library spec + +## Implementation Plan + +### Phase 1: Port and Configuration Alignment +**Priority:** High +**Estimated Effort:** 15 minutes + +1. **Fix Port Default:** + - Change default port from 8080 to 7654 in `main.go:32` + - Rationale: Align with README documentation + +2. **Add YAML Configuration Support:** + - Add HTTP server settings to `config.go`: + - `httpPort` (default: 7654) + - `httpToken` (default: empty) + - `httpEnabled` (default: false) + - Update config loading to support these fields + - Update `main.go` to prefer config file values, fall back to flags + +### Phase 2: Documentation Enhancement +**Priority:** High +**Estimated Effort:** 30 minutes + +1. **Update README.md:** + - Add usage section for HTTP server mode + - Include example commands: + ```bash + # Start server with default settings + gitplm -http -pmDir /path/to/partmaster + + # Start with custom port + gitplm -http -port 7654 -pmDir /path/to/partmaster + + # Start with authentication + gitplm -http -token mysecrettoken -pmDir /path/to/partmaster + ``` + - Add KiCad configuration instructions + - Document the API endpoints + +2. **Create Example Configuration:** + - Add example `gitplm.yml` with HTTP settings: + ```yaml + pmDir: /path/to/partmaster/directory + http: + enabled: false + port: 7654 + token: "" + ``` + +### Phase 3: Testing and Validation +**Priority:** Medium +**Estimated Effort:** 1-2 hours + +1. **Create Integration Test:** + - Add `kicad_api_test.go` with tests for: + - Server initialization + - Category extraction + - Part retrieval + - Authentication + - Error handling + +2. **Manual Testing:** + - Test against actual KiCad installation + - Verify all endpoints return correct JSON format + - Test with various CSV file structures + +3. **Add Example Requests:** + - Document curl commands for testing + - Add to README or separate TESTING.md + +### Phase 4: Feature Enhancements (Optional) +**Priority:** Low +**Estimated Effort:** 2-4 hours + +1. **Caching:** + - Add CSV reload capability (watch for file changes) + - Or add manual reload endpoint + +2. **Search Functionality:** + - Add search endpoint for parts by description/MPN/value + - Support filtering in parts list + +3. **HTTPS Support:** + - Add TLS/SSL configuration options + - Generate or use provided certificates + +4. **CORS Support:** + - Add CORS headers if needed for web-based tools + +## Implementation Sequence + +### Immediate (Next PR) +1. Fix port default to 7654 +2. Update README with usage examples +3. Add HTTP configuration to YAML config + +### Follow-up (Future PRs) +1. Add comprehensive tests +2. Manual validation with KiCad +3. Optional enhancements based on user feedback + +## Success Criteria + +- [ ] Server starts successfully with default port 7654 +- [ ] All four main endpoints return valid JSON +- [ ] Categories are correctly extracted from CSV files +- [ ] Parts are correctly filtered by category +- [ ] Part details include all CSV fields +- [ ] Authentication works when token is provided +- [ ] README includes clear usage instructions +- [ ] Configuration can be set via YAML file +- [ ] Manual testing with KiCad succeeds + +## Files to Modify + +1. `main.go` - Change default port to 7654, add YAML config support +2. `config.go` - Add HTTP server configuration fields +3. `README.md` - Add usage examples and configuration instructions +4. `gitplm.yml` (example) - Add HTTP configuration example +5. `kicad_api_test.go` (new) - Add comprehensive tests + +## Notes + +- The core implementation is already solid and well-structured +- Main work is polish, documentation, and testing +- Consider marking feature as stable (remove WIP) after testing phase +- May want to add logging/metrics for production use +- Consider rate limiting if server is exposed publicly + +## References + +- KiCad HTTP Libraries API: https://dev-docs.kicad.org/en/apis-and-binding/http-libraries/ +- Existing implementation: `kicad_api.go:1-495` +- Main program: `main.go:149-168` +- CSV loading: `csv_data.go:75-101` From 039d88a720de40f8c5a119872243678b9a4c6c9c Mon Sep 17 00:00:00 2001 From: Cliff Brake Date: Fri, 31 Oct 2025 11:53:14 -0400 Subject: [PATCH 4/4] work on kicad http library api --- README.md | 2 ++ kicad_api.go | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e55e8c4..ec2600b 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,8 @@ http: Then simply run `gitplm` to start the server with configured settings. +### Configuring what fields are visible + ### Configuring KiCad To use GitPLM as a parts library in KiCad: diff --git a/kicad_api.go b/kicad_api.go index d500d8f..9bc9fe9 100644 --- a/kicad_api.go +++ b/kicad_api.go @@ -341,6 +341,7 @@ func (s *KiCadServer) getPartDetail(partID string) *KiCadPartDetail { fields := make(map[string]KiCadPartField) partName := "" symbolID := "" + category := s.extractCategory(partID) // Add all fields from the CSV dynamically for i, header := range file.Headers { @@ -365,8 +366,14 @@ func (s *KiCadServer) getPartDetail(partID string) *KiCadPartDetail { log.Printf("ERROR: Part %s has no Symbol field defined", partID) } + // Format ID as category/part-id (e.g., "rfm/RFM-0000-0001") + formattedID := partID + if category != "" { + formattedID = strings.ToLower(category) + "/" + partID + } + return &KiCadPartDetail{ - ID: partID, + ID: formattedID, Name: partName, SymbolIDStr: symbolID, ExcludeFromBOM: "false", // Default to include in BOM