Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .cursor/rules/no-auto-commit.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
description: Never commit or push without explicit user instruction.
alwaysApply: true
---

# No auto-commit

Never run `git commit`, `git push`, `git tag`, or `npm publish` unless the user explicitly asks (e.g. "commit this", "push", "publish").

- Show the user what changed and let them decide.
- Use `git diff` or `git status` output to summarise changes in your response instead.
- If you are about to perform a git write operation, stop and confirm first.

This applies regardless of how small, clean, or obviously-correct the change appears.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Normalize line endings to LF everywhere. A CRLF shebang in scripts/init.mjs
# would break the published bin on Unix, so this is a correctness guard, not style.
* text=auto eol=lf
39 changes: 37 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,46 @@ on:
branches: [main]

jobs:
smoke-test:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
- name: Syntax-check scripts
run: |
node --check scripts/init.mjs
node --check scripts/smoke-test.mjs
- name: Validate package.json parses
run: node -e "JSON.parse(require('fs').readFileSync('package.json','utf8'))"
- name: Preview npm package contents
run: npm run pack:dry-run

- name: E2E — install from tarball and run the bin
run: |
npm pack
mkdir -p /tmp/e2e/proj
cd /tmp/e2e
npm init -y > /dev/null
npm install "$GITHUB_WORKSPACE"/cursor-os-*.tgz
./node_modules/.bin/cursor-os init --target ./proj
./node_modules/.bin/cursor-os doctor --target ./proj
# bare invocation must print help and write nothing
./node_modules/.bin/cursor-os | grep -q "Usage:"
# programmatic import must resolve
node -e "import('cursor-os').then(m => { if (typeof m.install !== 'function') process.exit(1); }).catch(() => process.exit(1))"

smoke-test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node: [20, 22]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm test
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,15 @@ Thumbs.db
.tmp/
tmp/
*.local

# npm pack output
*.tgz

# cursor-os installed on itself (dogfooded). The files below are byte-for-byte
.cursor/agents/
.cursor/skills/
.cursor/.cursor-os-version
.cursor/rules/core.mdc
.cursor/rules/debugging.mdc
.cursor/rules/frontend.mdc
prompts/
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This repository ships Cursor OS — an installable operating layer that makes Cu
- `template/` — the kit that gets copied into other projects. Never assume a specific stack here.
- `scripts/` — the installer (`init.mjs`) and its smoke test. Node built-ins only; no dependencies.
- `examples/` — concrete examples showing what localization looks like.
- `docs/` — this repo's own decision log (not installed into user projects).
- `README.md`, `CHANGELOG.md`, `CONTRIBUTING.md` — public-facing docs.

## Working agreements
Expand Down
35 changes: 32 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,37 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

<!-- Add new changes here. -->

## [0.2.0] — 2026-06-10

First npm release: `npx cursor-os init`.

### Added

- `init` now runs a post-install health check automatically: it reports missing files, the remaining placeholder count, and the exact next step (including a Cursor CLI one-liner for running localization).
- `doctor` now reports version drift between the installed `.cursor/.cursor-os-version` marker and the current Cursor OS version, and suggests re-running `init` to pick up new files.
- Smoke tests for the localized success path ("installed and localized"), version-drift reporting, the post-install check, and the new bare-invocation behavior (126 checks).
- CI hardening: smoke tests run on Node 20 and 22 across Ubuntu and Windows; a separate job syntax-checks the scripts, validates `package.json` parses, and previews the npm package contents.
- `docs/decision-log.md` recording the CLI default, upgrade-semantics, Node-version, and localization-detection decisions.
- Programmatic API: `import { install, doctor } from "cursor-os"` now resolves via the package `exports` field.
- Runtime Node version guard: the CLI fails fast with a clear message on Node older than 20 (the `engines` field is advisory only).
- CI end-to-end packaging test: packs the tarball, installs it into a scratch project, and runs the `cursor-os` bin (`init`, `doctor`, bare help, and programmatic import).
- `.gitattributes` enforcing LF line endings — a CRLF shebang would break the published bin on Unix.
- `.gitignore` entry for `*.tgz` (local `npm pack` output).

### Changed (breaking, pre-publish)

- A command (`init` or `doctor`) is now required whenever arguments are given. Bare invocation with no arguments prints help and writes nothing — `npx cursor-os` will never modify the filesystem by accident. The previous default-to-`init` behavior (including `node scripts/init.mjs <dir>`) is removed; use `init <dir>` or `init --target <dir>`.
- Minimum supported Node.js version raised from 18 (end-of-life) to 20 (`engines` field).

### Fixed

- `doctor` could never report "installed and localized": the install-time instruction notes in `template/AGENTS.md` and `template/docs/repo-memory.md` contained the literal word "TODO", so the placeholder count never reached zero. The notes no longer use the word, and the localization prompt now instructs deleting them when done. Fresh-install placeholder counts changed from 5/12 to 4/10.
- CLI direct-invocation guard now realpath-normalizes both paths, so the CLI runs correctly when invoked through a symlinked path (e.g. macOS `/tmp` → `/private/tmp`).
- `listFiles` uses `lstat` so a symlinked directory inside `template/` can no longer cause infinite recursion.
- Removed an unused variable in the smoke test; hoisted the doctor placeholder-file list to a module constant.

