Files
brain/project-files/docs/visualizations/hooks-skills-plugins-map.html
T

3227 lines
130 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Карта работы — Hooks · Skills · Plugins</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT,WONK@0,9..144,200..900,0..100,0..1;1,9..144,200..900,0..100,0..1&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js" defer></script>
<style>
/* ============================================================
COLOR SYSTEM — Vintage Engineering Manual
============================================================ */
:root {
--paper: #F2EBDC;
--paper-shade: #E8DFC8;
--paper-deep: #D9CFB5;
--ink: #0E2235;
--ink-soft: #2B3D52;
--ink-fade: #5E6F82;
--blueprint: #1A6E8E;
--blueprint-deep: #0F4D67;
--amber: #C48B26;
--amber-deep: #9A6A14;
--rust: #8B3A1B;
--rust-deep: #6A2A12;
--sage: #5E7A4F;
--sage-deep: #3E5333;
--grid: rgba(14, 34, 53, 0.06);
--rule: rgba(14, 34, 53, 0.15);
--shadow-paper: 0 1px 0 rgba(0,0,0,0.04), 0 4px 24px rgba(14, 34, 53, 0.08);
}
/* ============================================================
RESET + BASE
============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
scroll-behavior: smooth;
font-size: 16px;
}
body {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-weight: 400;
font-size: 1rem;
line-height: 1.6;
color: var(--ink);
background: var(--paper);
background-image:
linear-gradient(var(--grid) 1px, transparent 1px),
linear-gradient(90deg, var(--grid) 1px, transparent 1px);
background-size: 32px 32px;
background-attachment: fixed;
min-height: 100vh;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
/* Subtle paper grain overlay */
body::before {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
z-index: 1;
opacity: 0.4;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' /%3E%3CfeColorMatrix values='0 0 0 0 0.05 0 0 0 0 0.13 0 0 0 0 0.21 0 0 0 0.18 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
main { position: relative; z-index: 2; }
/* ============================================================
TYPOGRAPHY
============================================================ */
.display {
font-family: 'Fraunces', serif;
font-variation-settings: 'opsz' 144, 'SOFT' 50, 'WONK' 1;
font-weight: 400;
letter-spacing: -0.02em;
line-height: 0.95;
}
.display-i {
font-family: 'Fraunces', serif;
font-style: italic;
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
font-weight: 300;
}
.mono {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-weight: 400;
}
.caps {
font-family: 'Plus Jakarta Sans', sans-serif;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.18em;
font-size: 0.72rem;
}
/* ============================================================
PAGE FRAME
============================================================ */
.frame {
max-width: 1240px;
margin: 0 auto;
padding: 0 32px;
}
@media (max-width: 720px) {
.frame { padding: 0 20px; }
}
/* ============================================================
HERO
============================================================ */
.hero {
padding: 96px 0 64px;
position: relative;
}
.hero-meta {
display: flex;
align-items: baseline;
gap: 24px;
margin-bottom: 48px;
color: var(--ink-fade);
}
.hero-meta-divider {
flex: 1;
height: 1px;
background: var(--rule);
position: relative;
top: -4px;
}
.hero-title {
font-size: clamp(3rem, 9vw, 7rem);
margin-bottom: 32px;
}
.hero-title em {
font-style: italic;
color: var(--blueprint);
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
}
.hero-sub {
font-size: 1.25rem;
max-width: 720px;
color: var(--ink-soft);
line-height: 1.55;
}
.hero-sub strong {
font-weight: 600;
color: var(--ink);
background: linear-gradient(transparent 60%, rgba(196, 139, 38, 0.35) 60%);
padding: 0 2px;
}
.hero-stamp {
position: absolute;
top: 80px;
right: 32px;
display: flex;
flex-direction: column;
align-items: flex-end;
text-align: right;
color: var(--rust);
border: 2px solid var(--rust);
padding: 14px 18px;
transform: rotate(4deg);
background: rgba(242, 235, 220, 0.6);
}
.hero-stamp .num { font-family: 'Fraunces', serif; font-size: 2rem; font-weight: 400; line-height: 1; }
.hero-stamp .lbl { font-size: 0.65rem; letter-spacing: 0.2em; text-transform: uppercase; margin-top: 4px; }
@media (max-width: 720px) {
.hero { padding: 60px 0 40px; }
.hero-stamp { display: none; }
}
/* ============================================================
SECTION
============================================================ */
.section {
padding: 64px 0;
border-top: 1px solid var(--rule);
}
.section-num {
font-family: 'Fraunces', serif;
font-style: italic;
font-variation-settings: 'opsz' 144, 'SOFT' 100;
font-weight: 300;
font-size: 4rem;
color: var(--blueprint);
line-height: 1;
margin-bottom: 8px;
}
.section-title {
font-family: 'Fraunces', serif;
font-weight: 500;
font-variation-settings: 'opsz' 60, 'SOFT' 30;
font-size: clamp(2rem, 4vw, 3rem);
line-height: 1.1;
margin-bottom: 12px;
letter-spacing: -0.01em;
}
.section-lede {
font-size: 1.15rem;
color: var(--ink-soft);
max-width: 680px;
margin-bottom: 48px;
line-height: 1.55;
}
/* ============================================================
THE THREE CONCEPTS
============================================================ */
.triad {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0;
border: 1px solid var(--rule);
background: var(--paper);
}
@media (max-width: 900px) {
.triad { grid-template-columns: 1fr; }
}
.triad-cell {
padding: 36px 32px 40px;
position: relative;
background: var(--paper);
transition: background 250ms;
}
.triad-cell:not(:last-child) {
border-right: 1px solid var(--rule);
}
@media (max-width: 900px) {
.triad-cell:not(:last-child) {
border-right: none;
border-bottom: 1px solid var(--rule);
}
}
.triad-cell:hover { background: var(--paper-shade); }
.triad-tag {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--blueprint);
margin-bottom: 16px;
}
.triad-name {
font-family: 'Fraunces', serif;
font-weight: 400;
font-variation-settings: 'opsz' 100, 'SOFT' 50;
font-size: 2.4rem;
line-height: 1;
margin-bottom: 8px;
color: var(--ink);
}
.triad-name em {
font-style: italic;
color: var(--rust);
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
}
.triad-eq {
font-family: 'Fraunces', serif;
font-style: italic;
color: var(--ink-fade);
font-size: 1.05rem;
margin-bottom: 24px;
}
.triad-body {
font-size: 0.95rem;
line-height: 1.6;
color: var(--ink-soft);
}
.triad-key {
margin-top: 24px;
padding-top: 16px;
border-top: 1px dashed var(--rule);
font-size: 0.85rem;
}
.triad-key b {
font-weight: 600;
color: var(--ink);
}
.icon-shape {
width: 56px;
height: 56px;
margin-bottom: 24px;
display: flex;
align-items: center;
justify-content: center;
}
/* ============================================================
TIMELINE
============================================================ */
.timeline {
margin-top: 32px;
position: relative;
background: var(--paper-shade);
border: 1px solid var(--rule);
padding: 48px 32px 40px;
border-radius: 2px;
overflow-x: auto;
}
.timeline-rail {
position: relative;
min-width: 1000px;
padding: 16px 0 48px;
}
.timeline-line {
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 2px;
background: var(--ink);
background-image: linear-gradient(to right, var(--ink) 0, var(--ink) 6px, transparent 6px, transparent 12px);
background-size: 12px 2px;
z-index: 1;
}
.timeline-steps {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 16px;
position: relative;
z-index: 2;
}
.t-step {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
position: relative;
}
.t-step-dot {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--paper);
border: 2px solid var(--ink);
margin-bottom: 16px;
position: relative;
}
.t-step-dot.user { background: var(--ink); }
.t-step-dot.fire { background: var(--amber); border-color: var(--amber-deep); }
.t-step-dot.danger { background: var(--rust); border-color: var(--rust-deep); }
.t-step-dot.done { background: var(--sage); border-color: var(--sage-deep); }
.t-step-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--blueprint);
margin-bottom: 8px;
}
.t-step-title {
font-family: 'Fraunces', serif;
font-weight: 500;
font-variation-settings: 'opsz' 36, 'SOFT' 30;
font-size: 1.05rem;
line-height: 1.15;
margin-bottom: 8px;
}
.t-step-desc {
font-size: 0.82rem;
color: var(--ink-soft);
line-height: 1.45;
max-width: 200px;
}
.t-step-script {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
color: var(--rust);
margin-top: 8px;
padding: 4px 8px;
background: rgba(139, 58, 27, 0.08);
border-radius: 2px;
display: inline-block;
}
/* Mid-turn micro-section (between UserPromptSubmit and Stop) */
.timeline-inner {
margin: 56px 24px 0;
padding: 24px;
border: 1px dashed var(--blueprint);
background: rgba(26, 110, 142, 0.05);
position: relative;
}
.timeline-inner-tag {
position: absolute;
top: -10px;
left: 24px;
background: var(--paper-shade);
padding: 0 12px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--blueprint);
}
.timeline-inner-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
@media (max-width: 900px) {
.timeline-inner-grid { grid-template-columns: 1fr; }
}
.t-inner-step {
padding: 16px;
background: var(--paper);
border-left: 3px solid var(--blueprint);
}
.t-inner-step.special {
border-left-color: var(--rust);
}
.t-inner-title {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1rem;
margin-bottom: 4px;
line-height: 1.2;
}
.t-inner-trigger {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
color: var(--ink-fade);
margin-bottom: 8px;
}
.t-inner-desc {
font-size: 0.85rem;
color: var(--ink-soft);
line-height: 1.5;
}
/* Parallel hooks (SessionStart, PostCompact) */
.timeline-parallel {
margin-top: 32px;
padding-top: 24px;
border-top: 1px solid var(--rule);
}
.timeline-parallel-title {
font-family: 'Plus Jakarta Sans', sans-serif;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.15em;
font-size: 0.75rem;
color: var(--ink-fade);
margin-bottom: 16px;
}
.timeline-parallel-list {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
@media (max-width: 720px) {
.timeline-parallel-list { grid-template-columns: 1fr; }
}
.tp-item {
display: flex;
gap: 16px;
}
.tp-item-when {
font-family: 'Fraunces', serif;
font-style: italic;
color: var(--blueprint);
font-weight: 400;
white-space: nowrap;
min-width: 150px;
font-size: 0.95rem;
}
.tp-item-what {
font-size: 0.88rem;
color: var(--ink-soft);
}
/* ============================================================
HOOK ROSTER — table-card hybrid
============================================================ */
.roster {
margin-top: 32px;
border: 1px solid var(--rule);
}
.roster-row {
display: grid;
grid-template-columns: 180px 220px 1fr 120px;
gap: 24px;
padding: 20px 28px;
border-bottom: 1px solid var(--rule);
align-items: center;
background: var(--paper);
transition: background 200ms;
}
.roster-row:last-child { border-bottom: none; }
.roster-row:hover { background: var(--paper-shade); }
.roster-row.header {
background: var(--ink);
color: var(--paper);
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.roster-row.header:hover { background: var(--ink); }
@media (max-width: 900px) {
.roster-row {
grid-template-columns: 1fr;
gap: 8px;
}
.roster-row.header { display: none; }
}
.r-event {
font-family: 'JetBrains Mono', monospace;
font-size: 0.82rem;
font-weight: 500;
color: var(--blueprint-deep);
}
.r-matcher {
font-family: 'JetBrains Mono', monospace;
font-size: 0.78rem;
color: var(--ink-soft);
}
.r-script {
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
color: var(--rust);
}
.r-desc {
font-size: 0.92rem;
color: var(--ink-soft);
line-height: 1.5;
}
.r-type {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
text-align: center;
padding: 4px 10px;
border: 1px solid;
width: max-content;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.r-type.cmd { color: var(--sage-deep); border-color: var(--sage); background: rgba(94, 122, 79, 0.1); }
.r-type.agent { color: var(--rust); border-color: var(--rust); background: rgba(139, 58, 27, 0.1); }
/* ============================================================
PERMISSIONS BLOCK
============================================================ */
.perms {
margin-top: 32px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
@media (max-width: 900px) {
.perms { grid-template-columns: 1fr; }
}
.perm-card {
padding: 28px 24px;
border: 1px solid var(--rule);
background: var(--paper);
position: relative;
}
.perm-card-num {
position: absolute;
top: 16px;
right: 20px;
font-family: 'Fraunces', serif;
font-style: italic;
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
font-weight: 300;
font-size: 3.5rem;
line-height: 1;
}
.perm-card.allow { border-top: 4px solid var(--sage); }
.perm-card.allow .perm-card-num { color: var(--sage); }
.perm-card.deny { border-top: 4px solid var(--rust); }
.perm-card.deny .perm-card-num { color: var(--rust); }
.perm-card.ask { border-top: 4px solid var(--amber); }
.perm-card.ask .perm-card-num { color: var(--amber-deep); }
.perm-card-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.72rem;
letter-spacing: 0.18em;
text-transform: uppercase;
margin-bottom: 12px;
color: var(--ink-fade);
}
.perm-card-title {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.6rem;
margin-bottom: 12px;
line-height: 1.1;
}
.perm-card-body {
font-size: 0.88rem;
color: var(--ink-soft);
line-height: 1.5;
}
/* ============================================================
PLUGINS GRID
============================================================ */
.plugins {
margin-top: 32px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
}
@media (max-width: 900px) {
.plugins { grid-template-columns: 1fr; }
}
.plugin-card {
border: 1px solid var(--rule);
background: var(--paper);
padding: 28px 28px 24px;
position: relative;
}
.plugin-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px dashed var(--rule);
}
.plugin-card-name {
font-family: 'Fraunces', serif;
font-weight: 500;
font-variation-settings: 'opsz' 60, 'SOFT' 30;
font-size: 1.5rem;
line-height: 1.1;
}
.plugin-card-scope {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 4px 8px;
background: var(--ink);
color: var(--paper);
}
.plugin-card-desc {
font-size: 0.92rem;
color: var(--ink-soft);
line-height: 1.55;
margin-bottom: 16px;
}
.plugin-skills-list {
font-family: 'JetBrains Mono', monospace;
font-size: 0.78rem;
color: var(--blueprint-deep);
line-height: 1.7;
}
/* ============================================================
SKILLS BY PURPOSE
============================================================ */
.skills-purpose {
margin-top: 32px;
}
.sp-row {
display: grid;
grid-template-columns: 280px 1fr;
gap: 32px;
padding: 24px 0;
border-bottom: 1px solid var(--rule);
}
.sp-row:last-child { border-bottom: none; }
@media (max-width: 900px) {
.sp-row { grid-template-columns: 1fr; gap: 12px; }
}
.sp-cat {
display: flex;
flex-direction: column;
gap: 6px;
}
.sp-cat-symbol {
font-family: 'Fraunces', serif;
font-variation-settings: 'opsz' 144, 'WONK' 1, 'SOFT' 100;
font-size: 3rem;
font-style: italic;
font-weight: 300;
color: var(--rust);
line-height: 1;
}
.sp-cat-name {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.3rem;
line-height: 1.2;
}
.sp-cat-meta {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
color: var(--ink-fade);
}
.sp-skills {
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
line-height: 1.85;
color: var(--ink-soft);
}
.sp-skill {
display: inline-block;
padding: 2px 8px;
margin: 2px 4px 2px 0;
background: var(--paper-shade);
border: 1px solid var(--rule);
color: var(--ink);
font-size: 0.78rem;
white-space: nowrap;
}
/* ============================================================
FILESYSTEM TREE
============================================================ */
.fs {
margin-top: 32px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
line-height: 1.85;
background: var(--ink);
color: var(--paper);
padding: 36px 32px;
border-radius: 2px;
overflow-x: auto;
}
.fs-line {
display: flex;
align-items: center;
gap: 12px;
white-space: nowrap;
}
.fs-path { color: var(--paper); }
.fs-path b { color: var(--amber); font-weight: 600; }
.fs-comment { color: var(--ink-fade); font-style: italic; }
.fs-comment::before { content: '◆ '; color: var(--amber); }
.fs-section-tag {
display: inline-block;
padding: 2px 8px;
margin-right: 8px;
background: rgba(196, 139, 38, 0.2);
color: var(--amber);
font-size: 0.7rem;
letter-spacing: 0.08em;
text-transform: uppercase;
border: 1px solid rgba(196, 139, 38, 0.4);
}
/* ============================================================
MENTAL MODEL
============================================================ */
.mental {
margin-top: 32px;
border: 1px solid var(--ink);
padding: 48px 40px;
background: var(--paper);
position: relative;
}
.mental-stage {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
}
@media (max-width: 900px) {
.mental-stage { grid-template-columns: 1fr; gap: 32px; }
}
.mental-actor {
position: relative;
padding: 24px 20px;
border: 1px solid var(--rule);
background: var(--paper-shade);
}
.mental-actor.you { border-left: 4px solid var(--sage); }
.mental-actor.runtime { border-left: 4px solid var(--blueprint); }
.mental-actor.claude { border-left: 4px solid var(--amber); }
.mental-actor.verifier { border-left: 4px solid var(--rust); }
.mental-tag {
font-family: 'JetBrains Mono', monospace;
font-size: 0.68rem;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-fade);
margin-bottom: 12px;
}
.mental-name {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.2rem;
line-height: 1.1;
margin-bottom: 16px;
}
.mental-actor.you .mental-name { color: var(--sage-deep); }
.mental-actor.runtime .mental-name { color: var(--blueprint-deep); }
.mental-actor.claude .mental-name { color: var(--amber-deep); }
.mental-actor.verifier .mental-name { color: var(--rust); }
.mental-list {
list-style: none;
font-size: 0.85rem;
color: var(--ink-soft);
line-height: 1.55;
}
.mental-list li {
position: relative;
padding-left: 14px;
margin-bottom: 8px;
}
.mental-list li::before {
content: '→';
position: absolute;
left: 0;
color: var(--ink-fade);
}
/* ============================================================
PRACTICAL ACTIONS
============================================================ */
.actions {
margin-top: 32px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
@media (max-width: 900px) {
.actions { grid-template-columns: 1fr; }
}
.action {
padding: 24px;
background: var(--paper);
border: 1px solid var(--rule);
position: relative;
}
.action-num {
position: absolute;
top: 12px;
right: 16px;
font-family: 'Fraunces', serif;
font-style: italic;
color: var(--blueprint);
font-size: 1.8rem;
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
font-weight: 300;
}
.action-want {
font-family: 'Fraunces', serif;
font-style: italic;
font-size: 1.05rem;
color: var(--ink-fade);
margin-bottom: 6px;
}
.action-do {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.25rem;
line-height: 1.2;
margin-bottom: 12px;
}
.action-cmd {
font-family: 'JetBrains Mono', monospace;
font-size: 0.82rem;
background: var(--ink);
color: var(--amber);
padding: 12px 14px;
margin-top: 8px;
display: block;
word-break: break-all;
}
/* ============================================================
FOOTER
============================================================ */
.foot {
margin-top: 80px;
padding: 48px 0 64px;
border-top: 2px solid var(--ink);
font-size: 0.85rem;
color: var(--ink-fade);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 16px;
}
.foot .mono { color: var(--ink); }
.foot-ornament {
font-family: 'Fraunces', serif;
font-style: italic;
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
font-size: 1.6rem;
font-weight: 300;
color: var(--rust);
}
/* ============================================================
HIERARCHY SECTION
============================================================ */
.hier-section { margin-top: 32px; }
.hier-block {
margin-bottom: 48px;
border: 1px solid var(--rule);
background: var(--paper);
padding: 32px 28px;
position: relative;
}
.hier-block:last-child { margin-bottom: 0; }
.hier-block-tag {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--rust);
margin-bottom: 4px;
}
.hier-block-title {
font-family: 'Fraunces', serif;
font-weight: 500;
font-variation-settings: 'opsz' 48, 'SOFT' 30;
font-size: 1.8rem;
line-height: 1.1;
margin-bottom: 8px;
}
.hier-block-lede {
font-size: 0.92rem;
color: var(--ink-soft);
margin-bottom: 24px;
max-width: 640px;
line-height: 1.5;
}
/* 1. Containment ASCII tree */
.hier-tree {
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
line-height: 1.85;
background: var(--paper-shade);
border-left: 4px solid var(--blueprint);
padding: 20px 24px;
white-space: pre;
overflow-x: auto;
color: var(--ink);
}
.hier-tree .root { color: var(--rust); font-weight: 700; }
.hier-tree .leaf { color: var(--blueprint-deep); }
.hier-tree .note { color: var(--ink-fade); font-style: italic; }
/* 2. Priority chain — numbered list */
.hier-priority {
list-style: none;
counter-reset: prio;
}
.hier-priority-row {
display: grid;
grid-template-columns: 60px 1fr;
align-items: start;
gap: 16px;
padding: 14px 0;
border-bottom: 1px dashed var(--rule);
}
.hier-priority-row:last-child { border-bottom: none; }
.hier-priority-lvl {
font-family: 'Fraunces', serif;
font-style: italic;
font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 1;
font-weight: 300;
font-size: 2.4rem;
line-height: 0.9;
color: var(--blueprint);
}
.hier-priority-row.locked .hier-priority-lvl { color: var(--rust); }
.hier-priority-content {
display: flex;
flex-direction: column;
gap: 4px;
}
.hier-priority-name {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.1rem;
line-height: 1.15;
color: var(--ink);
}
.hier-priority-name .badge {
font-family: 'JetBrains Mono', monospace;
font-size: 0.65rem;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 2px 6px;
background: var(--rust);
color: var(--paper);
margin-left: 8px;
vertical-align: middle;
}
.hier-priority-note {
font-size: 0.85rem;
color: var(--ink-soft);
line-height: 1.45;
}
/* 3. Event timing — horizontal cards */
.hier-timing {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 16px;
margin-top: 16px;
}
.hier-event {
padding: 16px 14px 14px;
background: var(--paper-shade);
border-top: 3px solid var(--sage);
position: relative;
}
.hier-event.once { border-top-color: var(--sage); }
.hier-event.per-turn { border-top-color: var(--blueprint); }
.hier-event.per-tool { border-top-color: var(--amber); }
.hier-event.special { border-top-color: var(--rust); }
.hier-event-num {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.1em;
color: var(--ink-fade);
margin-bottom: 4px;
}
.hier-event-name {
font-family: 'JetBrains Mono', monospace;
font-size: 0.95rem;
font-weight: 500;
color: var(--ink);
margin-bottom: 4px;
}
.hier-event-freq {
font-family: 'Fraunces', serif;
font-style: italic;
font-size: 0.82rem;
color: var(--ink-soft);
margin-bottom: 8px;
}
.hier-event-script {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
color: var(--rust);
}
/* ============================================================
SKILLS DETAIL (replaces sp-skills chip-only)
============================================================ */
.sp-skills-detail {
display: flex;
flex-direction: column;
gap: 0;
}
.sp-skill-row {
display: grid;
grid-template-columns: 220px 1fr;
gap: 20px;
padding: 12px 0;
border-bottom: 1px dashed var(--rule);
align-items: baseline;
}
.sp-skill-row:last-child { border-bottom: none; }
@media (max-width: 720px) {
.sp-skill-row { grid-template-columns: 1fr; gap: 4px; padding: 14px 0; }
}
.sp-skill-key {
font-family: 'JetBrains Mono', monospace;
font-size: 0.82rem;
font-weight: 500;
color: var(--blueprint-deep);
}
.sp-skill-what {
font-size: 0.9rem;
color: var(--ink-soft);
line-height: 1.5;
}
.sp-skill-what em {
font-family: 'Fraunces', serif;
font-style: italic;
color: var(--rust);
font-weight: 500;
}
/* ============================================================
CONNECTIONS GRAPH (§X)
============================================================ */
.graph-controls {
margin-top: 32px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
flex-wrap: wrap;
padding: 16px 0;
border-top: 1px solid var(--rule);
border-bottom: 1px solid var(--rule);
}
.graph-filters {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.graph-filter {
font-family: 'JetBrains Mono', monospace;
font-size: 0.72rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 6px 12px;
border: 1px solid var(--rule);
background: var(--paper);
color: var(--ink);
cursor: pointer;
transition: background 200ms, color 200ms;
}
.graph-filter.active {
background: var(--ink);
color: var(--paper);
border-color: var(--ink);
}
.graph-filter:hover { background: var(--paper-shade); }
.graph-filter.active:hover { background: var(--ink-soft); }
.graph-reset {
font-family: 'JetBrains Mono', monospace;
font-size: 0.72rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 6px 14px;
border: 1px solid var(--rust);
background: var(--paper);
color: var(--rust);
cursor: pointer;
}
.graph-reset:hover { background: var(--rust); color: var(--paper); }
.graph-container {
margin-top: 24px;
display: grid;
grid-template-columns: 1fr 280px;
gap: 24px;
align-items: start;
}
.graph-svg-wrap {
border: 1px solid var(--rule);
background: var(--paper-shade);
background-image:
linear-gradient(rgba(14, 34, 53, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(14, 34, 53, 0.03) 1px, transparent 1px);
background-size: 24px 24px;
overflow: hidden;
min-height: 700px;
}
.graph-svg {
width: 100%;
height: 700px;
display: block;
cursor: default;
}
.graph-sidebar {
border: 1px solid var(--rule);
background: var(--paper);
padding: 20px 18px;
font-size: 0.88rem;
min-height: 200px;
position: relative;
}
.graph-sidebar-empty {
color: var(--ink-fade);
font-style: italic;
font-family: 'Fraunces', serif;
}
.graph-sidebar-title {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.15rem;
margin-bottom: 4px;
line-height: 1.15;
}
.graph-sidebar-badge {
display: inline-block;
font-family: 'JetBrains Mono', monospace;
font-size: 0.65rem;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 2px 8px;
background: var(--ink);
color: var(--paper);
margin-bottom: 12px;
}
.graph-sidebar-section {
margin-top: 16px;
padding-top: 12px;
border-top: 1px dashed var(--rule);
}
.graph-sidebar-section.governance {
border-top: 2px solid var(--rust);
padding-top: 14px;
}
.graph-sidebar-navlink {
margin-top: 10px;
padding: 5px 10px;
border: 1px solid var(--blueprint);
background: var(--paper);
color: var(--blueprint-deep);
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.06em;
text-transform: uppercase;
cursor: pointer;
transition: background 200ms, color 200ms;
}
.graph-sidebar-navlink:hover { background: var(--blueprint); color: var(--paper); }
.graph-sidebar-section-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.68rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--ink-fade);
margin-bottom: 8px;
}
.graph-conn-list {
list-style: none;
font-family: 'JetBrains Mono', monospace;
font-size: 0.78rem;
line-height: 1.7;
color: var(--ink-soft);
}
.graph-conn-list li b { color: var(--rust); font-weight: 600; }
.graph-close {
position: absolute;
top: 12px;
right: 14px;
border: none;
background: transparent;
font-family: 'JetBrains Mono', monospace;
font-size: 1.2rem;
cursor: pointer;
color: var(--ink-fade);
}
.graph-close:hover { color: var(--rust); }
.graph-legend {
margin-top: 24px;
padding: 20px 24px;
background: var(--paper);
border: 1px solid var(--rule);
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
.graph-legend-section h4 {
font-family: 'JetBrains Mono', monospace;
font-size: 0.68rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--ink-fade);
margin-bottom: 12px;
font-weight: 500;
}
.graph-legend-item {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
font-size: 0.82rem;
color: var(--ink-soft);
}
.graph-legend-swatch {
width: 16px;
height: 16px;
border: 1.5px solid var(--ink);
flex-shrink: 0;
}
.graph-legend-line {
width: 28px;
height: 0;
border-top: 2px solid var(--ink);
flex-shrink: 0;
}
.graph-fallback {
padding: 48px;
text-align: center;
color: var(--rust);
font-family: 'Fraunces', serif;
font-style: italic;
font-size: 1rem;
}
/* SVG node styles */
.gn-plugin { fill: var(--rust); stroke: var(--ink); stroke-width: 2; }
.gn-skill { fill: var(--blueprint); stroke: var(--ink); stroke-width: 1.5; }
.gn-script { fill: var(--amber); stroke: var(--ink); stroke-width: 1.5; }
.gn-event { fill: var(--sage); stroke: var(--ink); stroke-width: 2; }
.gn-state { fill: var(--rust); stroke: var(--ink); stroke-width: 2; }
.gn-perm { fill: var(--ink-fade); stroke: var(--ink); stroke-width: 1.5; }
.gn-rule { fill: var(--ink); stroke: var(--rust); stroke-width: 2; }
.gn-label {
font-family: 'Fraunces', serif;
font-size: 9px;
font-weight: 500;
fill: var(--ink);
pointer-events: none;
text-anchor: middle;
}
.gn-node { cursor: pointer; }
.gn-node:hover { filter: brightness(1.1); }
.dimmed { opacity: 0.15; }
.highlighted { opacity: 1; }
/* SVG link styles */
.gl { fill: none; pointer-events: stroke; }
.gl-contains { stroke: var(--blueprint); stroke-width: 1.5; }
.gl-triggers { stroke: var(--sage); stroke-width: 2; }
.gl-writes { stroke: var(--amber); stroke-width: 2; }
.gl-reads { stroke: var(--amber); stroke-width: 1.5; stroke-dasharray: 4 3; }
.gl-mandates { stroke: var(--rust); stroke-width: 2.5; }
.gl-references { stroke: var(--ink-fade); stroke-width: 1; stroke-dasharray: 2 3; }
.gl-blocks { stroke: var(--rust); stroke-width: 1.5; stroke-dasharray: 5 3; }
.gl-denies { stroke: var(--rust); stroke-width: 2; stroke-dasharray: 2 2; }
.gl-tooltip {
position: absolute;
background: var(--ink);
color: var(--paper);
font-family: 'JetBrains Mono', monospace;
font-size: 0.72rem;
padding: 4px 8px;
pointer-events: none;
z-index: 100;
border: 1px solid var(--paper-shade);
}
@media (max-width: 900px) {
.graph-container { grid-template-columns: 1fr; }
.graph-svg-wrap { overflow-x: auto; }
.graph-svg { min-width: 900px; }
.graph-sidebar {
position: fixed;
bottom: 0; left: 0; right: 0;
border-top: 2px solid var(--ink);
border-left: none; border-right: none; border-bottom: none;
z-index: 50;
max-height: 60vh;
overflow-y: auto;
}
.graph-legend { grid-template-columns: 1fr; }
}
/* ============================================================
PAGE LOAD ANIMATION
============================================================ */
@keyframes rise {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.hero, .section { animation: rise 700ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards; }
.section:nth-of-type(1) { animation-delay: 100ms; }
.section:nth-of-type(2) { animation-delay: 200ms; }
.section:nth-of-type(3) { animation-delay: 300ms; }
.section:nth-of-type(4) { animation-delay: 400ms; }
.section:nth-of-type(5) { animation-delay: 500ms; }
.section:nth-of-type(6) { animation-delay: 600ms; }
.section:nth-of-type(7) { animation-delay: 700ms; }
.section:nth-of-type(8) { animation-delay: 800ms; }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation: none !important;
transition: none !important;
}
html { scroll-behavior: auto; }
}
/* Decorative SVG underline for hero title */
.hero-title-svg {
display: block;
width: 140px;
margin: 16px 0 0;
}
.hero-title-svg path {
fill: none;
stroke: var(--rust);
stroke-width: 2;
stroke-linecap: round;
}
</style>
</head>
<body>
<main>
<!-- ============================================================
HERO
============================================================ -->
<header class="hero">
<div class="frame">
<div class="hero-meta">
<span class="caps">Carta · vol. i · 2026</span>
<span class="hero-meta-divider"></span>
<span class="mono">11.05.2026</span>
</div>
<h1 class="hero-title display">
Карта работы<br>
<em>hooks</em> · <em>skills</em> · <em>plugins</em>
</h1>
<svg class="hero-title-svg" viewBox="0 0 140 16" xmlns="http://www.w3.org/2000/svg">
<path d="M2 10 Q 35 2, 70 8 T 138 6" />
</svg>
<p class="hero-sub">
Иллюстрированный справочник по внутреннему устройству Claude Code в&nbsp;проекте с&nbsp;установленным <span class="mono">claude-brain&nbsp;v1.0</span>.
Что срабатывает в начале промпта, что — посреди вашей работы, и что — в конце.
<strong>Три типа сущностей, семь хуков, пять событий, четыре плагина, четыре MCP-сервера.</strong>
</p>
<div class="hero-stamp">
<span class="num">vIV</span>
<span class="lbl">Edition · Carta</span>
</div>
</div>
</header>
<!-- ============================================================
I. THE THREE CONCEPTS
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">I</div>
<h2 class="section-title">Три типа сущностей</h2>
<p class="section-lede">
Чтобы не путаться, важно понимать на каком слое живёт каждая вещь.
Один и тот же объект может быть одновременно частью плагина, скилом по природе и автоматизированным
хуком в действии — но <em>роль</em> у каждого своя.
</p>
<div class="triad">
<div class="triad-cell">
<div class="triad-tag">Слой&nbsp;01 · Доставка</div>
<div class="icon-shape">
<svg width="56" height="56" viewBox="0 0 56 56" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="14" width="40" height="32" fill="none" stroke="#0E2235" stroke-width="2"/>
<line x1="8" y1="22" x2="48" y2="22" stroke="#0E2235" stroke-width="2"/>
<line x1="28" y1="14" x2="28" y2="46" stroke="#0E2235" stroke-width="2" stroke-dasharray="2 3"/>
<circle cx="28" cy="22" r="3" fill="#C48B26"/>
</svg>
</div>
<div class="triad-name">Плагин</div>
<div class="triad-eq">= коробка / упаковка</div>
<div class="triad-body">
Контейнер. Сам ничего не исполняет — только доставляет в систему скилы, slash-команды,
хуки, MCP-серверы и subagent'ы. Как rpm-пакет или npm-модуль: внутри что-то полезное, наружу — манифест.
</div>
<div class="triad-key">
<b>Установка:</b> через marketplace в <span class="mono">~/.claude/settings.json</span>.
</div>
</div>
<div class="triad-cell">
<div class="triad-tag">Слой&nbsp;02 · Инструкция</div>
<div class="icon-shape">
<svg width="56" height="56" viewBox="0 0 56 56" xmlns="http://www.w3.org/2000/svg">
<path d="M14 8 L42 8 L42 48 L14 48 Z" fill="none" stroke="#0E2235" stroke-width="2"/>
<line x1="20" y1="16" x2="36" y2="16" stroke="#0E2235" stroke-width="2"/>
<line x1="20" y1="24" x2="36" y2="24" stroke="#0E2235" stroke-width="1.5"/>
<line x1="20" y1="30" x2="32" y2="30" stroke="#0E2235" stroke-width="1.5"/>
<line x1="20" y1="36" x2="36" y2="36" stroke="#0E2235" stroke-width="1.5"/>
</svg>
</div>
<div class="triad-name">Скил<em>·</em></div>
<div class="triad-eq">= инструкция в markdown</div>
<div class="triad-body">
Текст, который я (Claude) читаю и которому следую. Например, «брейнсторм, потом план, потом TDD».
Я <strong>могу его проигнорировать</strong> — это soft-правило: дисциплинированное самоприменение,
а не runtime gate.
</div>
<div class="triad-key">
<b>Вызов:</b> через <span class="mono">Skill</span>-tool или slash <span class="mono">/имя</span>.
</div>
</div>
<div class="triad-cell">
<div class="triad-tag">Слой&nbsp;03 · Принуждение</div>
<div class="icon-shape">
<svg width="56" height="56" viewBox="0 0 56 56" xmlns="http://www.w3.org/2000/svg">
<circle cx="28" cy="28" r="18" fill="none" stroke="#8B3A1B" stroke-width="2"/>
<rect x="22" y="22" width="12" height="12" fill="#8B3A1B"/>
<line x1="4" y1="28" x2="10" y2="28" stroke="#0E2235" stroke-width="2"/>
<line x1="46" y1="28" x2="52" y2="28" stroke="#0E2235" stroke-width="2"/>
<line x1="28" y1="4" x2="28" y2="10" stroke="#0E2235" stroke-width="2"/>
<line x1="28" y1="46" x2="28" y2="52" stroke="#0E2235" stroke-width="2"/>
</svg>
</div>
<div class="triad-name">Хук</div>
<div class="triad-eq">= shell-скрипт runtime'а</div>
<div class="triad-body">
Команда, которую запускает <strong>сам Claude Code</strong> в момент события (UserPromptSubmit, Stop, etc).
Я <strong>не могу его обойти</strong> и не вижу момент запуска. Это реальный gate.
</div>
<div class="triad-key">
<b>Зарегистрирован:</b> в <span class="mono">hooks</span> блоке settings.json.
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
II. HIERARCHY & ORDER
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">II</div>
<h2 class="section-title">Иерархия и&nbsp;порядок</h2>
<p class="section-lede">
Три разные «иерархии» накладываются друг на друга и часто путают.
<em>Контейнерная</em> отвечает на «что внутри чего».
<em>Приоритетная</em> — на «что важнее при конфликте».
<em>Временная</em> — на «что срабатывает раньше».
</p>
<div class="hier-section">
<!-- 1. CONTAINMENT -->
<div class="hier-block">
<div class="hier-block-tag">1 · Контейнерная</div>
<h3 class="hier-block-title">Что внутри чего лежит</h3>
<p class="hier-block-lede">
Плагин — упаковка. Содержит скилы, хуки, slash-команды, MCP-серверы, subagent'ы.
Сам плагин ничего не делает. Хуки регистрируются в&nbsp;settings.json и&nbsp;запускаются
самим Claude Code. Скилы — это .md-файлы, которые я читаю и которым следую.
</p>
<div class="hier-tree"><span class="root">ПЛАГИН</span> <span class="note">упаковка / контейнер</span>
├─ <span class="leaf">Skills</span> .md-инструкции для Claude
├─ <span class="leaf">Hooks</span> Python/Bash скрипты + регистрация в settings.json
├─ <span class="leaf">Slash-commands</span> /имя в промпте → запускает skill или агента
├─ <span class="leaf">MCP servers</span> внешние tool-провайдеры
└─ <span class="leaf">Subagents</span> специализированные агенты-исполнители
<span class="root">settings.json</span> <span class="note">главный runtime конфиг</span>
├─ <span class="leaf">enabledPlugins</span> что включить
├─ <span class="leaf">permissions</span> allow / deny / ask правила
├─ <span class="leaf">hooks</span> event → matcher → handler
└─ <span class="leaf">env / mcp / ...</span> остальное
<span class="note">─── ПОТОКИ ВЛИЯНИЯ ───────────────────────────────────</span>
Hook script ──> может запустить ЛЮБУЮ команду (Python, Bash, agent)
Skill markdown ──> я читаю и следую (но могу проигнорировать)
Plugin ──> ничего не делает сам — только доставляет содержимое</div>
</div>
<!-- 2. PRIORITY CHAIN -->
<div class="hier-block">
<div class="hier-block-tag">2 · Приоритетная</div>
<h3 class="hier-block-title">Что override'ит что при конфликте</h3>
<p class="hier-block-lede">
Когда правила противоречат — побеждает <em>верхний</em> уровень.
Так договорились в&nbsp;CLAUDE.md §1. Уровень 0 — единственный неотменяемый
(даже &laquo;отступления&raquo; не отменяют его).
</p>
<div class="hier-priority">
<div class="hier-priority-row locked">
<div class="hier-priority-lvl">0</div>
<div class="hier-priority-content">
<div class="hier-priority-name">Pravila §12 <span class="badge">hard rule</span></div>
<div class="hier-priority-note">Superpowers hard rule — инвокировать skill ПЕРВЫМ для подходящих задач.
§9 «Отступления» к этому не применяется. Неотменяемо.</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">1</div>
<div class="hier-priority-content">
<div class="hier-priority-name">Pravila_raboty_Claude.md</div>
<div class="hier-priority-note">Продуктовые правила работы Claude, утверждены заказчиком (~13 секций).</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">2a</div>
<div class="hier-priority-content">
<div class="hier-priority-name">CLAUDE.md</div>
<div class="hier-priority-note">Общая оперативная карта проекта, ссылается на источники истины.</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">2b</div>
<div class="hier-priority-content">
<div class="hier-priority-name">Tooling Прил.&nbsp;Н</div>
<div class="hier-priority-note">Детальный реестр 33 инструментов. При конфликте с 2a — приоритет у CLAUDE.md как корневой карты.</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">3</div>
<div class="hier-priority-content">
<div class="hier-priority-name">Plugin_stack_rules.md</div>
<div class="hier-priority-note">Координирующий слой между плагинами (Superpowers + Frontend Design + UPM + 21st Magic), 16 правил.</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">4</div>
<div class="hier-priority-content">
<div class="hier-priority-name">~/.claude/settings.json</div>
<div class="hier-priority-note">Runtime config: хуки, permissions, плагины. Исполняется средой Claude Code, не мной.</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">5</div>
<div class="hier-priority-content">
<div class="hier-priority-name">memory/*.md</div>
<div class="hier-priority-note">Кросс-сессионные факты о проекте, заказчике, окружении. Может быть stale — нужно verify.</div>
</div>
</div>
<div class="hier-priority-row">
<div class="hier-priority-lvl">6</div>
<div class="hier-priority-content">
<div class="hier-priority-name">Прочие плагины</div>
<div class="hier-priority-note">claude-md-management, ui-ux-pro-max, frontend-design, и&nbsp;т.&nbsp;д. — поведенческие подсказки.</div>
</div>
</div>
</div>
</div>
<!-- 3. TIMING -->
<div class="hier-block">
<div class="hier-block-tag">3 · Временная</div>
<h3 class="hier-block-title">В&nbsp;каком порядке всё срабатывает</h3>
<p class="hier-block-lede">
События имеют фиксированный порядок в&nbsp;жизненном цикле сессии. Цвет верхней полосы
— это частота срабатывания: <em>один раз</em> (зелёный), <em>на каждый submit</em> (синий),
<em>на каждый tool call</em> (янтарь), <em>нерегулярно</em> (ржавый).
</p>
<div class="hier-timing">
<div class="hier-event once">
<div class="hier-event-num">1·once</div>
<div class="hier-event-name">SessionStart</div>
<div class="hier-event-freq">один раз на старте сессии</div>
<div class="hier-event-script">economy-self-check.py</div>
</div>
<div class="hier-event per-turn">
<div class="hier-event-num">2·per submit</div>
<div class="hier-event-name">UserPromptSubmit</div>
<div class="hier-event-freq">каждый раз когда вы отправляете промпт</div>
<div class="hier-event-script">economy-mode.py</div>
</div>
<div class="hier-event per-tool">
<div class="hier-event-num">3·per tool</div>
<div class="hier-event-name">PreToolUse</div>
<div class="hier-event-freq">перед каждым моим tool-вызовом</div>
<div class="hier-event-script">skill-marker · skill-check · state-guard</div>
</div>
<div class="hier-event special">
<div class="hier-event-num">4·per response</div>
<div class="hier-event-name">Stop</div>
<div class="hier-event-freq">конец моего ответа на вас</div>
<div class="hier-event-script">Sonnet 4.6 verifier (agent-type)</div>
</div>
<div class="hier-event special">
<div class="hier-event-num">5·irregular</div>
<div class="hier-event-name">PostCompact</div>
<div class="hier-event-freq">когда runtime сжимает старые сообщения</div>
<div class="hier-event-script">economy-postcompact.py</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
III. TIMELINE OF A TURN
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">III</div>
<h2 class="section-title">Хронология одного запроса</h2>
<p class="section-lede">
Что именно происходит за кулисами, пока вы пишете промпт и читаете ответ.
Пять чёрных дисков — главные события. Внутренний прямоугольник —
то, что повторяется на каждый мой tool-вызов.
</p>
<div class="timeline">
<div class="timeline-rail">
<div class="timeline-line"></div>
<div class="timeline-steps">
<div class="t-step">
<div class="t-step-dot user"></div>
<div class="t-step-label">Шаг 1</div>
<div class="t-step-title">Вы пишете промпт</div>
<div class="t-step-desc">с опциональным «экономия N%» в самом конце</div>
</div>
<div class="t-step">
<div class="t-step-dot fire"></div>
<div class="t-step-label">UserPromptSubmit</div>
<div class="t-step-title">Парсер уровня</div>
<div class="t-step-desc">парсит экономию, пишет state-файл, инжектит правила в мой контекст</div>
<div class="t-step-script">economy-mode.py</div>
</div>
<div class="t-step">
<div class="t-step-dot"></div>
<div class="t-step-label">Шаг 3</div>
<div class="t-step-title">Я думаю и действую</div>
<div class="t-step-desc">читаю, вызываю инструменты, привожу аргументы</div>
</div>
<div class="t-step">
<div class="t-step-dot danger"></div>
<div class="t-step-label">Stop · agent</div>
<div class="t-step-title">Верификатор</div>
<div class="t-step-desc">Sonnet&nbsp;4.6 читает ответ, ловит cherry-pick и блокирует</div>
<div class="t-step-script">claude-sonnet-4-6</div>
</div>
<div class="t-step">
<div class="t-step-dot done"></div>
<div class="t-step-label">Шаг 5</div>
<div class="t-step-title">Вы видите ответ</div>
<div class="t-step-desc">проверенный, или с пометкой о повторной попытке</div>
</div>
</div>
<div class="timeline-inner">
<span class="timeline-inner-tag">Внутри шага 3 · PreToolUse</span>
<div class="timeline-inner-grid">
<div class="t-inner-step">
<div class="t-inner-title">Маркер скила</div>
<div class="t-inner-trigger">matcher: Skill</div>
<div class="t-inner-desc">Каждый раз, когда я вызываю Skill — фиксирует «отметку» в темпе сессии.
Часть механизма «дисциплина».</div>
<div class="t-step-script" style="margin-top:8px;">skill-marker.py</div>
</div>
<div class="t-inner-step">
<div class="t-inner-title">Проверка дисциплины</div>
<div class="t-inner-trigger">matcher: Edit|Write|MultiEdit</div>
<div class="t-inner-desc">Если я делаю правки без вызова скила — напоминает о §12 правил Claude.
Не блокирует, только подсказывает.</div>
<div class="t-step-script" style="margin-top:8px;">skill-check.py</div>
</div>
<div class="t-inner-step special">
<div class="t-inner-title">Страж экономии</div>
<div class="t-inner-trigger">matcher: Edit|Write|MultiEdit|Bash|Agent</div>
<div class="t-inner-desc">Напоминает активный уровень при каждом действии. Ловит Bash-обходы (<span class="mono">sed&nbsp;-i</span>, <span class="mono">echo&nbsp;&gt;</span>).
Передаёт уровень subagent'у.</div>
<div class="t-step-script" style="margin-top:8px;">economy-state-guard.py</div>
</div>
</div>
</div>
<div class="timeline-parallel">
<div class="timeline-parallel-title">Происходит отдельно</div>
<div class="timeline-parallel-list">
<div class="tp-item">
<span class="tp-item-when">На&nbsp;старте сессии</span>
<span class="tp-item-what">
<strong>economy-self-check.py</strong> проверяет, что все 5 hook-скриптов и Python на месте,
а settings.json валиден. При проблемах — видимое предупреждение в UI.
</span>
</div>
<div class="tp-item">
<span class="tp-item-when">После авто-сжатия</span>
<span class="tp-item-what">
<strong>economy-postcompact.py</strong> re-injects активный уровень обратно в контекст,
чтобы я не «забывал» правила после потери начала сессии.
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
III. HOOK ROSTER
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">IV</div>
<h2 class="section-title">Реестр хуков — построчно</h2>
<p class="section-lede">
Семь активных хуков, четыре уникальных события, два типа исполнителей.
Шесть хуков — обычные shell-команды (Python-скрипты), один — agent-type с моделью Sonnet&nbsp;4.6.
</p>
<div class="roster">
<div class="roster-row header">
<div>Событие</div>
<div>Matcher</div>
<div>Что делает</div>
<div>Тип</div>
</div>
<div class="roster-row">
<div class="r-event">SessionStart</div>
<div class="r-matcher">(any)</div>
<div class="r-desc">
<strong>economy-self-check.py</strong> · Проверяет инфраструктуру: hook-скрипты, Python в PATH, settings.json.
</div>
<div class="r-type cmd">command</div>
</div>
<div class="roster-row">
<div class="r-event">UserPromptSubmit</div>
<div class="r-matcher">(any)</div>
<div class="r-desc">
<strong>economy-mode.py</strong> · Парсит «экономия N%» в конце промпта, пишет state, инжектит правила.
</div>
<div class="r-type cmd">command</div>
</div>
<div class="roster-row">
<div class="r-event">PreToolUse</div>
<div class="r-matcher">Skill</div>
<div class="r-desc">
<strong>skill-marker.py</strong> · «Дисциплина»: ставит per-session отметку «скил был вызван».
</div>
<div class="r-type cmd">command</div>
</div>
<div class="roster-row">
<div class="r-event">PreToolUse</div>
<div class="r-matcher">Edit|Write|MultiEdit</div>
<div class="r-desc">
<strong>skill-check.py</strong> · «Дисциплина»: если отметки нет — напоминание о §12 правил Claude.
</div>
<div class="r-type cmd">command</div>
</div>
<div class="roster-row">
<div class="r-event">PreToolUse</div>
<div class="r-matcher">Edit|Write|MultiEdit|Bash|Agent</div>
<div class="r-desc">
<strong>economy-state-guard.py</strong> · Reminder активного уровня + Bash-bypass detection + subagent inheritance.
</div>
<div class="r-type cmd">command</div>
</div>
<div class="roster-row">
<div class="r-event">PostCompact</div>
<div class="r-matcher">(any)</div>
<div class="r-desc">
<strong>economy-postcompact.py</strong> · После авто-сжатия истории re-injects правила активного уровня.
</div>
<div class="r-type cmd">command</div>
</div>
<div class="roster-row">
<div class="r-event">Stop</div>
<div class="r-matcher">(any)</div>
<div class="r-desc">
<strong>Sonnet 4.6 verifier</strong> · Inline agent в settings.json. Читает мой ответ + tool calls,
эмитит decision: «block» при нарушениях. Timeout 90&nbsp;сек.
</div>
<div class="r-type agent">agent</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
IV. PERMISSIONS BLOCK
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">V</div>
<h2 class="section-title">Блок разрешений — Stage&nbsp;0&nbsp;ratchet</h2>
<p class="section-lede">
Декларативная защита от обхода. Эти правила в settings.json исполняются Claude Code <em>до</em> того,
как я успею что-то сделать. После их установки даже я сам не могу нейтрализовать систему через Edit или Bash —
проверено на практике.
</p>
<div class="perms">
<div class="perm-card allow">
<span class="perm-card-num">1</span>
<div class="perm-card-label">allow</div>
<div class="perm-card-title">Разрешено<br>без вопросов</div>
<div class="perm-card-body">
Одно правило: <span class="mono">Bash(git push origin main:*)</span> — пуш в main без диалога.
Всё остальное идёт по обычным правилам Claude Code.
</div>
</div>
<div class="perm-card deny">
<span class="perm-card-num">7</span>
<div class="perm-card-label">deny</div>
<div class="perm-card-title">Жёстко<br>заблокировано</div>
<div class="perm-card-body">
Семь паттернов: <span class="mono">rm</span> и <span class="mono">mv</span> на hook-скрипты,
на settings.json, и на state-файлы экономии. Никаких prompts — просто отказ.
</div>
</div>
<div class="perm-card ask">
<span class="perm-card-num">16</span>
<div class="perm-card-label">ask</div>
<div class="perm-card-title">Только<br>с вашим approve</div>
<div class="perm-card-body">
Шестнадцать правил: каждый Edit и Write на settings.json или любой hook-скрипт триггерит
permission prompt. Вы видите, что я хочу сделать, и решаете.
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
V. PLUGINS
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">VI</div>
<h2 class="section-title">Установленные плагины</h2>
<p class="section-lede">
Четыре плагина, доставленных через marketplace. Каждый включает в себя один или больше скилов.
Сами плагины ничего не делают — только привозят содержимое.
</p>
<div class="plugins">
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">superpowers</div>
<div class="plugin-card-scope">obra/superpowers · v5.1.0</div>
</div>
<div class="plugin-card-desc">
Главный плагин дисциплины процесса работы. Содержит 14 скилов: brainstorm, plan, execute,
TDD, debug, code-review, verify, parallel agents, worktrees, finishing-branch, writing-skills…
Связан с §12&nbsp;Pravila — half-вес проекта.
</div>
<div class="plugin-skills-list">
14&nbsp;skills · процесс работы
</div>
</div>
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">claude-md-management</div>
<div class="plugin-card-scope">anthropic · claude-plugins-official</div>
</div>
<div class="plugin-card-desc">
Единственный канал правок корневого CLAUDE.md. Не даёт ему расходиться с Pravila и Tooling.
Содержит claude-md-improver (skill — audit) и revise-claude-md (slash-command — capture learnings).
</div>
<div class="plugin-skills-list">
1&nbsp;skill + 1&nbsp;slash-command · инфраструктура CLAUDE.md
</div>
</div>
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">frontend-design</div>
<div class="plugin-card-scope">anthropic · claude-plugins-official</div>
</div>
<div class="plugin-card-desc">
Помощник для построения отличающихся frontend-интерфейсов. Знает 50+ стилей,
принципы типографики, цвета, motion, layout. Используется для UI работы — например, для
этого документа.
</div>
<div class="plugin-skills-list">
1&nbsp;skill · UI/UX дизайн
</div>
</div>
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">ui-ux-pro-max</div>
<div class="plugin-card-scope">nextlevelbuilder · ui-ux-pro-max-skill</div>
</div>
<div class="plugin-card-desc">
Резерв-библиотека: 67 UI styles, 161 palette, 57 font pairings, 99 UX guidelines, 25 chart types
(across 15+ tech stacks). Off-phase tool — активируется только через R14 pipeline в Plugin Stack Rules.
</div>
<div class="plugin-skills-list">
1&nbsp;skill · резерв-библиотека UI/UX
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
VI. SKILLS BY PURPOSE
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">VII</div>
<h2 class="section-title">Скилы по&nbsp;плагинам</h2>
<p class="section-lede">
Все 28 capabilities (27 skills + 1 slash-command) сгруппированы по родительскому плагину.
18 принадлежат одному из 4 установленных плагинов (17 skills + 1 command), 10 — &laquo;standalone / встроенные&raquo;
(не доставляются плагином, идут с Claude Code как часть базовой системы).
</p>
<div class="skills-purpose">
<div class="sp-row">
<div class="sp-cat">
<div class="sp-cat-symbol"></div>
<div class="sp-cat-name">superpowers</div>
<div class="sp-cat-meta">14&nbsp;skills · obra/superpowers v5.1.0</div>
</div>
<div class="sp-skills-detail">
<div class="sp-skill-row">
<div class="sp-skill-key">brainstorming</div>
<div class="sp-skill-what"><em>Идея → спек.</em> Через диалог уточняет требования, предлагает 2-3 подхода с trade-off'ами. Не позволяет писать код до утверждения дизайна.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">writing-plans</div>
<div class="sp-skill-what"><em>Спек → пошаговый план.</em> Bite-sized задачи (2-5 мин каждая) с точными путями файлов, кодом, командами и TDD-структурой.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">executing-plans</div>
<div class="sp-skill-what"><em>План → выполнение.</em> Исполняет существующий план по шагам с checkpoint'ами для ревью между задачами.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">test-driven-development</div>
<div class="sp-skill-what"><em>Iron law: тест ДО кода.</em> Red (увидеть как тест падает), потом green (минимальная реализация), потом refactor. Никаких «тестов после».</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">systematic-debugging</div>
<div class="sp-skill-what"><em>4 фазы перед любым фиксом.</em> Root cause → pattern → hypothesis → fix. Минимум 3 гипотезы. Запрет «быстрых патчей».</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">requesting-code-review</div>
<div class="sp-skill-what"><em>Перед merge / PR.</em> Двухстадийный review через subagent'ы: spec compliance + code quality.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">receiving-code-review</div>
<div class="sp-skill-what"><em>Когда получил feedback ревью.</em> Правила обработки замечаний без слепого согласия и без отвержения любой критики.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">verification-before-completion</div>
<div class="sp-skill-what"><em>Перед claim «готово».</em> Обязательно запустить verification команду, проверить exit code и output. Никаких «должно работать».</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">finishing-a-development-branch</div>
<div class="sp-skill-what"><em>Когда работа на ветке закончена.</em> Структурный выбор: merge / PR / cleanup с обоснованием каждого варианта.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">using-git-worktrees</div>
<div class="sp-skill-what"><em>Изоляция feature-работы.</em> Через `git worktree` — отдельный workspace вне current branch.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">subagent-driven-development</div>
<div class="sp-skill-what"><em>Диспатч свежего subagent'а на каждую задачу плана.</em> Изоляция контекста + 2-стадийный review между задачами.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">dispatching-parallel-agents</div>
<div class="sp-skill-what"><em>2+ независимых задачи без shared state.</em> Параллельные subagent'ы вместо последовательного выполнения. Экономия времени.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">using-superpowers</div>
<div class="sp-skill-what"><em>Базовый skill про другие skills.</em> Объясняет как находить и инвокировать остальные. Обычно срабатывает в начале сессии.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">writing-skills</div>
<div class="sp-skill-what"><em>Когда создаёшь новый skill.</em> Правила его написания, валидации и deployment.</div>
</div>
</div>
</div>
<div class="sp-row">
<div class="sp-cat">
<div class="sp-cat-symbol"></div>
<div class="sp-cat-name">claude-md-management</div>
<div class="sp-cat-meta">1&nbsp;skill + 1&nbsp;command · anthropic · claude-plugins-official</div>
</div>
<div class="sp-skills-detail">
<div class="sp-skill-row">
<div class="sp-skill-key">claude-md-improver</div>
<div class="sp-skill-what"><em>Audit + targeted updates CLAUDE.md.</em> Единственный канал структурных правок: добавление/удаление секций, версии в&nbsp;шапке, правки правил.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">revise-claude-md <span style="color:var(--rust); font-style:italic;">(command)</span></div>
<div class="sp-skill-what"><em>Захват session-learnings.</em> Новые квирки, команды, паттерны из текущей сессии → автоматически в CLAUDE.md. Доставляется как slash-command в <span class="mono">commands/</span>, не skill.</div>
</div>
</div>
</div>
<div class="sp-row">
<div class="sp-cat">
<div class="sp-cat-symbol"></div>
<div class="sp-cat-name">frontend-design</div>
<div class="sp-cat-meta">1&nbsp;skill · anthropic · claude-plugins-official</div>
</div>
<div class="sp-skills-detail">
<div class="sp-skill-row">
<div class="sp-skill-key">frontend-design</div>
<div class="sp-skill-what"><em>Создание distinctive UI.</em> Избегает generic AI-aesthetics. Distinctive fonts, bold direction, осознанные дизайн-выборы. Эта страница построена через него.</div>
</div>
</div>
</div>
<div class="sp-row">
<div class="sp-cat">
<div class="sp-cat-symbol"></div>
<div class="sp-cat-name">ui-ux-pro-max</div>
<div class="sp-cat-meta">1&nbsp;skill · nextlevelbuilder · ui-ux-pro-max-skill</div>
</div>
<div class="sp-skills-detail">
<div class="sp-skill-row">
<div class="sp-skill-key">ui-ux-pro-max</div>
<div class="sp-skill-what"><em>Резерв-библиотека UI/UX.</em> 67 UI styles, 161 palette, 57 font pairings, 99 UX guidelines, 25 chart types (across 15+ tech stacks). Активируется через PSR R14 pipeline.</div>
</div>
</div>
</div>
<div class="sp-row">
<div class="sp-cat">
<div class="sp-cat-symbol"></div>
<div class="sp-cat-name">Standalone / встроенные</div>
<div class="sp-cat-meta">10&nbsp;skills · без плагина (часть базовой системы Claude Code)</div>
</div>
<div class="sp-skills-detail">
<div class="sp-skill-row">
<div class="sp-skill-key">update-config</div>
<div class="sp-skill-what"><em>Правки settings.json.</em> Хуки, permissions, env vars, MCP servers, plugins. Любая автоматизация behaviour'а — через этот skill.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">keybindings-help</div>
<div class="sp-skill-what"><em>Клавиатурные сокращения.</em> Настройка `~/.claude/keybindings.json` — chord-bindings, rebind keys.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">simplify</div>
<div class="sp-skill-what"><em>Review недавнего кода.</em> Reuse / quality / efficiency. Находит дубли, over-engineering, dead code — потом фиксит.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">fewer-permission-prompts</div>
<div class="sp-skill-what"><em>Снижение шума permission prompts.</em> Сканирует transcript'ы, добавляет allowlist в settings.json для частых read-only действий.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">init</div>
<div class="sp-skill-what"><em>Новый проект → новый CLAUDE.md.</em> Инициализация документации для нового codebase с анализом структуры.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">claude-api</div>
<div class="sp-skill-what"><em>Claude API / Anthropic SDK apps.</em> Build / debug / optimize. Также миграция между версиями моделей (4.5 → 4.6 → 4.7).</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">loop</div>
<div class="sp-skill-what"><em>Запуск prompt'а на recurring interval.</em> Например `/loop 5m /foo` — каждые 5 мин. Или self-paced если без интервала. Для polling, мониторинга.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">schedule</div>
<div class="sp-skill-what"><em>Cron-расписания для агентов.</em> Создание / управление scheduled remote routines. Также one-time scheduled запуски («сделай это завтра в 15:00»).</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">review</div>
<div class="sp-skill-what"><em>Review текущего PR на GitHub.</em> Чтение diff'а, замечания по логике, стилю, тестам. Подготовка к merge.</div>
</div>
<div class="sp-skill-row">
<div class="sp-skill-key">security-review</div>
<div class="sp-skill-what"><em>Security audit pending changes.</em> Полный security review текущей ветки: OWASP top 10, secrets, RLS, injection vectors.</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
VII. FILESYSTEM
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">VIII</div>
<h2 class="section-title">Карта на&nbsp;диске</h2>
<p class="section-lede">
Где физически лежит каждый компонент. Три уровня: <em>user</em> (общая инфраструктура Claude Code),
<em>brain (source)</em> (репозиторий-источник, который правится осознанно), <em>project (consumer)</em>
(любой проект, в который brain установлен через <span class="mono">install.sh</span>).
</p>
<div class="fs">
<pre style="margin:0;">
<span class="fs-section-tag">user</span><span class="fs-path">C:\Users\Administrator\<b>.claude\</b></span>
├── settings.json <span class="fs-comment">главный конфиг: permissions + hooks (собран из settings-fragment.json)</span>
├── settings.json.backup-pre-economy-hardening
├── <span class="fs-path"><b>hooks/</b></span> <span class="fs-comment">Python-скрипты хуков (синкаются из brain user-level-files/hooks/)</span>
│ ├── skill-marker.py <span class="fs-comment">PreToolUse(Skill)</span>
│ ├── skill-check.py <span class="fs-comment">PreToolUse(Edit|Write|MultiEdit)</span>
│ ├── economy-mode.py (v3) <span class="fs-comment">UserPromptSubmit + state writer</span>
│ ├── economy-mode-test.py <span class="fs-comment">54 теста</span>
│ ├── economy-self-check.py <span class="fs-comment">SessionStart</span>
│ ├── economy-self-check-test.py <span class="fs-comment">4 теста</span>
│ ├── economy-state-guard.py <span class="fs-comment">PreToolUse + Bash detection</span>
│ ├── economy-state-guard-test.py <span class="fs-comment">6 тестов</span>
│ ├── economy-verifier.py <span class="fs-comment">Stop wrapper</span>
│ └── economy-postcompact.py <span class="fs-comment">PostCompact</span>
├── <span class="fs-path"><b>plugins/cache/</b></span> <span class="fs-comment">загруженные плагины (marketplace-источники в marketplaces.json)</span>
│ ├── superpowers-dev/superpowers/5.1.0/ <span class="fs-comment">obra/superpowers</span>
│ ├── claude-plugins-official/claude-md-management/1.0.0/
│ ├── claude-plugins-official/frontend-design/
│ └── ui-ux-pro-max-skill/ui-ux-pro-max/2.5.0/
└── <span class="fs-path"><b>projects/&lt;cwd&gt;/memory/</b></span> <span class="fs-comment">долгосрочная память (per-project)</span>
├── MEMORY.md (index)
└── ... per-project files
<span class="fs-section-tag">brain (source)</span><span class="fs-path">c:\моя\проекты\<b>claude-brain\</b></span>
├── manifest.json <span class="fs-comment">SHA-256 hashes всех файлов brain v1.0</span>
├── CLAUDE.md / README.md / CHANGELOG.md
├── <span class="fs-path"><b>project-files/</b></span> <span class="fs-comment">копируется в consumer-проекты install.sh'ом</span>
│ ├── CLAUDE.md.template
│ ├── .mcp.json.template <span class="fs-comment">playwright + github + semgrep</span>
│ └── docs/
│ ├── Pravila_raboty_Claude.template.md
│ ├── Plugin_stack_rules.template.md
│ ├── Tooling.template.md
│ └── visualizations/hooks-skills-plugins-map.html <span class="fs-comment">вы тут</span>
├── <span class="fs-path"><b>user-level-files/</b></span> <span class="fs-comment">копируется в ~/.claude/ install.sh'ом</span>
│ ├── hooks/ <span class="fs-comment">7 рантайм + 3 test .py</span>
│ ├── settings-fragment.json <span class="fs-comment">фрагмент для merge в settings.json</span>
│ ├── marketplaces.json <span class="fs-comment">3 marketplace-источника</span>
│ ├── plugins-manifest.json <span class="fs-comment">4 плагина + версии</span>
│ └── mcp-user.template.json <span class="fs-comment">magic (21st.dev)</span>
├── <span class="fs-path"><b>scripts/</b></span> <span class="fs-comment">инструменты sync</span>
│ ├── install.sh <span class="fs-comment">copy brain → consumer / ~/.claude</span>
│ ├── verify.sh <span class="fs-comment">cross-check hashes vs manifest.json</span>
│ └── extract.sh <span class="fs-comment">rescue: consumer → brain</span>
└── docs/ <span class="fs-comment">документация brain'а самого</span>
├── architecture.md
├── how-to-use-brain.md
├── secrets-and-tokens.md
└── sessions/2026-05-11-bootstrap-session.md
<span class="fs-section-tag">project (consumer)</span><span class="fs-path">&lt;consumer-project&gt;/</span>
├── CLAUDE.md <span class="fs-comment">из template, substitutions заполнены при install</span>
├── .mcp.json <span class="fs-comment">project-mode MCP (playwright/github/semgrep)</span>
└── docs/
├── Pravila_raboty_Claude.md <span class="fs-comment">§12 hard rule (без версии в имени)</span>
├── Plugin_stack_rules.md <span class="fs-comment">16 правил координации</span>
├── Tooling.md <span class="fs-comment">реестр инструментов проекта</span>
├── CHANGELOG_claude_md.md
├── superpowers/{specs,plans}/ <span class="fs-comment">создаются по мере работы</span>
└── visualizations/hooks-skills-plugins-map.html <span class="fs-comment">этот файл, installed copy</span>
</pre>
</div>
</div>
</section>
<!-- ============================================================
VIII. MENTAL MODEL
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">IX</div>
<h2 class="section-title">Кто за&nbsp;что отвечает</h2>
<p class="section-lede">
Четыре действующих лица — четыре роли. Каждый делает то, что больше никто не может,
и не лезет в чужой огород. Это про разделение обязанностей в системе.
</p>
<div class="mental">
<div class="mental-stage">
<div class="mental-actor you">
<div class="mental-tag">Actor&nbsp;01</div>
<div class="mental-name">Вы (Дмитрий)</div>
<ul class="mental-list">
<li>Пишете промпт, опционально ставите «экономия N%» в конце</li>
<li>Approve'ите permission prompts на правки hook-файлов</li>
<li>Можете выключить хуки через settings.json &rarr; disableAllHooks</li>
<li>Вне Claude Code — единственный, кто может править settings/hooks без вопросов</li>
</ul>
</div>
<div class="mental-actor runtime">
<div class="mental-tag">Actor&nbsp;02</div>
<div class="mental-name">Claude Code Runtime</div>
<ul class="mental-list">
<li>Запускает хуки на нужных событиях, не спрашивая меня</li>
<li>Применяет permissions (deny/ask) к моим действиям</li>
<li>Передаёт мне injected additionalContext от хуков</li>
<li>Auto-mode classifier ловит мои попытки обхода</li>
</ul>
</div>
<div class="mental-actor claude">
<div class="mental-tag">Actor&nbsp;03</div>
<div class="mental-name">Я (Claude Opus 4.7)</div>
<ul class="mental-list">
<li>Читаю injected правила и стараюсь им следовать</li>
<li>Вызываю skills — добровольно или по §12 требованию</li>
<li>Использую tools: Edit/Write/Bash/Read/Skill/etc.</li>
<li><em>Не могу</em> обойти хуки или permissions — проверено</li>
</ul>
</div>
<div class="mental-actor verifier">
<div class="mental-tag">Actor&nbsp;04</div>
<div class="mental-name">Sonnet 4.6 verifier</div>
<ul class="mental-list">
<li>Читает мой финальный ответ + последние tool calls</li>
<li>Сравнивает с активным уровнем экономии</li>
<li>При cherry-pick или claim'е без evidence — <strong>блок</strong></li>
<li>До 3 retry попыток за turn, потом — эскалация к вам</li>
</ul>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
X. CONNECTIONS GRAPH
============================================================ -->
<section class="section" id="graph-section">
<div class="frame">
<div class="section-num display-i">X</div>
<h2 class="section-title">Связи &mdash; интерактивная карта</h2>
<p class="section-lede">
50 узлов, 52 ребра, 8 типов связей. Кликни на любой узел &mdash;
подсветятся все его связи + откроется панель с деталями справа.
Тяни узлы мышкой для перестановки. Фильтры в верхней панели прячут
категории по одной.
</p>
<div class="graph-controls">
<div class="graph-filters">
<button class="graph-filter active" data-type="plugin">Плагины</button>
<button class="graph-filter active" data-type="skill">Скилы</button>
<button class="graph-filter active" data-type="script">Скрипты</button>
<button class="graph-filter active" data-type="event">События</button>
<button class="graph-filter active" data-type="state">Состояние</button>
<button class="graph-filter active" data-type="perm">Права</button>
<button class="graph-filter active" data-type="rule">Правила</button>
</div>
<button class="graph-reset">Сбросить расположение</button>
</div>
<div class="graph-container">
<div class="graph-svg-wrap">
<svg class="graph-svg" viewBox="0 0 1100 700" preserveAspectRatio="xMidYMid meet" role="img" aria-label="Граф связей: 50 узлов, 52 ребра, 8 типов связей между плагинами, скилами, хуками и правилами"></svg>
</div>
<aside class="graph-sidebar">
<div class="graph-sidebar-empty">
Кликни на узел чтобы увидеть его связи&hellip;
</div>
</aside>
</div>
<div class="graph-legend">
<div class="graph-legend-section">
<h4>Узлы (категории)</h4>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--rust); border-radius:50%;"></span>Плагин (4)</div>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--blueprint); border-radius:50%;"></span>Скил/команда (28)</div>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--amber); border-radius:50%;"></span>Скрипт хука (7)</div>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--sage);"></span>Событие хука (5)</div>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--rust); transform:rotate(45deg);"></span>Файл состояния (1)</div>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--ink-fade);"></span>Права (3)</div>
<div class="graph-legend-item"><span class="graph-legend-swatch" style="background:var(--ink); border-color:var(--rust);"></span>Правило (2)</div>
</div>
<div class="graph-legend-section">
<h4>Связи (типы)</h4>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--blueprint);"></span>содержит</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--sage); border-width:2px;"></span>запускает</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--amber); border-width:2px;"></span>пишет</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--amber); border-style:dashed;"></span>читает</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--rust); border-width:3px;"></span>обязывает</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--ink-fade); border-style:dotted;"></span>ссылается</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--rust); border-style:dashed;"></span>блокирует</div>
<div class="graph-legend-item"><span class="graph-legend-line" style="border-color:var(--rust); border-style:dashed; border-width:2px;"></span>запрещает</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
XI. MCP SERVERS
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">XI</div>
<h2 class="section-title">MCP-серверы — внешние tool-провайдеры</h2>
<p class="section-lede">
Четыре сервера Model Context Protocol. Один на user-уровне (магазин компонентов), три на project-уровне
(браузер, GitHub API, статанализ). MCP — это <em>не</em> плагин и <em>не</em> хук: это отдельный процесс,
который запускается рядом с Claude Code и предоставляет дополнительные tools через stdio или HTTP.
</p>
<div class="plugins">
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">magic</div>
<div class="plugin-card-scope">user · stdio · npx</div>
</div>
<div class="plugin-card-desc">
UI-генерация компонентов от 21st.dev. Поиск, inspiration, refiner, logo search — для быстрых
визуальных набросков. Зарегистрирован в <span class="mono">~/.claude/mcp.json</span>
(template: <span class="mono">user-level-files/mcp-user.template.json</span>).
</div>
<div class="plugin-skills-list">
<span class="mono">npx @21st-dev/magic@latest</span> · API_KEY required
</div>
</div>
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">playwright</div>
<div class="plugin-card-scope">project · stdio · npx</div>
</div>
<div class="plugin-card-desc">
Headless-браузер. Открытие <span class="mono">web/*.html</span>, screenshot, проверка интерактива,
навигация по DOM. Используется для визуальной верификации UI-работы.
</div>
<div class="plugin-skills-list">
<span class="mono">npx @playwright/mcp@latest</span>
</div>
</div>
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">github</div>
<div class="plugin-card-scope">project · HTTP · hosted</div>
</div>
<div class="plugin-card-desc">
Официальный hosted GitHub MCP. Issues, PRs, файлы, search, actions. Требует
<span class="mono">GITHUB_TOKEN</span> (PAT, scopes: repo, read:org).
Заменил deprecated <span class="mono">@modelcontextprotocol/server-github</span> 06.05.2026.
</div>
<div class="plugin-skills-list">
<span class="mono">https://api.githubcopilot.com/mcp</span>
</div>
</div>
<div class="plugin-card">
<div class="plugin-card-header">
<div class="plugin-card-name">semgrep</div>
<div class="plugin-card-scope">project · stdio · npx</div>
</div>
<div class="plugin-card-desc">
SAST. Семантический поиск и анализ кода через Semgrep rules прямо в Claude Code.
Для security-review и поиска паттернов уязвимостей.
</div>
<div class="plugin-skills-list">
<span class="mono">npx semgrep-mcp</span>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================
XII. ACTIONS
============================================================ -->
<section class="section">
<div class="frame">
<div class="section-num display-i">XII</div>
<h2 class="section-title">Что вы можете сделать</h2>
<p class="section-lede">
Шесть практических действий. Каждое — одна команда или одно изменение в одном файле.
</p>
<div class="actions">
<div class="action">
<span class="action-num">1</span>
<div class="action-want">Если вы хотите…</div>
<div class="action-do">Активировать экономию для одной задачи</div>
<div class="r-desc">Допишите в самый конец промпта одно из: <span class="mono">экономия 0%</span> · <span class="mono">экономия 25%</span> · <span class="mono">экономия 50%</span> · <span class="mono">экономия 75%</span>. 0% — максимум, 75% — мягко, без ключа — обычный режим.</div>
</div>
<div class="action">
<span class="action-num">2</span>
<div class="action-want">Если вы хотите…</div>
<div class="action-do">Посмотреть, что сейчас включено</div>
<code class="action-cmd">python -c "import json; s=json.load(open(r'C:\Users\Administrator\.claude\settings.json',encoding='utf-8')); print(list(s['hooks'].keys()))"</code>
</div>
<div class="action">
<span class="action-num">3</span>
<div class="action-want">Если вы хотите…</div>
<div class="action-do">Вызвать скил вручную</div>
<div class="r-desc">Напишите в промпте slash-команду: <span class="mono">/superpowers:brainstorming</span> · <span class="mono">/claude-md-management:claude-md-improver</span> · <span class="mono">/init</span> · <span class="mono">/review</span> · etc.</div>
</div>
<div class="action">
<span class="action-num">4</span>
<div class="action-want">Если вы хотите…</div>
<div class="action-do">Выключить все хуки временно</div>
<div class="r-desc">В <span class="mono">~/.claude/settings.json</span> на верхнем уровне добавьте <span class="mono">"disableAllHooks":&nbsp;true</span>. Потребует ваш approve через ask-rule (так как Edit на settings.json). Уберёт всё включая дисциплину и верификатор.</div>
</div>
<div class="action">
<span class="action-num">5</span>
<div class="action-want">Если вы хотите…</div>
<div class="action-do">Проверить, что хуки работают</div>
<div class="r-desc">Откройте новую сессию Claude Code. SessionStart self-check сработает автоматически. Если что-то сломано — увидите <em>«Economy hook self-check FAILED»</em> в начале сессии.</div>
</div>
<div class="action">
<span class="action-num">6</span>
<div class="action-want">Если вы хотите…</div>
<div class="action-do">Откатить всё на до-economy состояние</div>
<code class="action-cmd">copy "C:\Users\Administrator\.claude\settings.json.backup-pre-economy-hardening" "C:\Users\Administrator\.claude\settings.json"</code>
</div>
</div>
</div>
</section>
<!-- ============================================================
FOOTER
============================================================ -->
<footer class="foot">
<div class="frame" style="display:flex; justify-content:space-between; flex-wrap:wrap; gap:32px; align-items:baseline;">
<div>
<div class="caps" style="margin-bottom:6px;">Document meta</div>
<span class="mono">hooks-skills-plugins-map.html</span> &middot;
<span class="mono">2026-05-11</span> &middot;
<span class="mono">brain v1.0 · 7 хуков / 4 плагина / 4 MCP / 28 capabilities</span>
</div>
<div class="foot-ornament">~&nbsp;fin&nbsp;~</div>
<div style="text-align:right;">
<div class="caps" style="margin-bottom:6px;">Источник правды</div>
<span class="mono">~/.claude/settings.json</span><br>
<span style="font-style:italic;">прочитан напрямую, не из memory</span>
</div>
</div>
</footer>
</main>
<script>
// ============================================================
// CONNECTIONS GRAPH DATA
// ============================================================
const GRAPH_NODES = [
// === Plugins (4) ===
{ id: 'plg:superpowers', type: 'plugin', label: 'superpowers', desc: 'Главный плагин дисциплины процесса работы. 14 скилов.' },
{ id: 'plg:claude-md', type: 'plugin', label: 'claude-md-management', desc: 'Единственный канал правок CLAUDE.md. 2 скила.' },
{ id: 'plg:fd', type: 'plugin', label: 'frontend-design', desc: 'Создание distinctive frontend. Anthropic plugin.' },
{ id: 'plg:upm', type: 'plugin', label: 'ui-ux-pro-max', desc: 'Резерв-библиотека UI/UX (50+ стилей, 161 палитра).' },
// === Skills (28) ===
// Superpowers (14)
{ id: 'skl:brainstorming', type: 'skill', label: 'brainstorming', desc: 'Превращает идею в спек через диалог.' },
{ id: 'skl:writing-plans', type: 'skill', label: 'writing-plans', desc: 'Из спека → пошаговый план.' },
{ id: 'skl:executing-plans', type: 'skill', label: 'executing-plans', desc: 'Исполняет план по шагам.' },
{ id: 'skl:tdd', type: 'skill', label: 'test-driven-development', desc: 'Тест ДО кода. Red-green-refactor.' },
{ id: 'skl:debug', type: 'skill', label: 'systematic-debugging', desc: '4 фазы root cause. ≥3 гипотезы.' },
{ id: 'skl:req-review', type: 'skill', label: 'requesting-code-review', desc: 'Перед merge — двухстадийный review.' },
{ id: 'skl:recv-review', type: 'skill', label: 'receiving-code-review', desc: 'Обработка feedback ревью.' },
{ id: 'skl:verify', type: 'skill', label: 'verification-before-completion', desc: 'Перед claim готово — verify.' },
{ id: 'skl:finishing', type: 'skill', label: 'finishing-a-development-branch', desc: 'merge / PR / cleanup.' },
{ id: 'skl:worktrees', type: 'skill', label: 'using-git-worktrees', desc: 'Изоляция feature-работы.' },
{ id: 'skl:subagent', type: 'skill', label: 'subagent-driven-development', desc: 'Свежий subagent на каждую задачу.' },
{ id: 'skl:parallel', type: 'skill', label: 'dispatching-parallel-agents', desc: "Параллельные subagent'ы." },
{ id: 'skl:using-sp', type: 'skill', label: 'using-superpowers', desc: 'Базовый: как находить skills.' },
{ id: 'skl:writing-skills', type: 'skill', label: 'writing-skills', desc: 'Создание новых skills.' },
// claude-md-management (2)
{ id: 'skl:md-improver', type: 'skill', label: 'claude-md-improver', desc: 'Audit + targeted updates CLAUDE.md.' },
{ id: 'skl:md-revise', type: 'skill', label: 'revise-claude-md (command)', desc: 'Захват session-learnings. Доставляется как slash-command (commands/), не skill.' },
// frontend-design (1)
{ id: 'skl:fd-skill', type: 'skill', label: 'frontend-design', desc: 'Distinctive UI без AI-aesthetics.' },
// ui-ux-pro-max (1)
{ id: 'skl:upm-skill', type: 'skill', label: 'ui-ux-pro-max', desc: 'Резерв-библиотека стилей.' },
// Standalone (10)
{ id: 'skl:update-config', type: 'skill', label: 'update-config', desc: 'Правки settings.json.' },
{ id: 'skl:keybindings', type: 'skill', label: 'keybindings-help', desc: 'Клавиатурные сокращения.' },
{ id: 'skl:simplify', type: 'skill', label: 'simplify', desc: 'Review кода на reuse/quality.' },
{ id: 'skl:fewer-prompts', type: 'skill', label: 'fewer-permission-prompts', desc: 'Снижение шума prompts.' },
{ id: 'skl:init', type: 'skill', label: 'init', desc: 'Новый CLAUDE.md для нового проекта.' },
{ id: 'skl:claude-api', type: 'skill', label: 'claude-api', desc: 'Claude API / SDK apps.' },
{ id: 'skl:loop', type: 'skill', label: 'loop', desc: 'Recurring prompt на интервале.' },
{ id: 'skl:schedule', type: 'skill', label: 'schedule', desc: 'Cron-расписания для агентов.' },
{ id: 'skl:review', type: 'skill', label: 'review', desc: 'Review текущего PR.' },
{ id: 'skl:sec-review', type: 'skill', label: 'security-review', desc: 'Security audit pending changes.' },
// === Hook scripts (7) ===
{ id: 'scr:skill-marker', type: 'script', label: 'skill-marker.py', desc: 'Отметка о вызове Skill.' },
{ id: 'scr:skill-check', type: 'script', label: 'skill-check.py', desc: 'Reminder §12 если skill не вызван.' },
{ id: 'scr:economy-mode', type: 'script', label: 'economy-mode.py', desc: 'Парсит экономию N%, пишет state.' },
{ id: 'scr:economy-self-check', type: 'script', label: 'economy-self-check.py', desc: 'SessionStart runtime guard.' },
{ id: 'scr:economy-state-guard', type: 'script', label: 'economy-state-guard.py', desc: 'PreToolUse reminder + Bash bypass.' },
{ id: 'scr:economy-verifier', type: 'script', label: 'economy-verifier.py (Sonnet 4.6)', desc: 'Stop verifier — блокирует cherry-pick.' },
{ id: 'scr:economy-postcompact', type: 'script', label: 'economy-postcompact.py', desc: 'Re-inject правил после компакции.' },
// === Hook events (5) ===
{ id: 'evt:session-start', type: 'event', label: 'SessionStart', desc: 'Один раз на старте сессии.' },
{ id: 'evt:user-prompt-submit', type: 'event', label: 'UserPromptSubmit', desc: 'Каждый submit от пользователя.' },
{ id: 'evt:pre-tool-use', type: 'event', label: 'PreToolUse', desc: 'Перед каждым tool call.' },
{ id: 'evt:post-compact', type: 'event', label: 'PostCompact', desc: 'После авто-компакции.' },
{ id: 'evt:stop', type: 'event', label: 'Stop', desc: 'Конец моего ответа.' },
// === State file (1) ===
{ id: 'st:economy-state', type: 'state', label: 'claude-economy-state.json', desc: '$TEMP/claude-economy-<session_id>.json — shared state.' },
// === Permissions (3) ===
{ id: 'prm:allow', type: 'perm', label: 'permissions.allow (1)', desc: 'Разрешено без вопросов: Bash(git push origin main:*).' },
{ id: 'prm:deny', type: 'perm', label: 'permissions.deny (7)', desc: 'Жёстко заблокировано: rm/mv hook/settings/state.' },
{ id: 'prm:ask', type: 'perm', label: 'permissions.ask (16)', desc: 'С approve пользователя: Edit/Write hook files и settings.json.' },
// === Rules (2) ===
{ id: 'rul:pravila-12', type: 'rule', label: 'Pravila §12', desc: 'Hard rule: Superpowers skill ПЕРВЫМ.' },
{ id: 'rul:claude-md', type: 'rule', label: 'CLAUDE.md', desc: 'Главная карта проекта.' }
];
console.log('GRAPH_NODES:', GRAPH_NODES.length, '(expected 50)');
const GRAPH_LINKS = [
// === contains (18) — plugin → skill ===
// superpowers (14)
{ source: 'plg:superpowers', target: 'skl:brainstorming', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:writing-plans', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:executing-plans', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:tdd', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:debug', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:req-review', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:recv-review', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:verify', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:finishing', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:worktrees', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:subagent', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:parallel', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:using-sp', type: 'contains' },
{ source: 'plg:superpowers', target: 'skl:writing-skills', type: 'contains' },
// claude-md (2)
{ source: 'plg:claude-md', target: 'skl:md-improver', type: 'contains' },
{ source: 'plg:claude-md', target: 'skl:md-revise', type: 'contains' },
// fd (1)
{ source: 'plg:fd', target: 'skl:fd-skill', type: 'contains' },
// upm (1)
{ source: 'plg:upm', target: 'skl:upm-skill', type: 'contains' },
// === triggers (7) — event → script ===
{ source: 'evt:session-start', target: 'scr:economy-self-check', type: 'triggers' },
{ source: 'evt:user-prompt-submit', target: 'scr:economy-mode', type: 'triggers' },
{ source: 'evt:pre-tool-use', target: 'scr:skill-marker', type: 'triggers' },
{ source: 'evt:pre-tool-use', target: 'scr:skill-check', type: 'triggers' },
{ source: 'evt:pre-tool-use', target: 'scr:economy-state-guard', type: 'triggers' },
{ source: 'evt:post-compact', target: 'scr:economy-postcompact', type: 'triggers' },
{ source: 'evt:stop', target: 'scr:economy-verifier', type: 'triggers' },
// === writes (1) — script → state ===
{ source: 'scr:economy-mode', target: 'st:economy-state', type: 'writes' },
// === reads (3) — script → state ===
{ source: 'scr:economy-state-guard', target: 'st:economy-state', type: 'reads' },
{ source: 'scr:economy-verifier', target: 'st:economy-state', type: 'reads' },
{ source: 'scr:economy-postcompact', target: 'st:economy-state', type: 'reads' },
// === mandates (14) — Pravila §12 → 14 superpowers skills ===
{ source: 'rul:pravila-12', target: 'skl:brainstorming', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:writing-plans', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:executing-plans', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:tdd', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:debug', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:req-review', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:recv-review', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:verify', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:finishing', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:worktrees', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:subagent', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:parallel', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:using-sp', type: 'mandates' },
{ source: 'rul:pravila-12', target: 'skl:writing-skills', type: 'mandates' },
// === references (1) — CLAUDE.md → Pravila §12 ===
{ source: 'rul:claude-md', target: 'rul:pravila-12', type: 'references' },
// === blocks (7) — permissions.ask → hook scripts ===
{ source: 'prm:ask', target: 'scr:skill-marker', type: 'blocks' },
{ source: 'prm:ask', target: 'scr:skill-check', type: 'blocks' },
{ source: 'prm:ask', target: 'scr:economy-mode', type: 'blocks' },
{ source: 'prm:ask', target: 'scr:economy-self-check', type: 'blocks' },
{ source: 'prm:ask', target: 'scr:economy-state-guard', type: 'blocks' },
{ source: 'prm:ask', target: 'scr:economy-verifier', type: 'blocks' },
{ source: 'prm:ask', target: 'scr:economy-postcompact', type: 'blocks' },
// === denies (1) — permissions.deny → state file ===
{ source: 'prm:deny', target: 'st:economy-state', type: 'denies' }
];
console.log('GRAPH_LINKS:', GRAPH_LINKS.length, '(expected 52)');
// ============================================================
// RUSSIAN LABEL MAPPINGS + CLASSIFICATION
// ============================================================
const EDGE_TYPE_RU = {
contains: 'содержит',
triggers: 'запускает',
writes: 'пишет',
reads: 'читает',
mandates: 'обязывает',
references: 'ссылается',
blocks: 'блокирует',
denies: 'запрещает'
};
const NODE_TYPE_RU = {
plugin: 'Плагин',
skill: 'Скил',
script: 'Скрипт',
event: 'Событие',
state: 'Состояние',
perm: 'Права',
rule: 'Правило'
};
const EDGE_DESC = {
contains: 'Плагин упаковывает скил и доставляет его в систему как часть marketplace-пакета.',
triggers: 'Hook event запускает скрипт автоматически в момент события (SessionStart, PreToolUse, Stop, etc.).',
writes: 'Скрипт записывает данные в общий state-файл $TEMP/claude-economy-<session_id>.json для других хуков той же сессии.',
reads: 'Скрипт читает данные из state-файла, чтобы знать активный уровень экономии и применять правила.',
mandates: 'Pravila §12 hard rule обязывает использовать этот skill для подходящих задач — §9 «Отступления» НЕ применяется.',
references: 'Документ ссылается на другой как часть приоритетной цепочки правил (CLAUDE.md §1). При конфликте — приоритет у верхнего уровня.',
blocks: 'permissions.ask требует явный approve пользователя перед Edit/Write этого файла. Защита от tampering.',
denies: 'permissions.deny полностью запрещает Bash-операции (rm/mv/cp) над защищёнными файлами — обхода нет.'
};
const GOVERNANCE_TYPES = ['contains', 'mandates', 'triggers', 'blocks', 'denies'];
// ============================================================
// D3 SIMULATION + RENDER + INTERACTIVITY
// ============================================================
window.addEventListener('DOMContentLoaded', () => {
if (typeof d3 === 'undefined') {
document.querySelector('.graph-svg-wrap').innerHTML =
'<div class="graph-fallback">⚠ D3.js не загружен (нужен интернет для CDN). Остальная страница работает offline.</div>';
return;
}
const W = 1100, H = 700;
const svg = d3.select('.graph-svg');
// Y-position по типу для clustering
const Y_BY_TYPE = {
'rule': 80, 'plugin': 200, 'skill': 340,
'event': 540, 'script': 460, 'state': 380, 'perm': 600
};
const LINK_DISTANCE = {
'contains': 60, 'triggers': 50, 'writes': 40, 'reads': 40,
'mandates': 100, 'references': 80, 'blocks': 70, 'denies': 50
};
const NODE_SIZE = {
'plugin': 22, 'skill': 10, 'script': 14, 'event': 14,
'state': 16, 'perm': 16, 'rule': 18
};
// Force simulation
const sim = d3.forceSimulation(GRAPH_NODES)
.force('link', d3.forceLink(GRAPH_LINKS).id(d => d.id)
.distance(d => LINK_DISTANCE[d.type] || 50)
.strength(0.5))
.force('charge', d3.forceManyBody().strength(-280))
.force('center', d3.forceCenter(W / 2, H / 2))
.force('y', d3.forceY(d => Y_BY_TYPE[d.type] || H/2).strength(0.18))
.force('collide', d3.forceCollide().radius(d => (NODE_SIZE[d.type] || 10) + 6));
// Render links
const linkSel = svg.append('g').attr('class', 'links')
.selectAll('line')
.data(GRAPH_LINKS)
.join('line')
.attr('class', d => `gl gl-${d.type}`);
// Render nodes как <g>
const nodeSel = svg.append('g').attr('class', 'nodes')
.selectAll('g.gn-node')
.data(GRAPH_NODES)
.join('g')
.attr('class', d => `gn-node gn-node-${d.type}`);
// Shape по type
nodeSel.each(function(d) {
const g = d3.select(this);
const size = NODE_SIZE[d.type];
if (d.type === 'plugin' || d.type === 'skill' || d.type === 'script') {
g.append('circle').attr('r', size).attr('class', `gn-${d.type}`);
} else if (d.type === 'event') {
g.append('rect').attr('x', -size).attr('y', -size)
.attr('width', size*2).attr('height', size*2).attr('class', 'gn-event');
} else if (d.type === 'state') {
g.append('polygon')
.attr('points', `0,-${size} ${size},0 0,${size} -${size},0`)
.attr('class', 'gn-state');
} else if (d.type === 'perm') {
const s = size;
g.append('polygon')
.attr('points', `-${s},-${s/2} 0,-${s} ${s},-${s/2} ${s},${s/2} 0,${s} -${s},${s/2}`)
.attr('class', 'gn-perm');
} else if (d.type === 'rule') {
g.append('rect').attr('x', -size).attr('y', -size)
.attr('width', size*2).attr('height', size*2).attr('class', 'gn-rule');
}
});
// Labels
nodeSel.append('text')
.attr('class', 'gn-label')
.attr('dy', d => (NODE_SIZE[d.type] || 10) + 14)
.text(d => d.label);
// ============================================================
// INTERACTIVITY: click + highlight + sidebar
// ============================================================
const sidebar = document.querySelector('.graph-sidebar');
let activeId = null;
function showSidebar(node) {
const incoming = GRAPH_LINKS.filter(l =>
(typeof l.target === 'object' ? l.target.id : l.target) === node.id);
const outgoing = GRAPH_LINKS.filter(l =>
(typeof l.source === 'object' ? l.source.id : l.source) === node.id);
const governedBy = incoming.filter(l => GOVERNANCE_TYPES.includes(l.type));
const governing = outgoing.filter(l => GOVERNANCE_TYPES.includes(l.type));
const infoFlow = [...incoming, ...outgoing].filter(l => !GOVERNANCE_TYPES.includes(l.type));
const fmtIncoming = list => list.map(l => {
const srcId = typeof l.source === 'object' ? l.source.id : l.source;
const src = GRAPH_NODES.find(n => n.id === srcId);
return `<li>${src ? src.label : srcId} <b>${EDGE_TYPE_RU[l.type] ?? l.type}</b></li>`;
}).join('');
const fmtOutgoing = list => list.map(l => {
const tgtId = typeof l.target === 'object' ? l.target.id : l.target;
const tgt = GRAPH_NODES.find(n => n.id === tgtId);
return `<li><b>${EDGE_TYPE_RU[l.type] ?? l.type}</b> → ${tgt ? tgt.label : tgtId}</li>`;
}).join('');
const fmtInfoFlow = list => list.map(l => {
const sId = typeof l.source === 'object' ? l.source.id : l.source;
const tId = typeof l.target === 'object' ? l.target.id : l.target;
const isIncoming = tId === node.id;
if (isIncoming) {
const src = GRAPH_NODES.find(n => n.id === sId);
return `<li>${src ? src.label : sId} <b>${EDGE_TYPE_RU[l.type] ?? l.type}</b></li>`;
} else {
const tgt = GRAPH_NODES.find(n => n.id === tId);
return `<li><b>${EDGE_TYPE_RU[l.type] ?? l.type}</b> → ${tgt ? tgt.label : tId}</li>`;
}
}).join('');
const typeLabel = NODE_TYPE_RU[node.type] ?? node.type;
sidebar.innerHTML = `
<button class="graph-close" aria-label="Close">×</button>
<div class="graph-sidebar-title">${node.label}</div>
<div class="graph-sidebar-badge">${typeLabel}</div>
<div class="graph-sidebar-section">
<div class="graph-sidebar-section-label">За что отвечает</div>
<div style="font-size:0.85rem; color: var(--ink-soft); line-height: 1.5;">${node.desc}</div>
</div>
${governedBy.length ? `
<div class="graph-sidebar-section governance">
<div class="graph-sidebar-section-label">Кто руководит (${governedBy.length})</div>
<ul class="graph-conn-list">${fmtIncoming(governedBy)}</ul>
</div>` : ''}
${governing.length ? `
<div class="graph-sidebar-section governance">
<div class="graph-sidebar-section-label">Кем руководит (${governing.length})</div>
<ul class="graph-conn-list">${fmtOutgoing(governing)}</ul>
</div>` : ''}
${infoFlow.length ? `
<div class="graph-sidebar-section">
<div class="graph-sidebar-section-label">Связи — info flow (${infoFlow.length})</div>
<ul class="graph-conn-list">${fmtInfoFlow(infoFlow)}</ul>
</div>` : ''}
`;
sidebar.querySelector('.graph-close').addEventListener('click', clearHighlight);
}
function highlightNode(node) {
activeId = node.id;
const relatedIds = new Set([node.id]);
GRAPH_LINKS.forEach(l => {
const sId = typeof l.source === 'object' ? l.source.id : l.source;
const tId = typeof l.target === 'object' ? l.target.id : l.target;
if (sId === node.id) relatedIds.add(tId);
if (tId === node.id) relatedIds.add(sId);
});
nodeSel.classed('dimmed', d => !relatedIds.has(d.id));
linkSel.classed('dimmed', l => {
const sId = typeof l.source === 'object' ? l.source.id : l.source;
const tId = typeof l.target === 'object' ? l.target.id : l.target;
return sId !== node.id && tId !== node.id;
});
showSidebar(node);
}
function clearHighlight() {
activeId = null;
nodeSel.classed('dimmed', false);
linkSel.classed('dimmed', false);
sidebar.innerHTML = '<div class="graph-sidebar-empty">Кликни на узел или связь чтобы увидеть детали…</div>';
}
function showEdgeSidebar(edge) {
const sId = typeof edge.source === 'object' ? edge.source.id : edge.source;
const tId = typeof edge.target === 'object' ? edge.target.id : edge.target;
const src = GRAPH_NODES.find(n => n.id === sId);
const tgt = GRAPH_NODES.find(n => n.id === tId);
const ruLabel = EDGE_TYPE_RU[edge.type] ?? edge.type;
const desc = EDGE_DESC[edge.type] ?? '';
const srcType = NODE_TYPE_RU[src?.type] ?? '';
const tgtType = NODE_TYPE_RU[tgt?.type] ?? '';
sidebar.innerHTML = `
<button class="graph-close" aria-label="Close">×</button>
<div class="graph-sidebar-title">${ruLabel}</div>
<div class="graph-sidebar-badge">Связь</div>
<div class="graph-sidebar-section">
<div class="graph-sidebar-section-label">Что это значит</div>
<div style="font-size:0.85rem; color: var(--ink-soft); line-height: 1.5;">${desc}</div>
</div>
<div class="graph-sidebar-section">
<div class="graph-sidebar-section-label">Источник — ${srcType}</div>
<div style="font-family: 'Fraunces', serif; font-weight: 500; font-size: 1rem;">${src?.label ?? sId}</div>
<div style="font-size:0.82rem; color: var(--ink-soft); line-height: 1.45; margin-top: 4px;">${src?.desc ?? ''}</div>
<button class="graph-sidebar-navlink" data-nav-to="${sId}">Перейти к узлу →</button>
</div>
<div class="graph-sidebar-section">
<div class="graph-sidebar-section-label">Цель — ${tgtType}</div>
<div style="font-family: 'Fraunces', serif; font-weight: 500; font-size: 1rem;">${tgt?.label ?? tId}</div>
<div style="font-size:0.82rem; color: var(--ink-soft); line-height: 1.45; margin-top: 4px;">${tgt?.desc ?? ''}</div>
<button class="graph-sidebar-navlink" data-nav-to="${tId}">Перейти к узлу →</button>
</div>
`;
sidebar.querySelector('.graph-close').addEventListener('click', clearHighlight);
sidebar.querySelectorAll('.graph-sidebar-navlink').forEach(btn => {
btn.addEventListener('click', () => {
const targetId = btn.dataset.navTo;
const targetNode = GRAPH_NODES.find(n => n.id === targetId);
if (targetNode) highlightNode(targetNode);
});
});
}
function highlightEdge(edge) {
const sId = typeof edge.source === 'object' ? edge.source.id : edge.source;
const tId = typeof edge.target === 'object' ? edge.target.id : edge.target;
activeId = `edge:${sId}->${tId}`;
nodeSel.classed('dimmed', d => d.id !== sId && d.id !== tId);
linkSel.classed('dimmed', l => l !== edge);
showEdgeSidebar(edge);
}
nodeSel.on('click', (event, d) => {
if (event.defaultPrevented) return; // was a drag, not a click
event.stopPropagation();
if (activeId === d.id) clearHighlight();
else highlightNode(d);
});
svg.on('click', clearHighlight);
// ============================================================
// INTERACTIVITY: hover edge → tooltip
// ============================================================
const tooltip = d3.select(document.body)
.append('div').attr('class', 'gl-tooltip').style('display', 'none');
linkSel.on('mouseover', function(event, l) {
const sId = typeof l.source === 'object' ? l.source.id : l.source;
const tId = typeof l.target === 'object' ? l.target.id : l.target;
const src = GRAPH_NODES.find(n => n.id === sId);
const tgt = GRAPH_NODES.find(n => n.id === tId);
tooltip.html(`<b>${EDGE_TYPE_RU[l.type] ?? l.type}</b>: ${src?.label ?? sId}${tgt?.label ?? tId}`)
.style('display', 'block')
.style('left', (event.pageX + 12) + 'px')
.style('top', (event.pageY - 8) + 'px');
d3.select(this).style('stroke-width', '4');
});
linkSel.on('mousemove', function(event) {
tooltip.style('left', (event.pageX + 12) + 'px').style('top', (event.pageY - 8) + 'px');
});
linkSel.on('mouseout', function() {
tooltip.style('display', 'none');
d3.select(this).style('stroke-width', null);
});
linkSel.on('click', function(event, l) {
event.stopPropagation();
tooltip.style('display', 'none');
highlightEdge(l);
});
// ============================================================
// INTERACTIVITY: drag
// ============================================================
function dragstart(event, d) {
if (!event.active) sim.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragmove(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragend(event, d) {
if (!event.active) sim.alphaTarget(0);
d.fx = null;
d.fy = null;
}
nodeSel.call(d3.drag()
.on('start', dragstart)
.on('drag', dragmove)
.on('end', dragend));
// ============================================================
// INTERACTIVITY: filter chips + reset
// ============================================================
const filters = document.querySelectorAll('.graph-filter');
const hiddenTypes = new Set();
function applyFilters() {
// If currently-selected node's type is being hidden — clear selection
if (activeId && !activeId.startsWith('edge:')) {
const activeNode = GRAPH_NODES.find(n => n.id === activeId);
if (activeNode && hiddenTypes.has(activeNode.type)) clearHighlight();
}
// If currently-selected edge has hidden source/target type — clear
if (activeId && activeId.startsWith('edge:')) {
const match = activeId.match(/^edge:(.+)->(.+)$/);
if (match) {
const sN = GRAPH_NODES.find(n => n.id === match[1]);
const tN = GRAPH_NODES.find(n => n.id === match[2]);
if ((sN && hiddenTypes.has(sN.type)) || (tN && hiddenTypes.has(tN.type))) clearHighlight();
}
}
nodeSel.style('display', d => hiddenTypes.has(d.type) ? 'none' : null);
linkSel.style('display', l => {
const sT = (typeof l.source === 'object' ? l.source.type : GRAPH_NODES.find(n=>n.id===l.source).type);
const tT = (typeof l.target === 'object' ? l.target.type : GRAPH_NODES.find(n=>n.id===l.target).type);
return (hiddenTypes.has(sT) || hiddenTypes.has(tT)) ? 'none' : null;
});
}
filters.forEach(btn => {
btn.addEventListener('click', () => {
const type = btn.dataset.type;
if (hiddenTypes.has(type)) {
hiddenTypes.delete(type);
btn.classList.add('active');
} else {
hiddenTypes.add(type);
btn.classList.remove('active');
}
applyFilters();
});
});
document.querySelector('.graph-reset').addEventListener('click', () => {
hiddenTypes.clear();
filters.forEach(b => b.classList.add('active'));
applyFilters();
clearHighlight();
GRAPH_NODES.forEach(n => { n.fx = null; n.fy = null; });
sim.alpha(0.7).restart();
});
// Tick — обновление позиций
sim.on('tick', () => {
linkSel
.attr('x1', d => d.source.x).attr('y1', d => d.source.y)
.attr('x2', d => d.target.x).attr('y2', d => d.target.y);
nodeSel.attr('transform', d => `translate(${d.x},${d.y})`);
});
});
</script>
</body>
</html>