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
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: CI

# Typecheck + every test suite, including the render-dependent ones (Chromium
# is installed so the examples regression and the env-guarded CLI render tests
# actually run — a "trust the gates" repo tests its render path on every push).

on:
push:
branches: [master]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: "24"
cache: pnpm

- run: pnpm install --frozen-lockfile --ignore-scripts

- name: Install Chromium (version-matched to playwright-core)
run: pnpm exec playwright install --with-deps chromium

- name: Typecheck
run: pnpm typecheck

- name: Engine + gates
run: pnpm test

- name: Skill structural lint
run: pnpm test:lint

- name: Render extension
run: pnpm test:render
env:
KEYSTONE_RENDER_TEST: "1"

- name: Example regression (Tier 3)
run: pnpm test:examples
env:
KEYSTONE_RENDER_TEST: "1"

- name: Env-guarded CLI render tests
run: node --test test/engine/check-gates.test.mjs
env:
KEYSTONE_RENDER_TEST: "1"
82 changes: 82 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Release

# Publishes @getpipher/keystone to npm on tag push (v*).
# Uses the getpipher org secret NPM_TOKEN (granular npm token, Read-and-write,
# scoped to @getpipher, with "Bypass 2FA" — no OTP needed). Inherited by all
# getpipher repos. gh secret set NPM_TOKEN --org getpipher
#
# Idempotent: skips if the version is already on npm (safe to re-run).
# Gates on typecheck + the render-free suites before publishing. The render
# suites are intentionally NOT re-run here: the tagged commit already passed
# CI (which runs them with Chromium), and publish should not depend on a
# browser download. No build step — extensions ship raw .ts, run via tsx.

on:
push:
tags: ["v*"]
workflow_dispatch:

permissions:
contents: write # needed to create GitHub Releases on tag push

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: "24"
cache: pnpm
registry-url: https://registry.npmjs.org

- run: pnpm install --frozen-lockfile --ignore-scripts

- name: Typecheck
run: pnpm typecheck

- name: Engine + gates
run: pnpm test

- name: Skill structural lint
run: pnpm test:lint

- name: Skip if already published
id: check
run: |
set -u
ver=$(node -p "require('./package.json').version")
pkg=$(node -p "require('./package.json').name")
existing=$(npm view "$pkg@$ver" version 2>/dev/null || true)
if [ "$existing" = "$ver" ]; then
echo "::notice::$pkg@$ver already on npm — skipping publish"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "Publishing $pkg@$ver"
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Publish
if: steps.check.outputs.skip != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public

# Keep GitHub Releases in sync with npm: create a release for the tag
# (auto-generated notes). Idempotent — skips if the release already exists.
# Tag-guarded: on workflow_dispatch, GITHUB_REF_NAME is a branch, and
# creating a "release" for it would mint a bogus git tag.
- name: Create GitHub Release
if: success() && startsWith(github.ref, 'refs/tags/')
env:
GH_TOKEN: ${{ github.token }}
run: |
tag="${GITHUB_REF_NAME}"
if gh release view "$tag" >/dev/null 2>&1; then
echo "::notice::Release $tag already exists — skipping"
else
gh release create "$tag" --generate-notes --title "$tag"
fi
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,15 @@ node_modules/
keystone-report.{json,html}
keystone-audit-report.{md,json}
keystone-audit/
.keystone/
.keystone/
# examples: committed evidence (reports + screenshots); raw data stays local
!examples/**/keystone-report.json
!examples/**/keystone-report.html
!examples/**/*.png
!examples/**/keystone-audit-report.json
!examples/**/keystone-audit-report.md
examples/**/keystone-render/computed.json
examples/**/keystone-render/dom.html
examples/**/keystone-render/viewports.json
examples/**/keystone-render/clickable.json
examples/**/keystone-audit/
5 changes: 3 additions & 2 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Per the curated-rewrite policy in Keystone's design spec:
Playwright render extension, the 8 deep theme specifications, and the
engine-verified Step 7 loop are Keystone's original contribution.

