@akinet/akidevrule 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +835 -0
  2. package/LICENSE +21 -0
  3. package/README.md +356 -0
  4. package/claude/CLAUDE.md +40 -0
  5. package/claude/agents/aki-challenger.md +38 -0
  6. package/claude/agents/aki-conduct.md +54 -0
  7. package/claude/agents/aki-hands.md +59 -0
  8. package/claude/agents/aki-judge.md +37 -0
  9. package/claude/agents/aki-maker.md +36 -0
  10. package/claude/fragments/settings.akidoc.fragment.json +15 -0
  11. package/claude/hooks/aki-update-check.mjs +160 -0
  12. package/claude/hooks/aki_version_check.mjs +83 -0
  13. package/docs/ref/macos-codesign-tcc.md +59 -0
  14. package/install.mjs +1067 -0
  15. package/install.ps1 +11 -0
  16. package/install.sh +12 -0
  17. package/package.json +52 -0
  18. package/payload/GEMINI.md +147 -0
  19. package/payload/METHOD-audit-flow.md +147 -0
  20. package/payload/METHOD-audit-subtraction.md +67 -0
  21. package/payload/METHOD-audit-zero-trust.md +49 -0
  22. package/payload/METHOD-deep-think.md +172 -0
  23. package/payload/METHOD-proportionality.md +62 -0
  24. package/payload/METHOD-ux-psych.md +60 -0
  25. package/payload/RULE-agent-behavior.md +138 -0
  26. package/payload/RULE-biz.md +51 -0
  27. package/payload/RULE-coding.md +130 -0
  28. package/payload/RULE-content-write.md +54 -0
  29. package/payload/RULE-db-design.md +26 -0
  30. package/payload/RULE-docs.md +144 -0
  31. package/payload/RULE-pattern-core.md +80 -0
  32. package/payload/RULE-release.md +215 -0
  33. package/payload/RULE-seo.md +173 -0
  34. package/payload/RULE-stack-akiNuxtCf.md +179 -0
  35. package/payload/RULE-stack-tauri.md +59 -0
  36. package/payload/RULE-ui-pattern.md +167 -0
  37. package/payload/index.md +91 -0
  38. package/skills/aki-article-writer/SKILL.md +50 -0
  39. package/skills/aki-article-writer/references/article-workflow.md +377 -0
  40. package/skills/akidevsync-notes/SKILL.md +48 -0
  41. package/skills/akidevsync-notes/scripts/notes_cli.py +212 -0
  42. package/skills/akiflow/SKILL.md +221 -0
  43. package/skills/akiflow/references/harness-facts.md +215 -0
  44. package/skills/akiflow/scripts/council-cost.sh +4 -0
  45. package/skills/akiflow/scripts/council-open.sh +4 -0
  46. package/skills/akiflow/scripts/council-read.sh +4 -0
  47. package/skills/akiflow/scripts/council-verify.sh +4 -0
  48. package/skills/akiflow/scripts/council_cost.py +149 -0
  49. package/skills/akiflow/scripts/council_open.py +323 -0
  50. package/skills/akiflow/scripts/council_read.py +148 -0
  51. package/skills/akiflow/scripts/council_verify.py +315 -0
  52. package/skills/akiflow/scripts/scythe.py +307 -0
  53. package/skills/akiflow/scripts/scythe.sh +4 -0
  54. package/skills/akigitcommit/SKILL.md +85 -0
  55. package/skills/akihelp/SKILL.md +47 -0
  56. package/skills/akihtmlreport/SKILL.md +59 -0
  57. package/skills/akilint/SKILL.md +29 -0
  58. package/skills/akirule/SKILL.md +155 -0
  59. package/skills/akiship/SKILL.md +55 -0
  60. package/skills/akithink/SKILL.md +59 -0
