Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"name": "molecule-desci-marketplace",
"description": "Local marketplace for the molecule-desci plugin: DeSci orchestration skills + the molecule MCP server.",
"owner": {
"name": "Vladimir Demidov",
"name": "molecule-desci",
"email": "vladimir@molecule.to"
},
"plugins": [
{
"name": "molecule-desci",
"source": "./",
"description": "DeSci molecule orchestration (aura-orchestrator skill: public or private/encrypted data-room uploads) backed by the molecule MCP server. V2 GraphQL surface, keyed on ipnftUid.",
"version": "0.2.0"
"description": "DeSci molecule orchestration (aura-orchestrator skill: On-Chain Lab creation + public or private/encrypted data-room uploads) backed by the molecule MCP server. OCL/V3 GraphQL surface, keyed on oclId.",
"version": "0.4.0"
}
]
}
8 changes: 4 additions & 4 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "molecule-desci",
"description": "DeSci molecule orchestration for Molecule Labs in one skill (aura-orchestrator): POI registration + IP-NFT minting + project creation + x402-paid data-room file upload (public or client-side-encrypted) + announcement + transfer, backed by the `molecule` MCP server (Privy agentic wallet, full x402 payment flow, AES-256-GCM envelope crypto, ABI encoding, on-chain access conditions). V2 GraphQL surface, keyed on ipnftUid.",
"version": "0.2.0",
"description": "DeSci molecule orchestration for Molecule Labs in one skill (aura-orchestrator): resolve-or-create an On-Chain Lab (LabNFT + token-bound account) + register it (createLab) + x402-paid data-room file upload (public or client-side-encrypted) + announcement + role-grant/hand-off, backed by the `molecule` MCP server (Privy agentic wallet, full x402 payment flow, AES-256-GCM envelope crypto, ABI encoding, on-chain access conditions). OCL/V3 GraphQL surface, keyed on oclId.",
"version": "0.4.0",
"author": {
"name": "Vladimir Demidov",
"name": "molecule-desci",
"email": "vladimir@molecule.to"
},
"keywords": ["desci", "molecule", "x402", "ip-nft", "mcp", "privy", "encryption"],
"keywords": ["desci", "molecule", "x402", "ocl", "on-chain-labs", "mcp", "privy", "encryption"],
"mcpServers": "./.mcp.json"
}
4 changes: 2 additions & 2 deletions .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "molecule-desci",
"version": "0.2.0",
"description": "DeSci molecule orchestration for Molecule Labs in one skill (aura-orchestrator): POI registration + IP-NFT minting + project creation + x402-paid data-room file upload (public or client-side-encrypted) + announcement + transfer, backed by the `molecule` MCP server. V2 GraphQL surface, keyed on ipnftUid.",
"version": "0.4.0",
"description": "DeSci molecule orchestration for Molecule Labs in one skill (aura-orchestrator): resolve-or-create an On-Chain Lab (LabNFT + token-bound account) + register it (createLab) + x402-paid data-room file upload (public or client-side-encrypted) + announcement + role-grant/hand-off, backed by the `molecule` MCP server. OCL/V3 GraphQL surface, keyed on oclId.",
"skills": "./skills/",
"mcpServers": "./.mcp.json"
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ __pycache__/
*.log
.DS_Store
uv.lock
skills/privy-agentic-wallets-skill/
119 changes: 60 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# molecule-desci — cross-harness plugin

Packages the DeSci orchestration skill (+ a wallet helper) and the `molecule` MCP server into one
Packages the DeSci orchestration skill and the `molecule` MCP server into one
installable plugin that works under **Claude Code** and **OpenAI Codex** (and any MCP host, via the
server alone).

