When /understand runs with no --language flag and no stored outputLanguage,
step 3.6 now infers the conversation language and — only when it is non-English
— confirms once before generating, then persists the choice to config.json.
English conversations keep the exact same silent `en` path; --language flag and
stored config still take priority. README documents the behavior; version
bumped 2.7.5 -> 2.7.6 across all five manifests (user-visible behavior change).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes a cluster of community-profile gaps (#248, #249, #251, #252) in one
PR rather than four micro-PRs that all touch the same surface area.
### Templates (#251, #252)
- .github/ISSUE_TEMPLATE/bug_report.yml — required fields for repro
(plugin version, platform, OS, project language, file count); the four
pieces of context that are missing from ~every current bug report.
- .github/ISSUE_TEMPLATE/feature_request.yml — leads with the *problem*
rather than the proposed solution, which keeps maintainer review focused
on whether to solve, not just how.
- .github/ISSUE_TEMPLATE/question.yml — separate from bug to keep the
bug queue triagable.
- .github/ISSUE_TEMPLATE/config.yml — disables blank issues and routes
general discussion to README + Discussions.
- .github/PULL_REQUEST_TEMPLATE.md — includes the version-bump checklist
that CLAUDE.md says must stay in sync across 5 manifests; otherwise
every contributor learns this rule by getting their PR bounced.
### Community files
- CODE_OF_CONDUCT.md — short, project-specific document that names the
expectations and reporting path. Not a verbatim Contributor Covenant
to keep it readable.
- SECURITY.md — describes the project's local-only threat model
explicitly so reporters know what's in / out of scope before they
spend time on a writeup. Points at GitHub private vulnerability
reporting as the primary channel.
### CI (#249)
- ci.yml now also runs on pushes to main, not only PRs. Without this,
a direct push to main (which happens when maintainers merge a PR
branch locally) doesn't trigger CI, so a regression can land green-
looking and stay broken for days.
- Added a concurrency group that cancels stale runs for the same ref.
Saves runner minutes and keeps the per-ref status meaningful.
- Used `github.ref` (a controlled value), not user-controlled input,
so no script-injection surface.
### package.json (#248)
- Added description, license, repository, bugs, homepage, keywords —
the standard set for npm package discoverability and so GitHub's
community-profile check shows the project at 100%.
`enumerateViaGit` ran `git ls-files -co --exclude-standard` (newline-separated
output) and then `split('\n').map(trim)` on the result. Without `-z`,
`git ls-files` C-escapes any byte outside the locale's "safe" set and wraps
the path in double quotes — for example, a directory named `30. 🏗️ docs/`
comes back as `"30. \360\237\217\227\357\270\217 docs/"`. Downstream
consumers then can't round-trip those octal-quoted strings to real disk
paths, so every file under such directories is silently dropped from the
scan.
This is particularly biting on Windows (where the issue surfaces even with
UTF-8 locale settings) and for any project that uses emoji, accented
characters, or CJK codepoints in directory names — which is increasingly
common in design/spec/journal trees.
The fix is to use `-z` (NUL-terminated output), the same approach git
itself documents for downstream consumers (e.g. `xargs -0`). NUL-separated
chunks are raw bytes, so every codepoint round-trips back to its real disk
path on every platform. Split on `\0` instead of `\n`; drop the now-
unnecessary `.trim()`.
Verified on a real project with emoji-prefixed directory names:
bare `git ls-files`:
"30. \360\237\217\227\357\270\217\360\237\247\231\342\200\215..."
`git ls-files -z`:
30. 🏗️🧙♂️🔮 BD-CCSP/01. Demo's/DEMO--...
Discovered during a multi-agent scan of an Atlas Intelligence spoke repo;
~33 design-intent files in `30. 🏗️ BD-{app}/` directories were silently
dropped per scan. Full report: atlas-intelligence-io/fleet-feedback#491.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PR #199 documented the community-reported Cursor Settings → Plugins
workaround in README.md only; the seven READMEs/* locale files still
said auto-discovery always works. Mirror that fallback here so non-English
readers hit the same fix without hunting issue #172.
Several users have reported that cloning the repo and opening it in Cursor
doesn't always trigger auto-discovery of the .cursor-plugin manifest. Add
the community-reported workaround (Cursor Settings → Plugins, paste repo
URL) to the Cursor section so it isn't only discoverable from issue
threads.
Closes#172
`model: inherit` is a Claude Code-specific keyword that means "use the
parent session's model." Other tools that read the same agent frontmatter
(opencode, codex, etc.) don't understand it and instead try to use
`inherit` as a literal model id, which the configured provider rejects.
Reproduction (from #167): opencode + deepseek runs `/understand`, the
project-scanner subagent dispatches with `model: inherit`, deepseek
returns `ProviderModelNotFoundError`, and the pipeline halts on every
subagent dispatch.
With the field omitted, each platform falls back to its own configured
default:
- Claude Code: user's default subagent model
- opencode / codex / etc.: globally configured model
Note for Claude Code Opus users: subagents will no longer auto-inherit
the Opus session model. If you want the previous behavior, set your
default subagent model globally — that single setting now controls all
nine agents.
Closes#167
Several users have reported that cloning the repo and opening it in Cursor
doesn't always trigger auto-discovery of the .cursor-plugin manifest. Add
the community-reported workaround (Cursor Settings → Plugins, paste repo
URL) to the Cursor section so it isn't only discoverable from issue
threads.
Closes#172
Add to all 8 READMEs (English + 7 translations):
- "Keep learning" section gets inline commands for incremental re-runs, the --auto-update post-commit hook, and scoping /understand to a subdirectory for huge monorepos
- "Under the Hood" gets a new "Tree-sitter + LLM hybrid" subsection explaining the deterministic-vs-semantic split that powers the pipeline
Adds phase status lines, batch progress with total count, and phase
completion confirmations to the skill definition. Users now see
[Phase N/7] headers and Batch X/N during analysis instead of
unnumbered batch lines with no context.
Fixes#182
Tailwind v4's default source detection walks the nearest .git and
collects tracked files via git ls-files. When the dashboard sources
sit inside a gitignored subtree of an ancestor repo (e.g. the default
marketplace install path ~/.claude/plugins/cache/, which is ignored by
~/.claude/.gitignore), detection returns 0 files and the Oxide engine
skips all utility generation — the dashboard renders unstyled.
Adding explicit @source directives is the supported Tailwind v4 escape
hatch and is a no-op for installs where automatic detection works.
Verified: built CSS bundle jumps from ~9 KB to ~55 KB and utility
classes (.flex, .grid, .absolute, .w-full, .h-full) are present.
Fixes#179
- typescript-eslint preset: strict -> recommended for a usable first-pass
baseline (per PR discussion); ratchet up in a follow-up.
- Drop the projectService/parserOptions block. Neither `recommended` nor
`strict` is type-aware, so it was unused; removing it also avoids the
pnpm-workspace tsconfig-resolution failure mode flagged in review.
- Add Node + browser globals via the `globals` package so .mjs scripts and
the dashboard stop hitting `no-undef`.
- Expand ignores: built bundles (**/public/**), Astro generated (.astro/),
and .private/ (eval scratch). Cuts 2400+ errors in vendored output.
- Allow `_`-prefixed unused vars/args/caught errors; skip irregular
whitespace inside comments (json-parser intentionally embeds ZWSP-escaped
block-comment examples in JSDoc).
- Fix the residual 13 genuine errors: drop dead imports/vars, replace
two `as any[]` in schema.ts with `Array<Record<string, unknown>>`,
drop unused destructure in change-classifier, drop unused catch binding
in extract-structure.mjs.
- Add EOF newline to eslint.config.mjs.
- Refresh pnpm-lock.yaml.
- Add `pnpm lint` step to .github/workflows/ci.yml so the tooling
actually enforces something.
pnpm lint now exits 0 locally; 33+13 test files / 1445 tests still pass.
The generated onboarding markdown linked to a nonexistent repository
(anthropics/understand-anything) instead of the actual project URL
(Lum1104/Understand-Anything).
Adds the Trendshift trending-repository badge just below the tagline on the
English README and all 7 localized variants, and to the homepage hero between
the action row and the Enterprise pill.
Adds a Community section near the end of README (English + 7 localized
variants) and a CommunityVideo component on the homepage embedding the
YouTube walkthrough by Better Stack. Section invites future video / blog /
tutorial contributions to be featured here.
import.meta.url resolves through symlinks but pathToFileURL(process.argv[1])
preserves them, so extract-structure.mjs silently exited 0 without writing
output when invoked via the plugin's symlinked install path — the documented
Claude Code / Copilot CLI layout. Compare both sides via realpathSync and add
a post-write existence assertion plus caller-side guidance in the agent.
Closes#162
The repository has a pnpm lint script running 'eslint .' but ESLint
and typescript-eslint were not listed in devDependencies.
Added:
- eslint (^9.0.0)
- @eslint/js (^9.0.0)
- typescript-eslint (^8.0.0)
Added eslint.config.mjs with flat config (ESLint 9+) using
typescript-eslint strict rules. Ignores node_modules, dist, build,
and framework-specific output directories.
- Replace hardcoded hex with var(--color-*) and CJK font stacks with
var(--font-sans) / var(--font-heading) so the overlay tracks the theme
picker and uses the project's typography (DM Serif Display).
- Lift dismiss/visibility state to Dashboard (shouldShowOnboarding +
showOnboarding useState + dismissOnboarding callback). Gate the
Suspense mount with a boolean so the lazy chunk is only fetched on
first visit, matching the PathFinderModal / KeyboardShortcutsHelp
mount pattern.
- Add capture-phase Escape handler (stopPropagation prevents the global
shortcut chain from also firing) and role="dialog" / aria-modal /
aria-labelledby on the card for screen readers.
Schema (packages/core/src/schema.ts) defines node types: file, function,
class, module, concept, config, document, ... The welcome step body only
listed "file, concept, entity, claim", missing the most common code-side
types. Updated all 6 locales (en / zh / zh-TW / ja / ko / ru) to mention
file / class / function from code plus concept / entity / claim from the
knowledge wiki.
- Replace hardcoded Chinese strings with t.onboarding.* via useI18n
- Add `onboarding` namespace to en / zh / zh-TW / ja / ko / ru locales
- Inject @keyframes ua-fade-in (was referenced in inline style but
never defined, so the overlay popped in instead of fading)
Ships the fingerprints baseline fix (e7af9ae): every install since
2.7.0 had a broken Phase 7 step 2.5 that threw TypeError on the first
/understand run and left fingerprints.json empty/missing, which made
every subsequent auto-update escalate to FULL_UPDATE. This release
replaces the LLM-written script with a bundled build-fingerprints.mjs
and reorders Phase 7 to write fingerprints before meta.json.
Anyone upgrading from 2.7.0–2.7.2 should re-run /understand --full
to regenerate a valid baseline.
The Phase 7 step 2.5 code example in SKILL.md called
buildFingerprintStore() with 2 arguments, but the real signature
requires 4 (projectDir, filePaths, registry: PluginRegistry,
gitCommitHash: string). It also omitted the required
`await TreeSitterPlugin.init()`. Any LLM following the example
threw TypeError on `registry.analyzeFile()` and never produced a
baseline — which is why fingerprints.json never existed in a usable
form after a fresh /understand, and is the root cause behind
issue #152's "every auto-update escalates to FULL_UPDATE" cascade.
Replace the LLM-written script with a bundled `build-fingerprints.mjs`
that mirrors `extract-structure.mjs`: resolves @understand-anything/core
via createRequire, initializes TreeSitterPlugin + PluginRegistry
correctly, calls buildFingerprintStore with all four arguments, and
persists via saveFingerprints. Smoke-tested on this repo (3 files,
correct functions/classes/imports extracted).
Reorder Phase 7 so fingerprints are written BEFORE meta.json. If
fingerprint generation fails, the new step explicitly says to abort
Phase 7 — meta.json must not advance without a valid baseline, or
the next auto-update sees a fresh commit hash with no fingerprints
and classifies every file as STRUCTURAL.
Affects every install since 2.7.0 (when the broken example was
introduced). Users running /understand --full on 2.7.3+ will get
a usable fingerprints.json on the first try.