DEV Community

Cover image for Building Story CLI: From 30-Minute IP Registration to Under 5
Ola Adesoye
Ola Adesoye

Posted on

Building Story CLI: From 30-Minute IP Registration to Under 5

The problem that sparked this project

Here's something that bothered me about Web3 developer tools: they're often built by experienced blockchain developers for experienced blockchain developers.

In the case of IP registration via blockchain, if you're a solo creator who just wants to register your artwork, music, or code as intellectual property on-chain, you're looking at 15-30 minutes of fumbling through documentation, manually formatting JSON metadata, and praying your transaction doesn't fail after you've already spent gas.

I built Story CLI to fix that.


What I built

Story CLI is a command-line toolkit for registering IP assets on Story Protocol—a blockchain designed specifically for programmable intellectual property. Instead of writing code or crafting API calls, you get an interactive wizard:

story register ./my-artwork.jpg
Enter fullscreen mode Exit fullscreen mode

That's it. The CLI walks you through license selection, handles IPFS uploads, executes the blockchain transaction, and gives you a shareable portfolio visualization of all your registered IP.

The goal was simple: take a 15-30 minute process and compress it to under 5 minutes.

1. The license wizard state machine

One of the trickiest parts was translating legal license configurations into something a human could answer in 30 seconds. Story Protocol uses PIL (Programmable IP License) with multiple parameters—commercial use permissions, derivative rights, royalty percentages.

I mapped this to a 3-question decision tree:

Commercial use? → Yes/No
Allow derivatives? → Yes/No
Revenue share? → 0-100% (only if commercial + derivatives)
Enter fullscreen mode Exit fullscreen mode

These three questions deterministically map to one of 4 license configurations:

Commercial Derivatives Result
No No Non-commercial Only
No Yes Non-commercial Derivatives
Yes No Commercial No-Derivatives
Yes Yes Commercial Remix (+ royalty %)

The state machine approach meant I could validate answers in real-time and prevent invalid combinations before they ever hit the blockchain.

2. Fail-fast everything

Blockchain transactions cost gas. Failed transactions still cost gas. This created a design imperative: validate everything before touching the chain.

  • Wallet address format? Checked before any network call
  • IPFS hash format? Validated at input
  • Sufficient balance? Queried before transaction submission
  • Royalty percentage? Bounded 0-100 at prompt time

The philosophy: if something's going to fail, fail in the first 2 seconds, not after a 30-second transaction attempt.

3. Three-part error messages

Every error in Story CLI follows a structure: What went wrong → Why it matters → How to fix it.

✖ Pinata API key not found
  IPFS uploads require Pinata authentication for metadata storage.
  Run: story config set pinataApiKey YOUR_KEY
Enter fullscreen mode Exit fullscreen mode

This sounds obvious, but most CLI tools just dump "Error: invalid credentials" and leave you to figure it out. I spent real time ensuring every failure state had actionable guidance.

4. Self-contained portfolio HTML

After registration, users needed to see their IP. I chose Mermaid.js for graph visualization because it lets me generate a single HTML file with everything embedded—CSS, JavaScript, and relationship diagrams.

No server required. Download the file, email it to someone, and open it. It works.

story portfolio
# → generates story-portfolio.html with interactive graphs
Enter fullscreen mode Exit fullscreen mode

The tradeoff was less visual customization than D3.js would offer, but for an MVP, shipping > perfection.


Challenges & what I learned

Challenge 1: SDK documentation gaps

Story Protocol is relatively new. The SDK documentation had gaps—especially around error responses and edge cases. I ended up reading SDK source code directly and building a mock implementation (STORY_CLI_MOCK=true) so I could develop offline without burning testnet ETH.

Lesson: When integrating new SDKs, budget time for exploration. Mock modes aren't just for testing—they're essential for iteration speed.

Challenge 2: Terminal UX is harder than it looks

Making a CLI feel "good" requires attention to details you take for granted in web UIs:

  • Spinners during async operations (Ora)
  • Color-coded output for visual hierarchy (Chalk)
  • Boxed success messages for celebration moments (Boxen)
  • Clear prompt validation with inline feedback (Inquirer)

Each library handles a specific UX need. Combining them into a cohesive experience took more iteration than expected.

Lesson: CLI UX is a real discipline. Users notice when it's done well—they just don't notice consciously.

Challenge 3: Config file security

Storing API keys and wallet information in ~/.storyrc required thinking about permissions. The config file is created with chmod 600 (owner read/write only), and sensitive values can be overridden via environment variables for CI/CD pipelines.

export STORY_WALLET_PRIVATE_KEY=0x...  # Override config file
story register ./asset.png
Enter fullscreen mode Exit fullscreen mode

Lesson: Security isn't a feature—it's a constraint that shapes your entire design.


The Tech Stack

Architecture at a glance

User terminal
    │
    ▼
Command router (Commander.js)
    │
    ├──► Register command
    │    ├── License wizard (Inquirer.js)
    │    ├── Metadata prompts
    │    ├── IPFS upload (Pinata SDK)
    │    └── Blockchain transaction (Story SDK)
    │
    ├──► Portfolio command
    │    ├── Asset fetching (Story API)
    │    ├── Graph building (Mermaid.js)
    │    └── HTML rendering
    │
    ├──► Config command
    │    └── ~/.storyrc management
    │
    └──► Status command
         └── Wallet & network info
Enter fullscreen mode Exit fullscreen mode

Key patterns used:

  • Command pattern — Each CLI command is an isolated handler
  • Facade patternStoryClient wraps the complex SDK
  • Singleton patternConfigManager prevents redundant file reads
  • Fail-fast validation — Errors surface immediately, not after blockchain calls

Why this matters (Beyond the code)

IP registration on blockchain is one of those "obviously useful" ideas that's been stuck behind technical barriers. The people who would benefit most—independent artists, open-source developers, content creators—are often the least equipped to navigate Web3 tooling.

Story CLI is my attempt at a bridge. Not a dumbed-down version, but a well-designed version that respects users' time and treats errors as communication opportunities rather than dead ends.

The goal was never to abstract away the blockchain entirely—it was to remove the friction while preserving the power.


Try it yourself

npm install -g story-cli
story --help
Enter fullscreen mode Exit fullscreen mode

Quick start

# Configure your wallet
story config set walletAddress 0xYourAddress
story config set network testnet

# Set up IPFS (Pinata)
story config set pinataApiKey YOUR_KEY
story config set pinataApiSecret YOUR_SECRET

# Register your first IP asset
story register ./my-artwork.jpg

# View your portfolio
story portfolio
Enter fullscreen mode Exit fullscreen mode

What's next

  • Batch registration for multiple assets
  • License template sharing
  • Integration with popular creative tools
  • Mainnet deployment guides

Links:

Top comments (0)