Help us improve
Share bugs, ideas, or general feedback.
From plan-it
HTML-first persistent planning skill. Generates a single self-contained plan.html with interactive phases, drag-and-drop tickets, sliders, mockups, and embedded JSON state. Survives /clear via session catchup, tamper-protected by SHA-256, mirrors across 17 IDEs, ships 10 templates across Thariq's 9 categories, exports back to Markdown on demand. Use when asked to "plan it", "make me an html plan", "show me the plan", "render the plan", or when starting any multi-step task that needs a navigable artifact instead of a markdown wall.
npx claudepluginhub othmanadi/plan-it --plugin plan-itHow this skill is triggered — by the user, by Claude, or both
Slash command
/plan-it:plan-itThis skill is limited to the following tools:
if [ -f plan.html ]; then PY=$(command -v python3 || command -v python); HELPER="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/skills/plan-it}/scripts/plan-hook.py"; if [ -z "$PY" ] || [ ! -f "$HELPER" ]; then HELPER=$(ls "$HOME/.claude/skills/plan-it/scripts/plan-hook.py" "$HOME/.claude/plugins/marketplaces/plan-it/scripts/plan-hook.py" 2>/dev/null | head -1); fi; if [ -n "$PY" ] && [ -n "$HELPER" ] && [ -f "$HELPER" ]; then "$PY" "$HELPER" check-complete; fi; fi*if [ -f plan.html ]; then echo '[plan-it] PreCompact: context compaction about to occur.'; echo 'Before compaction completes: ensure plan.html embedded JSON captures recent progress_log entries and current_phase status.'; echo 'plan.html remains on disk and will be re-read after compaction.'; PY=$(command -v python3 || command -v python); HELPER="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/skills/plan-it}/scripts/plan-hook.py"; if [ -z "$PY" ] || [ ! -f "$HELPER" ]; then HELPER=$(ls "$HOME/.claude/skills/plan-it/scripts/plan-hook.py" "$HOME/.claude/plugins/marketplaces/plan-it/scripts/plan-hook.py" 2>/dev/null | head -1); fi; if [ -n "$PY" ] && [ -n "$HELPER" ] && [ -f "$HELPER" ]; then "$PY" "$HELPER" attestation; fi; fi; exit 0Write|Edit|Bash|Read|Glob|Grepif [ -f plan.html ]; then PY=$(command -v python3 || command -v python); HELPER="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/skills/plan-it}/scripts/plan-hook.py"; if [ -z "$PY" ] || [ ! -f "$HELPER" ]; then HELPER=$(ls "$HOME/.claude/skills/plan-it/scripts/plan-hook.py" "$HOME/.claude/plugins/marketplaces/plan-it/scripts/plan-hook.py" 2>/dev/null | head -1); fi; if [ -n "$PY" ] && [ -n "$HELPER" ] && [ -f "$HELPER" ]; then "$PY" "$HELPER" inject --mode active-phase --lines 15; fi; fiWrite|Editif [ -f plan.html ]; then echo '[plan-it] Update plan.html embedded JSON with what you just did (progress_log + phase status). The data lives in <script type="application/json" id="plan-data">. Do not edit the render layer.'; fiif [ -f plan.html ]; then PY=$(command -v python3 || command -v python); HELPER="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/skills/plan-it}/scripts/plan-hook.py"; if [ -z "$PY" ] || [ ! -f "$HELPER" ]; then HELPER=$(ls "$HOME/.claude/skills/plan-it/scripts/plan-hook.py" "$HOME/.claude/plugins/marketplaces/plan-it/scripts/plan-hook.py" 2>/dev/null | head -1); fi; if [ -n "$PY" ] && [ -n "$HELPER" ] && [ -f "$HELPER" ]; then "$PY" "$HELPER" inject --mode summary --lines 30; else echo '[plan-it] plan.html present but helper script not found. Run /plan to re-init.'; fi; fiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
HTML-first persistent planning. Work like Thariq: ship a single navigable artifact instead of a markdown wall the human will skip.
scripts/attest-plan.ps1scripts/attest-plan.shscripts/bump-version.pyscripts/export-markdown.pyscripts/init-plan.ps1scripts/init-plan.shscripts/plan-hook.pyscripts/render-plan.ps1scripts/render-plan.shscripts/session-catchup.pyscripts/sync-ide-folders.pytemplates/animation-sandbox.htmltemplates/annotated-pr.htmltemplates/feature-flag-editor.htmltemplates/implementation-plan.htmltemplates/incident-timeline.htmltemplates/living-design-system.htmltemplates/module-map.htmltemplates/three-approaches.htmltemplates/ticket-triage.htmlApplies 10 pre-set color/font themes or generates custom ones for slides, documents, reports, and HTML landing pages.
Share bugs, ideas, or general feedback.
HTML-first persistent planning. Work like Thariq: ship a single navigable artifact instead of a markdown wall the human will skip.
Before doing anything else, check if plan.html exists:
plan.html, the hooks will auto-inject the active-phase summary on every prompt.$(command -v python3 || command -v python) ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
If catchup reports unsynced context: run git diff --stat, read plan.html's embedded JSON, update progress_log, then proceed.
Per Thariq Shihipar's 2026-05-08 essay ("The Unreasonable Effectiveness of HTML"): the format the agent emits is the control surface the human inspects. With Opus 4.7's 1M context, token cost is the wrong metric. Engagement is. HTML preserves spatial relationships, interactivity, density-without-scroll, and visual hierarchy that markdown linearizes away. Sliders + drag-cards + copy-buttons + mockups are first-class.
| Location | What goes there |
|---|---|
Skill directory (${CLAUDE_PLUGIN_ROOT}/) | Templates, scripts, reference docs |
| Your project directory | plan.html (single source of truth) |
Before ANY complex task:
/plan or bash scripts/init-plan.sh <template>. Available templates: implementation-plan, three-approaches, ticket-triage, feature-flag-editor, module-map, annotated-pr, living-design-system, animation-sandbox, weekly-status, incident-timeline./plan-render or bash scripts/render-plan.sh. The page opens in your default browser.<script type="application/json" id="plan-data"> is the source of truth./plan-attest to compute and store SHA-256. Any future tamper of plan.html blocks injection until you re-attest.Context Window = RAM (volatile, limited)
Filesystem = Disk (persistent, unlimited)
plan.html = the canonical surface — visual to humans, structured to agents
The JSON data layer travels everywhere. The render layer is the human's UX.
{
"schema_version": "0.1.1",
"plan_title": "...",
"goal": "...",
"current_phase": 1,
"template": "implementation-plan",
"ownership": "agent",
"created_at": "ISO 8601",
"updated_at": "ISO 8601",
"phases": [
{
"id": 1,
"title": "...",
"status": "pending|in_progress|complete|blocked",
"items": [{"text": "...", "done": false, "owner": null}],
"milestones": ["..."]
}
],
"findings": [...],
"progress_log": [...],
"decisions": [...],
"errors": [...],
"attestation_sha256": null
}
ownership is optional, default unset. Accepts "agent", "user", or "shared". v0.1.1 documents the field for forward-compat; v0.2.0 will gate UI affordances on it. Plan authors can start tagging plans now without breaking back-compat.
| Command | What it does |
|---|---|
/plan | Create a new plan.html from a template |
/plan-render | Open plan.html in your default browser |
/plan-attest | Lock the plan with SHA-256 attestation (--show, --clear) |
/plan-status | Print one-line plan status to terminal |
/plan-export markdown | Flatten plan.html → task_plan.md (bidirectional) |
/plan-export json | Export the embedded JSON to plan.json |
/plan-goal | Compose with Claude Code's /goal — derive termination condition |
/plan-loop | Compose with Claude Code's /loop — re-read on every tick |
Six interactive templates (implementation-plan, annotated-pr, feature-flag-editor, incident-timeline, animation-sandbox, ticket-triage) ship a Save button in the header. Clicking it writes the current plan state back to disk:
plan.html into the browser's default download directory. Move the file into the project root to replace the original.Before serializing, the handler pushes the in-memory plan object into the embedded <script type="application/json" id="plan-data"> block so the saved file carries the new state. The render layer clears its containers on every page load, so re-opening a saved file does not double-render the cards baked into the serialized DOM. After a Save, the agent can re-read plan.html and see the user's edits.
The four pure display/export templates (living-design-system, module-map, three-approaches, weekly-status) do not need Save: they have no state to persist.
Never start a complex task without plan.html. Use /plan even for "quick" work — it forces a phase breakdown before code.
The render layer is derived. Always update the embedded JSON in <script type="application/json" id="plan-data">. NEVER hand-edit the HTML tags around it.
After every 2 view/browser/search operations, append a findings entry to the JSON. Prevents visual/multimodal information from being lost.
Before major decisions, re-read the plan.html (the hooks inject the active-phase summary anyway). Keeps goals in attention window.
After completing any phase:
phases[i].status: "complete" and completed_at timestampprogress_log entry with files modifiedcurrent_phaseAppend to errors array. Knowledge that survives /clear.
plan-it plans look like an editorial dashboard, not a SaaS dashboard. Apply these rules when authoring or extending templates:
system-ui, sans-serif, monospace. No web fonts.<style>, inline <script>, base64 images or inline SVG. No CDN. No build step.Every plan.html ships:
<style> inline<script type="application/json" id="plan-data"> — the canonical data<script> inline — vanilla JS renderer, ≤400 lines<link rel="stylesheet">, no <script src>, no eval, no Function(), no remote URLs===BEGIN PLAN DATA=== / ===END PLAN DATA=== markers (NEVER ---, that collides with YAML doc-separator and breaks Claude Code's skill loader — lesson from planning-with-files v2.38.1)./plan-attest. On tamper, injection is blocked with [PLAN TAMPERED — injection blocked] and expected/actual hashes.If you already use planning-with-files (the markdown predecessor at https://github.com/OthmanAdi/planning-with-files), plan-it composes cleanly. Run /plan-export markdown inside a plan-it project to flatten plan.html into the pwf three-file shape (task_plan.md, findings.md, progress.md). The HTML stays canonical, the markdown is a derived view that downstream pwf tooling and chained agents can consume.
plan.html on disk, click Save first; on Firefox/Safari, move the downloaded file into the project root./plan-attest --clear && /plan to re-init. Do not hand-edit HTML tags.<script type="application/json"> block, not raw HTML. Most editors will syntax-highlight it correctly if you set the line <script type="application/json"> first.scripts/render-plan.sh? On WSL, xdg-open may need wslview. On macOS, open is built in. On Windows PowerShell, Invoke-Item works. The .ps1 script handles all three.--lines 30 argument.--- substring. We use === for that exact reason.$HOME for fallback path resolution. If your install path is non-standard, set CLAUDE_PLUGIN_ROOT env var.PLAN_ID=<slug> env var. plan-it then reads .planning/<slug>/plan.html instead of plan.html. Use /plan-status to see active plan./plan-export markdown if you need lower-cost chained-agent intermediate output.