OpenFile and OpenDisk: the web doors onto an ipfile swarm and a paid2seed seeder (#162)

OpenSwarm says how a file lives on a swarm and how a seeder is paid to hold
it, and nothing in it gives a person with a browser, a search engine or a
directory a URL to start from. A manifest is on the DHT under a key, the
catalogue is a feed found through the DHT, the seed market is one-sided:
offers are listed and seeders poll them. A requester who wants a box in
Germany with two terabytes free and a year of clean proofs has no file to
read, and a seeder with those things has no file to serve.

OpenFile is /.well-known/openfile.json on a publisher's origin: each file
by its plaintext content hash (the ipfile plainRoot, so the id a reader
gets is the root the decrypted file verifies against), every way to fetch
it (an ipfile magnet, a webseed, plain HTTP by range, HLS for a player
with nothing installed), the pay2seed attestation and README, the price
as an x402 offer URL, and a holders list of who has the bytes now with
the age of each seeder's last proof. Encryption is ipfile unless the
publisher says none as an explicit act.

OpenDisk is /.well-known/opendisk.json on a machine that rents disk: free
GiB, price per GiB-month in the unit pay2seed already prices in, the
operator's accept policy stated up front so nobody posts an offer the disk
would never take, proof cadence, the seeder key and the hubs it takes
leases at, and a record block whose source is the hub's own seeder page,
because a marketplace reads standing from the hub and never from the
file. d1sks.com is the reference marketplace. A disk is also an OpenServer
offer of kind storage, and the mapping is a table, so the nichedb hosting
collection lists every disk without a second parser.

Neither restates a record that already has a name: the swarm is ipfile,
the consent is pay2seed, the leases and proofs are paid2seed, the payee
and the pass are ippay, the feed is ipdb. Both are registered in the four
places a LogicSRC spec needs and added to the OpenSwarm family table.
OpenFile has no product domain yet and says so.


Claude-Session: https://claude.ai/code/session_01Khk1C6Ese6xjdHAWLVstca

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-09-12 19:05:15 -07:00 • committed by GitHub
parent be2d67b8c3
commit 26295dd740
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 801 additions and 0 deletions

View file

@ -28,6 +28,8 @@ export function GET(): Response {
- [OpenMemory](${SITE_URL}/openmemory): The memory block of an OpenServer offer: RAM in mebibytes, DDR generation, ECC as three states, reserved or balloonable allocation, and a range priced per step.
- [OpenGPU](${SITE_URL}/opengpu): The gpu block of an OpenServer offer: the card by its vendor name, count and VRAM per device, interconnect, passthrough, MIG, vGPU or shared access, and a range over count.
- [OpenBandwidth](${SITE_URL}/openbandwidth): The network block of an OpenServer offer: port speed, transfer, unmetered, 95th percentile or flat metering, overage, IPv4 and IPv6 addresses as a priced resource, DDoS scrubbing, and a range.
- [OpenFile](${SITE_URL}/openfile): One file a publisher serves about the files it has published: content hash, swarm and HTTP fetch routes, verification, consent basis, price, and who holds it now, discovered at /.well-known/openfile.json. The web door onto an OpenSwarm ipfile swarm.
- [OpenDisk](${SITE_URL}/opendisk): One file a machine serves about the disk it will rent: free GiB, price per GiB-month, location, policy, proof cadence and hub standing, discovered at /.well-known/opendisk.json. What a peer-to-peer storage market is made of; reference marketplace d1sks.com.
- [AgentSwarm](${SITE_URL}/agent-swarm): Provider-neutral agent orchestration, model routing, and cost controls.
- [AgentByte](${SITE_URL}/agentbyte): Agent screening sessions, policy events, and APIs.
- [Credential Sharing](${SITE_URL}/credential-sharing): End-to-end-encrypted team vaults, plus source/target credential diffs, approval, sync, rollback, and audit.

View file

@ -0,0 +1,195 @@
import Link from "next/link";
import type { ReactNode } from "react";
import type { Metadata } from "next";
import { SiteShell } from "@/components/site-shell";
import { mono, pre, table, td, th } from "../openontology/ui";
export const metadata: Metadata = {
title: "OpenDisk · LogicSRC",
description:
"OpenDisk is one file a machine serves about the disk it will rent: free GiB, price per GiB-month, location, policy, proof cadence and hub standing, at /.well-known/opendisk.json. What a peer-to-peer storage market is made of. Reference marketplace d1sks.com.",
alternates: { canonical: "/opendisk" }
};
const DESCRIPTOR = `{
"name": "seeder-a41e, Falkenstein",
"operator": "https://seeder-a41e.example/.well-known/openprofile.md",
"key": "ed25519:a41e…7b0a",
"hubs": ["https://bittorrented.com/api/openswarm", "https://d1sks.com/api/openswarm"],
"capacity": { "total_gib": 3726, "free_gib": 2210 },
"price": { "currency": "USD", "per_gib_month": 0.12, "per_gib_transfer": 0.004, "max_gib": 2000, "max_days": 365 },
"location": { "regions": ["fsn1"], "countries": ["DE"] },
"network": { "bandwidth_mbps": 1000, "transfer_gb": 20000 },
"accepts": { "visibility": ["private", "public"], "encrypted_only": false, "max_file_gib": 500 },
"proof": { "kinds": ["challenge", "probe"], "every_hours_min": 6 },
"record": { "source": "https://bittorrented.com/api/openswarm/pay2seed/seeders/ed25519:a41e…7b0a", "standing": 412 },
"payout": { "payee": "ed25519:a41e…7b0a", "network": "eip155:8453" }
}`;
const MINIMAL = `{ "name": "spare drive, Lisbon", "capacity": { "free_gib": 900 },
"price": { "currency": "USD", "per_gib_month": 0.08 } }`;
const RENT: Array<[string, string]> = [
["1. Read", "The descriptor for policy and price, and record.source at the hub for standing."],
["2. Attest", "The consent record pay2seed requires, with README.md at the root of the swarm."],
["3. Offer", "A pay2seed offer at one of the disk's hubs, at or above per_gib_month, with the budget escrowed."],
["4. Lease", "The disk's seeder client takes it on its next poll, or at once when the hub pushes to proof.webhook."],
["5. Prove", "Challenges and probes every period, receipts per proven period, payout to the payee. All paid2seed, unchanged."]
];
const MAPPING: Array<[string, string]> = [
["offers[].kind", "storage"],
["offers[].model", "p2p for a peer, centralized for a provider; the disk may say"],
["offers[].price", "{ amount: per_gib_month, currency, interval: month, unit: gib }"],
["offers[].stock", "in_stock while free_gib covers min_gib"],
["location, network, storage", "the same keys, the same units"]
];
const ABSENT: Array<[string, string]> = [
["No lease in this file", "The descriptor is the ask, the offer is the bid, the lease is the match, made at the hub as paid2seed says."],
["No escrow at the disk", "Money sits at a hub. A disk never holds a requester's funds."],
["No reputation of its own", "record is a copy of what a hub signed. A marketplace reads the hub, and lists the hub's number."],
["No plaintext", "By default a disk holds ipfile ciphertext it cannot read, and a personal swarm's existence is not in its public list."],
["No central registry", "Anyone may serve a descriptor and anyone may read it. Two marketplaces reading the same file list the same disk."]
];
export default function OpenDiskPage(): ReactNode {
return (
<SiteShell active="OpenDisk">
<div className="band">
<div className="section-head">
<p className="eyebrow">LogicSRC standards surface</p>
<h2>OpenDisk</h2>
<p>
One file a machine serves about the disk it will rent, so a disk can be found instead of
waited for, and a peer with a spare terabyte is on the market by putting a file at a URL.
</p>
</div>
<p style={{ color: "#41505d" }}>
<Link href="/openswarm">OpenSwarm</Link> already says how a seeder is paid to hold a swarm:
an offer with money escrowed, a lease, a storage proof every period, a payout per
GiB-month. What it does not say is how a requester finds a seeder before posting. The
market is one-sided: offers are listed and seeders poll them. OpenDisk is the other side.
A disk puts its free space, price, location, policy, proof cadence and hub standing at{" "}
<code style={mono}>/.well-known/opendisk.json</code>, and a requester reads the disk
before it posts.
</p>
<p style={{ color: "#5b6b7a" }}>
Status: 0.1. <a href="https://d1sks.com">d1sks.com</a> is the reference marketplace: every
descriptor it has read, standing pulled from the hubs each disk names, and an offer form that
posts to the disk&apos;s hub. Every disk is also a hosting offer in the{" "}
<Link href="/openserver">OpenServer</Link> sense, listed as one at nichedb.dev.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The descriptor</h2>
<p>
Served at <code style={mono}>/.well-known/opendisk.json</code>. Only a name, the free
space and a price are required.
</p>
</div>
<pre style={pre}>{DESCRIPTOR}</pre>
<p style={{ color: "#41505d" }}>
<code style={mono}>key</code> is the seeder identity that signs proofs and is paid;{" "}
<code style={mono}>hubs</code> is where it takes leases. <code style={mono}>accepts</code>{" "}
is the operator&apos;s policy stated up front, so nobody posts an offer this disk would never
take. <code style={mono}>record.source</code> is the hub&apos;s own page for this seeder,
and a marketplace reads the hub, not the file, for anything it ranks on. The smallest valid
descriptor:
</p>
<pre style={pre}>{MINIMAL}</pre>
</div>
<div className="band">
<div className="section-head">
<h2>Renting a disk</h2>
<p>Nothing on the swarm side changes. The descriptor only moves the first step to a URL.</p>
</div>
<table style={table}>
<tbody>
{RENT.map(([step, what]) => (
<tr key={step}>
<td style={td}>
<strong>{step}</strong>
</td>
<td style={td}>{what}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="band">
<div className="section-head">
<h2>As an OpenServer offer</h2>
<p>A disk is a hosting offer, and a directory that reads OpenServer lists it without a second parser.</p>
</div>
<table style={table}>
<thead>
<tr>
<th style={th}>OpenServer</th>
<th style={th}>from OpenDisk</th>
</tr>
</thead>
<tbody>
{MAPPING.map(([key, from]) => (
<tr key={key}>
<td style={td}>
<code style={mono}>{key}</code>
</td>
<td style={td}>{from}</td>
</tr>
))}
</tbody>
</table>
<p style={{ color: "#41505d", marginTop: "1rem" }}>
A provider that sells storage plans and rents disk to swarms serves both files. A peer with
one drive serves only this one, and is listed in both places.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>What is deliberately absent</h2>
</div>
<table style={table}>
<tbody>
{ABSENT.map(([what, why]) => (
<tr key={what}>
<td style={td}>
<strong>{what}</strong>
</td>
<td style={td}>{why}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="band">
<div className="section-head">
<h2>Where everything lives</h2>
</div>
<ul style={{ color: "#41505d", lineHeight: 1.9, paddingLeft: "1.1rem" }}>
<li>
<Link href="/docs/opendisk">Specification</Link>: the descriptor, holding, renting a disk,
marketplaces, the OpenServer mapping
</li>
<li>
<a href="https://d1sks.com">d1sks.com</a>: the reference marketplace
</li>
<li>
<Link href="/openswarm">OpenSwarm</Link>: pay2seed for the offer, paid2seed for leases and
proofs, ippay for the payee, ipfile for what is held
</li>
<li>
<Link href="/openfile">OpenFile</Link>, the publisher&apos;s side and the holders list a disk
appears in; <Link href="/openserver">OpenServer</Link>, the hosting offer a disk maps onto
</li>
</ul>
</div>
</SiteShell>
);
}

View file

@ -0,0 +1,220 @@
import Link from "next/link";
import type { ReactNode } from "react";
import type { Metadata } from "next";
import { SiteShell } from "@/components/site-shell";
import { mono, pre, table, td, th } from "../openontology/ui";
export const metadata: Metadata = {
title: "OpenFile · LogicSRC",
description:
"OpenFile is one file a publisher serves about the files it has published: content hash, swarm and HTTP fetch routes, verification, consent basis, price, and who holds it now, at /.well-known/openfile.json. The web door onto an OpenSwarm ipfile swarm.",
alternates: { canonical: "/openfile" }
};
const DESCRIPTOR = `{
"publisher": {
"name": "Dartmoor Field Recordings",
"operator": "https://dartmoor.example/.well-known/openprofile.md",
"key": "ed25519:5d29…d59e",
"hubs": ["https://bittorrented.com/api/openswarm"]
},
"files": [{
"id": "sha256:d6c3…93ff",
"name": "interview-2026-09-05.flac",
"size": 734003200,
"swarm": { "file": "ed25519:0d87…295d", "infohashV2": "sha256:4b74…a342" },
"encryption": "ipfile",
"fetch": [
{ "kind": "ipfile", "url": "magnet:?xs=urn:btpk:0d87…295d&s=ipfile" },
{ "kind": "http", "url": "https://gw.c0mpute.com/file/d6c3…93ff" },
{ "kind": "hls", "url": "https://gw.c0mpute.com/file/d6c3…93ff/index.m3u8" }
],
"attestation": { "basis": "own", "license": "CC-BY-4.0" },
"price": { "amount": 0.5, "currency": "USD", "per": "key", "offer": "https://keys.dartmoor.example/…" },
"holders": "https://bittorrented.com/api/openswarm/files/d6c3…93ff/holders"
}]
}`;
const MINIMAL = `{ "publisher": { "name": "Dartmoor Field Recordings" },
"files": [{ "id": "sha256:d6c3…93ff", "name": "interview-2026-09-05.flac" }] }`;
const FETCH: Array<[string, string, string]> = [
["ipfile", "a magnet for an OpenSwarm client", "encrypted pieces, paid per piece, the key on a pass"],
["magnet", "a vanilla magnet", "the ciphertext, for a client that cannot pay"],
["webseed", "BEP 19, ciphertext by range", "a gateway standing in for peers"],
["http", "the plaintext by range from a gateway", "a browser with nothing installed, behind a pass when there is a price"],
["hls", "a media file as a standard playlist", "any player, sealed when there is a price"]
];
const REUSED: Array<[string, string]> = [
["The swarm and the manifest", "ipfile: the file key, both infohashes, plainRoot as the content hash, the plaintext piece layer"],
["Consent and the README", "pay2seed: the attestation record, its basis and licence, the notice endpoint, README.md at the root"],
["Who holds it", "paid2seed: leases and the proofs behind provenAt"],
["Payment", "ippay: a pass bought over x402, presented as a bearer token on the gateway"],
["The feed", "ipdb: the same catalogue, replicated between peers, for a reader that speaks the swarm"]
];
const ABSENT: Array<[string, string]> = [
["No new swarm format", "The swarm is ipfile, the consent is pay2seed's, the payment is ippay's. This is a JSON door onto records that already exist."],
["No search", "A descriptor lists one publisher's files. Finding a file across publishers is a directory's job."],
["No trust score", "verified says where the file came from and who signed the manifest. basis is what the publisher claimed. The rest is the reader's judgement."],
["No DRM", "A pass holder gets the key and the bytes, as ipfile says."]
];
export default function OpenFilePage(): ReactNode {
return (
<SiteShell active="OpenFile">
<div className="band">
<div className="section-head">
<p className="eyebrow">LogicSRC standards surface</p>
<h2>OpenFile</h2>
<p>
One file a publisher serves about the files it has published, so a file can be found
instead of crawled, and fetched by a browser that has never heard of a swarm.
</p>
</div>
<p style={{ color: "#41505d" }}>
A file on a swarm is findable by its infohash and by nothing else. <Link href="/openswarm">OpenSwarm</Link>{" "}
fixed the inside of the swarm: a signed manifest, encrypted pieces, consent at upload, a
replicated catalogue. What none of that gives a person with a browser, a search engine or a
directory is a URL to start from. OpenFile puts a publisher&apos;s catalogue at{" "}
<code style={mono}>/.well-known/openfile.json</code>, with a content hash to verify
against, every way to fetch the bytes, the basis it was published on, the price, and who is
holding it right now.
</p>
<p style={{ color: "#5b6b7a" }}>
Status: 0.1. The reference reader is bittorrented.com, which lists consented swarms beside
the bare infohashes of its DHT crawl, with the README as the page. A product for it is
planned under a name not yet chosen.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The descriptor</h2>
<p>
Served at <code style={mono}>/.well-known/openfile.json</code>. Only the publisher&apos;s
name and each file&apos;s content hash and name are required.
</p>
</div>
<pre style={pre}>{DESCRIPTOR}</pre>
<p style={{ color: "#41505d" }}>
<code style={mono}>id</code> is the SHA-256 of the plaintext, which for an ipfile swarm is
the manifest&apos;s <code style={mono}>plainRoot</code>: the same root the decrypted file
verifies against. Two publishers serving the same bytes list the same id, and a directory
has one file with two listings. <code style={mono}>encryption</code> is ipfile unless the
publisher says <code style={mono}>none</code> as an explicit act. The smallest valid
descriptor:
</p>
<pre style={pre}>{MINIMAL}</pre>
</div>
<div className="band">
<div className="section-head">
<h2>Five ways to fetch</h2>
<p>Listed in the publisher&apos;s order of preference. A reader picks the first kind it speaks.</p>
</div>
<table style={table}>
<thead>
<tr>
<th style={th}>kind</th>
<th style={th}>What it is</th>
<th style={th}>Who uses it</th>
</tr>
</thead>
<tbody>
{FETCH.map(([kind, what, who]) => (
<tr key={kind}>
<td style={td}>
<code style={mono}>{kind}</code>
</td>
<td style={td}>{what}</td>
<td style={td}>{who}</td>
</tr>
))}
</tbody>
</table>
<p style={{ color: "#41505d", marginTop: "1rem" }}>
Over any of them the bytes verify the same way: each piece against the plaintext piece
layer, or the whole against <code style={mono}>id</code>. A reader refuses bytes that fail
and says which holder served them.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>Holders</h2>
<p>A file is only as available as the machines holding it.</p>
</div>
<p style={{ color: "#41505d" }}>
<code style={mono}>holders</code> answers with who has the bytes now: a{" "}
<code style={mono}>seeder</code> with a lease and the time it last passed a proof, a{" "}
<code style={mono}>gateway</code> serving it over HTTP, a <code style={mono}>peer</code>{" "}
merely seen. Each carries its age, and a seeder&apos;s lease can be checked at the hub.
A holder that rents disk links its own <Link href="/opendisk">OpenDisk</Link> descriptor, so a
publisher that likes a holder can buy more of it.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>What is reused</h2>
<p>Every record OpenFile points at already has a name in the OpenSwarm family.</p>
</div>
<table style={table}>
<tbody>
{REUSED.map(([what, from]) => (
<tr key={what}>
<td style={td}>
<strong>{what}</strong>
</td>
<td style={td}>{from}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="band">
<div className="section-head">
<h2>What is deliberately absent</h2>
</div>
<table style={table}>
<tbody>
{ABSENT.map(([what, why]) => (
<tr key={what}>
<td style={td}>
<strong>{what}</strong>
</td>
<td style={td}>{why}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="band">
<div className="section-head">
<h2>Where everything lives</h2>
</div>
<ul style={{ color: "#41505d", lineHeight: 1.9, paddingLeft: "1.1rem" }}>
<li>
<Link href="/docs/openfile">Specification</Link>: the descriptor, the per-file descriptor,
holders, discovery, fetching and verifying, what a directory owes a publisher
</li>
<li>
<Link href="/openswarm">OpenSwarm</Link>: ipfile, pay2seed, paid2seed, ippay and ipdb,
the records this file is a door onto
</li>
<li>
<Link href="/opendisk">OpenDisk</Link>, what a holder serves about the disk it rents;{" "}
<Link href="/openserver">OpenServer</Link>, how a gateway or seeder is listed as hosting
</li>
<li>
<Link href="/openprofile">OpenProfile.md</Link>, the operator behind a publisher
</li>
</ul>
</div>
</SiteShell>
);
}

View file

@ -30,6 +30,8 @@ const STATIC_ROUTES: Array<{
{ path: "/openmemory", changeFrequency: "weekly", priority: 0.9 },
{ path: "/opengpu", changeFrequency: "weekly", priority: 0.9 },
{ path: "/openbandwidth", changeFrequency: "weekly", priority: 0.9 },
{ path: "/openfile", changeFrequency: "weekly", priority: 0.9 },
{ path: "/opendisk", changeFrequency: "weekly", priority: 0.9 },
{ path: "/openontology/explore", changeFrequency: "daily", priority: 0.7 },
{ path: "/openspec", changeFrequency: "weekly", priority: 0.8 },
{ path: "/agent-swarm", changeFrequency: "weekly", priority: 0.8 },

View file

@ -22,6 +22,8 @@ const NAV: Array<{ href: string; label: string; external?: boolean }> = [
{ href: "/openmemory", label: "OpenMemory" },
{ href: "/opengpu", label: "OpenGPU" },
{ href: "/openbandwidth", label: "OpenBandwidth" },
{ href: "/openfile", label: "OpenFile" },
{ href: "/opendisk", label: "OpenDisk" },
{ href: "/#cli", label: "CLI" },
{ href: "/docs", label: "Docs" },
{ href: "/blog", label: "Blog" },

View file

@ -21,6 +21,8 @@ export const DOC_SLUGS = [
"openmcp",
"openaccess",
"openserver",
"openfile",
"opendisk",
"openstream",
"opencpu",
"openmemory",