<?xml version="1.0" encoding="utf-8"?>
<!-- generator="Kukkaisvoima version 7" -->
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
>
<channel>
<title>vmx: ATProto</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi</link>
<description>Blog of Volker Mische</description>
<pubDate>Mon, 29 Jun 2026 15:26:34 +0200</pubDate>
<lastBuildDate>Mon, 29 Jun 2026 15:26:34 +0200</lastBuildDate>
<generator>http://23.fi/kukkaisvoima/</generator>
<language>en</language>
<item>
<title>JSON, floats and native types
</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi/json-floats-programming-languages.md%3A2026-06-29%3Aen%2CATProto</link>
<comments>https://vmx.cx/cgi-bin/blog/index.cgi/json-floats-programming-languages.md%3A2026-06-29%3Aen%2CATProto#comments</comments>
<pubDate>Mon, 29 Jun 2026 15:26:34 +0200</pubDate>
<dc:creator>Volker Mische</dc:creator>
<category>en</category>
<category>ATProto</category>
<guid isPermaLink="false">https://vmx.cx/cgi-bin/blog/index.cgi/json-floats-programming-languages.md%3A2026-06-29%3Aen%2CATProto/</guid>
<description><![CDATA[ <p>JSON only has a [single numeric type], though I state in an earlier blog post that <a href="https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto#numbers-in-json">most programming languages distinguish between integer and floats</a> when they encounter them. As <a href="https://vmx.cx/cgi-bin/blog/index.cgi/floats-on-atproto%3A2026-05-28%3Aen%2CATProto#json-without-context">this is a crucial piece</a> in order to get <a href="https://discourse.atprotocol.community/t/floats-on-atproto/877">native floats support on ATProto</a>, I <a href="https://github.com/vmx/json-floats-native-types">provide a survey across some languages and databases</a>. The goal is to find the edge cases and workarounds where things break, and hopefully also show that <a href="https://bsky.app/profile/vmx.cx/post/3moglriqo4k25">floats in practice are not as bad as they are in theory</a>.</p>
 [...]]]></description>