- GitHub Actions smoke-test workflow.
- Pull request and issue templates for public contributions.
- README badges and unofficial-project disclaimer.
Expand All @@ -31,18 +60,18 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `03-debug-regression.md` → `prompts/debug-regression.md`
- `04-pr-review.md` → `prompts/review-pr.md`
- All template references to numbered prompt filenames updated.
- CLI restructured with explicit `init` and `doctor` subcommands; bare invocation still defaults to `init`.
- CLI restructured with explicit `init` and `doctor` subcommands.
- CLI argument parsing hardened: unknown commands, unknown options, invalid `--target`, and `doctor --dry-run` now fail without writing files.
- `doctor` now checks the full installed template file set plus the version marker, not just core files.
- Smoke test updated for new prompt file names and extended with doctor and subprocess CLI tests (112 checks).
- Smoke test updated for new prompt file names and extended with doctor and subprocess CLI tests.
- `package.json` description updated; `examples/` and public-release docs added to published files list.
- `CONTRIBUTING.md` updated with prompt naming convention and test-sync guidance.
- `AGENTS.md` updated with `examples/` in the layout and prompt naming rule.
- README install and doctor examples now use explicit Cursor OS checkout and target-project paths.

### Not done yet

- npm publishing (`npx cursor-os init`) — planned for `v0.2`.
- Interactive setup with project detection and stack presets (Next.js, Supabase, Vercel) — planned for a future release.

## [0.1.0] — 2026-06-02

Expand Down
44 changes: 23 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
An installable operating layer that makes Cursor project-aware.

