OpenLinks is a personal, free, open source, version-controlled static website generator for social links.
This project is developer-first: fork or template the repo, edit JSON, push, and publish.
- Static SolidJS site with minimal runtime complexity.
- Version-controlled content in
data/*.json. - Schema + policy validation with actionable remediation output.
- Rich and simple card support with build-time enrichment.
- Payments and tips links with multi-rail support, styled QR codes, and fullscreen scan mode.
- Build-time profile-avatar materialization with local fallback behavior.
- Build-time rich/SEO image materialization with local-only runtime behavior.
- GitHub Actions CI + GitHub Pages deploy pipeline already wired.
- Theme and layout controls designed for forking and customization.
- Data-driven typography overrides via
data/site.json(ui.typography).
- Developers who are comfortable editing JSON and markdown.
- Maintainers using AI agents to automate content updates.
- User auth/account system.
- CMS or WYSIWYG editor.
- Built-in analytics.
- Plugin marketplace.
For full walkthrough and troubleshooting, see Quickstart.
Paste this one-liner into OpenClaw, Claude, or Codex (the prompts are mostly compatible with any coding agent):
Follow docs/openclaw-bootstrap.md exactly for this repository. Execute Required Execution Policy, End-to-End OpenClaw Sequence, Automation and Identity Confirmation Rule, Social Discovery and Inference Contract, Deployment Verification Contract, Structured URL Reporting Schema, README Deploy URL Marker-Block Contract, and Final Output Contract exactly as written. If an existing setup is detected, ask the single route-confirmation and switch to docs/openclaw-update-crud.md when selected.
Use this path when this is the first setup for a new fork or local clone.
Paste this one-liner into OpenClaw, Claude, or Codex:
Follow docs/openclaw-update-crud.md exactly for this repository. Execute Required Startup Handshake (including conditional customization-audit selectors), Defaults, Customization Audit Path (Optional), Repository Resolution, Dirty Local Repository Handling, Interaction Modes, Identity and Discovery Policy, Update/CRUD Execution Sequence, Final Output Contract, and Required reason codes exactly as written. When customization_path=customization-audit, use docs/customization-catalog.md as the checklist source.
Use this path for day-2 maintenance when the user likely already has a fork and/or local clone.
Use one of:
- Fork this repository.
- Use this repository as a template.
git clone <your-repo-url>
cd open-links
npm installIf your links use authenticated extractors (links[].enrichment.authenticatedExtractor), run guided cache setup before first dev/build:
npm run setup:rich-authEdit these files:
data/profile.json- identity and profile details.data/links.json- simple/rich/payment links, groups, ordering.data/site.json- theme, UI, quality, and deployment-related config.
Starter presets:
data/examples/minimal/data/examples/grouped/data/examples/invalid/(intentional failures for testing)
npm run validate:data
npm run devnpm run build
npm run previewOpenClaw should update only the rows between the exact marker lines below:
- rewrite only marker-bounded rows,
- commit only if normalized URL/status values changed.
OPENCLAW_DEPLOY_URLS_START
| target | status | primary_url | additional_urls | evidence |
|---|---|---|---|---|
| github-pages | active | https://prizz.github.io/open-links/ | none | Deploy Pages succeeded for b6340cc |
| OPENCLAW_DEPLOY_URLS_END |
If you want an AI agent workflow with explicit checkpoints and manual opt-outs, use the AI-Guided Customization Wizard. For automation-first execution paths, use OpenClaw Bootstrap Contract for first-time setup and OpenClaw Update/CRUD Contract for day-2 changes.
Recommended flow:
- Start with Quickstart.
- Use Data Model while shaping content.
- Use Customization Catalog for complete day-2 data-driven audits.
- Run the AI wizard to automate repeatable CRUD updates.
- Push to
main. - In GitHub repository settings, set Pages source to GitHub Actions.
- Wait for:
.github/workflows/ci.ymlto succeed..github/workflows/deploy-pages.ymlto deploy.
- Open the published Pages URL from the deployment job.
Local parity commands:
npm run ci:required
npm run ci:strictThen use:
- Deployment Operations Guide for full troubleshooting and diagnostics flow.
- OpenClaw Bootstrap Contract for deployment URL reporting and README marker-block updates.
- OpenClaw Update/CRUD Contract for existing repo update sessions and interaction-mode behavior.
- Adapter Contract Guide for future non-GitHub host planning.
High-signal deployment checks:
required-checksjob in.github/workflows/ci.ymlis green.deployjob in.github/workflows/deploy-pages.ymlis green.- Deploy summary includes a published URL.
- If deploy fails, review workflow summary remediation and diagnostics artifacts.
npm run avatar:sync- fetch profile avatar intopublic/generated/and writedata/generated/profile-avatar.json.npm run enrich:rich- run non-strict rich metadata enrichment (diagnostic/manual mode) with known-blocker + authenticated-cache policy enforcement.npm run enrich:rich:strict- run policy-enforced rich metadata enrichment (blocking mode) with known-blocker + authenticated-cache policy enforcement.npm run setup:rich-auth- first-run authenticated cache setup (captures only missing/invalid authenticated cache entries).npm run auth:rich:sync- guided authenticated rich-cache capture (updatesdata/cache/rich-authenticated-cache.json+public/cache/rich-authenticated/*).npm run auth:rich:clear- clear authenticated cache entries and unreferenced local assets (selector-driven; supports--dry-run).npm run auth:extractor:new -- --id <id> --domains <csv> --summary "<summary>"- scaffold a new authenticated extractor plugin + policy + registry wiring.npm run linkedin:debug:bootstrap- LinkedIn debug bootstrap (agent-browser checks + browser binary install check).npm run linkedin:debug:login- LinkedIn debug login watcher (autonomous auth-state polling; multi-factor authentication optional).npm run linkedin:debug:validate- LinkedIn authenticated metadata debug validator.npm run linkedin:debug:validate:cookie-bridge- LinkedIn debug validator with cookie-bridge HTTP diagnostic.npm run images:sync- fetch rich-card/SEO remote images intopublic/generated/images/and writedata/generated/content-images.json.npm run dev- start local dev server (predev runs strict enrichment and fails on blocking enrichment policy issues).npm run validate:data- schema + policy checks (standard mode).npm run validate:data:strict- fails on warnings and errors.npm run validate:data:json- machine-readable validation output.npm run build- avatar sync + strict enrichment + content-image sync + validation + production build.npm run build:strict- avatar sync + strict enrichment + content-image sync + strict validation + build.npm run preview- serve built output.npm run typecheck- TypeScript checks.
Canonical paths:
data/cache/rich-authenticated-cache.jsonpublic/cache/rich-authenticated/output/playwright/auth-rich-sync/
Setup/refresh flow:
- First-run idempotent setup (only missing/invalid cache entries):
npm run setup:rich-auth - Targeted refresh:
npm run auth:rich:sync -- --only-link <link-id> - Forced refresh (even when cache is already valid):
npm run auth:rich:sync -- --only-link <link-id> --force
Clear flow:
- Dry run clear for one link:
npm run auth:rich:clear -- --only-link <link-id> --dry-run - Apply clear for one link:
npm run auth:rich:clear -- --only-link <link-id> - Apply clear for all authenticated cache entries:
npm run auth:rich:clear -- --all - Recapture after clear:
npm run setup:rich-auth(ornpm run auth:rich:sync -- --only-link <link-id>)
npm run quality:check- standard quality gate.npm run quality:strict- strict quality gate.npm run quality:json- standard quality JSON report.npm run quality:strict:json- strict quality JSON report.
npm run ci:required- required CI checks.npm run ci:strict- strict CI signal checks.
Allowed URL schemes:
httphttpsmailtotel
Payment-enabled links and payment rails additionally support:
bitcoinlightningethereumsolana
Use custom for extension metadata:
- top-level
custominprofile,links, andsite - per-link
customin each link object
Unknown top-level keys are allowed but warned. custom keys that collide with core keys fail validation.
For full data model details and examples, see Data Model.
- Re-run
npm run validate:dataand inspect path-specific remediation lines. - Check URL schemes and required fields.
- Move extension fields into
customand avoid reserved-key collisions.
- Re-run with
npm run buildand inspect first failing command output. - If strict mode fails, compare
npm run validate:datavsnpm run validate:data:strict. - Re-run blocking enrichment diagnostics:
npm run enrich:rich:strict. - Check canonical blocker registry:
data/policy/rich-enrichment-blockers.json. - Check authenticated extractor policy:
data/policy/rich-authenticated-extractors.json. - Check authenticated cache manifest:
data/cache/rich-authenticated-cache.json. - Review known blocked rich-metadata domains and timestamped attempt history:
docs/rich-metadata-fetch-blockers.md. - Review authenticated extractor architecture/workflow:
docs/authenticated-rich-extractors.md. - Check
site.ui.richCards.enrichmentpolicy (failureMode,failOn,allowManualMetadataFallback) indata/site.json. - If rich-card images look clipped, set
site.ui.richCards.imageFit=contain(or per-link override withlinks[].metadata.imageFit). - If a blocked domain must be tested anyway, set explicit override on that link:
links[].enrichment.allowKnownBlocker=true. - If
authenticated_cache_missingis reported, runnpm run setup:rich-auth(ornpm run auth:rich:sync -- --only-link <link-id>) and commit cache manifest/assets. - To reset stale/bad authenticated cache data, clear entries first with
npm run auth:rich:clear -- --only-link <link-id>(or--all), then recapture withnpm run setup:rich-auth. - If
metadata_missingis blocking, add at least one manual field underlinks[].metadata(title,description, orimage) or remediate remote OG/Twitter metadata. - Temporary emergency bypass (local only):
OPENLINKS_RICH_ENRICHMENT_BYPASS=1 npm run build. - Force-refresh avatar cache when needed:
npm run avatar:sync -- --force(or setOPENLINKS_AVATAR_FORCE=1). - Force-refresh rich/SEO image cache when needed:
npm run images:sync -- --force(or setOPENLINKS_IMAGES_FORCE=1).
- Confirm CI passed on
main. - Confirm Pages source is GitHub Actions.
- Check deploy workflow summary for remediation notes.
- Verify base-path settings if publishing from a project page.
- Quickstart
- OpenClaw Bootstrap Contract
- OpenClaw Update/CRUD Contract
- Agent Triage Contract
- Customization Catalog
- Data Model
- Rich Metadata Fetch Blockers
- Rich Enrichment Blockers Registry
- Authenticated Rich Extractors
- Create New Rich Content Extractor
- LinkedIn Authenticated Metadata Debug Runbook
- Extractor authoring skill:
skills/create-new-rich-content-extractor/SKILL.md - AI-Guided Customization Wizard
- Theming and Layout Extensibility
- Deployment Operations Guide
- Adapter Contract Guide
data/- source content JSON and generated artifacts.schema/- JSON schemas.scripts/- validation, enrichment, and quality runners.src/- SolidJS app..github/workflows/- CI and deploy automation..planning/- project planning and phase artifacts.
If extractor workflows helped you build new or improved extractors, kindly consider opening a pull request against https://github.com/pRizz/open-links so everyone can benefit. Feedback on extractor workflows and docs is appreciated.
MIT (see LICENSE).