{"id":"understand-domain","name":"understand-domain","summary":"コードベースからビジネスドメインの知識を抽出し、インタラクティブなドメインフローグラフを生成する。単体で動作する(軽量なスキャン)か、既存の/理解した知識グラフから派生します。","body":"# /understand-domain\n\nExtracts business domain knowledge — domains, business flows, and process steps — from a codebase and produces an interactive horizontal flow graph in the dashboard.\n\n## How It Works\n\n- If a knowledge graph already exists (`.ua/knowledge-graph.json`, or the legacy `.understand-anything/knowledge-graph.json` when that directory is present), derives domain knowledge from it (cheap, no file scanning)\n- If no knowledge graph exists, performs a lightweight scan: file tree + entry point detection + sampled files\n- Use `--full` flag to force a fresh scan even if a knowledge graph exists\n\n## Instructions\n\n### Phase 0: Resolve `PROJECT_ROOT`\n\nSet `PROJECT_ROOT` to the current working directory.\n\n**Worktree redirect.** If `PROJECT_ROOT` is inside a git worktree (not the main checkout), redirect output to the main repository root. Worktrees managed by Claude Code are ephemeral — the data directory (`.ua/`, or legacy `.understand-anything/`) written there is destroyed when the session ends, taking the domain graph with it (issue #133). Detect a worktree by comparing `git rev-parse --git-dir` against `git rev-parse --git-common-dir`; in a normal checkout or submodule they resolve to the same path, in a worktree they differ and the parent of `--git-common-dir` is the main repo root.\n\n```bash\nCOMMON_DIR=$(git -C \"$PROJECT_ROOT\" rev-parse --git-common-dir 2>/dev/null)\nGIT_DIR=$(git -C \"$PROJECT_ROOT\" rev-parse --git-dir 2>/dev/null)\nif [ -n \"$COMMON_DIR\" ] && [ -n \"$GIT_DIR\" ]; then\n  COMMON_ABS=$(cd \"$PROJECT_ROOT\" && cd \"$COMMON_DIR\" 2>/dev/null && pwd -P)\n  GIT_ABS=$(cd \"$PROJECT_ROOT\" && cd \"$GIT_DIR\" 2>/dev/null && pwd -P)\n  if [ -n \"$COMMON_ABS\" ] && [ \"$COMMON_ABS\" != \"$GIT_ABS\" ]; then\n    MAIN_ROOT=$(dirname \"$COMMON_ABS\")\n    if [ -d \"$MAIN_ROOT\" ] && [ \"${UNDERSTAND_NO_WORKTREE_REDIRECT:-0}\" != \"1\" ]; then\n      echo \"[understand-domain] Detected git worktree at $PROJECT_ROOT\"\n      echo \"[understand-domain] Redirecting output to main repo root: $MAIN_ROOT\"\n      echo \"[understand-domain] (Set UNDERSTAND_NO_WORKTREE_REDIRECT=1 to keep PROJECT_ROOT as the worktree.)\"\n      PROJECT_ROOT=\"$MAIN_ROOT\"\n    fi\n  fi\nfi\n```\n\nUse `$PROJECT_ROOT` (not the bare CWD) for every reference to \"the current project\" / `<project-root>` in subsequent phases.\n\n**Resolve the data directory `$UA_DIR`.** All Understand-Anything artifacts live in the project's data directory. Resolve it once, now that `$PROJECT_ROOT` is known, and reuse `$UA_DIR` for every read and write in later phases:\n```bash\nUA_DIR=\"$PROJECT_ROOT/$([ -d \"$PROJECT_ROOT/.understand-anything\" ] && echo .understand-anything || echo .ua)\"\n```\nThis keeps the legacy `.understand-anything/` directory when it already exists (existing projects keep working with no migration) and uses the new `.ua/` otherwise. Because each phase may run in a fresh shell, carry `$UA_DIR` forward like `$PROJECT_ROOT`, re-resolving it with the line above if a later command block needs it.\n\n**Important:** do **not** assume the plugin root is simply two directories above the skill path string. In many installations `~/.agents/skills/understand-domain` is a symlink into the real plugin checkout. Prefer runtime-provided plugin roots first (for Claude), then fall back to universal symlinks, skill symlink resolution, and common clone-based install paths.\n\nResolve the plugin root like this:\n\n```bash\nSKILL_REAL=$(realpath ~/.agents/skills/understand-domain 2>/dev/null || readlink -f ~/.agents/skills/understand-domain 2>/dev/null || echo \"\")\nSELF_RELATIVE=$([ -n \"$SKILL_REAL\" ] && cd \"$SKILL_REAL/../..\" 2>/dev/null && pwd || echo \"\")\nCOPILOT_SKILL_REAL=$(realpath ~/.copilot/skills/understand-domain 2>/dev/null || readlink -f ~/.copilot/skills/understand-domain 2>/dev/null || echo \"\")\nCOPILOT_SELF_RELATIVE=$([ -n \"$COPILOT_SKILL_REAL\" ] && cd \"$COPILOT_SKILL_REAL/../..\" 2>/dev/null && pwd || echo \"\")\n\nPLUGIN_ROOT=\"\"\nfor candidate in \\\n  \"${CLAUDE_PLUGIN_ROOT}\" \\\n  \"$HOME/.understand-anything-plugin\" \\\n  \"$SELF_RELATIVE\" \\\n  \"$COPILOT_SELF_RELATIVE\" \\\n  \"$HOME/.codex/understand-anything/understand-anything-plugin\" \\\n  \"$HOME/.opencode/understand-anything/understand-anything-plugin\" \\\n  \"$HOME/.pi/understand-anything/understand-anything-plugin\" \\\n  \"$HOME/understand-anything/understand-anything-plugin\"; do\n  if [ -n \"$candidate\" ] && [ -f \"$candidate/package.json\" ] && [ -f \"$candidate/pnpm-workspace.yaml\" ]; then\n    PLUGIN_ROOT=\"$candidate\"\n    break\n  fi\ndone\n\nif [ -z \"$PLUGIN_ROOT\" ]; then\n  echo \"Error: Cannot find the understand-anything plugin root.\"\n  echo \"Checked:\"\n  echo \"  - ${CLAUDE_PLUGIN_ROOT:-<unset CLAUDE_PLUGIN_ROOT>}\"\n  echo \"  - $HOME/.understand-anything-plugin\"\n  echo \"  - ${SELF_RELATIVE:-<unresolved path derived from ~/.agents/skills/understand-domain>}\"\n  echo \"  - ${COPILOT_SELF_RELATIVE:-<unresolved path derived from ~/.copilot/skills/understand-domain>}\"\n  echo \"  - $HOME/.codex/understand-anything/understand-anything-plugin\"\n  echo \"  - $HOME/.opencode/understand-anything/understand-anything-plugin\"\n  echo \"  - $HOME/.pi/understand-anything/understand-anything-plugin\"\n  echo \"  - $HOME/understand-anything/understand-anything-plugin\"\n  echo \"Make sure the plugin is installed correctly.\"\n  exit 1\nfi\n```\n\nUse `$PLUGIN_ROOT` for every reference to agent definitions in subsequent phases.\n\n### Phase 1: Detect Existing Graph\n\n1. Check if `$UA_DIR/knowledge-graph.json` exists\n2. If it exists AND `--full` was NOT passed, check freshness before deriving from it:\n   - Read `project.gitCommitHash` from the graph metadata as `GRAPH_COMMIT_RAW`. Change to `$PROJECT_ROOT`, resolve it as a commit before using it in any Git diff, compare the resolved commit with `git rev-parse HEAD`, and inspect project-scoped committed and working-tree changes:\n     ```bash\n     GRAPH_COMMIT=$(git rev-parse --verify --end-of-options \"${GRAPH_COMMIT_RAW}^{commit}\" 2>/dev/null)\n     git rev-parse HEAD\n     git diff --name-only \"$GRAPH_COMMIT\" HEAD -- .\n     git diff --cached --name-only -- .\n     git diff --name-only -- .\n     git ls-files --others --exclude-standard -- .\n     ```\n   - The `-- .` pathspec is required: commits that only touch a sibling monorepo project must not make this graph stale. A hash mismatch alone is not stale when the project diff is empty.\n   - Ignore the selected data directory (`.ua/` or legacy `.understand-anything/`) in every command's output because it contains generated graph artifacts, not project source drift.\n   - If the committed diff or any working-tree command reports project files, warn that domain extraction may omit those changes. Suggest: Run `/understand` to refresh the knowledge graph.\n   - Run the commit diff only when `GRAPH_COMMIT_RAW` resolves successfully. If the graph commit or Git metadata is missing, invalid, or unavailable, give a brief best-effort warning and continue instead of blocking.\n3. After that preflight, proceed to Phase 3 (derive from graph).\n4. Otherwise, proceed to Phase 2 (lightweight scan). When `--full` is used, skip this preflight because the command performs a fresh scan instead of consuming the existing graph.\n\n### Phase 2: Lightweight Scan (Path 1)\n\nThe preprocessing script does NOT produce a domain graph — it produces **raw material** (file tree, entry points, exports/imports) so the domain-analyzer agent can focus on the actual domain analysis instead of spending dozens of tool calls exploring the codebase. Think of it as a cheat sheet: cheap Python preprocessing → expensive LLM gets a clean, small input → better results for less cost.\n\n1. Run the preprocessing script bundled with this skill, passing `$PROJECT_ROOT` from Phase 0:\n   ```\n   python ./extract-domain-context.py \"$PROJECT_ROOT\"\n   ```\n   This outputs `$UA_DIR/intermediate/domain-context.json` containing:\n   - File tree (respecting `.gitignore`)\n   - Detected entry points (HTTP routes, CLI commands, event handlers, cron jobs, exported handlers)\n   - File signatures (exports, imports per file)\n   - Code snippets for each entry point (signature + first few lines)\n   - Project metadata (package.json, README, etc.)\n2. Read the generated `domain-context.json` as context for Phase 4\n3. Proceed to Phase 4\n\n### Phase 3: Derive from Existing Graph (Path 2)\n\n1. Read `$UA_DIR/knowledge-graph.json`\n2. Format the graph data as structured context:\n   - All nodes with their types, names, summaries, and tags\n   - All edges with their types (especially `calls`, `imports`, `contains`)\n   - All layers with their descriptions\n   - Tour steps if available\n3. This is the context for the domain analyzer — no file reading needed\n4. Proceed to Phase 4\n\n### Phase 4: Domain Analysis\n\n1. Read the domain-analyzer agent prompt from `$PLUGIN_ROOT/agents/domain-analyzer.md`\n2. Dispatch a subagent with the domain-analyzer prompt + the context from Phase 2 or 3\n3. The agent writes its output to `$UA_DIR/intermediate/domain-analysis.json`\n\n### Phase 5: Validate and Save\n\n1. Read the domain analysis output\n2. Validate using the standard graph validation pipeline (the schema now supports domain/flow/step types)\n3. If validation fails, log warnings but save what's valid (error tolerance)\n4. Save to `$UA_DIR/domain-graph.json`\n5. Clean up `$UA_DIR/intermediate/domain-analysis.json` and `$UA_DIR/intermediate/domain-context.json`\n\n### Phase 6: Launch Dashboard\n\n1. Auto-trigger `/understand-dashboard` to visualize the domain graph\n2. The dashboard will detect `domain-graph.json` and show the domain view by default","author":"@Egonex-AI","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/Egonex-AI/Understand-Anything/tree/main/understand-anything-plugin/skills/understand-domain","license":"MIT","category":"coding","lang":"en","tokens":2369,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"extract-domain-context.py","size":16273,"sha256":"3ae26832a8df8090b606d86839d0721cc1c316aaac28e2b8fba77ed6d7455ae7"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":true,"networkEndpoints":[]}}