$npx -y skills add AlpacaLabsLLC/skills-for-architects --skill zoning-analysis-nycAnalyze zoning envelope rules for lots in New York City using PLUTO data and the NYC Zoning Resolution. Use when the user asks "what can I build" on a NYC lot, requests a zoning analysis, or asks about FAR or height limits for an address. For variances and special permits use /ny
| 1 | # /zoning-analysis-nyc — Zoning Envelope Analysis (New York City) |
| 2 | |
| 3 | Analyze building envelope rules for any lot in New York City using the PLUTO database (NYC Open Data) and the NYC Zoning Resolution. |
| 4 | |
| 5 | ## Project Dossier |
| 6 | |
| 7 | If `PROJECT.md` exists in the working directory, read it before fetching — the BBL, district, and prior envelope results may already be on file. After completing, append the zoning district, FAR set, envelope results, overlays/special districts, and landmark status to its **Zoning** section. Update values in place (the dossier holds current state, not history), every entry with a source and date. If the analysis surfaces a choice between development paths (as-of-right vs. a City of Yes / UAP bonus scheme), propose recording it with `/decision`. No `PROJECT.md`? Skip silently — or mention `/project-dossier init` if the user is clearly starting a project. |
| 8 | |
| 9 | ## Workflow |
| 10 | |
| 11 | ### Step 1: Parse Input |
| 12 | |
| 13 | Accept one of the following identifiers: |
| 14 | - **Address + Borough/Zip** — e.g., "123 Main St, Brooklyn 11201" |
| 15 | - **BBL** — 10-digit Borough-Block-Lot (e.g., 3012340056 = Brooklyn, Block 1234, Lot 56) |
| 16 | - **BIN** — Building Identification Number |
| 17 | |
| 18 | Normalize to BBL format: `[borough 1 digit][block 5 digits][lot 4 digits]` |
| 19 | |
| 20 | Borough codes: |
| 21 | | Code | Borough | |
| 22 | |------|---------| |
| 23 | | 1 | Manhattan | |
| 24 | | 2 | Bronx | |
| 25 | | 3 | Brooklyn | |
| 26 | | 4 | Queens | |
| 27 | | 5 | Staten Island | |
| 28 | |
| 29 | ### Step 2: Query PLUTO (tabular + polygon) |
| 30 | |
| 31 | Fetch lot data from **two** NYC APIs in parallel: |
| 32 | |
| 33 | #### 2a. Tabular data (Socrata PLUTO) |
| 34 | |
| 35 | **Endpoint:** `https://data.cityofnewyork.us/resource/64uk-42ks.json` |
| 36 | |
| 37 | **Query by BBL:** |
| 38 | ``` |
| 39 | https://data.cityofnewyork.us/resource/64uk-42ks.json?bbl=XXXXXXXXXX |
| 40 | ``` |
| 41 | |
| 42 | **Query by address (fallback):** |
| 43 | ``` |
| 44 | https://data.cityofnewyork.us/resource/64uk-42ks.json?$where=address='123 MAIN STREET' AND zipcode='10001' |
| 45 | ``` |
| 46 | |
| 47 | No authentication required for basic queries. |
| 48 | |
| 49 | Read `zoning-rules/pluto-fields.md` for the full field reference. |
| 50 | |
| 51 | **Extract these key fields:** |
| 52 | - `bbl` — Borough-Block-Lot |
| 53 | - `address`, `zipcode` — street address |
| 54 | - `zonedist1` through `zonedist4` — zoning district(s) |
| 55 | - `overlay1`, `overlay2` — commercial overlay districts |
| 56 | - `spdist1`, `spdist2`, `spdist3` — special purpose districts |
| 57 | - `ltdheight` — limited height district |
| 58 | - `splitzone` — Y if lot is split across zones |
| 59 | - `lotarea` — lot area in SF |
| 60 | - `bldgarea` — total building area in SF |
| 61 | - `builtfar` — as-built FAR |
| 62 | - `residfar` — maximum residential FAR |
| 63 | - `commfar` — maximum commercial FAR |
| 64 | - `facilfar` — maximum community facility FAR |
| 65 | - `numfloors` — existing number of floors |
| 66 | - `landuse` — current land use category |
| 67 | - `zonemap` — zoning map number |
| 68 | - `landmark` — landmark designation |
| 69 | - `histdist` — historic district name |
| 70 | - `borocode`, `block`, `lot` — parsed BBL components |
| 71 | |
| 72 | #### 2b. Lot polygon (MapPLUTO ArcGIS Feature Service) |
| 73 | |
| 74 | **Endpoint:** `https://a841-dotweb01.nyc.gov/arcgis/rest/services/GAZETTEER/MapPLUTO/MapServer/0/query` |
| 75 | |
| 76 | **Query by BBL:** |
| 77 | ``` |
| 78 | https://a841-dotweb01.nyc.gov/arcgis/rest/services/GAZETTEER/MapPLUTO/MapServer/0/query?where=BBL='XXXXXXXXXX'&outFields=BBL&f=json&outSR=4326 |
| 79 | ``` |
| 80 | |
| 81 | This returns the **exact tax lot polygon** in WGS84 (lat/lon). No authentication required. |
| 82 | |
| 83 | **Convert to local feet:** |
| 84 | 1. Extract the `features[0].geometry.rings[0]` coordinate array (pairs of `[lon, lat]`) |
| 85 | 2. Compute the centroid latitude for the cos correction factor: `cos(lat)` |
| 86 | 3. Convert to local feet using: |
| 87 | - `x_ft = (lon - lon_min) × 111320 × cos(lat) × 3.28084` |
| 88 | - `y_ft = (lat - lat_min) × 111320 × 3.28084` |
| 89 | 4. Origin at the southernmost point (Y=0 at street/south side) |
| 90 | 5. Output a `LOT_POLY` array of `[x, y]` pairs in feet |
| 91 | 6. Verify the computed area against PLUTO's `lotarea` (expect ±5% due to projection) |
| 92 | |
| 93 | **Always use the real polygon** for the 3D envelope viewer. Never fall back to a `lotfront × lotdepth` rectangle when polygon data is available. |
| 94 | |
| 95 | If either query returns no results, inform the user and ask them to verify the address or BBL. |
| 96 | |
| 97 | ### Step 3: Identify Zoning District |
| 98 | |
| 99 | Map the `zonedist1` value to its district type: |
| 100 | |
| 101 | | Prefix | Type | Rules File | |
| 102 | |--------|------|----------------| |
| 103 | | R | Residential | `zoning-rules/residential.md` | |
| 104 | | C | Commercial | `zoning-rules/commercial.md` | |
| 105 | | M | Manufacturing | `zoning-rules/manufacturing.md` | |
| 106 | |
| 107 | Check for: |
| 108 | - **Split zones** (`splitzone = Y`): Analyze each `zonedist1`–`zonedist4` separately. Pro-rate FAR by estimated area in each zone if lot dimensions are available, otherwise present both sets of controls. |
| 109 | - **Contextual suffixes** |