<content:encoded><![CDATA[
<p>JSON only has a [single numeric type], though I state in an earlier blog post that <a href="https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto#numbers-in-json">most programming languages distinguish between integer and floats</a> when they encounter them. As <a href="https://vmx.cx/cgi-bin/blog/index.cgi/floats-on-atproto%3A2026-05-28%3Aen%2CATProto#json-without-context">this is a crucial piece</a> in order to get <a href="https://discourse.atprotocol.community/t/floats-on-atproto/877">native floats support on ATProto</a>, I <a href="https://github.com/vmx/json-floats-native-types">provide a survey across some languages and databases</a>. The goal is to find the edge cases and workarounds where things break, and hopefully also show that <a href="https://bsky.app/profile/vmx.cx/post/3moglriqo4k25">floats in practice are not as bad as they are in theory</a>.</p>
<p>The central idea is that floats and integers have a different shape, and this can be used to distinguish them in JSON. It’s not mentioned in any standard, but it is a convention that many programming languages and databases have adopted. A JSON number is considered an integer when it contains only digits and an optional sign. If it contains a decimal point and/or an <code>e</code> for exponential notation, it’s a float.</p>
<h2 id="the-survey-repo">The survey repo</h2>
<p>The <a href="https://github.com/vmx/json-floats-native-types">json-floats-native-types repo</a> contains an overview in the README on how various languages behave, as well as an implementation for each of them. While writing the code was assisted by AI, this is not AI slop. It wasn’t a few prompts and then calling it a day, but many days of thorough code review and refinement of the implementations and test fixtures. For languages that don’t have built-in JSON processing, I’ve tried to find the most popular libraries.</p>
<p>If you find cases where I process the JSON in an unidiomatic way, please let me know or open a pull request. While I’m familiar with most of the languages covered, I’m not with all of them. The selection is a bit arbitrary: it’s the languages for which some ATProto SDK exists. Though the list ended up covering widely used languages as well as some more obscure ones, to ensure things will work in those cases too. I’ve also included a <a href="https://github.com/vmx/json-floats-native-types/blob/3d22b965cfbf754a8088beb075ec4c8228992039/README.md#databases">less elaborate database section</a>, as storing JSON in a database was <a href="https://discourse.atprotocol.community/t/floats-on-atproto/877/4">brought up in the floats on ATProto thread</a>.</p>
<h2 id="round-tripping-cbor">Round-tripping CBOR</h2>
<p>I want to show that for ATProto a CBOR -> JSON -> CBOR round-trip producing byte-identical CBOR is possible (using a CBOR subset called <a href="https://ipld.io/specs/codecs/dag-cbor/spec/">DAG-CBOR</a>/<a href="https://dasl.ing/drisl.html">DRISL</a>). That said, I would argue that the ATProto protocol should never rely on such behaviour. At the API level it makes sense to have a one-time conversion from JSON to CBOR, but later JSON representations should only be used for display or processing purposes, not for integrity verification. When you need that, you should supply the original CBOR. This is also how I understand the <a href="https://github.com/bluesky-social/atproto-website/blob/c663e4bfd8ffe7cefb747ecdc5c0bead6fe2113a/src/app/%5Blocale%5D/specs/data-model/en.mdx#json-representation">ATProto data model spec that states in the JSON representation section</a>: only DRISL-CBOR is used as a byte-reproducible representation.</p>
<h2 id="findings">Findings</h2>
<p>The repo contains all the details and you can run it yourself online or locally. Here’s my interpretation of the results.</p>
<h3 id="decoding">Decoding</h3>
<p>Decoding is the conversion from a JSON string into native types. For all languages there is a way to distinguish between integers and floats. When that distinction is made, it’s always based on the heuristic mentioned above: integers are numbers consisting of digits only with an optional sign; all other numbers are floats.</p>
<p>The results fall into these categories:</p>
<ul>
<li>Just works: C (jansson), C++ (nlohmann/json, RapidJSON), Dart (native), Elixir, Java (Jackson), PHP, PowerShell, Python, Ruby, Rust (serde_json), Swift, Zig</li>
<li>Needs introspection. The parsed number is somewhat wrapped, but the distinction can be made: C# (.NET), Go (json.Number), JavaScript, Kotlin (JVM)</li>
<li>No distinction possible: C (cJSON), Go</li>
</ul>
<p>The need for introspection may sound like a blocker, but for ATProto it isn’t. There, JSON is just an intermediate format used to produce CBOR. That transformation already requires some custom implementation, as CBOR can contain bytes and CIDs. Neither of which is natively supported by JSON, but both expressed through convention.</p>
<p>Hence I consider those results sufficient indication that for decoding purposes, no special syntax is needed to distinguish floats from integers at the JSON level. The established convention can be relied upon, meaning many implementations won’t need a custom code path at all.</p>
<h3 id="encoding">Encoding</h3>
<p>Encoding is the conversion from a native language type into a JSON string. This part focuses on floats only, with a single integer type included to verify it’s preserved. In all languages it’s possible to maintain the distinction at the JSON level.</p>
<p>Rounding correctly to the next representable number across the normal/subnormal boundary works well, all languages handle it the expected way by default. The smallest positive subnormal is also encoded correctly by all implementations. Although the formatting differs slightly, it would result in the same bytes across all implementations, as the <a href="https://github.com/vmx/json-floats-native-types/blob/3d22b965cfbf754a8088beb075ec4c8228992039/README.md#round-trip-decoding">Round-trip decoding section</a> shows.</p>
<p>Though there are differences, when encoding floats whose value fits without loss into an integer. Again we have three categories:</p>
<ul>
<li>Just works: C (jansson), C++ (nlohmann/json, RapidJSON), Dart (native), Elixir, Java (Jackson), Kotlin (JVM), PowerShell, Python, Ruby, Rust (serde_json)</li>
<li>Needs a setting or wrapper type: C# (.NET), Go, Go (json.Number), JavaScript, PHP, Swift, Zig</li>
<li>Not possible: C (cJSON)</li>
</ul>
<p>As with the decoding case, some languages require additional wrapper types. For most nothing special is needed, for others some custom handling is required. Since custom code for bytes and CIDs is already necessary anyway, this isn’t a significant burden.</p>
<h3 id="databases">Databases</h3>
<p>Databases are somewhat special, since you typically don’t produce data directly, but the language driving the database does. The tests here are therefore a bit different: we check whether the float/integer distinction survives insertion and querying. <a href="https://www.postgresql.org/">PostgreSQL</a> and <a href="https://sqlite.org/">SQLite</a> were chosen as they are already used in the ATProto reference implementation. <a href="https://couchdb.apache.org/">Apache CouchDB</a> was included as a JSON-native database I’m familiar with.</p>
<p>Things work as expected, with one exception: the <code>-0.0</code> case. With <a href="https://www.postgresql.org/docs/current/datatype-json.html">PostgreSQL’s <code>jsonb</code> type</a> and Apache CouchDB, negative zero loses its sign and becomes positive, making it impossible to produce byte-identical CBOR from it.</p>
<p>The solution is to forbid <code>-0.0</code> in the ATProto data model.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Most programming languages have a way to distinguish between floats and integers within JSON, and many have this built in. Sometimes tweaks or a different library are needed. Treating a JSON number that contains a fraction or exponent as a float is a well-established convention.</p>

]]></content:encoded>
<wfw:commentRss>https://vmx.cx/cgi-bin/blog/index.cgi/json-floats-programming-languages.md%3A2026-06-29%3Aen%2CATProto/feed/</wfw:commentRss>
</item>
<item>
<title>Floats on ATProto
</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi/floats-on-atproto%3A2026-05-28%3Aen%2CATProto</link>
<comments>https://vmx.cx/cgi-bin/blog/index.cgi/floats-on-atproto%3A2026-05-28%3Aen%2CATProto#comments</comments>
<pubDate>Thu, 28 May 2026 12:51:14 +0200</pubDate>
<dc:creator>Volker Mische</dc:creator>
<category>en</category>
<category>ATProto</category>
<guid isPermaLink="false">https://vmx.cx/cgi-bin/blog/index.cgi/floats-on-atproto%3A2026-05-28%3Aen%2CATProto/</guid>
<description><![CDATA[ <p><a href="https://atproto.com/">ATProto</a> currently does not support floats in their <a href="https://github.com/bluesky-social/atproto-website/blob/867580a166ffd5de97ec23be89deb2cb320da18c/src/app/%5Blocale%5D/specs/data-model/en.mdx#why-no-floats">data model</a>. I’ve created a <a href="https://github.com/vmx/floats-on-atproto">proof of concept for floats on ATProto</a> that works using the full stack, <a href="https://atproto.com/guides/glossary#pds-personal-data-server">PDS</a>, <a href="https://atproto.com/guides/glossary#relay">Relay</a> and <a href="https://atproto.com/guides/streaming-data#jetstream">Jetstream</a>.</p>
 [...]]]></description>
