npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sleekcms/sync

v1.1.0

Published

Edit SleekCMS sites locally — models, content, templates, images — with live two-way sync and AI agent support.

Readme

SleekCMS CLI

Build complete websites with AI. Edit them locally. Deploy instantly.

The SleekCMS CLI brings your CMS to your code editor — with full AI-agent support baked in. Spin up an entirely new site by describing it in plain English, or drop into any existing site and edit templates, content, and styles the way you'd expect: locally, with real files, in your editor of choice.

Every save auto-syncs. Every change goes live. No build steps. No Git hooks. No infrastructure to manage.


Why developers love it

  • AI generates your entire site from a description — models, templates, layouts, styles, and content, all wired up and ready to go.
  • AI-generated sites are plain files — EJS templates, JSON content, CSS, JS. You own every line. Open in VS Code, Cursor, or any editor.
  • Any AI can maintain it — the CLI injects AGENT.md, CLAUDE.md, and .vscode/copilot-instructions.md into your workspace. GitHub Copilot, Claude, Cursor — they all read the same site reference and understand your structure from day one.
  • Live sync, always — save a file, it syncs. Open the SleekCMS dashboard and your preview updates in real time.
  • One command to start — no installs required.

Quickstart

npx @sleekcms/sync --token <YOUR_AUTH_TOKEN>

That's it. The CLI fetches your site, opens an editor prompt, and starts watching for changes. Grab a token from your SleekCMS dashboard.


Installation

Run without installing (recommended)

npx @sleekcms/sync --token <YOUR_AUTH_TOKEN>

Install globally

npm install -g @sleekcms/sync
sleekcms --token <YOUR_AUTH_TOKEN>

Usage

npx @sleekcms/sync [OPTIONS]

| Option | Alias | Description | Default | |--------------------|-------|--------------------------------------------------------|---------------| | --token <token> | -t | Your SleekCMS CLI auth token (required) | — | | --path <path> | -p | Parent directory for the local workspace | ~/.sleekcms | | --help | -h | Show help | — |

The actual workspace folder is created at <path>/<site-name>-<site-id>/.

# Basic
npx @sleekcms/sync --token abc123-xxxx

# Custom workspace folder
npx @sleekcms/sync -t abc123-xxxx -p ~/Sites

Once running, press r to re-fetch all files or x / Ctrl+C to exit.


Building a site with AI

This is where SleekCMS CLI becomes something different. Instead of hand-crafting every template, you describe the site you want and let an AI agent build it.

How it works

When the CLI starts for the first time, it writes three files into your local workspace:

| File | Picked up by | |---|---| | AGENT.md | Copilot (agent mode), any generic agent | | CLAUDE.md | Claude / Claude Code | | .vscode/copilot-instructions.md | GitHub Copilot in VS Code |

These files contain the complete SleekCMS site-building reference — file naming conventions, model syntax, template helpers, content format, and all the rules an AI needs to produce valid, working code.

Generate a complete site

Open the workspace in Cursor, VS Code with GitHub Copilot, or Claude Code, then describe your site:

Build a portfolio site with:
- A home page with a hero section, featured projects, and a contact form
- A blog with individual post pages
- A shared header and footer
- Tailwind CSS styling
- SEO meta tags on every page

The AI creates the right files in the right places:

src/models/pages/home.model
src/models/pages/blog[].model
src/models/entries/header.model
src/models/entries/footer.model
src/models/blocks/hero.model
src/views/pages/home.ejs
src/views/pages/blog[].ejs
src/views/entries/header.ejs
src/views/entries/footer.ejs
src/views/blocks/hero.ejs
src/views/layouts/main.ejs
src/public/css/tailwind.css
src/content/pages/home.json
src/content/pages/blog[]/my-first-post.json
src/content/entries/header.json
src/content/entries/footer.json

As soon as those files hit disk, the watcher picks them up and syncs each one to SleekCMS. Your site is live before the AI finishes explaining what it built.

AI-generated sites are fully editable and maintainable — automatically

There's no lock-in, no proprietary format, no "AI black box". Every file the AI writes is the same real file you'd write by hand:

  • Templates are standard EJS — open them in any editor, tweak any line.
  • Models are plain JSON-like schema files — add a field, save, done.
  • Content is readable JSON — edit values directly without touching the CMS dashboard.