- **`aura-orchestrator`** — the whole molecule in one skill: POI registration → IP-NFT minting → project
creation → data-room file upload → announcement → transfer. V2 surface, keyed on `ipnftUid`. The file
upload (Phase 4) is the only branch: choose **public** (plaintext) or **private** (client-side
AES-256-GCM envelope-encrypted, access-controlled) — **x402 pays per call either way**.
- **`privy-agentic-wallets`** — helper for creating/managing the Privy server wallet (with a policy) that
signs payments and on-chain transactions. Run once if `PRIVY_WALLET_ID` is unset.
- **`molecule` MCP server** (`mcp/server.py`, Python/FastMCP, stdio) — Privy wallet ops, POI, Labs
GraphQL, the full x402 payment flow, S3 upload, AES-256-GCM envelope crypto, ABI encoding, on-chain
access conditions (`isAuthorizedSignerForIpnft`).
- **`aura-orchestrator`** — the whole molecule in one skill: resolve-or-create an **On-Chain Lab** (mint a
LabNFT + token-bound account, or reuse one the wallet admins) → register it (`createLab`) → data-room
file upload → announcement → role-grant/hand-off. OCL/V3 surface, keyed on `oclId`. The file upload
(Phase 3) is the only branch: choose **public** (plaintext) or **private** (client-side AES-256-GCM
envelope-encrypted, access-controlled) — **x402 pays per call either way**.
- **Privy wallet ops** — creating/managing the Privy server wallet (with a policy) that signs payments and
on-chain transactions is handled directly by the `molecule` MCP server's `privy_*` tools (see
aura-orchestrator Phase 0). For the official standalone Privy skill, see
[privy-io/privy-agentic-wallets-skill](https://github.com/privy-io/privy-agentic-wallets-skill).
- **`molecule` MCP server** (`mcp/server.py`, Python/FastMCP, stdio) — Privy wallet ops, on-chain OCL reads
(`ocl_read` / `ocl_tx_identity`), Labs GraphQL, the full x402 payment flow, S3 upload, AES-256-GCM
envelope crypto, ABI encoding, on-chain access conditions (`hasRole(oclId,…)` OR `isAuthorizedSignerForTba`).

> **The MCP server is the portable core** — both harnesses speak MCP. Skills (`SKILL.md`) are a shared
> standard both now read. Only the *plugin manifest* differs per harness, so this package ships both
Expand All @@ -23,13 +26,12 @@ molecule-plugin/
├── .claude-plugin/{plugin.json, marketplace.json} # Claude Code
├── .codex-plugin/plugin.json # Codex
├── .mcp.json # shared MCP server config (uv run)
├── skills/{aura-orchestrator,privy-agentic-wallets}/SKILL.md
├── skills/aura-orchestrator/SKILL.md
└── mcp/{server.py,pyproject.toml,requirements.txt,README.md,smoke.py}
```

This plugin directory is the **single source of truth** — it is the only version-controlled copy, so
edit the skills (`skills/<name>/SKILL.md`) and the MCP server (`mcp/`) here directly. (Older unversioned
copies under `molecule_core/skills/` are no longer synced and may be stale — ignore them.)
This plugin directory is the **single source of truth** for the `aura-orchestrator` skill and the MCP
server — edit `skills/aura-orchestrator/SKILL.md` and `mcp/` here directly.

---

Expand All @@ -44,10 +46,9 @@ The MCP server runs via **`uv run mcp/server.py`**, which reads the PEP 723 inli

The server reads all config/secrets from the environment (never from tool args). Provide them however
your harness injects env into MCP subprocesses. Non-secrets: `MOLECULE_CLIENT_URL`, `MOLECULE_LABS_URL`,
`X402_GATEWAY_URL`, `ACCESS_RESOLVER_ADDRESS`, `IPNFT_CONTRACT_ADDRESS`, `CHAIN_ID`, `ENVIRONMENT`,
`EVM_WALLET_ADDRESS`, `EXPERIMENT_COST_CENTS`, `IPNFT_UID`. Secrets: `PRIVY_APP_ID`, `PRIVY_APP_SECRET`,
`PRIVY_WALLET_ID`, `POI_API_KEY`, `MOLECULE_API_KEY`, `MOLECULE_SERVICE_TOKEN`. See `mcp/README.md` for
the per-tool breakdown.
`X402_GATEWAY_URL`, `ACCESS_RESOLVER_ADDRESS`, `ONCHAIN_LAB_FACTORY_ADDRESS`, `LABNFT_ADDRESS`, `CHAIN_ID`,
`EVM_WALLET_ADDRESS`, `EVM_RPC_URL`. Secrets: `PRIVY_APP_ID`, `PRIVY_APP_SECRET`, `PRIVY_WALLET_ID`,
`MOLECULE_API_KEY`, `MOLECULE_SERVICE_TOKEN`. See `mcp/README.md` for the per-tool breakdown.

---

Expand All @@ -70,35 +71,35 @@ The MCP server (`molecule`) loads automatically from `.mcp.json` using `${CLAUDE

Codex reads `SKILL.md` skills and supports plugins, but its plugin/skills paths are version-dependent —
verify with `codex --version` and `/skills`. The reliable, version-independent route is to register the
MCP server directly and point Codex at the skills:
MCP server directly and point Codex at the skill:

**Register the MCP server** (`~/.codex/config.toml`):
```toml
[mcp_servers.molecule]
command = "uv"
args = ["run", "/Users/vladimirdemidov/development/molecule/molecule/molecule_core/molecule-plugin/mcp/server.py"]
args = ["run", "/molecule-plugin/mcp/server.py"]

[mcp_servers.molecule.env]
MOLECULE_LABS_URL = "https://migration.graphql.api.molecule.xyz/graphql"
MOLECULE_LABS_URL = "https:///graphql"
X402_GATEWAY_URL = "https://…"
CHAIN_ID = "84532"
ENVIRONMENT = "migration"
EVM_WALLET_ADDRESS = "0x…"
ACCESS_RESOLVER_ADDRESS = "0x…"
ONCHAIN_LAB_FACTORY_ADDRESS = "0x…"
LABNFT_ADDRESS = "0x…"
# secrets:
PRIVY_APP_ID = "…"
PRIVY_APP_SECRET = "…"
PRIVY_WALLET_ID = "…"
POI_API_KEY = "…"
MOLECULE_API_KEY = "…"
MOLECULE_SERVICE_TOKEN = "…"
```
or, equivalently: `codex mcp add molecule --env CHAIN_ID=84532 --env … -- uv run /abs/path/to/molecule-plugin/mcp/server.py`

**Skills:** if your Codex version supports a plugin marketplace, it can also read
`.claude-plugin/marketplace.json` (interop). Otherwise copy `skills/<name>/SKILL.md` into the skills
directory your Codex version scans (`.agents/skills/` or `.codex/skills/` — check `/skills`), or surface
the runbook through `AGENTS.md`.
`.claude-plugin/marketplace.json` (interop). Otherwise copy `skills/aura-orchestrator/SKILL.md` into the
skills directory your Codex version scans (`.agents/skills/` or `.codex/skills/` — check `/skills`), or
surface the runbook through `AGENTS.md`.

---

Expand All @@ -110,71 +111,71 @@ cd mcp && uv run smoke.py # lists tools + exercises compute tools (no net

---

## Which skill, in what order
## Setup & run order

This workflow is **sequential — order matters**. Each skill's `SKILL.md` documents its own internal step
order; this is the cross-skill map.
This workflow is **sequential — order matters**. `aura-orchestrator`'s `SKILL.md` documents the internal
phase order; below is the one-time setup that precedes it.

### Step 0 — One-time setup (do once, before any skill)
### Step 0 — One-time setup (do once, before running the skill)

1. **Env + MCP.** Install `uv`, register the plugin (Claude) or MCP server (Codex), and set the env vars
above. Pick the surface with `MOLECULE_LABS_URL` / `X402_GATEWAY_URL` / `CHAIN_ID` / `ENVIRONMENT`.
2. **Wallet** → run **`privy-agentic-wallets`** *only if* `PRIVY_WALLET_ID` is unset. It creates a Privy
server wallet **with a policy** (single-chain + per-tx value cap); set the returned `PRIVY_WALLET_ID`.
Then **fund** that wallet: USDC on Base (x402 pays per call) + native gas on the mint chain.
2. **Wallet** → if `PRIVY_WALLET_ID` is unset, **aura-orchestrator Phase 0** creates a Privy server wallet
**with a policy** (single-chain + per-tx value cap) via the MCP `privy_*` tools; set the returned
`PRIVY_WALLET_ID`. Then **fund** that wallet: USDC on Base (x402 pays per call) + native gas on the mint chain.
3. **Service token** (private uploads only) → ensure `MOLECULE_SERVICE_TOKEN` is set, or issue one with the
MCP `issue_service_token` tool. This is an **off-chain JWT** (issued by `generateServiceToken` after a
wallet signature — *not* an on-chain mint). The Phase 4 **private** variant uses it for the direct DEK
calls (`labs_generate_dek` / `labs_decrypt_dek`). Not needed for public uploads.

### Step 1 — Run `aura-orchestrator`, choosing the upload visibility

There is **one** workflow — `aura-orchestrator` — and it covers everything end-to-end (POI → mint
project → upload → announce → transfer). The only choice is the **Phase 4 upload visibility**:
There is **one** workflow — `aura-orchestrator` — and it covers everything end-to-end (resolve/create lab
createLab → upload → announce → grant/transfer). The only choice is the **Phase 3 upload visibility**:

| Upload visibility | What Phase 4 does | Needs |
| Upload visibility | What Phase 3 does | Needs |
|-------------------|-------------------|-------|
| **Public** (default) | Plaintext file, `accessLevel: PUBLIC`, Steps A–C | funded wallet; a research PDF |
| **Private** (encrypted) | Client-side AES-256-GCM envelope encryption, non-PUBLIC `accessLevel` + on-chain access conditions, Steps E0–E6 | funded wallet + `MOLECULE_SERVICE_TOKEN`; a research PDF |

> **x402 pays per call for both** — `initiateCreateOrUpdateFileV2` / `finishCreateOrUpdateFileV2` are
> billed regardless of visibility. Everything outside Phase 4 (POI, mint, project, announcement, transfer)
> is identical for both. The private variant additionally needs a service token (for the direct, unpaid
> DEK generate/decrypt calls that keep the plaintext key inside the MCP).
> **x402 pays per call for both** — `initiateCreateOrUpdateFile` / `finishCreateOrUpdateFile` are billed
> regardless of visibility. Everything outside Phase 3 (lab resolve/create, createLab, announcement,
> grant/transfer) is identical for both. The private variant additionally needs a service token (for the
> direct, unpaid DEK generate/decrypt calls that keep the plaintext key inside the MCP).

### `aura-orchestrator` — phase order (do not reorder or skip)

```
Phase 1 POI registration → reservationId (= IP-NFT tokenId)
Phase 2 IP-NFT mint (sign terms → mint)
Phase 3 createProject → ipnftUid [wait ~90s after mint]
Phase 4 Upload file to data room PUBLIC (Steps A–C) OR encrypted (E0–E6) [wait ~90s after project]
Phase 5 createAnnouncementV2 (attach the datasetId from Phase 4)
Phase 6 Transfer IP-NFT + addProjectOwner (optional co-owner)
Phase 0 Wallet setup (Privy agentic wallet)
Phase 1 Resolve-or-create OCL lab → oclId, labAccountAddress, labNftTokenId (reuse via labs(walletAddress), else mint LabNFT)
Phase 2 createLab (x402) → registers the lab for oclId (poll labs(walletAddress) for indexer)
Phase 3 Upload file to data room PUBLIC (Steps A–C) OR encrypted (E0–E6)
Phase 4 createAnnouncement (x402) (attach the datasetId from Phase 3)
Phase 5 grantRole / LabNFT hand-off (optional co-owner)
```
Every phase consumes the previous phase's output (`reservationId` → `ipnftUid` → `datasetId`). The two
**90-second waits** are real: on-chain ownership and data-room provisioning are async.
Every phase consumes the previous phase's output (`oclId` + `labAccountAddress` → `datasetId`).

### `aura-orchestrator` Phase 4 — private (encrypted) variant (strict E0 → E6)
### `aura-orchestrator` Phase 3 — private (encrypted) variant (strict E0 → E6)

Run these **instead of** Phase 4 Steps A–C when the upload visibility is **private**:
Run these **instead of** Phase 3 Steps A–C when the upload visibility is **private**:

```
E0 labs_generate_dek (direct) → encryptedDek, dekHandle [no payment]
E1 encrypt_file → iv, contentHash, cipherBytes
E2 x402_pay initiateCreateOrUpdateFileV2 → uploadToken, uploadUrl [PAID]
E2 x402_pay initiateCreateOrUpdateFile → uploadToken, uploadUrl [PAID]
E3 s3_upload (the .enc ciphertext) [no payment]
E4 build_access_conditions (ipnft-signer, reservationId = tokenId) → json
E5 x402_pay finishCreateOrUpdateFileV2 (+ encryptionMetadata) [PAID]
E6 labs_decrypt_dek (ipnftUid+filePath) → decrypt_file → verify SHA-256 [optional, no payment]
E4 build_access_conditions (oclId + labAccountAddress) → json (hasRole OR isAuthorizedSignerForTba)
E5 x402_pay finishCreateOrUpdateFile (+ encryptionMetadata) [PAID]
E6 labs_decrypt_dek (oclId+filePath) → decrypt_file → verify SHA-256 [optional, no payment]
```
`contentLength` in E2 is the **ciphertext** size (`cipherBytes` from E1). The plaintext DEK never leaves
the MCP — only the opaque `dekHandle` is passed between E0→E1 and E6.

## ⚠️ Running cost

`aura-orchestrator` Phases 3–6 perform **paid x402 mutations — real USDC on Base per call** — and
on-chain transactions (mint/transfer). They need a funded Privy wallet and a valid service token / API
key (the **private** upload variant also needs `MOLECULE_SERVICE_TOKEN`). For a no-spend smoke, use
only the compute/direct tools (`encrypt_file`/`decrypt_file`, `build_access_conditions`, `sha256_file`;
`labs_generate_dek` needs only a service token, no payment).
`aura-orchestrator` Phases 2–5 perform **paid x402 mutations — real USDC on Base per call** — and
on-chain transactions (LabNFT mint / grantRole / transfer, plus the mint fee). They need a funded Privy
wallet and a valid service token / API key (the **private** upload variant also needs
`MOLECULE_SERVICE_TOKEN`). For a no-spend smoke, use only the compute/read tools (`encrypt_file`/
`decrypt_file`, `build_access_conditions`, `sha256_file`, `ocl_read`; `labs_generate_dek` needs only a
service token, no payment).
Loading