<content:encoded><![CDATA[
<p><a href="https://atproto.com/">ATProto</a> currently does not support floats in their <a href="https://github.com/bluesky-social/atproto-website/blob/867580a166ffd5de97ec23be89deb2cb320da18c/src/app/%5Blocale%5D/specs/data-model/en.mdx#why-no-floats">data model</a>. I’ve created a <a href="https://github.com/vmx/floats-on-atproto">proof of concept for floats on ATProto</a> that works using the full stack, <a href="https://atproto.com/guides/glossary#pds-personal-data-server">PDS</a>, <a href="https://atproto.com/guides/glossary#relay">Relay</a> and <a href="https://atproto.com/guides/streaming-data#jetstream">Jetstream</a>.</p>
<p>When I say floats, I mean the <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">IEEE 754 double-precision binary floating-point format</a>. This blog post explains some of the details and reasoning behind why things are done in a specific way. All this is really a proof of concept, floats could also be implemented differently. The following is based on my experience working on <a href="https://ipld.io/">IPLD</a> and JSON-based databases/indexes like <a href="https://couchdb.apache.org/">Apache CouchDB</a> and <a href="https://github.com/pipedown/noise">Noise</a>.</p>
<h2 id="why">Why</h2>
<p>ATProto never had floats for four years now. Why would you need them now?</p>
<p>ATProto is more than just micro-blogging. The science community is looking into ways to make good use of it, and floats are already used heavily in that space. Not supporting them at the protocol level hinders adoption and calls for workarounds at the application level that are future interoperability headaches in the making.</p>
<p>In the widely used <a href="https://geojson.org/">GeoJSON</a>, geometries are represented as nested arrays of floats. <a href="https://atgeo.org/faq/">ATGeo is currently using the “floats as strings” workaround</a>, but they would be more than happy to use proper floats. <a href="https://github.com/tmcw/atfloathack">Tom MacWright came up with a hack</a> to support floats on ATProto for his use case.</p>
<p><a href="https://emily.space/">Emily Hunt</a> mentions in her [Nebra] talk at the <a href="https://luma.com/ptrjn16w">CID Congress</a> that float support would be great for posting astronomy data to the AT Protocol, such as the <a href="https://github.com/nasa-gcn/gcn-schema">NASA General Coordinates Network events</a> in her <a href="https://lexicon.garden/nsid/eco.astrosky.transient.gcn"><code>eco.astrosky.transient.gcn</code> Lexicon</a>. As a workaround, she is storing the whole JSON as a string. For tools like <a href="https://bsky.app/profile/exhibit.so">Exhibit</a>, floating-point support is essential for <a href="https://iiif.io/">IIIF</a> annotations. These annotations use spatial coordinates to target specific regions of a canvas, which rarely map cleanly to whole-pixel boundaries.</p>
<p>I think the future is now and I believe I found a way to <a href="https://github.com/bluesky-social/atproto-website/blob/867580a166ffd5de97ec23be89deb2cb320da18c/src/app/%5Blocale%5D/specs/data-model/en.mdx#why-no-floats">“ensure reliable round-trip encoding of floats”</a>.</p>
<h2 id="how">How</h2>
<p>There are two distinct cases to consider: parsing JSON without any further context, and generating JSON from native types using Lexicons.</p>
<h3 id="json-without-context">JSON without context</h3>
<p>JSON has only a <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-6">single numeric type</a>, there’s no distinction between floats and integer. That’s a problem when you receive JSON without any further context. Programming languages with distinct types usually solve this by treating numbers with digits only (and an optional sign) as integers, and everything else as floats. For more details on how to do this in JavaScript, see my previous blog post about <a href="https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto">JSON, CBOR and numeric types</a>.</p>
<h3 id="js-lexicons-and-floats">JS, Lexicons and floats</h3>
<p>The second case is generating JSON from native types of a programming language. When creating new records on ATProto, we have the luxury of even more type information than the underlying language might support, thanks to <a href="https://atproto.com/guides/lexicon">Lexicon</a> schemas. The following sections focus on JS, as that’s what matters for the <a href="https://github.com/bluesky-social/atproto">reference PDS implementation</a>.</p>
<p>Using Lexicons, we can distinguish between integers and floats even within JS. When generating the JSON version of a record within the SDK, we can ensure that numbers are formatted according to their intended type. In our case that means a floating-point number like <code>42.0</code> is actually encoded as such, and not simply as <code>42</code>.</p>
<p>No changes are needed to the public API, everything happens at a lower level. <a href="https://github.com/bluesky-social/atproto/tree/47c71fcc157258c2f5dbe43ba2b27a5af7856341/packages/lex/lex#clientcreate"><code>client.create()</code></a> and <a href="https://github.com/bluesky-social/atproto/tree/47c71fcc157258c2f5dbe43ba2b27a5af7856341/packages/lex/lex#clientput"><code>client.put()</code></a> already take a Lexicon as a parameter. The new behaviour is that this information will now always be used when generating JSON. An escape hatch via <code>client.createRecord()</code> and <code>client.putRecord()</code> remains available for cases where you need to work around this.</p>
<h4 id="js-and-unexpected-fields">JS and unexpected fields</h4>
<p>The current Lexicon specification allows for <a href="https://github.com/bluesky-social/atproto-website/blob/867580a166ffd5de97ec23be89deb2cb320da18c/src/app/%5Blocale%5D/specs/lexicon/en.mdx#authority-and-control">unexpected fields</a>. Those are fields not specified in the Lexicon. They are currently ignored, but can be used for cases where user input adds arbitrary data.</p>
<p>The simplest approach with the least surprise is to check whether a numeric value can be represented as an integer without any loss, and if so, treat it as one. Otherwise consider it a float. This has one minor edge case: if you update a record, the underlying CBOR type could change. If you first have a value of 42.3 and later change it to 42.0, the type shifts from float to integer. In practice I don’t think that’s a real problem, it’s more of a theoretical one. If you have hard constraints, such as a schema, you should make them part of the Lexicon.</p>
<p>This approach may not always be sufficient. For example, if you have a key-value map where values should always be floats but you don’t know the exact keys, that currently cannot be expressed in a Lexicon. The proof of concept handles this by wrapping such values in a distinct type called <code>LexFloat()</code>. This ensures the number always has a decimal point in its JSON representation, even when it could be represented as an integer. Similarly, <code>LexInteger()</code> can be used to enforce an integer.</p>
<h2 id="the-proof-of-concept">The proof of concept</h2>
<p>The <a href="https://github.com/vmx/floats-on-atproto">proof of concept for floats on ATProto</a> does not only patch the PDS, but covers the full stack. From using the JS/TypeScript SDK to create records, to posting them on a local <a href="https://atproto.com/guides/glossary#pds-personal-data-server">PDS</a>, to observing them on the <a href="https://atproto.com/guides/glossary#relay">Relay</a>/<a href="https://atproto.com/guides/streaming-data#jetstream">Jetstream</a>. The README of the repo describes how to run everything along with the exact commands, so I won’t repeat that here.</p>
<p>I’ll just outline what to expect, so you can decide whether it’s worth trying yourself. The repo checks out the <a href="https://github.com/bluesky-social/atproto">atproto</a>, <a href="https://github.com/bluesky-social/indigo/">indigo</a> and <a href="https://github.com/bluesky-social/jetstream">jetstream</a> repos at arbitrary commits (from when I started the implementation). The <a href="https://github.com/vmx/floats-on-atproto/tree/39a7d1852788aff6f19b6c421e0632786c6bb625/patches">patches directory</a> contains the actual implementation of float support. The main changes are:</p>
<ul>
<li>JS/TypeScript SDK: Make record creation schema-aware</li>
<li>PDS/Relay: Make them aware of the integer/float distinction in JSON</li>
<li>Jetstream: Use the patched indigo code from the Relay</li>
</ul>
<p>There are three examples in the <code>repos/atproto/examples</code> directory (once patched). One demonstrates float encoding without running any service. The other two are meant to be used together when a local PDS and Relay are running. They insert data into the PDS and display the pretty-printed CBOR the Relay received.</p>
<h2 id="behavioural-changes">Behavioural changes</h2>
<p>Introducing floats obviously changes some parts of ATProto. The good news is that the public API of the JS/TypeScript SDK doesn’t need to change. Only additional helpers for special cases are added (like <code>LexFloat()</code>). When a record contains a number that cannot be represented as an integer, the SDK no longer throws an error.</p>
<p>I’ve added range support for floats to the Lexicon to mirror what integers already support, though I’m not sure that’s really necessary.</p>
<p>One breaking change I do consider worthwhile is in the JSON representation. Currently a number like <code>23e2</code> is treated as an integer. I believe it should be treated as a float instead, which would align ATProto with how  programming languages usually handle this.</p>
<h2 id="conclusion">Conclusion</h2>
<p>This blog post introduces a proof of concept for floats on ATProto. It should be taken as such, it’s not a finished solution. I’m sure I’ve missed subtle things that people working on ATProto daily would catch. It’s a starting point that hopefully shows that adding floats isn’t as daunting as it sounds, and that we can still have a system that behaves deterministically and remains easy to reason about.</p>
<p>If you have a use case for floats, or you think this is all a terrible idea, please let me (and the rest of the world) know. Either via Bluesky or on <a href="https://discourse.atprotocol.community/t/floats-on-atproto/877">this ATProto community forum thread</a>.</p>

]]></content:encoded>
<wfw:commentRss>https://vmx.cx/cgi-bin/blog/index.cgi/floats-on-atproto%3A2026-05-28%3Aen%2CATProto/feed/</wfw:commentRss>
</item>
<item>
<title>JSON, CBOR and numeric types
</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto</link>
<comments>https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto#comments</comments>
<pubDate>Mon, 20 Apr 2026 14:02:00 +0200</pubDate>
<dc:creator>Volker Mische</dc:creator>
<category>en</category>
<category>ATProto</category>
<guid isPermaLink="false">https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto/</guid>
<description><![CDATA[ <p>CBOR makes sense as a canonical representation format as that’s very hard to do with JSON (search for “canonical JSON” and you’ll find a lot of prior art). But having a JSON representation often makes sense, e.g. at HTTP API boundaries. Sending the data in a human readable string format almost every programming language natively supports is a big win. While the JSON doesn’t necessarily needs to be canonical, the data must survive a full CBOR -> JSON -> CBOR round-trip. One core problem are numeric types and this is exactly what this blog post is about.</p>
 [...]]]></description>