And because AGENT.md / CLAUDE.md live in the workspace, any AI session — today or months from now — picks up the same full site context. Ask it to add a dark mode toggle, refactor the blog layout, or generate ten more blog posts. It already knows your site.


How sync works

The CLI runs a local watcher after the initial fetch. Every time you save a file:

  1. The watcher detects the change (debounced to batch rapid edits).
  2. The changed file is classified — template, model, content record, CSS, or JS.
  3. It's pushed to the SleekCMS API in the correct order: models first, then templates, then content.
  4. The SleekCMS server rebuilds and redeploys the affected pages.

On first run, the CLI pulls the full site state from the server. After that, a local .cache/ folder tracks server-known state so only real diffs are pushed — no redundant API calls.

Your editor → file save → watcher → SleekCMS API → rebuild → live site

Watch mode commands

| Key | Action | |---|---| | r | Re-fetch all files from server | | x or Ctrl+C | Exit and clean up local workspace |


Previewing your site

Every change you sync is immediately reflected in SleekCMS. To preview:

  1. Open the SleekCMS dashboard.
  2. Navigate to your site.
  3. Click Preview — you'll see the live build with your latest changes.

No manual deploy. No waiting. SleekCMS rebuilds on every sync and the preview reflects the current state of your local workspace in real time.


Local workspace structure

<site-name>/
├── AGENT.md                              # AI agent reference (auto-generated)
├── CLAUDE.md                             # Claude reference (auto-generated)
├── .vscode/
│   ├── copilot-instructions.md           # GitHub Copilot context (auto-generated)
│   └── settings.json                     # Editor settings
│
└── src/
    ├── models/
    │   ├── pages/<key>.model             # Page content schema
    │   ├── entries/<key>.model           # Entry content schema
    │   └── blocks/<key>.model            # Block content schema
    │
    ├── views/
    │   ├── pages/<key>.ejs               # Page templates
    │   ├── entries/<key>.ejs             # Entry templates
    │   ├── blocks/<key>.ejs              # Block templates
    │   └── layouts/<name>.ejs            # Layout wrappers
    │
    ├── content/
    │   ├── pages/<key>.json              # Single page content
    │   ├── pages/<key>/<slug>.json       # Collection page content (one file per item)
    │   ├── entries/<key>.json            # Single entry content
    │   ├── entries/<key>[].json          # Collection entry content (array)
    │   └── images.json                   # Reusable site-level images (handle → shortcut)
    │
    └── public/
        ├── css/<name>.css                # Stylesheets
        └── js/<name>.js                  # Scripts

File naming

Keys are lowercase, dash-separated. For pages, _ in the key maps to / in the URL. A [] suffix marks a collection.

| Key | URL | |---|---| | _index | / | | about | /about | | blog[] | /blog/<slug> | | docs_getting-started | /docs/getting-started |


Content models

Models describe the shape of your content. They're JSON-like files with unquoted keys and type names as values.

{
    title: text,
    image: image,
    body: richtext,
    published: boolean
}

Nested groups:

{
    hero: {
        heading: text,
        background: image
    }
}

Repeatable lists:

{
    features: [
        {
            title: text,
            icon: image
        }
    ]
}

Block and entry references:

{
    cta: block(cta),
    author: entry(authors),
    tags: [entry(tags)]
}

Field types

| Type | Value | |---|---| | text | String | | paragraph | Multiline string | | richtext | HTML string | | markdown | Markdown string | | number | Number | | boolean | true / false | | date | YYYY-MM-DD | | image | { url, alt } | | video | { url, embed } | | link | URL string | | json | Object or array | | block(key) | Embedded block object | | entry(key) | Entry object or slug reference |


EJS template syntax

| Tag | Purpose | |---|---| | <%= expr %> | Output with HTML escaping | | <%- expr %> | Output raw HTML | | <% code %> | Execute JS (loops, conditionals) |

Template context

| Variable | Description | |---|---| | item | The current page, entry, or block record | | pages | All page records | | entries | All entries keyed by handle | | main | Rendered page output (layouts only) |

Helper functions

Content access