@@ -0,0 +1,59 @@
1
+ # Tauri v2 + Rust Stack Rule
2
+
3
+ <!-- Address map: tauri.A1-2 · tauri.B1-7 -->
4
+
5
+ ## Scope — when this applies
6
+ Every Aki desktop project built on Tauri v2 + Rust (backend commands) + any JS frontend framework. Generic lessons only — project-specific facts (titlebar height, bundle naming, etc.) stay in that project's own `CLAUDE.md`.
7
+
8
+ ## A. Never block the UI
9
+
10
+ ### A1. Never block the UI (ABSOLUTE — zero exceptions, no case-by-case judgment calls)
11
+
12
+ This bug class recurs constantly across Aki's Tauri projects because it is easy to miss in review: a `#[tauri::command]` that runs a **blocking subprocess wait** (`Command::output()`, `.wait()`, `.wait_with_output()`, an SSH round-trip, a poll-and-sleep loop) or a **blocking network call** directly on the thread that dispatches the IPC call. Tauri does not put a plain `fn` command on a separate thread for you — a slow subprocess or a dead network directly freezes window repaint and all input for however long that call takes, with zero partial-progress feedback to the user. Two concrete real-world instances: an app's statusline-customizer auto-install froze the whole window on modal-open because its host-check ran a blocking SSH probe synchronously; a `check_for_updates` command ran a blocking `curl` call on every single app launch with no timeout.
13
+
14
+ **The rule, no exceptions:** any `#[tauri::command]` whose body runs a subprocess or a blocking network call **must** be `async fn`, and the blocking call **must** be wrapped in `tauri::async_runtime::spawn_blocking(move || { … }).await.map_err(|e| format!("spawn_blocking panicked: {}", e))?`. Never call the blocking function directly inside the `async fn` body "just this once because it's quick" — network and remote-host calls have no fast-path guarantee; a bad connection is exactly the case that must not freeze the app.
15
+
16
+ **Before adding or reviewing any `#[tauri::command]`**, ask: does this call a subprocess, SSH, or the network? If yes, `spawn_blocking` goes in from the first draft, not as a follow-up fix. Audit with `grep -n "#\[tauri::command\]" -A2 src-tauri/src/*.rs` before closing out any Tauri-touching task, and check every new/changed command against this rule.
17
+
18
+ Plain, fast, synchronous local file I/O (reading a small JSON/config file, a single `Path::exists()` check) is **not** this bug class and does not need `spawn_blocking` — the line is "does this call wait on a subprocess or the network," not "is this technically a syscall."
19
+
20
+ ### A2. Subprocess PATH-resolution race at cold start (ABSOLUTE — apply to every spawned CLI binary)
21
+
22
+ Any Rust code that spawns a shell to invoke a user-installed CLI (`Command::new("sh"/"zsh"/"bash")`, or over `ssh host sh`) and relies on `zsh -lc`/`bash -lc` login-shell PATH resolution to find that binary is racing the user's shell rc/profile (nvm, path_helper, zinit, etc.) — which may not have finished sourcing yet if the subprocess is spawned right at/near app cold-start. Symptom: intermittent `exit=127 command not found: <bin>` that self-heals within minutes and is NOT reproducible when testing the identical command manually a bit later — easy to misdiagnose as a CLI-version or auth problem instead of a timing race.
23
+
24
+ **Fix pattern**: resolve the binary via static, well-known install-directory candidates FIRST (a `[ -x "$path" ]` file-existence test has zero dependency on rc-sourcing timing), falling back to `command -v` / login-shell PATH lookup only if none match — do this in ONE shared preamble injected at the single funnel where scripts are dispatched, not patched ad hoc at each call site. Seed the candidate path list for the platform(s) the app actually ships for first (e.g. macOS-only apps: `~/.local/bin`, `~/.claude/local`, `/opt/homebrew/bin`, `/usr/local/bin` for Claude Code specifically) — extend the list only when a new platform build actually ships, rather than guessing paths for platforms not yet supported.
25
+
26
+ ## B. Boundary & config
27
+
28
+ ### B1. Titlebar sacred boundary
29
+ `"decorations": false` + `"transparent": true` → no native titlebar. All `position: fixed/absolute` elements **must** start at `top: var(--titlebar-h)` (or the app's titlebar height), never `top: 0`. Window controls (drag/minimize/close) via JS `@tauri-apps/api/window`.
30
+
31
+ ### B2. IPC capability silent fail
32
+ Every Tauri command AND window API call must be granted in `src-tauri/capabilities/default.json`. Missing → **silent no-op**, no error, no log. Window needs: `core:window:allow-minimize`, `core:window:allow-close`, `core:window:allow-start-dragging`.
33
+
34
+ ### B3. Serde fields + old JSON
35
+ New fields on structs deserialized from persisted JSON need `#[serde(default)]` or old records silently drop the field instead of erroring.
36
+
37
+ ### B4. `#[cfg(target_os = "macos")]` scoping
38
+ Declare variables **inside** the cfg block. Declared outside but used only inside → unused-variable warning on non-macOS builds.
39
+
40
+ ### B5. Version SSOT
41
+ `package.json` only. `tauri.conf.json` → `"version": "../package.json"`. Never hardcode version in `tauri.conf.json`. `Cargo.toml` has its own crate version (separate concern) and **must always be bumped to the same number in the same commit** — a mismatch between `package.json` and `Cargo.toml` is the same class of bug as a bad tag. See [[RULE-release]] § Version string format for the absolute no-`v`-prefix rule that governs both fields and every git tag.
42
+
43
+ ### B6. Salient target context up front in the project CLAUDE.md
44
+ State the few decision-shaping target facts the agent must grasp without inferring — first of them the platform(s) the app actually ships to (drives shortcut glyphs ⌘ vs Ctrl, path shapes, packaging, the A2 candidate list). Surface the load-bearing few, not an inventory; when a platform-specific string is needed and the target is undeclared, ask — don't guess.
45
+
46
+ ### B7. macOS: a sidecar that works in Terminal can be denied inside the shipped `.app`
47
+
48
+ Symptom first: `git`/`rsync`/`ssh`/a CLI agent runner spawned by the backend (`std::process::Command`, `tauri-plugin-shell`, a PTY) fails only inside the bundled app — silent `EPERM`, or a consent dialog naming *your app* for a folder the user never associated with it. Cause: TCC — Transparency, Consent and Control, the macOS subsystem behind every "X would like to access your Documents" dialog — judges a child process by the **responsible process** at the head of the chain, inherited across `fork`/`posix_spawn`. For a shipped Tauri app that is the `.app` bundle, never the user's Terminal — so the child inherits your bundle's permission state, not the terminal's freedom, and every grant is charged to your bundle identity.
49
+
50
+ Three switches, routinely confused — pick by what each actually controls:
51
+ - **Full Disk Access** (`kTCCServiceSystemPolicyAllFiles`) — the top of the decision chain and a superset, not a peer: if the responsible app holds it, protected locations are readable with no per-folder prompt. Request it only when the app's reach is genuinely unbounded (backup, indexing); for a project-scoped tool it is far more privilege than the task needs.
52
+ - **Files & Folders** (`kTCCServiceSystemPolicyDocumentsFolder`, `…DesktopFolder`, `…DownloadsFolder`, plus separate removable/network-volume entries) — the least-privilege path, consulted only when the responsible app has no FDA; with no entry, first access prompts. A refusal is **sticky**: one "Don't Allow" persists as a denial with no re-prompt, so the user's reflexive dismissal looks like a bug in your app forever. Recovery is `tccutil reset` or **removing** the app's entry — flipping the existing toggle back on restores access but not prompting, so it does not reproduce a first-run.
53
+ - **Developer Tools** (`kTCCServiceDeveloperTool`) — **not file access.** It exempts the app from the system security policy when it *runs* software (unsigned/ad-hoc sidecars, local toolchains), i.e. Gatekeeper for what you spawn. It silences no file-consent dialog; reaching for it to stop folder prompts is the standard misdiagnosis and wastes a debugging session.
54
+
55
+ - **Scope every spawn.** Bind subprocesses, sidecars and filesystem probes to an explicit target (`cwd`, the project workspace, the app data dir). An unbounded walk from `$HOME` or `/` hits protected domains and turns into a prompt storm or a silent-`EPERM` storm — and per the sticky rule above, the damage outlives the run.
56
+ - **Ad-hoc signing loses the grant on every rebuild.** `codesign --sign -` (Xcode's "Sign to Run Locally") produces a new signature each build, and the authorization is tied to that exact build — so a permission granted yesterday is simply gone today, which reads as a random TCC bug. The fix is a **stable self-signed certificate**, which keeps grants across rebuilds; `tccutil reset All <bundle-id>` only clears the stale state, it does not prevent the next loss.
57
+ - **Scope limit — this chain governs consent-based reads.** It does not apply to paths the user picked in an Open/Save dialog or by drag-and-drop (user intent grants access directly), and Apple's own analysis excludes file *writes* from it. A write-only or file-picker-driven sidecar failing is a different diagnosis; don't reach for these switches first.
58
+
59
+ When you cannot tell which switch fired, watch it rather than guess: `log show --predicate 'subsystem == "com.apple.TCC"' --last 5m` prints the `AttributionChain` (which process was held responsible) and the request's result. Claims and sources: `docs/research/macos-tcc-tauri-boundary-aug21.md` in the akidevrule repo. Full lookup (switches + rebuild/DR mechanism): `~/.aki/akidevrule/docs/ref/macos-codesign-tcc.md`.
@@ -0,0 +1,167 @@
1
+ # UI Pattern — Frontend Enforcement (Nuxt / Vue / Tailwind)
2
+
3
+ <!-- Address map: ui.A1-4 · ui.B1-5 · ui.C1-5 -->
4
+
5
+ **Tier: Contextual.** Load on any UI authoring/refactor signal, or on an audit signal (see the Audit section). This file is the **UI-specific enforcement** of the universal laws in `RULE-pattern-core.md` — it does not redefine them. Nuxt/Cloudflare stack mechanics (rendering, i18n, layout chrome, deploy) live in `RULE-stack-akiNuxtCf.md`; this file owns the design-system layer: tokens, class taxonomy, variant API, and UI audit.
6
+
7
+ ## Map to RULE-pattern-core (which universal law each rule enforces)
8
+
9
+ - **SSoT (Law 1)** → design tokens are the single source for every visual value.
10
+ - **Evidence-based abstraction (Law 2)** → Rule of Three before a pattern class or base component.
11
+ - **Composition over duplication (Law 5)** → slots / dynamic components / `v-for`, never hand-copied markup.
12
+ - **OCP (Law 4)** → extend a component via props / variant / slot, never fork a copy.
13
+ - **Name by role (Law 7)** → semantic tokens and variants, never value-names.
14
+ - **Reshape, don't stack (Law 8)** → before packaging a repeated style, try to remove it. The tier ladder only *packages* repetition; Law 8 is the only thing that *eliminates* it, and without it a codebase obeys every rule here while growing without bound.
15
+ - **Documentation** → every global pattern is looked up before writing and recorded after, so the next agent reuses instead of rewriting.
16
+
17
+ ---
18
+
19
+ ## A. Taxonomy & tokens
20
+
21
+ ### A1. Four-tier class taxonomy
22
+
23
+ Every style belongs to exactly one tier — there is no fifth tier.
24
+
25
+ | Tier | Name | Definition | Lives in | Example |
26
+ |---|---|---|---|---|
27
+ | 0 | Design Token | Atomic value of the visual system | one source per project — `@theme` (Tailwind v4) or `tailwind.config` (v3), see A2 | `--color-primary`, `theme.spacing` |
28
+ | 1 | Utility | Single-property atomic class, used inline | Tailwind core | `flex`, `gap-4`, `text-sm` |
29
+ | 2 | Pattern class | Repeated utilities behind one semantic name, defined **once** — `@apply` or plain CSS, both valid | the shared stylesheet in `assets/css/*`, never an SFC `<style>` | `.c-card`, `.c-btn` |
30
+ | 3 | Variant (modifier) | Variation of a pattern — prefer a Vue prop + computed class-map; BEM modifier only where Vue can't control markup | SFC `computed()` or `.c-btn--sm` | `variant="primary"` |
31
+ | 4 | Component | Markup + variant logic packaged as a reusable SFC | `components/base/*.vue` | `<BaseButton variant="danger" />` |
32
+
33
+ **Before any tier — the subtraction pass (Law 8).** Every rung above adds something; none removes anything. Run these three first, and only what survives gets a tier:
34
+ 1. **Delete** — does the element need this style at all, or is it restating a browser or framework default?
35
+ 2. **Inherit** — is the property inheritable (color, font, size, leading, tracking, alignment)? Set it once on the nearest container and delete it from every child. A typography class repeated across siblings is almost always this case.
36
+ 3. **Hoist** — if siblings share a non-inheritable style, does it belong on the parent as a layout rule (`space-y-*`, `divide-*`, a grid/flex gap) rather than on each child?
37
+
38
+ Rules between tiers:
39
+ - Tier 1 is the default first reach for any styling need that survives the subtraction pass.
40
+ - **The second copy is the STOP; the third is only the extraction threshold.** Rule of Three (Law 2) counts ≥3 occurrences *repo-wide* — a count no editing session can observe, since one open file cannot see the other ninety. Waiting for a trigger nothing can fire is why a codebase reaches thousands of duplicates with an empty pattern layer. The observable trigger is the one in front of you (`pattern.A5`): the moment you are about to write a class string you already wrote once, stop and decide the shared shape. "Leave both inline" is a legitimate outcome — but it must be a decision, not a default. When the decision needs the real count, scan for it (`C1`); never estimate it.
41
+ - Tier 3 in Vue is **always prop-driven** (a computed class-map). Loose CSS modifiers are only for markup Vue does not render — Markdown/CMS output, static email templates.
42
+ - Tier 4 is the destination: once a pattern has variants, package it as a base component so callers never hand-assemble class strings.
43
+
44
+ **Mandatory order:** subtraction → Utility → Pattern class → Component variant → hand-written CSS.
45
+
46
+ **Inline `style=` is not a fifth tier — it is a single escape hatch for a value computed at runtime** (`:style="{ width: pct + '%' }"`). A static inline style is always a violation: no scan in `C1` sees it, it cannot carry a token, and it cannot be overridden without `!important`. Convert it; never add one.
47
+
48
+ **A `<style>` block must earn its place, and "last resort" is a quantity claim.** No single file reveals whether the mandatory order holds — inversion is only visible in aggregate, so it must be measured in aggregate (`C1`): when the CSS inside SFC `<style>` blocks outweighs the project's shared stylesheet, the order above has been inverted in practice no matter how reasonable each file looks alone. Legitimate residents of a `<style>` block: keyframes, selectors the framework cannot express (`:has()`, `::-webkit-scrollbar`, print rules, complex sibling logic), third-party overrides, and styling for markup the project does not author (CMS/Markdown output). Everything else belongs to a token, a utility, or a component.
49
+
50
+ ### A2. Design tokens = the single visual source (Law 1)
51
+
52
+ - Every visual value — color, spacing, radius, shadow, font, breakpoint, z-index, easing, duration — exists **once**, in whichever mechanism the installed framework version actually uses: a `@theme` block for Tailwind v4 (CSS-first), `tailwind.config` for v3, plain CSS custom properties otherwise. Read the project's own setup before writing a token — a rule that names the wrong file teaches the reader that the rule is decorative. Never rewrite a hex / px / ms value anywhere else.
53
+ - **The token layer is itself subject to SSoT: one theme source per project.** Several `@theme` blocks, or custom properties declared ad hoc across dozens of files, reintroduce exactly the drift tokens exist to prevent — a second definition wins by load order, which nothing in the source makes visible.
54
+ - Name tokens by **role**, not by hue/value: `primary`, `surface`, `danger`, `on-surface` — never `bg-blue-500` sprinkled across code. Rebrand = edit one place, not hundreds.
55
+ - Reuse the scientific scales required by `RULE-stack-akiNuxtCf.md`: z-index via `--z-index` variables, radius via `radius-sm | md | lg | xl | pill`.
56
+
57
+ ### A3. Arbitrary-value policy (Law 1 + Law 7)
58
+
59
+ `w-[123px]`, `text-[#3b82f6]`, `top-[13px]` are forbidden unless **all three** hold: (a) no existing token in the scale fits, (b) the value provably appears exactly once system-wide, (c) an inline comment explains why it is a one-off. A value likely to repeat → add a token first, use the token second.
60
+
61
+ ### A4. Framework-native scale first (Law 1 + Law 7)
62
+
63
+ Before adding **any** custom token — font-size, spacing, radius, shadow, whatever the framework already ships a scale for — check the framework's own default scale first. A custom token is only justified for the part of the range the framework genuinely does not cover.
64
+
65
+ - **Order of preference:** framework default utility (`text-sm`, `text-base`, `rounded-lg`, …) > project token that extends the framework's scale for a gap it doesn't cover > one-off arbitrary value (§A3).
66
+ - Never invent a parallel scale that duplicates what the framework already provides "for consistency" — that is the opposite of consistency; it is a second source of truth (Law 1 violation) and the exact drift this rule exists to prevent.
67
+ - When cleaning up scattered ad-hoc values (see §C), snap each value to the **nearest existing step** (framework or already-established project token) by midpoint, not the raw value — a cluster of `0.78rem / 0.8rem / 0.82rem` is drift around one intended size, not three intended sizes. Do not mint a new token per raw value found in the wild; that fossilizes noise instead of correcting it.
68
+ - Prefer **fewer, framework-aligned steps** over a deep bespoke scale. If a redesign of the scale is on the table, count how many genuine semantic roles exist (not how many raw values exist) — they are almost always far fewer than the raw-value count suggests.
69
+ - This is a stack-wide UI hygiene issue, not a one-page fix: when the same drift pattern (e.g. a near-continuous spread of hardcoded font-sizes) shows up on more than one page/component, treat it as a systemic gap in the token set, not N independent one-off violations — fix the pattern once at the token layer, then sweep every call site.
70
+
71
+ ## B. Component structure
72
+
73
+ ### B1. Atomic component structure (Law 3 + Law 6)
74
+
75
+ ```
76
+ components/
77
+ base/ # Atom — pure presentation, no fetch, no business logic
78
+ composite/ # Molecule — ≥2 base components into one meaningful unit
79
+ sections/ # Organism — page blocks; may use composables for data
80
+ layout/ # Layout singletons (app.vue / layouts/)
81
+ composables/ # All data + business logic lives here — never duplicated in components
82
+ ```
83
+
84
+ - Data and side effects live in composables (the boundary — see `RULE-stack-akiNuxtCf.md` External integrations), never duplicated across components.
85
+ - For the fixed layout roles (footer, top nav, sidebar, breadcrumb, admin sidebar…), reuse the **canonical component names** defined in `RULE-stack-akiNuxtCf.md`. Do not invent new names for those roles.
86
+
87
+ ### B2. Variant API (CVA-style) (Law 4)
88
+
89
+ A base component exposes a **finite enum** of variants/sizes; a `computed` class-map resolves `prop → classes`. A new visual need is a **new entry in the same map**, never a forked `BaseButtonRed.vue`. Props / slots / emits are a stable contract — extend it, do not mutate it for one caller.
90
+
91
+ ### B3. Composition, not hand-copied markup (Law 5)
92
+
93
+ Never duplicate a markup + logic block across components "for speed." Use slots, dynamic components (`<component :is>`), a composable, or `v-for` over data instead of writing N near-identical templates by hand.
94
+
95
+ ### B4. Documentation duty (Law 1 for knowledge)
96
+
97
+ The duty runs **both ways, and the lookup half comes first**: grep the project's shared stylesheet and token source for the concept before defining any named style, and record a new **global** pattern class or variant in the project's pattern library the moment it is created. An undocumented pattern does not exist — the next agent rewrites it and the duplication returns.
98
+
99
+ Recording alone does not prevent this. A write-only duty produces a documented pattern that the next session never reads, then redefines locally in an SFC `<style>` block; the shared name now has two live definitions, and the one that wins depends on load order rather than on anything visible at either site. That is strictly worse than raw duplication, because the shared name promises a consistency it no longer delivers. One name, one definition, one file — checked by lookup, not by memory.
100
+
101
+ ### B5. Hover proximity — no dead gap on the pointer path (Law 8)
102
+
103
+ Invariant: a `:hover`-shown popup/menu/tooltip stays open while the pointer travels trigger → content. Root fix first: eliminate the gap — nest the popup in the trigger's hover scope (parent `:hover` / `group-hover`) and create visual spacing with inner `padding`, never external `margin`. Only when the popup must escape the flow (portal/teleport, `overflow` clipping): transparent `::before`/`::after` bridge over the gap, or a short close-grace delay (~300ms). Closing mid-travel is a bug, not a styling choice.
104
+
105
+ ---
106
+
107
+ ## C. Audit playbook — cleaning existing code
108
+
109
+ **Triggers for this section:** `dọn dẹp`, `class trùng`, `duplicate class/CSS`, `trùng lặp`, `audit CSS`, `refactor CSS/UI`, `arbitrary value`, `quét class`. Pair with `METHOD-audit-flow.md` for the flow-level mindset; this section is the concrete UI grep layer. Run the steps in order — do not skip.
110
+
111
+ ### C1. Inventory by scan (quantify before refactoring by feel)
112
+
113
+ **Run the inversion check first — it decides whether anything else here is worth doing** (§A1, mandatory order). Compare the shared stylesheet against the CSS scattered through SFC `<style>` blocks; scattered outweighing shared means the tier order is inverted project-wide, which is a token/component-layer problem no amount of per-file tidying reaches:
114
+ ```bash
115
+ find . -path ./node_modules -prune -o -name '*.css' -print | xargs cat | wc -l # shared layer
116
+ find . -path ./node_modules -prune -o -name '*.vue' -print | xargs awk '/<style/{f=1} f{n++} /<\/style>/{f=0} END{print n+0}' | awk '{s+=$1} END{print s+0}' # scattered layer
117
+ ```
118
+ One name, several definitions (§B4 — the failure that is worse than duplication):
119
+ ```bash
120
+ grep -rhoE '^\.[a-zA-Z][a-zA-Z0-9_-]*[ ]*\{' --include="*.css" --include="*.vue" . | tr -d ' {' | sort | uniq -c | awk '$1>=2' | sort -rn
121
+ ```
122
+ Duplicate long class strings (pattern-class candidates — Law 2):
123
+ ```bash
124
+ grep -rhoE 'class="[^"]{20,}"' --include="*.vue" . | sort | uniq -c | sort -rn | awk '$1>=3'
125
+ ```
126
+ Un-tokenized arbitrary values (Law 1 + Law 7 / §A3):
127
+ ```bash
128
+ grep -rnoE 'class="[^"]*\[[^]]+\][^"]*"' --include="*.vue" .
129
+ ```
130
+ Hardcoded hex/rgb outside the token source (Law 1 / §A2):
131
+ ```bash
132
+ grep -rnoE '#[0-9a-fA-F]{3,6}\b|rgb\([^)]+\)' --include="*.vue" --include="*.css" --include="*.ts" . | grep -viE 'tokens|theme|tailwind\.config'
133
+ ```
134
+ Hand-written `px`/`ms` in `<style>`, and static inline `style=` — same treatment.
135
+
136
+ **Two blind spots these commands have; state them in the report rather than letting a clean number imply a clean codebase.** Only literal `class="…"` is matched, so every `:class`/`v-bind:class` binding is invisible and the duplicate counts are floors, not totals. And the presence of a pattern layer must never be inferred from an `@apply` grep — a project may express Tier 2 as ordinary CSS rules (entirely valid, and the norm under Tailwind v4), so absence of `@apply` says nothing about whether Tier 2 exists.
137
+
138
+ ### C2. Classify severity
139
+
140
+ SSoT breach (hardcoded value that should be a token) **>** duplicated business/logic **>** duplicated presentation style. Fix in that order of danger.
141
+
142
+ ### C3. Priority matrix (impact × effort)
143
+
144
+ Plot each finding on impact × effort. Do high-impact / low-effort first. Do not start a large refactor by feel before this matrix exists.
145
+
146
+ ### C4. Safe refactor loop
147
+
148
+ One pattern at a time: extract the token / pattern class / variant → replace every call site → verify build + type + visual → commit. Follow `RULE-release.md` for CHANGELOG/version; never push unasked (`RULE-agent-behavior.md`).
149
+
150
+ ### C5. Compliance scorecard
151
+
152
+ Score the codebase against `RULE-pattern-core.md` Definition of Done and the four-tier taxonomy: any tier-0 breach (hardcoded value), any un-evidenced abstraction, any forked component, any value-named token is a fail to record.
153
+
154
+ **Report template**
155
+
156
+ ```
157
+ UI Pattern Audit — <project> — <date>
158
+ 1. Inventory counts: dup class strings / arbitrary values / hardcoded colors / hand px-ms
159
+ 2. Top violations by severity (SSoT > logic > style)
160
+ 3. Priority matrix: quick wins vs large refactors
161
+ 4. Recommended extractions (token / pattern class / base component) with call-site counts
162
+ 5. Score against Definition of Done
163
+ ```
164
+
165
+ ## One-line reminder
166
+
167
+ Diversity of UI comes from a controlled variant system, not from ad-hoc class strings — one source per value, one pattern per repeated problem.
@@ -0,0 +1,91 @@
1
+ # Aki-RULE
2
+
3
+ Shared source-of-truth rules for Aki projects.
4
+
5
+ ## Purpose
6
+ Provides reusable rules for agent behavior, coding, content, docs, and stack-specific work. Project `CLAUDE.md` files bind these shared rules to a specific project.
7
+
8
+ ## File manifest
9
+
10
+ | File | Topic | Tier | Type | Purpose |
11
+ |------|-------|------|------|---------|
12
+ | `RULE-agent-behavior.md` | `agent` | Core — `@` import in `~/.claude/CLAUDE.md` | public | Core: full text already in context every turn — read it directly, not this summary |
13
+ | `RULE-coding.md` | `coding` | Core — `@` import in `~/.claude/CLAUDE.md` | public | Core: full text already in context every turn — read it directly, not this summary |
14
+ | `RULE-pattern-core.md` | `pattern` | Core — `@` import in `~/.claude/CLAUDE.md` | public | Core: full text already in context every turn — read it directly, not this summary |
15
+ | `RULE-docs.md` | `docs` | Contextual | public | Docs structure (incl. mandatory `docs/biz/` backbone), `updated <date> <version>` anchor stamp on every `arch|biz|feat` doc, plan lifecycle, research doc schema (event record: start time/purpose/strategy/checklist/result+verification/decision+cross-refs; frozen body, dated `## Amendments` for errata, successor doc only when the Decision changes), doc-sync behavior, drift audit (when it runs vs the two situations it does not, research+plan doc pair, comparison checklist, wrong/stale/incomplete/cosmetic severity) |
16
+ | `RULE-content-write.md` | `content` | Contextual | public | UI copy, semantic stability, writing style (density enforced by deletion test), i18n, content audit (`content.C2` — canonical-term drift, density deletion test, i18n coverage, severity-classified per `docs.C4`) |
17
+ | `RULE-stack-akiNuxtCf.md` | `stack` | Contextual | **mixed** — group C is ⟨Aki⟩ | Nuxt/Vue/Cloudflare Pages/Workers, Tailwind, i18n, canonical component names, state (useState-first), build & TypeScript, admin layout isolation, dev workflow scripts (killport/D1), layout chrome (breadcrumb/scroll-to-top), layout width (single source of truth in the layout, pages/apps never redeclare max-w), deploy verification after push |
18
+ | `RULE-stack-tauri.md` | `tauri` | Contextual | public | Tauri v2 + Rust: absolute never-block-the-UI rule for any command running a subprocess/network call (`spawn_blocking`), titlebar boundary, version SSOT, IPC capability silent-fail, serde default for persisted JSON, cfg(target_os) scoping, subprocess PATH-resolution cold-start race, salient target context (ship platform) surfaced in the project CLAUDE.md, macOS TCC/Gatekeeper boundary for spawned sidecars (responsible-process attribution, FDA vs Files & Folders vs Developer Tools, sticky denials, ad-hoc signing losing grants on every rebuild, and the read-only scope limit of the whole chain) |
19
+ | `RULE-ui-pattern.md` | `ui` | Contextual | public | Frontend enforcement of pattern-core: subtraction pass before any tier (delete/inherit/hoist — the ladder packages repetition, only this removes it), 4-tier class taxonomy with the second copy as the STOP (the ≥3 threshold is repo-wide and unobservable inside one file), inline `style=` as a runtime-only escape hatch, `<style>`-block budget measured in aggregate against the shared layer, design tokens in whichever mechanism the installed framework version uses with one theme source per project, arbitrary-value policy, atomic structure, variant API, two-way lookup-then-record pattern duty, UI audit/refactor playbook led by the inversion check |
20
+ | `RULE-seo.md` | `seo` | Contextual | **mixed** — group C is ⟨Aki⟩ | Meta limits, schema.org matrix, robots, sitemap, OG, AI visibility, entity linking |
21
+ | `RULE-release.md` | `release` | Contextual | **mixed** — group C is ⟨Aki⟩ | CHANGELOG.md mandatory in every project, release notes vs changelog split, GitHub Release compare-link footer, releases.json (web-only), release vs deploy boundary, cold-start version reconstruction, severity-driven bump, version minted only at the release event (`[Unreleased]` buffer, no local drift ahead of production), audit mode, pre-ship gate expanded into the full-release checklist (B7: leftover triage, diff-scoped hygiene — scythe/dead-code/comment-refs on the accumulation only, never repo-wide), autonomous-run contract (B8: only an explicit `/akiship` invocation is the authorization — activation owned by that skill's literal-token gate, this rule is never itself a trigger; asks front-loaded into one batch, three-case escalation floor and completion-intensity phrase list owned solely by B8 (the `/akiship` skill references, never restates them), redundant questions forbidden; entry point `/akiship`), registry-published packages (B9: the registry version is the release, publish mechanism derived from existing convention and sibling packages, account/scope/2FA probed, OTP publish as the single hand-off, tarball verified before the irreversible publish) |
22
+ | `RULE-db-design.md` | `db` | Contextual | public | Immutability & Event Sourcing, 1NF, Bounded Context (DDD), flat-query discipline — load when designing schema/migration/DB refactor |
23
+ | `RULE-biz.md` | `biz` | Contextual | public | Positioning & audience (one primary audience, falsifiable USP, `docs/biz/` as SSoT, niche-first), offer & pricing (value-based, few tiers, validate before building), messaging & customer psychology (benefit-first, anxiety at decision points, no dark patterns) — load on any market-facing decision |
24
+ | `METHOD-audit-flow.md` | `flow` | Analytical | public | Flow integrity audit method |
25
+ | `METHOD-deep-think.md` | `think` | Analytical | public | Deep-think brain: goal excavation, first principles, critique, conditional techbiz lens; passive via akirule, active via /akithink |
26
+ | `METHOD-ux-psych.md` | `ux` | Analytical | public | UX psychology audit: cognitive-load/recognition/feedback/defaults/motor-cost/mental-model lenses, persona walkthrough protocol (first-run, friction ledger, failure paths, state completeness), severity-weighted output routed through the design system |
27
+ | `METHOD-audit-zero-trust.md` | `zero-trust` | Analytical | public | Strict mechanical-first audit: scope locked by command (project-wide or change-plus-callers), detectors run before any opinion, findings split into CERTAIN (exact machine match — a verdict) vs SUGGESTED (pattern/naming — a candidate judgment must settle), signature propagation across the locked scope, short findings-only report. Read-only like every audit |
28
+ | `METHOD-proportionality.md` | `proportion` | Analytical | public | Sizing a defense against its real threat: four measures before any verdict (reach against the `docs/biz/` audience, capability ladder, motive, blast radius by recoverability), every number labeled measured or estimated; asymmetry law (irreversibility outranks frequency), the `coding.C4`/`biz.C3` floor that is never sizeable, the cheapest-sufficient-control ladder (impossible by shape → one trust boundary → detect → accept-and-record) with client-side limits classified as UX and never enforcement; verdict record carries a reopen trigger. Seated in akiflow as `risk-sizing` |
29
+ | `METHOD-audit-subtraction.md` | `subtract` | Analytical | public | Repo-wide "does this need to exist" sweep: inherits zero-trust's scope-lock, detector-first order, CERTAIN/SUGGESTED classes and signature propagation, changes only the question. Loop-until-dry termination (two empty rounds) because no detector returns "minimal", nine domain passes each delegating detectors to the rule that owns them, subtraction severity classes including the mandatory *load-bearing but ugly* class, Chesterton's Fence as the brake before any CERTAIN removal. Read-only; bulk sweeps route to workers, judgment does not |
30
+
31
+ Four files load mechanically, not by routing: this `index.md`, `RULE-agent-behavior.md`, `RULE-coding.md` and `RULE-pattern-core.md` are `@`-imported by `~/.claude/CLAUDE.md`, which the harness reads at session start. Routing for every other file is defined in `~/.claude/skills/akirule/SKILL.md` and takes effect only when the model invokes that skill.
32
+
33
+ The two rule files were promoted out of Tier 1 because "default ON" was a description of intent, not a mechanism: a router that runs only when the model chooses to invoke it cannot guarantee anything, and the rules the owner had to re-state most often (`coding.B4` comment budget, `pattern.A2` Rule of Three, `pattern.A8` fix-at-the-root) turned out to be missing from the context rather than present and ignored. A rule that must hold unconditionally belongs in an `@` import; anything left to the router is best-effort by construction. The cost — both files in every session, including sessions that touch no code — is the price of that guarantee and was accepted knowingly.
34
+
35
+ ## Addressing scheme — `topic.A1`
36
+
37
+ Every file is internally organized into groups **A/B/C** (a topic's broad themes) and numbered items **1/2/3…** within each group — e.g. `coding.B2` (Changing existing code), `stack.C1` (Canonical component names). `topic` is the manifest's Topic column above — usually the filename with its `RULE-`/`METHOD-` prefix dropped; the audit methods keep their short topics (`flow`, `zero-trust`, `subtract`). This is purely a recall/reference convention — it does not change routing (still governed by `akirule/SKILL.md`) and does not rename any file.
38
+
39
+ **`⟨Aki⟩`** marks a group (always the last group in its file) that is specific to Aki's own AkiNuxtCf ecosystem rather than universal — currently `seo.C`, `release.C`, `stack.C`. These groups stay in this public repo (auto-load is more useful to Aki, the heaviest user, than a clean public/ private split), but are logically separable if a stripped public export is ever needed. Everything outside a `⟨Aki⟩` group is universal and applies to any project on the matching stack.
40
+
41
+ | Topic | Groups |
42
+ |---|---|
43
+ | `agent` | §0 Penalty cards · A Communication · B Scope & decision discipline · C Files & memory |
44
+ | `coding` | A Philosophy & source of truth · B Quality, changing code & who verifies · C Runtime safety |
45
+ | `pattern` | A The 8 laws · B Decomposition & the forest pass · C Closure |
46
+ | `db` | A Data principles · B Unicode |
47
+ | `docs` | A Index & Structure · B Lifecycle & Sync · C Drift audit |
48
+ | `content` | A Content principles · B Style & patterns · C Separation |
49
+ | `seo` | A Meta & structure · B AI visibility & entity · **C ⟨Aki⟩ API & tooling stack** |
50
+ | `release` | A Versioning core · B Identify & audit · **C ⟨Aki⟩ Web release artifacts** |
51
+ | `stack` | A Cloudflare & TypeScript foundation · B Render · i18n · Vue patterns · **C ⟨Aki⟩ Ecosystem conventions** |
52
+ | `tauri` | A Never block the UI · B Boundary & config |
53
+ | `ui` | A Taxonomy & tokens · B Component structure · C Audit playbook |
54
+ | `think` | A Decision framework · B 5 Modules · C Radar |
55
+ | `flow` | A Flow thinking · B 8 first-principles questions · C Closure & output |
56
+ | `biz` | A Positioning & audience · B Offer & pricing · C Messaging & customer psychology |
57
+ | `ux` | A Lenses · B Walkthrough protocol · C Output & decision |
58
+ | `zero-trust` | A Scope-lock · B Mechanical pass first · C Evidence classes · D Signature propagation · E Adversarial self-challenge · F Report |
59
+ | `proportion` | A Dimensioning · B Verdict · C Output & reuse |
60
+ | `subtract` | A Scope & terminating condition · B The passes · C Output · D Runner |
61
+
62
+ Full item-level breakdown: `docs/research/public-private-abc-restructure.md`.
63
+
64
+ ## Cross-cutting lens
65
+
66
+ Some subjects legitimately live in several files: one **root rule** stating the principle, plus **domain applications** that must stay inside their domain (moving them would strip the context where they are actually read). This section is an **address map only — never rule text** — so it stays a pointer, not a duplicate.
67
+
68
+ | Subject | Root | Domain applications |
69
+ |---|---|---|
70
+ | **Naming** | `pattern.A7` — name by role, never by concrete value | `agent.C1` file names · `ui.A` design tokens · `stack.C1` ⟨Aki⟩ canonical component names · `release.A3` version/tag format · `content.A3` semantic stability (renaming an existing concept) |
71
+ | **External-action completeness** ("done" needs the outside world to move, not just the file) | `coding.B3` — a change requiring a separate action against an external system isn't done when the file describing it is written | `release.B5` ⟨Aki⟩ CHANGELOG/release entry not truthful until a migration/infra step actually ran · `stack.C8` ⟨Aki⟩ D1 migration must run `--remote` and move to `scripts/done/`, a green build alone proves nothing about the database |
72
+ | **Audit reports, never fixes** (and the output depends on whether the baseline is stable) | `agent.B5` — an audit writes only its report; never mutates git state, never auto-classifies ambiguous work | `docs.C` docs-vs-reality, research+plan doc pair on a published baseline · `content.C2` canonical-term drift, density deletion test, i18n coverage sweeps · `release.B7` pre-ship pass/fail gate, no doc · `ui.C` class/token audit playbook · `flow` flow and state drift · `zero-trust` mechanical-first strict sweep, evidence weighted by the mechanism that produced it · `subtract` repo-wide does-this-need-to-exist sweep, terminating on two dry rounds |
73
+ | **Sizing a control against its real threat** (severity is impact **and** who can actually reach it) | `proportion.A` — reach, capability, motive, blast radius, each labeled measured or estimated, before any guard is added, kept, or removed | `coding.C1` no defensive guards for impossible internal states · `coding.C4` the security floor this sizing never argues below · `pattern.A2` risk-weighted extraction at the 2nd occurrence for auth/money/permissions · `think.A1` one-way vs two-way door depth · `think.B5` when an edge-case is promoted above the MVP · `ux.C1` findings ranked by severity, never padded flat |
74
+ | **Density — the deletion test** (a line exists only if deleting it loses information the reader needs) | `agent.A4` — report density: conclusion-first, no padding, no trimming of load-bearing detail | `coding.B4` code comments (naming first; comment only what code cannot say) · `docs.B3` doc prose · `content.B2` product copy · akiflow Step 4 output-hygiene floor (the enforcement tier for subagents, which inherit no router) · mechanical detection: `skills/akiflow/scripts/scythe.py` (`[WRAP]`/`[YAP]` only — `[FLUFF]` stays judgment, `agent` §0) |
75
+ | **Subtraction before abstraction** (packaging repetition is second-best; not needing it is first) | `think.B4` — what can be deleted, skipped, merged, delayed, or made manual | `pattern.B3` first bullet of the critique gate · `ui.A1` delete/inherit/hoist pass ahead of the tier ladder · `subtract` the repo-wide audit form of the same question, read-only and detector-driven · akiflow's `aki-challenger`, which closes every solution-shaped item on "what can be cut?" |
76
+ | **Interrupting the owner** (a question must survive the kill-tests before it costs a read and an answer) | `agent.A3` — impact, already-authorized, silence≠contradiction, with reversibility as the fourth | `coding.B3` one human hand-off ledger per run, deduped by flow · `coding.B5` the six-rung ladder a check must fail before it may be handed to the owner at all, and the one-line reason each survivor carries · `release.B8` a question the repo already answers is a violation · akiflow Step 4 seat-raised `CONFLICT` filtered through the lead's kill-test pass |
77
+
78
+ Add a lens row only when a subject has actually caused a miss — `pattern.A2` (Rule of Three) applies to this rule corpus too, and so did a real production incident where a migration script shipped in CHANGELOG but was never executed against remote D1 (2026-07-23).
79
+
80
+ ## Precedence
81
+ When rules conflict, use this order:
82
+ 1. Current local source code, runtime output, and build output
83
+ 2. User's explicit instruction in the current conversation
84
+ 3. User's standing instructions — `~/.claude/CLAUDE.md` and the machine-local `~/.claude/CLAUDE.local.md`. An item marked ABSOLUTE there is never weakened by anything below it, including a shared rule that grants an autonomy other projects rely on; ordinary guidance there yields to a more specific project rule.
85
+ 4. Project `CLAUDE.md`
86
+ 5. Aki-RULE shared files
87
+ 6. Older docs, memory, or prior conversation context
88
+
89
+ Project `CLAUDE.md` may add project facts and stricter constraints. It must not silently weaken core safety, verification, or source-of-truth rules.
90
+
91
+ Corpus-maintenance material (project binding, change policy) lives in the source repo's `README.md` — repo path recorded in `~/.aki/akidevrule/.source-repo`.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: aki-article-writer
3
+ description: >-
4
+ Per-project article writing skill: research & fact-verification, SEO metadata,
5
+ JSON-LD schema generation, UX-psychology-aware content, and a separate Image Scout
6
+ subagent (Gemini Flash / Haiku) for image search, download, visual inspection,
7
+ slug-named processing, and WebP output. Activate when the user asks to write a
8
+ new article, create content, draft a blog post, or produce a knowledge entry for
9
+ any project.
10
+ ---
11
+
12
+ # aki-article-writer
13
+
14
+ Invoke with `/aki-article-writer` or by natural language: *"write an article about X"*, *"viết bài về X"*.
15
+
16
+ This skill delegates one full article to a dedicated **Article Worker subagent**. The worker spawns a separate **Image Scout subagent** (lightweight model) for all image work, keeping both agents' contexts clean and independent.
17
+
18
+ Read the full procedure before starting:
19
+
20
+ - **[references/article-workflow.md](references/article-workflow.md)** — the six-phase pipeline:
21
+ Phase 1 Research & Fact-Verification →
22
+ Phase 2 Metadata & JSON-LD Schema →
23
+ Phase 3 Content & UX Psychology →
24
+ Phase 4 Image Scout Pipeline →
25
+ Phase 5 Image Embed →
26
+ Phase 6 Self-Audit & Delivery
27
+
28
+ ## Per-project configuration
29
+
30
+ Before spawning the Article Worker, read the project's own `CLAUDE.md` (or `docs/ref/article-schema.md` if present) to extract:
31
+
32
+ | Field | Where to find it | Fallback |
33
+ |---|---|---|
34
+ | `tone` | `CLAUDE.md` project context | conservative and informative |
35
+ | `lang` | `CLAUDE.md` or site locale config | `vi` |
36
+ | `schema_type` | `CLAUDE.md` or `docs/ref/seo.md` | `BlogPosting` |
37
+ | `image_dir` | `CLAUDE.md` or `nuxt.config` public path | `public/images/articles/` |
38
+ | `image_format` | `CLAUDE.md` | `webp` |
39
+ | `article_arch` | Inspect how existing articles are actually stored and rendered — `.md`/`.mdx` files under `content/`/`docs/` → `markdown`; structured records in `.ts`/`.js`/`.vue` (e.g. a `posts.ts` data file rendered by a shared Vue/React component) → `component` | detect from repo; never assume |
40
+
41
+ Pass these as the Article Worker brief alongside the topic and slug. `article_arch` gates Phase 4/5 image behavior — see workflow doc.
42
+
43
+ ## Subagent model assignment
44
+
45
+ | Agent | Recommended model | Reason |
46
+ |---|---|---|
47
+ | Article Worker | Sonnet / Flash (default session model) | Holds full content context throughout |
48
+ | Image Scout | **Gemini Flash / Claude Haiku** | Mechanical: search → download → inspect → process. Cheap model; blank context is no handicap |
49
+
50
+ Never use the same subagent for both content writing and image processing — the image pipeline is iterative and token-heavy; keeping it separate prevents context flooding in the Article Worker.