<content:encoded><![CDATA[
<p>CBOR makes sense as a canonical representation format as that’s very hard to do with JSON (search for “canonical JSON” and you’ll find a lot of prior art). But having a JSON representation often makes sense, e.g. at HTTP API boundaries. Sending the data in a human readable string format almost every programming language natively supports is a big win. While the JSON doesn’t necessarily needs to be canonical, the data must survive a full CBOR -> JSON -> CBOR round-trip. One core problem are numeric types and this is exactly what this blog post is about.</p>
<h3 id="numbers-in-cbor">Numbers in CBOR</h3>
<p>We restrict the CBOR to a subset called <a href="https://ipld.io/specs/codecs/dag-cbor/spec/">DAG-CBOR</a>/<a href="https://dasl.ing/drisl.html">DRISL</a>. The supported numeric types are integers and floats. Integers must always be encoded in the smallest representation possible (8, 16, 32 and 64-bits are supported). Floats are always in <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_forma">IEEE 754 double-precision binary floating-point format</a>.</p>
<h3 id="numbers-in-json">Numbers in JSON</h3>
<p>Converting from JSON to CBOR is similar to converting it into the native types of a programming language. There is the same problem of having only <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-6">a single numeric type in JSON</a>. But most programming languages follow the same convention to distinguish between floats and integers. If the number consists of digits only, it’s considered an integer, else it’s a float.</p>
<p>We can use the same convention going from JSON to CBOR as well. Suddenly we have support for integers and floats in JSON.</p>
<h3 id="numbers-in-javascript">Numbers in JavaScript</h3>
<p>When converting between JSON and CBOR, there’s usually an intermediate step in your favourite programming language that converts it to its native types. So most of the time it’s really JSON -> programming language native types -> CBOR and vice versa.</p>
<p>In most languages that’s not a problem, as their native types also have support for integers and floats. The elephant in the room is JavaScript. Historically there’s only a single numeric type, which is a float. So a naive JSON -> JSON.parse() -> CBOR approach would fail, as all numbers would end up as floats in CBOR.</p>
<p>There a two ways out of this. One is to use JavaScript’s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt">BigInt type</a> that was introduced in 2020. You would use BigInt for integers and then use the native JavaScript number type for floats. For JSON parsing a [custom reviver] would need to be used that outputs a BigInt for every number that only consists of digits:</p>
<pre><code class="language-js">const reviver = (_, value, context) => {
  // When it's a number and the original text is a sign and digits only.
  if (typeof value === 'number' && /^-?\d+$/.test(context.source)) {
    return BigInt(context.source)
  }
  return value
}
</code></pre>
<p>For encoding it as CBOR again, you would need a CBOR library that treats BigInts as CBOR integers and encodes them into their minimal representation and encodes all native numbers as 64-bit floats. That library would then also be responsible for CBOR -> native JavaScript types conversion using BigInts.</p>
<p>For native Javascript types to JSON, you would need to make sure that floats are always represented with a decimal point. By default a number like <code>2.0</code> becomes just <code>2</code>. This can be done with a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter">custom replacer</a>:</p>
<pre><code class="language-js">const replacer = (_, value) => {
  if (typeof value === 'bigint') {
    return JSON.rawJSON(value.toString())
  }

  if (typeof value === 'number') {
    // NaN / Infinity are not valid JSON.
    if (!Number.isFinite(value)) {
      return null
    }

    // Force a decimal point even when the value is mathematically integral.
    if (Number.isInteger(value)) {
      return JSON.rawJSON(`${value}.0`)
    }
  }

  return value
}
</code></pre>
<p>Another way, which might be simpler, is to skip the native JavaScript object part and use a custom JSON tokenizer that then creates the CBOR directly (and vice versa). <a href="https://github.com/rvagg/cborg">cborg</a> can be used for that.</p>
<h3 id="conclusion">Conclusion</h3>
<p>It’s possible to have a well defined, clean round-trip between JSON and CBOR for numeric types. Integers and floats can be distinguished in JSON by treating digit-only numbers as integers and all others as floats. No additional schema information is needed.</p>

]]></content:encoded>
<wfw:commentRss>https://vmx.cx/cgi-bin/blog/index.cgi/json-cbor-and-numeric-types.md%3A2026-04-20%3Aen%2CATProto/feed/</wfw:commentRss>
</item>
<item>
<title>Atmospheric data portals reply
</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi/atmospheric-data-portals-reply%3A2026-04-02%3Aen%2CMatadisco%2CATProto%2Cgeo</link>
<comments>https://vmx.cx/cgi-bin/blog/index.cgi/atmospheric-data-portals-reply%3A2026-04-02%3Aen%2CMatadisco%2CATProto%2Cgeo#comments</comments>
<pubDate>Thu, 02 Apr 2026 23:02:11 +0200</pubDate>
<dc:creator>Volker Mische</dc:creator>
<category>en</category>
<category>Matadisco</category>
<category>ATProto</category>
<category>geo</category>
<guid isPermaLink="false">https://vmx.cx/cgi-bin/blog/index.cgi/atmospheric-data-portals-reply%3A2026-04-02%3Aen%2CMatadisco%2CATProto%2Cgeo/</guid>
<description><![CDATA[ <p>This is a reply to <a href="https://bsky.app/profile/davidgasquez.com">David Gasquez’</a> blog post <a href="https://davidgasquez.com/atmospheric-data-portals">Atmospheric Data Portals</a>. As there’s so much in it and much of it overlaps with future plans, I thought it makes sense to write a proper public reply instead of following up in a private conversation.</p>
 [...]]]></description>
