-
Notifications
You must be signed in to change notification settings - Fork 0
docs: publish demo and public project guide #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,100 +1,150 @@ | ||
| # pi-steel | ||
|
|
||
| Structural steel estimating skills for the [Pi coding agent](https://pi.dev). | ||
| [](https://www.npmjs.com/package/@structupath/pi-steel) | ||
| [](https://github.com/StructuPath/pi-steel/actions/workflows/ci.yml) | ||
| [](LICENSE) | ||
| [](https://pi.dev/packages?name=pi-steel) | ||
|
|
||
| By [StructuPath](https://structupath.ai). | ||
| Structural-steel estimating skills for the [Pi coding agent](https://pi.dev): | ||
| validated takeoffs, plate nesting, guarded DXF output, draft vendor RFQs, and a | ||
| review-gated estimate pipeline. | ||
|
|
||
| Built by [StructuPath](https://structupath.ai). | ||
|
|
||
| ## Demo | ||
|
|
||
|  | ||
|
|
||
| This demo uses only the repository's synthetic fixture. It runs the complete | ||
| `takeoff → nest → draft RFQ` pipeline and publishes an isolated package with a | ||
| machine-readable `rfq_ready_for_review` outcome. | ||
|
|
||
| ## Install | ||
|
|
||
| ```bash | ||
| pi install npm:@structupath/pi-steel | ||
| ``` | ||
|
|
||
| ## What's Inside | ||
| Then ask Pi: | ||
|
|
||
| ```text | ||
| Do a structural-steel takeoff from these drawings and build a validated BOM. | ||
| Nest these rectangular plate parts on 96 × 48 stock. | ||
| Prepare a draft RFQ from this estimate. | ||
| ``` | ||
|
|
||
| Run the local dependency check when using the source repository: | ||
|
|
||
| ```bash | ||
| npm run doctor | ||
| ``` | ||
|
|
||
| ### `steel-takeoff` — takeoffs, BOMs, tonnage | ||
| ## What is included | ||
|
|
||
| Structural steel quantity takeoff with a bundled **AISC 16th Edition shapes database (477 shapes)** — W, HSS, angles, channels, pipe — plus scripts the agent runs directly: | ||
| | Skill | Purpose | Primary outputs | | ||
| | --- | --- | --- | | ||
| | `steel-takeoff` | Validate member designations and calculate BOM weight and tonnage | Validated BOM and findings | | ||
| | `steel-nest` | Lay out plate parts with kerf, gap, and edge-margin controls | Nest results, cut list, reference drawings, and guarded burn DXFs | | ||
| | `steel-rfq` | Compile estimate data into a reviewable vendor request | Draft `.xlsx` RFQ and semantic workbook record | | ||
| | `steel-estimate` | Orchestrate the complete review-gated workflow | Immutable run directory, QA report, lineage, manifests, nesting, and draft RFQ | | ||
|
|
||
| - `lookup-member.sh` — full property set for any AISC designation (`W14X30` → plf, d, bf, A, Ix, Sx, …) | ||
| - `calculate-weight.sh` — BOM weight totals with connection and misc-steel allowances and tonnage; it does not invent pricing | ||
| - `validate-bom.py` — catches invalid designations, wrong grades, duplicate marks, unreasonable weights | ||
| ### Takeoff | ||
|
|
||
| Also includes reference guides for AISC shape families, takeoff procedures with worked examples, connection types and hardware weights, material grades, and bolt capacities. | ||
| `steel-takeoff` provides AISC shape lookup, weight calculation, and BOM | ||
| validation helpers. It checks member designations, grades, duplicate marks, and | ||
| unreasonable weights. It calculates from supplied quantities and allowances; it | ||
| does not invent pricing. | ||
|
|
||
| Ask your agent things like: | ||
| ### Nesting and DXF safety | ||
|
|
||
| > "Do a takeoff from these drawings and build me a BOM" | ||
| > "What's the lightest W-shape with depth ≥ 18" and Ix ≥ 1000?" | ||
| > "Total tonnage on this BOM with 12% connections" | ||
| `steel-nest` uses MaxRects bin packing for rectangular parts and reports yield, | ||
| scrap, reusable drops, and unplaced material. Irregular parts are estimated by | ||
| bounding box and are always flagged. | ||
|
|
||
| ### `steel-nest` — plate nesting & guarded DXF output | ||
| Per-sheet `burn_plate_N.dxf` files are emitted only when the full nest is | ||
| complete and every supported hole remains inside its part. Otherwise, pi-steel | ||
| suppresses burn DXFs for the entire run and leaves clearly labeled estimating | ||
| and reference artifacts for review. It does not emit G-code or claim | ||
| machine-specific CAM compatibility. | ||
|
|
||
| The plate-layout step CAM software does, minus the CAM seat: MaxRects bin-packing of parts onto stock plates with kerf/gap/edge-margin spacing, holes and rectangular cutouts, yield/scrap/reusable-drop numbers, and material cost. Outputs include a labeled layout (PDF + PNG per plate), a cut list, and an explicitly named all-sheets reference DXF. | ||
| ### Draft RFQs | ||
|
|
||
| Per-sheet `burn_plate_N.dxf` files are emitted only for a complete rectangular nest whose supported holes remain inside their parts. Those files contain cut entities only: closed outlines on `PROFILE` and holes/cutouts on `HOLES`. Sheet outlines and labels remain in clearly named reference files. Any irregular part, unplaced part, or out-of-bounds hole suppresses burn DXFs for the whole job and leaves the safe estimating/reference artifacts available with an explicit warning. | ||
| `steel-rfq` groups material by stock family, carries approved nesting data into | ||
| the workbook, and provides fill-in columns for vendor pricing. Workbooks remain | ||
| drafts until a person reviews and issues them. | ||
|
|
||
| Honest about its limits: rectangular parts nest exactly; irregular parts nest by bounding box (flagged, never hidden); reference DXFs are not cutting instructions; and the package deliberately does **not** emit G-code. Kerf compensation, lead-ins, pierce points, and machine-specific verification belong to the table's real CAM and post-processor. | ||
| Copy the example company profile to a private project location: | ||
|
|
||
| Each command publishes an isolated run under the requested output root and updates | ||
| `latest-run.json`. Exit `0` is geometry-verified, `2` requires review, and `3` is | ||
| blocked. No named CAM compatibility is claimed. | ||
| ```bash | ||
| mkdir -p .pi-steel | ||
| cp skills/steel-rfq/assets/company-profile.example.json \ | ||
| .pi-steel/company-profile.json | ||
| ``` | ||
|
|
||
| > "How many sheets does this job need?" | ||
| > "Nest these parts on 96×48 plate and give me the yield" | ||
| > "Lay this out for the burn table" | ||
| Complete that local copy with approved company information. Never commit the | ||
| completed profile. | ||
|
|
||
| Requires `ezdxf`, `matplotlib`, `numpy` (`pip install ezdxf matplotlib numpy`). | ||
| ## Workflow and outcomes | ||
|
|
||
| ### `steel-rfq` — vendor quote requests | ||
| ```text | ||
| estimate input | ||
| ↓ | ||
| contract validation → plate nesting → draft RFQ compilation | ||
| ↓ | ||
| QA findings + lineage + immutable run manifest | ||
| ↓ | ||
| ready | needs_review | blocked | ||
| ``` | ||
|
|
||
| Turns a steel estimate/takeoff spreadsheet into a standardized vendor RFQ (.xlsx): materials grouped the way vendors stock them (W-shapes / plate / flat bar), yellow fill-in pricing columns, nesting/drop reference, and terms & conditions — branded with **your** company profile. When `steel-nest` has run for the job, its cutting plan flows straight into the RFQ's nesting table. | ||
| Each run is published below the requested output root and referenced by | ||
| `latest-run.json`. Exit status `0` means geometry-verified, `2` means human | ||
| review is required, and `3` means the workflow is blocked. A blocked run never | ||
| contains an RFQ workbook. | ||
|
|
||
| The `steel-estimate` orchestrator chains the skills into a review-gated estimating | ||
| pipeline: **takeoff → nest → draft RFQ**. It publishes immutable run directories, | ||
| QA findings, lineage, and readiness labels; blocked runs never contain a workbook. | ||
| ## Public-repository safety | ||
|
|
||
| One-time setup: copy `skills/steel-rfq/assets/company-profile.example.json` to the | ||
| ignored path `.pi-steel/company-profile.json` in your project and enter approved | ||
| company and commercial information there. Never add the completed profile to this | ||
| repository. | ||
| This repository and all committed examples are public. Do not add: | ||
|
|
||
| Keep company profiles, customer files, vendor information, live pricing, and generated | ||
| artifacts outside this repository. Public examples are synthetic and must follow | ||
| [`PUBLIC_DATA_POLICY.md`](PUBLIC_DATA_POLICY.md). | ||
| - company profiles or internal business context; | ||
| - customer, vendor, employee, project, bid, or contract data; | ||
| - live pricing, margins, terms, credentials, or private contact information; | ||
| - generated RFQs, takeoffs, PDFs, DXFs, spreadsheets, or output directories. | ||
|
|
||
| > "Prepare a draft RFQ from this takeoff" | ||
| > "Generate an RFQ from this estimate" | ||
| Keep operational inputs and generated artifacts outside the repository. See the | ||
| [public data policy](PUBLIC_DATA_POLICY.md) and | ||
| [data provenance record](DATA_PROVENANCE.md) before contributing. | ||
|
|
||
| ## Requirements | ||
| ## Documentation | ||
|
|
||
| - `jq` and `python3` (with `pandas` + `openpyxl` for RFQ generation) | ||
| - macOS or Linux | ||
| - [GitHub wiki](https://github.com/StructuPath/pi-steel/wiki) | ||
| - [Public data policy](PUBLIC_DATA_POLICY.md) | ||
| - [Data provenance](DATA_PROVENANCE.md) | ||
| - [Pi package catalog](https://pi.dev/packages?name=pi-steel) | ||
| - [npm package](https://www.npmjs.com/package/@structupath/pi-steel) | ||
|
|
||
| ## Development and release checks | ||
| ## Development | ||
|
|
||
| ```bash | ||
| npm test # base, no-render suite | ||
| npm run test:full # optional PDF/PNG/DXF/LibreOffice smoke tests | ||
| npm run privacy:check # public-repository data guard | ||
| npm run privacy:history # redacted audit of every reachable commit | ||
| npm run pack:check # npm contents plus unpacked-runtime smoke test | ||
| npm run test:full # PDF/PNG/DXF/LibreOffice smoke tests | ||
| npm run privacy:check # current public-repository data guard | ||
| npm run privacy:history # redacted audit of reachable history | ||
| npm run pack:check # npm contents and installed-runtime smoke test | ||
| npm run provenance:check # shape-data integrity and recorded decision | ||
| npm run release:check # complete release gate | ||
| ``` | ||
|
|
||
| `release:check` is intentionally blocked while redistribution permission for the | ||
| checked-in transformed AISC shape dataset remains unverified. See | ||
| [`DATA_PROVENANCE.md`](DATA_PROVENANCE.md). Do not publish a new package release | ||
| by bypassing that gate. | ||
| The latest npm release is `0.2.2`. The source repository also declares `0.2.2` | ||
| until a later release passes every publishing gate. | ||
|
|
||
| `release:check` intentionally blocks a new npm publication while redistribution | ||
| permission for the transformed AISC shape dataset remains unverified. Do not | ||
| bypass that gate. An updated README or demo reaches the Pi catalog only through | ||
| a future, fully approved npm release. | ||
|
|
||
| ## License | ||
|
|
||
| StructuPath-authored code and documentation are MIT licensed. That license does | ||
| not grant rights in third-party data. The checked-in AISC-derived shape data has | ||
| a separate, currently blocked redistribution decision documented in | ||
| [`DATA_PROVENANCE.md`](DATA_PROVENANCE.md). | ||
|
|
||
| --- | ||
|
|
||
| Building software for steel fabricators? See [structupath.ai](https://structupath.ai). | ||
| [DATA_PROVENANCE.md](DATA_PROVENANCE.md). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
| import hashlib | ||
| import re | ||
| import subprocess | ||
| import sys | ||
|
|
@@ -34,6 +35,10 @@ | |
| "private-key", | ||
| "private_key", | ||
| } | ||
| AUDITED_PUBLIC_BINARY_SHA256 = { | ||
| Path("docs/assets/pi-steel-demo.gif"): | ||
| "ae6ad7286fc5f1eca31e960d4ac4414b7a32a566b975ddacc7d662824c34d91c", | ||
| } | ||
| PATTERNS = { | ||
| "private operating-company claim": re.compile( | ||
| r"team behind (?:a|the) production structural[- ]steel", re.I | ||
|
|
@@ -59,6 +64,11 @@ | |
| } | ||
|
|
||
|
|
||
| def is_audited_public_binary(relative: Path, content: bytes) -> bool: | ||
| expected = AUDITED_PUBLIC_BINARY_SHA256.get(relative) | ||
| return expected is not None and hashlib.sha256(content).hexdigest() == expected | ||
|
|
||
|
|
||
| def tracked_files(root: Path = ROOT) -> list[Path]: | ||
| result = subprocess.run( | ||
| ["git", "ls-files", "--cached", "--others", "--exclude-standard"], | ||
|
|
@@ -128,8 +138,11 @@ def scan_paths( | |
| if suffix in FORBIDDEN_BINARY_SUFFIXES: | ||
| findings.append(f"{relative}: public repository must not contain {suffix} artifacts") | ||
| continue | ||
| content = path.read_bytes() | ||
| if is_audited_public_binary(relative, content): | ||
| continue | ||
| try: | ||
| text = path.read_bytes().decode("utf-8") | ||
| text = content.decode("utf-8") | ||
|
Comment on lines
+141
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Fail closed on hash mismatch at the audited path. Both scanner entry points treat a digest mismatch as ordinary content; benign UTF-8 replacements can therefore pass with zero findings, despite the policy requiring an exact path and SHA-256 digest.
Proposed fail-closed handling content = path.read_bytes()
- if is_audited_public_binary(relative, content):
- continue
+ if relative in AUDITED_PUBLIC_BINARY_SHA256:
+ if is_audited_public_binary(relative, content):
+ continue
+ findings.append(f"{relative}: audited public binary hash mismatch")
+ continueApply the equivalent logic in 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| except UnicodeDecodeError: | ||
| findings.append(f"{relative}: unknown binary file") | ||
| continue | ||
|
|
@@ -163,6 +176,8 @@ def _scan_bytes( | |
| return [ | ||
| f"{prefix}{relative}: public repository must not contain {suffix} artifacts" | ||
| ] | ||
| if is_audited_public_binary(relative, content): | ||
| return [] | ||
| try: | ||
| text = content.decode("utf-8") | ||
| except UnicodeDecodeError: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 4396
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 513
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 20834
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 5566
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 6644
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 1466
🏁 Script executed:
Repository: StructuPath/pi-steel
Length of output: 4686
Clarify the company profile copy path. The command uses a repo-relative source path, so it only works from a source checkout. If this is meant for installed-package users, point to the shipped example path; otherwise mark it as source-only.
🤖 Prompt for AI Agents