mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
feat(skill): add /understand-onboard command for team onboarding guides
Generates a structured markdown onboarding guide from the knowledge graph, including project overview, architecture layers, key concepts, guided tour, file map, and complexity hotspots. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
eb0d2eaac0
commit
09fc78f321
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: understand-onboard
|
||||
description: Generate a structured onboarding guide for new team members using the knowledge graph
|
||||
---
|
||||
|
||||
# /understand-onboard
|
||||
|
||||
Generate a comprehensive onboarding guide from the project's knowledge graph.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Read the knowledge graph at `.understand-anything/knowledge-graph.json`
|
||||
2. If it doesn't exist, tell the user to run `/understand` first
|
||||
3. Generate a structured onboarding guide that includes:
|
||||
- Project overview (name, languages, frameworks, description)
|
||||
- Architecture layers and their responsibilities
|
||||
- Key concepts to understand
|
||||
- Guided tour (step-by-step walkthrough)
|
||||
- File map (what each key file does)
|
||||
- Complexity hotspots (what to be careful with)
|
||||
4. Format as clean markdown
|
||||
5. Offer to save the guide to `docs/ONBOARDING.md` in the project
|
||||
6. Suggest the user commit it to the repo for the team
|
||||
@@ -0,0 +1,87 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { buildOnboardingGuide } from "../onboard-builder.js";
|
||||
import type { KnowledgeGraph } from "@understand-anything/core";
|
||||
|
||||
const sampleGraph: KnowledgeGraph = {
|
||||
version: "1.0.0",
|
||||
project: {
|
||||
name: "test-project",
|
||||
languages: ["typescript", "python"],
|
||||
frameworks: ["express", "prisma"],
|
||||
description: "A test REST API",
|
||||
analyzedAt: "2026-03-14T00:00:00Z",
|
||||
gitCommitHash: "abc123",
|
||||
},
|
||||
nodes: [
|
||||
{ id: "file:src/index.ts", type: "file", name: "index.ts", filePath: "src/index.ts", summary: "Entry point", tags: ["entry"], complexity: "simple" },
|
||||
{ id: "file:src/service.ts", type: "file", name: "service.ts", filePath: "src/service.ts", summary: "Core service", tags: ["service"], complexity: "complex" },
|
||||
{ id: "concept:auth", type: "concept", name: "Auth Flow", summary: "JWT-based authentication", tags: ["concept", "auth"], complexity: "complex" },
|
||||
],
|
||||
edges: [
|
||||
{ source: "file:src/index.ts", target: "file:src/service.ts", type: "imports", direction: "forward", weight: 0.8 },
|
||||
],
|
||||
layers: [
|
||||
{ id: "layer:api", name: "API Layer", description: "Routes and handlers", nodeIds: ["file:src/index.ts"] },
|
||||
{ id: "layer:service", name: "Service Layer", description: "Business logic", nodeIds: ["file:src/service.ts"] },
|
||||
],
|
||||
tour: [
|
||||
{ order: 1, title: "Start Here", description: "Begin with index.ts", nodeIds: ["file:src/index.ts"] },
|
||||
{ order: 2, title: "Core Logic", description: "Service layer", nodeIds: ["file:src/service.ts"] },
|
||||
],
|
||||
};
|
||||
|
||||
describe("onboard-builder", () => {
|
||||
it("includes project overview section", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("# test-project");
|
||||
expect(guide).toContain("A test REST API");
|
||||
});
|
||||
|
||||
it("lists languages and frameworks", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("typescript");
|
||||
expect(guide).toContain("express");
|
||||
});
|
||||
|
||||
it("includes architecture layers section", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("## Architecture");
|
||||
expect(guide).toContain("API Layer");
|
||||
expect(guide).toContain("Service Layer");
|
||||
});
|
||||
|
||||
it("includes key concepts section", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("## Key Concepts");
|
||||
expect(guide).toContain("Auth Flow");
|
||||
});
|
||||
|
||||
it("includes getting started / tour section", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("## Getting Started");
|
||||
expect(guide).toContain("Start Here");
|
||||
});
|
||||
|
||||
it("includes complexity hotspots", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("## Complexity Hotspots");
|
||||
expect(guide).toContain("service.ts");
|
||||
});
|
||||
|
||||
it("includes file map section", () => {
|
||||
const guide = buildOnboardingGuide(sampleGraph);
|
||||
expect(guide).toContain("## File Map");
|
||||
});
|
||||
|
||||
it("handles graph with no layers gracefully", () => {
|
||||
const noLayers = { ...sampleGraph, layers: [] };
|
||||
const guide = buildOnboardingGuide(noLayers);
|
||||
expect(guide).toContain("# test-project");
|
||||
});
|
||||
|
||||
it("handles graph with no tour gracefully", () => {
|
||||
const noTour = { ...sampleGraph, tour: [] };
|
||||
const guide = buildOnboardingGuide(noTour);
|
||||
expect(guide).toContain("# test-project");
|
||||
});
|
||||
});
|
||||
@@ -14,3 +14,4 @@ export {
|
||||
formatExplainPrompt,
|
||||
type ExplainContext,
|
||||
} from "./explain-builder.js";
|
||||
export { buildOnboardingGuide } from "./onboard-builder.js";
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import type { KnowledgeGraph } from "@understand-anything/core";
|
||||
|
||||
/**
|
||||
* Generate a structured onboarding guide from the knowledge graph.
|
||||
* Output is standalone markdown suitable for a README, wiki, or docs.
|
||||
*/
|
||||
export function buildOnboardingGuide(graph: KnowledgeGraph): string {
|
||||
const { project, nodes, edges, layers, tour } = graph;
|
||||
const lines: string[] = [];
|
||||
|
||||
// --- Project Overview ---
|
||||
lines.push(`# ${project.name}`);
|
||||
lines.push("");
|
||||
lines.push(`> ${project.description}`);
|
||||
lines.push("");
|
||||
lines.push(`| | |`);
|
||||
lines.push(`|---|---|`);
|
||||
lines.push(`| **Languages** | ${project.languages.join(", ")} |`);
|
||||
lines.push(`| **Frameworks** | ${project.frameworks.join(", ")} |`);
|
||||
lines.push(`| **Components** | ${nodes.length} nodes, ${edges.length} relationships |`);
|
||||
lines.push(`| **Last Analyzed** | ${project.analyzedAt} |`);
|
||||
lines.push("");
|
||||
|
||||
// --- Architecture ---
|
||||
if (layers.length > 0) {
|
||||
lines.push("## Architecture");
|
||||
lines.push("");
|
||||
lines.push("The project is organized into the following layers:");
|
||||
lines.push("");
|
||||
|
||||
for (const layer of layers) {
|
||||
const memberNames = layer.nodeIds
|
||||
.map((id) => nodes.find((n) => n.id === id)?.name)
|
||||
.filter(Boolean);
|
||||
lines.push(`### ${layer.name}`);
|
||||
lines.push("");
|
||||
lines.push(layer.description);
|
||||
lines.push("");
|
||||
if (memberNames.length > 0) {
|
||||
lines.push(`Key components: ${memberNames.join(", ")}`);
|
||||
lines.push("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Key Concepts ---
|
||||
const conceptNodes = nodes.filter((n) => n.type === "concept");
|
||||
if (conceptNodes.length > 0) {
|
||||
lines.push("## Key Concepts");
|
||||
lines.push("");
|
||||
lines.push("Important architectural and domain concepts to understand:");
|
||||
lines.push("");
|
||||
for (const concept of conceptNodes) {
|
||||
lines.push(`### ${concept.name}`);
|
||||
lines.push("");
|
||||
lines.push(concept.summary);
|
||||
lines.push("");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Getting Started (Tour) ---
|
||||
if (tour.length > 0) {
|
||||
lines.push("## Getting Started");
|
||||
lines.push("");
|
||||
lines.push("Follow this guided tour to understand the codebase:");
|
||||
lines.push("");
|
||||
for (const step of tour) {
|
||||
const stepNodes = step.nodeIds
|
||||
.map((id) => nodes.find((n) => n.id === id))
|
||||
.filter(Boolean);
|
||||
lines.push(`### ${step.order}. ${step.title}`);
|
||||
lines.push("");
|
||||
lines.push(step.description);
|
||||
lines.push("");
|
||||
if (stepNodes.length > 0) {
|
||||
lines.push("**Files to look at:**");
|
||||
for (const node of stepNodes) {
|
||||
if (node!.filePath) {
|
||||
lines.push(`- \`${node!.filePath}\` — ${node!.summary}`);
|
||||
}
|
||||
}
|
||||
lines.push("");
|
||||
}
|
||||
if (step.languageLesson) {
|
||||
lines.push(`> **Language Tip:** ${step.languageLesson}`);
|
||||
lines.push("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- File Map ---
|
||||
const fileNodes = nodes.filter((n) => n.type === "file" && n.filePath);
|
||||
if (fileNodes.length > 0) {
|
||||
lines.push("## File Map");
|
||||
lines.push("");
|
||||
lines.push("| File | Purpose | Complexity |");
|
||||
lines.push("|------|---------|------------|");
|
||||
for (const node of fileNodes) {
|
||||
lines.push(`| \`${node.filePath}\` | ${node.summary} | ${node.complexity} |`);
|
||||
}
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
// --- Complexity Hotspots ---
|
||||
const complexNodes = nodes.filter((n) => n.complexity === "complex");
|
||||
if (complexNodes.length > 0) {
|
||||
lines.push("## Complexity Hotspots");
|
||||
lines.push("");
|
||||
lines.push("These components are the most complex and deserve extra attention:");
|
||||
lines.push("");
|
||||
for (const node of complexNodes) {
|
||||
lines.push(`- **${node.name}** (${node.type}): ${node.summary}`);
|
||||
}
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
// --- Footer ---
|
||||
lines.push("---");
|
||||
lines.push("");
|
||||
lines.push(`*Generated by [Understand Anything](https://github.com/anthropics/understand-anything) from knowledge graph v${graph.version}*`);
|
||||
lines.push("");
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
Reference in New Issue
Block a user