<content:encoded><![CDATA[
<p>This is a reply to <a href="https://bsky.app/profile/davidgasquez.com">David Gasquez’</a> blog post <a href="https://davidgasquez.com/atmospheric-data-portals">Atmospheric Data Portals</a>. As there’s so much in it and much of it overlaps with future plans, I thought it makes sense to write a proper public reply instead of following up in a private conversation.</p>
<p>First of all, read his blog post and follow the many links, there is so much to discover.</p>
<p>One re-occurring thing in the documents linked from the “issues on the earlier stages of the Open Data pipeline” section is that for most portals a static site should be sufficient. I fully agree with that. When it’s done properly, an automated rebuild of some parts when new data is added should work well. These days even <a href="https://lil.law.harvard.edu/blog/2025/10/24/rethinking-data-discovery-for-libraries-and-digital-humanities/">powerful client-sided search is possible</a>.</p>
<p>It’s a bit off-topic, but <a href="https://davidgasquez.com/barefoot-data-platforms">David’s Barefoot Data Platforms page</a> links to <a href="https://maggieappleton.com/home-cooked-software">Maggie Appleton’s Home Cooked Software and Barefoot Developers talk</a> linked. I highly recommend watching it, it was one of my favourite talks at the <a href="https://web.archive.org/web/20241003131259/https://www.localfirstconf.com/">Local-first Conference 2024</a>. I always wanted to blog about it, but never found the time.</p>
<p>But now to the concrete points David mentions. If anyone has ideas on how to make those things happen with Matadisco, please open issues on the <a href="https://github.com/ipfs-fdn/matadisco">main Matadisco repo</a>.</p>
<blockquote>
<p>Take inspiration from existing flexible standards like <a href="https://datapackage.org/standard/data-package/">Data Package</a>, <a href="https://github.com/mlcommons/croissant">Croissant</a>, and GEO ones for the core fields. Start with the smallest shared lexicon while leaving room for specialized extensions (sidecars?).</p>
</blockquote>
<p>I don’t think Matadisco should go into too much detail on specifying what the metadata should look like. Making one metadata standard to rule them all is destined to fail from my experience (<a href="https://en.wikipedia.org/wiki/Geospatial_metadata">ISO 19115/19139</a> anyone?). Though there might be a lowest common denominator, similar to what <a href="https://standard.site/">Standard.site is doing for long-form publishing</a>. In order to find out what that looks like, I propose that individual communities start by specifying Lexicons for their own needs. This could be done through tags, which I’ve outlined in the <a href="https://github.com/ipfs-fdn/matadisco/issues/3">Matadisco issue “Introducing tags for filtering and extension point”</a>.</p>
<blockquote>
<p>Split datasets from “snapshots”. Say, <code>io.datonic.dataset</code> holds long-term properties like <code>description</code> and points to <code>io.datonic.dataset.release</code> or <code>io.datonic.dataset.snapshot</code>, which point to the actual resources.</p>
</blockquote>
<p>Some kind of hierarchical relationship would be useful. <a href="https://github.com/TomNicholas/FROST">FROST</a>, which Matadisco drew a lot of inspiration from, is centred around <a href="https://icechunk.io/">IceChunk</a>, which also has the <a href="https://icechunk.io/en/v1.1.21/concepts/#snapshots">concept of snapshots</a>. But I don’t think we should stop at the concept of snapshots. In my original demo, I scrape a <a href="https://stacspec.org/">STAC catalogue</a> for <a href="https://documentation.dataspace.copernicus.eu/Data/SentinelMissions/Sentinel2.html#sentinel-2-level-2a-surface-reflectance">Sentinel-2 imagery</a>. Every new image is a new record. They are all part of the same <a href="https://github.com/radiantearth/stac-spec/blob/ec002bb93dbfa47976822def8f11b2861775b662/collection-spec/collection-spec.md">STAC collection</a>, so we could use a similar concept in Matadisco as well.</p>
<blockquote>
<p>Add an optional <a href="https://dasl.ing/cid.html">DASL-CID field</a> for resources so we “pin” the bytes.</p>
</blockquote>
<p>Yes, that’s something <a href="https://bsky.app/profile/mosh.bsky.social">@mosh</a> is keen to have. It’s not only useful for pinning things to a specific version, but also to make it possible to verify that the data you received is the one you expected. It sounds trivial, but the problem would be where to put it. Do you only hash the metadata record it points to? Do you hash the data container (if there’s one)? Or each resource a metadata record points to?</p>
<blockquote>
<p>Core lexicon should be as agnostic as possible!</p>
</blockquote>
<p>As mentioned above, it might be out of scope for Matadisco and for now it’s left to the individual communities.</p>
<blockquote>
<p>Bootstrap the catalog. There are many <a href="https://github.com/datonic/hub/blob/main/notes/related-projects.md#indexes">open indexes and organizations</a>. Crawl them!</p>
</blockquote>
<p>Indeed! My first two Matadisco producers are <a href="https://github.com/vmx/sentinel-to-atproto/">sentinel-to-atproto</a> crawling <a href="https://radiantearth.github.io/stac-browser/#/external/earth-search.aws.element84.com/v1/collections/sentinel-2-l2a">Element 84’s Earth Search STAC catalogue</a> and <a href="https://github.com/vmx/gdi-de-csw-to-atproto/">gdi-de-csw-to-atproto</a> crawling the <a href="https://gdk.gdi-de.org/">GeoNetwork instance of the official German geo metadata catalogue</a>.</p>
<blockquote>
<p>Integrate with external repositories. E.g., a service <a href="https://developers.google.com/search/docs/appearance/structured-data/dataset">that creates <code>JSON-LD</code> files</a> from the datasets it sees appearing on the Atmosphere so <a href="https://datasetsearch.research.google.com/">Google Datasets picks them up</a>. The same cron job could push data into Hugging Face or any other tool that people are already using in their fields.</p>
</blockquote>
<p>At first this would need to happen for each individual type of record, see the tags proposal above.</p>
<blockquote>
<p>Convince and work with high quality organizations doing something like this! I’d <a href="https://source.coop/harvard-lil/gov-data">definitely collaborate with <code>source.coop</code> for example</a>.</p>
</blockquote>
<p>That surely is the goal!</p>

]]></content:encoded>
<wfw:commentRss>https://vmx.cx/cgi-bin/blog/index.cgi/atmospheric-data-portals-reply%3A2026-04-02%3Aen%2CMatadisco%2CATProto%2Cgeo/feed/</wfw:commentRss>
</item>
<item>
<title>FOSSGIS 2026
</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi/fossgis-2026%3A2026-04-01%3Aen%2CMatadisco%2CATProto%2Cconference%2Cgeo</link>
<comments>https://vmx.cx/cgi-bin/blog/index.cgi/fossgis-2026%3A2026-04-01%3Aen%2CMatadisco%2CATProto%2Cconference%2Cgeo#comments</comments>
<pubDate>Wed, 01 Apr 2026 13:24:23 +0200</pubDate>
<dc:creator>Volker Mische</dc:creator>
<category>en</category>
<category>Matadisco</category>
<category>ATProto</category>
<category>conference</category>
<category>geo</category>
<guid isPermaLink="false">https://vmx.cx/cgi-bin/blog/index.cgi/fossgis-2026%3A2026-04-01%3Aen%2CMatadisco%2CATProto%2Cconference%2Cgeo/</guid>
<description><![CDATA[ <p>This is a short write-up on the <a href="https://www.fossgis-konferenz.de/2026/">FOSSGIS 2026 conference</a>. It’s a German speaking conference on free and open source geographic information systems and <a href="https://en.wikipedia.org/wiki/OpenStreetMap">OpenStreetMap</a>. So maybe a blog post in English spreads the word even wider.</p>
 [...]]]></description>