Hallmark's MIT license is preserved at /tmp/hallmark/LICENSE and acknowledged
here with thanks. See README § "How Keystone relates to Hallmark" for the
Hallmark's MIT license is preserved in the upstream repository
(https://github.com/Nutlope/hallmark/blob/main/LICENSE) and acknowledged here
with thanks. See the README section "How Keystone relates to Hallmark" for the
full relationship.
140 changes: 112 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,129 @@
# @getpipher/keystone

Anti-AI-slop design skill with an **executable gate engine**. Beats Hallmark
by *enforcing* its gates instead of imagining them.
**Anti-AI-slop design skill with an executable gate engine.** Makes the UIs an
AI coding assistant generates look *made, not generated* — and can prove it.

## Status
Every LLM has on-distribution defaults: hero → 3 feature cards → CTA → footer,
Inter font, indigo gradients, glassmorphism, `hover:scale-105`, emoji icons,
re-drawn browser chrome. [Hallmark](https://github.com/Nutlope/hallmark) (MIT)
encodes the best existing rule-set against this — 58 anti-slop gates, 21
macrostructures, 50 component archetypes — but its gates are **prose**: the
model is told to "imagine the rendered output," then claims "58/58 ✓" on its
own honor. There is no enforcement.

| Layer | Version | What |
|---|---|---|
| Engine | v0.1.0 ✅ | 13 deterministic gates + Playwright render extension + CLI (merged, PR #1) |
| Skill catalog | in development | SKILL.md + references/ (this branch) |
| Vision pass | planned | @getpipher/vision integration (Plan 3) |
Keystone reuses the taxonomy (credited in [NOTICE](NOTICE)) and makes the gates
**executable**: a real Node engine parses the emitted HTML/CSS, a real headless
Chromium renders it at exact CSS px, real APCA math scores every contrast pair,
and a vision pass asks *"does this look AI-generated?"* on the actual
screenshots — the one question Hallmark cannot ask its model, because its model
never sees the page.

> The user can trust the gates ran because a script checked them, not because
> the model claimed it did.

## Install

```bash
pi install npm:@getpipher/keystone
```

Exposes the `keystone` skill (Build + Audit verbs) and the `keystone_render`
tool in one pi package.

## What you get

**`keystone build`** — a 7-step design flow: design-context gate →
macrostructure pick (21, diversification-enforced against project memory) →
theme (8 deep specs) → build → **Step 7, the engine-verified slop test**:
deterministic gates first (≤3 iterations), then the vision pass (≤2), then the
honest resolution — the stamp in your CSS says the real score, whatever it is.

## What it does
**`keystone audit <path|URL>`** — the same engine pointed at someone else's
code. Read-only, ranked punch list, four severity tiers, computed APCA numbers,
real file:line evidence. Path mode renders from disk; URL mode navigates live
(behind an SSRF guard).

`keystone build` runs a 7-step design flow. Step 7 is the differentiator:
instead of the model claiming "58/58 ✓" on its honor, a real Node engine
parses the emitted HTML/CSS, a real headless Chromium renders it at exact CSS
px, real APCA math scores contrast, and a vision model answers "does this
look AI-generated?" on a real screenshot. The report is openable. Failures
are declared, never silently claimed.
**The engine** — 46 deterministic detectors covering 48 gate numbers: banned
fonts, gradient text, 3-equal card grids, pure black/white, transition-all,
animating layout props, contrast (WCAG + APCA on every computed pair),
horizontal scroll at 320–768, two-line clickables, hero-fit-the-fold, token
discipline, the nav/footer AI fingerprints, re-drawn chrome, accent-area
budget, missing interaction states, input states, reduced-motion coverage, and
more. Every gate in [`skills/keystone/references/gates.md`](skills/keystone/references/gates.md)
is annotated with its checker — the model pre-empts the gates because it knows
what the engine will catch.

## Quick start (standalone, no pi)

```bash
npm i -g @getpipher/keystone

`keystone audit <path|URL>` points the same engine at someone else's code —
a read-only ranked punch list with computed APCA numbers and real file:line
evidence.
# audit a local page (renders it, scores 48 gates, writes a ranked report)
keystone audit ./my-page/

# audit a live URL (SSRF-guarded)
keystone audit https://example.com

# or the build CLIs directly
node engine/check-gates.mjs --html page.html --css page.css \
--render --viewports 1280,375,320,414,768 --out .
```

## Examples — the proof

Five complete builds, five different macrostructures, five themes spanning all
four genres, every one scored by its own engine:

| Build | Theme · Macro | Score |
|---|---|---|
| [Kestrel — observability](examples/01-cobalt-observability/) | Cobalt · Split Studio | **48/48** (+ self-audit 43/43) |
| [Fern & Fog — plant shop](examples/02-garden-plantshop/) | Garden · Long Document | **48/48** |
| [capstan — deploy CLI](examples/03-terminal-cli/) | Terminal · Manifesto | **48/48** |
| [Two Drum Press — riso studio](examples/04-riso-printstudio/) | Riso · Catalogue | **48/48** |
| [Lingua Potluck — language co-op](examples/05-hum-languages/) | Hum · Bento Grid | **48/48** |

Each directory carries its evidence: the openable `keystone-report.html`, the
five viewport screenshots the vision pass judged, and a `brief.md` recording
every decision and verdict — including the honest ones. See
[examples/README.md](examples/README.md).

## How Keystone relates to Hallmark

Hallmark (github.com/Nutlope/hallmark, MIT) encodes a tight anti-slop rule-set
but its gates are prose — the model "imagines the render" and self-grades.
Keystone reuses Hallmark's taxonomy (21 macrostructures, 50 archetypes, 58
gates, 4 genres, 7-step skeleton) and makes the gates executable. See NOTICE
for full attribution.
The thesis is falsifiable: run the *same brief* through both skills, with the
same model, no human intervention — then render and score both outputs with
*our* engine, and ask the vision question of both screenshots. The harness
ships in [`test/compare/`](test/compare/) (8 verbatim briefs from Hallmark's
own MIT test suite); the runs and the public gallery land in Plan 5b.

**The honesty clause:** if Hallmark beats Keystone on a brief, the gallery
shows it. A rigged demo would destroy the very thing this project sells.

## Status

| Layer | State |
|---|---|
| Engine | ✅ complete — 46 detectors / 48 gate numbers, 275 tests |
| Skill catalog | ✅ SKILL.md + 21 macros + 50 archetypes + 8 deep theme specs |
| Audit verb | ✅ path + URL mode, SSRF guard, ranked punch list |
| Examples | ✅ 5 builds, all 48/48, committed evidence |
| Comparison gallery | 🔜 Plan 5b — harness shipped, runs pending |

## Install (pi)
## Development

```bash
pi install npm:@getpipher/keystone
pnpm install
pnpm test # engine + gates (162)
pnpm test:lint # skill structural lint (103)
pnpm typecheck # extensions/render.ts
KEYSTONE_RENDER_TEST=1 pnpm test:render # render extension (needs Chromium)
KEYSTONE_RENDER_TEST=1 pnpm test:examples # example regression (needs Chromium)
```

Exposes the `keystone` skill + the `keystone_render` tool.
Releases: push a `v*` tag → CI gates → npm publish (org NPM_TOKEN).

## Repo
## Attribution & license

Private during development. Public flip + npm publish in Plan 5.
MIT — see [LICENSE](LICENSE) and [NOTICE](NOTICE). Keystone reuses Hallmark's
taxonomy (macrostructure names, archetype codes, gate concepts, the 7-step
skeleton) under MIT with credit; all prose, theme specs, tokens, the engine,
and the examples are original work.
Loading
Loading