Package Exports
- tskb
- tskb/jsx-runtime
Readme
tskb
Let your AI assistant document your codebase as it works. Architecture knowledge accumulates in a compiler-verified artifact — query it, ask questions about your system, navigate it with your AI.
Your AI writes the docs. You navigate them.
⚠️ Status
Experimental / early concept.
- APIs and output may evolve
- Not production-ready
- Best viewed as a proof-of-concept and research tool
What is tskb?
tskb is a TypeScript-native DSL for expressing architectural intent as code.
Your AI assistant writes and maintains documentation in .tskb.tsx files that:
- are type-checked by the TypeScript compiler
- reference real folders, files, and exports
- fail the build when documentation and code drift apart
The result is a structured knowledge graph you can:
- query with natural language through your AI assistant
- navigate programmatically via the CLI
- visualize (Graphviz, diagrams)
Refactor your code → stale documentation breaks at compile time. The AI fixes it.
Why tskb exists
Large TypeScript codebases eventually suffer from:
- Tribal knowledge - architecture lives in senior developers’ heads
- Compound complexity - the mental model becomes fragile and expensive to communicate
- Documentation decay - Markdown and diagrams drift silently
tskb addresses this by making architecture documentation:
- typed
- validated
- enforced at build time
Core features
- AI-maintained docs — generated skills let your AI assistant write, update, and validate docs during development sessions
- Architecture as code using TSX
- Compiler-verified references via
typeof import() - Type-checked code snippets (not copied text)
- Doc priority (
essential,constraint,supplementary) to control AI guidance and enforce architectural rules - Flows — named, ordered sequences through the system (
<Flow>+<Step>), surfaced in queries and AI skill files - Native IDE support (autocomplete, refactoring, go-to-definition)
- Zero runtime impact (pure build-time tooling)
- CLI for querying (
ls,pick,search,docs,flows,contextcommands) - JSON knowledge graph output
- Graphviz visualization
- Monorepo-friendly by design
- Optimized for AI assistants & programmatic consumption
Quick start (recommended setup)
0) Install and setup
Install tskb:
npm install --save-dev tskbRun the interactive scaffolder:
npx tskb initThis will ask you:
- Where to put the docs folder (default:
docs/) - The glob pattern and tsconfig path
- Whether to enable Claude Code (
.claude/skills/) and/or GitHub Copilot (.github/instructions/) integrations
It creates everything you need:
your-repo/
├── docs/
│ ├── tsconfig.json # TypeScript config for docs (jsxImportSource: "tskb")
│ └── architecture.tskb.tsx # Starter doc — edit this first
├── package.json # "docs" script added automatically
├── .claude/skills/ # Created if Claude Code was selected
└── .github/ # Created if Copilot was selectedBuild the knowledge graph:
npm run docsVerify:
npx tskb ls --plain # Should show your folder structure
npx tskb docs --plain # Should list your starter docFor monorepos: create
docs/at workspace root, and ensuretsconfig.jsoncan resolve all packages you want to document.
Define your vocabulary
Declare architecture primitives using TypeScript declaration merging. All primitives are declared inside the global tskb namespace.
// docs/vocabulary.tskb.tsx
import type { Folder, File, Export, Term } from "tskb";
declare global {
namespace tskb {
interface Folders {
DataLayer: Folder<{
desc: "Data access layer with repositories and database logic";
path: "src/server/database";
}>;
ServiceLayer: Folder<{
desc: "Business logic and application services";
path: "src/server/services";
}>;
APILayer: Folder<{
desc: "HTTP controllers and route handlers";
path: "src/server/controllers";
}>;
}
interface Modules {
AuthServiceModule: Module<{
desc: "Authentication service module";
type: typeof import("../src/server/services/auth.service.js");
}>;
}
interface Exports {
UserRepository: Export<{
desc: "User data access using repository pattern";
type: typeof import("../src/server/database/repositories/user.repository.js").UserRepository;
}>;
AuthService: Export<{
desc: "Authentication and authorization business logic";
type: typeof import("../src/server/services/auth.service.js").AuthService;
}>;
}
interface Files {
"api-spec": File<{
desc: "OpenAPI specification for the REST API";
path: "docs/openapi.yml";
}>;
}
interface Terms {
"repository-pattern": Term<"Repository Pattern for data access abstraction">;
jwt: Term<"JSON Web Tokens for stateless authentication">;
"layered-architecture": Term<"Layered architecture pattern (API → Service → Data)">;
}
interface Externals {
postgres: External<{
desc: "Primary relational database";
kind: "database";
url: "https://www.postgresql.org";
}>;
redis: External<{
desc: "Session cache and pub/sub messaging";
kind: "cache";
url: "https://redis.io";
}>;
}
}
}Documentation format
This is the format your AI assistant writes into. Multiple docs across multiple teams share the same global vocabulary — the AI navigates and extends it as the codebase evolves.
// docs/authentication.tskb.tsx
import { Doc, H1, H2, P, Snippet, ref } from "tskb";
import type { AuthService } from "../src/server/services/auth.service.js";
import type { UserRepository } from "../src/server/database/repositories/user.repository.js";
import type { LoginCredentials, AuthResponse } from "../src/shared/types/auth.types.js";
// Reference the global vocabulary
const ServiceLayer = ref as tskb.Folders["ServiceLayer"];
const DataLayer = ref as tskb.Folders["DataLayer"];
const AuthServiceExport = ref as tskb.Exports["AuthService"];
const UserRepositoryExport = ref as tskb.Exports["UserRepository"];
const Jwt = ref as tskb.Terms["jwt"];
const RepositoryPattern = ref as tskb.Terms["repository-pattern"];
export default (
<Doc
explains="Authentication architecture: login flow, JWT tokens, and service-repository interaction"
priority="essential"
>
<H1>Authentication Architecture</H1>
<P>
The {AuthServiceExport} in the {ServiceLayer} handles authentication using {Jwt}. It depends
on {UserRepositoryExport} in the {DataLayer} following the {RepositoryPattern}.
</P>
<H2>Example: Login Flow</H2>
<Snippet
code={async () => {
const authService: AuthService = new AuthService();
const credentials: LoginCredentials = {
email: "user@example.com",
password: "hashedPassword",
};
const response: AuthResponse = await authService.login(credentials);
return response.tokens.accessToken;
}}
/>
</Doc>
);Snippet type checking
<Snippet> is not a string literal.
- Snippet bodies are fully type-checked
- Real types and APIs can be imported
- Broken examples fail the documentation build
// docs/repository-pattern.tskb.tsx
import { Doc, H1, P, Snippet } from "tskb";
import type { UserRepository } from "../src/server/database/repositories/user.repository.js";
import type { User } from "../src/shared/types/user.types.js";
import type { Database } from "../src/server/database/connection.js";
export default (
<Doc explains="Repository pattern implementation for data access abstraction">
<H1>Repository Pattern Example</H1>
<P>The UserRepository demonstrates the repository pattern for data access abstraction.</P>
<Snippet
code={async () => {
const db: Database = new Database(config);
const userRepository: UserRepository = new UserRepository(db);
const user: User | null = await userRepository.findByEmail("test@example.com");
return user?.id;
}}
/>
</Doc>
);If the API changes:
❌ Property 'findByEmail' does not exist on type 'UserRepository'.The snippet is never executed - it is parsed, validated, and stringified.
What tskb produces: a semantic architecture graph
tskb builds a typed, semantic knowledge graph describing your system.
The graph captures:
- Nodes - folders, modules, exports, files, terms, docs
- Edges - explicit and inferred relationships
- Hierarchy - nested architectural contexts
- Semantics - intent expressed through JSX
This graph is the primary output. Everything else (diagrams, markdown, AI context) is derived from it.
Output schema (high level)
{
nodes: {
folders: Record<string, FolderNode>; // id, desc, path
modules: Record<string, ModuleNode>; // id, desc, resolvedPath, typeSignature, imports
exports: Record<string, ExportNode>; // id, desc, resolvedPath, typeSignature
files: Record<string, FileNode>; // id, desc, path
terms: Record<string, TermNode>; // id, desc
flows: Record<string, FlowNode>; // id, desc, priority, steps[]
docs: Record<string, DocNode>; // id, explains, priority, filePath, content
},
edges: Array<{
from: string;
to: string;
type: "references" | "contains" | "belongs-to" | "imports" | "related-to" | "flow-step";
label?: string;
}>,
metadata: {
generatedAt: string;
version: string;
stats: { folderCount, moduleCount, exportCount, fileCount, termCount, flowCount, docCount, edgeCount };
}
}DocNode.priority controls visibility:
"essential"— included in generated skill/instructions files andlsoutput"constraint"— architectural rule shown inpickandsearchresults, must be followed when working on referenced areas"supplementary"— graph-only (default), queryable viasearch/pick
The schema is intentionally graph-first and machine-oriented.
Nested contexts
Folders define architectural contexts, not just paths.
From folder paths, tskb infers:
- hierarchical containment (
contains) - ownership of modules and exports (
belongs-to) - the most specific enclosing context
Your architecture becomes a tree of nested contexts, not a flat list.
Relations
Relations in the graph come from two sources:
Explicit intent
When you reference entities in JSX:
<P>Authentication is handled by {AuthService}.</P>tskb records a semantic edge:
Doc → AuthService (references)Semantic Relations with <Relation />
To express a semantic relationship between two nodes, use the <Relation /> JSX tag:
<Relation from={AuthService} to={UserRepository} label="depends on" />This creates a related-to edge in the graph, optionally labeled for richer semantics:
AuthService → UserRepository (related-to, label: "depends on")fromandtomust be node constants (extracted from the registry)labelis optional and can be any string describing the relationship
These relations are visible in CLI output (e.g., pick), and the label is included if present.
Inferred structure
From filesystem paths and imports:
- Folder → Folder (
contains) - Module → Folder (
belongs-to) - Module → Module (
imports) — from resolved import statements - Export → Module (
belongs-to) - File → Folder (
belongs-to)
The graph combines authored intent with structural truth.
Flows
Flows model named, ordered sequences through the system — login pipelines, build processes, request handling chains.
import { Doc, H1, Flow, Step, ref } from "tskb";
const AuthMiddleware = ref as tskb.Exports["AuthMiddleware"];
const AuthService = ref as tskb.Modules["AuthServiceModule"];
const UserRepository = ref as tskb.Exports["UserRepository"];
export default (
<Doc explains="Authentication flows">
<H1>Auth Flows</H1>
<Flow name="login" desc="User login from HTTP request to session token" priority="essential">
<Step node={AuthMiddleware} label="Validates request format" />
<Step node={AuthService} label="Checks credentials, generates JWT" />
<Step node={UserRepository} label="Queries user record" />
</Flow>
</Doc>
);Each <Flow> becomes a first-class node in the graph with flow-step edges connecting it to its participants. Only <Step> children are allowed (validated at build time).
Priority controls visibility:
priority="essential"— included in generated skill/instructions files andtskb flowsoutputpriority="supplementary"(default) — graph-only, queryable viatskb flowsandsearch
Why JSX: semantics, not rendering
JSX in tskb is not about UI.
It is a semantic DSL that allows you to declare meaning in a structured, type-safe way. Each JSX element becomes semantic data — not HTML.
JSX provides composability, static analysis, and extensibility without inventing a new syntax.
Querying the graph
These commands are embedded in the generated skill files — AI assistants use them automatically during sessions to orient themselves and look things up. You can also run them directly:
List folder structure
npx tskb ls # List top-level folders (depth=1)
npx tskb ls --depth 4 # List folders up to depth 4
npx tskb ls --depth -1 # List all folders (unlimited depth)Returns essential docs first, then folders ordered by depth.
Pick a node
npx tskb pick "ServiceLayer" # Pick a folder by ID
npx tskb pick "src/server/services" # Pick by filesystem path
npx tskb pick "auth.AuthService" # Pick a module by IDReturns type-specific data: parent, children, modules, exports, files, and referencing docs with their priority. When picking a doc node, the full content is included inline. Constraint docs in the results indicate rules that must be followed.
Search the graph
npx tskb search "auth" # Single keyword
npx tskb search "build command" # Multi-word fuzzy searchReturns ranked results with scores across all node types. Doc results include priority so constraint and essential docs are immediately visible.
List and search docs
npx tskb docs # List all docs sorted by priority
npx tskb docs "auth" # Search docs by query (matches explains, content, filePath)Lists all docs sorted by priority (constraints first, then essential, then supplementary). With a query, returns fuzzy-matched results with scores, filtered to relevant matches. Use pick on a doc nodeId to get its full content.
List and search flows
npx tskb flows # List all flows sorted by priority
npx tskb flows "build" # Search flows by queryLists all flows sorted by priority. Essential flows are shown first. Use pick on a flow nodeId to see its steps and referenced nodes.
Get full context for an area
npx tskb context "ServiceLayer" # Depth 1 (default): node + immediate children + docs
npx tskb context "ServiceLayer" --depth 2 # Deeper: includes grandchildren and their docs
npx tskb context "src/server/services" # Also works with filesystem pathsReturns the target node, all neighborhood nodes (child folders, modules, exports) up to the specified depth, and all referencing docs — deduplicated and sorted by priority. Constraint doc IDs are surfaced at the top level so they can't be missed.
All commands output JSON by default. Use --plain for structured plain text optimized for AI assistants (fewer tokens, no JSON overhead), or --optimized for compact JSON.
Visualize
The build command automatically generates a Graphviz DOT file in .tskb/graph.dot.
To render it as an image:
dot -Tpng .tskb/graph.dot -o .tskb/graph.pngOr view it interactively:
xdot .tskb/graph.dotWorkflow integration
Pre-commit hook
Validate docs on every commit:
npm install --save-dev husky
npx husky init
echo "npm run docs" > .husky/pre-commitCI/CD (GitHub Actions)
- name: Validate architecture docs
run: npm run docs
- name: Upload graph artifact
uses: actions/upload-artifact@v3
with:
name: architecture-graph
path: .tskb/This ensures documentation stays synchronized with code changes.
AI assistant integration
TSKB closes a loop: your AI assistant writes the docs, then reads them — so architectural knowledge accumulates and carries forward across sessions. You navigate the graph, ask questions about your system, interrupt when something is wrong, and steer what gets documented.
- Auto-generated integrations: Build produces a Claude Code skill (
.claude/skills/tskb/SKILL.md) and Copilot instructions (.github/instructions/tskb.instructions.md) with folder tree, essential doc summaries, command response shapes, and workflow guidance baked in - Doc priority: Controls what AI assistants see —
essentialdocs appear in generated files andlsoutput,constraintdocs surface inpick/searchwith their priority visible,supplementarydocs are graph-only - Constraint docs: Mark docs with
priority="constraint"to define architectural rules. When an AI picks a node, constraint docs referencing that area appear in the results — signaling rules that must be followed before making changes - Docs command:
docslists or searches all documentation, with fuzzy matching across explains, content, and file paths — essential docs are boosted in search results - Context command:
contextreturns a node's full neighborhood (children, modules, exports) with referencing docs — replacing multi-steppick→ read →pickworkflows with a single call - Plain text mode:
--plainoutputs structured text instead of JSON — ~30% fewer tokens for AI consumption while preserving all semantic content - Flows command:
flowslists or searches named sequences through the system — essential flows are included in generated skill/instructions files - Structured queries: AI can use
ls,pick,search,docs,flows, andcontextto navigate architecture — all return JSON (or plain text with--plain) with priority metadata on doc results
The AI assistant both writes and reads the graph. During development it documents what it builds; at the start of a session it consults what was documented before. You can query it at any point.
How it works in practice: The generated skill files embed the CLI commands and teach assistants when and how to use them — no manual instruction needed. At the start of a session the assistant already knows the folder tree and essential docs; when it needs more detail it runs search, context, or pick on its own:
- Folder tree and essential doc summaries are baked into the skill — loaded before the first message
searchfinds relevant nodes for a taskdocsfilters documentation by topiccontextgets the full neighborhood — nodes, docs, and constraints in one callpickreads a single node or full doc content- Only the files that matter get read
This dramatically reduces tokens spent on exploration and increases accuracy.
Generated skills
The build produces two skills for each integration (Claude Code and GitHub Copilot):
| Skill | Purpose | Generated files |
|---|---|---|
| tskb | Codebase map — folder tree, essential doc summaries, CLI commands. Loaded on every prompt. | .claude/skills/tskb/SKILL.md.github/instructions/tskb.instructions.md |
| tskb-update | How the AI writes and maintains .tskb.tsx files — JSX syntax, registry primitives, when to trigger an update, best practices. Activates when working with .tskb.tsx files. |
.claude/skills/tskb-update/SKILL.md.github/instructions/tskb-update.instructions.md |
How they work:
- Claude Code: Skills in
.claude/skills/are loaded automatically based on context. The maintskbskill is always available;tskb-updateactivates when working with.tskb.tsxfiles. - GitHub Copilot: Instructions in
.github/instructions/useapplyTofrontmatter patterns.tskb.instructions.mdapplies to all files (**),tskb-update.instructions.mdapplies to**/*.tskb.tsx. - Content is auto-generated: Every
npm run docsbuild regenerates these files from the current graph. Don't edit them manually — they'll be overwritten.
To enable these integrations, select them during npx tskb init or create the directories manually (.claude/skills/ and/or .github/). The build detects their presence and writes the corresponding files.
How is this different?
vs ADRs / Markdown docs: Type-checked and validated against real code, not just text files that drift.
vs Structurizr / C4 / PlantUML: Native TypeScript (not a custom DSL), produces a queryable knowledge graph (not just static diagrams).
vs TypeDoc: Documents architecture and intent (why components exist, how they relate), not just API surfaces (what methods exist).
Unique to tskb:
- Type-checks architecture docs at compile time
- Validates against actual code via
typeof import() - CLI for querying the graph (no file scanning needed)
- Documents whole systems (multiple packages, monorepos)
- Type-checked code snippets (not string literals)
- First-class flows — named, ordered sequences as graph nodes
- Doc priority system (essential, constraint, supplementary) for AI guidance
- Optimized for AI assistants with structured queries and constraint enforcement
Roadmap
- Architectural constraints validation
- Interactive visualization (beyond Graphviz)
- Plugin system for custom node types
License
MIT © Dimitar Mihaylov