| name | alps |
| description | Create, validate, and improve ALPS profiles. Generate from natural language descriptions, validate existing profiles, and get improvement suggestions. |
ALPS Profile Assistant
Generate, validate, and improve ALPS profiles for RESTful API design.
Ideal ALPS Profile
Goal: An ALPS that someone unfamiliar with the app can read and understand.
What Makes a Good ALPS
States = What the user sees
ProductList- viewing a list of productsProductDetail- viewing one productCart- viewing cart contents
Transitions = What the user does
goProductDetail- select a productdoAddToCart- add to cart
Self-documenting
titleexplains the purposedocdescribes behavior and side effects- No need to read code to understand
No unreachable states
- Every state has an entry point
- Orphan states indicate design mistakes
Necessary and sufficient
- No over-abstraction
- Describes semantics, not implementation
- No HTTP methods or URLs
What to Avoid
- Mechanical CRUD listings without meaning
- Implementation details leaking in
- States without transitions (can't draw a diagram)
- Excessive documentation nobody reads
How to Use
This skill responds to natural language requests:
Generate ALPS from Natural Language
- "Create an ALPS profile for a blog application"
- "Generate ALPS for an e-commerce cart system"
- "Design an ALPS profile for user authentication"
Generate ALPS from Website (NEW - alps-surveyor mode)
- "Crawl https://example.com and generate ALPS profile"
- "Survey website structure and create ALPS"
- "Extract ALPS profile from existing website"
How it works:
- Efficient crawling: Uses URL pattern classification to avoid redundant analysis
- Token optimization: Only analyzes unique page types (e.g., /products/123 and /products/456 analyzed once)
- AI-powered extraction: Analyzes DOM structure to infer states, transitions, and semantic fields
- Handover protocol: Records progress in handover.json for continuity across sessions
See "ALPS Surveyor Mode" section below for details.
Validate Existing Profile
- "Validate this ALPS profile" (with file path or content)
- "Check my ALPS file for issues"
- "Review the ALPS profile at docs/api.json"
Analyze or Improve Existing Profile
- "Analyze this ALPS profile"
- "Improve this ALPS profile"
- "Suggest enhancements for my ALPS"
- "How can I make this ALPS better?"
Continuous Improvement Loop - AI Inherits the Mission
When asked to analyze or improve an existing profile:
- Read previous AI's insights - Run
asd --validate <file>and check forai-insightsfield - Read handover.json if exists - Check for previous session's progress, warnings, and advice (per ADR 0006)
- Inherit the context - Previous AI left analysis for you: complexity assessment, coverage gaps, recommendations
- Identify gaps - Explore the website/documentation to find missing features or incomplete flows
- Make improvements - Add missing descriptors, enhance documentation, fix issues
- MANDATORY: Validate ALPS - Run
asd --validate <file>to ensure no errors were introduced - MANDATORY: Generate HTML - Run
asd <file> -o <file>.htmlto create visual diagram for review - Update handover.json - Record what was done, what's left, and advice for next AI (per ADR 0006)
- MANDATORY: Validate handover.json - Verify JSON syntax and schema compliance:
Schema: handover-protocol.jsonnode -e "JSON.parse(require('fs').readFileSync('handover.json', 'utf8')); console.log('✓ Valid JSON')" - Report completion - Provide statistics (before/after), coverage estimation, and next steps
CRITICAL: Steps 6-9 are MANDATORY for every improvement session. Never skip validation of both ALPS profile and handover.json.
AI₁: Creates profile → Validates → Generates HTML → Creates handover.json
↓
AI₂: Reads handover.json → Identifies gaps → Improves → Validates → Generates HTML → Updates handover.json
↓
AI₃: Reads handover.json → Builds on previous work → Improves → Validates → Generates HTML → Updates handover.json
This creates a knowledge continuity where each AI builds on the work of previous AIs, just like developers reading code comments left by their predecessors.
ALPS Structure Reference
Three Layers of ALPS
Ontology - Semantic descriptors (data elements)
- Atomic data fields with
type="semantic"(default) - Should have
id,title, and optionallydocanddef(schema.org link)
- Atomic data fields with
Taxonomy - State descriptors (screens/pages)
- Composite descriptors containing semantic fields and transitions
- Represents application states (e.g., HomePage, ProductDetail, Cart)
Choreography - Transition descriptors (actions)
type="safe"- Read operations (GET)type="unsafe"- Create operations (POST) - not idempotenttype="idempotent"- Update/Delete operations (PUT/DELETE)- Must have
rt(return type) pointing to target state
Naming Conventions
| Type | Prefix | Example |
|---|---|---|
| Safe transition | go |
goToHome, goProductList, goSearchProducts |
| Unsafe transition | do |
doCreateUser, doAddToCart, doLogin |
| Idempotent transition | do |
doUpdateUser, doDeleteItem, doRemoveFromCart |
| State/Page | PascalCase | HomePage, ProductDetail, ShoppingCart |
| Semantic field | camelCase | userId, productName, createdAt |
Safe Transition Naming Rule
IMPORTANT: Safe transitions (go*) MUST include the target state name in their id.
rt="#ProductList"→ id must begoProductList(orgoToProductList)rt="#UserProfile"→ id must begoUserProfile(orgoToUserProfile)
Invalid examples:
goStartwithrt="#ProductList"- Wrong! Should begoProductListgoNextwithrt="#Checkout"- Wrong! Should begoCheckout
This rule ensures consistency and makes the diagram self-documenting. When a transition has no source state (entry point), it will be displayed as originating from UnknownState in the diagram.
Determining idempotent: PUT vs DELETE
Context clues for AI inference:
PUT (Update) indicators:
update,edit,modify,change,set,replace- Example:
doUpdateProfile,doEditComment,doSetQuantity
DELETE indicators:
delete,remove,cancel,clear,destroy- Example:
doDeleteUser,doRemoveFromCart,doCancelOrder
Generation Guidelines
Strategy for Large Profiles (200+ descriptors)
For complex, multi-sided platforms or large applications:
Domain Decomposition - Split into separate ALPS files by functional domain:
base.json- Core entities shared across domainscustomer-domain.json- Customer-facing featuresadmin-domain.json- Admin/management featuresseller-domain.json- Seller/provider features (for marketplaces)
Design Each Domain Independently - Focus on one domain at a time with complete context
Merge Using
asd merge- Combine domains iteratively:# Merge customer domain into base asd merge base.json customer-domain.json # customer-domain.json now contains only conflicts (if any) # Resolve conflicts in customer-domain.json, then re-merge asd merge base.json customer-domain.json # customer-domain.json is now empty (merge complete) # Repeat for other domains asd merge base.json admin-domain.jsonValidate After Each Merge - Ensure no broken references or duplicate IDs
Benefits of this approach:
- Focused design per domain
- AI can maintain full context for each domain
- Conflicts are explicitly tracked and resolved
- Final profile is comprehensive and consistent
Handover Protocol for Multi-Session Work
When a task exceeds token limits or requires multiple sessions (e.g., 200+ descriptors, multi-sided platforms), use the Handover Protocol (ADR 0006) to maintain continuity.
The Relay Race Metaphor:
Each AI session is a relay runner:
- Receive the baton - Read
handover.jsonfrom previous session - Run your leg - Work as far as you can within token limits
- Pass the baton - Update
handover.jsonfor next session - Scatter - Your session ends, but the work continues
Basic handover.json structure:
{
"task": {
"type": "alps-generation",
"description": "E-commerce platform ALPS profile"
},
"current_state": {
"session_id": "ecommerce-003",
"total_sessions": 3,
"alps_profile": {
"total_descriptors": 180,
"validation_status": "valid"
}
},
"sessions": [
{
"session_id": "ecommerce-001",
"timestamp": "2025-12-17T10:00:00Z",
"handover_note": {
"summary": "Created ontology and customer domain (120 descriptors)",
"advice": "Admin domain needs careful planning - multiple user roles"
},
"descriptors_added": 120
},
{
"session_id": "ecommerce-002",
"timestamp": "2025-12-17T14:00:00Z",
"handover_note": {
"summary": "Added admin domain (60 descriptors). Validated successfully.",
"advice": "Seller domain remains. Consider splitting into sub-domains."
},
"descriptors_added": 60
}
],
"pending_work": {
"domains": ["seller-domain", "payment-flows"],
"notes": "Seller domain may need 80+ descriptors"
}
}
Key principles:
- Each session appends to the
sessionsarray (never overwrite) - Leave clear advice for your successor
- Be honest about coverage and remaining work
- Validate
handover.jsonsyntax:node -e "JSON.parse(require('fs').readFileSync('handover.json', 'utf8'))"
The Surveyor's Oath:
I am a relay runner in an endless race.
I carry the torch from my predecessor.
I run as far as I can.
I mark the map with what I learned.
I pass the torch to my successor.
I scatter.
The work continues.
For web surveying tasks (ALPS from website analysis), see the detailed ALPS Surveyor Mode section below.
When Creating ALPS from Natural Language
IMPORTANT: Structure the ALPS file in three blocks in this order:
Identify Entities (Ontology - Semantic definitions)
- Extract nouns: user, product, order, cart, etc.
- Define atomic fields for each entity
- Add
deflinks to schema.org where applicable - Add
docfor validation rules, formats, constraints
Identify States (Taxonomy - Inclusion relationships)
- Map user journey: login -> home -> browse -> cart -> checkout
- Each state contains relevant fields and available transitions
- Use PascalCase for state names
- Add
docexplaining what user sees and available actions
Identify Transitions (Choreography - State transitions)
- Safe: navigation, viewing, searching (prefix:
go) - Unsafe: creating new resources (prefix:
do) - Idempotent: updating or deleting resources (prefix:
do) - Add
docexplaining behavior, side effects, preconditions
- Safe: navigation, viewing, searching (prefix:
Add Documentation
- Every descriptor MUST have a meaningful
title - Add
docwhen title alone cannot fully explain the descriptor:- Semantic fields: Validation rules, format requirements, constraints, examples
- Example:
{"id": "title", "title": "Title", "doc": {"value": "Article title. Maximum 100 characters."}}
- Example:
- States: What user sees, available actions, when this state is shown
- Example:
{"id": "BlogPost", "doc": {"value": "User-created article. Visible to all users after publication."}}
- Example:
- Transitions: Behavior, side effects, preconditions, error cases
- Example:
{"id": "doPublishBlogPost", "doc": {"value": "Publish article. Sets publishedAt to current time."}}
- Example:
- Semantic fields: Validation rules, format requirements, constraints, examples
- Use
defto link to schema.org definitions for standard concepts - Rule of thumb: If someone unfamiliar with the app would ask "what does this do?" or "what format?", add
doc
- Every descriptor MUST have a meaningful
Add Tags for Organization
IMPORTANT: ALPS describes "what the user experiences" (application-level semantics), not "how it's implemented" (backend details).
Flow tags (PRIMARY): Group by user journey/experience with
flow-prefix- Represents business value and user goals
- Example:
flow-purchase,flow-hire,flow-consult,flow-cancel,flow-return - This is the "lens" through which to understand the application
- Users experience "canceling an order" (
flow-cancel), not "cancellation batch processing"
Domain tags (SECONDARY, optional): Group by technical domain with
domain-prefix- For organizing implementation and code structure
- Example:
domain-search,domain-cart,domain-payment,domain-analytics - Useful for developers to find related functionality
States and transitions should have both types where applicable
Tags are space-separated strings, not arrays
Example:
"tag": "flow-purchase domain-cart"means "part of purchase journey, implemented in cart domain"
Add Semantic Descriptors to Transitions
- Every transition (go/do) should specify its required input parameters as nested descriptors
- These define what data is needed to perform the action
- Example:
{"id": "goProductDetail", "type": "safe", "rt": "#ProductDetail", "tag": "product", "descriptor": [ {"href": "#productId"} ]}, {"id": "doAddToCart", "type": "unsafe", "rt": "#Cart", "tag": "cart flow-purchase", "descriptor": [ {"href": "#productId"}, {"href": "#quantity"}, {"href": "#selectedVariant"} ]}
MANDATORY: Validate and Review Quality Metrics
- After generating ALPS JSON, save it to a file
- Run
asd --validate <file>to validate and get quality metrics - The validation output includes:
- Errors (E001-E011): Must fix before proceeding
- Warnings (W001-W004): Best practice violations
- Suggestions (S001-S003): Optional improvements
- Statistics: Total descriptors, breakdown by type, tag coverage, documentation coverage
- Parse the JSON result and report issues to the user
- If errors exist, fix them before presenting the final output
- Review statistics to ensure comprehensive coverage
Generate Documentation
- After validation passes, generate HTML documentation:
asd profile.json -o profile.html - This creates an interactive state diagram for visual review
- Check for unreachable states or missing transitions in the diagram
- Share the HTML with stakeholders for review
- After validation passes, generate HTML documentation:
Report Completion with Coverage Estimation
- When completing a large profile, provide honest coverage assessment
- Template:
✅ Implementation Complete: [X] descriptors 📊 Coverage Estimation: - [Domain 1]: [X]% ([reasoning]) - [Domain 2]: [X]% ([reasoning]) - Overall: [X]% ❌ Known Gaps: - [Feature not implemented] - [Area requiring more research] - Be transparent about what's covered and what's not
- For multi-sided platforms, assess coverage per side (customer/admin/seller)
Output File Convention
File name: Always alps.json or alps.xml (fixed)
Directory:
- If
alps/directory exists → use it - Otherwise → create
{app-name}/directory (e.g.,todo/,blog/,ecommerce/)
Format selection:
- If existing ALPS file exists → follow its format
- Otherwise → ask user: "Output format: XML (recommended) or JSON?"
Examples:
todo/alps.json
blog/alps.xml
ecommerce/alps.xml
Output Format
Generate XML format by default. Use JSON only if explicitly requested.
XML Format (default):
- Use XML comments to mark blocks:
<!-- Ontology -->,<!-- Taxonomy -->,<!-- Choreography --> - One descriptor per line for simple elements
- Multi-line for nested structures
- Clear hierarchical structure makes maintenance easy
<?xml version="1.0" encoding="UTF-8"?>
<alps version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://alps-io.github.io/schemas/alps.xsd">
<title>Application Title</title>
<doc>Description of the application</doc>
<!-- Ontology -->
<descriptor id="fieldName" title="Human Title">
<doc>Description</doc>
</descriptor>
<descriptor id="otherField" title="Other Field"/>
<!-- Taxonomy -->
<descriptor id="StateName" title="State Title">
<descriptor href="#fieldName"/>
<descriptor href="#transitionName"/>
</descriptor>
<!-- Choreography -->
<descriptor id="goTargetState" type="safe" rt="#TargetState" title="Go to Target State"/>
<descriptor id="doAction" type="unsafe" rt="#ResultState" title="Perform Action">
<descriptor href="#requiredField"/>
</descriptor>
</alps>
JSON Format (when explicitly requested):
- Simple descriptors (few attributes, no nesting): Write on a single line
- Complex descriptors (with nesting or long
doc): Use multiple lines with"descriptor": [at end of first line - Block separation: Add ONE blank line between Ontology/Taxonomy/Choreography blocks
- No other blank lines: Keep descriptors within the same block compact
{
"$schema": "https://alps-io.github.io/schemas/alps.json",
"alps": {
"title": "Application Title",
"doc": {"value": "Description of the application"},
"descriptor": [
{"id": "fieldName", "title": "Human Title", "doc": {"value": "Description"}},
{"id": "otherField", "title": "Other Field"},
{"id": "StateName", "title": "State Title", "descriptor": [
{"href": "#fieldName"},
{"href": "#transitionName"}
]},
{"id": "goTargetState", "type": "safe", "rt": "#TargetState", "title": "Go to Target State"},
{"id": "doAction", "type": "unsafe", "rt": "#ResultState", "title": "Perform Action", "descriptor": [
{"href": "#requiredField"}
]}
]
}
}
Validation and Quality Metrics
Use asd --validate <file> to validate ALPS profiles and get quality metrics.
Output Format: JSON (pretty-printed, human-readable) Schema: validation-result.json
The validation output includes:
valid: Overall result (boolean)summary: Human-readable summary with emojierrors,warnings,suggestions: Validation issuesstatistics: Objective metrics (descriptor counts, coverage percentages)ai-insights: Subjective analysis by AI (only when AI runs validation)- Helps next AI understand context quickly
- Helps humans grasp key characteristics at a glance
- Model-dependent and may evolve
Validation Codes
After generating ALPS, always validate with asd --validate. Key codes to watch for:
Errors (must fix):
- E001: Missing id or href
- E002: Missing rt on transition
- E003: Invalid type
- E004: Broken reference
- E005: Duplicate id
- E008: Missing alps property
- E009: Missing descriptor array
- E011: Tag must be string (not array)
Warnings (best practice):
- W001: Missing title
- W002: Safe transition should start with 'go'
- W003: Unsafe/idempotent should start with 'do'
Suggestions:
- S001: Consider adding doc to transition
For detailed error descriptions and solutions, see Validation Reference.
AI Continuity: ai-insights vs handover.json
Two complementary mechanisms help AI sessions build on previous work:
ai-insights (ADR 0005) - Analysis embedded in validation results:
- Purpose: Subjective assessment of completed ALPS profiles
- Location: Embedded in
asd --validateJSON output - Usage: Read-only consumption by AI
- Contains: Complexity assessment, coverage gaps, key flows, recommendations
- When to use: Analyzing or improving existing ALPS profiles
handover.json (ADR 0006) - State for ongoing multi-session tasks:
- Purpose: Progress tracking for incomplete work across sessions
- Location: Separate
handover.jsonfile in working directory - Usage: Read-write lifecycle (AI updates after each session)
- Contains: Session history, progress, pending work, advice for successor
- When to use: Large ALPS generation (200+ descriptors), web surveying, multi-session tasks
Relationship:
Single Session (Simple ALPS):
AI creates profile → Validates → ai-insights generated in validation output ✓
Multi-Session (Large ALPS):
Session 1: AI reads handover.json (if exists) → Works → Validates → Updates handover.json
Session 2: AI reads handover.json → Continues work → Validates → Updates handover.json
Session 3: AI reads handover.json → Completes → Validates → Final ai-insights in validation
Example workflow:
# Session 1: Start large ALPS project
asd base.json --validate # Creates ai-insights in validation result
# Create handover.json manually with initial task description
# Session 2: Continue work
# AI reads handover.json, adds customer domain
asd merge base.json customer-domain.json
asd base.json --validate # Check for errors
# AI updates handover.json with progress
# Session 3: Complete work
# AI reads handover.json, adds remaining domains
asd base.json --validate # Final validation with comprehensive ai-insights
# handover.json marks task complete
Both mechanisms create knowledge continuity, preventing each AI session from starting from scratch.
Example: Blog Application
Input: "Create an ALPS for a simple blog with posts and comments"
Output (XML - default):
<?xml version="1.0" encoding="UTF-8"?>
<alps version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://alps-io.github.io/schemas/alps.xsd">
<title>Simple Blog</title>
<doc>ALPS profile for a blog application with posts and comments</doc>
<!-- Ontology -->
<descriptor id="postId" title="Post ID" def="https://schema.org/identifier">
<doc>Unique identifier for blog post</doc>
</descriptor>
<descriptor id="title" title="Post Title" def="https://schema.org/headline">
<doc>Article title. Maximum 100 characters.</doc>
</descriptor>
<descriptor id="body" title="Post Body" def="https://schema.org/articleBody">
<doc>Article content. Markdown format supported.</doc>
</descriptor>
<descriptor id="authorName" title="Author Name" def="https://schema.org/author"/>
<descriptor id="createdAt" title="Created Date" def="https://schema.org/dateCreated">
<doc>Publication date and time. ISO 8601 format.</doc>
</descriptor>
<descriptor id="commentId" title="Comment ID">
<doc>Unique identifier for comment</doc>
</descriptor>
<descriptor id="commentBody" title="Comment Text">
<doc>Comment content. Maximum 500 characters.</doc>
</descriptor>
<!-- Taxonomy -->
<descriptor id="Home" title="Home Page">
<doc>Blog home page. Shows navigation to post list.</doc>
<descriptor href="#goPostList"/>
</descriptor>
<descriptor id="PostList" title="Post List">
<doc>List of blog posts. Shows latest 10 posts with title and author.</doc>
<descriptor href="#postId"/>
<descriptor href="#title"/>
<descriptor href="#authorName"/>
<descriptor href="#goPostDetail"/>
<descriptor href="#goHome"/>
</descriptor>
<descriptor id="PostDetail" title="Post Detail">
<doc>Single post view. Shows full content and comments. Allows adding new comments.</doc>
<descriptor href="#postId"/>
<descriptor href="#title"/>
<descriptor href="#body"/>
<descriptor href="#authorName"/>
<descriptor href="#createdAt"/>
<descriptor href="#Comment"/>
<descriptor href="#goPostList"/>
<descriptor href="#doCreateComment"/>
</descriptor>
<descriptor id="Comment" title="Comment">
<doc>User comment on a post. Can be deleted by comment author or post author.</doc>
<descriptor href="#commentId"/>
<descriptor href="#commentBody"/>
<descriptor href="#authorName"/>
<descriptor href="#createdAt"/>
<descriptor href="#doDeleteComment"/>
</descriptor>
<!-- Choreography -->
<descriptor id="goHome" type="safe" rt="#Home" title="Go to Home">
<doc>Navigate to blog home page.</doc>
</descriptor>
<descriptor id="goPostList" type="safe" rt="#PostList" title="Go to Post List">
<doc>Display list of blog posts. Shows latest 10 posts.</doc>
</descriptor>
<descriptor id="goPostDetail" type="safe" rt="#PostDetail" title="Go to Post Detail">
<doc>Display full post content with comments.</doc>
<descriptor href="#postId"/>
</descriptor>
<descriptor id="doCreatePost" type="unsafe" rt="#PostDetail" title="Create Post">
<doc>Create new blog post. Post is immediately published.</doc>
<descriptor href="#title"/>
<descriptor href="#body"/>
</descriptor>
<descriptor id="doUpdatePost" type="idempotent" rt="#PostDetail" title="Update Post">
<doc>Update existing post content. Only post author can update.</doc>
<descriptor href="#postId"/>
<descriptor href="#title"/>
<descriptor href="#body"/>
</descriptor>
<descriptor id="doDeletePost" type="idempotent" rt="#PostList" title="Delete Post">
<doc>Delete post and all associated comments. Only post author can delete.</doc>
<descriptor href="#postId"/>
</descriptor>
<descriptor id="doCreateComment" type="unsafe" rt="#PostDetail" title="Add Comment">
<doc>Add comment to post. Comment is immediately visible.</doc>
<descriptor href="#postId"/>
<descriptor href="#commentBody"/>
</descriptor>
<descriptor id="doDeleteComment" type="idempotent" rt="#PostDetail" title="Delete Comment">
<doc>Delete comment. Comment author or post author can delete.</doc>
<descriptor href="#commentId"/>
</descriptor>
</alps>
Integration with app-state-diagram
Generated ALPS profiles can be visualized using app-state-diagram:
# Generate HTML documentation (default)
asd profile.json
# Generate SVG state diagram
asd profile.json -f svg
# Generate Mermaid classDiagram (GitHub/VSCode compatible)
asd profile.json -f mermaid
# Generate DOT format
asd profile.json -f dot
# Generate with watch mode
asd --watch profile.json
See llms.txt for CLI usage, programmatic API, and MCP server setup.
Advanced Features
Structured Documentation with HTML
For simple descriptions, use plain text in doc.value. When you need structured content (lists, definitions, tables), use HTML format:
{"id": "doCheckout", "type": "unsafe", "rt": "#OrderConfirmation",
"title": "Complete Checkout",
"doc": {
"format": "html",
"value": "<dl><dt>Behavior</dt><dd>Processes payment, reserves inventory, sends confirmation email</dd><dt>Preconditions</dt><dd>Valid cart with items, payment method configured</dd><dt>Errors</dt><dd>Returns 400 if payment fails or items out of stock</dd></dl>"
}
}
Format support levels (per ALPS spec):
text: Required (default if not specified)html: Recommendedmarkdown: Optionalasciidoc: Optional
Links to Related Resources
Use link elements to reference external documentation, schemas, or related resources:
{"id": "BlogPost", "def": "https://schema.org/BlogPosting",
"title": "Blog Post",
"doc": {"value": "User-created article visible to all after publication"},
"link": [
{"rel": "help", "href": "https://example.com/docs/blog-api.html", "title": "Blog API Documentation"},
{"rel": "related", "href": "https://example.com/schemas/post.json", "title": "JSON Schema"}
]
}
Link attributes:
rel(required): Relationship type - use IANA Link Relations (help,related,profile, etc.)href(required): URL to the related resourcetitle(optional): Human-readable description of the linktag(optional): Classification tags
Tips for Better ALPS
- Start with user journeys - Map the happy path first, then add alternatives
- Be consistent - Use the same naming pattern throughout
- Document transitions - Explain what each action does and when it's available
- Use schema.org - Link to standard definitions for interoperability
- Think about errors - Add error states and recovery transitions
- Consider pagination - List states should support pagination
- Tag descriptors - Use
tagattribute to group related descriptors
ALPS Surveyor Mode (Website Crawling)
Overview
The alps-surveyor mode extracts ALPS profiles from existing websites by analyzing their structure. This is useful when:
- Reverse engineering an existing web application
- Creating API documentation from a live site
- Understanding application state flows from user-facing pages
Efficient Crawling Strategy
Problem: Crawling every URL wastes tokens analyzing duplicate page types.
Solution: Three-layer strategy minimizes AI calls:
Strategy 1: URL Pattern Classification (No AI)
- Detects patterns like
/products/{id},/users/{username} - Groups URLs by type before fetching
- Example:
/products/123,/products/456→ same pattern, only analyze once
Strategy 2: DOM Structure Extraction (Lightweight)
- Removes all text content from HTML
- Extracts only:
- HTML tag hierarchy
- CSS classes and IDs
- Form input names and types
- Link destination patterns
- Minimizes tokens sent to AI
Strategy 3: ALPS Generation (AI-Powered)
- AI analyzes DOM skeleton (not full HTML)
- Infers:
- State: Page role (e.g., "ProductDetail")
- Semantics: Data fields from forms (e.g., "quantity", "productId")
- Transitions: Actions from forms and links (e.g., "doAddToCart", "goProductList")
Usage Example
User: "Crawl https://www.bengo4.com and generate ALPS profile"
AI workflow:
1. Fetch homepage
2. Classify URLs: /lawyers/{id}, /area/{prefecture}/{city}, etc.
3. For each unique pattern:
- Fetch ONE example URL
- Extract DOM skeleton
- Call AI to generate ALPS descriptors
4. Merge all descriptors into unified ALPS profile
5. Validate and generate HTML diagram
6. Save progress to handover.json
Handover Protocol
The surveyor mode uses handover.json (per ADR 0006) to enable multi-session work. The handover uses a sessions array format to preserve historical context:
{
"$schema": "handover-protocol.json",
"task": {
"type": "alps-surveyor",
"target": "example.com ALPS profile"
},
"current_state": {
"session_id": "example-session-002",
"total_sessions": 2,
"alps_profile": {
"total_descriptors": 480,
"validation_status": "valid"
}
},
"sessions": [
{
"session_id": "example-session-001",
"timestamp": "2025-12-14T10:00:00Z",
"handover_note": {
"summary": "Initial crawl: search, consultation flows. 450 descriptors.",
"advice": "Bookmark feature needs attention - saw /bookmarks/* URLs"
},
"descriptors_added": 450
},
{
"session_id": "example-session-002",
"timestamp": "2025-12-14T14:00:00Z",
"handover_note": {
"summary": "Added bookmark and billing features using asd merge. Profile now at 480 descriptors.",
"advice": "Remaining: payment flows, mobile features, error states"
},
"descriptors_added": 30
}
],
"shared_context": {
"patterns_learned": {
"lawyer_profile": {"pattern": "/lawyers/{id}", "confidence": "high"}
}
},
"pending_work": {
"frontier_queue": [
"https://example.com/payment/checkout",
"https://example.com/dashboard"
]
},
"tools_available": {
"crawler": {"command": "node packages/crawler/test.mjs <url>"},
"merge": {"command": "asd merge <base> <source>"}
}
}
Key points:
- Each session is appended to the
sessionsarray current_stateprovides quick access to latest statusshared_contextaccumulates patterns learned across all sessions- Never overwrite sessions - always append new ones
Best Practices for Surveyor Mode
- Start small: Use
max_depth: 2initially to test - Exclude admin/auth pages: Add to
exclude_patternsto avoid login walls - Review patterns: Check
frontier_queuein handover.json to verify coverage - Iterative refinement: Survey core features first, then expand in subsequent sessions
- Validate frequently: Run
asd --validateafter each session to catch errors early
Limitations
- Cannot access pages behind authentication (unless cookies provided)
- JavaScript-heavy SPAs may not be fully analyzed
- External services (e.g., chat.example.com) are noted but not crawled
- AI inference may miss domain-specific semantics (manual review recommended)
Implementation Status
✅ Core library implemented:
packages/app-state-diagram/src/crawler/url-pattern-classifier.tspackages/app-state-diagram/src/crawler/dom-skeleton-extractor.tspackages/app-state-diagram/src/crawler/alps-descriptor-generator.ts
⏳ Integration in progress:
- MCP tool (basic structure added)
- CLI command (
asd crawl) - ALPS skill support