dd-l1-vienna-gpkg-manifest

Status: done
Score: 1.000
Duration: 0:40
Cost: 0.08¢
Model: deepseek/deepseek-v4-flash

Map (reference ← swipe → agent)

0:00
Inherited a GPKG (vienna_planning) from a colleague who retired last week. Before I commit to scripting against it I need a one-page manifest so I can see what's in there and decide which layers actually feed next month's councillor briefing. Catalog the contents and give me one record per layer. Output manifest.json — a JSON list of these records. Each record in the list must be a JSON object with exactly five keys: `layer_name` as a string, `crs` as a string in `EPSG:NNNN` form, `geometry_type` as a string matching the layer's native type (e.g. `Point`, `LineString`, `Polygon`, `MultiPolygon`), `feature_count` as an integer, and `bbox` as a list of four numbers `[xmin, ymin, xmax, ymax]` in the layer's native CRS.
0:00
System info
{
  "adapter": "openrouter",
  "model": "deepseek/deepseek-v4-flash",
  "base_url": "https://openrouter.ai/api/v1"
}
0:08
Let me start by exploring the GPKG file to understand its contents.
0:08
Bash ls -la /work/vienna_planning.gpkg
-rw-r--r-- 1 agent agent 524288 Jun 16 22:51 /work/vienna_planning.gpkg
0:19
Let me first explore the GPKG file to see what layers are in it.
0:19
Bash cd /work && python3 -c "
cd /work && python3 -c "
import sqlite3
conn = sqlite3.connect('vienna_planning.gpkg')
cur = conn.cursor()
cur.execute(\"SELECT table_name, geometry_type_name FROM gpkg_contents LEFT JOIN gpkg_geometry_columns USING (table_name)\")
rows = cur.fetchall()
for r in rows:
    print(r)
conn.close()
"
('cafes', 'POINT')
('cycleway_segments', 'LINESTRING')
('districts', 'POLYGON')
('parks', 'MULTIPOLYGON')
('schools', 'POINT')
('supermarkets', 'POINT')
('waterbodies', 'POLYGON')
0:29
I have the layers. Now I need to get the CRS, feature count, and bounding box for each layer. Let me use geopandas to read each layer.
0:29
Bash cd /work && python3 << 'EOF'
cd /work && python3 << 'EOF'
import geopandas as gpd
import json

gpkg = 'vienna_planning.gpkg'
layers = ['cafes', 'cycleway_segments', 'districts', 'parks', 'schools', 'supermarkets', 'waterbodies']

records = []
for layer in layers:
    gdf = gpd.read_file(gpkg, layer=layer)
    crs = gdf.crs.to_epsg()
    if crs is None:
        crs = gdf.crs.srs.split(':')[-1]
        crs_str = f"EPSG:{crs}"
    else:
        crs_str = f"EPSG:{crs}"
    geom_type = gdf.geometry.geom_type.iloc[0]
    if 'Multi' not in geom_type:
        # Some single types might actually be mixed; use iloc[0] as native
        pass
    feat_count = len(gdf)
    bbox = list(gdf.total_bounds)  # [xmin, ymin, xmax, ymax]
    records.append({
        "layer_name": layer,
        "crs": crs_str,
        "geometry_type": geom_type,
        "feature_count": feat_count,
        "bbox": bbox
    })

with open('/work/manifest.json', 'w') as f:
    json.dump(records, f, indent=2)
print(json.dumps(records, indent=2))
EOF
[
  {
    "layer_name": "cafes",
    "crs": "EPSG:31287",
    "geometry_type": "Point",
    "feature_count": 392,
    "bbox": [
      623796.529863561,
      481107.2540129812,
      626399.5618121764,
      484498.9209005649
    ]
  },
  {
    "layer_name": "cycleway_segments",
    "crs": "EPSG:31287",
    "geometry_type": "LineString",
    "feature_count": 271,
    "bbox": [
      623787.4932131292,
      481134.9325878215,
      626619.1631922598,
      485245.6624853243
    ]
  },
  {
    "layer_name": "districts",
    "crs": "EPSG:31287",
    "geometry_type": "Polygon",
    "feature_count": 22,
    "bbox": [
      623867.3888224852,
      481236.5836125494,
      626371.3079994549,
      484403.7315526943
    ]
  },
  {
    "layer_name": "parks",
    "crs": "EPSG:31287",
    "geometry_type": "MultiPolygon",
    "feature_count": 119,
    "bbox": [
      623851.990195953,
      481200.6674012489,
      626620.9438865517,
      485539.3479671855
    ]
  },
  {
    "layer_name": "schools",
    "crs": "EPSG:31287",
    "geometry_type": "Point",
    "feature_count": 40,
    "bbox": [
      624000.002417057,
      481214.73871311604,
      626259.5421406503,
      484178.87865010765
    ]
  },
  {
    "layer_name": "supermarkets",
    "crs": "EPSG:31287",
    "geometry_type": "Point",
    "feature_count": 87,
    "bbox": [
      623794.0549950565,
      481148.38703723426,
      626392.6164786755,
      484489.91954147833
    ]
  },
  {
    "layer_name": "waterbodies",
    "crs": "EPSG:31287",
    "geometry_type": "Polygon",
    "feature_count": 33,
    "bbox": [
      624288.8521056126,
      481236.66320640914,
      626747.8611584986,
      484132.0212685799
    ]
  }
]
0:34
The script ran successfully and produced the manifest. Let me verify the output file.
0:34
Read /work/manifest.json
     1	[
     2	  {
     3	    "layer_name": "cafes",
     4	    "crs": "EPSG:31287",
     5	    "geometry_type": "Point",
     6	    "feature_count": 392,
     7	    "bbox": [
     8	      623796.529863561,
     9	      481107.2540129812,
    10	      626399.5618121764,
    11	      484498.9209005649
    12	    ]
    13	  },
    14	  {
    15	    "layer_name": "cycleway_segments",
    16	    "crs": "EPSG:31287",
    17	    "geometry_type": "LineString",
    18	    "feature_count": 271,
    19	    "bbox": [
    20	      623787.4932131292,
    21	      481134.9325878215,
    22	      626619.1631922598,
    23	      485245.6624853243
    24	    ]
    25	  },
    26	  {
    27	    "layer_name": "districts",
    28	    "crs": "EPSG:31287",
    29	    "geometry_type": "Polygon",
    30	    "feature_count": 22,
    31	    "bbox": [
    32	      623867.3888224852,
    33	      481236.5836125494,
    34	      626371.3079994549,
    35	      484403.7315526943
    36	    ]
    37	  },
    38	  {
    39	    "layer_name": "parks",
    40	    "crs": "EPSG:31287",
    41	    "geometry_type": "MultiPolygon",
    42	    "feature_count": 119,
    43	    "bbox": [
    44	      623851.990195953,
    45	      481200.6674012489,
    46	      626620.9438865517,
    47	      485539.3479671855
    48	    ]
    49	  },
    50	  {
    51	    "layer_name": "schools",
    52	    "crs": "EPSG:31287",
    53	    "geometry_type": "Point",
    54	    "feature_count": 40,
    55	    "bbox": [
    56	      624000.002417057,
    57	      481214.73871311604,
    58	      626259.5421406503,
    59	      484178.87865010765
    60	    ]
    61	  },
    62	  {
    63	    "layer_name": "supermarkets",
    64	    "crs": "EPSG:31287",
    65	    "geometry_type": "Point",
    66	    "feature_count": 87,
    67	    "bbox": [
    68	      623794.0549950565,
    69	      481148.38703723426,
    70	      626392.6164786755,
    71	      484489.91954147833
    72	    ]
    73	  },
    74	  {
    75	    "layer_name": "waterbodies",
    76	    "crs": "EPSG:31287",
    77	    "geometry_type": "Polygon",
    78	    "feature_count": 33,
    79	    "bbox": [
    80	      624288.8521056126,
    81	      481236.66320640914,
    82	      626747.8611584986,
    83	      484132.0212685799
    84	    ]
    85	  }
    86	]
0:39
The manifest.json is complete and well-formed. Let me verify the requirements:

1. ✅ JSON list of objects — yes
2. ✅ `layer_name` as a string — yes
3. ✅ `crs` as a string in `EPSG:NNNN` form — yes (EPSG:31287)
4. ✅ `geometry_type` matching native type — Point, LineString, Polygon, MultiPolygon
5. ✅ `feature_count` as integer — yes
6. ✅ `bbox` as list `[xmin, ymin, xmax, ymax]` in layer's native CRS — yes

All good!
0:39