-
Notifications
You must be signed in to change notification settings - Fork 2
Skill Architecture
This document describes the three-component architecture used to build domain skills in Skillful-Alhazen.
A skill in Skillful-Alhazen is a complete vertical slice that enables Claude to work with a specific knowledge domain (job hunting, literature review, etc.). Each skill consists of three interconnected components and includes portability features to work across multiple AI agent frameworks:
┌─────────────────────────────────────────────────────────────────────────────┐
│ SKILL ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ (A) TypeDB Schema (B) Skill Definition (C) Dashboard │
│ ┌──────────────┐ ┌──────────────────┐ ┌────────────┐ │
│ │ <domain> │ │ SKILL.md │ │ Next.js │ │
│ │ .tql │◄────────────►│ <domain>.py │◄──────►│ Pages │ │
│ └──────────────┘ └──────────────────┘ └────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Defines types, Commands for Visual UI for │
│ attributes, ingestion, query, pipeline views, │
│ relations sensemaking matrices, etc. │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
| Component | Location | Purpose |
|---|---|---|
| TypeDB Schema | local_resources/typedb/namespaces/<domain>.tql |
Data model (entities, attributes, relations) |
| Skill Definition |
.claude/skills/<domain>/SKILL.md + <domain>.py
|
Claude's interface and CLI script |
| Dashboard (optional) |
dashboard/src/app/ + dashboard/src/lib/
|
Web UI for visualization and interaction |
The schema defines the data model for your domain. It extends the core Alhazen notebook schema with domain-specific types.
Location: local_resources/typedb/namespaces/<domain>.tql
What it defines:
- Attributes - Properties (strings, numbers, dates)
- Entities - Things, Artifacts, Fragments, Notes (domain subtypes)
- Relations - How entities connect
Example (jobhunt.tql):
define
# Attributes
job-url sub attribute, value string;
salary-range sub attribute, value string;
application-status sub attribute, value string;
# Entities - Things
jobhunt-company sub research-item,
owns company-url,
plays position-at-company:employer;
jobhunt-position sub research-item,
owns job-url,
owns salary-range,
plays position-at-company:position;
# Artifacts
jobhunt-job-description sub artifact;
# Fragments
jobhunt-requirement sub fragment,
owns skill-name,
owns skill-level;
# Notes
jobhunt-fit-analysis-note sub note,
owns fit-score,
owns fit-summary;
# Relations
position-at-company sub relation,
relates position,
relates employer;
Design principles:
- Extend core types (
research-item,artifact,fragment,note) - Prefix all types with
<domain>-for namespace isolation - Keep the schema focused on structure, not business logic
Reference: See Design Concepts for the Alhazen data model (Collection, Thing, Artifact, Fragment, Note).
The skill definition has two parts:
- SKILL.md - Instructions for Claude on how to use the skill
- Python script - CLI tool that handles TypeDB operations
Location: .claude/skills/<domain>/SKILL.md and .claude/skills/<domain>/<domain>.py
Tells Claude:
- When to use the skill (triggers)
- What commands are available
- How to perform sensemaking workflows
- Data model reference
Structure:
---
name: <domain>
description: One-line description
---
# <Domain> Skill
## Philosophy (how it follows curation pattern)
## Prerequisites
## Commands Reference
## Sensemaking Workflow (Claude's reasoning steps)
## Data Model
## TypeQL ExamplesHandles all TypeDB operations. Claude calls this script; the script talks to TypeDB.
Key design principles:
- JSON output to stdout (for parsing)
- Errors/progress to stderr
- argparse subcommands for each operation
- No parsing/sensemaking - scripts do data operations, Claude does reasoning
Script structure:
#!/usr/bin/env python3
"""Domain CLI - Description."""
import argparse
import json
from typedb.driver import TypeDB, SessionType, TransactionType
# Configuration
TYPEDB_HOST = os.getenv("TYPEDB_HOST", "localhost")
TYPEDB_DATABASE = os.getenv("TYPEDB_DATABASE", "alhazen_notebook")
def cmd_ingest(args):
"""Fetch and store raw content."""
# ... TypeDB insert operations ...
print(json.dumps({"success": True, "id": entity_id}))
def cmd_list(args):
"""Query and return entities."""
# ... TypeDB fetch operations ...
print(json.dumps({"success": True, "items": [...]}))
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command")
# ... define subcommands ...
commands[args.command](args)
if __name__ == "__main__":
main()Separation of concerns:
| Script Does | Claude Does |
|---|---|
| Fetch URLs | Read and comprehend content |
| Store raw artifacts | Extract entities and relations |
| Run TypeDB queries | Create notes with analysis |
| Return JSON data | Reason across multiple notes |
Visual web interface for data exploration. Not all skills need a dashboard.
Location:
- API routes:
dashboard/src/app/api/<domain>/ - Pages:
dashboard/src/app/<domain>/or inline in main pages - Client library:
dashboard/src/lib/<domain>.ts
┌────────────────────────────────────────────────────────────────────┐
│ DASHBOARD LAYER │
├────────────────────────────────────────────────────────────────────┤
│ │
│ Browser Next.js Server │
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ React │──HTTP GET───►│ API Route │────►│ lib/*.ts │ │
│ │ Pages │◄─────JSON────│ /api/... │◄────│ (calls │ │
│ └──────────┘ └──────────────┘ │ script) │ │
│ └────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ uv run python │ │
│ │ <domain>.py │ │
│ │ --command │ │
│ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ TypeDB │ │
│ └──────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
Wraps script calls for use by API routes:
import { exec } from 'child_process';
async function runCommand(args: string[]): Promise<CommandResult> {
const cmd = `uv run python "${SCRIPT_PATH}" ${args.join(' ')}`;
const { stdout } = await execAsync(cmd);
return JSON.parse(stdout);
}
export async function listPipeline(filters?: {...}) {
const args = ['list-pipeline'];
if (filters?.status) args.push('--status', filters.status);
return runCommand(args);
}Thin wrappers that call the client library:
// app/api/<domain>/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { listPipeline } from '@/lib/<domain>';
export async function GET(request: NextRequest) {
const data = await listPipeline();
return NextResponse.json(data);
}| View Type | Purpose | Example |
|---|---|---|
| Pipeline/Kanban | Track items through stages | Job applications by status |
| Matrix | Compare across dimensions | Skills × Positions |
| List + Detail | Browse and drill down | Papers in collection |
| Progress | Track completion | Learning plan |
| Stats/Cards | Key metrics | Fit scores, counts |
USER REQUEST
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ CLAUDE │
│ 1. Reads SKILL.md to understand available commands │
│ 2. Calls script commands for data operations │
│ 3. Performs sensemaking (reasoning, note creation) │
│ 4. Reports findings to user │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ Python Script │ │ Dashboard │
│ <domain>.py │ │ (for visual │
│ │ │ exploration) │
└──────────────┘ └──────────────────┘
│ │
└───────────────────┬────────────────────┘
▼
┌──────────────────┐
│ TypeDB │
│ │
│ Schema from │
│ <domain>.tql │
└──────────────────┘
Data flow:
- Ingestion: Script fetches raw content → stores as Artifact in TypeDB
- Sensemaking: Claude reads Artifact → creates Fragments and Notes in TypeDB (via script)
- Query: Script queries TypeDB → returns JSON to Claude/Dashboard
- Display: Dashboard calls script → renders in React components
-
Design the data model
- What entities do you track? (Map to Thing, Artifact, Fragment, Note)
- What attributes do they have?
- How do they relate?
-
Create the schema (
local_resources/typedb/namespaces/<domain>.tql)- Define attributes
- Define entity subtypes
- Define relations
- Load into TypeDB
-
Create the skill directory (
.claude/skills/<domain>/) -
Write the script (
<domain>.py)- Ingestion commands (fetch, store raw)
- Query commands (list, show)
- Update commands (status, tags)
- Output JSON, errors to stderr
-
Write SKILL.md
- Frontmatter (name, description)
- Philosophy/pattern explanation
- Prerequisites
- Command reference
- Sensemaking workflow
- Data model summary
-
Test the skill
- Manual CLI commands work
- Claude can invoke via skill
-
(Optional) Create dashboard
- Client library in
lib/<domain>.ts - API routes in
app/api/<domain>/ - UI components
- Client library in
A skill template is available at .claude/skills/_template/ with:
-
SKILL.md- SKILL.md boilerplate -
template.py- Script boilerplate -
schema.tql- TypeDB schema template -
README.md- Usage instructions
The jobhunt skill demonstrates all three components:
| Component | File | Description |
|---|---|---|
| Schema | local_resources/typedb/namespaces/jobhunt.tql |
Company, Position, Requirements, Notes |
| SKILL.md | .claude/skills/jobhunt/SKILL.md |
Curation workflow, commands |
| Script | .claude/skills/jobhunt/jobhunt.py |
20+ commands for job tracking |
| Dashboard | dashboard/src/app/ |
Pipeline, Skills Matrix, Learning Plan |
The epmc-search skill shows a simpler pattern:
| Component | File | Description |
|---|---|---|
| Schema | local_resources/typedb/namespaces/scilit.tql |
Paper, Citation, Author |
| SKILL.md | .claude/skills/epmc-search/SKILL.md |
Search commands, ingestion |
| Script | .claude/skills/epmc-search/epmc_search.py |
API search, paper storage |
| Dashboard | - | None (CLI-only) |
The APM skill demonstrates a complex domain model with no dashboard (CLI-only):
| Component | File | Description |
|---|---|---|
| Schema | local_resources/typedb/namespaces/apm.tql |
Cases, Genes, Variants, Diseases, Phenotypes, Drugs, Pathways |
| SKILL.md | .claude/skills/apm/SKILL.md |
Two-phase investigation workflow (diagnostic + therapeutic) |
| Script | .claude/skills/apm/apm.py |
35+ commands for rare disease investigation |
| Dashboard | - | None (CLI-only) |
The domain-modeling skill is a meta-skill with no script:
| Component | File | Description |
|---|---|---|
| Schema | - | N/A (uses existing) |
| SKILL.md | .claude/skills/domain-modeling/SKILL.md |
Design guidance, templates |
| Script | - | None (Claude follows instructions) |
| Dashboard | - | None |
# Start TypeDB
docker compose -f docker-compose-typedb.yml up -d
# Load schema (in TypeDB console)
docker exec -it alhazen-typedb /opt/typedb-all-linux-x86_64/typedb console
> database create test_db
> transaction test_db schema write
> source /schema/alhazen_notebook.tql
> commit
> transaction test_db schema write
> source /schema/namespaces/<domain>.tql
> commit# Test individual commands
uv run python .claude/skills/<domain>/<domain>.py --help
uv run python .claude/skills/<domain>/<domain>.py <command> --help
uv run python .claude/skills/<domain>/<domain>.py <command> [args]
# Run Python tests
uv run pytest tests/test_<domain>.py -vcd dashboard
npm install
npm run dev
# Open http://localhost:3000- Design Concepts - Curation pattern, 5-phase workflow
- Getting Started - Installation and setup
-
.claude/skills/domain-modeling/SKILL.md- Design guidance for Claude -
.claude/skills/_template/- Skill template files
Getting Started
Architecture
Core Skills
Domain Skills
- Skills: Scientific Literature
- Skills: ALG Precision Therapeutics
- Skills: Literature Trends
- Skills: They Said Whaaa
- Skills: DisMech
- Skills: Jobhunt
Links