references/example-setup/flow.html
<!doctype html>
<html lang="vi">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>dym-setup — luồng workflow overstack</title>
<meta name="description" content="Sơ đồ luồng chính xác 6 workflow-skill của bundle doyourmagic/setup: skill nào chạy khi nào, sinh ra gì, skill kế tiếp nhận gì.">
<meta name="theme-color" content="#eaf2fd">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%230a84ff'/%3E%3C/svg%3E">
<script>(function(){try{var t=localStorage.getItem("dym-setup-flow-theme");if(t==="dark"||t==="light")document.documentElement.setAttribute("data-theme",t)}catch(e){}})();</script>
<style>
:root{--nav-pad-y:18px;--blur-1:18px;--glass-1:rgba(255,255,255,.42);--glass-2:rgba(255,255,255,.30);--border:rgba(30,90,170,.14);--t1:#0f0f12;--t2:#4a4a55;--accent:#0a84ff;
--c0:#30b0c7;--c1:#5856d6;--c2:#ff9500;--c3:#34c759;--c4:#ff2d55}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;padding-left:200px;font:13.5px/1.6 -apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Roboto,sans-serif;color:var(--t1);
background:radial-gradient(900px 500px at 12% -10%,rgba(10,132,255,.10),transparent 60%),radial-gradient(700px 420px at 95% 15%,rgba(90,162,232,.08),transparent 55%),linear-gradient(180deg,#f7fbff 0%,#eaf2fd 100%);min-height:100vh}
body::before{content:'';position:fixed;inset:-10%;z-index:-1;pointer-events:none;
background:radial-gradient(640px 440px at 10% 14%,rgba(10,132,255,.22),transparent 65%),radial-gradient(380px 460px at 4% 52%,rgba(48,176,199,.18),transparent 65%),radial-gradient(540px 400px at 88% 10%,rgba(88,86,214,.13),transparent 60%),radial-gradient(720px 500px at 74% 76%,rgba(48,176,199,.13),transparent 65%),radial-gradient(480px 380px at 16% 86%,rgba(255,149,0,.12),transparent 60%);
animation:orbDrift 46s ease-in-out infinite alternate}
@keyframes orbDrift{100%{transform:translate(2.2%,1.6%) scale(1.045)}}
body::after{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;background-image:radial-gradient(rgba(30,90,170,.11) 1px,transparent 1.3px);background-size:22px 22px;mask-image:linear-gradient(180deg,rgba(0,0,0,.55),rgba(0,0,0,.22))}
/* ── sidebar kính ── */
nav{position:fixed;top:0;left:0;bottom:0;width:200px;z-index:100;display:flex;flex-direction:column;align-items:stretch;gap:2px;padding:var(--nav-pad-y) 12px;
background:linear-gradient(165deg,rgba(255,255,255,.46) 0%,rgba(255,255,255,.22) 48%,rgba(240,248,255,.34) 100%);
backdrop-filter:blur(var(--blur-1)) saturate(1.7) brightness(1.04);-webkit-backdrop-filter:blur(var(--blur-1)) saturate(1.7) brightness(1.04);
border-right:1px solid rgba(255,255,255,.55);box-shadow:inset 0 1px 0 rgba(255,255,255,.9),inset 1px 0 0 rgba(255,255,255,.5),inset -1px 0 0 rgba(30,90,170,.10),4px 0 24px rgba(30,90,170,.08);transition:transform .22s}
nav::before{content:'';position:absolute;inset:0;pointer-events:none;background:radial-gradient(220px 160px at 18% 4%,rgba(255,255,255,.55),transparent 70%),linear-gradient(115deg,rgba(255,255,255,.28) 0%,transparent 28%,transparent 72%,rgba(255,255,255,.14) 100%)}
nav>*{position:relative}
nav .logo{margin:0 0 12px;padding:6px 10px;font-weight:800;font-size:15px;letter-spacing:-.02em;background:linear-gradient(135deg,#0a84ff,#64b5f7);-webkit-background-clip:text;background-clip:text;color:transparent}
nav a{display:block;padding:5px 12px;border-radius:10px;font-size:12px;color:var(--t2);text-decoration:none;position:relative;overflow:hidden}
nav a.active,nav a:hover{color:var(--accent);background:rgba(10,132,255,.08)}nav a.active{font-weight:600}
nav .grp{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--t2);padding:10px 12px 3px;opacity:.75}
.nav-toggle{display:none;position:fixed;top:10px;left:10px;z-index:120;width:36px;height:36px;border-radius:10px;border:1px solid var(--border);background:var(--glass-1);backdrop-filter:blur(12px);cursor:pointer;overflow:hidden}
@media(max-width:640px){body{padding-left:0}nav{transform:translateX(-100%);box-shadow:0 8px 30px rgba(0,0,0,.14)}nav.open{transform:none}.nav-toggle{display:block}}
.theme-row{position:sticky;bottom:calc(-1 * var(--nav-pad-y));margin-top:auto;display:flex;align-items:center;justify-content:space-between;padding:11px 4px 0;border-top:1px solid var(--border);font-size:11px;color:var(--t2)}
.theme-switch{cursor:pointer;position:relative;overflow:hidden;border-radius:999px}
.theme-switch .track{display:inline-block;position:relative;width:50px;height:26px;border-radius:999px;background:rgba(10,132,255,.18);border:1px solid var(--border);transition:background .2s}
.theme-switch .track::before{content:'☀️';position:absolute;left:6px;top:4px;font-size:11px}.theme-switch .track::after{content:'🌙';position:absolute;right:6px;top:4px;font-size:11px}
.theme-switch .knob{position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.25);transition:left .18s;z-index:1}
.theme-switch.on .knob{left:26px}.theme-switch.on .track{background:rgba(88,86,214,.45)}
.ripple-ink{position:absolute;border-radius:50%;pointer-events:none;background:radial-gradient(circle at 35% 30%,rgba(255,255,255,.70) 0%,rgba(255,255,255,.28) 38%,rgba(10,132,255,.20) 72%,transparent 100%);box-shadow:inset 0 1px 0 rgba(255,255,255,.9),inset 0 -10px 20px rgba(10,132,255,.12),0 0 14px rgba(10,132,255,.10);backdrop-filter:blur(2px) saturate(1.25);transform:scale(0);opacity:1;animation:rippleGrow .6s cubic-bezier(.25,.46,.45,.94) forwards}
@keyframes rippleGrow{55%{transform:scale(1);opacity:.75}100%{transform:scale(1.04);opacity:0}}
/* ── content ── */
main{max-width:1040px;margin:0 auto;padding:36px 28px 80px}
.skip-link{position:fixed;top:8px;left:8px;z-index:200;padding:8px 14px;border-radius:10px;background:var(--glass-1);backdrop-filter:blur(var(--blur-1));border:1px solid var(--border);transform:translateY(-150%);transition:transform .2s;color:var(--t1)}
.skip-link:focus-visible{transform:translateY(0)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:8px}:focus:not(:focus-visible){outline:none}
section{scroll-margin-top:24px;margin-bottom:40px}
h1{font-size:clamp(26px,4vw,40px);line-height:1.1;letter-spacing:-.03em;margin:0 0 8px}
h2{font-size:21px;letter-spacing:-.02em;margin:0 0 12px}
h3{font-size:15px;margin:18px 0 6px}
p{margin:0 0 10px}.lead{font-size:14px;color:var(--t2)}
.card{background:var(--glass-1);backdrop-filter:blur(var(--blur-1)) saturate(1.4);-webkit-backdrop-filter:blur(var(--blur-1)) saturate(1.4);border:1px solid rgba(255,255,255,.6);box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 8px 28px rgba(30,90,170,.08);border-radius:16px;padding:16px 18px;margin:12px 0}
code{font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;background:rgba(10,132,255,.08);padding:.1em .35em;border-radius:5px}
pre{background:rgba(15,15,18,.06);border:1px solid var(--border);border-radius:10px;padding:12px 14px;overflow-x:auto;margin:8px 0 12px}pre code{background:none;padding:0}
table{width:100%;border-collapse:collapse;font-size:12.5px;margin:8px 0 12px}th,td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);vertical-align:top}th{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--t2)}
.tag{display:inline-block;font-size:10px;letter-spacing:.06em;text-transform:uppercase;padding:2px 8px;border-radius:999px;border:1px solid var(--border);color:var(--t2);background:rgba(255,255,255,.5)}
.term{border-bottom:1px dotted var(--t2);cursor:help}
/* ── sơ đồ luồng: node + connector JS ── */
.flow{position:relative;display:grid;grid-template-columns:1fr;gap:40px;padding:8px 40px 8px 0}
.flow-svg{position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:0}
.flow-svg path{fill:none;stroke-width:2;opacity:.7;stroke-linecap:round}
.flow-svg .lbl{font-size:10px;fill:var(--t2);paint-order:stroke;stroke:#f3f7fd;stroke-width:4px;stroke-linejoin:round}
.lane{position:relative;z-index:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:18px;align-items:start}
.lane-h{grid-column:1/-1;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--t2);margin:6px 0 -8px}
.node{position:relative;z-index:1;background:var(--glass-1);backdrop-filter:blur(14px);border:1px solid rgba(255,255,255,.65);border-left:4px solid var(--c0);border-radius:14px;padding:11px 13px;box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 6px 20px rgba(30,90,170,.08)}
.node.c1{border-left-color:var(--c1)}.node.c2{border-left-color:var(--c2)}.node.c3{border-left-color:var(--c3)}.node.c4{border-left-color:var(--c4)}
.node .cmd{font:12px ui-monospace,Menlo,monospace;font-weight:700;color:var(--accent)}
.node .pur{font-size:12.5px;margin:3px 0 6px}
.node .out{font-size:11px;color:var(--t2)}.node .out b{color:var(--t1)}
.node .trap{font-size:11px;margin-top:6px;padding-top:6px;border-top:1px dashed var(--border);color:#8a2f22}
/* ── mind map ── */
.mm{overflow-x:auto;padding:14px 4px 6px}.mm-canvas{position:relative;width:max-content}
.mm-links{position:absolute;top:0;left:0;pointer-events:none;overflow:visible;z-index:0}.mm-links path{fill:none;stroke-width:2.2;opacity:.55;stroke-linecap:round}
.mm .tree{position:relative;z-index:1}.mm .tree,.mm .children{display:flex;flex-direction:column;gap:9px;justify-content:center}
.mm .row{display:flex;align-items:center;gap:48px;position:relative}.mm .children{position:relative}.mm .children.collapsed{display:none}
.mm .mnode{position:relative;display:inline-flex;flex-direction:column;gap:1px;padding:7px 13px;border-radius:13px;cursor:default;white-space:nowrap;background:rgba(255,255,255,.55);border:1px solid var(--border);box-shadow:0 2px 10px rgba(30,90,170,.06)}
.mm .mnode.has-children{cursor:pointer}.mm .mnode:hover{transform:translateY(-1px)}
.mm .mnode .nm{font-size:13px;font-weight:700;letter-spacing:-.01em}.mm .mnode .ds{font-size:10.5px;color:var(--t2)}
.mm .mnode .ct{font-size:10px;color:#fff;font-weight:700;padding:1px 7px;border-radius:999px;position:absolute;top:-8px;right:-8px;background:var(--accent)}
.mm .mnode.has-children::after{content:'';position:absolute;right:-7px;top:50%;width:6px;height:6px;border-right:2px solid var(--t2);border-bottom:2px solid var(--t2);transform:translateY(-50%) rotate(-45deg)}
.mm .mnode.collapsed-parent::after{transform:translateY(-50%) rotate(45deg)}
.mm .mnode.root{background:linear-gradient(135deg,rgba(10,132,255,.16),rgba(88,86,214,.14));border-color:rgba(10,132,255,.4)}
.mm .b-0 .nm{color:var(--c0)}.mm .b-1 .nm{color:var(--c1)}.mm .b-2 .nm{color:var(--c2)}
footer{margin-top:40px;padding-top:16px;border-top:1px solid var(--border);font-size:11px;color:var(--t2);word-break:break-all}
/* ── dark: một danh sách token, hai prefix ── */
@media (prefers-color-scheme: dark){
html:not([data-theme=light]){--glass-1:rgba(22,26,36,.55);--glass-2:rgba(22,26,36,.4);--border:rgba(120,160,220,.18);--t1:#eceef4;--t2:#a7adbb;background:#0c0f16}
html:not([data-theme=light]) body{background:radial-gradient(900px 500px at 12% -10%,rgba(10,132,255,.14),transparent 60%),linear-gradient(180deg,#0c0f16 0%,#121724 100%)}
html:not([data-theme=light]) nav{background:linear-gradient(165deg,rgba(30,36,50,.6),rgba(20,24,34,.45));border-right-color:rgba(255,255,255,.08)}
html:not([data-theme=light]) .node,html:not([data-theme=light]) .mm .mnode{background:rgba(28,33,46,.7);border-color:rgba(255,255,255,.1)}
html:not([data-theme=light]) pre{background:rgba(255,255,255,.05)}
html:not([data-theme=light]) .node .trap{color:#f0a094}
html:not([data-theme=light]) .flow-svg .lbl{stroke:#141a26}
}
html[data-theme=dark]{--glass-1:rgba(22,26,36,.55);--glass-2:rgba(22,26,36,.4);--border:rgba(120,160,220,.18);--t1:#eceef4;--t2:#a7adbb;background:#0c0f16}
html[data-theme=dark] body{background:radial-gradient(900px 500px at 12% -10%,rgba(10,132,255,.14),transparent 60%),linear-gradient(180deg,#0c0f16 0%,#121724 100%)}
html[data-theme=dark] nav{background:linear-gradient(165deg,rgba(30,36,50,.6),rgba(20,24,34,.45));border-right-color:rgba(255,255,255,.08)}
html[data-theme=dark] .node,html[data-theme=dark] .mm .mnode{background:rgba(28,33,46,.7);border-color:rgba(255,255,255,.1)}
html[data-theme=dark] pre{background:rgba(255,255,255,.05)}
html[data-theme=dark] .node .trap{color:#f0a094}
html[data-theme=dark] .flow-svg .lbl{stroke:#141a26}
</style>
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<button class="nav-toggle" aria-label="Mở menu" type="button">☰</button>
<nav>
<div class="logo">dym-setup</div>
<a href="#tong-quan" class="active">Tổng quan</a>
<a href="#mind-map">Mind map</a>
<a href="#luong">Sơ đồ luồng</a>
<div class="grp">Tiêu thụ</div>
<a href="#install">install</a>
<a href="#guardrail-cli">guardrail-cli</a>
<a href="#agent-workflow">agent-workflow</a>
<a href="#ci">ci</a>
<a href="#maintain">maintain</a>
<div class="grp">Đóng góp</div>
<a href="#contributor">contributor</a>
<div class="grp">Khác</div>
<a href="#thuat-ngu">Thuật ngữ</a>
</nav>
<main id="main">
<section id="tong-quan">
<h1>Luồng 6 workflow-skill của overstack</h1>
<p class="lead">Bundle sinh bởi <code>/doyourmagic github.com/rheinmir/setup</code>. Một <span class="term" title="skill trung tâm, chỉ tốn một dòng context; đọc workflow con khi được gọi">hub</span> <code>/dym-setup</code> và 6 <span class="term" title="mỗi workflow là một SKILL.md đầy đủ, copy sang repo chính là thành skill cài bằng npx">sub-skill</span>. Trang này ghi <b>chính xác</b> skill nào chạy khi nào, sinh ra gì, và skill kế nhận gì — không phải mô tả tính năng.</p>
<div class="card">
<b>Cài dùng tại chỗ (chỉ hub vào context):</b>
<pre><code>mkdir -p .claude/skills && ln -sfn ../../doyourmagic/setup/skills/dym-setup .claude/skills/dym-setup</code></pre>
Gõ <code>/dym-setup</code> để xem bảng slug, <code>/dym-setup install</code> để chạy một workflow. Chế độ đặt tên: mặc định <code>dym-<repo>-<slug></code>.
</div>
<table>
<tr><th>skill</th><th>gọi</th><th>nhánh</th><th>sinh ra</th></tr>
<tr><td><code>dym-setup-install</code></td><td><code>/dym-setup install</code></td><td>tiêu thụ</td><td><code>.harness/</code> <code>.llmwiki/</code> hook + CI + pre-commit + engine global</td></tr>
<tr><td><code>dym-setup-guardrail-cli</code></td><td><code>/dym-setup guardrail-cli</code></td><td>tiêu thụ · shell</td><td>không file — vi phạm ra stderr, kết luận ở mã thoát</td></tr>
<tr><td><code>dym-setup-agent-workflow</code></td><td><code>/dym-setup agent-workflow</code></td><td>tiêu thụ · chat</td><td>SPEC/PLAN dưới <code>.llmwiki/wiki/sources/draft/</code>, commit sạch</td></tr>
<tr><td><code>dym-setup-ci</code></td><td><code>/dym-setup ci</code></td><td>tiêu thụ · CI</td><td><code>.github/workflows/wiki-rules.yml</code></td></tr>
<tr><td><code>dym-setup-maintain</code></td><td><code>/dym-setup maintain</code></td><td>tiêu thụ</td><td>engine global mới, <code>CAPABILITIES.md</code> regen, wiki backfill</td></tr>
<tr><td><code>dym-setup-contributor</code></td><td><code>/dym-setup contributor</code></td><td>đóng góp</td><td>bảng ✓/✗ 21 step, <code>RELEASE-vX.Y.Z.md</code>, nhánh canary</td></tr>
</table>
</section>
<section id="mind-map">
<h2>Mind map</h2>
<div class="card"><div class="mm"><div class="mm-canvas"><svg class="mm-links"></svg><div class="tree"><div class="row">
<div class="mnode root has-children"><span class="nm">dym-setup</span><span class="ds">hub · 1 dòng context</span><span class="ct">6</span></div>
<div class="children">
<div class="row">
<div class="mnode b-0 cat has-children"><span class="nm">Tiêu thụ</span><span class="ds">dùng overstack trong dự án mình</span><span class="ct">5</span></div>
<div class="children">
<div class="row"><div class="mnode b-0 leaf"><span class="nm">install</span><span class="ds">bootstrap · cờ · $HOME · gỡ</span></div></div>
<div class="row"><div class="mnode b-0 leaf"><span class="nm">guardrail-cli</span><span class="ds">3 mode · 19 luật · rc 0/1/2</span></div></div>
<div class="row"><div class="mnode b-0 leaf"><span class="nm">agent-workflow</span><span class="ds">/propose → /plan → /ship</span></div></div>
<div class="row"><div class="mnode b-0 leaf"><span class="nm">ci</span><span class="ds">Actions tối giản · 3 bẫy xanh giả</span></div></div>
<div class="row"><div class="mnode b-0 leaf"><span class="nm">maintain</span><span class="ds">update · migrate · rc 0/3/4/1</span></div></div>
</div>
</div>
<div class="row">
<div class="mnode b-1 cat has-children"><span class="nm">Đóng góp</span><span class="ds">sửa chính overstack</span><span class="ct">1</span></div>
<div class="children">
<div class="row"><div class="mnode b-1 leaf"><span class="nm">contributor</span><span class="ds">fdk-gate 21 · medic 18 · UAT · ship</span></div></div>
</div>
</div>
<div class="row">
<div class="mnode b-2 cat has-children"><span class="nm">Sản phẩm phụ</span><span class="ds">không phải skill</span><span class="ct">2</span></div>
<div class="children">
<div class="row"><div class="mnode b-2 leaf"><span class="nm">workflows.md</span><span class="ds">chỉ mục + bảng kiểm chứng</span></div></div>
<div class="row"><div class="mnode b-2 leaf"><span class="nm">flow.html</span><span class="ds">trang này</span></div></div>
</div>
</div>
</div>
</div></div></div></div></div>
</section>
<section id="luong">
<h2>Sơ đồ luồng — skill → sản phẩm → skill kế</h2>
<p class="lead">Mỗi cạnh ghi <b>cái gì</b> đi từ skill này sang skill kia. Đường nối do JS đo vị trí thật rồi vẽ, đổi cỡ cửa sổ thì vẽ lại.</p>
<div class="card">
<div class="flow" id="flow">
<svg class="flow-svg"></svg>
<div class="lane">
<div class="lane-h">Bước 1 — bắt buộc</div>
<div class="node" data-id="install"><div class="cmd">/dym-setup install</div><div class="pur">Cài 3 trụ bằng một dòng curl; xác nhận rào cắn thật.</div><div class="out"><b>ra:</b> <code>.harness/</code> <code>.llmwiki/</code> hook project + global, CI, pre-commit</div><div class="trap">Bẫy đo được: <code>--harness-only</code> không phải cờ của <code>install.sh</code> (rc=1); lệnh ghi cả vào <code>$HOME</code>.</div></div>
</div>
<div class="lane">
<div class="lane-h">Bước 2 — tự tay xác nhận luật cắn</div>
<div class="node c1" data-id="guardrail"><div class="cmd">/dym-setup guardrail-cli</div><div class="pur">Gọi validator từ shell trên input bẩn/sạch.</div><div class="out"><b>ra:</b> rc <b>2</b> (mode <code>path</code>/<code>claude-hook</code>) hoặc <b>1</b> (mode <code>files</code>) khi vi phạm; <b>0</b> khi sạch <i>hoặc</i> fail-open</div><div class="trap">Bẫy: file không tồn tại → rc 0; thiếu <code>pyyaml</code> → mọi luật tắt mà xanh.</div></div>
</div>
<div class="lane">
<div class="lane-h">Bước 3 — hai đường song song, độc lập nhau</div>
<div class="node c2" data-id="agent"><div class="cmd">/dym-setup agent-workflow</div><div class="pur">Vòng chat: propose → plan → verify-before-commit → ship.</div><div class="out"><b>ra:</b> SPEC/PLAN trong wiki, commit sạch; R7/R18 gác hai văn bản</div><div class="trap">Lệnh <code>/x</code> chỉ gõ trong chat — dán vào terminal là <code>command not found</code>.</div></div>
<div class="node c3" data-id="ci"><div class="cmd">/dym-setup ci</div><div class="pur">Workflow Actions viết mới cho dự án tiêu thụ.</div><div class="out"><b>ra:</b> <code>.github/workflows/wiki-rules.yml</code> — chặn PR khi <code>.md</code> wiki vi phạm luật tầng repo</div><div class="trap">Không bê <code>harness.yml</code> của installer (đó là CI của chính framework).</div></div>
</div>
<div class="lane">
<div class="lane-h">Bước 4 — khi cần nâng bản</div>
<div class="node c4" data-id="maintain"><div class="cmd">/dym-setup maintain</div><div class="pur">Chạy lại installer (idempotent) hoặc <code>/harness-update --self-heal</code>.</div><div class="out"><b>ra:</b> engine global mới khi <code>template_version</code> đổi (đo: 1.3.68→1.3.69), <code>CAPABILITIES.md</code> regen; rc <b>0</b>/<b>3</b>/<b>4</b>/<b>1</b></div><div class="trap">Installer chỉ cài lại global khi version đổi — sửa hook global mà không bump là user cũ không nhận.</div></div>
</div>
<div class="lane">
<div class="lane-h">Nhánh riêng — không phụ thuộc 1–4</div>
<div class="node c1" data-id="contrib"><div class="cmd">/dym-setup contributor</div><div class="pur">Clone <code>rheinmir/setup</code>, sửa, qua cổng.</div><div class="out"><b>ra:</b> <code>fdk-gate.py</code> 21 step (exit 0 / 2), <code>medic</code> 18 probe, PR vào <code>orca</code></div><div class="trap">R15 chặn commit ghi công AI; layout repo framework không dấu chấm nên không dính bẫy của <code>install</code>.</div></div>
</div>
</div>
</div>
</section>
<section id="install"><h2>dym-setup-install</h2><div class="card"><span class="tag">tiêu thụ · setup</span><p>Một dòng <code>curl … | bash</code> cài cả ba trụ. Sub-skill nói rõ cờ nào tồn tại ở <code>bootstrap.sh</code> mà không tồn tại ở <code>install.sh</code>, lệnh ghi những gì vào <code>$HOME</code>, cách thử an toàn bằng <code>HOME</code> cô lập, và bản vá tay cho bản cài trước PR #114.</p><p><b>Nghiệm thu 30 giây:</b></p><pre><code>echo '{"tool_name":"Write","tool_input":{"file_path":"llmwiki/raw/x.md","content":"x"}}' \
| python3 .harness/poc-vendor-neutral/bin/llmwiki-validate.py claude-hook; echo "rc=$?" # kỳ vọng 2</code></pre></div></section>
<section id="guardrail-cli"><h2>dym-setup-guardrail-cli</h2><div class="card"><span class="tag">tiêu thụ · shell</span><p>Một binary, ba mode; bảng 19 luật đọc từ <code>policy.yaml</code>; bốn đường <span class="term" title="lỗi hạ tầng thì cho qua (exit 0) thay vì chặn — đúng triết lý harness, nhưng dễ tạo CI xanh giả">fail-open</span>. Kèm ba luật từng chết dưới layout <code>.llmwiki/</code> (R14/R16/R19, đã vá #114) và lỗ <code>check_deny_write_bash</code> (đã vá).</p></div></section>
<section id="agent-workflow"><h2>dym-setup-agent-workflow</h2><div class="card"><span class="tag">tiêu thụ · chat</span><p>SPEC (người đọc để duyệt) tách khỏi PLAN (bơm vào agent context=0); tỷ lệ độ dài ≈ 1:8. Sự cố thì đi <code>/orca-issue</code>, không <code>/propose</code>. Không có mã thoát để đo — phần kiểm chứng là tên skill và luật gác (R7/R18).</p></div></section>
<section id="ci"><h2>dym-setup-ci</h2><div class="card"><span class="tag">tiêu thụ · CI</span><p>Workflow tối giản tự đủ, xử sẵn ba chỗ xanh giả: thiếu <code>pyyaml</code>, file đã xoá còn trong danh sách (<code>--diff-filter=d</code>), rẽ nhánh nhầm mã thoát (mode <code>files</code> thoát 1).</p></div></section>
<section id="maintain"><h2>dym-setup-maintain</h2><div class="card"><span class="tag">tiêu thụ · bảo trì</span><p>Update = chạy lại installer. Dự án cũ đi <code>/harness-update</code> với <code>--self-heal</code>: rc 0 sạch · 3 còn nợ tự sửa không được · 4 smoke thất bại · 1 hạ tầng. Danh sách 16 tool cố tình không có ở global (<code>harness-doctor</code>, <code>fdk-gate</code>…).</p></div></section>
<section id="contributor"><h2>dym-setup-contributor</h2><div class="card"><span class="tag">đóng góp</span><p>Entry point thật là <code>policy.yaml</code> + <code>gen-converters.py</code>. Cổng <code>fdk-gate.py</code> 21 step; từng đỏ 5/21 trên <code>orca</code> pristine (sửa ở #116, nay 21/21). Cách chụp baseline trước/sau vẫn là thói quen đúng.</p></div></section>
<section id="thuat-ngu">
<h2>Thuật ngữ</h2>
<div class="card"><table>
<tr><td><b>hub</b></td><td>skill trung tâm <code>/dym-setup</code>: chỉ tốn một dòng description trong context; đọc đúng một workflow con khi được gọi với slug.</td></tr>
<tr><td><b>sub-skill</b></td><td>thư mục <code>skills/dym-setup-<slug>/SKILL.md</code> — một workflow ở dạng skill đầy đủ, tự chứa, copy sang repo chính là promote được.</td></tr>
<tr><td><b>slug</b></td><td>tên ngắn nói việc (<code>install</code>, <code>ci</code>…), không đánh số.</td></tr>
<tr><td><b>fail-open</b></td><td>gặp lỗi hạ tầng (thiếu policy, file không tồn tại, mode lạ) thì cho qua (rc 0) thay vì chặn.</td></tr>
<tr><td><b>layout dot</b></td><td>dự án downstream đặt <code>.llmwiki/</code> + <code>.harness/</code> (ẩn) thay vì <code>llmwiki/</code> + <code>harness/</code> — lỗi dây nối theo layout này đã vá ở PR #114–#117.</td></tr>
<tr><td><b>promote</b></td><td>đưa một sub-skill lên repo chính (<code>rheinmir/setup</code> <code>skills/</code>) qua <code>fdk-kit.sh</code> để cài bằng <code>npx skills add</code>.</td></tr>
</table></div>
</section>
<footer>File này: <code id="selfpath">doyourmagic/setup/flow.html</code> · Sinh bởi skill <code>/doyourmagic</code> · chỉ mục + bảng kiểm chứng: <a href="workflows.md">workflows.md</a></footer>
</main>
<script>
/* nav toggle + active + ripple */
(function(){var nav=document.querySelector('nav'),tg=document.querySelector('.nav-toggle');tg.addEventListener('click',function(){nav.classList.toggle('open')});
nav.querySelectorAll('a').forEach(function(a){a.addEventListener('click',function(){nav.querySelectorAll('a').forEach(function(x){x.classList.remove('active')});a.classList.add('active');if(innerWidth<=640)nav.classList.remove('open')})});
function attach(el){el.addEventListener('pointerdown',function(e){var r=el.getBoundingClientRect(),x=e.clientX-r.left,y=e.clientY-r.top,rad=Math.hypot(Math.max(x,r.width-x),Math.max(y,r.height-y)),ink=document.createElement('span');ink.className='ripple-ink';ink.style.width=ink.style.height=rad*2+'px';ink.style.left=(x-rad)+'px';ink.style.top=(y-rad)+'px';el.appendChild(ink);ink.addEventListener('animationend',function(){ink.remove()})})}
document.querySelectorAll('nav a,.nav-toggle').forEach(attach);window.__attachRipple=attach;
try{var p=decodeURIComponent(location.pathname);if(location.protocol==='file:'&&p)document.getElementById('selfpath').textContent=p}catch(e){}})();
/* theme switch — nút gạt ở footer sidebar, chống FOUC ở head */
(function(){var K='dym-setup-flow-theme',d=document.documentElement,nav=document.querySelector('nav');if(!nav)return;
function isDark(){var t=d.getAttribute('data-theme');return t?t==='dark':matchMedia('(prefers-color-scheme: dark)').matches}
var sw=document.createElement('div');sw.className='theme-switch';sw.setAttribute('role','switch');sw.setAttribute('tabindex','0');sw.innerHTML='<span class="track"><span class="knob"></span></span>';
var row=document.createElement('div');row.className='theme-row';var lb=document.createElement('span');lb.className='lbl';lb.textContent='Giao diện';row.appendChild(lb);row.appendChild(sw);nav.appendChild(row);
function paint(){var dk=isDark();sw.classList.toggle('on',dk);sw.setAttribute('aria-checked',dk?'true':'false');sw.setAttribute('aria-label',dk?'Nút gạt giao diện: đang tối — gạt sang sáng':'Nút gạt giao diện: đang sáng — gạt sang tối')}
function flip(){var n=isDark()?'light':'dark';d.setAttribute('data-theme',n);try{localStorage.setItem(K,n)}catch(e){}paint();setTimeout(function(){window.__drawFlow&&window.__drawFlow();window.__drawMM&&window.__drawMM()},30)}
sw.addEventListener('click',flip);sw.addEventListener('keydown',function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();flip()}});window.__attachRipple(sw);paint()})();
/* sơ đồ luồng: cạnh skill→skill, đo getBoundingClientRect, vẽ lại khi resize */
(function(){var EDGES=[['install','guardrail','.harness/ + hook đã cài'],['guardrail','agent','rc=2 xác nhận rào cắn'],['guardrail','ci','cùng validator, mode files (rc 1)'],['agent','maintain','wiki + commit tích luỹ'],['ci','maintain','CI đỏ khi bản cũ'],['maintain','install','installer chạy lại (idempotent)']];
var COL={install:'#30b0c7',guardrail:'#5856d6',agent:'#ff9500',ci:'#34c759',maintain:'#ff2d55'};var NS='http://www.w3.org/2000/svg';
function draw(){var f=document.getElementById('flow'),svg=f.querySelector('.flow-svg');if(!f||!svg)return;var fr=f.getBoundingClientRect();svg.setAttribute('width',fr.width);svg.setAttribute('height',fr.height);svg.setAttribute('viewBox','0 0 '+fr.width+' '+fr.height);while(svg.firstChild)svg.removeChild(svg.firstChild);
EDGES.forEach(function(e){var a=f.querySelector('[data-id="'+e[0]+'"]'),b=f.querySelector('[data-id="'+e[1]+'"]');if(!a||!b)return;var ra=a.getBoundingClientRect(),rb=b.getBoundingClientRect();var back=rb.top<ra.top;
var x1=ra.left-fr.left+ra.width/2,y1=(back?ra.top:ra.bottom)-fr.top,x2=rb.left-fr.left+rb.width/2,y2=(back?rb.bottom:rb.top)-fr.top;
if(back){x1=ra.right-fr.left;y1=ra.top-fr.top+ra.height/2;x2=rb.right-fr.left;y2=rb.top-fr.top+rb.height/2}
var p=document.createElementNS(NS,'path');var c=Math.abs(y2-y1)/2;var rx=fr.width-8;var dd=back?('M'+x1+','+y1+' C'+rx+','+y1+' '+rx+','+y2+' '+x2+','+y2):('M'+x1+','+y1+' C'+x1+','+(y1+c)+' '+x2+','+(y2-c)+' '+x2+','+y2);
p.setAttribute('d',dd);p.setAttribute('stroke',COL[e[0]]||'#0a84ff');if(back)p.setAttribute('stroke-dasharray','5 5');svg.appendChild(p);
var t=document.createElementNS(NS,'text');t.setAttribute('class','lbl');t.setAttribute('x',back?(rx-4):((x1+x2)/2+8));t.setAttribute('y',back?((y1+y2)/2):((y1+y2)/2+4));if(back)t.setAttribute('text-anchor','end');t.textContent=e[2];svg.appendChild(t)})}
window.__drawFlow=draw;draw();addEventListener('load',function(){setTimeout(draw,60)});addEventListener('resize',function(){clearTimeout(window.__ft);window.__ft=setTimeout(draw,120)},{passive:true})})();
/* mind map: bezier theo nhánh, nhánh .cat đóng mặc định, click toggle */
(function(){var mm=document.querySelector('.mm');if(!mm)return;var NS='http://www.w3.org/2000/svg';
function colorOf(n){return n.classList.contains('b-0')?'#30b0c7':n.classList.contains('b-1')?'#5856d6':n.classList.contains('b-2')?'#ff9500':'#0a84ff'}
function draw(){var canvas=mm.querySelector('.mm-canvas'),svg=mm.querySelector('.mm-links');if(!canvas||!svg)return;var cr=canvas.getBoundingClientRect();svg.setAttribute('width',canvas.offsetWidth);svg.setAttribute('height',canvas.offsetHeight);while(svg.firstChild)svg.removeChild(svg.firstChild);
mm.querySelectorAll('.mnode.has-children').forEach(function(n){var row=n.parentElement,kids=null;for(var i=0;i<row.children.length;i++){if(row.children[i].classList.contains('children'))kids=row.children[i]}if(!kids||kids.classList.contains('collapsed'))return;var a=n.getBoundingClientRect();
kids.querySelectorAll(':scope > .row > .mnode').forEach(function(k){var b=k.getBoundingClientRect();var x1=a.right-cr.left,y1=a.top-cr.top+a.height/2,x2=b.left-cr.left,y2=b.top-cr.top+b.height/2,mx=(x1+x2)/2;var p=document.createElementNS(NS,'path');p.setAttribute('d','M'+x1+','+y1+' C'+mx+','+y1+' '+mx+','+y2+' '+x2+','+y2);p.setAttribute('stroke',colorOf(k));svg.appendChild(p)})})}
mm.querySelectorAll('.mnode.cat.has-children').forEach(function(n){var row=n.parentElement;for(var i=0;i<row.children.length;i++){if(row.children[i].classList.contains('children')){row.children[i].classList.add('collapsed');n.classList.add('collapsed-parent')}}});
mm.querySelectorAll('.mnode.has-children').forEach(function(n){n.addEventListener('click',function(){var row=n.parentElement;for(var i=0;i<row.children.length;i++){if(row.children[i].classList.contains('children')){row.children[i].classList.toggle('collapsed');n.classList.toggle('collapsed-parent')}}draw()})});
window.__drawMM=draw;draw();addEventListener('load',function(){setTimeout(draw,60)});addEventListener('resize',function(){clearTimeout(window.__mmt);window.__mmt=setTimeout(draw,120)},{passive:true})})();
</script>
</body>
</html>
references/example-setup/README.md
# example-setup — một lượt chạy thật của /doyourmagic trên rheinmir/setup (overstack)
Bundle gốc nằm ở dự án tiêu thụ: `doyourmagic/setup/` với `skills/<tên>/SKILL.md`. Trong reference này các file skill được lưu dạng `skills/<tên>.skill.md` để loader (`skills/*/SKILL.md`, `npx skills`) không quét nhầm chúng thành skill của repo.
Đọc theo thứ tự: `workflows.md` (chỉ mục + bảng "kiểm chứng thế nào" 30+ dòng) → `flow.html` (docs-site-macos: sidebar, mind map, sơ đồ luồng skill→sản phẩm→skill kế, nút gạt sáng/tối) → `skills/dym-setup.skill.md` (hub, 1 dòng context) → 6 sub-skill.
Cách sinh: 2 lần cài thật vào sandbox `HOME` cô lập + đối chiếu 1 bản cài thật trên máy → 5 lỗi thật tìm ra (vá ở PR #114–#117). Test phiên mới: `/dym-setup` không đọc file nào; `/dym-setup guardrail-cli` đọc đúng 1 file con và 4/4 lệnh cho rc như tài liệu ghi. `flow.html` mở thật bằng Playwright: 6 cạnh luồng, mind map, toggle lưu localStorage, mobile nav, 0 lỗi console.
references/example-setup/skills/dym-setup-agent-workflow.skill.md
---
name: dym-setup-agent-workflow
description: "Vòng làm việc hằng ngày bằng lệnh CHAT /propose → /plan → /verify-before-commit → /ship và bảng skill theo việc (KHÔNG phải lệnh shell). Gọi khi: 'workflow overstack', 'dùng skill nào', 'propose rồi làm gì'."
disable-model-invocation: true
---
# Skill: dym-setup-agent-workflow — Vòng làm việc hằng ngày: các lệnh `/<skill>` (CHAT, không phải terminal)
## When to use
- **Tại sao chạy:** đây là phần overstack thật sự thay đổi cách bạn làm việc — agent buộc phải thiết kế trước khi code, và luật ở [02](02-guardrail-cli-and-rules.md) chỉ là lưới an toàn phía dưới.
- **Sinh ra gì:** file wiki dưới `.llmwiki/wiki/` (SPEC draft, PLAN, concept, ADR), cộng commit sạch.
- Gọi qua hub: `/dym-setup agent-workflow` — hoặc trực tiếp `/dym-setup-agent-workflow` nếu đã symlink riêng.
## Steps
### 1. Vòng chuẩn: propose → gate → dispatch → verify
```
/propose thêm endpoint xuất báo cáo tồn kho theo kho
↓ sinh SPEC ở .llmwiki/wiki/sources/draft/DDMMYY-<tên>.md — DỪNG chờ bạn duyệt
↓ (bạn đọc, sửa, gật)
/plan DDMMYY-<tên>.md
↓ sinh DDMMYY-<tên>-PLAN.md: đường dẫn file chính xác, Interfaces, code từng bước
↓
(agent code, hoặc dispatch cho CLI rẻ chạy headless)
↓
/verify-before-commit
↓ typecheck → lint → test → task_lifecycle → commit → promote draft sang wiki
↓
/ship push (hoặc /ship pr · /ship mr · /ship release)
```
**Hai văn bản, hai người đọc — đừng gộp.** `/propose` sinh **SPEC**: thứ *người* đọc để bấm duyệt ở cổng. `/plan` sinh **PLAN**: thứ bơm thẳng vào một agent context=0 không hỏi lại được. Tỷ lệ độ dài spec:plan ≈ 1:8. Nhồi code-level vào SPEC thì người duyệt không đọc nổi thứ mình đang duyệt và cổng duyệt mất tác dụng.
Cả hai văn bản đều bị luật gác: SPEC thiếu `## Agent Task Assignment` / Sequence diagram / `## Global constraints` → R7 chặn; PLAN thiếu Files / Interfaces / code từng bước → R18 chặn.
**Rẽ nhánh quan trọng:** đầu vào là **sự cố** (bug, regression, "hôm qua còn chạy") thì gọi `/orca-issue` chứ không `/propose` — nó có cổng repro-first: chưa tái hiện được thì chưa được sửa.
### 2. Bảng lệnh theo việc
### Vòng tri thức (wiki)
| Lệnh | Dùng khi |
|---|---|
| `/ingest` | vừa thả tài liệu thô vào `raw/` → distill thành trang wiki |
| `/query <câu hỏi>` | hỏi wiki; trả lời kèm mục Evidence trích edge-id trong graph |
| `/lint` | kiểm tra sức khoẻ wiki: orphan, wikilink gãy, mâu thuẫn, drift code→wiki |
| `/record-episode` | ghi lại một session có cấu trúc cho phiên sau truy hồi |
### Vòng phát triển
| Lệnh | Dùng khi |
|---|---|
| `/propose` | tính năng mới, hoặc chạm code dùng chung |
| `/plan` | SPEC đã duyệt, sắp dispatch |
| `/impact-check` | trước khi sửa một symbol dùng chung — map hết caller |
| `/safe-change` | sửa code dùng chung mà không vỡ caller |
| `/qc-code` | review kiểu senior: security · performance · naming · logic + sinh test tái hiện |
| `/verify-before-commit` | cổng trước mọi `git commit` |
| `/ship` | push / release / PR / MR / merge |
| `/teach-me <thứ>` | hiểu một file/hàm/cơ chế, có chứng bằng chạy thật |
### Onboard & bảo trì
| Lệnh | Dùng khi |
|---|---|
| `/new-project-setup` | dự án **đã có code**, muốn gắn overstack + populate wiki từ code |
| `/onboard-codebase`, `/orca-onboard` | phân tích codebase sâu, dựng wiki + HTML |
| `/harness-update` | dự án đã có overstack bản cũ → nâng bản (xem [05](../dym-setup-maintain/SKILL.md)) |
| `/harness-tour` | xem tận mắt hook chặn mình theo thời gian thực (`short` = R1·R2·R3, `full` = R1–R10) |
| `/health-check` | xác nhận rào còn cắn sau khi update |
Danh mục đầy đủ 87 skill nằm ở `CAPABILITIES.md` trong dự án bạn (sinh bằng code, đếm từ đĩa). Tìm nhanh theo việc cần làm:
```bash
python3 ~/.claude/harness/fdk/tools/build-skill-search.py # lệnh SHELL, sinh index
```
### 3. Chọn đúng lối vào cho dự án mới
| Tình huống | Lối vào |
|---|---|
| Dự án **từ con số 0**, chưa có code | dán nguyên nội dung `00-New-Project.md` của repo vào agent — nó chạy 4 pha: cài → kickoff 3 câu → knowledge base → scaffold MVP |
| Dự án **đã có codebase** | `/new-project-setup` |
| Đã có overstack bản cũ | `/harness-update` |
⚠️ `00-New-Project.md` (PHA 0) bảo agent "ĐỌC `llmwiki/AGENT.md` + `llmwiki/CLAUDE.md`". Với bản installer hiện tại, hai file đó **không được seed xuống dự án** — `--with-wiki` chỉ tạo `.llmwiki/{wiki/…, raw, html, .harness-stamp}`. Agent sẽ báo không tìm thấy. Thay bằng: đọc `CAPABILITIES.md` ở gốc dự án và `.llmwiki/html/overstack.html`. Prompt cũng viết đường dẫn `llmwiki/…` không dấu chấm ở PHA 2 — dịch sang `.llmwiki/…` khi làm theo.
### 4. Vì sao không đo được như `02`
Không có lệnh nào trong file này có mã thoát để đối chiếu — chúng chạy bên trong phiên agent. Phần được kiểm chứng ở đây là: **tên skill và mô tả** (đọc từ `skills/<tên>/SKILL.md` trong repo), **luồng propose→plan** (đọc `skills/propose/SKILL.md` và `skills/plan/SKILL.md`), và **các luật gác hai văn bản đó** (R7/R18 trong `policy.yaml`). Hành vi thực tế của từng skill khi chạy thì chưa đo.
## Rules
- Làm đúng thứ tự Steps; lệnh nào ghi rc đo được thì đối chiếu rc, không đoán.
references/example-setup/skills/dym-setup-ci.skill.md
---
name: dym-setup-ci
description: "Cắm luật overstack vào CI dự án TIÊU THỤ: workflow GitHub Actions tối giản viết mới, 3 bẫy CI xanh giả, pre-commit, adapter non-Claude. Gọi khi: 'thêm overstack vào CI', 'github actions cho wiki rules', 'pre-commit overstack'."
disable-model-invocation: true
---
# Skill: dym-setup-ci — Cắm luật overstack vào CI của **dự án bạn**
## When to use
- **Tại sao chạy:** hook phiên chỉ gác agent Claude, và agent non-Claude lờ mọi rule advisory. CI là chỗ duy nhất nói "không" mà không bypass được khi merge.
- **Sinh ra gì:** một job GitHub Actions chặn PR khi file `.md` wiki vi phạm luật tầng `repo`.
- Gọi qua hub: `/dym-setup ci` — hoặc trực tiếp `/dym-setup-ci` nếu đã symlink riêng.
## Steps
### 1. Đừng dùng workflow mà installer sinh ra
Installer đặt sẵn `.github/workflows/harness.yml`. File đó **không phải** workflow tối giản cho người tiêu thụ: nó `git clone` cả framework về runner, chạy `install-harness.sh --global`, rồi chạy `harness-doctor --ci` fire-drill và `harness-local run.py firedrill`. Đó là **CI của chính overstack** — nó chứng minh framework còn cắn, không chứng minh wiki dự án bạn sạch. Nó cũng pin `HARNESS_REF: orca` nên mỗi lần upstream đổi là CI của bạn đổi theo mà bạn không biết.
Nếu bạn không phát triển framework: **xoá nó và dùng bản dưới**.
```bash
rm .github/workflows/harness.yml
```
### 2. Workflow tối giản, tự đủ
`.github/workflows/wiki-rules.yml`:
```yaml
name: wiki rules
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-python@v5
with: { python-version: '3.x' }
# BẮT BUỘC: thiếu pyyaml thì validator fail-OPEN (exit 0) và CI xanh giả.
- run: pip install pyyaml
- name: validator có mặt?
run: test -f .harness/poc-vendor-neutral/bin/llmwiki-validate.py
- name: kiểm file .md thay đổi
run: |
set -euo pipefail
base="${{ github.event.pull_request.base.sha || github.event.before }}"
if [ -z "$base" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
base="$(git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD)"
fi
# CHỈ giữ file .md CÒN TỒN TẠI: validator trả 0 cho file đã xoá → xanh giả.
files=$(git diff --name-only --diff-filter=d "$base" HEAD | grep -E '\.md$' || true)
[ -z "$files" ] && { echo "không có .md đổi — bỏ qua"; exit 0; }
echo "kiểm tra:"; echo "$files" | sed 's/^/ /'
# mode `files` → exit 1 khi có vi phạm (KHÔNG phải 2)
# shellcheck disable=SC2086
python3 .harness/poc-vendor-neutral/bin/llmwiki-validate.py files $files
```
### 3. Ba chỗ dễ tạo CI xanh giả
| Bẫy | Vì sao | Đã xử ở workflow trên |
|---|---|---|
| Thiếu `pyyaml` | validator không đọc được policy → in `fail-open` ra stderr rồi **exit 0**. Mọi luật tắt, CI vẫn xanh | `pip install pyyaml` + `test -f` validator |
| File đã xoá vẫn nằm trong danh sách | validator trả **0** im lặng cho file không tồn tại | `--diff-filter=d` |
| Rẽ nhánh theo `rc == 2` | mode `files` thoát **1**, không phải 2 | dùng exit code trực tiếp, không tự so sánh |
Muốn tự rẽ nhánh (ví dụ báo cáo thay vì chặn), nhớ đúng bảng ở [02](../dym-setup-guardrail-cli/SKILL.md):
```bash
python3 .harness/poc-vendor-neutral/bin/llmwiki-validate.py files $files
rc=$?
case $rc in
0) echo "sạch" ;;
1) echo "có vi phạm luật tầng repo"; exit 1 ;;
*) echo "lỗi hạ tầng validator (rc=$rc)"; exit 1 ;;
esac
```
### 4. Pre-commit (tuỳ chọn, tầng nhanh hơn CI)
```bash
pipx install pre-commit # hoặc: pip install pre-commit
pre-commit install
pre-commit run --all-files
```
⚠️ Bản cài **trước** PR #114 sẽ đỏ ở bước này với `can't open file … harness/poc-vendor-neutral/…` trên **mọi** commit chạm `.md`. Đó là triệu chứng của bẫy dot-layout, không phải wiki của bạn bẩn — chạy lại installer bản mới, hoặc áp bản vá ở [01](../dym-setup-install/SKILL.md).
### 5. Cắm luật cho agent non-Claude
`gen-converters.py` sinh sẵn adapter cho từng vendor dưới `.harness/poc-vendor-neutral/out/`:
| Vendor | File sinh ra | Mức |
|---|---|---|
| Claude / OpenClaude | `out/claude/settings.snippet.json` | **chặn** (hook) |
| opencode | `out/opencode/opencode.json` | **chặn** (`permission.edit` native) |
| Cursor | `out/cursor/.cursor/rules/harness.mdc` | advisory |
| Kiro | `out/kiro/.kiro/steering/harness.md` | advisory |
| Codex | `out/codex/AGENTS.snippet.md` | advisory (dán tay vào `AGENTS.md`) |
Sửa luật thì sửa `policy.yaml` rồi sinh lại — **đừng sửa adapter bằng tay**:
```bash
python3 .harness/poc-vendor-neutral/gen-converters.py
```
Từ PR #114, generator lấy tên thư mục harness từ env `OVERSTACK_HARNESS_DIR` (mặc định `harness`). Ở dự án layout dot phải truyền vào, nếu không snippet sinh ra lại trỏ sai:
```bash
OVERSTACK_HARNESS_DIR=.harness python3 .harness/poc-vendor-neutral/gen-converters.py
```
(Chạy lại `install.sh` thì nó tự truyền — đây chỉ là đường gọi generator trực tiếp.)
Advisory chỉ là *nhắc*, agent lờ được. Vì thế với đội dùng nhiều vendor, CI ở mục 2 là tầng gác duy nhất đáng tin.
## Rules
- ⚠️ Bản cài **trước** PR #114 sẽ đỏ ở bước này với `can't open file … harness/poc-vendor-neutral/…` trên **mọi** commit chạm `.md`. Đó là triệu chứng của bẫy dot-layout, không phải wiki của bạn bẩn — chạy lại installer bản mới, hoặc áp bản vá ở [01](../dym-setup-install/SKILL.md).
references/example-setup/skills/dym-setup-contributor.skill.md
---
name: dym-setup-contributor
description: "Sửa CHÍNH overstack: fdk-gate 21 step (exit 0/2), medic 18 probe, sửa luật đúng đường policy→gen-converters, /fdk-uat canary, /ship, R15 no-ai-attribution. Gọi khi: 'contribute overstack', 'sửa rule harness', 'fdk-gate', 'release overstack'."
disable-model-invocation: true
---
# Skill: dym-setup-contributor — Đóng góp: sửa chính overstack
## When to use
- **Tại sao chạy:** repo framework có định-nghĩa-hoàn-thành riêng, máy-đọc-được. Bạn không tự đoán "đã đủ chưa" — bạn chạy một lệnh và nó trả lời.
- **Sinh ra gì:** bảng ✓/✗ 21 step, `RELEASE-vX.Y.Z.md` khi cắt release, và (khi cần) nhánh canary `uat/<ts>` trên remote.
- Gọi qua hub: `/dym-setup contributor` — hoặc trực tiếp `/dym-setup-contributor` nếu đã symlink riêng.
## Steps
### 1. Lấy repo và định vị
```bash
git clone -b orca https://github.com/rheinmir/setup.git
cd setup
python3 -c "import yaml" || pip install pyyaml # thiếu pyyaml → validator fail-open, mọi cổng xanh giả
```
Không có `package.json` / `pyproject.toml` / `Makefile`. "Entry point" của repo là:
| Đường | Là gì |
|---|---|
| `harness/poc-vendor-neutral/policy.yaml` | **nguồn chân lý duy nhất** của 19 luật |
| `harness/poc-vendor-neutral/gen-converters.py` | sinh mọi adapter vendor + CI + pre-commit từ policy |
| `harness/poc-vendor-neutral/bin/llmwiki-validate.py` | lõi validator (đọc policy, không hardcode luật) |
| `harness/scripts/` (68 file) · `harness/validators/` (18 file) | engine + validator production |
| `fdk/tools/` (23 file) | đồ nghề phát triển **chính** framework |
| `skills/` (87 thư mục) | canonical skill, mirror sang `llmwiki/skills/` |
| `fdk/wiki/` | wiki RIÊNG của framework (ADR-001..010) — không travel xuống dự án |
Front door on-demand cho mọi việc phát triển framework: gọi `/fdk` **trong chat** (pre-flight + inventory live).
### 2. Cổng bắt buộc: `fdk-gate.py`
Định-nghĩa-hoàn-thành, bản máy đọc. **exit 0 = đủ điều kiện push · exit 2 = thiếu step.**
```bash
python3 harness/scripts/fdk-gate.py --root .
python3 harness/scripts/fdk-gate.py --root . --json # cùng mã thoát, output máy đọc
```
21 step, mỗi step trỏ tới một gate đã có (single source — không lặp lại logic):
`R3 index-sync` · `L4 wiki-health` · `arch-scan` · `harness-lint` · `agent↔claude parity` · `duplicate-basename` · `harness-doctor` · `adapt-registry leak-gate` · `overstack-docs current` · `capabilities current` · `skill mirror parity` · `skill cross-surface` · `task-lifecycle` · `audit-chain` · `code-health` · `bnal self-test wired` · `policy↔converters drift` · `graph-engineering tests` · `vendor-neutral demo` · `vendor-neutral broad` · `BNAL feature self-tests`
Thêm gate mới = thêm một dòng vào `STEPS` (và cập nhật checklist con-người ở master-wiki cho khớp).
### ⚠️ HEAD của `orca` từng KHÔNG qua chính cổng của nó (tới `5456eb3`; đã sửa ở #116)
> **Cập nhật 2026-09-07 (sau lượt fix #116–#119):** `orca` HEAD `16e1971` **xanh toàn bộ CI** lần đầu; `fdk-gate` 21/21; `template_version` 1.3.69 (installer tự cài lại global khi thấy version đổi — đã đo trên máy thật: `1.3.68 → 1.3.69`, smoke OK). Bẫy migrate (#106) và pre-commit trỏ engine đã gỡ cũng đã vá ở #117. Skill `/playwright-verify` có trong repo (#119, 88 skill).
Chạy thật trên clone sạch tại `5456eb3` (2026-09-04), không sửa gì:
```
✗ THIẾU 5/21 step → CHƯA đủ điều kiện push.
rc = 2
```
| Step đỏ | Thông điệp |
|---|---|
| `L4 wiki-health` | quét 175 trang `llmwiki/wiki`, broken wikilink từ `entities/repowise.md`: `[[code-graph]]` ×3, `[[frontier-gap-scan]]`, `[[innovation-110826]]`, … |
| `overstack-docs current` | `[build-overstack-docs] ⚠ 1 skill chưa phân nhóm mind map (đang ở '❓ chưa phân loại'): diag…` |
| `task-lifecycle` | `[task-lifecycle] LỆCH state-machine Trụ 3` |
| `bnal self-test wired` | `[bnal-selftest] DRIFT — script có --self-test nhưng fdk-gate KHÔNG chạy (1): overstack_pat…` |
| `graph-engineering tests` | chạy riêng từng test: 6/7 PASS, đỏ duy nhất là `harness/tests/ge-reachability-test.sh` (rc=2) |
Nghĩa là: **đừng dùng "gate xanh" làm mốc so sánh cho thay đổi của bạn.** Chụp baseline trước khi sửa:
```bash
python3 harness/scripts/fdk-gate.py --root . --json > /tmp/gate-before.json
# … sửa …
python3 harness/scripts/fdk-gate.py --root . --json > /tmp/gate-after.json
python3 - <<'PY'
import json
b = {r["step"]: r["ok"] for r in json.load(open("/tmp/gate-before.json"))["results"]}
a = {r["step"]: r["ok"] for r in json.load(open("/tmp/gate-after.json"))["results"]}
new = [s for s in a if a[s] is False and b.get(s) is True]
fixed = [s for s in a if a[s] is True and b.get(s) is False]
print("BẠN LÀM ĐỎ THÊM:", new or "không")
print("bạn sửa xanh: ", fixed or "không")
PY
```
Chỉ `BẠN LÀM ĐỎ THÊM: không` mới là điều kiện đủ để đi tiếp.
Gate **read-only**: `git status --porcelain` sau khi chạy vẫn sạch (đã kiểm).
### 3. Cổng sức khoẻ tổng: `medic`
```bash
python3 fdk/tools/medic.py # tất cả
python3 fdk/tools/medic.py --list # liệt kê probe
python3 fdk/tools/medic.py rules docs # chỉ nhóm khớp mô tả phạm vi
python3 fdk/tools/medic.py --ci # exit ≠ 0 nếu có mục FAIL
```
18 probe (đếm thật từ `--list`): `rules` · `coverage` · `backstop` · `docs` · `wikisummary` · `frontend` · `prose` · `narrative` · `foundation` · `selfstate` · `code` · `eval` · `freshinstall` · `capsurface` · `capproof` · `provenance` · `orchestration` · `deps`.
`medic` fail-open từng probe: probe lỗi → SKIP, không giết cả cổng. Nó cũng **chỉ chạy trên repo framework** — `ROOT = Path(__file__).resolve().parents[2]`, nên gọi từ bản global thì nó chấm chính bản global.
### 4. Sửa một luật — đường đúng
```bash
# 1. sửa luật (nguồn chân lý DUY NHẤT)
$EDITOR harness/poc-vendor-neutral/policy.yaml
# 2. sinh lại MỌI adapter từ policy — đừng sửa file trong out/ bằng tay
python3 harness/poc-vendor-neutral/gen-converters.py
# 3. self-test lõi
bash harness/poc-vendor-neutral/demo.sh # 13 assertion
bash harness/poc-vendor-neutral/test-broad.sh # 80 assertion
# 4. chứng adapter không drift khỏi policy
bash harness/tests/policy-converters-drift-test.sh
# 5. cổng đầy đủ
python3 harness/scripts/fdk-gate.py --root .
```
Thêm skill mới: `python3 fdk/tools/new-skill.py` (sinh vào **cả hai** cây publish cùng lúc — `skills/` canonical và `llmwiki/skills/` mirror). Kiểm parity: `python3 harness/scripts/sync-skills.py --check`.
Quyết định kiến trúc: viết ADR vào `fdk/wiki/sources/adr/`. Gate **R13** ép mọi quyết định `architecture` trong `decisions.md` phải ref một ADR.
### 5. UAT trước khi công bố năng lực mới
Gọi `/fdk-uat` **trong chat**. Nó có hai pha, và pha 2 là pha duy nhất kiểm được **giá trị mặc định**:
1. **Canary trước merge** — đẩy lên nhánh tạm `uat/<ts>`, rồi `curl` bootstrap **từ raw của chính nhánh đó** với `HARNESS_BASE` + `REPO_RAW` + `SKILLS_REF` trỏ canary. FAIL thì xoá canary, nhánh chính chưa hề bị bẩn.
2. **main-URL smoke ngay sau merge** — chạy đúng lệnh người mới gõ, **không override biến nào**. Chỉ pha này bắt được chỗ hardcode tên nhánh. FAIL thì gỡ commit khỏi remote.
Vì sao `SKILLS_REF` phải override được ở pha 1: không có nó, cài-từ-nhánh-X vẫn kéo skill của `orca` → bài UAT chấm bản CŨ rồi báo PASS cho bản MỚI. Một cổng nói dối mà vẫn xanh còn tệ hơn không có cổng.
`medic --ci` và `fresh-install-smoke.sh` cài từ working-tree qua `file://` nên **không** chứng minh được đường remote. Bản đầy đủ curl-github: `bash harness/scripts/fresh-install-smoke.sh --remote`.
### 6. Push / release
Gọi `/ship` **trong chat** — nó dừng chờ duyệt trước mọi bước side-effect. Năm mức:
| Mức | Làm gì |
|---|---|
| `ship push` | đẩy, không tag |
| `ship release` | đẩy + tag `vX.Y.Z` + `RELEASE-vX.Y.Z.md` |
| `ship pr` | đẩy nhánh + `gh pr create` |
| `ship mr` | đẩy nhánh + `glab mr create` |
| `ship merge` | liệt kê PR/MR *đến* → kéo về → gate + test → chỉ merge nếu xanh |
Checklist nó chạy trước khi đẩy: `medic --ci` → git sạch (rác `scratchpad/` không track) → selftest các engine chạm tới → version `x.x.x+1` từ tag gần nhất (chỉ mức release) → patch note trung thực có mục **Known-limitations**, không phóng đại.
⚠️ **R15 no-ai-attribution** chặn commit message ghi công cho AI: `Co-Authored-By: Claude…`, "Generated with Claude Code", 🤖. Nếu môi trường agent của bạn tự chèn trailer đó, phải gỡ trước khi commit — nếu không pre-commit/CI đỏ.
### 7. CI của repo (đọc để hiểu, đừng bê xuống dự án tiêu thụ)
`.github/workflows/harness.yml` chạy trên mọi PR và push lên `orca`, ba job:
- **selftest** — `demo.sh` + `test-broad.sh` + `wiki-graph-user-reachability-test.sh` + `memory-map-user-reachability-test.sh`
- **validate-content** — `llmwiki-validate.py files` trên các `.md` thay đổi (mode `files`, **exit 1**)
- **repo-health** — `index_sync.py` trên **cả hai** wiki (`fdk/wiki` và `llmwiki/wiki`), `wiki-health.py --fail-on broken`, `arch-scan.py`
Tên job từng ghi "demo 13 + broad 54 = 67 assertion" trong khi số thật là **13 + 80**; PR #114 đã sửa thành `13 + 80 = 93`. Nhớ cập nhật nhãn này mỗi lần thêm assertion.
Muốn cắm luật vào CI của một dự án *tiêu thụ*, đừng copy file này — dùng bản tối giản ở [04](../dym-setup-ci/SKILL.md).
## Rules
- > **Cập nhật 2026-09-07 (sau lượt fix #116–#119):** `orca` HEAD `16e1971` **xanh toàn bộ CI** lần đầu; `fdk-gate` 21/21; `template_version` 1.3.69 (installer tự cài lại global khi thấy version đổi — đã đo trên máy thật: `1.3.68 → 1.3.69`, smoke OK). Bẫy migrate (#106) và pre-commit trỏ engine đã gỡ cũng đã vá ở #117. Skill `/playwright-verify` có trong repo (#119, 88 skill).
- ⚠️ **R15 no-ai-attribution** chặn commit message ghi công cho AI: `Co-Authored-By: Claude…`, "Generated with Claude Code", 🤖. Nếu môi trường agent của bạn tự chèn trailer đó, phải gỡ trước khi commit — nếu không pre-commit/CI đỏ.
references/example-setup/skills/dym-setup-guardrail-cli.skill.md
---
name: dym-setup-guardrail-cli
description: "Gọi validator overstack từ SHELL: 3 mode (path/files/claude-hook), 19 luật R1–R19, mã thoát 0/1/2 không đồng nhất, 4 đường fail-open. Gọi khi: 'luật còn cắn không', 'chạy validator', 'test rule', 'exit code validator'."
disable-model-invocation: true
---
# Skill: dym-setup-guardrail-cli — Gọi guardrail từ terminal: 3 mode, 19 luật, mã thoát
## When to use
- **Tại sao chạy:** tự tay xác nhận luật CÓ cắn, và biết chính xác mã thoát để rẽ nhánh trong script/CI thay vì đoán 0/1.
- **Sinh ra gì:** không sinh file. Chỉ in vi phạm ra **stderr** rồi thoát với mã tương ứng.
- Gọi qua hub: `/dym-setup guardrail-cli` — hoặc trực tiếp `/dym-setup-guardrail-cli` nếu đã symlink riêng.
## Steps
### 1. Một binary, ba mode
```
python3 .harness/poc-vendor-neutral/bin/llmwiki-validate.py [--policy P] {path <FILE> | files <F...> | claude-hook}
```
| Mode | Đọc gì | Áp luật tầng | Mã thoát khi VI PHẠM |
|---|---|---|---|
| `path <FILE>` | 1 đường dẫn | `repo` | **2** |
| `files <F...>` | nhiều đường dẫn | `repo` | **1** |
| `claude-hook` | JSON hook Claude từ **stdin** | `session` | **2** |
`--policy P` trỏ policy khác; mặc định là `policy.yaml` cạnh binary.
**Cùng một vi phạm, hai mã thoát khác nhau** — đây không phải lỗi đánh máy, nó nằm ngay trong mã (`block_code = 2` cho `path`/`claude-hook`, `= 1` cho `files`). Script nào rẽ nhánh theo mã thoát phải biết mình đang gọi mode nào.
Đo thật trên file thiếu `## Origin` + thiếu frontmatter:
```bash
$ python3 $V files .llmwiki/wiki/concepts/bad.md
[R2 origin-required] .llmwiki/wiki/concepts/bad.md thiếu '## Origin' — …
[R9 okf-frontmatter] .llmwiki/wiki/concepts/bad.md thiếu YAML frontmatter (--- … ---) — …
rc=1
$ python3 $V path .llmwiki/wiki/concepts/bad.md
[R2 origin-required] …
[R9 okf-frontmatter] …
rc=2
```
### 2. ⚠️ Bốn đường fail-open — đều thoát 0
| Tình huống | Mã thoát | Hệ quả |
|---|---|---|
| Mode lạ (`bogus`) | **0** + `mode lạ 'bogus' — fail-open` ra stderr | gõ sai mode → CI xanh giả |
| Không tham số | **0** + dòng usage | như trên |
| **File không tồn tại** | **0**, im lặng hoàn toàn | target sai đường dẫn → CI xanh giả |
| Không đọc được `policy.yaml` | **0** + `không đọc được policy … — fail-open` | thiếu `pyyaml` → mọi luật tắt, không ai biết |
Trong CI, luôn kiểm tra file tồn tại **trước** khi giao cho validator — xem [04](../dym-setup-ci/SKILL.md).
### 3. Bộ 19 luật (đếm từ `policy.yaml`, không đếm từ README)
`enforce_at: session` = chặn lúc agent định ghi (hook). `repo` = chặn lúc commit/PR (pre-commit + CI).
| ID | Tên | Chặn gì | Tầng |
|---|---|---|---|
| R1 | no-write-raw | agent ghi vào `raw/` — inbox của con người, chỉ đọc | session |
| R2 | origin-required | wiki content thiếu `## Origin` | session + repo |
| R3 | index-sync | `wiki/index.md` lệch tập file thật | session + repo |
| R4 | audit-log | ghi `.claude/audit/audit.jsonl` (không chặn) | session |
| R5 | folder-structure | file `.md` nằm trần ở `wiki/` root | session + repo |
| R6 | verify-before-commit | commit chưa qua validator + lint + drift-test | repo |
| R7 | proposal-complete | SPEC thiếu `## Agent Task Assignment` / Sequence diagram / `## Global constraints` | session + repo |
| R8 | session-health | báo số rule đang gác + drift policy đầu phiên (không chặn) | session |
| R9 | okf-frontmatter | wiki content thiếu YAML frontmatter + `type:` | session + repo |
| R10 | docs-gate | nhắc bổ sung docs mỗi N prompt (không chặn) | session |
| R11 | seq-html-glass-style | `*-seq.html` không theo style liquid-glass | session + repo |
| R12 | pull-before-change | chưa `pull-gate` trước khi fan-out / trước push | session + repo |
| R13 | decision-to-adr | quyết định `architecture` trong `decisions.md` không ref ADR | repo |
| R14 | patterns-protected | agent tự sửa `llmwiki/patterns/` (unlock: `LLMWIKI_PATTERNS_UNLOCK=1`) | session |
| R15 | no-ai-attribution | commit message ghi công cho AI (`Co-Authored-By: Claude…`, 🤖) | repo |
| R16 | report-show-path | HTML report dưới `llmwiki/html/` không nhúng đường dẫn tuyệt đối của chính nó | session |
| R17 | problem-tree-flush | SessionEnd chạm bề mặt framework mà problem-tree chưa cập nhật (không chặn) | session |
| R18 | plan-executable | `*-PLAN.md` thiếu Files/Interfaces/code từng bước | session + repo |
| R19 | evidence-terminal | khối ```evidence-chain có đường đi không kết thúc ở nút chứng cứ | session + repo |
### 4. Thử luật cắn — bốn lệnh đủ
```bash
V=.harness/poc-vendor-neutral/bin/llmwiki-validate.py
# R1 — agent ghi vào raw/ (mode hook)
echo '{"tool_name":"Write","tool_input":{"file_path":"llmwiki/raw/x.md","content":"x"}}' \
| python3 $V claude-hook; echo "rc=$?" # 2 + [R1 no-write-raw]
# R1 qua Bash redirect
echo '{"tool_name":"Bash","tool_input":{"command":"echo hi > .llmwiki/raw/a.md"}}' \
| python3 $V claude-hook; echo "rc=$?" # 2
# R2 + R9 — wiki page thiếu Origin/frontmatter (mode repo)
printf '# Thiếu\n\nnội dung\n' > .llmwiki/wiki/concepts/bad.md
python3 $V files .llmwiki/wiki/concepts/bad.md; echo "rc=$?" # 1
# R5 — file .md nằm trần ở wiki/ root
printf -- '---\ntype: x\n---\n## Origin\nz\n' > .llmwiki/wiki/loose.md
python3 $V files .llmwiki/wiki/loose.md; echo "rc=$?" # 1 + [R5 folder-structure]
```
Trang wiki **hợp lệ** tối thiểu (qua cả R2, R5, R9):
```markdown
---
type: concept
---
# Tên khái niệm
## Origin
Nguồn: cuộc họp 06/09/2026 · file raw/notes.md
```
### 5. Ba luật CHẾT dưới layout dot — ĐÃ SỬA Ở UPSTREAM (PR #114)
> **Audit sau merge (PR #115):** #114 mới vá glob R14 ở lõi vendor-neutral (hook per-project). Validator production `patterns_guard.py` mà hook **global** gọi vẫn hardcode `llmwiki/patterns` ở nhánh write — đo rc=0 dưới `.llmwiki/patterns/`. Đã vá ở PR #115.
> **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
`01` sửa **đường dây** (hook trỏ sai file). Đây là chuyện khác: ba luật hardcode segment `llmwiki` **trong chính glob của luật**, nên khi dự án dùng `.llmwiki/` thì glob không khớp và luật im lặng không bao giờ cắn:
| Luật | Glob trong `policy.yaml` | `.llmwiki/…` |
|---|---|---|
| R14 patterns-protected | `**/llmwiki/patterns/**`, `llmwiki/patterns/**` | TRƯỢT |
| R16 report-show-path | `**/llmwiki/html/*.html` | TRƯỢT |
| R19 evidence-terminal | `**/llmwiki/wiki/**/*.md` | TRƯỢT |
**R11 KHÔNG nằm trong nhóm này** dù glob đầu của nó cũng chứa `llmwiki`: nó có glob thứ hai `**/html/*-seq.html` không kèm tên thư mục gốc, nên vẫn khớp bình thường.
Các luật còn lại dùng glob **không** kèm tên thư mục gốc (`**/raw/**`, `**/wiki/concepts/**/*.md`) nên vẫn khớp bình thường. Đo thật:
```
TRƯỢT **/llmwiki/patterns/** vs .llmwiki/patterns/p.md
KHỚP **/llmwiki/patterns/** vs llmwiki/patterns/p.md
TRƯỢT **/llmwiki/wiki/**/*.md vs .llmwiki/wiki/concepts/a.md
KHỚP **/raw/** vs .llmwiki/raw/a.md
KHỚP **/wiki/concepts/**/*.md vs .llmwiki/wiki/concepts/a.md
```
Cách vá tại chỗ — thêm biến thể dot vào `policy.yaml` của dự án rồi sinh lại adapter:
```bash
python3 - <<'PY'
import re, pathlib
p = pathlib.Path(".harness/poc-vendor-neutral/policy.yaml")
s = p.read_text(encoding="utf-8")
# thêm dòng glob song song cho mọi glob chứa 'llmwiki/'
out = []
for line in s.splitlines(True):
out.append(line)
m = re.match(r'^(\s*- )"?([^"\n]*llmwiki/[^"\n]*)"?\s*$', line)
if m and ".llmwiki/" not in m.group(2):
out.append(f'{m.group(1)}"{m.group(2).replace("llmwiki/", ".llmwiki/")}"\n')
p.write_text("".join(out), encoding="utf-8")
print("đã thêm biến thể .llmwiki/ vào policy")
PY
python3 .harness/poc-vendor-neutral/gen-converters.py # sinh lại adapter từ policy
```
Nghiệm thu:
```bash
echo '{"tool_name":"Write","tool_input":{"file_path":".llmwiki/patterns/p.md","content":"x"}}' \
| python3 $V claude-hook; echo "rc=$?" # trước vá: 0 · sau vá: 2 [R14]
```
### 6. Lỗ trong `check_deny_write_bash` — ĐÃ SỬA Ở UPSTREAM (PR #114)
> **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
Nhánh xử lý tool `Bash` **không đọc glob của luật**. Nó chỉ kiểm tra chuỗi con `"raw/"` có trong câu lệnh không:
```python
def check_deny_write_bash(command, rule):
cmd = command or ""
if "raw/" in cmd and (BASH_WRITE.search(cmd) or BASH_COPY.search(cmd)):
return f"[{_tag(rule)}] chặn bash ghi raw/: {cmd[:100]}"
return None
```
Hai hệ quả đo được:
- **Dương tính giả:** một lệnh bash ghi vào `raw/` bị báo **hai lần** — một dòng `[R1 no-write-raw]` và một dòng `[R14 patterns-protected]` với cùng nội dung "chặn bash ghi raw/". R14 không liên quan gì tới `raw/`.
- **Âm tính giả:** `echo x > llmwiki/patterns/p.md` qua tool `Bash` → **rc=0**, không chặn, dù đó đúng là đích R14 muốn gác. Nói cách khác **R14 chỉ gác đường `Write/Edit`, không gác đường `Bash`** — kể cả với layout không dấu chấm.
Đừng dựa vào R14 để khoá `patterns/` trước một agent có quyền `Bash`. Muốn khoá thật: đặt quyền ở `permissions.deny` của Claude, hoặc để file ngoài repo.
### 7. Self-test lõi
```bash
bash .harness/poc-vendor-neutral/demo.sh # 13 assertion
bash .harness/poc-vendor-neutral/test-broad.sh # 80 assertion
```
Cả hai in `OK`/`FAIL` từng dòng và thoát 0 khi xanh. Số thật đo được là **80** (`demo.sh` 13). Nhãn `(68)` trong log cài và `broad 54 = 67 assertion` ở tên job CI là chuỗi cứng đã trôi — PR #114 sửa cả hai thành `13 + 80 = 93`.
## Rules
- > **Audit sau merge (PR #115):** #114 mới vá glob R14 ở lõi vendor-neutral (hook per-project). Validator production `patterns_guard.py` mà hook **global** gọi vẫn hardcode `llmwiki/patterns` ở nhánh write — đo rc=0 dưới `.llmwiki/patterns/`. Đã vá ở PR #115.
- > **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
- > **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
references/example-setup/skills/dym-setup-install.skill.md
---
name: dym-setup-install
description: "Cài overstack vào dự án (bootstrap 1 dòng), cờ nào có thật ở đâu, ghi gì vào $HOME, xác nhận rào cắn, gỡ. Gọi khi: 'cài overstack', 'bootstrap', 'setup harness', 'gỡ overstack'."
disable-model-invocation: true
---
# Skill: dym-setup-install — Cài overstack vào dự án của bạn
## When to use
- **Tại sao chạy:** biến agent của bạn thành cộng sự có luật cứng — 19 rule tất định chặn agent ghi bậy, 0 token, không cần API key.
- **Sinh ra gì:** `.harness/` (lõi luật) · `.llmwiki/` (khung wiki) · `.github/workflows/harness.yml` · `.pre-commit-config.yaml` · `.claude/settings.json` (merge) · `CAPABILITIES.md` · và một bản engine global ở `~/.claude/harness/`.
- Gọi qua hub: `/dym-setup install` — hoặc trực tiếp `/dym-setup-install` nếu đã symlink riêng.
## Steps
### 1. Lệnh chuẩn (một dòng)
Chạy **tại thư mục gốc dự án**:
```bash
curl -fsSL https://raw.githubusercontent.com/Rheinmir/setup/orca/harness/poc-vendor-neutral/bootstrap.sh | bash
```
Mặc định = **cả 3 trụ** (harness + skills global + llmwiki). Đây là mặc định thật, không phải cần thêm cờ: `bootstrap.sh` tự chèn `--full` khi bạn không truyền `--harness-only`.
Cờ đi sau `bash -s --`:
```bash
# chỉ harness, không đụng ~/.claude/skills
curl -fsSL .../bootstrap.sh | bash -s -- --harness-only
# ép vendor thay vì để nó tự dò
curl -fsSL .../bootstrap.sh | bash -s -- --vendor claude,opencode
# bỏ bước self-test cuối (nhanh hơn ~10s)
curl -fsSL .../bootstrap.sh | bash -s -- --no-verify
```
Đổi nguồn/nhánh (fork, canary):
```bash
HARNESS_BASE=https://raw.githubusercontent.com/<owner>/<repo>/<branch>/harness/poc-vendor-neutral \
bash -c 'curl -fsSL $HARNESS_BASE/bootstrap.sh | bash'
```
### 2. ⚠️ `--harness-only` chỉ tồn tại ở `bootstrap.sh`
`bootstrap.sh` **dịch** cờ này rồi bỏ nó đi trước khi gọi `install.sh`. Nếu bạn đã clone repo và gọi thẳng installer:
```bash
bash harness/poc-vendor-neutral/install.sh . --harness-only
# tham số lạ: --harness-only
# rc = 1 → KHÔNG cài gì cả
```
Đúng là:
```bash
bash harness/poc-vendor-neutral/install.sh . # = harness-only
bash harness/poc-vendor-neutral/install.sh . --full # = cả 3 trụ
bash harness/poc-vendor-neutral/install.sh . --with-wiki --no-verify
```
Danh sách cờ `install.sh` chấp nhận (nguyên văn từ `case` của nó): `--vendor <list>` · `--no-verify` · `--clean` · `--with-skills` · `--with-wiki` · `--full`. Tham số không bắt đầu bằng `-` được hiểu là `project_root`.
### 3. Lệnh này ghi vào `$HOME`, không chỉ vào dự án
Đọc kỹ trước khi chạy trên máy đang làm việc:
| Đích | Khi nào | Ghi gì |
|---|---|---|
| `<project>/.harness/`, `<project>/.llmwiki/` | luôn | lõi + khung wiki |
| `<project>/.claude/settings.json` | vendor `claude` được dò thấy | merge 6 hook (có backup `.bak`) |
| `~/.claude/harness/` | luôn (khi chưa có, hoặc bản cũ hơn) | engine global: `hooks/`, `harness/scripts/` (58 file), `fdk/tools/` (17 file) |
| `~/.claude/settings.json` | luôn | merge 8 hook global + 3 `permissions.deny` (có backup `.bak.*`) |
| `~/.claude/skills/` | **chỉ khi `--full` / `--with-skills`** | `npx skills add rheinmir/setup#orca --global --all` — **đè 87 skill global** |
| `~/.openclaude/skills` | khi có binary `openclaude` | symlink sang `~/.claude/skills` |
**Muốn thử mà không đụng máy thật** — cô lập `HOME` (đây chính là cách bundle này được đo):
```bash
SB=$(mktemp -d); mkdir -p "$SB/fakehome" "$SB/proj/.claude"
git -C "$SB/proj" init -q
HOME="$SB/fakehome" bash /path/to/clone/harness/poc-vendor-neutral/install.sh "$SB/proj"
# mọi thứ global rơi vào $SB/fakehome/.claude/, ~/.claude thật không bị đụng
```
### 4. 🔴 Bẫy dot-layout — ĐÃ SỬA Ở UPSTREAM (PR #114)
> **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
Cài từ `orca` kể từ `d8f1967` thì bỏ qua mục này. Nếu bản cài của bạn có trước đó, hoặc bạn không muốn chạy lại installer, dùng bản vá tay bên dưới.
**Triệu chứng:** cài xong, log in `TRẠNG THÁI 3 TRỤ ✓`, nhưng **không luật nào cắn** khi agent ghi bậy; và mọi `git commit` chạm file `.md` thì pre-commit đỏ với `can't open file`.
**Nguyên nhân:** với dự án downstream, installer chọn layout có dấu chấm (`.harness/`, `.llmwiki/`) vì `fdk/wiki` không tồn tại. Nhưng ba chỗ sinh dây vẫn hardcode đường **không** dấu chấm:
- `gen-converters.py` — `CLI = "harness/poc-vendor-neutral/bin/llmwiki-validate.py"`, `EVT = "harness/poc-vendor-neutral/bin/harness-events.py"`
- `install.sh` — heredoc pre-commit: `entry: python3 harness/poc-vendor-neutral/bin/llmwiki-validate.py files`
- `install-harness.sh` (global) — mọi hook gác bằng `[ -f "${CLAUDE_PROJECT_DIR:-.}/llmwiki/.harness-stamp" ]`, còn stamp thật nằm ở `.llmwiki/.harness-stamp`
Hậu quả đo được:
```bash
# đúng chuỗi lệnh trong .claude/settings.json
echo '{"tool_name":"Write","tool_input":{"file_path":"llmwiki/raw/hack.md","content":"x"}}' \
| ( [ -f "$PWD/harness/poc-vendor-neutral/bin/llmwiki-validate.py" ] \
&& exec python3 "$PWD/harness/poc-vendor-neutral/bin/llmwiki-validate.py" claude-hook || exit 0 )
echo "rc=$?" # → 0 KHÔNG chặn
# cùng payload, đường thật
echo '{"tool_name":"Write","tool_input":{"file_path":"llmwiki/raw/hack.md","content":"x"}}' \
| python3 .harness/poc-vendor-neutral/bin/llmwiki-validate.py claude-hook
echo "rc=$?" # → 2 [R1 no-write-raw] chặn ghi: llmwiki/raw/hack.md
```
Ba tầng gác đều trượt cùng lúc: hook project (im lặng), hook global (stamp guard sai), deny-glob global (`./llmwiki/raw/**` không phủ `.llmwiki/raw/**`). **Chỉ CI còn sống** vì nó gọi đường global tuyệt đối.
### Bản vá (chạy một lần, ngay sau khi cài)
```bash
# 1. hook Claude của dự án: harness/ → .harness/
python3 - <<'PY'
import json, pathlib, re
p = pathlib.Path(".claude/settings.json")
d = json.loads(p.read_text(encoding="utf-8"))
n = 0
for ev, defs in d.get("hooks", {}).items():
for grp in defs:
for h in grp.get("hooks", []):
c = h.get("command", "")
new = re.sub(r'(?<![\w.])harness/poc-vendor-neutral/', '.harness/poc-vendor-neutral/', c)
if new != c:
h["command"] = new; n += 1
p.write_text(json.dumps(d, ensure_ascii=False, indent=2), encoding="utf-8")
print(f"đã vá {n} hook")
PY
# 2. pre-commit
sed -i '' 's#python3 harness/poc-vendor-neutral/#python3 .harness/poc-vendor-neutral/#' .pre-commit-config.yaml # macOS
# sed -i 's#python3 harness/poc-vendor-neutral/#python3 .harness/poc-vendor-neutral/#' .pre-commit-config.yaml # Linux
# 3. stamp cho hook global — symlink, một nguồn chân lý
mkdir -p llmwiki && ln -sf ../.llmwiki/.harness-stamp llmwiki/.harness-stamp
```
Bước 3 tạo `llmwiki/` rỗng chỉ để chứa symlink stamp. Nếu bạn không muốn thư mục đó, cách thay thế là sửa `~/.claude/settings.json` đổi mọi `llmwiki/.harness-stamp` → `.llmwiki/.harness-stamp` và `./llmwiki/raw/**` → `./.llmwiki/raw/**` — nhưng lần chạy installer sau sẽ ghi đè lại, nên symlink bền hơn.
### Nghiệm thu bản vá
```bash
echo '{"tool_name":"Write","tool_input":{"file_path":"llmwiki/raw/x.md","content":"x"}}' \
| python3 "$PWD/.harness/poc-vendor-neutral/bin/llmwiki-validate.py" claude-hook; echo "rc=$?"
# kỳ vọng: rc=2 + dòng [R1 no-write-raw]
pre-commit run --all-files 2>&1 | tail -3 # không còn "can't open file"
```
**Cách né bẫy ngay từ đầu:** nếu dự án bạn KHÔNG ngại thư mục trần ở gốc, tạo sẵn `harness/` và `llmwiki/` **trước** khi cài — `install.sh` thấy `$ROOT/.harness` không tồn tại thì giữ `HARNESS_DIR="harness"`. Nhưng dot-layout tồn tại có lý do (cổng thiết kế của dự án quét `**/*.html` sẽ vớ phải `overstack.html` 530KB), nên bản vá ở trên là đường khuyên dùng.
### 5. Xác nhận cài đúng
```bash
ls -d .harness .llmwiki .github/workflows/harness.yml .pre-commit-config.yaml CAPABILITIES.md
head -3 CAPABILITIES.md # "87 skill · 19 rule · 23 fdk-tool · 68 harness-script"
cat .llmwiki/.harness-stamp # {"schema": 1, "guarded_by": "1.3.68"}
bash .harness/poc-vendor-neutral/demo.sh >/dev/null && echo "demo ok (13 assertion)"
bash .harness/poc-vendor-neutral/test-broad.sh >/dev/null && echo "broad ok (80 assertion)"
```
Tài liệu người-đọc đi kèm bản cài (self-contained, mở bằng `file://`, không cần mạng): `.llmwiki/html/overstack.html`.
**Claude Code: phải mở session mới (hoặc `/hooks` reload) thì hook mới nạp.**
### 6. Gỡ
```bash
bash .harness/poc-vendor-neutral/uninstall.sh . # gỡ wiring + lõi
bash .harness/poc-vendor-neutral/uninstall.sh . --keep-core # chỉ gỡ wiring
bash .harness/poc-vendor-neutral/uninstall.sh . --purge-bak # xoá luôn file .bak
```
`uninstall.sh` chỉ đảo ngược phần installer thêm vào **dự án**: CI workflow, hook pre-commit, hook trong `settings.json`. Nó **không** gỡ `~/.claude/harness/` hay `~/.claude/skills/` — hai thứ đó dùng chung cho mọi dự án, xoá tay nếu thật sự muốn.
## Rules
- > **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
references/example-setup/skills/dym-setup-maintain.skill.md
---
name: dym-setup-maintain
description: "Nâng bản, migrate dự án cũ (/harness-update --self-heal rc 0/3/4/1), công cụ nào chạy được ở downstream, 16 tool bị gỡ khỏi global, trần token, gỡ. Gọi khi: 'update overstack', 'nâng bản harness', 'migrate llmwiki cũ', 'health-check'."
disable-model-invocation: true
---
# Skill: dym-setup-maintain — Nâng bản, migrate dự án cũ, và những gì bạn KHÔNG chạy được ở downstream
## When to use
- **Tại sao chạy:** overstack cập nhật thường xuyên; bản cũ để lâu thì luật mới không xuống tới dự án, và bạn không biết mình đang bị gác bởi bao nhiêu luật.
- **Sinh ra gì:** engine global mới ở `~/.claude/harness/`, lõi per-project mới ở `.harness/`, `CAPABILITIES.md` sinh lại, và (khi có nợ) các trang wiki được backfill `## Origin` / frontmatter / dòng index.
- Gọi qua hub: `/dym-setup maintain` — hoặc trực tiếp `/dym-setup-maintain` nếu đã symlink riêng.
## Steps
### 1. Update thường: chạy lại đúng lệnh cài
> **Cập nhật 2026-09-07 (sau lượt fix #116–#119):** `orca` HEAD `16e1971` **xanh toàn bộ CI** lần đầu; `fdk-gate` 21/21; `template_version` 1.3.69 (installer tự cài lại global khi thấy version đổi — đã đo trên máy thật: `1.3.68 → 1.3.69`, smoke OK). Bẫy migrate (#106) và pre-commit trỏ engine đã gỡ cũng đã vá ở #117. Skill `/playwright-verify` có trong repo (#119, 88 skill).
Installer **idempotent** — chạy lại là update.
```bash
curl -fsSL https://raw.githubusercontent.com/Rheinmir/setup/orca/harness/poc-vendor-neutral/bootstrap.sh | bash
```
Cài mới hoàn toàn (gỡ cũ rồi cài):
```bash
curl -fsSL .../bootstrap.sh | bash -s -- --clean
```
✅ **Từ `orca` commit `d8f1967` (PR #114) trở đi, chạy lại installer là CÁCH SỬA bẫy dot-layout** — không cần bản vá tay ở [01](../dym-setup-install/SKILL.md) mục 4 nữa. Với bản cài cũ hơn thì ngược lại: installer ghi đè `.claude/settings.json` + `.pre-commit-config.yaml` bằng snippet đường không-dấu-chấm, nên phải áp lại bản vá sau mỗi lần chạy.
Xác nhận bản đang chạy:
```bash
cat .llmwiki/.harness-stamp # {"schema": 1, "guarded_by": "1.3.68"}
python3 -c "import json;print(json.load(open('$HOME/.claude/harness/version.json')).get('template_version'))"
head -3 CAPABILITIES.md
```
### 2. Dự án cũ (đã có `llmwiki/` từ trước harness) — `/harness-update`
Gọi `/harness-update` **trong chat**. Nó chạy một lệnh shell duy nhất rồi đọc mã thoát:
```bash
test -f harness/scripts/install-harness.sh \
&& bash harness/scripts/install-harness.sh . --self-heal \
|| { git clone -q --depth 1 -b orca https://github.com/rheinmir/setup.git /tmp/llmwiki-tpl \
&& bash /tmp/llmwiki-tpl/harness/scripts/install-harness.sh . --self-heal ; rm -rf /tmp/llmwiki-tpl; }
```
Nhánh clone gần như luôn được dùng ở downstream: `install-harness.sh` nằm trong nhóm **framework-only**, bản global cố tình **không** mang nó (xem mục 4).
`--self-heal` gộp cả vòng vào một process: cài L0–L4 → audit (Origin + index + OKF) → tự backfill nợ → re-audit một lần → activate + smoke. Không có cờ này thì nó giữ hành vi cũ: audit rồi thoát 3 nếu còn nợ.
**Mã thoát — đọc rồi mới hành động, đừng re-run mù:**
| rc | Nghĩa | Làm gì |
|---|---|---|
| **0** | sạch, đã backfill xong | xong; sang bước nghiệm thu |
| **3** | còn nợ self-heal không tự sửa được (conflict file, `type` OKF không suy được) | danh sách nằm ngay trong output — sửa tay **một lần** rồi chạy lại |
| **4** | auto-smoke thất bại: 3 luật lẽ ra phải chặn mà không chặn | rào đang thủng — dừng, không dùng tiếp |
| **1** | lỗi hạ tầng (mạng, python3, validator hỏng) | dừng, báo nguyên văn, đừng đoán |
Nghiệm thu sau update:
Trong output bước trên, tìm dòng `[audit] backfill xong — Origin:<a> index:<b> OKF:<c>` — đó là số nợ đã tự trả. Rồi sinh lại bản đồ năng lực để agent thấy đúng đồ nghề sau update:
```bash
python3 ~/.claude/harness/hooks/build-capabilities.py --root . # sinh lại CAPABILITIES.md
```
Đường cài global có smoke tự chạy; log xanh sẽ có dòng:
```
[harness] GLOBAL smoke OK: no_write_raw chặn đúng (rc=2)
```
Dòng đó **là** bằng chứng luật còn cắn ở tầng global. Không thấy nó thì đừng tin bảng "3 trụ ✓".
### 3. Kiểm tra sức khoẻ — công cụ nào dùng được ở đâu
| Lệnh | Chạy được ở dự án bạn? | Ghi chú |
|---|---|---|
| `bash .harness/poc-vendor-neutral/demo.sh` | ✅ | 13 assertion, nhanh |
| `bash .harness/poc-vendor-neutral/test-broad.sh` | ✅ | 80 assertion |
| `python3 $V claude-hook` (xem [02](../dym-setup-guardrail-cli/SKILL.md)) | ✅ | cách trực tiếp nhất để hỏi "luật còn cắn không" |
| `/harness-tour` (chat) | ✅ | Claude tự cố tình vi phạm cho bạn xem, tự dọn |
| `python3 ~/.claude/harness/harness/scripts/health-check.py --root . --offline` | ⚠️ | đòi `.template-manifest.json`; dự án thường **rc=1** + `manifest không tồn tại`. Đây là công cụ cho repo đồng bộ template, không phải cho dự án tiêu thụ |
| `harness-doctor.py --ci` | ❌ | framework-only, không có trong bản global |
| `medic` | ⚠️ | có trong global nhưng `ROOT = parents[2]` → nó chấm **chính bản global**, không chấm dự án bạn |
### 4. 16 tool cố tình bị gỡ khỏi bản global (+ 7 mục không bao giờ được chép sang)
Log cài in `GLOBAL: gỡ 16 tool framework_only`. Danh sách **16** đó là biến `STRIP_TIER3` trong `install-harness.sh` (đếm lại khi audit — bản đầu của tài liệu này gộp nhầm thành 23):
**`harness/scripts/` (10):** `adapt-registry.py` · `arch-scan.py` · `audit.py` · `bnal-selftest.py` · `dispatch-verify.py` · `fdk-gate.py` · `harness-doctor.py` · `harness-lint.py` · `skill-registry.py` · `sync-skills.py`
**`fdk/tools/` (6):** `build-cheatsheet.py` · `build-docs-index.py` · `build-health-dashboard.py` · `build-overstack-docs.py` · `new-skill.py` · `whiteboard-skill-map.py`
Ngoài ra **7 mục không nằm trong danh sách gỡ nhưng cũng vắng ở global** — chúng đơn giản không được chép sang ngay từ đầu: `harness/scripts/{install-harness.sh, fresh-install-smoke.sh, tour.sh, lib/}` và `fdk/tools/{fdk-kit.sh, sync-skill.sh, artifacts.config.yaml}`. Hệ quả với bạn giống nhau: không gọi được từ `~/.claude/harness/`.
Đây là **thiết kế**, không phải cài thiếu: tầng 3 (FDK) chỉ chạy ở repo framework. Cần chúng thì clone `rheinmir/setup` và đọc [06](../dym-setup-contributor/SKILL.md).
Còn lại ở global mà consumer dùng được: 58 script trong `harness/scripts/` (gồm `code-logger.py`, `wiki-health.py`, `wiki-graph.py`, `token-budget.py`, `loop-runner.py`, `council.py`…) và 17 tool trong `fdk/tools/`.
### 5. Trần token — mặc định là CẢNH BÁO, không chặn
Installer chạy `token-budget.py configure --if-tty`. Không có terminal (curl | bash trong script, CI) thì nó im lặng giữ mặc định:
```
[token-budget] không có terminal — giữ trần mặc định (mode: warn).
```
Mọi trần trong `token-budget.config.yaml` đều gắn `# ASSUMPTION (not verified)`. Muốn nó thật sự chặn thì phải tự chọn:
```bash
python3 ~/.claude/harness/harness/scripts/token-budget.py configure --root .
```
### 6. Gỡ
```bash
bash .harness/poc-vendor-neutral/uninstall.sh . # CI + pre-commit + hook trong settings.json + lõi
bash .harness/poc-vendor-neutral/uninstall.sh . --keep-core # chỉ gỡ wiring, giữ .harness/poc-vendor-neutral/
bash .harness/poc-vendor-neutral/uninstall.sh . --purge-bak # xoá luôn các file .bak installer tạo
```
Nó **không** đụng `~/.claude/harness/`, `~/.claude/skills/`, `~/.claude/settings.json` hay symlink `~/.openclaude/skills`. Muốn sạch hoàn toàn thì xoá tay — nhớ khôi phục `~/.claude/settings.json` từ bản `.bak.*` mà installer để lại.
## Rules
- > **Cập nhật 2026-09-07 (sau lượt fix #116–#119):** `orca` HEAD `16e1971` **xanh toàn bộ CI** lần đầu; `fdk-gate` 21/21; `template_version` 1.3.69 (installer tự cài lại global khi thấy version đổi — đã đo trên máy thật: `1.3.68 → 1.3.69`, smoke OK). Bẫy migrate (#106) và pre-commit trỏ engine đã gỡ cũng đã vá ở #117. Skill `/playwright-verify` có trong repo (#119, 88 skill).
references/example-setup/skills/dym-setup.skill.md
---
name: dym-setup
disable-model-invocation: true
description: "overstack (rheinmir/setup) — workflow đã kiểm chứng. Gõ /dym-setup <slug>. slugs: install · guardrail-cli · agent-workflow · ci · maintain · contributor"
---
# Skill: dym-setup — hub workflow cho overstack
## When to use
- User gõ `/dym-setup` (không tham số → bảng slug) hoặc `/dym-setup <slug>`.
- Đây là hub: context chỉ tốn dòng description; thân workflow con chỉ đọc khi được gọi.
## Steps
1. Đọc ARGUMENTS → `<slug>`. Không có slug → in bảng dưới rồi dừng, không đọc file nào.
| slug | mục đích | nhánh |
|---|---|---|
| `install` | cài/gỡ overstack, cờ thật, ghi gì vào $HOME, xác nhận rào cắn | tiêu thụ |
| `guardrail-cli` | validator từ shell: 3 mode, 19 luật, mã thoát 0/1/2 | tiêu thụ |
| `agent-workflow` | vòng /propose → /plan → /verify-before-commit → /ship (lệnh chat) | tiêu thụ |
| `ci` | GitHub Actions tối giản cho dự án tiêu thụ + pre-commit | tiêu thụ |
| `maintain` | nâng bản, migrate, rc 0/3/4/1, tool nào chạy được ở downstream | tiêu thụ |
| `contributor` | sửa chính overstack: fdk-gate, medic, UAT canary, ship | đóng góp |
2. Tìm file con theo thứ tự, lấy file ĐẦU TIÊN tồn tại rồi đọc ĐÚNG MỘT file đó:
1. `.claude/skills/dym-setup-<slug>/SKILL.md` (đã cài qua `npx skills add rheinmir/dym`)
2. `doyourmagic/setup/skills/dym-setup-<slug>/SKILL.md` (bundle nằm trong dự án, hub được symlink)
3. `doyourmagic-bundles/setup/skills/dym-setup-<slug>/SKILL.md` (clone `rheinmir/dym` cạnh dự án)
Làm theo `## Steps` và `## Rules` của file đó. Không đọc file con khác. Không thấy ở cả 3 chỗ → nói rõ và dừng.
3. Slug lạ → in bảng ở bước 1, dừng.
## Rules
- Chỉ đọc file con được gọi; không nạp cả bundle.
- Lệnh chat (`/x`) chỉ gõ trong chat; lệnh shell chỉ gõ trong terminal — file con đã tách sẵn.
references/example-setup/workflows.md
# overstack (`rheinmir/setup`) — bộ workflow chạy được
Sinh từ một lượt khảo sát **read-only** repo `Rheinmir/setup` nhánh `orca`, commit `5456eb3` (2026-09-04), cộng với **hai lần cài thật vào sandbox** (`HOME` bị cô lập) và một lần **đối chiếu với bản cài thật** đang nằm ở `/Users/giatran/orca/workspaces/hoh-autonomous/isonade`.
overstack không phải một CLI. Nó là **ba trụ** cắm vào dự án của bạn:
| Trụ | Là gì | Cài vào đâu |
|---|---|---|
| **Harness** | 19 luật tất định (R1–R19) + validator Python, không cần LLM, không cần API key | per-project `.harness/` + global `~/.claude/harness/` |
| **Skills** | 87 skill gọi bằng `/<tên>` trong phiên chat agent | global `~/.claude/skills/` (qua `npx skills`) |
| **llmwiki** | khung wiki `concepts/entities/sources/draft` + `raw/` inbox | per-project `.llmwiki/` |
## Cài dùng tại chỗ — một lệnh, chỉ nạp khi cần
```bash
mkdir -p .claude/skills && ln -sfn ../../doyourmagic/setup/skills/dym-setup .claude/skills/dym-setup
```
Chỉ hub `dym-setup` vào context (1 dòng). Gõ `/dym-setup` xem bảng slug, `/dym-setup install` để chạy một workflow. **Chế độ đặt tên:** mặc định `dym-<repo>-<slug>` (repo = `setup`). Mỗi thư mục `skills/dym-setup-<slug>/` là một SKILL.md tự chứa — promote lên repo chính bằng cách copy sang `skills/<tên-mới>/` rồi register (xem skill `doyourmagic` mục Promote). Sơ đồ luồng skill: [`flow.html`](flow.html).
Bundle chia theo **đối tượng người dùng**, không theo tính năng:
- **Nhánh tiêu thụ (`01`–`05`)** — bạn muốn *dùng* overstack trong dự án của mình.
- **Nhánh đóng góp (`06`)** — bạn clone chính `rheinmir/setup` để *sửa* framework.
| # | Skill (gọi qua hub) | Mục đích | Nhánh |
|---|------|----------|-------|
| 1 | [`/dym-setup install`](skills/dym-setup-install/SKILL.md) | Một dòng `curl \| bash`, cờ nào có thật ở đâu, file nào rơi xuống đâu, **và bản vá bắt buộc cho bẫy dot-layout** | Tiêu thụ — setup |
| 2 | [`/dym-setup guardrail-cli`](skills/dym-setup-guardrail-cli/SKILL.md) | Gọi validator từ shell: 3 mode, 19 luật, mã thoát **0/1/2 không đồng nhất** | Tiêu thụ — dùng hằng ngày (terminal) |
| 3 | [`/dym-setup agent-workflow`](skills/dym-setup-agent-workflow/SKILL.md) | Vòng `propose → gate → dispatch`: các lệnh `/<skill>` — **chỉ gõ trong chat**, không phải terminal | Tiêu thụ — dùng hằng ngày (chat) |
| 4 | [`/dym-setup ci`](skills/dym-setup-ci/SKILL.md) | Cắm luật vào CI **dự án của bạn** như cổng chặn thật, rẽ nhánh đúng mã thoát | Tiêu thụ — CI |
| 5 | [`/dym-setup maintain`](skills/dym-setup-maintain/SKILL.md) | Update bản mới, migrate dự án cũ, `--self-heal` với rc 0/3/4, gỡ sạch | Tiêu thụ — bảo trì |
| 6 | [`/dym-setup contributor`](skills/dym-setup-contributor/SKILL.md) | `/fdk` → `fdk-gate.py` (21 step) → `medic` → `/fdk-uat` canary → `/ship` | Đóng góp |
## Thứ tự chạy đề xuất
**Người mới dùng:** `01` (bắt buộc — gồm bản vá) → `02` để tự tay xác nhận luật CẮN → rồi `03` và `04` song song (đường chat và đường CI độc lập nhau) → `05` khi cần nâng bản.
**Người đóng góp:** vào thẳng `06`; nó không phụ thuộc `01`–`05`, vì repo framework dùng layout **không dấu chấm** và không dính bẫy ở `01`.
## Bốn cái bẫy đắt nhất — đọc trước khi gõ lệnh
> **Cập nhật 2026-09-07 (sau lượt fix #116–#119):** `orca` HEAD `16e1971` **xanh toàn bộ CI** lần đầu; `fdk-gate` 21/21; `template_version` 1.3.69 (installer tự cài lại global khi thấy version đổi — đã đo trên máy thật: `1.3.68 → 1.3.69`, smoke OK). Bẫy migrate (#106) và pre-commit trỏ engine đã gỡ cũng đã vá ở #117. Skill `/playwright-verify` có trong repo (#119, 88 skill).
> **Đã sửa ở upstream.** Ba lỗi dưới đây được vá trong PR #114, merge vào `orca` ngày 2026-09-06 (commit `d8f1967`, đóng #111 · #112 · #113). Phần mô tả giữ nguyên vì nó vẫn đúng cho **bản cài cũ** trên máy bạn — bản cài chỉ hết lỗi sau khi bạn chạy lại installer. Cài từ `orca` từ nay: bỏ qua bản vá tay.
1. **Cài xong nhưng KHÔNG luật nào cắn ở tầng phiên.** Installer đặt lõi vào `.harness/` (có dấu chấm) nhưng hook sinh ra lại trỏ `harness/` (không dấu chấm) → mọi hook Claude rơi vào nhánh `|| exit 0`, im lặng. Hook **global** thì gác bằng `llmwiki/.harness-stamp` trong khi stamp thật nằm ở `.llmwiki/.harness-stamp` → cũng bỏ qua. Chỉ CI còn sống. **Đã tái hiện 1:1 trên bản cài thật của máy này.** Bản vá 3 dòng: `01`. Riêng ba luật **R14 · R16 · R19** hardcode segment `llmwiki` ngay trong glob của luật nên bản vá đó không cứu — vá riêng ở `02` mục 5.
2. **`--harness-only` KHÔNG phải cờ của `install.sh`.** Nó là cờ của `bootstrap.sh`. Gọi thẳng `bash install.sh . --harness-only` → `tham số lạ: --harness-only`, **exit 1**, không cài gì. `install.sh` trần vốn đã là harness-only. Chi tiết: `01`.
3. **Mã thoát của validator không đồng nhất.** Cùng một vi phạm: mode `files` thoát **1**, mode `path` và `claude-hook` thoát **2**. Mode lạ, thiếu tham số, hoặc **file không tồn tại** đều thoát **0** (fail-open) — target sai đường dẫn sẽ không làm CI đỏ. Chi tiết: `02`, `04`.
4. **Một dòng `curl | bash` cũng ghi vào `$HOME`, không chỉ vào dự án.** Nó cài global harness ở `~/.claude/harness/`, merge `~/.claude/settings.json`, và với `--full` thì `npx skills add ... --global --all` đè lên `~/.claude/skills`. Muốn thử an toàn: cô lập `HOME`. Chi tiết: `01`.
## Bundle này được KIỂM CHỨNG thế nào, không chỉ diễn giải README
Môi trường đo: macOS 24.6.0, `python3` 3.9 (Command Line Tools), `git`, không mạng cho phần validator.
| Khẳng định | Nguồn kiểm chứng |
|---|---|
| Ba trụ + cờ `--harness-only/--clean/uninstall` | `README.md` + `harness/poc-vendor-neutral/bootstrap.sh:20-45` (khối dịch cờ `WANT_FULL`) |
| `install.sh` chỉ nhận `--vendor/--no-verify/--clean/--with-skills/--with-wiki/--full` | `install.sh:21-31` (`case`), nhánh `-*) … exit 1` |
| `--harness-only` gãy ở `install.sh` | Chạy thật: `bash install.sh $SB/proj --harness-only` → `tham số lạ: --harness-only`, **rc=1** |
| Layout dot `.harness/` + `.llmwiki/` cho dự án downstream | `install.sh:94-96` (`[ -d "$ROOT/fdk/wiki" ] \|\| { OVERSTACK_DIR=".llmwiki"; HARNESS_DIR=".harness"; }`) + cài thật, `find` ra `.harness/poc-vendor-neutral` |
| Hook Claude sinh ra trỏ `harness/` không dấu chấm | `gen-converters.py:25` (`CLI = "harness/poc-vendor-neutral/bin/llmwiki-validate.py"`) và `:49` (`EVT`); hàm `merge_claude_hooks` trong `install.sh` copy snippet nguyên văn, không rewrite đường dẫn |
| pre-commit cũng trỏ sai | `install.sh:153` — heredoc hardcode `entry: python3 harness/poc-vendor-neutral/…` |
| Hook im lặng KHÔNG chặn | Chạy thật đúng chuỗi lệnh trong `.claude/settings.json` với payload `Write llmwiki/raw/hack.md` → **rc=0**; cùng payload qua `.harness/…` → **rc=2** kèm `[R1 no-write-raw]` |
| pre-commit gãy TO (không im lặng) | Chạy thật entry của `.pre-commit-config.yaml` → `can't open file … harness/poc-vendor-neutral/…` **rc=2** |
| Hook global bị stamp-guard chặn | `~/.claude/settings.json` sinh ra 8 hook, tất cả gác `[ -f "${CLAUDE_PROJECT_DIR:-.}/llmwiki/.harness-stamp" ]`; installer ghi stamp ở `.llmwiki/.harness-stamp` → guard sai |
| Deny-glob global cũng trượt | `~/.claude/settings.json` → `permissions.deny = ["Edit(./llmwiki/raw/**)", …]`, không phủ `.llmwiki/raw/**` |
| Tái hiện trên bản cài THẬT, không chỉ sandbox | `/Users/giatran/orca/workspaces/hoh-autonomous/isonade`: `.harness/` có lõi, `harness/` không; stamp ở `.llmwiki/`; cả 6 hook project + 8 hook global đều trỏ đường không dấu chấm |
| CI vẫn sống | `.github/workflows/harness.yml` sinh ra tự clone framework rồi gọi `$HOME/.claude/harness/harness/poc-vendor-neutral/bin/llmwiki-validate.py` — đường global, đúng |
| 19 luật R1–R19 + `enforce_at` từng luật | Parse `harness/poc-vendor-neutral/policy.yaml` bằng `yaml.safe_load` — đếm từ đĩa, không đếm bảng trong README |
| Mã thoát validator 0/1/2 | `bin/llmwiki-validate.py:280,283,286,294` (`block_code`) + chạy thật cả 6 trường hợp (bad/good/path/mode lạ/không tham số/file thiếu) |
| Validator vẫn chấm đúng file trong `.llmwiki/` | Chạy thật trên `.llmwiki/wiki/concepts/bad.md` → bắt R2 + R9; glob `**/wiki/concepts/**` phủ cả layout dot — **lỗi nằm ở dây, không nằm ở luật** |
| Self-test 13 + 80 assertion | Chạy thật `test-broad.sh` → **80 PASS**. Nhãn `(68)` trong log cài và `broad 54 = 67` ở tên job CI đều là chuỗi cứng đã trôi — PR #114 sửa cả hai thành 13 + 80 = 93 |
| `install-harness.sh` rc 0/3/4 | `install-harness.sh:718` (`exit 3` — còn nợ), `:741` (`exit 4` — smoke fail), `:463` (`exit 0` global) |
| Global install chạy smoke thật | Log cài: `GLOBAL smoke OK: no_write_raw chặn đúng (rc=2)` (`install-harness.sh:461`) |
| 21 step của `fdk-gate` + exit 2 | Parse AST `harness/scripts/fdk-gate.py` → `len(STEPS) == 21`; mã thoát tại `:136,146,148` |
| `medic` chấm repo FRAMEWORK, không chấm dự án bạn | `fdk/tools/medic.py` — dòng `ROOT = Path(__file__).resolve().parents[2]` |
| `health-check.py` đòi `.template-manifest.json` | `health-check.py:159-178` + chạy thật trên dự án sạch → **rc=1**, `manifest không tồn tại` |
| 87 skill / 19 rule / 23 fdk-tool / 68 harness-script | `fdk/CAPABILITIES.md` dòng 3 (sinh bằng code) + `ls skills \| wc -l` = 87 |
| R14/R16/R19 chết dưới layout dot | Nạp `glob_to_regex` của chính validator rồi khớp thử: `**/llmwiki/patterns/**` **TRƯỢT** `.llmwiki/patterns/p.md` nhưng **KHỚP** `llmwiki/patterns/p.md`; `**/raw/**` và `**/wiki/concepts/**/*.md` vẫn khớp bình thường |
| Bản vá policy ở `02` mục 5 cứu R14 ở **hook per-project**; hook **global** (validator `patterns_guard.py`) còn hở, vá ở PR #115 | Chạy thật: trước vá `Write .llmwiki/patterns/p.md` → rc=0; sau vá + `gen-converters.py` → **rc=2** kèm `[R14 patterns-protected]`, YAML vẫn parse đủ 19 rule |
| `check_deny_write_bash` bỏ qua glob của luật | `bin/llmwiki-validate.py:89-93` — chỉ kiểm `"raw/" in cmd`. Chạy thật: bash ghi `raw/` bị báo **hai** dòng (R1 + R14); bash ghi `llmwiki/patterns/p.md` → **rc=0**, không chặn |
| HEAD của `orca` không qua chính `fdk-gate` của nó | Chạy thật trên clone sạch: `✗ THIẾU 5/21 step`, **rc=2**. Đỏ: `L4 wiki-health` (broken wikilink từ `entities/repowise.md`, quét 175 trang) · `overstack-docs current` · `task-lifecycle` · `bnal self-test wired` · `graph-engineering tests` (chỉ `ge-reachability-test.sh` đỏ, 6/7 còn lại PASS). `git status` sau khi chạy vẫn sạch → gate read-only |
| 18 probe của `medic` | Chạy thật `python3 fdk/tools/medic.py --list` → 18 dòng, rc=0 |
| CI của overstack **không** được bê nguyên vào `04` | `.github/workflows/harness.yml` của repo tự-cài framework, chạy fire-drill + self-test *của chính framework* — `04` viết mới, tối giản, cho người tiêu thụ |
**Chưa kiểm chứng, đã ghi rõ tại chỗ:** đường `--with-skills` (cần `npx` + mạng, và nó ghi đè `~/.claude/skills` global nên không chạy trong sandbox này); mọi lệnh `/<skill>` ở `03` (chỉ chạy trong phiên agent, không có mã thoát để đo); `05` phần `install-harness.sh --self-heal` (đọc mã + mã thoát, chưa chạy trên một dự án có nợ wiki thật); `06` phần `/fdk-uat` canary (cần quyền push nhánh lên remote).
SKILL.md
---
name: doyourmagic
proof: skills/doyourmagic/references/example-setup/workflows.md
description: "Given a freshly-cloned external repo/tool, run clone→explore→verify→write to produce a bundle of RUNNABLE workflow skills under doyourmagic/<repo>/skills/ — one hub skill /dym-<repo> (1 dòng context, chỉ nạp workflow con khi được gọi) + N sub-skills dạng SKILL.md promote thẳng lên repo chính (npx skills add) — plus workflows.md (index + bảng kiểm chứng) and flow.html (docs-site-macos, sơ đồ luồng skill→sản phẩm→skill kế). Trigger on 'kéo repo mới về', 'clone tool này làm workflow', 'doyourmagic', 'onboard external tool/repo', 'generate workflow docs/skills for this repo', or /doyourmagic. Options: --name <prefix> · --humanize."
---
# Skill: doyourmagic
## When to use
- User just cloned/installed an external repo/CLI/tool and wants "how do I actually use this thing" as something **gõ được**, not a README to re-read each time.
- User says "kéo repo mới về", "doyourmagic <repo>", "làm workflow cho tool này", "generate workflow docs for this repo", "viết hộ cách dùng runnable cho repo này".
- Before folding an external tool into project conventions/CI — produce the bundle first so the integration decision is grounded in verified commands, not README paraphrase.
## Output shape (what a finished run leaves behind)
```
doyourmagic/<repo>/
workflows.md # chỉ mục + thứ tự chạy + bảng "kiểm chứng thế nào" (thứ không thuộc về một skill nào)
flow.html # docs-site-macos: sidebar · mind map · SƠ ĐỒ LUỒNG skill→sản phẩm→skill kế · toggle sáng/tối
skills/
<hub>/SKILL.md # /<hub> <slug> — 1 dòng description, disable-model-invocation, đọc ĐÚNG file con được gọi
<hub>-<slug-1>/SKILL.md # mỗi workflow = một skill đầy đủ (frontmatter + When/Steps/Rules), tự chứa, promote được
<hub>-<slug-2>/SKILL.md
```
- **Hub** là thứ duy nhất được symlink vào `.claude/skills/` → context chỉ tốn **một** dòng description; thân workflow con chỉ được đọc khi user gõ `/<hub> <slug>`. Đây là "hub 1-tên, mô tả phạm vi" của `/fdk`, không phải N skill rải trong context.
- Sub-skill là **SKILL.md thật** (không phải doc): copy nguyên thư mục sang `skills/` của repo chính là thành skill cài bằng `npx skills add`.
- Không còn `NN-*.md`: nội dung runnable nằm trong Steps của sub-skill — một nguồn, không có bản doc song song để drift.
## Naming — 3 chế độ, ghi chế độ đã dùng vào `workflows.md`
| Chế độ | Hub | Sub-skill | Khi nào |
|---|---|---|---|
| **mặc định** | `dym-<repo>` | `dym-<repo>-<slug>` | user không nói gì. Không bao giờ trùng, nhìn tên biết nguồn; đổi tên lúc promote |
| `--name <prefix>` | `<prefix>` | `<prefix>-<slug>` | user tự đặt |
| `--humanize` | agent đặt tên ngắn gõ được bằng cơ bắp (vd `overstack`) | `<hub>-<slug>` | phải `ls ~/.claude/skills .claude/skills` kiểm trùng TRƯỚC khi chốt; trùng → rơi về mặc định và nói rõ |
`<repo>` = tên repo (segment cuối của URL, bỏ `.git`), chữ thường, `-` thay ký tự lạ. `<slug>` = 1–2 từ nói việc (`install`, `ci`, `contributor`), không đánh số.
## Steps
1. **Clone vào sandbox** (scratch dir) — không khám phá tại chỗ trong cây dự án của user. Exploration là **read-only** với clone.
2. **Manifest trước, prose sau**: tìm `package.json` / `pyproject.toml` / `Cargo.toml` / `go.mod` / installer script TRƯỚC khi đọc README — nó cho lệnh cài thật, entry point/bin, danh sách script.
3. **README/AGENTS.md/docs là giả thuyết**, không phải sự thật. Mỗi lệnh định viết ra phải đối chiếu với argument parser / `--help` chạy thật / literal `process.exit(...)` `sys.exit(...)` — đọc mã thoát thật, đừng giả định 0/1.
4. **Chạy thật những gì chạy được** trong sandbox với scope pin chặt (`HOME` cô lập, `--scope=project`, `--no-verify`…): installer, validator trên input bẩn/sạch, mode lạ, file thiếu. Ghi rc từng ca — bảng kiểm chứng của `workflows.md` lấy từ đây.
5. **Nếu máy đã có một bản tích hợp thật** (config đã commit ở dự án khác) → đọc nó; nó thắng fixture trong clone về "dùng đúng ngoài đời trông thế nào". Tái hiện lỗi trên bản thật là bằng chứng mạnh nhất.
6. **Chia workflow theo ĐỐI TƯỢNG, không theo tính năng**: tiêu thụ (dùng tool trong dự án của mình) vs đóng góp (sửa chính tool). Lệnh chat (`/x`) và lệnh shell tách skill riêng — trộn là copy-paste gãy.
7. **Chốt tên** theo bảng Naming (kiểm trùng nếu `--humanize`).
8. **Viết mỗi workflow thành một sub-skill** `doyourmagic/<repo>/skills/<hub>-<slug>/SKILL.md`:
- frontmatter `name: <hub>-<slug>`, `description` = một câu nói KHI NÀO gọi + từ khoá trigger, và **`disable-model-invocation: true`** — để khi cài cả bundle qua `npx skills add` (7 skill) cũng không có dòng description nào tự nhồi vào context; chỉ nạp khi gõ.
- `## When to use` — tình huống + "tại sao chạy / sinh ra gì".
- `## Steps` — lệnh copy-paste được, đường dẫn chính xác, output/mã thoát kỳ vọng. Lệnh nào đã chạy thật thì ghi rc đo được.
- `## Rules` — bẫy đã ĐO (không phải đoán), kèm cách né; carve-out "không được làm".
- Self-contained: không trỏ tới file chỉ có trong clone; cần thì "nếu file X có mặt thì…".
9. **Viết hub** `doyourmagic/<repo>/skills/<hub>/SKILL.md`:
```
---
name: <hub>
disable-model-invocation: true
description: "<một dòng: tool gì · gõ /<hub> <slug> · slugs: a · b · c>"
---
## Steps
1. Đọc ARGUMENTS → <slug>. Không có slug → in bảng slug + một dòng mục đích, dừng.
2. Tìm file con theo thứ tự, lấy file ĐẦU TIÊN tồn tại rồi đọc ĐÚNG MỘT file:
(1) `.claude/skills/<hub>-<slug>/SKILL.md` — đã cài qua `npx skills add rheinmir/dym`;
(2) `doyourmagic/<repo>/skills/<hub>-<slug>/SKILL.md` — bundle nằm trong dự án, hub symlink;
(3) `doyourmagic-bundles/<repo>/skills/<hub>-<slug>/SKILL.md` — clone `rheinmir/dym` cạnh dự án.
Làm theo Steps/Rules của file đó; không đọc file con khác; không thấy cả 3 → nói rõ, dừng.
```
10. **`workflows.md`**: bảng (skill · mục đích · nhánh · lệnh gọi), "thứ tự chạy đề xuất", "bẫy đắt nhất", bảng **"kiểm chứng thế nào"** (khẳng định → file:dòng / ca chạy thật / rc), chế độ đặt tên đã dùng, và **lệnh symlink 1 dòng** (mục Install bên dưới).
11. **`flow.html`** — sinh theo skill `docs-site-macos` (BẮT BUỘC: sidebar kính, background orbs, mind map collapsible, nút gạt sáng/tối ở footer sidebar + chống FOUC, cỡ chữ compact 13″, skip-link/focus ring, footer hiện **đường dẫn tuyệt đối** của chính file). Nội dung = **luồng chính xác các skill thực hiện**: mỗi skill một node, cạnh `skill → sản phẩm → skill kế` (connector do JS vẽ từ `getBoundingClientRect`, vẽ lại khi resize — không hardcode toạ độ), thứ tự chạy theo nhánh, mỗi node ghi lệnh gọi + sản phẩm + bẫy 1 dòng. Thuật ngữ có giải nghĩa trong ngoặc. **Mở thật bằng trình duyệt** (hoặc `/playwright-verify`) trước khi giao — đọc code không đủ.
12. **Gate adapt-modes** — bundle không phải đích đến. Đưa MỘT verdict cho user: **HÒA TAN** (rewrite thành code/skill của ta) · **KÉO NGOÀI** (pointer + pin) · **NHÚNG-SỞ-HỮU** (vendor) · **KHÔNG LẤY** (đã có gì phủ, ghi path). So trên trục quyết định chi phí — số lượt agent/lần dùng, code sinh được không cần LLM — không so byte. Verdict HÒA TAN/NHÚNG → hỏi trước khi scaffold.
## Kho bundle đã chạy — `rheinmir/dym`
Mỗi lượt chạy xong, đẩy `doyourmagic/<repo>/` lên https://github.com/Rheinmir/dym thành `<repo>/` (PR) để người sau **kéo về thay vì chạy lại**: `npx skills add rheinmir/dym` (cài hub + sub-skill, project-scope; thêm `-g` cho global) hoặc `git clone --depth 1 https://github.com/Rheinmir/dym.git doyourmagic-bundles`. Trước khi chạy `/doyourmagic <repo>` mới: **xem ở đó đã có bundle chưa**.
## Install (dùng tại chỗ) — một lệnh, chỉ nạp khi cần
```bash
mkdir -p .claude/skills && ln -sfn ../../doyourmagic/<repo>/skills/<hub> .claude/skills/<hub>
```
Chỉ hub vào context. Gõ `/<hub>` để xem bảng slug, `/<hub> <slug>` để chạy một workflow. Muốn gọi thẳng `/<hub>-<slug>` thì symlink thêm đúng thư mục đó — mỗi symlink thêm là thêm một dòng context, cân nhắc.
## Promote lên repo chính (skill cài bằng npx)
Đường `/fdk` có sẵn, không đẻ tool:
```bash
bash <(curl -fsSL https://raw.githubusercontent.com/Rheinmir/setup/orca/fdk/tools/fdk-kit.sh) pull # lần đầu
cp -R doyourmagic/<repo>/skills/<hub>-<slug> .overstack-kit/skills/<tên-mới> # đổi tên nếu bỏ tiền tố dym-
cd .overstack-kit && python3 fdk/tools/new-skill.py <tên-mới> --dry-run # in checklist register
# register: LOOP_MAP (sync-skills.py) · LOOP_GROUPS · marketplace.json · bảng AGENT.md+CLAUDE.md · provenance
bash fdk/tools/fdk-kit.sh check && bash fdk/tools/fdk-kit.sh submit skill/<tên-mới> "<mô tả>"
```
Sửa `name:` trong frontmatter cho khớp tên mới; giữ `description` trigger. Hub KHÔNG promote (nó chỉ có nghĩa cạnh bundle).
## Rules
- Không paraphrase README thành "runnable" — mỗi lệnh phải có trong manifest scripts / `--help` thật / argument parser.
- Không giả định mã thoát 0/1 — đọc literal exit; tool có thể dùng 2 = "có finding" hay fail-open 0 khi thiếu file, người gọi phải rẽ nhánh đúng.
- Không bê `.github/workflows/*.yml` của tool vào skill CI cho người tiêu thụ — viết ví dụ tối giản riêng.
- Lệnh chat và lệnh shell không chung một skill.
- **Không chạy installer của tool mà không pin scope** (đo 2026-09-04: `npx impeccable install --help` cài thật vào `$HOME` 13 thư mục). Sandbox + `HOME` cô lập + cờ scope tường minh.
- Read-only với clone; chỉ ghi vào `doyourmagic/<repo>/`.
- Mỗi sub-skill tự chứa; hub chỉ đọc đúng file được gọi — không nhồi cả bundle vào context.
- `flow.html` tự chứa (không CDN, không path tuyệt đối cục bộ), đọc được cả sáng/tối, mở qua `file://`.
- Ưu tiên bằng chứng chạy thật hơn trích dẫn; cái gì chưa chạy được thì ghi "chưa kiểm chứng" ngay tại chỗ.
## Reference example
`references/example-setup/` — một lượt chạy thật của skill này trên `rheinmir/setup` (overstack: bootstrap + 19 luật + 87 skill): hub `dym-setup` + 6 sub-skill (file con lưu dạng `<tên>.skill.md` để không bị loader quét nhầm thành skill), `workflows.md` với bảng kiểm chứng 30 dòng, `flow.html`. Lượt đó tìm ra 5 lỗi thật (đã vá ở PR #114–#117) — đó là mức "kiểm chứng" cần khớp.