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

cans-spec

v0.5.0

Published

Canonical Agent-Native Spec — the outline is the spec, the state, and the task board

Readme


The pitch

Your spec is a markdown file with bullets. Your AI agent reads it and knows everything. Your state lives in checkboxes. Your coordination protocol is indentation and see: links. Your transport layer is git.

There is no registry. There is no adapter. There is no artifact DAG. There is no Zod schema validating your English sentences. There is no telemetry phoning home. There is no 4-phase pipeline gating your Tuesday afternoon.

There is a file. You edit it. cans check tells you if it's healthy. That's the whole product.


Why this exists

We used OpenSpec. It's a fine project. It also ships 200+ files, 30+ tool adapters, a 4-artifact pipeline, Zod validation, DAG resolution, delta-spec merges, SHALL/MUST keyword enforcement, scenario counting, a telemetry system, a store/registry layer, and burns 50k–100k tokens per invocation.

We tried deleting things. Everything kept working.

So we kept deleting.

| OpenSpec ships | CANS ships | |---|---| | 4-artifact pipeline (proposal → specs → design → tasks) | Edit the spec. ADR records why. Task tracks work. | | Zod schemas + DAG resolver + 30 adapter files | Structural lint on markdown bullets | | Delta-spec merge engine at archive time | see: references + git diff | | SHALL / MUST / WHEN / THEN / GIVEN keywords | Natural language. Dense bullets. | | ~36,000 tokens of agent instructions across 12 skills | ~800 tokens. One file. Loaded once. | | openspec status --json to query project state | Agents read the file. The file IS the state. | | 30+ tool-specific command formatters | One prompt block. String-replace the tool name. | | YAML frontmatter + markdown headers + requirement blocks | Bullets. Just bullets. | | Custom merge logic for spec reconciliation | Git merges. Humans resolve conflicts. | | Telemetry, stores, registries, profiles | None. | | 50,000–100,000 tokens per invocation | ~800 tokens, loaded once |

OpenSpec is a framework. CANS is a file with a linter.


See it in action

You: cans init
     ✓ Created cans/ with 7 spec files, _adr/, _tasks/, _collab/

You:  (write your spec as dense bullets)
      - Authentication
        - Sign up
          - Email: requires verification
          - Google: uses provider verification
        - Sessions
          - Expire after 24 hours
          - Refresh allowed for 30 days

You: cans check
     ✓ 7 files, 42 nodes, max depth 3
     ✓ 3 see: refs, 0 broken, 0 deep hops
     ✓ back-pointers: 3/3 current
     0 errors, 0 warnings.

You: cans new task add-dark-mode
     ✓ Created _tasks/add-dark-mode.md

You:  (agent implements, checks off tasks, edits specs directly)

You: cans done add-dark-mode
     ✓ Archived to _tasks/_archive/2025-09-03-add-dark-mode.md

No /opsx:propose. No /opsx:apply. No /opsx:archive. No pipeline. No phases. You edit the file. The agent edits the file. cans check keeps it honest.

Bullets. Indented. Dense. No special syntax. No keywords. No scenario blocks.

- Authentication
  - Sign up
    - Email
      - Requires verification
      - Creates user account
    - Google
      - Uses provider verification
  - Sessions
    - Expire after 24 hours
    - Refresh allowed for 30 days
  - Passwords
    - Never stored in plaintext
    - Minimum 12 characters

Reference, don't duplicate:

# in 04-api.md
- Authentication
  - Session rules: see 02-authentication.md#Sessions
  - Requires Bearer token

That's it. That's the whole spec format. Your agent reads this and knows what to build.


Five principles

1. Dense over verbose. Every bullet earns its place. No filler levels. No manufactured identifiers.

# bad                          # good
- Authentication               - Authentication
  - Capability                   - Sign up
    - Behavior
      - Sign up

2. Canonical over duplicated. Every concept has one home. Everywhere else uses see:.

3. One hop. Never chain. A→B is fine. A→B→C is forbidden. cans check catches it.

4. Unknowns are first-class. TBD is valid. Don't guess. Don't block. Mark it, move on.

5. Structure emerges from subject. No fixed hierarchy. No required vocabulary. No kebab-casing reality.