| Function | Description | |---|---| | getPage(path) | Page by exact path | | getPages(path, opts?) | Pages where path starts with prefix; pass { collection: true } for collection pages only | | getEntry(handle) | Entry by handle | | getImage(handle) | Site-level image by handle (from images.json) | | getSlugs(path) | Slugs under a collection path | | path(page) | Relative URL path of a page (e.g. /blog/my-post) | | url(pathOrPage?) | Site origin, or a full absolute URL when given a path string or page object |

Rendering

| Function | Description | |---|---| | render(val) | Render a block or entry through its template | | marked(md) | Convert markdown to HTML |

Images

| Function | Description | |---|---| | img(image, attr) | <img> element | | src(image, attr) | Optimized image URL | | picture(image, attr) | <picture> with dark/light variants | | svg(image, attr?) | Inline SVG |

attr can be a "WxH" string or { w, h, class, style, fit } object.

Head injection (deduplicated automatically)

| Function | Description | |---|---| | title(text) | Set <title> | | meta(attrs) | Add <meta> tag | | link(value) | Add <link> (CSS URL, font, etc.) | | style(css) | Inline <style> block | | script(value) | External or inline <script> |

Tailwind: Creating src/public/css/tailwind.css enables Tailwind automatically — it's compiled and injected for you. Do not add it via link().


Example templates

Layout (src/views/layouts/main.ejs)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  <%- render(getEntry('header')) %>
  <main><%- main %></main>
  <%- render(getEntry('footer')) %>
</body>
</html>

Page (src/views/pages/blog[].ejs)

<% title(item.title + ' | My Blog') %>
<% link('/css/styles.css') %>

<article>
  <h1><%= item.title %></h1>
  <%- img(item.cover, '1200x600') %>
  <%- marked(item.body) %>
</article>

Blog index listing

<% for (const post of getPages('/blog', { collection: true })) { %>
  <a href="<%- path(post) %>">
    <%- img(post.cover, '400x250') %>
    <h3><%= post.title %></h3>
  </a>
<% } %>

Forms (no backend needed)

<form data-sleekcms="contact">
  <input name="name" type="text" required>
  <input name="email" type="email" required>
  <textarea name="message"></textarea>
  <button type="submit">Send</button>
</form>

Any form with data-sleekcms="<name>" captures and stores submissions in the CMS dashboard automatically.


Content files

Content lives in src/content/ as plain JSON. Edit any content file and save — it syncs like any other file.

Images

Images are part of content, not a separate asset pipeline. Drop a shortcut string into any image field and the sync engine resolves it to a full { url, alt } object on save:

{
  "title": "About Us",
  "image": "pexels:team meeting",
  "hero": {
    "heading": "Hello",
    "background": "unsplash:mountain sunrise|Sunrise over the mountains"
  }
}

Supported sources: unsplash, pexels, pixabay, iconify, url, cms. Append |<alt text> to set the image's alt.

Reusable images (src/content/images.json)

For images used in more than one place — logos, recurring icons, shared hero art — declare them once as handle → shortcut:

{
  "logo": "url:https://cdn.example.com/logo.svg",
  "hero": "pexels:team meeting|Our team",
  "favicon": "iconify:mdi:rocket"
}

Then reference any of them from any image field with "cms:<handle>" (e.g. "cms:logo"). Templates can also fetch the resolved object directly via getImage('logo').

Images in markdown

Inside markdown fields, the same shortcuts work in standard image syntax. Append |<alt> for alt text and a <width>x<height> token to set the rendered dimensions (defaults to 600x400):

![doctor](pexels:doctor|Smiling doctor 800x600)

Prerequisites

  • Node.js v16 or later
  • A SleekCMS account with a CLI auth token (get one here)

Troubleshooting

| Problem | Fix | |---|---| | Authentication error | Verify your token in the SleekCMS dashboard | | No files downloaded | Check your token and --env setting | | Changes not syncing | Check terminal output; changes are debounced by 5 seconds | | Wrong workspace opened | Each token maps to a specific workspace folder | | Workspace disappeared | Expected — the local workspace is wiped on Ctrl+C / x. Your edits are already on the server; re-run the CLI to pull a fresh copy. |


License

ISC — Yusuf Bhabhrawala


SleekCMS · Documentation · Dashboard