@artblocks/abx-cli 0.1.0-alpha.15 → 0.1.0-alpha.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/skill/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: abx-self-host
3
3
  description: Launch and operate a self-hosted ABX NFT end to end with the ABX CLI (`abx`) on testnet — a 1/1 (`abx deploy`), a multi-token Series from a folder of media (`abx deploy-series`), or a generative/code drop (`abx deploy-code`). Covers on-chain vs off-chain metadata, storage custody (local disk, S3/R2, IPFS, Arweave), deploy + mint (now or pre-warmed at a predicted address), rendered thumbnails and on-chain traits for code art, primary sales via the shared fixed-price minter, and owner ops (transfer, refresh, re-point URIs, royalties, lock fields, pause/unpause, supply cap, delegate minting). Use when the user wants to self-host an ABX project, take an image to an NFT on testnet, deploy a collection from a folder of images, launch generative/code art, mint or run a primary sale, refresh a listing, operate a project they launched, choose a storage backend, stand up hosting they own, or point a project at a hosted/managed metadata provider with an API key.
4
4
  compatibility: Drives the abx CLI (@artblocks/abx-cli). Co-versioned with it — install/refresh with `abx skill install` so this skill matches the CLI's `abx version`. Requires Node 22.5+.
5
5
  metadata:
6
- version: "0.1.0-alpha.15"
6
+ version: "0.1.0-alpha.16"
7
7
  ---
8
8
 
9
9
  # ABX Self-Host Toolkit (`abx`)
@@ -180,7 +180,10 @@ A **program is the content** (`abx deploy-code` → a `SeriesCode`): output is a
180
180
  | Script + a library on-chain (e.g. `p5@1.0.0`, **Sepolia only** — needs the AB dependency registry, absent on Base Sepolia) | `--script f.js --onchain-uri --dep p5@1.0.0` | **fully on-chain** — *iff the dep report says “ON-CHAIN bytes available”* |
181
181
  | Script + a CDN-only library, or very large params | `--script f.js --public-base-url https://…` | **resolver lane** — you host a resolver; live metadata |
182
182
  | A pre-built app (webpack/vite output) | `--code-dir build/` (+ `--onchain-uri` or `--public-base-url`) | **no server to run**, gateway-served → **never** chain-complete (8KB param budget) |
183
- | A **Solidity renderer** (SVG on-chain, from seed+params) | `--image-renderer 0x<svg> [--attributes-renderer 0x<traits>] --onchain-uri` (**no `--script`**) | **truly in-chain** — image + traits computed on-chain, tokenURI on-chain, **zero infra** |
183
+ | A **Solidity renderer** (SVG on-chain, from seed+params) | `--image-renderer 0x<svg> [--attributes-renderer 0x<traits>] --onchain-uri` (no `--script`) | **truly in-chain** — image + traits computed on-chain, tokenURI on-chain, **zero infra**; no `animation_url` (no program) |
184
+ | **A JS program AND on-chain thumbnail/traits** — the both-worlds shape | `--script f.js --image-renderer 0x<svg> --attributes-renderer 0x<traits> --onchain-uri` | **every surface in-chain, zero infra** — `animation_url` assembles from the script chunks, `image`+`attributes` computed by Solidity. **Nothing to render or host.** |
185
+
186
+ **`--script` and `--image-renderer` are NOT an either-or.** Passing both is the strongest shape available and the most-missed one: the program keeps driving `animation_url` on-chain while the Solidity renderers supply `image` and `attributes`, so an interactive generative piece gets a real marketplace thumbnail and real traits with **no resolver, no runner, no bucket**. Reach for it whenever the creator can supply (or fork) a Solidity renderer. The dry run's `Surfaces` block confirms each surface before gas is spent.
184
187
 
