Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .claude/skills/aspid-wiki/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: aspid-wiki
description: Build, update, query, and lint the Aspid.MVVM knowledge wiki — a navigable Obsidian vault of concept/entity/binder/flow/risk pages under docs/wiki/ that lets agents and developers orient in the codebase without reading hundreds of source files. Use this skill whenever the user asks to "build/update/ingest the wiki", "обнови вики", "построй вики по проекту", "document the codebase", "sync the wiki with the code", "lint the wiki", "answer from the wiki", or "export the wiki", or when you are about to read many source files to answer an architecture/orientation question and a wiki page would answer it more cheaply. Also use after a significant code change to keep the wiki in sync via the git-diff checkpoint.
---

# Aspid.MVVM Knowledge Wiki

A persistent, compounding knowledge base for the Aspid.MVVM framework. The committed **code at git `HEAD` is the source of truth**; the wiki is a separate, human- and agent-readable layer that explains architecture, concepts, flows, conventions, and accumulated decisions — *not* a copy of the code.

**Why it exists:** re-establishing project context from raw source costs 5,000–15,000 tokens per session before any real work begins. A structured wiki, navigated by index + summary pages, replaces that with a few cheap page reads. Read the wiki first; fall back to source only when a page is missing or marked `stale`.

- **Vault location:** `docs/wiki/` at the repo root — deliberately **outside** `Assets/` so Unity does not generate `.meta` files for notes and `.obsidian/` churn does not pollute the asset tree.
- **Format:** Markdown + YAML frontmatter + Obsidian `[[wikilinks]]`. Opened directly as an Obsidian vault (graph view, Dataview). Separate from the public GitBook docs.
- **Entry point:** `docs/wiki/index.md` — the navigation hub answering 8 orientation questions. Always start here.
- **Languages:** `docs/wiki/` is **English and the single source of truth** — the only vault ingested from code. Translations live in sibling vaults `docs/wiki-<lang>/` (e.g. `docs/wiki-ru/`) that mirror the English tree 1:1 and are generated **from the English wiki, never from code**. See `references/translations.md`.

## Operations

This skill exposes four operations. Pick the one matching the request.

### 1. Ingest — build or update the wiki from source

Keeps the wiki in sync with the code, cheaply, by only processing what changed.

1. Read `docs/wiki/index.md` frontmatter. If `last_commit` is missing/empty → **first run** (build everything). Otherwise → **incremental run**.
2. Determine the changed set (see `references/sync.md` for exact commands — it covers the **submodule-aware** checkpoint, which plain git-wiki does not handle):
- First run: candidate set from `git ls-files` at `HEAD`, excluding `docs/wiki/**` and filtering `*.meta`.
- Incremental: `git diff --name-status -M <last_commit> HEAD` for the superproject **plus** a per-submodule diff against `submodule_commits` (the generators/analyzers live in separate git repos; the superproject diff only shows pointer bumps).
3. Map changed files → wiki pages via each page's `source_paths` frontmatter. Update or create only affected pages.
4. **Generated-code awareness (Aspid-specific):** `[ViewModel]`, `[Bind]`, `[RelayCommand]` emit the *other half* of each partial class at build time. Pages must describe the **generated** members and the relationships they create, not only the hand-written partial. A reader looking only at source files will not see them — the wiki is where that knowledge lives.
5. Advance the checkpoint: write the new superproject `HEAD` to `last_commit` and each submodule `HEAD` to `submodule_commits`, only **after** the full changed set is processed. Append an entry to `docs/wiki/log.md`.
6. Respect granularity: per-concept for the core, **per-category (not per-file)** for the ~593 StarterKit binders — see `references/taxonomy.md`.

For a full first-run ingest across the whole taxonomy, prefer a **Workflow** that fans out one agent per page (each reads its `source_paths` and writes per `references/page-templates.md`), then a Lint pass. Do not hand-write 50+ pages serially.

### 2. Query — answer a question from the wiki

1. Read `docs/wiki/index.md`, follow `[[wikilinks]]` to the relevant pages.
2. Answer from the wiki. **Verify against `source_paths`** before stating anything load-bearing — pages can drift or contain inferences.
3. If the answer required reading source the wiki should have covered, file it back: create/extend a page so the next query is cheaper (the artifact compounds).

### 3. Lint — detect drift and gaps

Report (do not auto-fix): pages whose `source_paths` no longer exist or changed significantly (mark `status: stale`, never delete), broken `[[wikilinks]]`, orphan pages (no inbound links), and changed modules with no covering page. Suggest dedicated pages for concepts referenced across ≥3 pages but lacking their own. See `references/sync.md`.

### 4. Export — bundle for sharing / GitBook / LLM feed

Concatenate all pages into one deterministic markdown file (sorted by path, TOC, per-file start/end markers), flattening `[[wikilinks]]` to plain text. The live vault stays Obsidian-native; the bundle is the portable artifact. (Bundling script lives under `scripts/` once added; until then, produce the bundle inline.)

## Conventions (read the references before writing pages)

- **`references/taxonomy.md`** — folder layout, page granularity (per-concept vs per-category), slug/naming rules.
- **`references/page-templates.md`** — frontmatter schema per page type, page templates, writing style (target a "smart newcomer", explain *why* before *what*, keep pages under ~500 words, separate facts from inferences).
- **`references/sync.md`** — the submodule-aware git-diff checkpoint mechanism, first-run vs incremental, stale handling.

## Hard rules

- Never put the vault inside `Assets/`. Always filter `*.meta` from any file scan.
- Page filenames are **human-readable** and unique across the vault (the filename is the Obsidian node label): code types mirror the identifier (`IViewModel.md`, `BindMode.md`), other pages use Title Case (`ViewModel Generation.md`). System files stay lowercase (`index.md`, `log.md`). Full rules in `references/taxonomy.md`.
- `Aspid.Collections` is an external UPM package (`tech.aspid.collections`), not in this repo — document it as an external dependency with a link out, never as an in-repo module.
- Generator DLLs are committed into `Assets/`; Unity consumes the DLL, not the submodule source. Capture this in the relevant `generation/` and `risks/` pages.
70 changes: 70 additions & 0 deletions .claude/skills/aspid-wiki/references/page-templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Page templates & writing style

## Frontmatter

### Hub — `docs/wiki/index.md`

```yaml
---
title: Aspid.MVVM Wiki
type: index
status: active
last_commit: "" # superproject HEAD at last ingest; empty = never ingested (first run)
submodule_commits:
generators: "" # Aspid.MVVM.Generators HEAD
unity_generators: "" # Aspid.MVVM.Unity.Generators HEAD
analyzers: "" # Aspid.MVVM.Analyzers HEAD
updated_at: 2026-05-31
---
```

### Content page

```yaml
---
title: ViewModel Generation
type: concept # overview | concept | entity | binder-category | converter | flow | generation | risk | reference | note
status: active # draft | active | stale
source_paths: # repo-relative paths this page is derived from; drives incremental sync
- Aspid.MVVM/Assets/Aspid/MVVM/Source/ViewModels/Generation/ViewModelAttribute.cs
- Aspid.MVVM.Generators/.../ViewModelGenerator.cs
tags: [generation, viewmodel]
updated_at: 2026-05-31
---
```

`source_paths` may point into the main `Assets/` tree **or** into a submodule (`Aspid.MVVM.Generators/...`). It is the link back to code and the key the Ingest step uses to decide which pages a changed file affects.

## Page body template

```markdown
# <Title>

> One-sentence answer to "what is this and why do I care?"

## Why it exists
<The problem it solves / the decision behind it. Rationale ages slower than code — lead with it.>

## How it works
<The mechanism, at the altitude a smart newcomer needs. Name the generated members where source generation is involved.>

## Key relationships
- Implements / used by [[IViewModel]], drives [[Binders Catalog]] via [[BindMode]] …

## Gotchas
<Only if real. Link to the relevant [[risks]] page.>

## Source
<source_paths rendered as a short list, so a human can jump to code.>
```

Adapt sections to the page type — a `binder-category` page lists the family and variants; a `flow` page is an ordered walkthrough; a `risk` page is symptom → cause → fix.

## Writing style

- **Audience: a smart newcomer.** Explain *why a thing matters* before naming details.
- **Keep pages under ~500 words.** Prefer useful coverage over exhaustive documentation; link out rather than inline everything.
- **Separate facts from inferences.** State verified behavior plainly; mark anything inferred ("appears to…", "likely…") so it can be checked.
- **Document generated code.** For `[ViewModel]`/`[Bind]`/`[RelayCommand]`, describe the members the generator emits — they are invisible in the hand-written source but are the point of the framework.
- **Link liberally** with `[[wikilinks]]`. A dense link graph is what makes the vault navigable (and the Obsidian graph view useful).
- **Language:** match the codebase — content in English (Readme/XML docs/GitBook are English). Configurable per the language-variant convention if needed.
56 changes: 56 additions & 0 deletions .claude/skills/aspid-wiki/references/sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Submodule-aware sync (the checkpoint mechanism)

Git is the maintenance engine. The wiki tracks the last ingested commit(s) so each update only processes what changed — cost stays bounded as the project grows. Aspid.MVVM has **three git submodules** (the generators/analyzers), so the plain single-`last_commit` git-wiki scheme is extended with per-submodule checkpoints.

## Checkpoint state

Stored in `docs/wiki/index.md` frontmatter:
- `last_commit` — superproject `HEAD` at last ingest.
- `submodule_commits.{generators,unity_generators,analyzers}` — each submodule's `HEAD` at last ingest.

Missing or empty `last_commit` ⇒ no checkpoint ⇒ treat as **first run**.

## First run

Build the candidate file set and ingest the full taxonomy:

```bash
# superproject tracked files, minus the vault, minus Unity meta noise
git ls-files | grep -v '^docs/wiki/' | grep -v '\.meta$'
# each submodule's tracked files
git -C Aspid.MVVM.Generators ls-files | grep -v '\.meta$'
git -C Aspid.MVVM.Unity.Generators ls-files | grep -v '\.meta$'
git -C Aspid.MVVM.Analyzers ls-files | grep -v '\.meta$'
```

## Incremental run

Diff each repo independently against its checkpoint. The superproject diff shows submodule **pointer bumps**, not the source changes inside them — so the submodules must be diffed in their own repos.

```bash
# superproject (main Assets tree)
git diff --name-status -M <last_commit> HEAD -- . ':(exclude)docs/wiki/**' | grep -v '\.meta$'
# submodules — diff inside each one
git -C Aspid.MVVM.Generators diff --name-status -M <generators_sha> HEAD
git -C Aspid.MVVM.Unity.Generators diff --name-status -M <unity_generators_sha> HEAD
git -C Aspid.MVVM.Analyzers diff --name-status -M <analyzers_sha> HEAD
```

`-M` enables rename tracking. Map each changed path to the pages whose `source_paths` reference it; update/create only those. A changed generator file affects `generation/` pages **and** any `concepts/`/`flows/` page describing the code it emits — follow the link graph.

## Stale handling

- Source file deleted or heavily changed and not yet reflected ⇒ set the page's `status: stale` and note the drift. **Never auto-delete** a page.
- Committed generator DLLs (`*.dll` under `Assets/`) changing without a corresponding submodule source change is a signal the DLL was rebuilt — verify the `generation/` pages still match.

## After ingest

Advance the checkpoint (superproject + all three submodules) in `index.md`, set `updated_at`, and append a `docs/wiki/log.md` entry: date, commit range(s), pages touched.

## Lint checks

- Broken `[[wikilinks]]` (target file absent).
- Orphan pages (no inbound links).
- `source_paths` pointing at non-existent files.
- Changed modules (from the diff) with no covering page.
- Concepts mentioned across ≥3 pages with no dedicated page → suggest one.
33 changes: 33 additions & 0 deletions .claude/skills/aspid-wiki/references/taxonomy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Wiki taxonomy & granularity

The vault root is `docs/wiki/`. Top-level folders are fixed; pages go in the folder matching their type.

## Folders

| Folder | Holds | Granularity |
|---|---|---|
| `overview/` | What Aspid.MVVM is, architecture, getting started | A handful of orientation pages |
| `concepts/` | Framework concepts: viewmodel generation, data binding, bindable members, bind modes, relay commands, the source-generation pipeline, DI integration | **Per concept** |
| `entities/` | Core public contracts / API surface: `IViewModel`, `IRelayCommand`, `IBinder`, `View` | **Per contract** (the small, high-value `Source/` core) |
| `binders/` | The StarterKit binder catalog (~593 files, ~33 UI categories) | **Per category, NOT per file** — one page per UI-element family (texts, images, toggles, sliders, …). A per-class page would produce 500+ near-duplicate stubs and be unusable. |
| `converters/` | The ~44 StarterKit value converters | One overview page + clusters if needed |
| `flows/` | End-to-end execution paths: how a `[ViewModel]` becomes generated code, runtime binding resolution, View initialization | **Per flow** |
| `generation/` | The source-generation pipeline, keyed to the 3 submodules: source generator, Unity generators, analyzer (diagnostics) | **Per submodule/tool** |
| `risks/` | Gotchas that break the build/runtime: must-be-`partial`, committed generator DLLs, submodule init, .NET 9 SDK pin | **Per gotcha** |
| `reference/` | Samples, Unity editor tooling, external dependencies (Collections UPM) | Mixed, summary-level |
| `notes/` | Anything that doesn't fit yet | Free |

## Granularity principle

The codebase is **heavily skewed**: StarterKit is ~73% of files and the binder/converter catalog is wide, shallow, and repetitive; the conceptually dense core (`Source/`, 67 files) and the generators are small. **Invest depth in the small core + generation pipeline; summarize the large repetitive catalogs at category level.** A category page lists the binders in that family, the shared base class/pattern, the Mono/Switcher/Enum variants, and the one or two things that actually differ — not one page per class.

## File naming rules

