Automated summary
Development guide for the modular lemline-runner ecosystem (Quarkus/Kotlin), covering the module architecture, commands/events messaging, feature modules and Flyway migrations.
Strengths
- Clear map of the modules (common, main runner, definitions, waits, retries, parents, forks, schedules, listeners, failures) with their associated tables
- Points to the right documentation or source file per task (module README, runner-messaging.md, WorkflowState.kt, WorkflowCommandHandler.kt)
- Covers concrete infrastructure concerns: dual-channel messaging, the outbox pattern, coroutine-based repositories
Limitations
- Tightly coupled to the lemline repository and unusable outside that codebase
- The provided text cuts off mid-section on event handling, so some references are incomplete
- Assumes prior familiarity with Quarkus, Kotlin and relational databases
Use when modifying or debugging a lemline-runner-* module, adding a command/event type, or writing a Flyway migration inside this repository.
Avoid it for unrelated Quarkus projects or workflow engines that are not part of the lemline ecosystem.
Security analysis
SafeThis is a documentation/development guide for a Kotlin/Quarkus workflow runner. It contains no executable commands, network calls, credential handling, destructive operations, or instructions to bypass safety controls.
No concerns found
How this analysis is madeExamples
I need to add a new command type for the waits module in lemline-runner. Walk me through updating WorkflowState.kt and WorkflowCommandHandler.kt, the corresponding event flow, and any Flyway migration needed for lemline_waits.Explain the dual-channel architecture and the outbox pattern in lemline-runner-common, and show how a command published by the main runner reaches a feature module like lemline-runner-retries.Read lemline-runner-schedules/README.md and help me implement support for cron-based schedules in the lemline_schedules table, including the repository layer with Kotlin coroutines.name: runner-dev description: Development guide for the lemline-runner ecosystem. Use when working with the modular runner architecture (lemline-runner-* modules), messaging (commands/events channels), feature modules (waits, retries, parents, schedules, listeners, forks, failures), shared infrastructure (lemline-runner-common), CLI commands, configuration, repositories with Kotlin coroutines, or Flyway migrations. Covers the dual-channel architecture, outbox pattern, and production best practices for the Quarkus/Kotlin runtime.
Lemline Runner Development Guide
Purpose
Guide development across the modular lemline-runner ecosystem - a collection of feature-focused modules built on shared infrastructure. The main lemline-runner module provides messaging, CLI, and configuration, while feature modules (lemline-runner-*) implement specific workflow capabilities.
Core Documentation:
- Main Runner README - Configuration, database, messaging setup
- CLI Commands
- Configuration
- Messaging Architecture
- Database Tables
- Repositories Guide
Module Architecture
Core Infrastructure
| Module | Purpose |
|--------|---------|
| lemline-runner-common | Shared infrastructure: outbox pattern, cleaner pattern, repository abstractions, model interfaces |
| lemline-runner | Main runtime: messaging (commands/events), CLI, configuration, activity runners |
Feature Modules
| Module | Purpose | Tables |
|--------|---------|--------|
| lemline-runner-definitions | Workflow definition storage and cache sync | lemline_definitions |
| lemline-runner-waits | Wait/sleep task implementation | lemline_waits |
| lemline-runner-retries | Task retry scheduling with exponential backoff | lemline_retries |
| lemline-runner-parents | Parent-child workflow relationships (run task) | lemline_parents |
| lemline-runner-forks | Parallel branch execution (fork task) | lemline_forks, lemline_fork_branches |
| lemline-runner-schedules | Scheduled workflow execution (cron/interval/after) | lemline_schedules |
| lemline-runner-listeners | CloudEvent listeners (listen task) | lemline_listeners, lemline_listener_events |
| lemline-runner-failures | Failed workflow tracking and dead letter storage | lemline_failures |
Each feature module has its own README.md with detailed architecture, file reference, and usage patterns.
Quick Reference
If you need to work on...
A Specific Feature:
Read the module's README first:
- Wait task → lemline-runner-waits/README.md
- Retry logic → lemline-runner-retries/README.md
- Parent-child workflows → lemline-runner-parents/README.md
- Fork/parallel execution → lemline-runner-forks/README.md
- Scheduled workflows → lemline-runner-schedules/README.md
- CloudEvent listeners → lemline-runner-listeners/README.md
- Failure tracking → lemline-runner-failures/README.md
- Definition storage → lemline-runner-definitions/README.md
Messaging:
First, read runner-messaging.md
- Add a new command/event type → Modify WorkflowState.kt
- Update commands behavior → Modify WorkflowCommandHandler.kt
- Update events behavior → Modify WorkflowEventHandler.kt
Shared Infrastructure:
Read lemline-runner-common/README.md first
- Add new outbox processor → Extend
AbstractOutbox<T>in lemline-runner-common - Add new cleaner → Extend
AbstractCleaner<T>in lemline-runner-common - Add repository operations → Add to
lemline-runner-common/repositories/ops/ - Add model interface → Create in
lemline-runner-common/models/
Configuration:
First read runner-configuration.md
- Add/Update config property → Modify LemlineConfiguration.kt
- Add database/broker type → Read runner-configuration.md
CLI:
First read runner-cli.md
Critical Rules
✅ ALWAYS Do This
- Use
suspendfunctions for all database operations (Kotlin coroutines, NOT Mutiny) - Use native SQL via repositories (NOT Hibernate ORM/Panache)
- Use Flyway migrations for all schema changes
- Support all databases (PostgreSQL, MySQL, H2) - use database-agnostic SQL
- Use
FOR UPDATE SKIP LOCKEDfor outbox queries to prevent double-processing - Use IDV7 (UUID v7) for all entity IDs - time-sortable, globally unique
- Test with all supported databases when touching persistence layer
❌ NEVER Do This
- Use Mutiny (Uni/Multi) - use Kotlin coroutines with
suspendfunctions instead - Use Hibernate ORM/Panache - use native SQL with repositories
- Block the event loop - all I/O must be non-blocking
- Skip database migrations - never modify tables directly
- Use database-specific SQL without providing variants for all databases
- Commit sensitive data (.env, credentials, API keys)
Architecture Overview
Modular Feature Design
┌────────────────────────────────────────────────────────────────────┐
│ lemline-runner (core) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Messaging │ │ CLI Commands │ │ Configuration │ │
│ │ (commands/events)│ │ (Picocli) │ │ (Quarkus) │ │
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
│
┌───────────────┴────────────────┐
│ lemline-runner-common │
│ (shared infrastructure) │
│ • Outbox pattern │
│ • Cleaner pattern │
│ • Repository abstractions │
│ • Model interfaces │
└───────────────┬────────────────┘
│
┌───────────────────────┼────────────────────────┐
│ │ │
┌───────▼──────┐ ┌───────────▼──────┐ ┌────────────▼─────┐
│ Feature │ │ Feature │ │ Feature │
│ Modules │ │ Modules │ │ Modules │
│ │ │ │ │ │
│ • waits │ │ • schedules │ │ • definitions │
│ • retries │ │ • listeners │ │ • failures │
│ • parents │ │ │ │ │
│ • forks │ │ │ │ │
└──────────────┘ └───────────────────┘ └──────────────────┘
Dual-Channel Messaging
┌─────────────────────────────────────────────────────────────────────────────┐
│ COMMANDS CHANNEL (high-throughput) │
│ commands ──► WorkflowCommandHandler ──► commands │
│ ▲ │ │
│ │ │ (needs persistence) │
└───────│─────────────────│───────────────────────────────────────────────────┘
│ │
┌───────│─────────────────│───────────────────────────────────────────────────┐
│ │ ▼ EVENTS CHANNEL │
│ │ events ──► WorkflowEventHandler ──► Feature Modules │
│ │ │ │
│ │ ┌─────────┴─────────┐ │
│ │ ▼ ▼ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │
│ │ │ Feature Service │ │ Feature Service │ │
│ │ │ (e.g., Waits) │ │ (e.g., Parents) │ │
│ │ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │
│ │ │ DB Table │ │ DB Table │ │
│ │ │ (lemline_waits) │ │(lemline_parents)│ │
│ │ └────────┬────────┘ └─────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ │ │ Outbox Relay │ │
│ └──────────────│ (scheduled poll)│ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
Key principle: State travels with messages. Database only used when necessary. Each feature is self-contained.
Key Files
| Purpose | File | |-------------------|-----------------------------------------------------------------------------------------------------------------------------| | Step execution | StepByStepRunner.kt | | Command handling | WorkflowCommandHandler.kt | | Event handling | WorkflowEventHandler.kt | | Message structure | InstanceMessage.kt | | Outbox base | AbstractOutbox.kt | | Cleaner base | AbstractCleaner.kt |
Common Patterns
Creating a New Feature Module
1. Module Structure:
lemline-runner-myfeature/
├── src/
│ ├── main/kotlin/com/lemline/runner/myfeature/
│ │ ├── MyFeatureService.kt ← Business logic
│ │ ├── MyFeatureModel.kt ← Database entity
│ │ ├── MyFeatureRepository.kt ← Database operations
│ │ ├── MyFeatureOutbox.kt ← Outbox processor (optional)
│ │ ├── MyFeatureCleaner.kt ← Cleanup scheduler (optional)
│ │ └── MyFeatureConfig.kt ← Configuration
│ ├── test/kotlin/ ← Tests for all databases
│ └── testFixtures/kotlin/ ← Test utilities
├── build.gradle.kts
└── README.md ← Architecture and usage
2. Dependencies in build.gradle.kts:
dependencies {
implementation(project(":lemline-common"))
implementation(project(":lemline-core"))
implementation(project(":lemline-runner-common")) // Always required!
// Add other feature modules if needed
}
3. Model with Interfaces:
// Compose behavior from lemline-runner-common interfaces
data class MyFeatureModel(
override val id: IDV7,
override val instanceMessage: InstanceMessage<MyEvent>,
// Outbox fields
override val outboxScheduledFor: Instant,
override var outboxDelayedUntil: Instant? = outboxScheduledFor,
override var outboxAttemptCount: Int = 0,
override var outboxCompletedAt: Instant? = null,
override var outboxFailedAt: Instant? = null,
// ... other outbox fields
// Cleanup field
override var cleanupAfter: Instant? = null,
) : WithId, WithInstanceMessage, WithOutbox, WithCleanup
4. Repository:
@ApplicationScoped
class MyFeatureRepository : Repository<MyFeatureModel>(),
WithIdRepository<MyFeatureModel>,
OutboxRepository<MyFeatureModel>,
CleanerRepository<MyFeatureModel> {
override suspend fun findByUUID(uuid: IDV7): MyFeatureModel? {
// Use pool from base Repository
return pool.withConnection { conn ->
conn.preparedQuery("SELECT * FROM lemline_myfeature WHERE id = $1")
.execute(Tuple.of(uuid.value))
.awaitSuspending()
.firstOrNull()
?.let { MyFeatureModel.fromRow(it) }
}
}
// OutboxRepository provides findPendingWithLock() automatically
// CleanerRepository provides findOldCompleted() automatically
}
5. Service:
@ApplicationScoped
class MyFeatureService @Inject constructor(
private val repository: MyFeatureRepository,
private val commandEmitter: CommandEmitter
) {
suspend fun handleMyEventStarted(message: InstanceMessage<MyEventStarted>) {
val model = MyFeatureModel.from(message)
repository.insert(model)
}
}
6. Outbox (if needed):
@ApplicationScoped
class MyFeatureOutbox @Inject constructor(
private val repository: MyFeatureRepository,
private val emitter: WorkflowCommandEmitter,
private val config: MyFeatureConfig
) : AbstractOutbox<MyFeatureModel>(
name = "MyFeature",
config = config.outbox
) {
override suspend fun findEntitiesToProcess(limit: Int) =
repository.findPendingWithLock(limit)
override suspend fun process(entity: MyFeatureModel) {
emitter.send(createResumeCommand(entity))
}
override suspend fun markCompleted(entity: MyFeatureModel) {
repository.markCompleted(entity.id)
}
}
7. Register in WorkflowEventHandler:
// In lemline-runner/src/.../messaging/events/WorkflowEventHandler.kt
when (val state = message.state) {
is MyEventStarted -> myFeatureService.handleMyEventStarted(message)
// ...
}
Event Handling Pattern
// In feature module service
suspend fun handleMyEvent(message: InstanceMessage<MyEvent>) {
val event = message.state
// 1. Create model from event
val model = MyFeatureModel.from(message, event)
// 2. Persist to database
repository.insert(model)
// 3. If immediate resume needed (no outbox), emit command
if (!needsDelay) {
commandEmitter.send(createResumeCommand(message))
}
// Otherwise, outbox processor will handle it later
}
Testing Patterns
Multi-Database Repository Test
Test all 3 databases: PostgreSQL, MySQL, H2
// Base test with test logic
abstract class MyRepositoryTestBase : FunSpec({
lateinit var repository: MyRepository
test("should find by UUID") {
val model = createTestModel()
repository.insert(model)
val found = repository.findByUUID(model.id)
found shouldNotBe null
found?.id shouldBe model.id
}
})
// PostgreSQL test
@QuarkusTest
@TestProfile(PostgresProfile::class)
class MyRepositoryPostgresTest : MyRepositoryTestBase() {
@Inject
override lateinit var repository: MyRepository
}
// MySQL test
@QuarkusTest
@TestProfile(MySQLProfile::class)
class MyRepositoryMySQLTest : MyRepositoryTestBase() {
@Inject
override lateinit var repository: MyRepository
}
// H2 test
@QuarkusTest
@TestProfile(H2Profile::class)
class MyRepositoryH2Test : MyRepositoryTestBase() {
@Inject
override lateinit var repository: MyRepository
}
Feature Service Test
@QuarkusTest
class MyFeatureServiceTest : FunSpec({
@Inject
lateinit var service: MyFeatureService
@Inject
lateinit var repository: MyFeatureRepository
test("should handle event") {
val message = createTestMessage()
service.handleMyEvent(message)
// Verify database state
val stored = repository.findByUUID(message.workflowId)
stored shouldNotBe null
}
})
Outbox Test
@QuarkusTest
class MyFeatureOutboxTest : FunSpec({
@Inject
lateinit var outbox: MyFeatureOutbox
@Inject
lateinit var repository: MyFeatureRepository
test("should process pending entities") {
// Insert pending entity
val model = createPendingModel()
repository.insert(model)
// Process
outbox.doWork()
// Verify marked completed
val processed = repository.findByUUID(model.id)
processed?.outboxCompletedAt shouldNotBe null
}
})
Database Migrations
IMPORTANT: Place migrations in the feature module, not in lemline-runner!
Location in Feature Module
lemline-runner-myfeature/
└── src/main/resources/db/migration/
├── postgresql/
│ └── V{N}__Create_myfeature_table.sql
├── mysql/
│ └── V{N}__Create_myfeature_table.sql
└── h2/
└── V{N}__Create_myfeature_table.sql
Naming: V{N}__Description.sql where N is the next available version number across all modules.
Check existing versions first:
# Find highest version number
find . -name "V*.sql" | sort
Migration Template
-- PostgreSQL version
CREATE TABLE lemline_myfeature
(
id UUID PRIMARY KEY,
-- Instance message (serialized workflow state)
instance_message TEXT NOT NULL,
-- Feature-specific columns
my_custom_field VARCHAR(255),
-- Outbox columns (if using outbox pattern)
outbox_scheduled_for TIMESTAMP NOT NULL,
outbox_delayed_until TIMESTAMP NOT NULL,
outbox_attempt_count INT NOT NULL DEFAULT 0,
outbox_completed_at TIMESTAMP,
outbox_failed_at TIMESTAMP,
outbox_error_class VARCHAR(255),
outbox_error_message VARCHAR(500),
outbox_error_stacktrace TEXT,
-- Cleanup column (if using cleaner pattern)
cleanup_after TIMESTAMP,
-- Timestamps
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Index for outbox queries (FOR UPDATE SKIP LOCKED)
CREATE INDEX idx_lemline_myfeature_pending
ON lemline_myfeature (outbox_delayed_until)
WHERE outbox_completed_at IS NULL AND outbox_failed_at IS NULL;
-- Index for cleanup queries
CREATE INDEX idx_lemline_myfeature_cleanup
ON lemline_myfeature (cleanup_after)
WHERE cleanup_after IS NOT NULL;
Database-Specific Considerations
PostgreSQL:
- Use
UUIDtype - Use
TEXTfor long strings - Partial indexes with
WHEREclause
MySQL:
- Use
CHAR(36)instead of UUID - Use
LONGTEXTfor long strings - No partial indexes - use regular index
H2:
- Use
UUIDtype - Use
CLOBfor very long strings - Supports partial indexes
Testing Migrations
# Test with PostgreSQL
./gradlew :lemline-runner-myfeature:test -Dquarkus.test.profile=postgres
# Test with MySQL
./gradlew :lemline-runner-myfeature:test -Dquarkus.test.profile=mysql
# Test with H2
./gradlew :lemline-runner-myfeature:test -Dquarkus.test.profile=h2
Running Tests
# All tests in main runner
./gradlew :lemline-runner:test
# All tests in feature module
./gradlew :lemline-runner-myfeature:test
# Specific test class
./gradlew :lemline-runner-myfeature:test --tests "com.lemline.runner.myfeature.MyTest"
# Test specific module with specific database
./gradlew :lemline-runner-waits:test -Dquarkus.test.profile=postgres
./gradlew :lemline-runner-waits:test -Dquarkus.test.profile=mysql
./gradlew :lemline-runner-waits:test -Dquarkus.test.profile=h2
# Test all runner modules
./gradlew test -p lemline-runner -p lemline-runner-common -p lemline-runner-waits -p lemline-runner-retries ...
Adding a New DSL Feature
Example: Adding support for a new task type that requires persistence
-
Add task to lemline-core (see core-dev skill)
- Create model in
lemline-core/src/.../models/tasks/ - Create processor in
lemline-core/src/.../processors/ - Throw
AsyncTaskExceptionif needs persistence
- Create model in
-
Create feature module
mkdir -p lemline-runner-myfeature/src/{main,test}/kotlin/com/lemline/runner/myfeature mkdir -p lemline-runner-myfeature/src/main/resources/db/migration/{postgresql,mysql,h2} -
Add to settings.gradle.kts
include("lemline-runner-myfeature") -
Create build.gradle.kts
dependencies { implementation(project(":lemline-common")) implementation(project(":lemline-core")) implementation(project(":lemline-runner-common")) } -
Implement feature (Model, Repository, Service, Outbox, Cleaner)
-
Add migrations for all 3 databases
-
Register in WorkflowEventHandler
// In lemline-runner when (val state = message.state) { is MyFeatureStarted -> myFeatureService.handleStarted(message) // ... } -
Add tests for all databases
-
Add to main runner dependencies
// In lemline-runner/build.gradle.kts implementation(project(":lemline-runner-myfeature")) -
Document in README.md in the feature module
Related Documentation
- CLAUDE.md - Project-wide guidelines and architecture overview
- AGENTS.md - Build, test, and lint commands
- core-dev skill - lemline-core module (DSL, orchestrators, processors)
- Serverless Workflow DSL - https://serverlessworkflow.io/
Module Dependency Graph
lemline-common
↑
│
lemline-core
↑
│
lemline-runner-common ←────┐
↑ │
│ │
├──────────────────────┼─────────────────┐
│ │ │
lemline-runner-* lemline-runner-* lemline-runner-*
(feature modules) (feature modules) (feature modules)
↑ ↑ ↑
│ │ │
└──────────────────────┴─────────────────┘
│
lemline-runner
(main runtime)
Key principle: Feature modules depend only on common modules, not on each other (except rare cases like schedules/parents).
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/lemline-runner-development-guide-mm5t89dx' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/lemline-runner-development-guide-mm5t89dx/download' --output '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md.part' && mv '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md.part' '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
Original excerpt: Quick Reference
If you need to work on...
A Specific Feature:
Read the module's README first:
- Wait task → lemline-runner-waits/README.md
- Retry logic → lemline-runner-retries/README.md
- Parent-child workflows → lemline-runner-parents/README.md
- Fork/parallel execution → lemline-runner-forks/README.md
- Scheduled workflows → lemline-runner-schedules/README.md
- CloudEvent listeners → lemline-runner-listeners/README.md
- Failure tracking → lemline-runner-failures/README.md
- Definition storage → lemline-runner-definitions/README.md
Messaging:
First, read runner-messaging.md
- Add a new command/event type → Modify WorkflowState.kt
- Update commands behavior → Modify WorkflowCommandHandler.kt
- Update events behavior → Modify WorkflowEventHandler.kt
Shared Infrastructure:
Read lemline-runner-common/README.md first
- Add new outbox processor → Extend
AbstractOutbox<T>in lemline-runner-common - Add new cleaner → Extend
AbstractCleaner<T>in lemline-runner-common - Add repository operations → Add to
lemline-runner-common/repositories/ops/ - Add model interface → Create in
lemline-runner-common/models/
Configuration:
First read runner-configuration.md
- Add/Update config property → Modify LemlineConfiguration.kt
- Add database/broker type → Read runner-configuration.md
CLI:
First read runner-cli.md
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md' && test -s '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/runner-dev' && cp -R '.skill-downloads/lemline-runner-development-guide-mm5t89dx' '.claude/skills/runner-dev'Cursor
test -f '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md' && test -s '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/runner-dev' && cp -R '.skill-downloads/lemline-runner-development-guide-mm5t89dx' '.cursor/skills/runner-dev'Codex
test -f '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md' && test -s '.skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/runner-dev' && cp -R '.skill-downloads/lemline-runner-development-guide-mm5t89dx' '.agents/skills/runner-dev'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/lemline-runner-development-guide-mm5t89dx'openskills read 'lemline-runner-development-guide-mm5t89dx'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/lemline-runner-development-guide-mm5t89dx/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.