[![CI](https://github.com/KingEmma7/cursor-os/actions/workflows/ci.yml/badge.svg)](https://github.com/KingEmma7/cursor-os/actions/workflows/ci.yml)
[![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)](package.json)
[![Version](https://img.shields.io/github/package-json/v/KingEmma7/cursor-os)](package.json)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

> **Unofficial project.** Cursor OS is a community-maintained installable layer for Cursor. It is not affiliated with, endorsed by, or maintained by Cursor or Anysphere.
Expand Down Expand Up @@ -50,9 +50,8 @@ The installer copies these files. The localization prompt fills them in for your
**Step 1 — Install the base OS** (the installer does this):

```bash
git clone https://github.com/KingEmma7/cursor-os.git ~/cursor-os
cd /path/to/your-project
node ~/cursor-os/scripts/init.mjs init
npx cursor-os init
```

This gives you the structure. The files contain TODO placeholders — Cursor knows to use them, but they don't yet describe your project.
Expand All @@ -71,13 +70,13 @@ Cursor OS is designed to drop into any project at any stage — greenfield or ma

```bash
# From the root of any existing project
node /path/to/cursor-os/scripts/init.mjs init
npx cursor-os init

# Preview what would be installed first
node /path/to/cursor-os/scripts/init.mjs init --dry-run
npx cursor-os init --dry-run

# Check if Cursor OS is already installed
node /path/to/cursor-os/scripts/init.mjs doctor
npx cursor-os doctor
```

For new repos, create your project normally first, then run the installer from the project root. This repository's root is the Cursor OS source project, not the installed project layout.
Expand All @@ -91,31 +90,33 @@ After localization:
- When you paste `prompts/plan-feature.md` into Cursor and describe a feature, the plan references your actual architecture and patterns without you explaining them.
- When you paste `prompts/implement-change.md`, Cursor follows your conventions without being told.

Use the Cursor OS checkout to check the installation state:
Check the installation state of any project:

```bash
node ~/cursor-os/scripts/init.mjs doctor --target /path/to/your-project
npx cursor-os doctor --target /path/to/your-project
```

Example output:

```
Cursor OS v0.1.0 — doctor
Cursor OS vX.Y.Z — doctor
Target: /path/to/your-project

ok .cursor/agents/verifier.md
ok .cursor/rules/core.mdc
ok .cursor/skills/implementation-loop/SKILL.md
ok AGENTS.md
note: 5 TODO placeholder(s) remain — run prompts/localize-cursor-os.md
note: 4 TODO placeholder(s) remain — run prompts/localize-cursor-os.md
ok docs/quality-rubric.md
ok docs/repo-memory.md
note: 12 TODO placeholder(s) remain — run prompts/localize-cursor-os.md
note: 10 TODO placeholder(s) remain — run prompts/localize-cursor-os.md
ok prompts/localize-cursor-os.md
ok .cursor/.cursor-os-version
```

(Abbreviated — `doctor` lists every installed file. The `note:` lines flag the unfilled TODO placeholders in `AGENTS.md` and `docs/repo-memory.md` that localization resolves.)
(Abbreviated — `doctor` lists every installed file; the version shown matches your checkout. The `note:` lines flag the unfilled TODO placeholders in `AGENTS.md` and `docs/repo-memory.md` that localization resolves. Once localization fills them, `doctor` reports "installed and localized". If the install came from an older Cursor OS version, `doctor` also notes the drift so you can re-run `init` to pick up new files.)

`init` runs this same health check automatically after installing, so you always see the placeholder count and the next step without a separate command.

## What Cursor loads automatically vs. what you paste

Expand Down Expand Up @@ -145,27 +146,25 @@ See the [prompts guide](template/prompts/README.md) (installs as `prompts/README

Custom instruction sets or system-prompt files (sometimes called "behavioral guideline packs") tell Cursor how to behave generically. Cursor OS does something different: it tells Cursor about *this* project specifically. The two are complementary. Cursor OS files live in the repo, travel with the code, and get updated as the project evolves.

## Current status
## Installing from a checkout

Cursor OS is **not published to npm yet**. For v0.1, clone the repo and run the installer script directly.
If you prefer not to use npm, clone the repo and run the installer script directly — it behaves identically:

```bash
git clone https://github.com/KingEmma7/cursor-os.git ~/cursor-os
cd your-project
node ~/cursor-os/scripts/init.mjs init
```

`npx cursor-os init` is planned for a future release.

Before publishing, run through [`RELEASE_CHECKLIST.md`](RELEASE_CHECKLIST.md). The checklist covers release readiness, package metadata, installer checks, template quality, and `npm pack --dry-run`.
Maintainers: before tagging a release, run through [`RELEASE_CHECKLIST.md`](RELEASE_CHECKLIST.md).

## CLI reference

```
node scripts/init.mjs [command] [target] [options]
npx cursor-os <command> [target] [options]

Commands:
init Install Cursor OS into the target directory (default)
init Install Cursor OS into the target directory
doctor Check whether Cursor OS is installed in the target directory

Options:
Expand All @@ -175,6 +174,8 @@ Options:
-h, --help Show this help
```

A command is required: bare invocation (`npx cursor-os` with no arguments) prints help and never writes files. For a target directory named `init` or `doctor`, or one whose name starts with `-`, use the explicit form `init --target <dir>`. Requires Node.js 20 or newer.

## What gets installed

```
Expand Down Expand Up @@ -217,8 +218,9 @@ prompts/

## Roadmap

- `v0.1` — installable operating layer: contract, rules, skills, verifier, docs, prompts, installer, doctor command.
- `v0.2` — npm publishing (`npx cursor-os init`), interactive setup with project detection, stack presets (Next.js, Supabase, Vercel).
- `v0.1` — installable operating layer: contract, rules, skills, verifier, docs, prompts, installer, doctor command. ✅
- `v0.2` — npm publishing (`npx cursor-os init`), safer CLI defaults, post-install health check, version-drift detection. ✅
- Next — interactive setup with project detection, stack presets (Next.js, Supabase, Vercel).

## Contributing

Expand Down
13 changes: 12 additions & 1 deletion RELEASE_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Use this checklist before tagging a public release or publishing Cursor OS to np
## Installer and CLI

- [ ] `node scripts/init.mjs --help` shows `init`, `doctor`, `--target`, `--dry-run`, and `--version`.
- [ ] `node scripts/init.mjs` with no arguments prints help and writes nothing.
- [ ] `node scripts/init.mjs --version` matches `package.json`.
- [ ] `node scripts/init.mjs init --dry-run --target <tmp>` writes nothing.
- [ ] `node scripts/init.mjs init --target <tmp>` installs the expected file set.
Expand All @@ -41,16 +42,26 @@ Use this checklist before tagging a public release or publishing Cursor OS to np

- [ ] `npm test` passes.
- [ ] `node -e "JSON.parse(require('fs').readFileSync('package.json','utf8'))"` succeeds.
- [ ] No hardcoded version strings in `README.md` or `examples/` (the badge is dynamic; example outputs use `vX.Y.Z`). Versions appear only in `package.json` and `CHANGELOG.md`.
- [ ] Final old-branding search has no matches outside historical changelog context.
- [ ] Final search has no numbered prompt references outside historical changelog context.

## Packaging integrity

- [ ] `npm pack`, install the tarball into a scratch project, and run the bin: `init`, `doctor`, and bare invocation all behave. (CI runs this on every push.)
- [ ] `import('cursor-os')` resolves and exposes `install` and `doctor`.
- [ ] `head -1 scripts/init.mjs` is exactly `#!/usr/bin/env node` (no CRLF, no BOM).
- [ ] No stray `*.tgz` files tracked in git.

## npm publishing

Only after all previous sections pass:

- [ ] npm account has 2FA enabled (at minimum for writes).
- [ ] Confirm the intended version.
- [ ] Update `CHANGELOG.md` with release date.
- [ ] Create a git tag for the release.
- [ ] Run `npm publish --dry-run`.
- [ ] Run `npm publish` only when intentionally publishing.
- [ ] After publish, update README install examples from local script usage to `npx cursor-os init`.
- [ ] README install examples use the `npx cursor-os` form (done in the release commit, not after).
- [ ] After publish, verify with `npm view cursor-os` and `npx cursor-os@latest init --dry-run --target <tmp>`.
Loading
Loading