⚙️

Install Node.js & CredCLI

🤖
Claude can do this for you. Open a terminal in Claude Code and say: "Install CredCLI and verify it works." Claude will run the commands below on your behalf.

Step 1 — Install Node.js (>= 18)

CredCLI requires Node.js 18 or later. Download it from nodejs.org or use a version manager:

Using nvm (macOS / Linux)

nvm install 20
nvm use 20
node --version

Using winget (Windows)

winget install OpenJS.NodeJS.LTS
node --version

Step 2 — Install CredCLI

Install globally for persistent use, or run one-off with npx:

# Option A: Install globally (recommended)
npm install -g @credcli/cli

# Option B: Run without installing
npx @credcli/cli <command>
⏳
First-run note: CredCLI uses Playwright for headless rendering. On first use, Chromium (~130 MB) downloads automatically. This is a one-time download.

Step 3 — Verify installation

credcli help

You should see a list of commands. If not, ensure npm bin -g is on your PATH.

🖥️

Cowork VM Setup

⚠️
Cowork VMs only. Skip this section if you are using a standard local machine, VSCode, or Claude Code directly. These steps are only needed in Cowork sandbox environments where the default npm prefix and Playwright cache paths are not user-writable.

Cowork VMs have two constraints that require a one-time workaround:

  • The default npm global prefix is not writable — install into ~/.npm-global instead.
  • The mounted workspace folder blocks file deletion (EPERM) — a one-line patch silences this after render.

Step 1 — Install into a writable prefix

npm install -g @credcli/cli --prefix ~/.npm-global
export PATH="$HOME/.npm-global/bin:$PATH"
credcli --version

Step 2 — Run the Cowork setup script

This installs Playwright's Chromium browser into the package directory (so it survives session resets) and applies the EPERM patch to cli.mjs. Safe to re-run — each step checks before acting.

bash ~/.npm-global/lib/node_modules/@credcli/cli/scripts/setup.sh
🤖
Let Claude do it. If you paste your Chainletter token URL and say "Set up CredCLI on this Cowork VM", Claude will run both steps above automatically.

Step 3 — Use the browser path when rendering

Every credcli run command needs the PLAYWRIGHT_BROWSERS_PATH variable pointing at the package-local browser:

PLAYWRIGHT_BROWSERS_PATH=~/.npm-global/lib/node_modules/@credcli/cli/.browsers \
  credcli run <job> --format png

The setup script prints this exact command at the end so you can copy it from there.

🔑

Claim Your Chainletter Token

Every CredCLI operation requires a Chainletter workspace token. You receive this as a shortlink URL from your Chainletter account.

# Claim your token from a Chainletter shortlink
credcli register https://yourserver.chainletter.io/jwt/abc123

# Verify it was saved correctly
credcli register -i

This creates a token.json file in your working directory containing:

{
  "jwt":        "eyJhbGci...",   // Bearer token for API calls
  "webhookUrl": "https://yourserver.chainletter.io/webhook/...",
  "tenant":     "yourname",      // Used as .data/ subdirectory
  "groupname":  "spring-2026",
  "expires":    "2027-01-01T00:00:00Z"
}
⚠️
Token expiry: If you see 401 Unauthorized during send or stamp, your token has expired. Run credcli register <new-url> with a fresh shortlink from Chainletter.

Set workspace identity

Your issuer name and logo are automatically injected into every rendered credential as {{WorkspaceIssuer}} and {{WorkspaceLogo}}. Set them once:

credcli workspace --issuer "Acme University"
credcli workspace --logo ./logo.png   # PNG/JPG/SVG → embedded as base64
credcli workspace                     # view current values
🪄

Expand Claude Skills

CredCLI is designed to be orchestrated by Claude Code. Run the commands below in your working directory — Claude Code picks up the reference files automatically and gains detailed knowledge of every command, flag, and workflow:

# Write CLAUDE.md (short quick-reference, auto-loaded by Claude Code)
credcli help -c

# Write SKILL.MD (full agent reference with API docs and patterns)
credcli help -s
💡
How it works: Claude Code automatically reads any CLAUDE.md in your working directory. Once present, Claude understands every CredCLI command and the full workflow, and can run steps on your behalf.
🏅

Stamped Credential Workflow

The full end-to-end workflow takes a CSV of recipients, renders one credential per row, uploads to IPFS, and blockchain-stamps the collection. Each step is idempotent — safe to repeat or resume.