185
188
  **⭐ In-chain Solidity lane — recommend on-chain `tokenURI` without hesitation.** The artwork is a Solidity `IAbxFieldRenderer` returning an SVG from seed+params (not a JS program), wired `--image-renderer 0x… [--attributes-renderer 0x…] --onchain-uri` with **no `--script`/`--code-dir`**: image AND traits computed on-chain, `tokenURI` assembled on-chain — **genuinely nothing to run** (a small SVG, so the large-`tokenURI` caveat doesn't apply). **NOT no-code, though**: the renderer is a contract the creator compiles + deploys with Foundry. **`abx scaffold-renderer <dir>`** writes a ready-to-build project (worked renderer + coherent traits + the interfaces with invariants + never-revert tests + deploy script); they `forge test`, deploy, and hand the address to `--image-renderer 0x…` (which verifies code-at-address, never compiles/deploys Solidity). Not comfortable with Solidity? Steer to the resolver or (tiny static SVG) `--onchain-image`. Depth → [reference/code-projects.md](reference/code-projects.md#in-chain-solidity-svg--the-zero-dependency-lane) · interface/invariants → https://abx.docs.artblocks.io/protocol/renderers/.
186
189
 
@@ -184,7 +184,8 @@ abx deploy-code --image-renderer 0x<svgRenderer> [--attributes-renderer 0x<trait
184
184
  --onchain-uri --schema palette:HexColor:TokenOwner --name "…" --symbol … [--dep none]
185
185
  ```
186
186
 
187
- - **No `--script`/`--code-dir`.** `deploy-code` allows a renderer-only project (neither program mode) as long as `--image-renderer` (and/or `--attributes-renderer`) is set. There is no `animation_url` — the SVG `image` *is* the artwork; the metadata renderer omits an unset animation field, and the CLI does **not** wire the generator (wiring an animation leg at a zero generator would revert every `tokenURI`).
187
+ - **No `--script`/`--code-dir` is ALLOWED, not required.** `deploy-code` accepts a renderer-only project (neither program mode) as long as `--image-renderer` (and/or `--attributes-renderer`) is set. Renderer-only has no `animation_url` — the SVG `image` *is* the artwork; the metadata renderer omits an unset animation field, and the CLI does **not** wire the generator (wiring an animation leg at a zero generator would revert every `tokenURI`).
188
+ - **But a script AND renderers together is the both-worlds shape — verified, and the most-missed option.** `--script f.js --image-renderer 0x… --attributes-renderer 0x… --onchain-uri` gives `animation_url` assembled on-chain from the script chunks *and* `image`/`attributes` computed by Solidity: every marketplace surface has an on-chain home, and there is **nothing to render, host, or refresh** (no runner, no bucket, no resolver). The fields are independent in the metadata renderer, so they compose. Prefer this over renderer-only whenever the piece is actually a program.
188
189
  - **On-chain `tokenURI` is the CLEAR default here** — unlike the JS/p5 lanes. A Solidity SVG reads *small* (a few hundred bytes–few KB), so the large-`tokenURI` marketplace-read caveat does not apply. Recommend it enthusiastically; there is no maneuverability/infra tradeoff to weigh because there is no infra.
189
190
  - **The renderer is a contract the creator deploys separately** (the CLI doesn't compile Solidity). **`abx scaffold-renderer <dir>`** writes a ready-to-build Foundry project — a worked `MyRenderer.sol` (image → `image/svg+xml` from `seed` + a `palette` PostParam), a coherent `MyTraits.sol` reading the SAME seed math, the `IAbxFieldRenderer`/`IAbxParams` interfaces (with the invariants documented), a `forge test` proving `render()` never reverts (incl. the collection surface + a fuzz), a `Deploy.s.sol`, and a README. The creator forks the art, then `forge soldeer install && forge test`, deploys with forge, and passes the address to `deploy-code --image-renderer 0x…`, which **verifies the address has code** (real deploy refuses a codeless address; dry-run probes best-effort) — same guard as `--attributes-renderer`. A renderer reads the token's seed/params directly (`IAbxParams(token).tokenParam(tokenId, "seed"|"palette")`), computes bytes, and returns `(contentType, data)`. Interface + invariants also at https://abx.docs.artblocks.io/protocol/renderers/.
190
191
  - **PostParams still apply — and you MUST declare them; the CLI can't.** Unlike the JS lane (where `abx inspect` statically detects the params a script reads), a Solidity renderer is opaque to the CLI — it cannot know your renderer reads a `palette`. **Read the renderer, and declare every PostParam it reads with `--schema key:Type:Auth`** (the example reads `palette` → `--schema palette:HexColor:TokenOwner`). Skip it and the param is **fixed at the renderer's default forever** — collectors can't set it (the exact miss from a real session: a palette-tinted renderer shipped with `schemas []`, stuck on the default). With the schema declared, a collector's `configure-param` re-addresses the on-chain image automatically (the renderer reads the live param — no re-render, there's no off-chain still). `deploy-code --dry-run` nudges when renderers are set with no `--schema`.
@@ -199,7 +200,7 @@ The renderer is the creator's own Solidity (compiled + deployed with forge — t
199
200
  - **Correct content-type + shape.** `image` → `image/svg+xml` (or another image MIME) returning a valid document; `attributes` → `application/json` whose bytes are a JSON **array** `[{"trait_type":…,"value":…},…]` (numbers unquoted, strings escaped). A wrong type or malformed array is a broken/blank marketplace field.
200
201
  - **Guard the field, wire the right one.** Revert `UnsupportedField` for a field it doesn't serve (a wiring mistake fails loud), and make sure `--image-renderer`/`--attributes-renderer` point at the renderer that actually serves that field.
201
202
  - **`view` + deterministic.** Same chain state → same bytes. No unseeded randomness; read block/oracle state only if you *intend* live data (it re-reads per view).
202
- - **Read params LIVE via `IAbxParams(token)`** (`tokenParam`/`contractParam`, token scope wins; `tokenParamKeys`/`contractParamKeys` if the renderer must handle keys it wasn't written to name) — so a collector's `configure-param` shows up on the next read with no redeploy. Never bake a param value in at deploy.
203
+ - **Read params LIVE via `IAbxParams(token)`** (`tokenParam`/`contractParam`, token scope wins; `tokenParamKeys`/`contractParamKeys` if the renderer must handle keys it wasn't written to name). **`Bytes`/`String` params need the OTHER reader:** their `bytes32` is a keccak commitment (`valueIsHash == true`) and the content comes from `tokenParamData(tokenId, key)` / `contractParamData(key)` (~24KB per key the two types that can carry an actual payload). Reading a `Bytes` param through `tokenParam` hands the renderer a hash and draws garbage with nothing failing anywhere; empty returned bytes are the "use a default" signal — so a collector's `configure-param` shows up on the next read with no redeploy. Never bake a param value in at deploy.
203
204
  - **Keep the output bounded.** It assembles into `tokenURI` per call; a very large SVG/HTML can strain the `eth_call` gas on unauthenticated public reads.
204
205
 
205
206
  Fork `contracts/src/renderers/examples/{SeedSvgRenderer,SeedTraitsRenderer}.sol` — they satisfy every invariant above (graceful fallbacks, the sentinel, content-types, live param reads) and are the reference to review a fork against.
@@ -232,7 +233,7 @@ abx deploy-code (--script <file> | --code-dir <dir>) --name "…" --symbol … \
232
233
  - **`--code-dir <dir>`** — directory mode: a build folder (must contain `index.html` **and its own `abx.js` copy** — the build must read `abx.tokenData` + call `abx.traits({…})`, see [Authoring the program](#authoring-the-program--the-abxjs-runtime-contract-get-this-right-first)) uploaded via `putDirectory` (ipfs/arweave); its root becomes the on-chain `code` field. The live view 302s to the gateway with `?abx=<canonical tokenData>` — **so the gateway must serve HTML** (dedicated Pinata gateway or Arweave, never the shared public one).
233
234
  - **`--description "…"` / `--external-url <url>`** — collection identity, written as **on-chain collection fields in the deploy tx** (a code project has no operator-metadata table of its own, so these ride on-chain; the metadata renderer stitches them into `tokenURI` under `--onchain-uri`, a resolver reads the same fields). Set them or the metadata is bare. (Any other unsupported flag warns "unrecognized flag, ignored" — a typo can't quietly drop a value.)
234
235
  - **Seeds** — drawn at mint from the canonical `AbxSeedSource` (settled once assigned; `--no-seed` opts out; curated pre-set seeds win).
235
- - **`--schema key:Type:Auth`** — governed PostParams (e.g. `palette:HexColor:TokenOwner`). Reconfigure any lane with `abx configure-param <addr> <tokenId> <key> <value>` — it reads the on-chain schema and canonically encodes the input (`#rrggbb`, decimals, Select by label; `String`/`Bytes` via `--file`); delegate.xyz honored on the TokenOwner leg. A param change **re-addresses** renders (self-invalidating stills). **The re-render is automatic wherever the resolver's chain watcher is on (the default):** the watcher sees the change on its next poll (~12s) — no matter WHO sent it or WITH WHAT tool — re-indexes, and notifies the runner. `abx configure-param … --remote <resolver>` remains an **immediate nudge** (skips the poll wait) and the fallback for a watcher-disabled resolver. Expect thumbnail refresh ≈ poll cadence + render time (~15–30s), not instant.
236
+ - **`--schema key:Type:Auth`** — governed PostParams (e.g. `palette:HexColor:TokenOwner`). Reconfigure any lane with `abx configure-param <addr> <tokenId> <key> <value>` — it reads the on-chain schema and canonically encodes the input (`#rrggbb`, decimals, Select by label). **Payload types are explicit: `String` takes literal text, `Bytes` takes `0x`-prefixed hex or `--file <path>` — a bare string on a `Bytes` key is REFUSED**, because storing those characters as bytes can't be told apart from meaning them literally; delegate.xyz honored on the TokenOwner leg. A param change **re-addresses** renders (self-invalidating stills). **The re-render is automatic wherever the resolver's chain watcher is on (the default):** the watcher sees the change on its next poll (~12s) — no matter WHO sent it or WITH WHAT tool — re-indexes, and notifies the runner. `abx configure-param … --remote <resolver>` remains an **immediate nudge** (skips the poll wait) and the fallback for a watcher-disabled resolver. Expect thumbnail refresh ≈ poll cadence + render time (~15–30s), not instant.
236
237
  - **How it resolves (live, uncached; not on-chain):** the resolver rebuilds `tokenData` per view. Directory mode 302-redirects to the gateway with params in the **query string** (so **very large PostParams favor template mode**, which inlines them with no URL ceiling); template mode assembles the HTML inline from the chunks.
237
238
  - **Lanes**: all three. `--unsigned` needs `--for <signer>` and prints the whole pre-computed sequence (deterministic deploy → the clone address is known up front). On a chain with no canonical factory, all deploy commands **stop with guidance**; deploying your OWN trust anchor is an explicit `--bootstrap-factory` opt-in (private chains/sandboxes only).
238
239
 
@@ -28,6 +28,8 @@ After launch the owner operates the project. Each command builds a tx, signs it
28
28
 
29
29
  **`lock-field` / `lock-uri` are permanent — always confirm with the human first.**
30
30
 
31
+ **Welding a PARAM is a different verb.** Fields and [PostParams](code-projects.md#postparams) are separate namespaces that can share a name, and `lock-field` freezes the *field*. To make a param's value permanent, lock its schema: `abx set-schema <addr> --schema <key>:<Type>:<Auth>:lock=now` — after which every `configure-param` on that key reverts. (`lock-field` refuses a declared param key rather than letting you lock the wrong thing.)
32
+
31
33
  ### Authorship + rights (credit + license)
32
34
 
33
35
  The reserved **collection** keys are `artist`, `display_notes`, `artist_links`, `license` (a rights *identifier* like `CC0-1.0` / `CC-BY-NC-4.0`). Two ways to set them, both writing on-chain inline collection fields: