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
35 changes: 33 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Publish Docker image
name: Verify and Publish Docker image

on:
push:
branches: ['main']
pull_request:
release:
types: [published]

Expand All @@ -11,7 +12,37 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
verify:
name: Verify (${{ matrix.os }}, Node ${{ matrix.node-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [18, 20, 24]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test

- name: Type-check
run: npm run build

build-and-push-image:
if: github.event_name != 'pull_request'
needs: verify
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -40,4 +71,4 @@ jobs:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
labels: ${{ steps.meta.outputs.labels }}
32 changes: 32 additions & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Credits

---

## [obra/superpowers](https://github.com/obra/superpowers)

**License:** MIT © Jesse Vincent

Hyperstack's gate skill enforcement pattern - Iron Laws, 1% Rule, rationalization tables, `<HARD-GATE>` blocks, and the "spirit of the rule is the letter of the rule" clause - was adopted from superpowers. The core insight is that AI compliance gates need to be written adversarially to survive model pressure. We agreed, and built on it.

Five Hyperstack workflow skills (`ship-gate`, `debug-discipline`, `run-plan`, `deliver`, `forge-plan`) are structurally derived from their superpowers equivalents. They have since been extended with MCP integration, DESIGN.md pipeline hooks, and Hyperstack-specific domain content.

Everything else - the MCP server, 11 plugins, 79 tools, designer engine, DESIGN.md pipeline, React Flow / Motion / Lenis / Echo / Go / Rust / design tokens domain content, shadcn expert, and SessionStart hook - has no equivalent in superpowers and is original work.

---

## Research and Prior Art

The designer plugin's knowledge base is distilled from publicly available design research and real-world design systems:

- **Cognitive psychology** - Fitts's Law, Hick's Law, Miller's Law, Gestalt principles, Von Restorff effect, Serial Position effect, Peak-End Rule, Doherty Threshold
- **UX heuristics** - Jakob Nielsen's 10 usability heuristics
- **Typography and layout** - Bringhurst's *Elements of Typographic Style*, Müller-Brockmann's grid systems
- **Design systems** - Patterns observed across Linear, Stripe, Vercel, Apple HIG, Carbon, shadcn, Notion, Supabase, and Figma - used as reference, not reproduced

The design-patterns-skill draws on principles from:

- *Clean Code* - Robert C. Martin
- *The Pragmatic Programmer* - Hunt and Thomas
- *Code Complete* - Steve McConnell
- *Refactoring* - Martin Fowler
- *Design Patterns* - Gang of Four
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,15 @@ The MCP server gives you tools. The skills give you discipline. Install both:
git clone https://github.com/orkait/hyperstack.git ~/.claude/skills/hyperstack
```

After installing, the SessionStart hook (at `hooks/session-start`) will auto-inject the `using-hyperstack` skill into every session. No manual activation needed.
After installing, the SessionStart hook (at `hooks/session-start.mjs`) will auto-inject the `using-hyperstack` skill into every session. No manual activation needed.

### 💻 From source

```bash
git clone https://github.com/orkait/hyperstack.git
cd hyperstack
npm install
node bin/hyperstack.mjs # same entrypoint the published bin uses
npm start # runs via tsx, no build step
npm run dev # watch mode
npm run build # tsc --noEmit (type-check only, no dist output)
Expand Down Expand Up @@ -130,7 +131,7 @@ Your AI calls these for exact API data. Memory is not acceptable. Every plugin s

Markdown with adversarial enforcement. Each gate skill has an Iron Law, a 1% Rule, and a rationalization table that names the exact excuses your AI will use to skip the gate and counters each one.

The `using-hyperstack` skill is injected into every session by `hooks/session-start`. You do not have to invoke it manually.
The `using-hyperstack` skill is injected into every session by `hooks/session-start.mjs`. You do not have to invoke it manually.

<details>
<summary><strong>🧱 Core (13)</strong> - workflow, discipline, gates used on every task</summary>
Expand Down Expand Up @@ -361,9 +362,12 @@ Only invoked when the user explicitly chose shadcn in designer Q11b.

## 🏗️ Architecture

Everything runs via `tsx` at runtime. No `dist/` output, no build step for deployment - just type checking.
Everything runs from source. The published `hyperstack` bin is a small Node wrapper that boots `src/index.ts` through `tsx`, and Docker uses the same source-first runtime. No `dist/` output, no build step for deployment - just type checking.

```text
bin/
└── hyperstack.mjs # Published CLI wrapper - boots src/index.ts via tsx

src/
├── index.ts # Entry - creates McpServer, loads all 11 plugins
├── registry.ts # Plugin interface + loadPlugins()
Expand All @@ -389,7 +393,8 @@ skills/

hooks/
├── hooks.json # Registers the SessionStart hook
├── session-start # Bash script that injects using-hyperstack as context
├── session-start.mjs # Cross-platform hook entrypoint for auto-injecting using-hyperstack
├── session-start # Legacy shell helper
└── run-hook.cmd # Windows dispatcher

scripts/
Expand Down Expand Up @@ -433,3 +438,9 @@ npm run build # tsc --noEmit
## 📄 License

MIT © [Orkait](https://github.com/orkait)

---

## 🙏 Acknowledgements

The enforcement philosophy behind Hyperstack's gate skills - Iron Laws, 1% Rule, rationalization tables - was adopted from [obra/superpowers](https://github.com/obra/superpowers) (MIT © Jesse Vincent). We agreed with how it frames AI compliance: adversarially, not politely. See [CREDITS.md](./CREDITS.md).
43 changes: 43 additions & 0 deletions bin/hyperstack.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env node

import { spawn } from "node:child_process";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const binDir = dirname(fileURLToPath(import.meta.url));
const rootDir = resolve(binDir, "..");
const entrypoint = resolve(rootDir, "src/index.ts");
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
const tsxLoaderArgs = nodeMajor >= 20 ? ["--import", "tsx"] : ["--loader", "tsx"];

const child = spawn(process.execPath, [...tsxLoaderArgs, entrypoint, ...process.argv.slice(2)], {
cwd: rootDir,
env: process.env,
stdio: "inherit",
});

const forwardSignal = (signal) => {
if (!child.killed) {
child.kill(signal);
}
};

process.on("SIGINT", () => forwardSignal("SIGINT"));
process.on("SIGTERM", () => forwardSignal("SIGTERM"));

child.on("error", (error) => {
console.error("Failed to start hyperstack:", error);
process.exit(1);
});

child.on("exit", (code, signal) => {
if (signal === "SIGINT") {
process.exit(130);
}

if (signal === "SIGTERM") {
process.exit(143);
}

process.exit(code ?? 1);
});
2 changes: 1 addition & 1 deletion hooks/hooks-cursor.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"hooks": [
{
"type": "command",
"command": "\"${CURSOR_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
"command": "node \"${CURSOR_PLUGIN_ROOT}/hooks/session-start.mjs\"",
"async": false
}
]
Expand Down
2 changes: 1 addition & 1 deletion hooks/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"hooks": [
{
"type": "command",
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\"",
"async": false
}
]
Expand Down
35 changes: 35 additions & 0 deletions hooks/session-start.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env node

import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const scriptDir = dirname(fileURLToPath(import.meta.url));
const pluginRoot = dirname(scriptDir);

function emit(payload) {
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
}

try {
const skillPath = join(pluginRoot, "skills", "using-hyperstack", "SKILL.md");
const skillContent = readFileSync(skillPath, "utf8");
const sessionContext = `<EXTREMELY_IMPORTANT>\nYou have Hyperstack.\n\n**Below is the full content of your 'hyperstack:using-hyperstack' skill - your introduction to using Hyperstack. For all other skills, use the 'Skill' tool:**\n\n${skillContent}\n</EXTREMELY_IMPORTANT>`;

if (process.env.CURSOR_PLUGIN_ROOT) {
emit({ additional_context: sessionContext });
} else if (process.env.CLAUDE_PLUGIN_ROOT && !process.env.COPILOT_CLI) {
emit({
hookSpecificOutput: {
hookEventName: "SessionStart",
additionalContext: sessionContext,
},
});
} else {
emit({ additionalContext: sessionContext });
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
process.stderr.write(`${JSON.stringify({ error: `Hyperstack session-start hook failed: ${message}` })}\n`);
process.exit(1);
}
10 changes: 5 additions & 5 deletions install.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Clone this repository into the appropriate skills directory for your environment
| **OpenCode / Codex** | Follow the platform's file-based skill installation path |
| **Other** | If your environment supports local file-based skills, clone the repo to the standard skills/extensions directory for your platform. If not supported, you may skip this step and proceed to installing the MCP server, but note that the SessionStart hook and adversarial enforcement will not activate. |

The repository includes a `hooks/session-start` script that injects the `using-hyperstack` skill content into every session automatically. This is how the enforcement (Iron Laws, 1% Rule, rationalization tables) reaches the agent without manual invocation. On platforms that support `.claude-plugin/hooks.json`, this happens automatically. On others, the skill is still readable but the hook will not fire.
The repository includes a `hooks/session-start.mjs` entrypoint that injects the `using-hyperstack` skill content into every session automatically. This is how the enforcement (Iron Laws, 1% Rule, rationalization tables) reaches the agent without manual invocation. On platforms that support `.claude-plugin/hooks.json`, this happens automatically. On others, the skill is still readable but the hook will not fire.

## Step 3: Configure the MCP Server

Expand Down Expand Up @@ -60,7 +60,7 @@ The `--memory=256m` and `--cpus=0.5` flags are intentional resource limits. Do n

### Option B: Local Node (Fallback)

If Docker is NOT available, run the server locally using Node 18+ and `tsx`:
If Docker is NOT available, run the server locally using Node 18+:

1. Navigate to the directory where you cloned the repository (e.g., `~/.claude/skills/hyperstack`)
2. Run `npm install` in that directory
Expand All @@ -70,14 +70,14 @@ If Docker is NOT available, run the server locally using Node 18+ and `tsx`:
{
"mcpServers": {
"hyperstack": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/hyperstack/src/index.ts"]
"command": "node",
"args": ["/absolute/path/to/hyperstack/bin/hyperstack.mjs"]
}
}
}
```

There is no build step. The server runs directly from source via `tsx`.
There is no build step. The wrapper starts the server directly from source via `tsx`.

## Step 4: Verify Installation

Expand Down
Loading
Loading