🤖
Let Claude drive. Paste your recipient CSV and say: "Issue blockchain-stamped diplomas to everyone in recipients.csv using the Diploma template, then generate claim emails." Claude will run each step below.
1

Set workspace identity

Your issuer name and logo stamp every credential automatically. Do this once per workspace.

credcli workspace --issuer "Acme University"
credcli workspace --logo ./logo.png
2

Discover available templates

List all templates with their dimensions and required CSV columns. Always run this before creating a job.

credcli templates
3

Create a job

A job is a folder that holds the template, CSV, and all output files. Use --template N with the number from credcli templates.

credcli new --template 4   # template 4 = Diploma
# Creates: .data/{tenant}/jobs/job001/
4

Load recipients CSV

Your CSV header must exactly match the template's field names (case-sensitive). Run credcli templates to get the exact column list. The new job also creates an empty mailmerge.csv with the correct header — use it as a starter.

credcli csv job001 students.csv

Example CSV rows:

FullName,Title,Institution,Major,IssueDate,CredentialID
Jane Smith,Bachelor of Science,Acme University,Computer Science,2026-06-01,CRED-0001
Alex Jones,Bachelor of Arts,Acme University,History,2026-06-01,CRED-0002
5

Render credentials

Headless Chromium renders one PDF or PNG per CSV row. Use --resume to skip rows already rendered.

credcli run job001 --format pdf
# or: --format png  (default)
# or: --limit 5     (render first 5 rows only, for testing)
# or: --resume      (skip already-rendered files)
credcli output job001   # list generated file paths
6

Assign a Chainletter collection

Link this job to a named collection on Chainletter. Use --network public to make credentials publicly accessible on IPFS (required for claim links in emails).

credcli assign job001 spring-2026 --network public
7

Upload to Chainletter (IPFS)

Uploads all output files to Chainletter. Files already uploaded are deduplicated automatically (409 = safe to ignore). Use --yes to skip confirmation.

credcli send job001 --yes
8

Blockchain stamp

Stamps the collection with an immutable blockchain postmark. This is permanent and irreversible. After stamping, each file gets a claim link and a verification link.

credcli stamp job001
⚠️
Stamping is irreversible. Verify your output files with credcli output job001 before stamping.
9

Generate claim emails

Creates one .eml per recipient with their credential claim link and QR code embedded. Also produces an all_recipients.mbox archive and a mail_merge_manifest.csv.

credcli email job001

# To use a specific email template:
credcli email job001 --email-template credential-claim-email_600x900.html

Emails are saved to output/mail_merge/. If SMTP is configured in workspace settings, they are sent automatically.

Full workflow at a glance

# ── One-shot copy-paste workflow ─────────────────────────────────────────────
credcli register https://server.chainletter.io/jwt/abc123
credcli workspace --issuer "Acme University" --logo ./logo.png
credcli templates
credcli new --template 4
credcli csv job001 students.csv
credcli run job001 --format pdf
credcli assign job001 spring-2026 --network public
credcli send job001 --yes
credcli stamp job001
credcli email job001

Check remaining credits

credcli credits
📧

Mail Merge

Optional

Mail merge is the core of CredCLI's batch processing: one CSV row = one credential = one email. You don't have to use the email step, but it completes the delivery loop from stamped credential to recipient inbox.

How it works

After credcli stamp job001, each credential has a unique claim URL stored in job.json. The email command uses your CSV data plus those claim URLs to render an email template for each recipient:

credcli email job001
# Output: job001/output/mail_merge/
#   ├── Jane_Smith_CRED-0001.eml
#   ├── Alex_Jones_CRED-0002.eml
#   ├── all_recipients.mbox       ← archive of all emails
#   └── mail_merge_manifest.csv   ← metadata: name, email, file, claim URL

CSV format rules

  • First row is the header — column names are case-sensitive and must match the template's field list exactly
  • One row per credential; blank rows are skipped
  • {{FieldName}} placeholders in the HTML template are replaced by the matching column value
  • Extra columns in the CSV are ignored; missing columns render as empty string
  • Include an Email column if you want email delivery

All available field names

These are the recognized placeholder names for use in templates and CSV headers:

FullName FName LName Email Title Achievement BadgeLevel CredentialID Institution Issuer Signature Location IssueDate ExpirationDate CourseName Major GPA Hours Notes QRUrl VerificationURL WorkspaceIssuer WorkspaceLogo Course1Name…12 Course1Grade…12 Course1Credits…12 Course1Semester…12
📌
WorkspaceIssuer and WorkspaceLogo are injected automatically from workspace settings. You do not need to include them in your CSV.
📌
QRUrl and VerificationURL are populated automatically after stamping. Do not include them in your source CSV.

Custom email templates

The email template is itself an HTML file with {{Placeholder}} syntax. The built-in template (template #6) works out of the box. To use a custom one:

credcli email job001 --email-template my-email-template.html

SMTP auto-send

If SMTP credentials are stored in workspace settings (.data/{tenant}/workspace.json), emails are sent automatically rather than written to .eml files. Configure SMTP via the web UI (credcli serve) or set environment variables:

[email protected]
TEST_SENDER_PW=your-app-password

Public vs. private collections

⚠️
Private collections do not generate claim links. If you want recipients to receive a link to claim their credential, assign the collection with --network public before stamping. You cannot change this after stamping.
🌐

Web UI Alternative

Every CLI command has a browser-based equivalent. The web UI is useful for visual template editing, drag-and-drop CSV upload, and monitoring render progress.

credcli serve              # opens localhost:3037
credcli serve --port 8080  # custom port

Template Editor

Live split-view HTML editor with placeholder chips and instant preview rendering.

CSV Upload

Drag-and-drop zone with field validation and recipient preview table.

Render Progress

Real-time progress log and output file grid with PDF/PNG thumbnails.

Chainletter Panel

Collection assignment, upload, stamp, and email generation in one place.

📋

Built-in Template Reference

Run credcli templates to see the full field list for each template at any time.

# Name Size Key CSV Fields
1 Achievement Badge 600×600 FullName, CourseName, Institution, IssueDate, CredentialID, BadgeLevel
2 Certificate of Achievement 1200×900 FullName, Title, CourseName, IssueDate, CredentialID
3 Course Completion Certificate 1200×900 FullName, CourseName, IssueDate, CredentialID, Hours, GPA
4 Diploma 1200×900 FullName, Title, Institution, Major, IssueDate, CredentialID
5 Transcript 1200×1600 FullName, Institution, GPA, Major, IssueDate + 12 course rows
6 Credential Claim Email 600×900 FullName, Email, Title, VerificationURL type: email

Custom templates

Any HTML file in .data/{tenant}/templates/ with a metadata comment is recognized as a template:

<!-- Add this near the top of your HTML file -->
<!--CREDCLI:{"name":"My Diploma","width":1200,"height":900,
             "fields":["FullName","Programme","IssueDate","CredentialID"]}-->

<!-- Use {{FieldName}} placeholders in the body -->
<h1>{{FullName}}</h1>
<p>{{Programme}} — {{IssueDate}}</p>

After saving, run credcli templates — your template appears immediately. Use credcli serve for a live browser-based editor.

🔧

Error Reference

Symptom Cause Fix
No token registered token.json missing or wrong directory Run credcli register <url> in the project root
Invalid template number --template N out of range Run credcli templates to see the valid range
Credentials render blank CSV column names don't match template fields Check credcli templates for exact field names (case-sensitive)
409 Conflict on send File already uploaded (deduplication) Safe to ignore — the skipped count is reported
401 Unauthorized on send/stamp JWT token expired Run credcli register <url> with a fresh shortlink
No claim links after stamp Collection was assigned as private Re-create the job and use --network public before stamping
Chromium not found Playwright browsers not installed Run npx playwright install chromium

Full command reference

Command Purpose Key flags
register <url>Claim Chainletter token-i show token info
workspaceShow / set issuer name + logo--issuer --logo
templatesList templates + their fields—
newCreate a credential job--template N
listList jobs + recipient counts—
csv <job> <file>Load recipient CSV into a job—
run <job>Render credentials to PDF/PNG--format --limit --resume
preview <job>Render row 1 and open the file--row N --format
output <job>Print absolute paths of output files—
assign <job> <id>Link job to Chainletter collection--network public|private
send <job>Upload files to Chainletter-y auto-confirm
stamp <job>Blockchain-stamp the collection—
email <job>Generate .eml + mbox for recipients--email-template <file>
creditsShow remaining stamp credits—
delete <job>Delete a job folder-y skip confirm
serveStart web UI at localhost:3037--port N
helpShow usage-c write CLAUDE.md, -s write SKILL.md