<content:encoded><![CDATA[
<p>This is a short write-up on the <a href="https://www.fossgis-konferenz.de/2026/">FOSSGIS 2026 conference</a>. It’s a German speaking conference on free and open source geographic information systems and <a href="https://en.wikipedia.org/wiki/OpenStreetMap">OpenStreetMap</a>. So maybe a blog post in English spreads the word even wider.</p>
<p>While being the biggest edition ever (1000 registrations on-site, 300 online) it was well run and organized as every year. It didn’t even feel larger than usual. The <a href="https://c3voc.de/">CCC video team</a> streamed live and <a href="https://media.ccc.de/c/fossgis2026">published the cut videos</a> the same day in outstanding quality as always.</p>
<p>I split this post into two sections, one about interesting talks for the geo world in general and then follow up discussions on my <a href="https://matadisco.org/">Matadisco</a> talk and <a href="https://atproto.com/">ATProto</a> in general.</p>
<h3 id="talks">Talks</h3>
<p>I’ve spent most of my time in hallway chatting with people as this is what matters most to me when I’m attending a conference in person. Nonetheless I’ve still managed to see some excellent talks.</p>
<h4 id="panel-discussion-on-digital-sovereignty-in-the-cloud">Panel discussion on digital sovereignty in the cloud</h4>
<p>The conference started with a <a href="https://pretalx.com/fossgis2026/talk/HG87KC/">high-class panel discussion on digital sovereignty in the cloud</a>. The public discussion on that topic is often centered around where servers are located. Though that doesn’t actually matter. US companies can be forced by their government to give access to the data independent of their physical location.</p>
<p>Other topics touched were best practices on switching from proprietary to open source systems.</p>
<h4 id="barrier-free-travelling-thanks-to-paid-mappers">Barrier-free travelling thanks to paid mappers</h4>
<p>Public transport in Germany must be accessible to disabled individuals (reality is far away from that). For routing, you need the data basis for it. This talk gets into the details on how <a href="https://en.wikipedia.org/wiki/Baden-W%C3%BCrttemberg">Baden-Württemberg</a>, a federal state in south Germany, works on enabling <a href="https://pretalx.com/fossgis2026/talk/V7YYG9/">barrier-free travelling</a>. They decided to add that information of all their 1100 train stations directly to OpenStreetMap. In order to achieve the required high quality they’ve hired through a third party company several experienced mappers from the community.</p>
<p>I really like the idea that OpenStreetMap can now be used as source of truth for that data set. I hope other federal states follow this lead.</p>
<h4 id="routing-talks">Routing talks</h4>
<p>I’ve seen two talks about routing. The one about <a href="https://pretalx.com/fossgis2026/talk/NHZTAM/">Valhalla routing engine with MapLibre Native</a> was interesting because it was about a special case, where you want to re-route bus lines in case of construction. Although the resulting system is not open source, they’ve contributed upstream to <a href="https://github.com/valhalla/valhalla">Valhalla</a>, to make it work well with <a href="https://github.com/maplibre/maplibre-native">MapLibre Native</a>. Those contributions can be more valuable than a one time source code dump of forked repositories, just to call it open source.</p>
<p>Another one was about <a href="https://pretalx.com/fossgis2026/talk/FNSWK8/">Real-time mobility analytics for disaster relief operations</a>, which was interesting to see how routing is used in such cases. The limitations and how such systems really help on the ground.</p>
<h3 id="matadisco-and-atproto">Matadisco and ATProto</h3>
<p>My <a href="https://pretalx.com/fossgis2026/talk/KV8VC7/">talk on Matadisco</a> was about the current status of metadata catalogues, the problems and how ATProto can make things better. What I should have made clearer is what Matadisco actually is. I didn’t make it clear that it’s just a schema/convention people would use to announce their data on ATProto. It could’ve been mistaken as a piece of software or a service. You would use Matadisco in order to implement something for your pipeline.</p>
<p>Nonetheless people got the idea and I had good conversations afterwards. I talked with <a href="https://bsky.app/profile/oliviaguyot.bsky.social">Olivia Guyot</a> about the possible ways on how to integrate Matadisco record publishing into <a href="https://geonetwork-opensource.org/">GeoNetwork</a>. With <a href="https://bsky.app/profile/cwillmes.mastodon.social.ap.brid.gy">Christian Willmes</a> about creating a portal for combining paleoenvironmental and archaeological data.</p>
<p>While chatting about ATProto at one of the social events <a href="https://bsky.app/profile/lapizistik.social.tchncs.de.ap.brid.gy">Klaus Stein</a> talked about how he would like a social network to be. Users would just put static files somewhere. I agree that having static webspace somewhere without any server component is not only cheap, but also the easiest to get. He is not bothered about other components being operated by other parties, e.g. for indexing. That kept me thinking how far ATProto is away from that. I’d like to build a prototype that is like a static site generator for ATProto records. It won’t be able to act as a full PDS, you would need a WebSocket connection to get the data to a relay. But there could be a minimal service operated by a third party that polls those static PDS for updates and forwards them to a relay.</p>

]]></content:encoded>
<wfw:commentRss>https://vmx.cx/cgi-bin/blog/index.cgi/fossgis-2026%3A2026-04-01%3Aen%2CMatadisco%2CATProto%2Cconference%2Cgeo/feed/</wfw:commentRss>
</item>
<item>
<title>Matadisco
</title>
<link>https://vmx.cx/cgi-bin/blog/index.cgi/matadisco%3A2026-03-23%3Aen%2CATProto%2Cgeo</link>
<comments>https://vmx.cx/cgi-bin/blog/index.cgi/matadisco%3A2026-03-23%3Aen%2CATProto%2Cgeo#comments</comments>
<pubDate>Mon, 23 Mar 2026 16:58:12 +0200</pubDate>
<dc:creator>Volker Mische</dc:creator>
<category>en</category>
<category>ATProto</category>
<category>geo</category>
<guid isPermaLink="false">https://vmx.cx/cgi-bin/blog/index.cgi/matadisco%3A2026-03-23%3Aen%2CATProto%2Cgeo/</guid>
<description><![CDATA[ <p>Open data is only as useful as it is discoverable. Finding datasets, whether it’s satellite imagery, scientific research, or cultural archives involves navigating dozens of siloed portals, each of them with different interfaces and APIs. Project <a href="https://matadisco.org/">Matadisco</a> tries to solve this by using <a href="https://atproto.com/">ATProto</a> to create an open, decentralized network for data discovery. Anyone can publish metadata about their datasets. You can then pick the records that matter to you and build views for the specific needs of your community. By focusing on metadata rather than the data itself, the system works with any dataset format, keeps records lightweight, and remains agnostic about storage.</p>
 [...]]]></description>
