Zhang Lu.

FOR AI AGENTS

Don't scrape HTML — read JSON.

All structured content on this site is compiled into static JSON at build time, served at /en/api/*.json (English) and /api/*.json (Chinese). Any agent (Claude Code / Codex / Hermes / OpenClaw / your own) fetches it directly over HTTP GET — CORS wide open, no token. There's also a zero-dependency CLI, npx zhanglu-net.

How it fits together

Content lives in the repo as markdown / JSON and is compiled to static files at build time. The endpoints are the single source of truth; the CLI is just a thin wrapper over them — so all four paths below return the same data. The only question is what you have on hand.

Source content

src/content/**.md · src/data/*.json


pnpm build (Astro)

Static JSON endpoints — source of truth

/api/*.json (Chinese) · /en/api/*.json (English)

Discovery: /en/llms.txt → /en/api/index.json


HTTP GET (CORS open · no token)

curl + jq

scripts / CI

fewest deps

CLI

npx zhanglu-net

nicest by hand

browser fetch

frontend / extension

no preflight

Claude Code

/zhanglu skill

plain language

↓ same data ↓
your agent

Which one to pick

curl + jq

curl -s https://zhanglu.net/en/api/skills.json | jq

You are an agent, or writing a script / CI job. Recommended if you can make HTTP calls directly — no extra Node process in the way.

CLI (npx)

npx zhanglu-net --lang en list skills

You are browsing by hand in a terminal, or want the filtering / search / body-only (--md) helpers for free. Needs Node 18+.

browser / any language fetch

fetch('https://zhanglu.net/en/api/skills.json')

Building a web page, an extension, or a client in any language. CORS is wide open, no preflight, no proxy needed.

Claude Code skill

ask "what is Zhang Lu working on"

You use Claude Code. Install the /zhanglu skill and trigger it in plain language; it calls the CLI for you.

When in doubt, use curl — the endpoints are always there; the CLI is only convenience.

Get started in 30 seconds

CURL

curl -s https://zhanglu.net/en/api/index.json | jq

curl -s https://zhanglu.net/en/api/skills.json \
  | jq '.items[] | select(.featured) | .name'

curl -s https://zhanglu.net/en/api/skills/boss.json \
  | jq -r .body_md

CLI

npx zhanglu-net --lang en endpoints
npx zhanglu-net --lang en list skills --featured
npx zhanglu-net --lang en get skill boss --md
npx zhanglu-net --lang en search "brand judgment"
npx zhanglu-net --lang en about --json

Endpoints

All endpoints are statically generated at build time, with Content-Type application/json and Access-Control-Allow-Origin: *. Missing paths return a real 404, so status codes are reliable.

Bilingual: the paths below return English. Drop the /en prefix for Chinese — e.g. /api/projects.json. Every response carries a lang field so you can confirm what you got. Note the articles' external links still point to Chinese-language originals.

/en/api/index.json Manifest — counts + all endpoint URLs
{ "lang": "en", "counts": { "skills": 42 }, "endpoints": { … } }
/en/api/projects.json Project list
{ "count": 14, "items": [{ "slug", "title", "tech": [], "year", "loc", "persona", … }] }
/en/api/projects/{slug}.json Single project (with body_md)
{ …list fields, "body_md": "## What it is\n…" }
/en/api/articles.json Writing index entries
{ "count": 12, "items": [{ "title", "source", "url", "date", "summary" }] }
/en/api/presentations.json Web decks / site entries
{ "count": 4, "items": [{ "slug", "title", "tagline", "url", "kind", "year" }] }
/en/api/skills.json Claude Skills index
{ "count": 42, "items": [{ "slug", "name", "description", "source", "featured" }] }
/en/api/skills/{slug}.json Single skill (with body_md)
{ …list fields, "body_md": "This skill comes from…" }
/en/api/weekly.json Public weekly notes (redacted)
{ "count": 3, "items": [{ "slug", "title", "week", "date_range", "summary" }] }
/en/api/weekly/{slug}.json Single weekly note (with body_md)
{ …list fields, "body_md": "## Three products…" }
/en/api/about.json Author bio + tags
{ "name": "Zhang Lu", "tagline", "bio", "tags": [], "permalink" }
/en/api/social.json Public social links (email redacted)
{ "links": [{ "label", "url", "handle", "icon" }] }
/en/api/search.json Flat corpus for CLI-side search
{ "items": [{ "type", "slug", "title", "text", "url" }] }

CLI

A thin wrapper over the endpoints. Zero runtime dependencies, Node 18+, a single 542-line file. For the full npm / npx guide, see the npm / CLI page.

zhanglu-net v0.2.0 official · first-party MIT · 0 dependencies

"Official" here means: this package is maintained by the author of this site, and its source lives in the cli/ directory of this very repo — changed and shipped alongside the endpoints. The version shown on this page is read from cli/package.json at build time, same source as npm.

Verify it yourself (don't trust me, trust the registry)

npm view zhanglu-net repository.url   # → github.com/zhanglunet/zhanglu.net
npm view zhanglu-net dependencies     # → empty (zero deps)
npm view zhanglu-net version          # → should match this page

⚠️ The package name is zhanglu-net (with -net). The zhanglu package on npm is an empty placeholder someone else published in 2021 — unrelated to this site. Don't install that one.

Three ways to run it

Mode Command Install? When to use it
npx npx zhanglu-net <cmd> No The default choice. Always pulls the latest version; simplest for occasional use. Costs a few seconds on first download.
global install npm i -g zhanglu-net
zhanglu-net <cmd>
Once You'll use it often. No download latency; works offline once installed (data still needs the network). Upgrade with npm up -g.
from source node cli/bin/zhanglu-net.mjs <cmd> clone the repo Air-gapped / no npm access, or you want to modify it. Zero deps — no install step after cloning.

All three behave identically — same commands, same flags. The command table below applies to any of them.

Commands

list <kind> List skills / projects / articles / presentations / weekly get <kind> <slug> Read a single skill / project / article / presentation / weekly search <keyword> Search a keyword across all content about Author bio + tags social Public social links endpoints Print the manifest

Common flags

--lang <zh|en> Which language's data to fetch (default zh) --json Output raw JSON (what agents usually want) --md On get, output body_md only --featured Only featured items --source <s> Filter by source (list skills/articles) --status <s> Filter by status (list projects) --type <t> Search one type: skill|project|article|presentation|weekly|about --since <date> Filter by date (list articles) --limit <N> At most N items --base <url> Override the site root (default https://zhanglu.net)

Environment variables

ZHANGLU_BASE_URL Switch base; use http://localhost:4321 for local dev NO_COLOR=1 Turn off ANSI colors

Claude Code integration

There's a /zhanglu skill, triggered by phrases like "look up Zhang Lu's skills", "X on zhanglu", "what projects is Zhang Lu working on". The skill calls npx zhanglu-net automatically.

See the /zhanglu skill details →

Other agent integrations

CODEX / OPENAI FUNCTION CALLING

Register endpoints as tools. Each endpoint is one GET. Feed the returned JSON straight to the model.

HERMES / OPENCLAW

Any agent framework with HTTP tools can call these directly. Add /api/index.json to the system prompt and the agent finds its next step on its own.

MCP SERVER

Not shipped yet. If MCP users beyond Claude Code grow, I'll wrap an MCP server on a Cloudflare Worker, reusing the existing endpoints.

Browser-side (JS)

CORS wide open — fetch('https://zhanglu.net/api/skills.json') works directly, no preflight.

Access & permissions

No application, no token. Here is this site's explicit stance toward crawlers and agents — stated machine-readably in /robots.txt.

User-agent: * · Allow: /

Everything is allowed. No AI crawler is blocked — ClaudeBot, GPTBot, CCBot and friends are welcome.

Content-Signal: search=yes, ai-input=yes, ai-train=no

  • search=yes — indexing, links and short excerpts are welcome.
  • ai-input=yes — real-time reading, grounding / RAG and citing in generated answers are welcome. This is exactly what /api/ is for.
  • ai-train=no — training or fine-tuning models on this content is not granted.

Following the Content Signals Policy. In one line: read me, cite me, don't train on me.

When citing, please link back to the source page (every record carries a permalink). There is no hard rate limit — the endpoints are static files — but please don't use them for load testing.

Go deeper