diff --git a/README.md b/README.md
index 1e1c9cb..9098573 100644
--- a/README.md
+++ b/README.md
@@ -10,16 +10,28 @@ claude plugin install crew@johantor
claude plugin install board@johantor
```
+You can also install from the UI: run `/plugin` in Claude Code and browse to **Discover**.
+
+Site:
+
| Plugin | What it does | Repository |
|---|---|---|
| `crew` | A `lead` agent plans the work and delegates each step to specialists, behind hook-enforced guardrails and one review gate. | [johantor/crew](https://github.com/johantor/crew) |
| `board` | A local kanban board of every Claude Code session: what needs you, what is running, what you closed today. | [johantor/board](https://github.com/johantor/board) |
+## Updating and uninstalling
+
+```bash
+claude plugin marketplace update johantor # refresh the catalog
+claude plugin update crew@johantor # update a plugin
+claude plugin uninstall crew@johantor # remove it
+```
+
## Moving from `johantor/crew`
-The marketplace used to live in `johantor/crew`. The marketplace name and the install ids are
-the same, so only the source changes. Removing a marketplace uninstalls its plugins, so
-install the ones you use again:
+The marketplace used to live in `johantor/crew`. That source is gone. The marketplace name and
+the install ids are the same, so only the source changes. Removing a marketplace uninstalls its
+plugins, so install the ones you use again:
```bash
claude plugin marketplace remove johantor
@@ -27,10 +39,17 @@ claude plugin marketplace add johantor/plugins
claude plugin install crew@johantor # and board@johantor
```
-`johantor/crew` keeps a copy of the catalog for now, so the old source still works.
-
## Maintaining
A plugin entry's `name` and `description` copy the plugin's own `plugin.json`, which is
canonical. CI (`validate.yml`) fetches each `plugin.json` from its repository and fails on a
mismatch, so update the entry here when a plugin changes its description.
+
+The site is `docs/`, served by GitHub Pages from `main`. `docs/style.css` is a copy of the crew
+site's stylesheet (`johantor/crew`, `docs/style.css`), so keep the two in step; marketplace-only
+styles live in `docs/plugins.css`.
+
+## License
+
+[Apache-2.0](LICENSE). The plugins collect no data and send nothing to the maintainers. An
+independent project, not affiliated with or endorsed by Optimizely or Anthropic.
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..016e8b9
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,163 @@
+
+
+
+
+
+johantor — Claude Code plugins: crew and board
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Claude Code plugin marketplace
+
Work in Claude Code like a team.
+
Two plugins, one marketplace. crew splits a feature into planned
+ lanes behind one review gate. board shows every session on your machine, so
+ you see which one needs you.
+
+
+
$ claude plugin marketplace add johantor/plugins
+$ claude plugin install crew@johantor
+$ claude plugin install board@johantor
+
Copy commands
+
+
Install one or both. Or run /plugin in Claude Code and open Discover .
+
+
+
+
+
+
+
+
+
The plugins
+
Pick what you need.
+
Each plugin lives in its own repository, with its own site, releases and changelog.
+
+
+
+ crew.
+ An agent team for Optimizely work. A lead plans the work and delegates each
+ step to specialists that know the CMS they work in.
+
+ Specialists per lane. Backend, frontend, tests, design, review and more.
+ Hooks, not promises. Guardrails in code keep each worker in its lane.
+ One review gate. Nothing ships until it says go. It pays down tech debt too.
+
+$ claude plugin install crew@johantor
+
+
+
+ board.
+ A local kanban board of every Claude Code session: what needs you, what is running, and
+ what you closed today.
+
+ Needs me first. Permission prompts and questions move to the front.
+ Back in with one click. Copy resume copies the command to reopen a session.
+ Local only. A Node server on 127.0.0.1. Nothing is sent anywhere.
+
+$ claude plugin install board@johantor
+
+
+
+
+
+
+
+
+
+
+
Better together.
+
Sessions that run a crew: agent get a Crew badge on the board, and each
+ subagent shows on the card with its current tool.
+
+
Install both
+
+
+
+
+
+
+
+
Manage
+
Update and remove.
+
+
+ claude plugin marketplace update johantorRefresh the catalog.
+ claude plugin update crew@johantorUpdate a plugin. The same for board@johantor.
+ claude plugin uninstall crew@johantorRemove a plugin.
+
+
Added the marketplace from johantor/crew before? That source is gone.
+ Run claude plugin marketplace remove johantor, then the install commands . Removing a
+ marketplace uninstalls its plugins, so install them again.
+
+
+
+
+
+
+
+
+
diff --git a/docs/plugins.css b/docs/plugins.css
new file mode 100644
index 0000000..3bc6d29
--- /dev/null
+++ b/docs/plugins.css
@@ -0,0 +1,16 @@
+ /* Marketplace-only layouts. style.css stays an exact copy of the crew site's, so additions live here. */
+
+ /* plugins: one card per plugin */
+ .picks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}
+ .pick{min-width:0;display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);
+ border-radius:24px;padding:32px 32px 28px}
+ .pick .brand{font-size:34px}
+ .pick > p{margin:14px 0 0;color:var(--muted)}
+ .pick .checks{margin:20px 0 28px}
+ .pick pre{margin:auto 0 22px;background:var(--term);border-radius:14px;padding:14px 18px;
+ font:13.5px/1.8 var(--mono);color:#e8e8f4;overflow-x:auto}
+ .pick .p{color:#8c93ff;user-select:none}
+ .pick .cta{margin-top:0}
+
+ @media (max-width:900px){.picks{grid-template-columns:1fr}}
+ @media (max-width:640px){.pick{padding:24px}}
diff --git a/docs/style.css b/docs/style.css
new file mode 100644
index 0000000..8a06029
--- /dev/null
+++ b/docs/style.css
@@ -0,0 +1,174 @@
+ /* A copy of the crew site's stylesheet (johantor/crew, docs/style.css): keep the two in step. */
+ :root{
+ --bg:#f6f4ef;
+ --surface:#ffffff;
+ --soft:#efece4;
+ --line:#e2ded4;
+ --ink:#0c0c1d;
+ --text:#2a2b3a;
+ --muted:#5d6070;
+ --accent:#2f3bff;
+ --accent-ink:#ffffff;
+ --accent-soft:#e3e4ff;
+ --go:#0e6b55;
+ --go-soft:#ddf1ea;
+ --warm:#b4541f;
+ --warm-soft:#fbe6d9;
+ /* System fonts only: no third-party font request, so the site sends visitors nowhere. */
+ --display:"Inter Tight","Inter",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
+ --sans:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
+ --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
+ --wrap:1120px;
+ /* Terminal panels stay dark in both schemes: their text colour is fixed. */
+ --term:#0c0c1d;
+ }
+ @media (prefers-color-scheme:dark){
+ :root{
+ --bg:#0e0f1a; --surface:#161827; --soft:#1c1e30; --line:#2a2d44;
+ --ink:#f4f3ff; --text:#d9d9e8; --muted:#9b9db2;
+ --accent:#8c93ff; --accent-ink:#0e0f1a; --accent-soft:#23264a;
+ --go:#5fd3b0; --go-soft:#163a31; --warm:#f2a06e; --warm-soft:#3a2418;
+ --term:#05060c;
+ }
+ }
+ *{box-sizing:border-box}
+ html{scroll-behavior:smooth}
+ /* Anchor targets clear the sticky nav. */
+ [id]{scroll-margin-top:88px}
+ body{margin:0;background:var(--bg);color:var(--text);font:17px/1.6 var(--sans);
+ -webkit-font-smoothing:antialiased}
+ .wrap{max-width:var(--wrap);margin:0 auto;padding:0 24px}
+ h1,h2,h3{color:var(--ink);font-family:var(--display);margin:0}
+ a{color:var(--accent);text-decoration:none}
+ a:hover{text-decoration:underline;text-underline-offset:3px}
+ code{font-family:var(--mono);font-size:.86em}
+
+ /* nav */
+ nav{position:sticky;top:0;z-index:20;background:color-mix(in srgb,var(--bg) 88%,transparent);
+ backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
+ nav .wrap{display:flex;align-items:center;gap:28px;height:64px}
+ .brand{font-family:var(--display);font-weight:900;font-size:24px;letter-spacing:-.04em;color:var(--ink)}
+ .brand i{font-style:normal;color:var(--accent)}
+ nav ul{display:flex;gap:24px;list-style:none;margin:0 0 0 auto;padding:0;flex-wrap:wrap}
+ nav a{color:var(--text);font-size:15px;font-weight:500}
+
+ /* hero */
+ header.hero{padding:96px 0 72px}
+ .eyebrow{font-family:var(--sans);font-weight:700;font-size:13px;letter-spacing:.14em;
+ text-transform:uppercase;color:var(--accent);margin-bottom:22px}
+ h1{font-weight:900;font-size:clamp(2.8rem,8.4vw,6.2rem);line-height:.95;letter-spacing:-.045em;max-width:14ch}
+ h1 em{font-style:normal;color:var(--accent)}
+ .lede{max-width:40rem;margin:30px 0 0;font-size:clamp(1.08rem,2.1vw,1.3rem);color:var(--muted)}
+ .lede strong{color:var(--ink);font-weight:700}
+
+ .install{max-width:620px;margin:40px 0 0;background:var(--term);border:1px solid var(--line);border-radius:18px;overflow:hidden}
+ .install pre{margin:0;padding:22px 24px 8px;font-family:var(--mono);font-size:14px;line-height:2;
+ color:#e8e8f4;overflow-x:auto;white-space:pre}
+ .install .p{color:#8c93ff;user-select:none}
+ button.copy{margin:0 24px 18px;padding:8px 14px;border:1px solid #3a3c55;border-radius:999px;
+ background:transparent;color:#e8e8f4;font:600 13px/1 var(--sans);cursor:pointer}
+ button.copy:hover{background:#262840}
+
+ .cta{margin-top:30px;display:flex;gap:12px;flex-wrap:wrap}
+ .btn{display:inline-block;padding:14px 24px;border-radius:999px;font-weight:700;font-size:15px;
+ border:2px solid var(--ink);color:var(--ink)}
+ .btn:hover{text-decoration:none;background:var(--soft)}
+ .btn.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
+ .btn.primary:hover{filter:brightness(1.08);background:var(--accent)}
+
+ /* sections */
+ section{padding:88px 0;border-top:1px solid var(--line)}
+ .kicker{font-weight:700;font-size:13px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:14px}
+ h2{font-weight:900;font-size:clamp(2rem,5vw,3.4rem);line-height:1;letter-spacing:-.04em;max-width:18ch}
+ .sec-head{margin-bottom:44px}
+ .sec-head p{max-width:42rem;color:var(--muted);margin:18px 0 0;font-size:1.08rem}
+ h3{font-weight:800;font-size:1.2rem;letter-spacing:-.02em}
+
+ figure{margin:0}
+ figure img{width:100%;height:auto;display:block;border-radius:20px;border:1px solid var(--line)}
+ figcaption{margin-top:14px;font-size:14px;color:var(--muted)}
+
+ /* tags */
+ .tag{padding:4px 11px;border-radius:999px;font:700 11.5px/1.4 var(--sans);
+ letter-spacing:.06em;text-transform:uppercase}
+ .tag.beta{background:var(--warm-soft);color:var(--warm)}
+
+ .stacks{display:flex;gap:10px;flex-wrap:wrap;margin-top:28px}
+ .stacks span{padding:9px 16px;border-radius:999px;background:var(--accent-soft);color:var(--ink);
+ font-weight:700;font-size:14px}
+
+ /* lists */
+ .cmds{list-style:none;padding:0;margin:0;border-top:2px solid var(--ink)}
+ .cmds li{display:flex;gap:24px;flex-wrap:wrap;align-items:baseline;padding:16px 0;border-bottom:1px solid var(--line)}
+ .cmds code{min-width:12rem;font-weight:700;font-size:14.5px;color:var(--ink)}
+ .cmds li > span{flex:1;min-width:15rem;color:var(--muted);font-size:15.5px}
+ .cmds .tag{margin-left:8px;vertical-align:2px}
+
+ .hint{margin:14px 0 0;font-size:15px;color:var(--muted)}
+ .sec-head p strong{color:var(--ink)}
+ .note{margin-top:28px;padding:18px 22px;border-radius:16px;background:var(--soft);color:var(--muted);font-size:15px}
+
+ /* layouts beyond cards: numbered steps, text beside a terminal, a checklist, a closing band */
+ .steps{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:repeat(3,1fr);
+ counter-reset:step;border-top:2px solid var(--ink)}
+ .steps li{counter-increment:step;padding:24px 28px 8px 0}
+ .steps li + li{padding-left:28px;border-left:1px solid var(--line)}
+ .steps li::before{content:counter(step,decimal-leading-zero);display:block;font-family:var(--display);
+ font-weight:900;font-size:3rem;line-height:1;letter-spacing:-.04em;color:var(--accent);margin-bottom:14px}
+ .steps b{display:block;color:var(--ink);font-family:var(--display);font-weight:800;font-size:1.15rem;margin-bottom:6px}
+ .steps span{color:var(--muted);font-size:15.5px}
+
+ .split{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:center}
+ .split .sec-head{margin-bottom:0}
+ .checks{list-style:none;padding:0;margin:24px 0 0}
+ .checks li{padding:10px 0 10px 32px;position:relative;border-bottom:1px solid var(--line);font-size:15.5px}
+ .checks li::before{content:"✓";position:absolute;left:4px;color:var(--go);font-weight:900}
+ .checks b{color:var(--ink)}
+ .logline{margin:0;background:var(--term);border:1px solid var(--line);border-radius:18px;padding:22px 24px;
+ font:13px/1.8 var(--mono);color:#e8e8f4;overflow-x:auto;white-space:pre-wrap}
+ .logline .k{color:#8c93ff}
+ .logline .c{color:#8b8ea6}
+ .logline .x{color:#f2a06e}
+
+ .band{display:flex;gap:24px;align-items:center;justify-content:space-between;flex-wrap:wrap;
+ background:var(--accent-soft);border-radius:24px;padding:32px 36px}
+ .band h2{font-size:clamp(1.6rem,3.6vw,2.4rem)}
+ .band p{margin:10px 0 0;color:var(--text);max-width:36rem}
+
+ /* a two-column spec sheet, and grouped lists */
+ .spec{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:48px;border-top:2px solid var(--ink)}
+ .spec div{display:flex;gap:16px;align-items:baseline;padding:14px 0;border-bottom:1px solid var(--line)}
+ .spec b{min-width:10rem;color:var(--ink);font-family:var(--display);font-weight:800}
+ .spec span{color:var(--muted);font-size:15px}
+ .groups{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:28px;margin-top:36px}
+ .groups h3{font-family:var(--sans);font-size:12.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
+ color:var(--muted);padding-bottom:10px;border-bottom:2px solid var(--ink)}
+ .groups ul{list-style:none;padding:0;margin:0}
+ .groups li{padding:10px 0;border-bottom:1px solid var(--line);font-size:14.5px;color:var(--muted)}
+ .groups code{display:block;color:var(--accent);font-weight:700;font-size:14px}
+
+ footer{border-top:1px solid var(--line);padding:56px 0 64px;color:var(--muted);font-size:14.5px}
+ .flinks{display:flex;gap:24px;flex-wrap:wrap;margin-bottom:22px}
+ .flinks a{color:var(--ink);font-weight:600}
+ .fine{margin:0;font-size:13.5px}
+ .fine + .fine{margin-top:6px}
+
+ @media (max-width:900px){
+ .split{grid-template-columns:1fr;gap:28px}
+ .groups{grid-template-columns:1fr 1fr}
+ .spec{grid-template-columns:1fr}
+ }
+ @media (max-width:640px){
+ header.hero{padding:60px 0 48px}
+ section{padding:60px 0}
+ nav .wrap{height:auto;padding-top:12px;padding-bottom:12px;flex-wrap:wrap;gap:12px}
+ nav ul{gap:16px;margin-left:0}
+ .cmds code{min-width:auto}
+ [id]{scroll-margin-top:160px}
+ .steps{grid-template-columns:1fr}
+ .steps li + li{padding-left:0;border-left:0;border-top:1px solid var(--line)}
+ .groups{grid-template-columns:1fr}
+ .spec b{min-width:7rem}
+ .band{padding:24px}
+ }
+ @media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}