co/core is a place where people share the compute they already own to run AI for each other, instead of renting from a handful of giant providers
TypeScript
52
477 commits
updated Sep 18, 2026
Compute, but shared. A small, federated compute co-op built on the AT Protocol — where the spare cycles under your desk can answer someone else's inference job, every bit of work leaves a signed receipt you own, and the books are open to anyone who wants to check them.
This is an experiment, run in the open. The network is small enough today that the founders know most of the people on it. If that sounds like the kind of thing you'd want to poke at, you're exactly who this is for.
New here? Start with the two posts that explain the why: Hello, world (what we're building) and How the cocore economy is shaped (how the co-op settles up). Then come back.
cocore has three kinds of participants, and only the third one is "ours":
The first two are owned entirely by the people who run them. Job records live on requester PDSes; receipts live on provider PDSes; your identity is a DID you can carry anywhere AT Protocol is spoken. Nothing in this repo holds authoritative state about who did what work for whom.
Most "decentralized compute" networks distribute the machines but keep the ledger in one company's database. Ask that one service who did what, for whom, at what price — and you trust its uptime, its operator, and its willingness to keep talking to you. The compute is spread out; the record is not.
cocore moves the record onto the protocol. Every completed job emits a
signed receipt — an AT Protocol record under a public lexicon
(dev.cocore.compute.*) written to the provider's own repo. A receipt
commits to:
Hand someone a receipt, the lexicon, and the provider's DID document and they can verify it offline — no API call, no permission, no privileged operator in the loop. Because the lexicon is public, anyone can run an AppView that indexes receipts across providers for discovery, billing, or auditing. None of those AppViews is canonical. The canonical record is the signed entry sitting in the provider's PDS.
Requester (DID) Provider (DID)
│ 1. publish a job │
│ (dev.cocore.compute.job) │
│ ───────────────────────────────▶│
│ 2. run the work
│ on attested hardware
│ 3. signed receipt │
│ (dev.cocore.compute.receipt) │
│ ◀───────────────────────────────│
│ │
└──────────────┬──────────────────┘
│
anyone can index the firehose
and run an AppView — or a whole
other exchange — off these receipts
Settlement runs on tokens: one model token in or out costs one token from your balance, full stop. There's no exchange rate to anything outside the system and no secondary market — the token buys compute, and that's the only value we try to assert. It's a mutual-credit unit in the tradition of Sardex and the 1934 WIR cooperative bank.
The mechanics are deliberately few:
proBono: true with a zero price and zero token
counts, so a balance-less requester can still be served unlimited. It's
purely additive — a requester the policy doesn't cover is still served as a
normal paid job, so opting in never costs the machine paid work.Every parameter lives on a public dev.cocore.compute.exchangePolicy
record, so you — or a competing exchange — can replicate the math without
asking us. The full rationale, and what we deliberately left out, is in
the economy post.
As a requester: sign in at console.cocore.dev with your Bluesky handle. You'll land with a million tokens and can run a job right away.
As a provider: turn an Apple Silicon Mac into a node. The friendly path is the menu-bar app (it pairs, downloads a model, and starts serving); the headless path is one line:
curl -fsSL https://console.cocore.dev/agent | sh
Either way the agent pairs to your identity, attests the machine, loads a
local model, and starts publishing receipts as it earns. See
docs/install-mac.md for the details.
An application can connect its users' co/core accounts in one click — publish a
dev.cocore.app.registration record on your app's account, serve a well-known
file on your domain, and use the device-pairing XRPC. Users approve
"Connect Your App to co/core" and come straight back. See
docs/connect-with-cocore.md.
The completions API and the in-app chat take optional routing controls beyond just the model:
country (ISO 3166-1 alpha-2, e.g. US) to route
only to providers advertising that coarse region. A machine opts into
publishing its country from its per-machine settings on the website (the
agent then geolocates the machine's IP and refreshes it each time it serves);
it's an advisory, self-asserted hint — a VPN moves it — so requests fail
closed (no_providers_for_country) rather than silently routing elsewhere.POST /v1/probono/chat/completions, or the toggle in chat) routes only to
providers that have elected to serve you for free. A provider configures this
per machine on the website: off, free for anyone, or free for an explicit
list of people (friends-only). Pro-bono jobs are unmetered and take no
exchange cut, so a balance-less requester can still be served.min_provider_version (e.g. 0.9.32) to route
only to providers running that tray release or newer — useful for pinning a
feature that landed in a specific version. Each machine reports its
binaryVersion when it registers with the matchmaker; only versions at or
above your floor are eligible (one reporting no version is excluded). A
multimodal request (images/tool messages) already derives this floor on its
own; an explicit pin and the automatic floor combine to whichever is higher.
Requests fail closed (no_providers_for_version) when none qualify./v1/verified/... and /v1/private/... are the
existing trust- and friend-constrained paths.Full reference: the OpenAPI spec at
packages/console/public/openapi.yaml
(also rendered at console.cocore.dev/docs) and the lexicon notes in
lexicons/README.md.
The agent spawns vllm-mlx for each
model you pick, and that is still the zero-config default. If a different
server runs your hardware better — mei on an
M1, mlx_lm.server, llama-server — run it yourself and attach it:
# ~/.cocore/engine-map (or COCORE_ENGINE_MAP="model=url,...")
mlx-community/Qwen3.6-35B-A3B-4bit = http://127.0.0.1:8024
The agent proves the server answers, runs the same tool-calling canary it runs
on vllm-mlx plus a structured-output canary, advertises only what passed, and
proxies jobs to it. A model in the map is never also spawned under vllm-mlx,
and a machine whose every model is attached needs no Python at all. Attached
engines are best-effort tier, exactly like the vllm-mlx child. Details, the
admission gate that goes with it, and the mei recipe:
docs/attached-engine.md.
The lexicon is the source of truth. Everything else exists to make it useful — and if code ever disagrees with a lexicon, the lexicon wins.
lexicons/dev/cocore/ the schemas — the spec for receipts, jobs, attestations,
settlements, and the exchange policy
provider/ the Rust agent: runs inference, attests, signs receipts
provider-shell/ the macOS menu-bar app that pairs + supervises the agent
packages/
sdk/ TypeScript SDK: lexicon types, canonical JSON, and the
verification helpers shared across appview/exchange/console
appview/ indexer + read-only API over the lexicon
console/ the requester web app + device pairing (console.cocore.dev)
exchange/ settlement / token-ledger orchestration
infra/
advisor/ the WebSocket matchmaker the agent's `serve` connects to
services/ bridge + AppView API + exchange for local/single-host dev
docs/ install, deploy, and the ADRs behind the big decisions
Lexicon NSIDs live under dev.cocore.*: compute.{provider,job,attestation, receipt,settlement} for the work itself, compute.exchangePolicy for the
published rules, and account.{tokenGrant,tokenPatronage} for the auditable
co-op trail. The account.{create,list,revoke,delete}ApiKey methods expose
API-key lifecycle over XRPC so you can automate access (docs/api-keys.md).
Lexicons only ever change additively — existing fields never change
meaning; new behavior is a new optional field or a new NSID.
You'll want Rust (provider), Node + pnpm (the TypeScript workspaces), and —
if you're touching the Mac app — Swift. The repo uses mise to pin tool
versions and a Makefile that wraps the common loops:
pnpm install # TypeScript workspaces (packages/* and infra/*)
make build # build provider, appview, console, exchange, shell
make test # lexicon validation + all suites
make stack-up # bring up the local dev stack
cargo test --manifest-path provider/Cargo.toml # just the agent
The order of operations when you extend the system is always the same:
lexicon first. Sketch the change against the invariants below; if it
violates one, write an ADR (docs/adr/) explaining why the invariant
should change. Then land the lexicon, regenerate types, and update the
provider, the AppView, and the SDKs — in that order, so the thing that
writes records can do so before anything assumes they exist. (More in
CLAUDE.md, which doubles as a guide for human and AI
contributors alike.)
The "no central exchange" claim is enforced in code, not just asserted:
packages/appview/src/indexer/federation.test.ts,
…/replay.test.ts, …/integration/firehose.test.ts.)If a change would let two correctly-implemented operators disagree about a canonical record, that change is a bug — the design kind, not the typo kind.
Early, live, and a little held together with tape in places — on purpose. There's one exchange running today at cocore.dev, under one DID, with a policy anyone can read. The agent runs on Apple Silicon. The identity layer is founder-vouched: a verified Bluesky handle gets you in, which is plenty for a network this size. Expect rough edges and the occasional breaking change while the lexicon settles.
Almost nothing here is novel; it's mostly solved problems borrowed from adjacent ones and kept honest in translation. The mutual-credit unit comes from Sardex and WIR. The patronage rebate comes from the Rochdale tradition by way of REI and rural electric co-ops. The "signed, portable artifact of work" pattern was sharpened by the open-source work at darkbloom.dev. The federate-don't-coordinate posture is just the AT Protocol's own lesson about what happens when one service ends up owning everyone's canonical state. And the original framing — Airbnb for compute, a cloud co-op — came from a Silicon Florist post that named cocore in the first place.
This is a cooperative, so the most useful thing you can do is participate — run a node, dispatch a job, read the receipts, and tell us where it breaks. And there's one kind of bug we especially want to hear about: a place where the design isn't honest — where the numbers don't add up, the published policy doesn't match what the code does, or some piece of state is hiding on our side that shouldn't be. That's the only kind we don't think we can engineer our way out of alone.
Open an issue, or find us on Bluesky at @cocore.dev.
TypeScript
68.9%
Rust
18.2%
Swift
6.5%
Python
3.0%
Shell
2.5%
co/core is a place where people share the compute they already own to run AI for each other, instead of renting from a handful of giant providers
TypeScript
52
477 commits
updated Sep 18, 2026
Compute, but shared. A small, federated compute co-op built on the AT Protocol — where the spare cycles under your desk can answer someone else's inference job, every bit of work leaves a signed receipt you own, and the books are open to anyone who wants to check them.
This is an experiment, run in the open. The network is small enough today that the founders know most of the people on it. If that sounds like the kind of thing you'd want to poke at, you're exactly who this is for.
New here? Start with the two posts that explain the why: Hello, world (what we're building) and How the cocore economy is shaped (how the co-op settles up). Then come back.
cocore has three kinds of participants, and only the third one is "ours":
The first two are owned entirely by the people who run them. Job records live on requester PDSes; receipts live on provider PDSes; your identity is a DID you can carry anywhere AT Protocol is spoken. Nothing in this repo holds authoritative state about who did what work for whom.
Most "decentralized compute" networks distribute the machines but keep the ledger in one company's database. Ask that one service who did what, for whom, at what price — and you trust its uptime, its operator, and its willingness to keep talking to you. The compute is spread out; the record is not.
cocore moves the record onto the protocol. Every completed job emits a
signed receipt — an AT Protocol record under a public lexicon
(dev.cocore.compute.*) written to the provider's own repo. A receipt
commits to:
Hand someone a receipt, the lexicon, and the provider's DID document and they can verify it offline — no API call, no permission, no privileged operator in the loop. Because the lexicon is public, anyone can run an AppView that indexes receipts across providers for discovery, billing, or auditing. None of those AppViews is canonical. The canonical record is the signed entry sitting in the provider's PDS.
Requester (DID) Provider (DID)
│ 1. publish a job │
│ (dev.cocore.compute.job) │
│ ───────────────────────────────▶│
│ 2. run the work
│ on attested hardware
│ 3. signed receipt │
│ (dev.cocore.compute.receipt) │
│ ◀───────────────────────────────│
│ │
└──────────────┬──────────────────┘
│
anyone can index the firehose
and run an AppView — or a whole
other exchange — off these receipts
Settlement runs on tokens: one model token in or out costs one token from your balance, full stop. There's no exchange rate to anything outside the system and no secondary market — the token buys compute, and that's the only value we try to assert. It's a mutual-credit unit in the tradition of Sardex and the 1934 WIR cooperative bank.
The mechanics are deliberately few:
proBono: true with a zero price and zero token
counts, so a balance-less requester can still be served unlimited. It's
purely additive — a requester the policy doesn't cover is still served as a
normal paid job, so opting in never costs the machine paid work.Every parameter lives on a public dev.cocore.compute.exchangePolicy
record, so you — or a competing exchange — can replicate the math without
asking us. The full rationale, and what we deliberately left out, is in
the economy post.
As a requester: sign in at console.cocore.dev with your Bluesky handle. You'll land with a million tokens and can run a job right away.
As a provider: turn an Apple Silicon Mac into a node. The friendly path is the menu-bar app (it pairs, downloads a model, and starts serving); the headless path is one line:
curl -fsSL https://console.cocore.dev/agent | sh
Either way the agent pairs to your identity, attests the machine, loads a
local model, and starts publishing receipts as it earns. See
docs/install-mac.md for the details.
An application can connect its users' co/core accounts in one click — publish a
dev.cocore.app.registration record on your app's account, serve a well-known
file on your domain, and use the device-pairing XRPC. Users approve
"Connect Your App to co/core" and come straight back. See
docs/connect-with-cocore.md.
The completions API and the in-app chat take optional routing controls beyond just the model:
country (ISO 3166-1 alpha-2, e.g. US) to route
only to providers advertising that coarse region. A machine opts into
publishing its country from its per-machine settings on the website (the
agent then geolocates the machine's IP and refreshes it each time it serves);
it's an advisory, self-asserted hint — a VPN moves it — so requests fail
closed (no_providers_for_country) rather than silently routing elsewhere.POST /v1/probono/chat/completions, or the toggle in chat) routes only to
providers that have elected to serve you for free. A provider configures this
per machine on the website: off, free for anyone, or free for an explicit
list of people (friends-only). Pro-bono jobs are unmetered and take no
exchange cut, so a balance-less requester can still be served.min_provider_version (e.g. 0.9.32) to route
only to providers running that tray release or newer — useful for pinning a
feature that landed in a specific version. Each machine reports its
binaryVersion when it registers with the matchmaker; only versions at or
above your floor are eligible (one reporting no version is excluded). A
multimodal request (images/tool messages) already derives this floor on its
own; an explicit pin and the automatic floor combine to whichever is higher.
Requests fail closed (no_providers_for_version) when none qualify./v1/verified/... and /v1/private/... are the
existing trust- and friend-constrained paths.Full reference: the OpenAPI spec at
packages/console/public/openapi.yaml
(also rendered at console.cocore.dev/docs) and the lexicon notes in
lexicons/README.md.
The agent spawns vllm-mlx for each
model you pick, and that is still the zero-config default. If a different
server runs your hardware better — mei on an
M1, mlx_lm.server, llama-server — run it yourself and attach it:
# ~/.cocore/engine-map (or COCORE_ENGINE_MAP="model=url,...")
mlx-community/Qwen3.6-35B-A3B-4bit = http://127.0.0.1:8024
The agent proves the server answers, runs the same tool-calling canary it runs
on vllm-mlx plus a structured-output canary, advertises only what passed, and
proxies jobs to it. A model in the map is never also spawned under vllm-mlx,
and a machine whose every model is attached needs no Python at all. Attached
engines are best-effort tier, exactly like the vllm-mlx child. Details, the
admission gate that goes with it, and the mei recipe:
docs/attached-engine.md.
The lexicon is the source of truth. Everything else exists to make it useful — and if code ever disagrees with a lexicon, the lexicon wins.
lexicons/dev/cocore/ the schemas — the spec for receipts, jobs, attestations,
settlements, and the exchange policy
provider/ the Rust agent: runs inference, attests, signs receipts
provider-shell/ the macOS menu-bar app that pairs + supervises the agent
packages/
sdk/ TypeScript SDK: lexicon types, canonical JSON, and the
verification helpers shared across appview/exchange/console
appview/ indexer + read-only API over the lexicon
console/ the requester web app + device pairing (console.cocore.dev)
exchange/ settlement / token-ledger orchestration
infra/
advisor/ the WebSocket matchmaker the agent's `serve` connects to
services/ bridge + AppView API + exchange for local/single-host dev
docs/ install, deploy, and the ADRs behind the big decisions
Lexicon NSIDs live under dev.cocore.*: compute.{provider,job,attestation, receipt,settlement} for the work itself, compute.exchangePolicy for the
published rules, and account.{tokenGrant,tokenPatronage} for the auditable
co-op trail. The account.{create,list,revoke,delete}ApiKey methods expose
API-key lifecycle over XRPC so you can automate access (docs/api-keys.md).
Lexicons only ever change additively — existing fields never change
meaning; new behavior is a new optional field or a new NSID.
You'll want Rust (provider), Node + pnpm (the TypeScript workspaces), and —
if you're touching the Mac app — Swift. The repo uses mise to pin tool
versions and a Makefile that wraps the common loops:
pnpm install # TypeScript workspaces (packages/* and infra/*)
make build # build provider, appview, console, exchange, shell
make test # lexicon validation + all suites
make stack-up # bring up the local dev stack
cargo test --manifest-path provider/Cargo.toml # just the agent
The order of operations when you extend the system is always the same:
lexicon first. Sketch the change against the invariants below; if it
violates one, write an ADR (docs/adr/) explaining why the invariant
should change. Then land the lexicon, regenerate types, and update the
provider, the AppView, and the SDKs — in that order, so the thing that
writes records can do so before anything assumes they exist. (More in
CLAUDE.md, which doubles as a guide for human and AI
contributors alike.)
The "no central exchange" claim is enforced in code, not just asserted:
packages/appview/src/indexer/federation.test.ts,
…/replay.test.ts, …/integration/firehose.test.ts.)If a change would let two correctly-implemented operators disagree about a canonical record, that change is a bug — the design kind, not the typo kind.
Early, live, and a little held together with tape in places — on purpose. There's one exchange running today at cocore.dev, under one DID, with a policy anyone can read. The agent runs on Apple Silicon. The identity layer is founder-vouched: a verified Bluesky handle gets you in, which is plenty for a network this size. Expect rough edges and the occasional breaking change while the lexicon settles.
Almost nothing here is novel; it's mostly solved problems borrowed from adjacent ones and kept honest in translation. The mutual-credit unit comes from Sardex and WIR. The patronage rebate comes from the Rochdale tradition by way of REI and rural electric co-ops. The "signed, portable artifact of work" pattern was sharpened by the open-source work at darkbloom.dev. The federate-don't-coordinate posture is just the AT Protocol's own lesson about what happens when one service ends up owning everyone's canonical state. And the original framing — Airbnb for compute, a cloud co-op — came from a Silicon Florist post that named cocore in the first place.
This is a cooperative, so the most useful thing you can do is participate — run a node, dispatch a job, read the receipts, and tell us where it breaks. And there's one kind of bug we especially want to hear about: a place where the design isn't honest — where the numbers don't add up, the published policy doesn't match what the code does, or some piece of state is hiding on our side that shouldn't be. That's the only kind we don't think we can engineer our way out of alone.
Open an issue, or find us on Bluesky at @cocore.dev.
TypeScript
68.9%
Rust
18.2%
Swift
6.5%
Python
3.0%
Shell
2.5%