What CANS does NOT do

This is the most important section.

  • ❌ No schema.yaml / artifact DAG / topological sort
  • ❌ No Zod validation of requirement text
  • ❌ No SHALL / MUST keyword enforcement
  • ❌ No scenario counting (WHEN / THEN / GIVEN)
  • ❌ No 30 tool adapters / adapter registry
  • ❌ No YAML frontmatter in spec files
  • ❌ No "delta operations" (ADDED / MODIFIED / REMOVED)
  • ❌ No telemetry. None. Ever.
  • ❌ No store / registry system for multi-repo
  • ❌ No requirement-block parsing
  • ❌ No phase gates (proposal → specs → design → tasks)
  • ❌ No LLM-powered anything (CANS is deterministic; LLMs use CANS)
  • ❌ No auto-fixing (flags only, human decides)
  • ❌ No plugin system (10 commands, no extension points)
  • ❌ No web UI / dashboard
  • ❌ No database backend (files ARE the state)
  • ❌ No merge pipeline (agent edits specs directly)
  • ❌ No versioned schema migrations (delete a config key = disable that check)

CANS is advisory, not coercive. The outline is the contract. cans check catches drift. Humans resolve it.


Install

No build step. Source IS distribution. Two runtimes are supported — Bun is the primary, Node.js is the fallback (issue #12):

  • Bun ≥ 1.0 (recommended, primary) — fastest path, used automatically when Bun is on your PATH.
  • Node.js ≥ 23.2 (fallback) — for Termux / Android harnesses and any environment without Bun. Termux: pkg install nodejs (ships Node 26.x ✓). Node's builtin TypeScript stripping runs the sources directly; running from a source checkout also works on Node ≥ 22.6 via --experimental-strip-types.

npm

npm install -g cans-spec

Bun

bun install -g cans-spec

One-shot, no install

npx -p cans-spec cans init
# or, with Bun installed:
bunx cans-spec init

All three give you the same cans command:

cd your-project
cans init

Done. You have a cans/ directory. Start writing bullets.

How to use it

  1. Scaffold — cans init creates cans/ with 7 spec files, _adr/, _tasks/, _collab/. Use cans init --flat for a flat layout, --bare for the minimal skeleton, --tool claude to also emit CLAUDE.md.
  2. Write your spec as dense bullets — hierarchy is indentation, cross-links are see: references. The outline is the spec; there is nothing else to learn.
  3. Check health — cans check lints structure, broken refs, deep hops, redundancy, style, and overflow. cans check --fix repairs back-pointers. Exit codes: 0 clean · 1 warnings · 2 errors — agents read $?, skip parsing.
  4. Track work — cans new task add-dark-mode creates a task, cans status shows the board, cans done add-dark-mode archives it (it blocks on ← @human gates until a human signs off).
  5. Mind the budget — cans budget read <concept> gives your agent a token-budgeted reading plan; cans budget write <concept> says what it may edit.
  6. Interoperate — cans export logseq --from cans and cans import logseq <path> round-trip OPML / Dynalist, Logseq, and Obsidian. State lives in git; the transport layer is a plain text format your tools already read.

Everything else — ADRs, ownership arrows (← agent-1, ← @human), rules in _rules.yaml — is documented inline by the scaffolded files.


Commands

cans init          scaffold workspace
cans check         validate everything (structure, refs, style, redundancy, overflow)
cans new adr       create a decision record
cans new task      create a task file
cans done          archive completed task (blocks on ← @human gates)
cans status        workspace summary
cans budget read   token-budgeted reading plan for a concept
cans budget write  what you can / can't edit for a concept
cans import        bring in OPML / Logseq / Obsidian
cans export        push out to OPML / Logseq / Obsidian

Every command supports --json for agent consumption.

cans check --json
cans budget read "sessions" --limit 2000 --json
cans status --json

How agents work with CANS

Agents read one file: cans/AGENTS.md. It's ~800 tokens. Here's the gist:

Reading: Find the concept → read its canonical home → follow see: (one hop only) → read surrounding hierarchy for context.

Writing: One canonical home per concept. Reference, don't duplicate. Preserve real identifiers. Mark unknowns as TBD. Smallest correct change.

Deciding: Create an ADR. ADRs are permanent. Specs are the truth. ADRs record WHY.

Tracking: Create a task. Agent edits specs directly. When done: cans done <name>. Blocks until ← @human gates are checked.

Token budget: Before reading: cans budget read "<concept>" --json. Read ONLY the files in the plan. Before writing: cans budget write "<concept>" --json. Only edit files in canEdit.

That's the entire agent instruction surface. No 12 skills. No 30 adapters. No slash commands.


Validation

cans check runs five deterministic engines. No ML. No LLM. No embeddings.

| Engine | Catches | |---|---| | Structure | Node length, depth, sibling count, single-child collapse, empty nodes | | Style | Sibling vs nested grouping, shared prefix detection | | References | Broken see:, deep hops (A→B→C), self-refs, orphans, stale back-pointers | | Redundancy | Word frequency, phrase overlap, fuzzy typos, cross-file duplication | | Overflow | Code fences, tables, oversized nodes that belong in separate files |

Configure in cans/_rules.yaml. Delete a key to disable that check. No migration.

cans check                  # human-readable: one line per pattern, count prefixes,
                            # root-cause grouping, timing on the summary line
cans check --json           # machine-readable: sections → {file, line, rule, detail}
cans check --show redundancy  # expand a folded section (structure|style|refs|
                            #   redundancy|overflow|all — comma-separated list works)
cans check --fix            # rebuild back-pointer comments (nothing else)
cans check --strict         # warnings flip `ok` to false
cans check 04-api.md        # single file

The default report groups repeated findings: 61× <min children (2/3) instead of 61 identical lines, 91× missing file with per-target counts instead of 91 lines + 91 fix hints. Fix hints appear once per pattern; every file:line stays present in compact comma lists. Exit codes: 0 clean · 1 warnings · 2 errors.


Workspace layout

cans/
├── _rules.yaml              # validation config
├── AGENTS.md                # ~800-token agent instructions
├── 00-overview.md
├── 01-architecture.md
├── 02-authentication.md
├── 03-data.md
├── 04-api.md
├── 05-frontend.md
├── 06-operations.md
├── _adr/                    # decisions (permanent)
│   ├── 001-css-variables-over-tailwind.md
│   └── 002-postgres-over-mysql.md
├── _tasks/                  # work tracking (transient)
│   └── add-dark-mode.md
└── _collab/                 # handoffs, conflicts, decision index

How we compare

vs. OpenSpec — Comprehensive but heavy. 200+ files, 4-artifact pipelines, 30+ adapters, 50k–100k tokens per invocation. CANS is 1080 lines, zero deps, 800 tokens. You don't need a framework. You need a file.

vs. Spec Kit (GitHub) — Rigid phase gates, Python setup, lots of Markdown. CANS has no phases. You edit the spec. That's the workflow.

vs. Kiro (AWS) — Locked to their IDE, limited to Claude. CANS is a CLI that reads markdown files. Works with any agent, any editor, any model.

vs. nothing — AI coding without specs means vague prompts and drift. CANS gives you a contract in 800 tokens of agent instructions instead of 36,000.


Requirements

  • Bun ≥ 1.0 (primary) or Node.js ≥ 23.2 (fallback, no Bun needed — Termux: pkg install nodejs)
  • Git (for coordination; not required by CANS itself)
  • An AI agent that can read markdown (all of them)

No Python. No package-lock.json. No build step. The dependencies field in package.json does not exist — zero runtime dependencies on both runtimes.


Contributing

The entire codebase is ~1100 lines of TypeScript across 20 files. Read it in an afternoon.

  • bun test runs the suite on the primary runtime; npm run test:node runs the same suite on the Node fallback (node:test via a tiny bun:test compat shim in test/node-compat.ts)
  • CI runs both (test-bun + test-node matrix on Node 22/24)
  • All runtime-sensitive IO goes through one shim, src/core/runtime.ts — the only file allowed to touch Bun APIs; a self-audit test keeps it that way
  • No build step. Edit src/, run bun test, done.
  • PRs that add features get closed. PRs that delete code get merged.
  • If you want a new command, open an issue and justify it. Most get rejected. That's the point.

License

MIT