dd-l1-vienna-gpkg-manifest
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:01
Let me start by exploring the GPKG file to understand its contents.
0:01
Bash
ls -la /work/vienna_planning* 2>/dev/null || find /work -name "vienna_planning*"...
-rw-r--r-- 1 agent agent 524288 Jun 9 10:23 /work/vienna_planning.gpkg
0:04
Let me explore the GPKG to find out its layers, CRS, geometry types, feature counts, and bounding boxes.
0:04
Bash
python3 -c "
python3 -c "
import geopandas as gpd
import json
# List all layers in the GPKG
layers = gpd.list_layers('/work/vienna_planning.gpkg')
print(layers)
"
name geometry_type 0 districts Polygon 1 parks MultiPolygon 2 waterbodies Polygon 3 schools Point 4 cafes Point 5 supermarkets Point 6 cycleway_segments LineString
0:16
Great, I have 7 layers. Now I need to get the CRS, feature count, and bounding box for each. Let me write a comprehensive script.
0:16
Bash
python3 -c "
python3 -c "
import geopandas as gpd
import json
gpkg_path = '/work/vienna_planning.gpkg'
layers_df = gpd.list_layers(gpkg_path)
print('Layers found:')
print(layers_df)
print()
records = []
for _, row in layers_df.iterrows():
name = row['name']
geom_type = row['geometry_type']
gdf = gpd.read_file(gpkg_path, layer=name)
feat_count = len(gdf)
crs = gdf.crs
if crs is None:
crs_str = 'Undefined'
else:
crs_str = crs.to_epsg()
if crs_str:
crs_str = f'EPSG:{crs_str}'
else:
crs_str = str(crs)
# Get bounding box in native CRS (the CRS of the GeoDataFrame)
# total_bounds returns [minx, miny, maxx, maxy]
bounds = gdf.total_bounds.tolist()
# Round to reasonable precision
bounds = [round(b, 6) for b in bounds]
record = {
'layer_name': name,
'crs': crs_str,
'geometry_type': geom_type,
'feature_count': feat_count,
'bbox': bounds
}
records.append(record)
print(f'{name}: {crs_str}, {geom_type}, {feat_count} features, bbox={bounds}')
output = '/work/manifest.json'
with open(output, 'w') as f:
json.dump(records, f, indent=2)
print(f'\nWritten to {output}')
"
Layers found:
name geometry_type
0 districts Polygon
1 parks MultiPolygon
2 waterbodies Polygon
3 schools Point
4 cafes Point
5 supermarkets Point
6 cycleway_segments LineString
districts: EPSG:31287, Polygon, 22 features, bbox=[623867.388822, 481236.583613, 626371.307999, 484403.731553]
parks: EPSG:31287, MultiPolygon, 119 features, bbox=[623851.990196, 481200.667401, 626620.943887, 485539.347967]
waterbodies: EPSG:31287, Polygon, 33 features, bbox=[624288.852106, 481236.663206, 626747.861158, 484132.021269]
schools: EPSG:31287, Point, 40 features, bbox=[624000.002417, 481214.738713, 626259.542141, 484178.87865]
cafes: EPSG:31287, Point, 392 features, bbox=[623796.529864, 481107.254013, 626399.561812, 484498.920901]
supermarkets: EPSG:31287, Point, 87 features, bbox=[623794.054995, 481148.387037, 626392.616479, 484489.919541]
cycleway_segments: EPSG:31287, LineString, 271 features, bbox=[623787.493213, 481134.932588, 626619.163192, 485245.662485]
Written to /work/manifest.json
0:18
Let me verify the output file looks correct.
0:18
Read
/work/manifest.json
1 [
2 {
3 "layer_name": "districts",
4 "crs": "EPSG:31287",
5 "geometry_type": "Polygon",
6 "feature_count": 22,
7 "bbox": [
8 623867.388822,
9 481236.583613,
10 626371.307999,
11 484403.731553
12 ]
13 },
14 {
15 "layer_name": "parks",
16 "crs": "EPSG:31287",
17 "geometry_type": "MultiPolygon",
18 "feature_count": 119,
19 "bbox": [
20 623851.990196,
21 481200.667401,
22 626620.943887,
23 485539.347967
24 ]
25 },
26 {
27 "layer_name": "waterbodies",
28 "crs": "EPSG:31287",
29 "geometry_type": "Polygon",
30 "feature_count": 33,
31 "bbox": [
32 624288.852106,
33 481236.663206,
34 626747.861158,
35 484132.021269
36 ]
37 },
38 {
39 "layer_name": "schools",
40 "crs": "EPSG:31287",
41 "geometry_type": "Point",
42 "feature_count": 40,
43 "bbox": [
44 624000.002417,
45 481214.738713,
46 626259.542141,
47 484178.87865
48 ]
49 },
50 {
51 "layer_name": "cafes",
52 "crs": "EPSG:31287",
53 "geometry_type": "Point",
54 "feature_count": 392,
55 "bbox": [
56 623796.529864,
57 481107.254013,
58 626399.561812,
59 484498.920901
60 ]
61 },
62 {
63 "layer_name": "supermarkets",
64 "crs": "EPSG:31287",
65 "geometry_type": "Point",
66 "feature_count": 87,
67 "bbox": [
68 623794.054995,
69 481148.387037,
70 626392.616479,
71 484489.919541
72 ]
73 },
74 {
75 "layer_name": "cycleway_segments",
76 "crs": "EPSG:31287",
77 "geometry_type": "LineString",
78 "feature_count": 271,
79 "bbox": [
80 623787.493213,
81 481134.932588,
82 626619.163192,
83 485245.662485
84 ]
85 }
86 ]
0:21
The manifest.json is complete and well-formed. Let me verify it's valid JSON and has all the required fields.
0:21