stele1 Spec

Datatypes

Metadata

Name (metadata.name)

the name of the catalog

Examples
"New River Gorge Sport"
a catalog that covers only sport climbing at The New
"New River Gorgeous"
a lighthearted name; obviously the new, but less generic

Description (metadata.description)

a sentence or two about what the catalog covers.

Examples
"all the crashpad-protectable boulders in Joshua Tree"
for a generic Joshua Tree Bouldering guide
"The highest quality, most accessible routes in Yosemite"
for a generic Select Yosemite Climbs book

Contributors (metadata.contributors)

people who have contributed to the catalog

Examples
[
  "Jane Doe",
  "John Doe"
]
simple, married couple authors
[
  "Name <email@example.com>"
]
if email is desirable, use RFC 5322
[
  "Bob (maintainer 2010-present)",
  "Sally (maintainer 1999-2010)",
  "Joe",
  "Glenda"
]
mention all contributors, maintainers at the top with notes.

UUID (metadata.uuid)

A universally unique identifier. Under nearly all circumstances, this should be autogenerated at creation and never changed.

Examples
"c5ae7ddd-243d-47bf-8a6e-aa456d2f54c2"
"4c7efeb1-aa50-4ddc-ae6d-84a908ae8a15"
See Also

License (metadata.license)

a SPDX identifier for the license of the catalog

Examples
"CC-BY-4.0"
Indicates the Creative Commons Attribution 4.0 International license. lets anyone share and adapt a work for any purpose, including commercially, as long as they give appropriate credit, link to the license, and indicate if changes were made.
See Also

Climb

Name (climb.name)

the name of the climb

Examples
"Mañana"
"Biographie"

Alternate Names (climb.alternate_names)

A list of alternate names for the climb.

When there is history, confusion, or disagreement in the community, alternate names keep climbs discoverable and reinforce a common idea moving forward.

This issue comes up most frequently when different guides use different names or, more rarely, more direct naming conflicts (e.g., Realization vs. Biographie, Rastaman SDS vs. Lucid Dreaming, Veritas Right Project becoming Hypnotized Minds).

Examples
[ "Realization" ]
a non-empty list of names for "Biographie"
[ "S.S.S.", "SSS", "Shipley's Shivering Shimmy" ]
a non-empty list of names for Triple S at Seneca
See Also

Project Status (climb.project_status)

This indicates whether this is a known climb awaiting an ascent. for areas where ethics support the idea of closed/reserved projects, this should include relevant info. it's a good idea to make the first word "open" or "closed". null is invalid. Presence of this attribute implies project status, and that status should be clarified

Examples
"open"
the climb is established as a project but anyone may attempt it
"closed for equipper John Smith until 2055"
recommended pattern for closed projects gives the community context to respect the reservation. It identifies who, why, and adds a limit (however distant).
"closed"
the climb hasn't been redpointed, but attempts from the community are discouraged

Rating (climb.rating)

a concise summary of what it takes to climb a route or problem. it makes little sense to have an empty object. use an object with at least one field or nothing.

Examples
{"difficulty": "5.14c", "style": "sport"}
Just Do It in Smith Rocks, OR
{ "difficulty": "E11" }
Rhapsody on Dumbarton Rock in Scotland
{
  "difficulty": "5.7",
  "protection": "R",
  "style": "trad"
}
Snake Dike on Half Dome in Yosemite
{ "style": "boulder" }
a boulder-problem project with no established difficulty rating or relevant safety rating
{
  "difficulty": "V11",
  "protection": "X",
  "style": "boulder"
}
Ambrosia on Bishop's Grandpa Peabody boulder
Context

these are encapsulated into a single unit because they can't be cleanly separated. protection always depends on the style of climbing, and difficulty grading systems like the aid scales and the british adjectival grade also take protection into account. Furthermore, when a certain climb is done in a different discipline, (aiding vs freeing the nose) (top roping or bouldering too big to flail) all three of these aspects tend to change together.

See Also

Location (climb.location)

The GPS location for the start of the climb. In addition to the longitude and latitude (in decimal degrees), an accuracy measure (in meters) can specify a margin of error for the coordinates

Examples
{
  "latitude": 37.728367,
  "longitude": -119.637183,
  "meter_radius": 5
}
The Nose in Yosemite
See Also

Length (climb.length)

Length answers a single question about a climb: how far does a climber travel from start to finish? Length can be imagined as if a climber dragged a tape measure along the wall from start to finish. This is almost always an approximation, but if you've measured a climb, you can express an exact value by making the lower_estimate and upper_estimate identical. Depending on conventions (in the case of a shared catalog) or publishing intent, you can decide how these numbers are collapsed if you're printing a single value. you probably don't want to pick the lower_estimate, but you might want some sort of average, or to safely use the upper_estimate This is not the height of a climb; a 7 meter traverse that stays a few feet off the ground has a length of 7 meters.