Filenames are **human-readable** — they double as the node label in Obsidian's graph and file tree (Obsidian shows the filename, not the frontmatter `title`).

- Pages that *are* a code type → the **exact identifier**: `IViewModel.md`, `BindMode.md`, `IRelayCommand.md`.
- Concept / flow / risk / overview / binder-category pages → **Title Case with spaces**: `ViewModel Generation.md`, `Runtime Binding Resolution.md`, `Text Binders.md`, `Must Be Partial.md`.
- Names are **unique across the entire vault** — Obsidian resolves `[[links]]` by basename regardless of folder. Never create two names differing only in case (macOS is case-insensitive, so they collide).
- **No leading dot** in a filename (it hides the file on Unix and confuses tooling): write `NET 9 SDK Pin.md`, not `.NET 9 SDK Pin.md`.
- **System/meta files stay lowercase**: the hub is the only `index.md`; the journal is `log.md`. Section landing pages get a normal name (`Binders Catalog.md`), never a second `index.md`.
- `[[wikilinks]]` use the human name: `[[IViewModel]]`, `[[ViewModel Generation]]`. A link to a page that doesn't exist yet is fine — it marks a page worth writing (Obsidian shows it unresolved; Lint flags it as missing coverage).
38 changes: 38 additions & 0 deletions .claude/skills/aspid-wiki/references/translations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Translations (multilingual wiki)

`docs/wiki/` is **English and the source of truth**. Every other language is a **translation of the English wiki**, never generated from code directly.

## Layout

- `docs/wiki/` — English. Ingested from code (see `sync.md`).
- `docs/wiki-<lang>/` — one sibling vault per language: `docs/wiki-ru/`, later `docs/wiki-<xx>/`.
- Each translation **mirrors the English tree 1:1**: same folders, same filenames, same `[[wikilink]]` targets. Only the *content* (frontmatter `title`, the `#` H1, and the prose) is translated.

Mirroring filenames (not translating them) keeps `[[wikilinks]]` identical across every language, so the link graph and cross-references stay in sync automatically and a translated page is trivially matched to its English original (same relative path).

## What to translate vs keep

**Translate:** `title` frontmatter value, the H1, and all prose/body text, table cell prose, callouts.

**Keep verbatim (do NOT translate):**
- Code identifiers and type names (`IViewModel`, `BindMode`, `[Bind]`, `TMP_Text`).
- `[[wikilink]]` targets — they point at English filenames. For an aliased link `[[Target|alias]]`, keep `Target` and translate only the `alias`.
- Frontmatter keys, `type`, `status`, `source_paths`, `tags`, and all code blocks.

## Translation frontmatter

Add to every translated page (on top of the mirrored English frontmatter, with `title` translated):

```yaml
lang: ru
translated_from: <english-relative-path> # e.g. concepts/BindMode.md
translated_at: YYYY-MM-DD
```

## Translation checkpoint & staleness

A translation is downstream of its English page. When the English page changes (Ingest updated it), re-translate the affected language pages. Track this by comparing the English page's `updated_at` (or the wiki commit) against the translation's `translated_at`; if the English page is newer, the translation is stale — re-translate it. The English vault's `last_commit`/`submodule_commits` checkpoint is authoritative; translations never advance the code checkpoint.

## Index & log per language

Each `docs/wiki-<lang>/` gets its own translated `index.md` and `log.md`. The translated `index.md` keeps the English checkpoint fields for reference but states that English is the source of truth and links resolve within the same-language vault.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
skills-lock.json
.zed/
.idea/

# Obsidian working state for the knowledge wiki (all language vaults docs/wiki*) — keep notes, ignore local UI/cache
docs/wiki*/.obsidian/workspace*
docs/wiki*/.obsidian/cache
docs/wiki*/.obsidian/*.json.bak
docs/wiki*/.trash/
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ Submodules:

- Full docs: https://vpd-inc.gitbook.io/aspid.mvvm/
- Unity Asset Store: https://assetstore.unity.com/packages/slug/298463
- **Knowledge wiki**: `docs/wiki/` — Obsidian vault of concept/entity/binder/flow/risk pages for fast codebase orientation (read it before reading source). Built and kept in sync by the `aspid-wiki` skill in `.claude/skills/`. Start at `docs/wiki/index.md`.
- **XML doc conventions**: skill `aspid-mvvm-xmldoc` in `.claude/skills/` — rules for writing XML documentation comments
- Key entry points for new contributors:
- `Readme.md` — project overview
Expand Down
1 change: 1 addition & 0 deletions docs/wiki-ru/.obsidian/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions docs/wiki-ru/.obsidian/appearance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
33 changes: 33 additions & 0 deletions docs/wiki-ru/.obsidian/core-plugins.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}
Loading
Loading