Bitcoin Schema

Registry

On-chain package registry for skills, agents, themes, and components

Schemas for publishing and discovering registry items on-chain. Registry items are multi-file packages inscribed as ordinals with ord-fs/json manifests, making them natively servable by ORDFS and installable via the shadcn CLI protocol.

Registry Item

A registry item is a multi-output ordinal inscription where individual files are 1-sat inscription outputs and a manifest ordinal ties them together with metadata.

Transaction Structure

Output 0:  file inscription (1 sat) — SKILL.md content
Output 1:  file inscription (1 sat) — example.md
...
Output N:  manifest inscription (1 sat, tracked ordinal)
           Content-Type: ord-fs/json
           Content: { "SKILL.md": "_0", "example.md": "_1" }
           MAP: { app, type, name, version, language, ... }
           AIP: author signature

Each file output is a standard ordinal inscription with a P2PKH prefix (spendable). The manifest output is the package's on-chain identity — it goes in the ordinals basket and is the outpoint used to reference the package.

Manifest Format (ord-fs/json)

The manifest is an inscription with content type ord-fs/json. Its content is a JSON object mapping filenames to sibling output references using relative vout notation:

{
  "SKILL.md": "_0",
  "example.md": "_1"
}

The _N values are relative vout references — the underscore-vout suffix from the standard outpoint format (txid_vout), without the txid. ORDFS resolves _N to {manifest_txid}_{N} using the directory inscription's own txid. Requesting /content/{manifestOutpoint}/SKILL.md returns the file content via directory traversal.

For nested directories (e.g., refs/api.md), create a separate ord-fs/json inscription for the subdirectory and reference it from the root manifest. ORDFS traverses nested directories by following the chain of ord-fs/json inscriptions.

MAP Metadata

Registry items carry MAP metadata on the manifest inscription following the standard MAP SET protocol:

MAP SET app <registry> type <registryType> name <name> version <version> ...
FieldRequiredDescription
appYesRegistry identifier (e.g. clawnet)
typeYesRegistry type with registry: prefix (see types below)
nameYesPackage name (lowercase, hyphenated, 1-64 chars)
versionYesSemantic version (e.g. 1.0.0)
descriptionYesHuman-readable description of the package
languageNoBCP 47 language tag (e.g. en, zh, ja, es, ko). Indicates the primary language of the package content. Defaults to en if omitted.
titleNoHuman-readable display title (e.g. "Bitcoin Avatar")
authorNoAuthor name or identifier
dependenciesNoJSON-serialized array of npm package dependencies
devDependenciesNoJSON-serialized array of dev dependencies
registryDependenciesNoJSON-serialized array of other registry items this depends on
categoriesNoJSON-serialized array of category tags
homepageNoURL to the package's homepage or repository
prevNoPrevious manifest outpoint for version chaining
opns.nameNoOpNS name if the publisher owns it (trust signal)
opns.outpointNoOutpoint of the OpNS name ordinal

AIP Signature

The manifest is signed using AIP (Author Identity Protocol) to prove authorship:

AIP BITCOIN_ECDSA <signerAddress> <signature>

The signature covers the MAP protocol data, enabling any indexer to verify the publisher's identity without trusting a central registry.

Registry Types

All types use the registry: prefix for consistency across the shadcn ecosystem and ClawNet extensions.

shadcn/ui Standard Types

TypeDescription
registry:libUtility libraries
registry:blockMulti-component page sections (hero, pricing table)
registry:componentReusable UI components
registry:uiBase UI primitives
registry:hookReact hooks
registry:pageFull page templates
registry:fileGeneric file (not categorized)
registry:fontIndividual font file with metadata (family, weights, subsets)
registry:styleCSS variables and rules — color schemes, typography presets, spacing
registry:themeComplete visual theme — style + bundled assets (fonts, patterns, wallpapers)
registry:exampleExample/demo code
registry:internalInternal implementation files

ClawNet Extension Types

TypeDescription
registry:skillAI agent skills (SKILL.md + reference files)
registry:agentAI agent definitions (frontmatter + system prompt)
registry:appFull web applications published on-chain (APP.md + assets)
registry:organizationAgent organizations (agent roster + skills)

registry:app

A full web application published on-chain via APP.md manifest. Interoperable with the metanet-apps package — apps broadcast to the tm_apps overlay topic are discoverable by any wallet.

APP.md frontmatter:

---
name: my-app
description: What the app does
domain: myapp.com
icon: https://myapp.com/icon.png
version: 1.0.0
httpURL: https://myapp.com
category: DeFi
tags: [trading, tokens]
banner_image_url: https://myapp.com/banner.png
screenshot_urls: [https://myapp.com/s1.png]
---

Required fields: name, description, domain, icon, version

MAP metadata:

MAP SET app clawnet type registry:app name my-app version 1.0.0 description "..." domain myapp.com icon https://...

Overlay discovery: App tokens can be broadcast to the tm_apps overlay topic using the PushDrop protocol ([1, 'metanet apps']). The APP.md frontmatter maps directly to the PublishedAppMetadata interface, enabling cross-wallet app catalog discovery.

Publishing an app on-chain:

import { buildPackageOutputs } from "@1sat/templates";

const files = [
  { path: "APP.md", content: appMdContent, contentType: "text/markdown" },
  { path: "icon.png", content: iconBytes, contentType: "image/png" },
];

const metadata = {
  app: "clawnet",
  type: "registry:app",
  name: "my-app",
  version: "1.0.0",
  description: "My web application",
  domain: "myapp.com",
  icon: "https://myapp.com/icon.png",
};

const { outputs, manifestVout } = await buildPackageOutputs(
  files, metadata, signingKey
);
// outputs — ready for createAction()
// manifestVout — index of the manifest output

Any registry service can index registry:app inscriptions by querying for transactions matching MAP SET type registry:app. The overlay topic tm_apps provides an additional discovery channel for wallets and app catalogs.

Design Asset Types

Design assets form a composability stack: individual fonts are installable standalone, styles compose fonts into typography systems, and themes bundle everything into a complete visual package.

registry:font

An individual font file with metadata describing its typographic properties. The manifest wraps a single font file (.woff2, .woff, .ttf) with structured metadata.

Transaction structure:

Output 0:  font file inscription (font/woff2, 1 sat)
Output 1:  manifest (ord-fs/json, 1 sat, MAP + AIP)
           { "space-grotesk.woff2": "_0" }

Additional MAP fields for fonts:

FieldRequiredDescription
font.familyYesCSS font-family name (e.g. Space Grotesk Variable)
font.variableYesCSS custom property name (e.g. --font-space-grotesk)
font.weightNoJSON array of available weights (e.g. ["400","500","700"])
font.subsetsNoJSON array of character subsets (e.g. ["latin","cyrillic"])
font.styleNoFont style — normal or italic (default: normal)
licenseNoLicense identifier (e.g. OFL-1.1, CC0, MIT)

Example MAP:

MAP SET app theme-token type registry:font name space-grotesk
    version 1.0.0 description "Space Grotesk variable weight sans-serif"
    font.family "Space Grotesk Variable" font.variable "--font-space-grotesk"
    font.weight ["400","500","600","700"] font.subsets ["latin","latin-ext"]
    license OFL-1.1 categories ["sans-serif","variable","geometric"]

registry:style

CSS variables and rules without bundled asset files. Styles are composable — they reference fonts and other styles via registryDependencies rather than bundling them.

Use cases:

  • Color schemes — OKLCH color variables for light/dark modes
  • Typography presets — font variable mappings + typographic scale (h1-h6 sizing, line-height, letter-spacing)
  • Spacing/radius presets — design token variables

Typography style example:

A typography preset maps semantic CSS variables (--font-heading, --font-body, --font-mono) to specific fonts and defines a typographic scale. It declares the fonts as registryDependencies — the installer resolves the dependency chain.

MAP SET app theme-token type registry:style name editorial
    version 1.0.0 description "High-contrast editorial typography"
    registryDependencies ["playfair-display","dm-sans","jetbrains-mono"]
    categories ["serif","editorial","contrast"]

Transaction structure:

Output 0:  style.json (application/json, 1 sat) — the CSS configuration
Output 1:  manifest (ord-fs/json, 1 sat, MAP + AIP)
           { "style.json": "_0" }

File content (style.json at output 0):

{
  "cssVars": {
    "theme": {
      "--font-heading": "var(--font-playfair-display)",
      "--font-body": "var(--font-dm-sans)",
      "--font-mono": "var(--font-jetbrains-mono)"
    }
  },
  "css": {
    "@layer base": {
      "h1": { "font-family": "var(--font-heading)", "font-size": "2.25rem", "line-height": "1.2", "letter-spacing": "-0.02em" },
      "h2": { "font-family": "var(--font-heading)", "font-size": "1.875rem", "line-height": "1.3" },
      "body, p": { "font-family": "var(--font-body)", "line-height": "1.65" },
      "code, pre": { "font-family": "var(--font-mono)" }
    }
  }
}

Color style example:

{
  "cssVars": {
    "light": {
      "--background": "oklch(0.98 0.01 240)",
      "--foreground": "oklch(0.15 0.02 240)",
      "--primary": "oklch(0.55 0.25 260)"
    },
    "dark": {
      "--background": "oklch(0.15 0.02 240)",
      "--foreground": "oklch(0.95 0.01 240)",
      "--primary": "oklch(0.65 0.25 260)"
    }
  }
}

Styles that reference no font files have no registryDependencies and are self-contained — just CSS variables inscribed as JSON.

registry:theme

A complete visual package that bundles styles with actual asset files (fonts, patterns, wallpapers). The manifest is a pure ord-fs/json directory — only string→string file mappings. Style configuration lives in a separate theme.json file that the manifest points to.

Transaction structure (theme with bundled font and pattern):

Output 0:  font file (font/woff2, 1 sat)
Output 1:  pattern file (image/svg+xml, 1 sat)
Output 2:  theme.json (application/json, 1 sat) — style definition
Output 3:  manifest (ord-fs/json, 1 sat, MAP + AIP) — pure directory
           { "font.woff2": "_0", "pattern.svg": "_1", "theme.json": "_2" }

Manifest content (pure directory — no inline config):

{
  "font.woff2": "_0",
  "pattern.svg": "_1",
  "theme.json": "_2"
}

theme.json content (at output 2):

{
  "cssVars": {
    "light": { "--background": "oklch(0.98 0.01 240)", "--foreground": "oklch(0.15 0.02 240)" },
    "dark": { "--background": "oklch(0.15 0.02 240)", "--foreground": "oklch(0.95 0.01 240)" },
    "theme": {
      "--font-heading": "var(--font-space-grotesk)",
      "--font-body": "var(--font-space-grotesk)",
      "--radius": "0.5rem"
    }
  }
}

The manifest is always a pure ord-fs/json directory — ORDFS needs clean string→string mappings to traverse. Style configuration, CSS variables, and any structured data live in separate files (like theme.json) that the manifest points to.

The key distinction between types: a registry:theme bundles its assets as sibling inscription outputs (assets travel with the theme). A registry:style references assets externally via registryDependencies (enables reuse across themes). Both are valid approaches.

Cross-Registry Publishing

The registry package format is designed for cross-registry interoperability. Components from any shadcn-compatible registry can be published on-chain:

Source RegistryTypeExample
BigBlocksregistry:block, registry:uiBitcoin wallet components, social feeds
FontTrioregistry:font, registry:styleFont packages, curated typography presets
theme-tokenregistry:theme, registry:styleVisual themes with bundled fonts/patterns
ClawNetregistry:skill, registry:agentAI agent skills and configurations

All registries share the same registry:* type system, _N relative vout references, and ord-fs/json manifest format. A component published on-chain is installable via any compatible gateway:

bunx shadcn@latest add https://clawnet.sh/r/blocks/bitcoin-avatar
bunx shadcn@latest add https://bigblocks.dev/r/bitcoin-avatar.json
bunx shadcn@latest add https://themetoken.dev/r/themes/{origin}

All serve the same shadcn-compatible JSON — from on-chain data or registry servers.

Language Support

The language field uses BCP 47 language tags to declare the primary language of a package's content. This enables:

  • Filtering: Registries can filter and sort by language
  • Discovery: Users find packages in their preferred language
  • Indexing: Search engines and AI systems can index content appropriately

Common values:

TagLanguage
enEnglish
zhChinese
jaJapanese
koKorean
esSpanish
frFrench
deGerman
ptPortuguese
ruRussian
arArabic

Packages without a language field are assumed to be English (en).

Installation Protocols

Registry items support multiple installation paths:

By OpNS Name

When the publisher owns the OpNS name matching their package slug:

npx clawnet add humanize

The CLI resolves the OpNS name on-chain, finds the bound identity key, looks up the latest manifest outpoint, and installs from ORDFS.

By Outpoint

Direct installation from a manifest outpoint:

npx clawnet add {txid}_{vout}

By shadcn CLI

Registry items are compatible with the shadcn CLI protocol:

bunx shadcn@latest add https://clawnet.sh/r/skills/humanize
bunx shadcn@latest add https://clawnet.sh/r/themes/{origin}
bunx shadcn@latest add https://clawnet.sh/r/components/{origin}

The gateway at /r/{type}/{origin} fetches the manifest from ORDFS, hydrates file content from sibling inscriptions, and returns shadcn-compatible JSON.

Version Chaining

Packages form a version chain via the prev MAP field. Each new version references the previous manifest outpoint:

v1.0.0  →  manifest_outpoint_a
v1.1.0  →  manifest_outpoint_b  (prev: manifest_outpoint_a)
v2.0.0  →  manifest_outpoint_c  (prev: manifest_outpoint_b)

This creates a verifiable on-chain history without requiring a central version database.

Registry Discovery

Registries declare themselves on-chain via MAP metadata with app as the registry identifier. Any indexer can discover and aggregate registry items by querying for transactions with:

MAP SET app <registry> type registry:*

This enables a decentralized ecosystem where multiple registries can coexist and cross-reference items.

JavaScript Examples

Skill Package

// buildPackageOutputs from the ClawNet CLI package system
import { buildPackageOutputs } from "clawnet/package/package-tx";

const result = await buildPackageOutputs(
  [
    { path: "SKILL.md", content: skillBytes, contentType: "text/markdown" },
    { path: "refs/api.md", content: apiBytes, contentType: "text/markdown" },
  ],
  {
    app: "clawnet",
    type: "registry:skill",
    name: "humanize",
    version: "1.0.0",
    description: "Rewrites AI-generated text to sound natural",
    author: "Satchmo",
    categories: JSON.stringify(["writing", "style"]),
  },
  privateKey
);
// result.outputs — ready for createAction()
// result.manifestVout — index of the manifest output

Font Package

const result = await buildPackageOutputs(
  [
    { path: "space-grotesk.woff2", content: fontBytes, contentType: "font/woff2" },
  ],
  {
    app: "theme-token",
    type: "registry:font",
    name: "space-grotesk",
    version: "1.0.0",
    description: "Space Grotesk variable weight sans-serif",
    "font.family": "Space Grotesk Variable",
    "font.variable": "--font-space-grotesk",
    "font.weight": JSON.stringify(["400", "500", "600", "700"]),
    "font.subsets": JSON.stringify(["latin", "latin-ext"]),
    categories: JSON.stringify(["sans-serif", "variable", "geometric"]),
  },
  privateKey
);

Theme with Bundled Assets

const result = await buildPackageOutputs(
  [
    { path: "font.woff2", content: fontBytes, contentType: "font/woff2" },
    { path: "pattern.svg", content: patternBytes, contentType: "image/svg+xml" },
    { path: "theme.json", content: themeJsonBytes, contentType: "application/json" },
  ],
  {
    app: "theme-token",
    type: "registry:theme",
    name: "midnight-editorial",
    version: "1.0.0",
    description: "Dark editorial theme with serif headings and geometric patterns",
    categories: JSON.stringify(["dark", "editorial", "serif"]),
  },
  privateKey
);

Low-Level (without @1sat/actions)

import { Inscription, MAP, AIP, PrivateKeySigner, P2PKH } from "@1sat/templates";
import { PrivateKey, Utils } from "@bsv/sdk";

const p2pkh = new P2PKH().lock(privateKey.toAddress());

// File inscription outputs
const files = [
  { path: "SKILL.md", content: skillMarkdown, contentType: "text/markdown" },
  { path: "example.md", content: exampleDocs, contentType: "text/markdown" },
];

const outputs = files.map(f => {
  const inscription = Inscription.create(
    new Uint8Array(Utils.toArray(f.content, "utf8")),
    f.contentType,
    { scriptPrefix: p2pkh }
  );
  return { script: inscription.lock(), satoshis: 1 };
});

// ord-fs/json manifest
const manifest = {};
files.forEach((f, i) => { manifest[f.path] = `_${i}`; });

const mapFields = {
  app: "clawnet",
  type: "registry:skill",
  name: "humanize",
  version: "1.0.0",
  description: "Rewrites AI-generated text to sound natural",
};

const manifestInscription = Inscription.create(
  new Uint8Array(Utils.toArray(JSON.stringify(manifest), "utf8")),
  "ord-fs/json",
  { scriptPrefix: p2pkh, scriptSuffix: buildMapAipSuffix(mapFields, privateKey) }
);
outputs.push({ script: manifestInscription.lock(), satoshis: 1 });

On this page