Examples
{ "lower_estimate": 20, "upper_estimate": 25, "unit": "meters" }
a rough guess at a climb
{ "lower_estimate": 30, "upper_estimate": 30, "unit": "feet" }
an accurate measurement of a short route
See Also
rationale

A Climb's length gets a lower_estimate and upper_estimate, and a unit. This isn't the only choice, but it's better than the alternatives. Climbers rarely (if ever) measure each climb, so the format models the uncertainty that usually exists.

Units are included because a catalog shouldn't be stuck with the same units for boulders and routes.

lower_estimate and upper_estimate match how most climbers think. We say "20 or 30 feet" instead of "25±5 feet". (we might say "around 20 feet", but that can't be clearly modeled) It's natural to think "I know this is over 15'", or "definitely under 100'" and modeling endpoints aligns with this relative-thinking that we're prone to. It also happens to simplify code: consumers don't branch on an (imaginary) exactly key before checking the upper_estimate. Checking a catalog for climbs under 100 feet requires a single check of whether upper_estimate is under 100'.

It could have been specified as flexible plain text, but the field exists to capture data, and a string gives up the re-usability of data. A user wanting text should use a "length" or "height" as a climb.field.

Steepness (climb.steepness)

this represents the steepness of the wall as the climber progresses. this is a rough sketch of the climb and is treated stepwise. the "from" value can be anything from 0 to 1 and each segment must be in order

Examples
[
  { "from": 0.0,  "degrees_overhung": 45 },
  { "from": 0.1,  "degrees_overhung": 25 },
  { "from": 0.25, "degrees_overhung": 10 },
  { "from": 0.8,  "degrees_overhung": -5 }
]
starts steep, eases up to slightly overhung, and finishes as slab
[
  { "from": 0,    "degrees_overhung": 0 },
  { "from": 0.75, "degrees_overhung": 90 },
  { "from": 0.8,  "degrees_overhung": 0 }
]
perfectly vertical to a perfect roof and back to vertical
[
  {
    "from": 0,
    "degrees_overhung": 5
  }
]
slightly overhung the whole way

Terrain (climb.terrain)

this represents the type of rock climbing as a climber progresses the "from" value increases from 0 (the start of the climb) towards 1 (the end of the climb) and each segment must be in order, strictly increasing Always start at 0, assume that the last segment continues to 1.

Examples
[
  {
    "from": 0,
    "description": "crack, 3in"
  }
]
a continuous 3" crack from start to finish
[
  {
    "from": 0.0,
    "description": "pockets"
  },
  {
    "from": 0.25,
    "description": "jugs"
  },
  {
    "from": 0.75,
    "description": "crimps"
  }
]
an imaginary climb that you might find at The Red
[
  {
    "from": 0.0,
    "description": "corner, right-facing, 5cm"
  },
  {
    "from": 0.5,
    "description": "crack, 2cm"
  },
  {
    "from": 0.6,
    "description": "seam"
  },
  {
    "from": 0.8,
    "description": "face"
  }
]
a disappearing corner

Tags (climb.tags)

a tag is a single word or phrase to highlight something unique about the climb. that isn't covered by other features. In many bouldering areas, it might be worth having a highball tag. In Bishop though, it might be better to have fluttering-heart field. useful labels help climbers identify climbs with unique aspects.

Examples
[ "manufactured" ]
a climb with chipping or glued-on holds
[ "area classic", "crimpy" ]
for Slash And Burn at the New River Gorge
[ "classic", "exposed" ]
for Zoo View at Moore's Wall in North Carolina
[ "top-out crux", "bad fall", "slick" ]
these imaginary tags describe an unsettling problem

Notes (climb.notes)

plain text descriptions about various aspects of the climb. notes are divided into topics for easy organization and simple inclusion and exclusion in different publishing formats.

Examples
[
  {
    "topic": "elevator pitch",
    "content": "unless you love unpleasant choss, don't climb it"
  }
]
must be a terrible climb
[
  {
    "topic": "Elevator Pitch",
    "content": "non-stop quality climbing with a stellar view and a rich history makes this one of Yosemite's greatest routes"
  },
  {
    "topic": "FFA Story",
    "content": "It was May 1975. John Bachar, John Long, and Ron Kauk were ..."
  }
]
for Astroman
[
  {
    "topic": "Elevator Pitch",
    "content": "a beautiful roof crack"
  },
  {
    "topic": "Recognizing It",
    "content": "this boulder is hard to find and looks tiny from the front ... "
  }
]
an imaginary boulder

Fields (climb.fields)

a set of fields and their values. fields are useful to describe the climb in a slightly-standard way.

Examples
{
  "sun": "all day",
  "rain": "ok in light rain",
  "descent": "walk off"
}
an imaginary climb

History (climb.history)

Most commonly this will be an entry with the first free ascent. Depending on the area or history, the first ascent on aid, top-rope, lead, or any other significant first could be worth mentioning. Noting "FA" or "FFA" is almost always redundant and sometimes incorrect when earlier ascents are discovered.

Examples
[ { "date": "1991-09-14",
    "event": "FA",
    "party": "Wolfgang Güllich" } ]
Action Directe, Frankenjura
[
  {
    "date": "1989",
    "event": "Started Equipping",
    "party": "Porter Jarrard"
  },
  {
    "date": "1997",
    "event": "Lead",
    "party": "Brian McCray"
  },
  {
    "date": "2008",
    "event": "Lead, onsight",
    "party": "Chris Sharma"
  },
  {
    "date": "2010",
    "event": "Lead",
    "party": "Porter Jarrard"
  },
  {
    "date": "2010",
    "event": "Trad",
    "party": "Brent Perkins"
  }
]
Proper Soul, at the NRG. Note the community's progression on style, a visiting pro, and especially Jarrard's return 20 years after equipping to get an ascent. It builds a history more than giving credit or ownership.
[
  {
    "date": "1967",
    "event": "Aid",
    "party": "John Stannard"
  },
  {
    "date": "1970",
    "event": "Free",
    "party": "John Stannard"
  }
]
Foops, The Gunks
[
  {
    "date": "1989",
    "event": "equipped",
    "party": "Jean-Christophe Lafaille"
  },
  {
    "date": "199X",
    "event": "middle anchor added",
    "party": "Arnaud Petit"
  },
  {
    "date": "1996",
    "event": "climbed to middle anchor",
    "party": "Arnaud Petit"
  },
  {
    "date": "2001",
    "event": "FA",
    "party": "Chris Sharma"
  },
  {
    "date": "2010",
    "event": "lower boulder problem breaks"
  }
]
Biographie, Ceuse
[
  {
    "date": "1957",
    "event": "Aid, siege",
    "party": "Warren Harding, Mark Powell, Bill \"Dolt\" Feuerer"
  },
  {
    "date": "1960",
    "event": "Aid, continuous",
    "party": "Royal Robbins, Joe Fitschen, Chuck Pratt, and Tom Frost"
  },
  {
    "date": "1993",
    "event": "Free",
    "party": "Lynn Hill, Steve Sutton (belay)"
  },
  {
    "date": "2005",
    "event": "Free",
    "party": "Tommy Caldwell and Beth Rodden"
  },
  {
    "date": "2019-11",
    "event": "Free, ground up",
    "party": "Sébastien Berthe"
  }
]
The Nose, El Cap. Highlight style of ascent
[
  {
    "date": "1957",
    "event": "Aid",
    "party": "Warren Harding, Mark Powell, Bill \"Dolt\" Feuerer"
  },
  {
    "date": "1993",
    "event": "Free",
    "party": "Lynn Hill"
  }
]
The Nose, El Cap. Condensed
See Also

Resources (climb.resources)

Offers an opportunity for developers to record info about where to find further info.

Examples
[{"title": "2012 Trip Report",
  "resource": "https://southernsierraclimber.blogspot.com/2012/12/blog-post.html",
  "description": "From Southern Sierra Climber, this offers the only well-documented ascent of this obscure route"}]
Potential links for the East Face Route on Moro Rock in Sequoia National Park
[
  {
    "title": "FA Video by Ben May",
    "resource": "https://www.youtube.com/watch?v=_VtpZ9GtNP4"
  },
  {
    "title": "Third Ascent Video by Matt",
    "resource": "https://www.youtube.com/watch?v=QnYS1x9t16Y",
    "description": "shows alternative, much more dynamic, beta"
  }
]
a boulder problem in San Diego
  • climb[].resource can hold a URI, not only a URL.
  • Prefer https: when the work is online.
  • For a book, urn:isbn:9781938393235 is technically valid (though a bit opaque).
  • For a work with no identifier (like a DVD, zine, or an out-of-print guide) use a WorldCat or Wikidata URI, to tell a reader where a copy can be found.

A chapter, a page range, or a timecode is a locator, not a separate resource. One entry per work. Put the locator in title, and why a reader should go there in description.

If your catalog is intended as a more of an archive, consider using a Wayback Machine snapshot; it preserves the content, capture date, and the original URL.

UUID (climb.uuid)

A universally unique identifier. Under nearly all circumstances, this should be autogenerated and never changed. It can be changed to align with another catalog's UUID for the same climb. Doing so breaks references from photos and any external tools keyed on the old value. Update those at the same time.

Examples
"0cf19a54-4af9-44db-9de3-dfecb700c3ce"
"6833840f-d801-43c6-a2d7-7da71a6ed1c8"
See Also

Area

Name (area.name)

the primary name of the area.

Examples
"Yosemite"
...
"Éléphant"
a Fontainebleau area

Alternate Names (area.alternate_names)

A list of other names that the area can go by. This can be important to reduce confusion and/or to respect historical names.

Examples
[
  "Underworld Boulder"
]
for the Spragueasorus Boulder in Rumney
[
  "Manure Pile Buttress"
]
for what is now Ranger Rock in Yosemite

Location (area.location)

GPS coordinates for the boundary of the area.

When using a perimeter, the first and last points of a polygon must be identical to form a ring (like GeoJSON and WKT). It's recommended that the points should wind counterclockwise and the first point starts where the trail comes in. This can help make downstream judgements about rendering. The perimeter is a single ring. Unlike many geospatial polygon representations, an area doesn't contain holes and is not a multi-polygon.

Examples
{
  "type": "approximation",
  "circle": {
    "longitude": -79.81768,
    "latitude": 39.63972,
    "meter_radius": 50
  }
}
The Mushroom boulder (Cooper's Rock) is a good candidate for approximation because the dense tree cover makes it hard to draw an exact perimeter. This circle can guide the construction of a hierarchy, but might require manual review.
{
  "type": "perimeter",
  "polygon": [
    { "longitude": -105.37592, "latitude": 41.15422 },
    { "longitude": -105.37543, "latitude": 41.15382 },
    { "longitude": -105.37363, "latitude": 41.15396 },
    { "longitude": -105.37249, "latitude": 41.15498 },
    { "longitude": -105.37060, "latitude": 41.15579 },
    { "longitude": -105.36977, "latitude": 41.15683 },
    { "longitude": -105.37095, "latitude": 41.15749 },
    { "longitude": -105.37333, "latitude": 41.15657 },
    { "longitude": -105.37507, "latitude": 41.15552 },
    { "longitude": -105.37592, "latitude": 41.15422 }
  ]
}
The Nautilus is a perfect use-case for a perimeter. it's oblong and easy to outline with satellite imagery. Climbs inside the polygon are undoubtedly on the Nautilus

Tags (area.tags)

a tag is a single word or phrase to highlight something unique about the area. that isn't covered by other features.

Useful labels help climbers identify areas that stand out in particular ways.

Examples
[ "beginner friendly", "easy access" ]
for Sandstonia at the New River Gorge
[ "moderate access", "good for groups" ]
this imaginary area is less frequently traveled and has many routes close to one another
[ "frequently crowded", "beginner friendly" ]
for The Black Corridor at Second Pullout in Red Rock

Notes (area.notes)

plain text descriptions about various aspects of the area. notes are divided into topics for easy organization and simple inclusion and exclusion in different publishing formats.

Examples
[
  {
    "topic": "elevator pitch",
    "content": "unless you love choss and poison ivy and getting lost don't bother hiking out"
  }
]
must be a terrible area
[
  {
    "topic": "Elevator Pitch",
    "content": "an excellent winter climbing destination in North Carolina. The granite/gneiss here provides any style of climbing you could ask for"
  },
  {
    "topic": "History",
    "content": "The first routes were established in the early 1970s ..."
  }
]
for Rumbling Bald in North Carolina
[
  {
    "topic": "Elevator Pitch",
    "content": "Solid, sticky rock with all climbing over 8,000'"
  },
  {
    "topic": "History",
    "content": "Developed almost entirely by Mike and Tommy Caldwell [...]"
  },
  {
    "topic": "Getting There",
    "content": "expect many turns: from the town of Drake, [...]"
  }
]
The Monastery in Colorado

Fields (area.fields)

a set of fields and their values. these names describe the area.

Examples
{
  "orientation": "north east",
  "water": "none nearby",
  "good season": "summer"
}
simple info for a backcountry area
{
  "dog friendly": "yes, on a leash",
  "time from car": "5 minutes",
  "shade": "afternoon"
}
a nice after-work crag

UUID (area.uuid)

A universally unique identifier. Under nearly all circumstances, this should be autogenerated and never changed.

Examples
"93ef6423-2bf4-4b5b-929c-91f89e03d943"
"580f443e-9593-4dd0-8bad-857eec248978"
See Also

Photo

Tags (photo.tags)

a tag is a single word or phrase to highlight something unique about the photo that isn't covered by other attributes. tags are well-suited to a photo's purpose, condition, or capture context. for properties that apply to most photos in a catalog and/or take a range of values, prefer fields. useful labels help authors and consumers find photos to fit a specific need.

Examples
[ "overview", "drone" ]
a wide shot of an area, captured from the air (important because it's a view a climber can never see)
[ "historical" ]
a photo kept for record rather than current reference, e.g., a wall before a rockfall
[ "needs-reshoot", "low-quality" ]
a placeholder photo flagged for replacement
[ "topo" ]
this probably shouldn't be used because in most catalogs it's the default assumption for stele1 photos

Fields (photo.fields)

a set of fields and their values. fields are useful to describe the photo in a somewhat-standard way.

Examples
{
  "captured from": "air (via drone)",
  "credit": "Jane Doe"
}
credit to the photographer and info about where the photo was taken from
{
  "caption": "John Doe pulling through the crux",
  "credit": "Jane Doe"
}
a caption can be a good field when appropriate. most photos in a catalog will be documentation-quality and a caption would be clutter.

Climb Layers (photo.climb_layers)

a collection of lines it's suggested that the first point be the start of the climb

Examples
[
  {
    "climb_uuid": "0d3fdc6b-a4c3-4036-afe6-ed524a1b44f7",
    "path": [ { "top_offset": 0.9, "left_offset": 0.1 },
              { "top_offset": 0.3, "left_offset": 0.1 } ]
  },
  {
    "climb_uuid": "b3422197-b4c4-4b07-bcdd-74a77d787941",
    "path": [ { "top_offset": 0.9, "left_offset": 0.4 },
              { "top_offset": 0.2, "left_offset": 0.4 } ]
  },
  {
    "climb_uuid": "a4f519cb-4aeb-4814-aa52-4cdcc292402e",
    "path": [ { "top_offset": 0.9, "left_offset": 0.7 },
              { "top_offset": 0.1, "left_offset": 0.7 } ]
  }
]

Area Layers (photo.area_layers)

a collection of polygons that identify areas on a photo It's suggested that the first point be on or near the access trail, and that the points wind counterclockwise. first and last points are identical, enforcing a ring

Examples
[
  {
    "area_uuid": "c3056703-ee36-4312-8913-4ce8b444476f",
    "polygon": [
      {
        "top_offset": 0.9,
        "left_offset": 0.1
      },
      {
        "top_offset": 0.3,
        "left_offset": 0.5
      },
      {
        "top_offset": 0.9,
        "left_offset": 0.9
      },
      {
        "top_offset": 0.9,
        "left_offset": 0.1
      }
    ]
  }
]
[no description]

Capture Location (photo.capture_location)

The GPS coordinates for where the photo was taken from. It's useful to initialize this with the coordinates from a photo's EXIF data when available.

Examples
{
  "longitude": -121.142848,
  "latitude": 44.365012,
  "meter_radius": 1
}
A photo showing much of Smith Rock would be taken from across the river
See Also

Capture Time (photo.capture_time)

date, time or both

Examples
"2000-02-01"
a photo taken on the first day of February 2000
Context

This can be useful for giving a hint about shade and vegetation at certain times of the day or year. Usually this can be pulled straight from the photo's metadata.

See Also

UUID (photo.uuid)

A universally unique identifier. Under nearly all circumstances, this should be autogenerated and never changed.

Examples
"b644e46c-e690-4af0-ae25-80230ea23de1"
[no description]
"66a0bb80-1364-478c-8800-487d6d2efb86"
[no description]
See Also

Parking

Name (parking.name)

is there an official name for this parking area? if not then a concise, descriptive name works fine.

Examples
"Camp 4 Day Use Parking"
a section of the Camp 4 lot that doesn't allow overnight parking
See Also

Location (parking.location)

a point for the entrance to the parking area.

Examples
{
  "longitude": -74.200394,
  "latitude": 41.735855
}
the main parking area for the most popular climbing at The Gunks

Description (parking.description)

info about the parking area: - does it close at dusk? - are break-ins a concern? - do you need to pay? - is it hard to find? - is there a towing policy?

Examples
"this is a school bus turnaround; do not use on the weekdays"
"a gravel strip on the side of the road. rarely maintained, frequently covered in trash"

Capacity (parking.capacity)

the number of cars that the parking can hold.

Examples
200
a large parking area, like what you'd get for some of the bouldering areas in RMNP
5
a modest parking area
1
space to fit a single car, perhaps a small pullout at a local crag.

UUID (parking.uuid)

A universally unique identifier. Under nearly all circumstances, this should be autogenerated and never changed.

Examples
"23ff1c9b-43a0-41ce-88f3-385d8736b176"
[no description]
"24a899f8-a1e1-4d6f-a066-c1a3424eb13b"
[no description]
See Also

Trail

Name (trail.name)

is there an official name for this trail? if not then a concise, descriptive placeholder works fine.

Examples
"Billy Goat Trail"
for the rocks around Great Falls (near Washington D.C.)

Description (trail.description)

The description should be a concise overview.

  • is it a trail, access road, paved street, or something else?
  • what quality is the trail in?
  • is the trail quality unpredictable, e.g., does it wash out in heavy rain? does it get overgrown in the summer?
  • other noteworthy features
Examples
"don't even bother from May through August, the \"trail\" is just thick jungle"
an all too common condition for many areas North Carolina's Linville Gorge

Path (trail.path)

This is a list of coordinates, a GPS path for the trail.

Examples
[
  { "latitude": 44.36680, "longitude": -121.13623 },
  { "latitude": 44.36720, "longitude": -121.13688 },
  { "latitude": 44.36717, "longitude": -121.13726 },
  { "latitude": 44.36697, "longitude": -121.13783 },
  { "latitude": 44.36640, "longitude": -121.13804 },
  { "latitude": 44.36640, "longitude": -121.13825 },
  { "latitude": 44.36651, "longitude": -121.13823 },
  { "latitude": 44.36642, "longitude": -121.13855 },
  { "latitude": 44.36660, "longitude": -121.13849 },
  { "latitude": 44.36742, "longitude": -121.13888 },
  { "latitude": 44.36809, "longitude": -121.13928 }
]
an access trail at Smith Rock
See Also

UUID (trail.uuid)

A universally unique identifier. Under nearly all circumstances, this should be autogenerated and never changed.

Examples
"90c0ab19-b6ff-4645-b00c-0364042d77fe"
[no description]
"0393e141-7a63-44b2-95dc-4c5aa2410d93"
[no description]
See Also

File Layout

  • stele1.json
  • stele1.txt
  • climb
    • {climb.uuid}.json
  • area
    • {area.uuid}.json
  • trail
    • {trail.uuid}.json
  • parking
    • {parking.uuid}.json
  • photo
    • {photo.uuid}.json
    • {photo.uuid}_image.{extension}
  • extension
    • {extension_name}

stele1.json

machine-readable metadata for the specific stele1 catalog. Structured data describing the catalog as a whole. (follows the Metadata format)

stele1.txt

a human-oriented introduction to stele1 for someone who comes across the catalog without context. your tools should populate this with a file automatically. Add a readme.md next to this file if you want a human-friendly intro to the specific stele1 catalog.

climb

contains a file for each climb

climb/{climb.uuid}.json

a spec-conforming json object for a climb

area

contains a file for each area

area/{area.uuid}.json

a spec-conforming json object for an area

trail

contains a file for each trail

trail/{trail.uuid}.json

a spec-conforming json object for a trail

parking

contains a file for each parking

parking/{parking.uuid}.json

a spec-conforming json object for a parking

photo

contains a file for each photo

photo/{photo.uuid}.json

a spec-conforming json object for a photo

photo/{photo.uuid}_image.{extension}

the raw photo data. filetype (e.g., jpeg, heif, png, gif) and extension (e.g., .jpg, .jpeg) support are left to the implementation

extension

contains a directory for each extension used in the catalog

extension/{extension_name}

A self-contained directory for everything related to an extension. Its contents are at the discretion of the extension.

UUIDs

Use lowercase when UUIDs appear in filenames.

  • Use lowercase: it's valid per RFC 9562 and compatible with portable catalog filenames.
  • Use v4.
  • intra-catalog alignment: rename never or very cautiously. it's unlikely that stele1 will ever ship tools to manage this.
  • inter-catalog alignment: this is not what stele1 uuids are intended for. sharing uuids between two catalogs is an agreement between catalog owners

stele1 mirrors uuids in filenames as {uuid}.json and the file's .uuid field for durability. uuids are the id scheme for stele1 and mirroring means that mv climb/{uuid_a}.json climb/{uuid_b}.json is a loud, obvious break.

The Packed Catalog (a *.stele1 file)

A .stele1 file is a ZIP archive whose entries are the files of a stele1 catalog. Paths are relative to the catalog root.

This is a distribution format, not intended as a working copy.

ZIP was chosen because it's been on every system for a long time. The container is ordinary ZIP, with a few details:

  • Entries sit at the archive root. stele1.json is an entry; yosemite.stele1-folder/stele1.json is not. Extract into a new, empty directory and you have the catalog.
  • The archive starts with the ZIP local file header signature (PK\x03\x04) at offset 0. Self-extracting archives puts an executable in front, so a self-extracting archive is not a stele1 archive. These are recognizable and you can check on disk with $ od -c -N4 squamish.stele1.
  • Don't duplicate entry names or make prefix collisions. Readers should fail loudly (optionally suggest falling back to an unzip tool).
  • An entry's bytes are the file's bytes. Nothing is transcoded or line-ending converted, packing or unpacking.
  • Readers and writers handle ZIP64, so an extension asset can be larger than 4 GiB.

A packed catalog transferred over a network is application/zip. The .stele1 name is what identifies the format inside the container.

Two archives of the same catalog may differ in compression, timestamps, and entry order. They are the same catalog; the entry paths and the extracted bytes are the content.

You're free to archive catalogs with zip, rar, tar using the archive tool's extension. The .stele1 extension is reserved for ZIP files that match the rules above.

Open Vocabularies

Attributes like tags, fields, note.topic, and rating.difficulty, don't have a spec-enforced taxonomy. These fields are intentionally open.

Different climbing destinations have different needs, and local authors are the best ones to pick how to describe their area.

The editor has an extension to help keep words consistent. You can review the least used terms that appear in a catalog to catch drift.

Modeling Geometry

Geometry is modeled for each use case; this differs from what you'd get from GeoJSON. Areas might not be possible to draw on a map cleanly, so two representations apply. Climb location has a meter radius because it's not possible to always get perfect gps coordinates and the climber should know how close the gap between a specific point and what an author intended. Parking is a specific point (no meter_radius) because it marks the last useful point for vehicle nav software. Even 10m or 100m accuracy would be fine in most cases you're setting your nav software to route to the nearest point. Trail .path does what it needs to, point a to b.

This diverges from other standards because these are significantly better-fit for the climbing community.

Area-Climb Relationships

stele1 stores no area-climb relationships, by design. A climb's location is a fact, Some areas, like a specific formation (boulder or wall) are also facts. Many areas are judgment calls, boundaries for how to group climbs. The judgment can change as developers get to know the place, as trails are built, or as new sectors are developed. Recording membership directly would make every rethink a chore and harden a catalog around its earliest, least-informed choices. Instead, the catalog records locations and lets the map inform membership: redraw an area, and its climbs follow.

stele1 is also a foundation for publishing and respects that groupings change depending on the publication target: Plucking climbs from a catalog for a small best-of guide demands a shallow hierarchy; marshalling everything for a comprehensive guidebook benefits from more intermediate areas.

There's also the technical hurdle that areas aren't necessarily exclusive. Suppose a canyon where the "lower canyon" is anything before the tunnel and the "upper canyon" is everything after. It's natural to also refer "middle canyon" for the rocks around the tunnel. The climbs just past the tunnel are both upper and middle canyon — depending on who's talking, or who's making the guidebook.

In practice, many areas (especially in the open terrain of the western US) work on geometry alone. In other regions (e.g., where tree cover obscures satellite imagery and makes the map a weaker tool, as across much of the east), a publication might benefit from an an explicit tree. The classic-area-organization extension holds it: geometry scaffolds a first draft, and the author massages it into finished shape: walls are ordered for the approach, splitting or collapsing groups to fit the guide. The tree comes from stable facts about location and the author's judgement. It's cheap to rebuild when the area or the publication changes.

In regular catalog maintenance, an explicit hierarchy has turned out to be mostly unnecessary: search and a map are easier than clicking through breadcrumbs. When publishing, editorial needs dictate the hierarchy's shape.

Hard-coding a canonical series of parents into the core entity wouldn't be a net positive. Where and when it is needed, it's well supported.

The Catalog Directory

A stele1 catalog is a directory containing a stele1.json and a stele1.txt file

the folder is yours, and you can put anything you want in it; but it is nonetheless intended for structured climbing data

the root should stay fairly clear; stele1 will never add a top level file or directory that starts with x-. so if you're adding catalog-specific content at the root, the safe choice is to prefix with x-.

If you want a catch-all place for files that don't provide data directly, but should move with the catalog they can go in extension/misc/

Root Files and Directories

stele1 is a container with defined contents.

In addition to the mandatory stele1.json and stele1.txt, a catalog often includes

  • readme.md - human-friendly intro to the project
  • license.txt - full text of the license
  • attribution.md - how to credit the project when reusing the data
  • disclaimer.txt

Portable Catalogs

If you're using stele1 to document your local area, this section has detail that you'll never need. And if you're extending stele1 for private use, this section is more of a recommendation than a rule. This section is critical if you're building a public stele1 extension or if you're maintaining a catalog by hand that you intend to share.

A catalog is a set of paths (for example, climb/{uuid}.json) and their contents. Catalog contents are regular files only. Directories are not records themselves; they are implied by file paths. Empty directories carry no meaning, as in Git. File formats are covered in Datatypes.

If you are the only person who will ever touch the catalog, you can ignore everything below. The low-level stele1 tools are tolerant on read and precise on write: your non-stele1 files will not break them, and they will not break your non-stele1 files. Treat the rest of this section as a recommendation for private use and a rule for anything shared.

Sharing means exposing the catalog to HTTP, Linux, macOS, Windows, Android, iOS, and whatever device someone drags the ZIP onto in five years.

For portability, we need paths to follow a few rules (divided into two groups):

Path Rules

  • / separates segments, and a path never begins with /.
    • An absolute path would write outside the extraction destination.
  • No path is a segment-wise prefix of another.
    • A name is a file or a folder, never both.
    • Impossible on a filesystem, trivial in a ZIP.
    • The only rule requiring the whole path set. It cannot be checked one file at a time.
    • Fails at pack time, distant from the mistake.

Segment Rules

  • A path segment uses only [a-z0-9._-].
    • This falls within the POSIX portable filename set.
    • It is also within RFC 3986 unreserved, so the path can be used in a URL path without percent-encoding.
    • It already rules out everything Windows rejects (< > : " | ? *, backslash, space, and control characters).
    • ASCII-only avoids Unicode normalization issues (macOS decomposes, Linux doesn't, and ZIP has a UTF-8 flag).
    • Lowercase makes case collisions impossible when sharing from a case-sensitive filesystem to a case-insensitive one.
  • A segment starts with [a-z0-9].
    • A leading - is excluded, so segments don't look like command-line flags.
    • A leading . is excluded, so . and .. are unrepresentable.
    • dotfiles are hidden files and don't belong in a format that's intended to be obvious. they are not valid catalog content.
  • A segment must not end with ..
    • Windows strips trailing dots, so the write path would differ from the read path.
  • A segment must not be empty.
    • One path, one spelling. No // and no trailing /.
  • Segments must not use Windows device names: con, prn, aux, nul, com1com9, lpt1lpt9 (with or without an extension).
    • Windows opens the device instead of the file. Still a live vulnerability class.

Recommendations

Path Rules and Segment Rules are permanent. They encode disagreements between operating systems that no single vendor can fix.

Recommendations are different: they track limits that erode. A future stele1 vintage may retire them, so treat them as guidance rather than law.

  • No path exceeds 200 characters.
    • Windows MAX_PATH is 260 and long-path support remains opt-in per application.
    • Leaves roughly 60 characters for the directory the catalog is extracted into.
  • No segment exceeds 255 characters.
    • The common per-name limit on Linux, macOS, and Windows.
    • A segment that fits the path recommendation fits this with room to spare.

Following these rules and recommendations means your catalog can land on almost any system with essentially zero concern.

Tradeoffs

stele1 catalogs can be shared from any system to any other system with essentially zero concern. This is the design goal, but the format still had to make a few concessions. Lowercase-only loses the familiar all-caps README.md. That is a tough bandage to peel off, but life is not that bad with a readme.md. The small set of segment characters means that you can't cp many files straight into the catalog. Copying files is nice, but mv isn't much of a downgrade.

Experimental Data

stele1 is built for stability and portability, but a private catalog only needs a solid foundation.

The first option is to fork stele1 or pin a version and develop on that base. This is always an option; but it cuts you off from stele1 fixes and improvements.

The supported path is to use x- prefixes for root files and x_ prefixes for root attributes on climbs, areas, trails, etc.

Extra structured data belongs in an x_ attribute, which no filesystem ever sees and every tool preserves. Before reaching for x-{name} consider using an extension/x-{name}.

These will be safe forever. stele1 will never add a root file matching x-* or an entity attribute matching x_*. Extensions matching extension/x-* are experimental.

These give you a safe place to do unstable stuff in a stable format.

Extension Names

It's recommended that extension names match [a-z][a-z0-9]*(-[a-z0-9]+)*, but stele1 tooling won't enforce this; it's an ergonomics issue.

Extensions live under extension/{name}/, which is the place for data outside the core spec. (after determinining that it's not a good fit for .tags or .fields when available)

A good name is somewhere between generic and elaborate. Make it slightly unique so it doesn't collide with someone else's work in the same area.

  • use your name: toms-3d-model
  • use a generic adjective: super-3d-model
  • use a descriptive qualifier: fast-3d-model or detailed-3d-model depending on what you optimize for
  • be specific: expiring-access-issues if your extension only models access issue that have expected end dates
  • use the area that motivated it: yoyo-3d-model (suppose the model was originally developed for Yosemite, but is sufficiently general to use elsewhere; do not reuse the exact area name in an extension name. that's confusing.)

Coordinates

Coordinates are expressed as decimal degrees. Assume WGS 84 (EPSG:4326) unless the catalog authors specifically state otherwise. This is the de facto standard for consumer mapping. GPS receivers, phones, CalTopo, and OpenStreetMap all use WGS 84.

Coordinates in stele1 use the named {latitude, longitude} instead of an ordered pair. Pair order is a widespread point of confusion. stele1's format is unconfusable.

Dates

Photo's capture_time or an event in a climb History's date are stored as a string.

For dates that software can sort and filter, use EDTF, an extension of ISO 8601. Level 0 is plain ISO 8601; Level 1 adds the coarse and uncertain forms that suit old photos and half-remembered events.

  • 2003-04-20 is April 20, 2003
  • 2025-03~ means around March 2025
  • 199X means in the 1990s
  • 1975-23 means Fall of 1975. (21 spring, 22 summer, 23 autumn, 24 winter)
  • 1988? means maybe 1988

Partial Records

the only thing you need anywhere is a uuid, so that you have a filename to store the entity. A climb with just a location is valid. An area with just a name is valid. The minimum valid area is not the minimum useful area

Versioning

stele1 is stable. the 1 is a compatibility commitment.

The spec is firm but not frozen. New attributes are possible but would have to clear a significant bar, and those changes will never break existing catalogs or tools. Specifically:

  • Top-level attributes defined in the spec will never change shape. climb.rating, area.location, photo.climb_layers, etc. are permanent as specified.
  • Top-level attributes can be added under a compelling case.
  • Top-level attributes will never be deprecated.
  • A reader that encounters an unknown top-level attribute preserves the value verbatim on write. Unknown nested keys (e.g. a custom attribute inside climb.notes[x]) are out of spec and fail loudly to ensure future compatibility; extensions and top-level attributes are the points for growth.
  • A reader from 2060 loads a catalog from today. Today's readers load 2060 catalogs without erroring; unrecognized attributes are preserved.
  • Extensions are not covered. Anything under extension/{name}/ is at the discretion of the extension's author.