<content:encoded><![CDATA[
<p>Open data is only as useful as it is discoverable. Finding datasets, whether it’s satellite imagery, scientific research, or cultural archives involves navigating dozens of siloed portals, each of them with different interfaces and APIs. Project <a href="https://matadisco.org/">Matadisco</a> tries to solve this by using <a href="https://atproto.com/">ATProto</a> to create an open, decentralized network for data discovery. Anyone can publish metadata about their datasets. You can then pick the records that matter to you and build views for the specific needs of your community. By focusing on metadata rather than the data itself, the system works with any dataset format, keeps records lightweight, and remains agnostic about storage.</p>
<p>It’s early stage and experimental, but the potential is significant. To see it in action, visit the <a href="https://vmx.github.io/matadisco-viewer/">matadisco-viewer demo</a>. It listens to the incoming stream of ATProto events and renders them. At the moment it’s satellite images only, but that will hopefully change soon.</p>
<p><a href="/blog/2026-03-23/S2C_35NRB_20260121_0_L2A-TCI_page3.jpg"><img src="/blog/2026-03-23/S2C_35NRB_20260121_0_L2A-TCI_small.jpg" alt="Satellite image" /></a></p>
<p>Above is an example of what crossed my screen while developing (<a href="https://earth-search.aws.element84.com/v1/collections/sentinel-2-l2a/items/S2C_35NRB_20260121_0_L2A">metadata</a>, <a href="https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/35/N/RB/2026/1/S2C_35NRB_20260121_0_L2A/TCI.tif">download at full resolution (253MiB)</a>).</p>
<h2 id="motivation">Motivation</h2>
<p>Metadata records can be very diverse. They might describe geodata, your favourite news site or your favourite podcasts. What they all have in common is that users usually rely on centralized platforms in order to find them. For geodata, this is often a government-run open data or geo portal. These platforms decide which data gets published.</p>
<p>You might generate a derived dataset or clean up an existing one. If you operate from outside of the original creators, you probably won’t even be able to get your data linked from there. So how will anyone find out about it? That’s a problem of metadata discovery.</p>
<p>The other side of the problem is that even when metadata <em>is</em> available, it can be hard to find. There are large metadata aggregation portals like the <a href="https://data.europa.eu/">portal for European data</a>, with almost 2 million records. How do you find what exactly you are looking for. What if there were specialized portals tailored to specific communities?</p>
<p>For even more details, see the <a href="https://ipfsfoundation.org/matadisco-can-we-bootstrap-public-data-discovery-with-atproto/">companion blog post of the IPFS Foundation</a>.</p>
<h2 id="the-idea">The idea</h2>
<p>The idea is to support both: an easy way for anyone to publish discoverable metadata, and a way to make that metadata widely accessible to build both large aggregators and specialized portals tailored to specific communities.</p>
<p>The central building block is <a href="https://atproto.com/">ATProto</a>. It allows anyone to publish and subscribe to records. Rather than defining a single metadata schema to rule them all, the approach here is more meta-meta. Each record contains a link to the actual metadata. That’s the absolute minimum. Though it could make sense to go beyond this minimalism and store additional information to make it easier to build custom portals.</p>
<p>One example of such additional information is a preview. It’s nice to get a quick sense of the underlying data that the metadata describes. For satellite imagery, this could be a true color thumbnail of the scene. For long form articles, a summary or excerpt. For podcasts it may be a brief audio snippet or trailer.</p>
<h2 id="the-implementation">The implementation</h2>
<p>As part of my work at the <a href="https://ipfsfoundation.org/">IPFS Foundation</a>, I started with geodata. The first prototype focuses on [Copernicus Sentinel-2 L2A satellite images].</p>
<p>The metadata is sourced from <a href="https://radiantearth.github.io/stac-browser/#/external/earth-search.aws.element84.com/v1/collections/sentinel-2-l2a">Element 84’s Earth Search STAC catalogue</a>. It provides free, publicly accessible HTTP links to the images (the <a href="https://radiantearth.github.io/stac-browser/#/external/stac.dataspace.copernicus.eu/v1/collections/sentinel-2-l2a">official Copernicus STAC</a> does not). A [Cloudflare Worker] checks the STAC instance every few minutes for updates. When new records appear, a link to the metadata along with a preview is ingested into ATProto. The source code for the worker is available at <a href="https://github.com/vmx/sentinel-to-atproto/">https://github.com/vmx/sentinel-to-atproto/</a>.</p>
<p>Below is the Lexicon schema for this ATProto meta-metadata record, which I call Matadisco. To improve readability, the <a href="https://mlf.lol/playground/?share=Ly8vIEEgTWF0YWRpc2NvIHJlY29yZApyZWNvcmQgbWF0YWRpc2NvIHsKICAgIC8vLyBUaGUgdGltZSB0aGUgb3JpZ2luYWwgbWV0YWRhdGEvZGF0YSB3YXMgcHVibGlzaGVkCiAgICBwdWJsaXNoZWRBdCE6IERhdGV0aW1lLAogICAgLy8vIEEgVVJJIHRoYXQgbGlua3MgdG8gcmVzb3VyY2UgY29udGFpbmluZyB0aGUgbWV0YWRhdGEKICAgIHJlc291cmNlITogVXJpLAogICAgLy8vIFByZXZpZXcgb2YgdGhlIGRhdGEKICAgIHByZXZpZXc6IHsKICAgICAgICAvLy8gVGhlIG1lZGlhIHR5cGUgdGhlIHByZXZpZXcgaGFzCiAgICAgICAgbWltZVR5cGUhOiBzdHJpbmcsCiAgICAgICAgLy8vIFRoZSBVUkwgdG8gdGhlIHByZXZpZXcKICAgICAgICB1cmw6IFVyaSwKICAgIH0sCn0K">MLF syntax</a> is used:</p>
<pre><code>/// A Matadisco record
record matadisco {
    /// The time the original metadata/data was published
    publishedAt!: Datetime,
    /// A URI that links to resource containing the metadata
    resource!: Uri,
    /// Preview of the data
    preview: {
        /// The media type the preview has
        mimeType!: string,
        /// The URL to the preview
        url: Uri,
    },
}
</code></pre>
<p>Once records are available on ATProto, they can be processed and displayed. I built a simple viewer that renders records conforming to the <code>cx.vmx.matadisco</code> Lexicon schema defined above. A <a href="https://github.com/bluesky-social/jetstream">Bluesky Jetstream</a> instance streams newly added records directly into the browser. A demo is available at <a href="https://vmx.github.io/matadisco-viewer/">https://vmx.github.io/matadisco-viewer/</a>.</p>
<p>If you’re interested in seeing the raw records, you can find them <a href="https://pdsls.dev/at://did:plc:otu6ccrwycke33kl3h4yjhwn/cx.vmx.matadisco">on my ATProto dev account</a>.</p>
<h2 id="prior-art">Prior art</h2>
<p>This work builds on ideas by <a href="https://github.com/TomNicholas/">Tom Nicholas</a>, who started a project called <a href="https://github.com/TomNicholas/FROST">FROST</a>. His <a href="https://hackmd.io/@TomNicholas/H1KzoYrPJe">motivating blog post</a> is an excellent read about data-sharing challenges in a scientific context. His <a href="https://discourse.pangeo.io/t/pangeo-showcase-frost-federated-registry-of-scientific-things-feb-12-2025/4861">presentation on FROST</a> explains why such a system should remain simple, with the metadata URL as the only required field.</p>
<p><a href="https://github.com/edsilv">Edward Silverton</a>, who works in the <a href="https://en.wikipedia.org/wiki/GLAM_(cultural_heritage)">GLAM</a> space, explored a similar idea for publishing <a href="https://en.wikipedia.org/wiki/International_Image_Interoperability_Framework">IIIF</a> data. We refined his approach to align it more closely with FROST. <a href="https://docs.google.com/document/d/1CylRKwnnWsnGQS4enAf4xihz8wmjf3CEGcT1gwwz1PM/edit?usp=sharing">He published</a> further details on the complete workflow for his use case, which has a broader scope.</p>
<p>There was also a discussion thread on Bluesky about <a href="https://bsky.app/profile/brookie.blog/post/3m6uu3emkwc2s">metadata for long-form content to build cross-platform discovery</a>.</p>
<h2 id="whats-next">What’s next</h2>
<p>Possible future steps I want to look into:</p>
<ul>
<li>Adding another, different geodata source, such as metadata from the <a href="https://geodatenkatalog.de">German geodata catalogue</a>.</li>
<li>Including another image-based source, for example GLAM catalogues that use <a href="https://en.wikipedia.org/wiki/International_Image_Interoperability_Framework">IIIF</a>.</li>
<li>Integrating a completely different data source, such as metadata from the <a href="https://www.ardaudiothek.de/">podcasts of the German public broadcasting</a>.</li>
</ul>
<p>As mentioned in the introduction, this is deliberately experimental, things may break or change dramatically. The upside is that no one needs to worry about breakage. Please experiment with these ideas and let us now about them at the <a href="https://github.com/ipfs-fdn/matadisco">Matadisco GitHub repository</a>. Publish records under your own namespace, or even reuse the one I am currently using.</p>

]]></content:encoded>
<wfw:commentRss>https://vmx.cx/cgi-bin/blog/index.cgi/matadisco%3A2026-03-23%3Aen%2CATProto%2Cgeo/feed/</wfw:commentRss>
</item>
</channel>
</rss>
