feat(specs): OpenObject and OpenSlice 0.1

OpenObject is a bucket you can mount: keyed objects as ipfile swarms placed
on OpenDisk disks under pay2seed at a stated redundancy (three replicas on
three operators in two countries by default), an ipdb index as the bucket's
clock, a repair loop, an HTTP API, an S3 mapping and a mount whose
consistency is close-to-open by seq. d1sks.com is the reference store.

OpenSlice is a container whose compute is rented from one market and whose
disk is mounted from another: a host descriptor at
/.well-known/openslice.json, one signed slice file (image by digest,
OpenCPU/OpenMemory/OpenGPU units, OpenObject mounts, OpenCreds env, ports,
placement, lifetime), and a reservation that is a paid2seed lease applied to
compute with presence proofs per epoch. slic3s.com is the reference
marketplace; c0mpute hosts take the slice role.

Both are registered under OpenServer in the catalogs family with landing
pages, rows in the OpenSwarm family table, and the spec-discovery contract.
llms.txt now cites the specification URL for child specs too, which every
block under OpenServer had been missing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-09-21 08:58:04 +00:00
parent 08490aecf3
commit ff896d1daa
8 changed files with 1020 additions and 4 deletions

View file

@ -14,7 +14,9 @@ describe.each([
{ slug: "openabtest", name: "OpenABTest", family: "process" },
{ slug: "openfleet", name: "OpenFleet", family: "process" },
{ slug: "openrental", name: "OpenRental", family: "catalogs" },
{ slug: "openwall", name: "OpenWall", family: "people" }
{ slug: "openwall", name: "OpenWall", family: "people" },
{ slug: "openobject", name: "OpenObject", family: "catalogs" },
{ slug: "openslice", name: "OpenSlice", family: "catalogs" }
])("$name public discovery", ({ slug, name, family }) => {
it("serves the specification through its family and docs index", () => {
expect(familyOfSpec(slug)?.slug).toBe(family);

View file

@ -11,9 +11,10 @@ export function GET(): Response {
const url = `${SITE_URL}${spec.landing ?? spec.doc ?? ""}`;
const doc = spec.doc && spec.landing ? ` Specification: ${SITE_URL}${spec.doc}.` : "";
const head = `- [${spec.name}](${url}): ${spec.line}.${doc}`;
const kids = children.map(
(c) => ` - [${c.name}](${SITE_URL}${c.landing ?? c.doc ?? ""}): ${c.line}.`
);
const kids = children.map((c) => {
const kidDoc = c.doc && c.landing ? ` Specification: ${SITE_URL}${c.doc}.` : "";
return ` - [${c.name}](${SITE_URL}${c.landing ?? c.doc ?? ""}): ${c.line}.${kidDoc}`;
});
return [head, ...kids];
});
return `## ${family.name}\n\n${family.line}. Family page: ${SITE_URL}/specs/${family.slug}\n\n${lines.join("\n")}`;

View file

@ -0,0 +1,230 @@
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: "OpenObject · LogicSRC",
description:
"OpenObject is a bucket you can mount: keyed objects encrypted by their owner, placed on paid OpenDisk disks under a stated redundancy such as three replicas, verified every period, repaired when a disk fails, listed by prefix and read back by path. Reference store d1sks.com.",
alternates: { canonical: "/openobject" }
};
const DESCRIPTOR = `{
"name": "d1sks.com",
"operator": "https://profullstack.com/.well-known/openprofile.md",
"key": "ed25519:7c02…0c3b",
"api": "https://d1sks.com/openobject/v1",
"hubs": ["https://d1sks.com/api/openswarm"],
"disks": "https://d1sks.com/api/disks",
"policies": [
{ "id": "3x", "mode": "replicas", "replicas": 3, "min_operators": 3, "min_countries": 2, "default": true },
{ "id": "rs-10-4", "mode": "erasure", "k": 10, "parity": 4, "min_operators": 14 }
],
"price": { "currency": "USD", "per_gib_month": { "3x": 0.036, "rs-10-4": 0.017 }, "per_gib_transfer": 0.005 },
"capacity": { "free_gib": 184000, "disks": 412 },
"accepts": { "encryption": ["owner", "store"], "mounts": ["fuse", "nfs", "webdav", "s3"] },
"proof": { "every_hours": 6, "repair_within_hours": 24 },
"record": { "source": "https://d1sks.com/api/openswarm/pay2seed/requesters/ed25519:7c02…0c3b", "lost": 0 }
}`;
const OBJECT = `{
"type": "openobject.object",
"bucket": "ed25519:3a9f…4a6c",
"key": "photos/2026/09/a.jpg",
"rev": 3, "seq": 48211,
"id": "sha256:d6c3…93ff",
"size": 4194304,
"swarm": { "infohashV2": "sha256:4b74…a342" },
"policy": { "mode": "replicas", "replicas": 3 },
"holders": [
{ "disk": "ed25519:a41e…7b0a", "lease": "sha256:5c02…", "provenAt": "2026-09-21T06:00:05Z" },
{ "disk": "ed25519:9d3c…11ef", "lease": "sha256:71aa…", "provenAt": "2026-09-21T06:00:09Z" },
{ "disk": "ed25519:02be…c8d0", "lease": "sha256:c3f0…", "provenAt": "2026-09-21T05:59:58Z" }
],
"state": "healthy"
}`;
const LOOP: Array<[string, string]> = [
["1. Write", "PUT the bytes, or a record for a swarm already seeded. The client keeps its copy until the store says healthy."],
["2. Place", "One pay2seed offer per object with seeders.min = replicas, from the owner's escrow, onto distinct disks, operators and countries."],
["3. Prove", "Every holder answers paid2seed challenges each period; provenAt on the record is the last one the store saw."],
["4. Repair", "A failed holder is marked at once; a replacement is leased within repair_within_hours; the object is degraded, never silently short."],
["5. Read", "GET by key, Range honoured, verified against id before the last byte. LIST by prefix from the index, never from a disk."],
["6. Mount", "Keys are paths, the index is the metadata, the swarm is the data, writes are write-back, close-to-open by seq."]
];
const MAPPING: Array<[string, string]> = [
["offers[]", "one per policy: kind storage, model p2p, management managed"],
["offers[].price", "{ amount: per_gib_month[policy], currency, interval: month, unit: gib }"],
["offers[].stock", "in_stock while capacity.free_gib is above zero"],
["location", "the pool's countries, unchanged"]
];
const ABSENT: Array<[string, string]> = [
["No settlement of its own", "Every byte held is a pay2seed offer and a paid2seed lease. This document adds the index, the policy and the repair loop, nothing under them."],
["No plaintext at a disk", "With owner encryption a disk holds ciphertext it cannot read and a store holds an index it cannot decrypt."],
["No central registry", "A store is anyone with an index and a hub account. A bucket moves by handing a second store its record and its index."],
["No POSIX", "A mount is a bucket seen as paths. It promises close-to-open by seq and no locks, and no more."],
["No consensus", "One bucket key, one index, one clock. Two stores serving one bucket follow the same feed."]
];
export default function OpenObjectPage(): ReactNode {
return (
<SiteShell active="OpenObject">
<div className="band">
<div className="section-head">
<p className="eyebrow">LogicSRC standards surface</p>
<h2>OpenObject</h2>
<p>
A bucket you can mount: keyed objects, encrypted by their owner, kept on paid disks at a
stated redundancy, verified every period, repaired when a disk fails, and read back by path
from anywhere.
</p>
</div>
<p style={{ color: "#41505d" }}>
<Link href="/openswarm">OpenSwarm</Link> says how one swarm is paid to be held and how a
holder proves it still holds it. <Link href="/opendisk">OpenDisk</Link> says how a disk is
found. What neither says is what an application needs: a bucket with a name, a thousand keys
under it that change, a promise that each object is on three different machines in two
countries, a list by prefix, a version history, and a mount so a process can open a path
without knowing any of the above. OpenObject is that shape written down, so a bucket at one
store is the same bucket at another.
</p>
<p style={{ color: "#5b6b7a" }}>
Status: 0.1. <a href="https://d1sks.com">d1sks.com</a> is the reference store, running every
bucket at three replicas on three operators in two countries by default. Every store is also
a storage offer in the <Link href="/openserver">OpenServer</Link> sense. An{" "}
<Link href="/openslice">OpenSlice</Link> slice mounts a bucket as its disk.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The store descriptor</h2>
<p>
Served at <code style={mono}>/.well-known/openobject.json</code>. Only a name, an API and
one policy are required.
</p>
</div>
<pre style={pre}>{DESCRIPTOR}</pre>
<p style={{ color: "#41505d" }}>
<code style={mono}>policies</code> is what the store will run: <code style={mono}>replicas</code>{" "}
means every holder has the whole object, <code style={mono}>erasure</code> means every holder
has one shard and any k rebuild it. <code style={mono}>min_operators</code> and{" "}
<code style={mono}>min_countries</code> are floors on distinctness. <code style={mono}>disks</code>{" "}
is the pool, as OpenDisk descriptors, so an owner reads it before trusting a promise of three
operators. <code style={mono}>record.lost</code> is how many objects ever went below the read
threshold, and a store that has lost one says so.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The object</h2>
<p>One record per revision, appended to the bucket&apos;s index, an ipdb feed under the bucket key.</p>
</div>
<pre style={pre}>{OBJECT}</pre>
<p style={{ color: "#41505d" }}>
<code style={mono}>key</code> is a path. <code style={mono}>seq</code> is the bucket&apos;s
clock: the higher seq is the newer statement about a key. <code style={mono}>id</code> is
the SHA-256 of the plaintext and the ETag. <code style={mono}>holders</code> are the disks
under lease, one per replica or per shard. <code style={mono}>state</code> is healthy,
degraded, lost or pending, and a read of a degraded object still succeeds.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The loop</h2>
<p>Nothing on the swarm side changes. The store keeps the index and posts the offers.</p>
</div>
<table style={table}>
<tbody>
{LOOP.map(([step, what]) => (
<tr key={step}>
<td style={td}>
<strong>{step}</strong>
</td>
<td style={td}>{what}</td>
</tr>
))}
</tbody>
</table>
<p style={{ color: "#41505d", marginTop: "1rem" }}>
A store may also serve S3, because every tool already speaks it: ETag is the id, versions are
revisions, multipart becomes one swarm. Owner-encrypted buckets are not reachable over S3,
because S3 has nowhere to put the key.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>As an OpenServer offer</h2>
<p>A store is a storage offer; its disks are listed separately as OpenDisk offers.</p>
</div>
<table style={table}>
<thead>
<tr>
<th style={th}>OpenServer</th>
<th style={th}>from OpenObject</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>
</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/openobject">Specification</Link>: the store descriptor, the bucket, the
object, placement, repair, the API, mounting, S3, the OpenServer mapping, c0mpute
</li>
<li>
<a href="https://d1sks.com">d1sks.com</a>: the reference store, three replicas by default
</li>
<li>
<Link href="/opendisk">OpenDisk</Link>: the disks a store places onto;{" "}
<Link href="/openswarm">OpenSwarm</Link>: pay2seed and paid2seed for holding and proof,
ipdb for the index
</li>
<li>
<Link href="/openslice">OpenSlice</Link>: the container that mounts a bucket;{" "}
<Link href="/openserver">OpenServer</Link>: the storage offer a store maps onto
</li>
</ul>
</div>
</SiteShell>
);
}

View file

@ -0,0 +1,227 @@
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: "OpenSlice · LogicSRC",
description:
"OpenSlice is a container whose compute is rented from one market and whose disk is mounted from another: a host serves /.well-known/openslice.json, a slice is one signed file, the state lives in an OpenObject bucket, so the host is interchangeable. Reference marketplace slic3s.com.",
alternates: { canonical: "/openslice" }
};
const DESCRIPTOR = `{
"name": "rig-7b, Helsinki",
"operator": "https://rig-7b.example/.well-known/openprofile.md",
"key": "ed25519:b70c…9c2b",
"hubs": ["https://slic3s.com/api/openswarm", "https://c0mpute.com/api/openswarm"],
"runtime": { "engine": "crun", "oci": "1.1", "rootless": true, "arch": "x86_64", "gpu": "nvidia" },
"capacity": { "vcpu_free": 20, "ram_mb_free": 81920, "scratch_gb_free": 800,
"gpu": [{ "model": "NVIDIA RTX 4090", "count": 1, "vram_mb": 24576, "free": 1 }] },
"price": { "currency": "USD", "per_vcpu_hour": 0.006, "per_gib_ram_hour": 0.002, "per_gpu_hour": 0.35 },
"location": { "countries": ["FI"] },
"network": { "bandwidth_mbps": 1000, "ipv4": 1, "ipv6": true, "ports": "any", "domains": true },
"accepts": { "images": ["ghcr.io", "docker.io", "openobject"], "privileged": false, "mounts": ["openobject"] },
"proof": { "kinds": ["presence", "probe"], "epoch_seconds": 3600 },
"record": { "source": "https://slic3s.com/api/openswarm/openslice/hosts/ed25519:b70c…9c2b", "standing": 96, "evicted": 0 },
"payout": { "payee": "ed25519:b70c…9c2b", "network": "eip155:8453" }
}`;
const SLICE = `{
"type": "openslice.slice",
"id": "ed25519:5e1d…1e6d",
"name": "shop-api",
"image": { "ref": "ghcr.io/ana/shop-api@sha256:1f0e…d9c2" },
"compute": { "vcpu": 2, "ram_mb": 4096, "gpu": null, "scratch_gb": 10 },
"mounts": [
{ "bucket": "ed25519:3a9f…4a6c", "prefix": "shop/", "path": "/data", "mode": "rw", "cache_gb": 4 }
],
"env": [{ "name": "DATABASE_URL", "vault": "opencreds://ana.example/shop/database-url" }],
"ports": [{ "container": 8080, "protocol": "tcp", "public": true, "domain": "api.shop.example" }],
"health": { "http": "/healthz", "every_seconds": 30 },
"placement": { "countries": ["FI", "DE", "NL"], "near": "ed25519:3a9f…4a6c", "min_standing": 80 },
"lifetime": { "hours": 720, "renew": true, "restart": "always" },
"price_cap": { "currency": "USD", "per_hour": 0.05 }
}`;
const RUN: Array<[string, string]> = [
["1. Read", "The host descriptor for accepts, capacity and price, and record.source at the hub for standing."],
["2. Reserve", "An openslice.reservation at one of the host's hubs: the spec, hours, an hourly price, the budget escrowed."],
["3. Take", "The host takes it on its next poll or when the hub pushes, and answers with an address per public port."],
["4. Start", "Pull by digest, resolve env from the vault, attach the mounts inside the slice's namespace, apply cgroup limits, run."],
["5. Prove", "One signed presence record per epoch, a probe of health from outside; a proven epoch is paid, a missed one is not."],
["6. Move", "Stop here, reserve there under the same id; the mounts reattach at the index's current seq. Nothing on the old host is needed."]
];
const MAPPING: Array<[string, string]> = [
["offers[].kind", "cloud, model p2p for a peer"],
["offers[].compute", "{ vcpu: vcpu_free, ram_mb: ram_mb_free, arch }"],
["offers[].gpu", "capacity.gpu[0] as an OpenGPU block, count its free"],
["offers[].price", "{ amount: per_vcpu_hour, currency, interval: hour, unit: vcpu }"],
["offers[].stock", "in_stock while threads and memory are free and slices_running is below slices_max"]
];
const ABSENT: Array<[string, string]> = [
["No orchestration", "One slice is one container on one host. No pods, no services, no autoscaling. Two slices find each other by domain."],
["No confidential compute", "A host can read what the container reads. What is promised is the other direction: nothing on the host is needed to get the slice back."],
["No persistent local disk", "Scratch is gone on a move. State that must survive is in a mount."],
["No network between slices", "Each slice has its own address on its own host. A private network across hosts is a different specification."],
["No settlement of its own", "The reservation is a lease, the epoch is a period, the presence record is a proof, payout is ippay."]
];
export default function OpenSlicePage(): ReactNode {
return (
<SiteShell active="OpenSlice">
<div className="band">
<div className="section-head">
<p className="eyebrow">LogicSRC standards surface</p>
<h2>OpenSlice</h2>
<p>
A container whose compute is rented from one market and whose disk is mounted from
another, so the host is interchangeable: stop the slice here, start it there, the mount
reattaches.
</p>
</div>
<p style={{ color: "#41505d" }}>
A <a href="https://c0mpute.com">c0mpute</a> job ends; a service does not. A web app, a game
server, an agent that listens for messages need a share of a machine for a while, not a job
done. OpenSlice is that share written down: a host puts its free threads, memory, GPU, price,
runtime and policy at <code style={mono}>/.well-known/openslice.json</code>, an owner writes
one signed file that says image, resources, mounts, ports and lifetime, and a reservation at
a hub matches them for a number of hours with proofs every epoch. The durable state is an{" "}
<Link href="/openobject">OpenObject</Link> bucket kept at three replicas elsewhere, which is
what makes a peer&apos;s machine tolerable to run on.
</p>
<p style={{ color: "#5b6b7a" }}>
Status: 0.1. <a href="https://slic3s.com">slic3s.com</a> is the reference marketplace: every
host descriptor it has read, standing from the hubs each names, and a launcher that takes a
slice spec. Compute from c0mpute.com, disk from d1sks.com, the pair from slic3s.com. The name
is shared with ETSI&apos;s OpenSlice, an operations system for 5G network slicing; this
document is about containers.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The host descriptor</h2>
<p>
Served at <code style={mono}>/.well-known/openslice.json</code>. Only a name, free threads,
free memory and the two hourly prices are required.
</p>
</div>
<pre style={pre}>{DESCRIPTOR}</pre>
<p style={{ color: "#41505d" }}>
<code style={mono}>capacity</code> is in <Link href="/docs/opencpu">OpenCPU</Link>,{" "}
<Link href="/docs/openmemory">OpenMemory</Link> and <Link href="/docs/opengpu">OpenGPU</Link>{" "}
units, and <code style={mono}>*_free</code> is what a new slice can have now.{" "}
<code style={mono}>runtime</code> is what runs the container. <code style={mono}>accepts</code>{" "}
is policy stated up front. <code style={mono}>record.evicted</code> counts slices the host
stopped before the owner did, and a marketplace ranks on the hub&apos;s number, not the
file&apos;s.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>The slice</h2>
<p>One signed file. The id is the slice key and it keeps it across hosts, which is what makes a move a move.</p>
</div>
<pre style={pre}>{SLICE}</pre>
<p style={{ color: "#41505d" }}>
<code style={mono}>image</code> is by digest, from a registry or from a bucket, so it
outlives the registry. <code style={mono}>mounts</code> are OpenObject buckets seen as
directories, the content key granted to the slice, not the host.{" "}
<code style={mono}>env</code> resolves secrets from an <Link href="/opencreds">OpenCreds</Link>{" "}
vault at start. <code style={mono}>placement.near</code> names a bucket so the marketplace
prefers hosts on the same network as its holders.
</p>
</div>
<div className="band">
<div className="section-head">
<h2>Running one</h2>
<p>The disk protocols were written first. A reservation is a lease, an epoch is a period, a presence record is a proof.</p>
</div>
<table style={table}>
<tbody>
{RUN.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 host 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 OpenSlice</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>
</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/openslice">Specification</Link>: the host descriptor, the slice, running
one, the reservation, the marketplace, the OpenServer mapping, c0mpute
</li>
<li>
<a href="https://slic3s.com">slic3s.com</a>: the reference marketplace
</li>
<li>
<Link href="/openobject">OpenObject</Link>: the bucket a slice mounts;{" "}
<Link href="/opendisk">OpenDisk</Link>: the same shape for a disk
</li>
<li>
<Link href="/openswarm">OpenSwarm</Link>: the reservation&apos;s shape and the payee;{" "}
<Link href="/openserver">OpenServer</Link>: the hosting offer a host maps onto
</li>
</ul>
</div>
</SiteShell>
);
}

View file

@ -88,6 +88,8 @@ export const FAMILIES: Family[] = [
s("opengpu", "OpenGPU", "The gpu block: the card by vendor name, count, VRAM, interconnect, access", { parent: "openserver" }),
s("openbandwidth", "OpenBandwidth", "The network block: port, meter, overage, IPv4 and IPv6 as a priced resource", { parent: "openserver" }),
s("openfile", "OpenFile", "One file a publisher serves about the files it has published: hash, swarm and HTTP routes", { parent: "openserver" }),
s("openobject", "OpenObject", "A bucket you can mount: keyed objects encrypted by their owner, kept on paid disks at a stated redundancy, verified, repaired and read back by path", { parent: "openserver" }),
s("openslice", "OpenSlice", "A container whose compute is rented from one market and whose disk is mounted from another: the host descriptor, the slice file and the reservation between them", { parent: "openserver" }),
s("openmcp", "OpenMCP", "An open catalog of MCP relays: a relay serves /.well-known/openmcp.json and a catalog probes it"),
s("opencoupon", "OpenCoupon", "One file a merchant serves about what is on offer right now, expired codes kept so directories learn they died"),
s("opensaas", "OpenSaaS", "One file a subscription service serves about the way in and the way out of every plan, for a person and for an agent"),