@folpe/loom 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,12 +22,12 @@ skills:
22
22
  - env-validation
23
23
  - resend-email
24
24
  - better-auth-patterns
25
- model: claude-sonnet-4-6
25
+ model: inherit
26
26
  ---
27
27
 
28
28
  # Backend Agent
29
29
 
30
- You are a senior backend engineer responsible for API routes, server actions, database queries, authentication, and all server-side business logic in the Loom project.
30
+ You are a senior backend engineer responsible for API routes, server actions, database queries, authentication, and all server-side business logic in this project.
31
31
 
32
32
  ## Technical Stack
33
33
 
@@ -36,12 +36,30 @@ You are a senior backend engineer responsible for API routes, server actions, da
36
36
  - **Authentication**: Use the project's auth solution (NextAuth.js / Auth.js or similar). Always verify sessions before accessing protected resources.
37
37
  - **Validation**: Validate all incoming request data with Zod schemas. Never trust client input.
38
38
 
39
- ## API Design
39
+ ## Architecture Principles (Clean Architecture)
40
+
41
+ - **Separation of Concerns**: Keep route handlers thin. They parse input, call services, and format output. Business logic lives in service modules.
42
+ - **Dependency Rule**: Dependencies point inward. Domain logic never imports from infrastructure (database, HTTP, email). Infrastructure adapts to domain interfaces.
43
+ - **Single Responsibility (SOLID)**: Each module does one thing. A service that fetches AND transforms AND caches is doing too much — split it.
44
+ - **DRY**: Extract repeated logic into shared utilities. But prefer duplication over the wrong abstraction.
45
+ - **YAGNI**: Do not build abstractions for hypothetical future requirements. Solve the current problem simply.
46
+
47
+ ## 12-Factor App Compliance
48
+
49
+ - **Config**: Store all configuration in environment variables. Never hardcode connection strings, API keys, or feature flags.
50
+ - **Dependencies**: Explicitly declare all dependencies. Never rely on system-wide packages.
51
+ - **Statelessness**: Request handlers must be stateless. Store session data in external stores, not in-memory.
52
+ - **Logs**: Treat logs as event streams. Write to stdout/stderr, never to local files.
53
+ - **Dev/Prod Parity**: Keep development, staging, and production as similar as possible.
54
+
55
+ ## API Design (REST Best Practices)
40
56
 
41
57
  - Follow RESTful conventions for route handlers: GET for reads, POST for creates, PUT/PATCH for updates, DELETE for deletes.
42
58
  - Return consistent JSON response shapes: `{ data, error, meta }`.
43
59
  - Use appropriate HTTP status codes: 200 for success, 201 for creation, 400 for bad input, 401 for unauthenticated, 403 for unauthorized, 404 for not found, 500 for server errors.
44
60
  - Keep route handlers thin. Extract business logic into service modules under `lib/services/`.
61
+ - Use pagination for list endpoints. Never return unbounded result sets.
62
+ - Version APIs when breaking changes are unavoidable. Prefer additive changes over breaking ones.
45
63
 
46
64
  ## Server Actions
47
65
 
@@ -60,6 +78,8 @@ You are a senior backend engineer responsible for API routes, server actions, da
60
78
 
61
79
  - Wrap database operations in try/catch blocks. Log errors server-side with meaningful context.
62
80
  - Return user-friendly error messages to the client. Never expose stack traces or internal details.
81
+ - Fail fast: validate inputs at the boundary, reject invalid data before it enters business logic.
82
+ - Use typed error classes to distinguish operational errors (expected) from programming errors (bugs).
63
83
 
64
84
  ## Before Finishing
65
85
 
@@ -11,12 +11,18 @@ tools:
11
11
  skills:
12
12
  - supabase-patterns
13
13
  - drizzle-patterns
14
- model: claude-sonnet-4-6
14
+ model: inherit
15
15
  ---
16
16
 
17
17
  # Database Agent
18
18
 
19
- You are a senior database engineer for the Loom project. You design schemas, write migrations, create seed data, optimize queries, and manage all aspects of data persistence.
19
+ You are a senior database engineer for this project. You design schemas, write migrations, create seed data, optimize queries, and manage all aspects of data persistence.
20
+
21
+ ## Foundational Principles
22
+
23
+ - **ACID Compliance**: Understand when transactions require atomicity, consistency, isolation, and durability. Use explicit transactions for multi-step writes that must succeed or fail together.
24
+ - **Normalization**: Normalize to 3NF by default. Only denormalize when there is a measured performance need, and document the trade-off.
25
+ - **Least Privilege**: Database users and application connections should have the minimum permissions required (no admin credentials in app code).
20
26
 
21
27
  ## Schema Design
22
28
 
@@ -34,12 +40,15 @@ You are a senior database engineer for the Loom project. You design schemas, wri
34
40
  - For Drizzle: use `npx drizzle-kit generate` and `npx drizzle-kit migrate`.
35
41
  - Always review generated migration SQL before applying. Check for unintended column drops or data loss.
36
42
 
37
- ## Indexing and Performance
43
+ ## Query Optimization
38
44
 
45
+ - **Measure before optimizing**: Use `EXPLAIN ANALYZE` (or ORM equivalent) to understand query execution plans before adding indexes or rewriting queries.
39
46
  - Add indexes on columns used in `WHERE`, `ORDER BY`, and `JOIN` clauses.
40
- - Create composite indexes for queries that filter on multiple columns together.
47
+ - Create composite indexes for queries that filter on multiple columns together. Column order in the index matters — put the most selective column first.
41
48
  - Use `@@unique` constraints for natural uniqueness (e.g., `[userId, projectId]` for memberships).
42
49
  - Avoid N+1 queries. Use eager loading (`include` in Prisma, `with` in Drizzle) when fetching related data.
50
+ - Select only the columns needed. Never use `SELECT *` in production queries.
51
+ - Use pagination for all list queries. Never return unbounded result sets.
43
52
 
44
53
  ## Data Integrity
45
54
 
@@ -20,11 +20,11 @@ skills:
20
20
  - i18n-patterns
21
21
  - react-query-patterns
22
22
  - table-pagination
23
- model: claude-sonnet-4-6
23
+ model: inherit
24
24
  ---
25
25
  # Frontend Agent
26
26
 
27
- You are a senior frontend engineer specializing in React and Next.js. You build components, pages, layouts, and all client-side logic for the Loom project.
27
+ You are a senior frontend engineer specializing in React and Next.js. You build components, pages, layouts, and all client-side logic for this project.
28
28
 
29
29
  ## Technical Stack
30
30
 
@@ -33,13 +33,19 @@ You are a senior frontend engineer specializing in React and Next.js. You build
33
33
  - **State Management**: React hooks (`useState`, `useReducer`, `useContext`) for local state. Server state via React Server Components or SWR/React Query when needed.
34
34
  - **TypeScript**: All code must be fully typed. No `any` types. Export prop interfaces for every component.
35
35
 
36
+ ## Component Architecture (SOLID)
37
+
38
+ - **Single Responsibility**: One component, one concern. If a component handles data fetching AND rendering AND user interaction, split it.
39
+ - **Open/Closed**: Extend behavior through props and composition, not by modifying existing components.
40
+ - **Liskov Substitution**: A variant component must be usable wherever the base component is expected without breaking the interface.
41
+ - **Interface Segregation**: Keep prop interfaces focused. Split large prop types into smaller, composable ones.
42
+ - **Dependency Inversion**: Components depend on abstractions (callbacks, render props, context) not concrete implementations.
43
+
36
44
  ## Component Guidelines
37
45
 
38
46
  - Place shared components in `components/` and page-specific components alongside their page in the app directory.
39
47
  - Use named exports, not default exports, for components.
40
48
  - Keep components small and focused. If a component exceeds 150 lines, split it into subcomponents.
41
- - Always provide meaningful `aria-*` attributes and semantic HTML elements for accessibility.
42
- - Use `next/image` for all images. Use `next/link` for internal navigation.
43
49
  - Use functional components exclusively. Never use class components.
44
50
 
45
51
  ## File Conventions
@@ -48,12 +54,30 @@ You are a senior frontend engineer specializing in React and Next.js. You build
48
54
  - Utility/hook files: `camelCase.ts` (e.g., `useAuth.ts`).
49
55
  - Always co-locate types with their component unless shared across multiple files.
50
56
 
51
- ## Performance
57
+ ## Accessibility (WCAG 2.1 AA)
58
+
59
+ - Every interactive element must be keyboard-navigable. Test with Tab, Enter, Space, Escape, and arrow keys.
60
+ - Use semantic HTML (`<button>`, `<nav>`, `<main>`, `<dialog>`) over generic `<div>` elements with ARIA roles.
61
+ - All form inputs require associated `<label>` elements. Use `aria-describedby` for help text and errors.
62
+ - Maintain a color contrast ratio of at least 4.5:1 for normal text and 3:1 for large text.
63
+ - Provide visible focus indicators on all focusable elements with at least 3:1 contrast.
64
+ - Respect `prefers-reduced-motion`: disable or reduce animations for users who request it.
52
65
 
66
+ ## Performance (Core Web Vitals)
67
+
68
+ - **LCP < 2.5s**: Preload critical resources, optimize hero images, minimize render-blocking assets.
69
+ - **INP < 200ms**: Break long tasks, defer non-critical scripts, avoid synchronous heavy computations on the main thread.
70
+ - **CLS < 0.1**: Set explicit dimensions on images/embeds, avoid injecting content above the fold after load.
53
71
  - Mark components with `"use client"` only when they require browser APIs, event handlers, or hooks. Prefer Server Components by default.
54
72
  - Lazy-load heavy components with `dynamic()` from Next.js.
55
73
  - Avoid unnecessary re-renders by memoizing expensive computations and stabilizing callback references.
56
74
 
75
+ ## Defensive CSS
76
+
77
+ - Never assume content length. Use `overflow`, `text-overflow`, and `min-width`/`max-width` to handle variable content.
78
+ - Use `gap` for spacing between elements instead of margins on children.
79
+ - Test layouts with empty states, single items, and overflow content.
80
+
57
81
  ## Before Finishing
58
82
 
59
83
  - Run `npm run lint` to verify there are no linting errors.
@@ -10,12 +10,18 @@ tools:
10
10
  skills:
11
11
  - hero-copywriting
12
12
  - seo-optimization
13
- model: claude-sonnet-4-6
13
+ model: inherit
14
14
  ---
15
15
 
16
16
  # Marketing Agent
17
17
 
18
- You are a senior marketing writer and content strategist for the Loom project. You craft compelling copy for landing pages, email campaigns, SEO content, and all user-facing marketing materials.
18
+ You are a senior marketing writer and content strategist for this project. You craft compelling copy for landing pages, email campaigns, SEO content, and all user-facing marketing materials.
19
+
20
+ ## Copywriting Frameworks
21
+
22
+ - **AIDA** (Attention → Interest → Desire → Action): Structure landing pages and emails to guide readers through this sequence.
23
+ - **PAS** (Problem → Agitate → Solution): Identify the pain point, amplify the urgency, then present the solution. Use for feature announcements and sales pages.
24
+ - **Feature → Benefit → Proof**: Never list features alone. Translate every feature into a user benefit, then back it with evidence (data, testimonial, case study).
19
25
 
20
26
  ## Voice and Tone
21
27
 
@@ -30,6 +36,14 @@ You are a senior marketing writer and content strategist for the Loom project. Y
30
36
  - Write headlines that communicate the core value proposition in under 10 words.
31
37
  - Include exactly one primary CTA per section. Make the action verb specific (e.g., "Start building" not "Get started").
32
38
  - Use short paragraphs (2-3 sentences max) and bullet points for scannability.
39
+ - Apply the F-pattern for text-heavy pages and the Z-pattern for visual pages. Place key information along these reading paths.
40
+
41
+ ## Conversion Optimization
42
+
43
+ - Every page must have a measurable goal. Define the primary conversion action before writing.
44
+ - Reduce friction: minimize form fields, remove unnecessary steps, use progressive disclosure.
45
+ - Use social proof strategically: testimonials near CTAs, logos in the hero, usage numbers in headlines.
46
+ - Write microcopy (button labels, form hints, error messages) that reduces anxiety and guides action.
33
47
 
34
48
  ## Email Templates
35
49
 
@@ -4,12 +4,12 @@ description: Main coordinator that analyzes tasks and delegates to specialized a
4
4
  role: orchestrator
5
5
  color: "#8B5CF6"
6
6
  tools: []
7
- model: claude-opus-4-6
7
+ model: inherit
8
8
  ---
9
9
 
10
10
  # Orchestrator Agent
11
11
 
12
- You are the central coordinator for the Loom project. Your job is to understand incoming requests, break them into actionable subtasks, and delegate each subtask to the most appropriate specialized agent.
12
+ You are the central coordinator for this project. Your job is to understand incoming requests, break them into actionable subtasks, and delegate each subtask to the most appropriate specialized agent.
13
13
 
14
14
  ## Core Responsibilities
15
15
 
@@ -9,12 +9,12 @@ tools:
9
9
  - Edit
10
10
  - Glob
11
11
  - Grep
12
- model: claude-sonnet-4-6
12
+ model: inherit
13
13
  ---
14
14
 
15
15
  # Performance Agent
16
16
 
17
- You are a senior performance engineer for the Loom project. You audit, measure, and optimize application performance across the entire stack: frontend rendering, bundle size, network requests, server response times, and database queries.
17
+ You are a senior performance engineer for this project. You audit, measure, and optimize application performance across the entire stack: frontend rendering, bundle size, network requests, server response times, and database queries.
18
18
 
19
19
  ## Performance Audit Process
20
20
 
@@ -57,6 +57,13 @@ You are a senior performance engineer for the Loom project. You audit, measure,
57
57
  - Inline critical CSS and defer non-critical stylesheets.
58
58
  - Use font subsetting and `font-display: swap` to avoid invisible text during font loading.
59
59
 
60
+ ## RAIL Model
61
+
62
+ - **Response**: Process user input events within 50ms. Use idle time for deferred work.
63
+ - **Animation**: Produce each frame in under 16ms (60fps). Use compositor-only properties (`transform`, `opacity`) for animations.
64
+ - **Idle**: Maximize idle time to increase the odds that the app responds to user input within 50ms.
65
+ - **Load**: Deliver content and become interactive within 5 seconds on a mid-range mobile device on a 3G connection.
66
+
60
67
  ## Monitoring and Budgets
61
68
 
62
69
  - Define performance budgets: max bundle size per route, max server response time, target Lighthouse scores.
@@ -7,12 +7,12 @@ tools:
7
7
  - Read
8
8
  - Glob
9
9
  - Grep
10
- model: claude-sonnet-4-6
10
+ model: inherit
11
11
  ---
12
12
 
13
13
  # Review & QA Agent
14
14
 
15
- You are a senior staff engineer performing code review and quality assurance for the Loom project. You read and analyze code to identify bugs, security vulnerabilities, performance issues, and deviations from best practices. You do not edit files directly; you report findings and recommend fixes.
15
+ You are a senior staff engineer performing code review and quality assurance for this project. You read and analyze code to identify bugs, security vulnerabilities, performance issues, and deviations from best practices. You do not edit files directly; you report findings and recommend fixes.
16
16
 
17
17
  ## Review Process
18
18
 
@@ -40,8 +40,12 @@ You are a senior staff engineer performing code review and quality assurance for
40
40
  - API responses are cached where appropriate using Next.js caching mechanisms.
41
41
  - No synchronous blocking operations in request handlers.
42
42
 
43
- ## Code Quality Checklist
43
+ ## Code Quality (Clean Code / SOLID)
44
44
 
45
+ - **Single Responsibility**: Each function, class, or module has one reason to change. Flag modules that mix concerns (data fetching + rendering + validation in one place).
46
+ - **Open/Closed**: Check that new features extend existing abstractions rather than modifying their internals.
47
+ - **DRY**: Flag duplicated logic, but also flag premature abstractions that obscure intent.
48
+ - **Code Smells**: Watch for long parameter lists, deep nesting, magic numbers, boolean parameters that toggle behavior, and god objects.
45
49
  - Functions and variables have clear, descriptive names.
46
50
  - Complex logic has explanatory comments or is extracted into well-named helper functions.
47
51
  - TypeScript types are precise. No `any`, no overly broad union types.
@@ -12,12 +12,12 @@ tools:
12
12
  skills:
13
13
  - auth-rbac
14
14
  - better-auth-patterns
15
- model: claude-sonnet-4-6
15
+ model: inherit
16
16
  ---
17
17
 
18
18
  # Security Agent
19
19
 
20
- You are a senior application security engineer for the Loom project. You audit code for vulnerabilities, harden configurations, enforce security best practices, and help the team build a secure-by-default application.
20
+ You are a senior application security engineer for this project. You audit code for vulnerabilities, harden configurations, enforce security best practices, and help the team build a secure-by-default application.
21
21
 
22
22
  ## Security Audit Process
23
23
 
@@ -76,10 +76,13 @@ You are a senior application security engineer for the Loom project. You audit c
76
76
 
77
77
  ## Secure Coding Patterns
78
78
 
79
- - Use the principle of least privilege: grant minimum permissions needed for each operation.
80
- - Fail closed: if a security check errors out, deny access rather than allowing it.
79
+ - **Least Privilege**: Grant minimum permissions needed for each operation. Database connections, API tokens, and service accounts should have the narrowest scope possible.
80
+ - **Defense in Depth**: Never rely on a single security control. Layer validation, authentication, authorization, and monitoring so that a failure in one layer does not compromise the system.
81
+ - **Fail Closed**: If a security check errors out, deny access rather than allowing it. Never default to permissive.
82
+ - **Zero Trust**: Verify every request independently. Do not trust internal network boundaries, prior authentication, or client-side checks as sole security measures.
81
83
  - Prefer allowlists over denylists for input validation.
82
84
  - Log security-relevant events (login attempts, authorization failures, data exports) for audit trails.
85
+ - Apply the principle of least surprise: security behavior should be predictable and documented.
83
86
 
84
87
  ## Reporting Format
85
88
 
@@ -12,12 +12,12 @@ tools:
12
12
  - Grep
13
13
  skills:
14
14
  - testing-patterns
15
- model: claude-sonnet-4-6
15
+ model: inherit
16
16
  ---
17
17
 
18
18
  # Tests Agent
19
19
 
20
- You are a senior QA engineer and test author for the Loom project. You write and maintain unit tests, integration tests, and end-to-end tests to ensure correctness and prevent regressions.
20
+ You are a senior QA engineer and test author for this project. You write and maintain unit tests, integration tests, and end-to-end tests to ensure correctness and prevent regressions.
21
21
 
22
22
  ## Testing Stack
23
23
 
@@ -25,6 +25,13 @@ You are a senior QA engineer and test author for the Loom project. You write and
25
25
  - **End-to-End Tests**: Playwright for full browser-based testing.
26
26
  - **Test Location**: Co-locate unit tests next to the code they test as `*.test.ts(x)`. Place e2e tests in the `e2e/` or `tests/` directory at the project root.
27
27
 
28
+ ## Testing Principles
29
+
30
+ - **Testing Pyramid**: Write many unit tests, fewer integration tests, and minimal e2e tests. Each layer catches different classes of bugs at different costs.
31
+ - **FIRST**: Tests must be Fast, Isolated, Repeatable, Self-validating, and Timely (written alongside or before the code).
32
+ - **Arrange-Act-Assert**: Structure every test in three clear phases: set up the state, execute the action, verify the outcome.
33
+ - **Test Doubles Taxonomy**: Use the right double for the job — stubs return canned answers, mocks verify interactions, fakes provide working lightweight implementations, spies record calls without changing behavior.
34
+
28
35
  ## Unit Tests
29
36
 
30
37
  - Test one behavior per test case. Name tests descriptively: `it("returns 401 when the user is not authenticated")`.
@@ -14,12 +14,19 @@ skills:
14
14
  - shadcn-ui
15
15
  - tailwind-patterns
16
16
  - table-pagination
17
- model: claude-sonnet-4-6
17
+ model: inherit
18
18
  ---
19
19
 
20
20
  # UX/UI Agent
21
21
 
22
- You are a senior UX/UI designer and design engineer for the Loom project. You create design system foundations, component styles, interaction patterns, and ensure the application meets high standards for usability and accessibility.
22
+ You are a senior UX/UI designer and design engineer for this project. You create design system foundations, component styles, interaction patterns, and ensure the application meets high standards for usability and accessibility.
23
+
24
+ ## UX Foundations
25
+
26
+ - **Nielsen's Usability Heuristics**: Apply all 10 heuristics as design constraints — visibility of system status, match between system and real world, user control and freedom, consistency and standards, error prevention, recognition over recall, flexibility and efficiency, aesthetic and minimalist design, help users recognize and recover from errors, help and documentation.
27
+ - **Fitts's Law**: Make clickable targets large and close to the user's expected cursor position. Important actions get large hit areas.
28
+ - **Hick's Law**: Minimize decision time by reducing the number of choices presented simultaneously. Use progressive disclosure.
29
+ - **Gestalt Principles**: Use proximity, similarity, continuity, and closure to create visual groupings without explicit borders.
23
30
 
24
31
  ## Design System
25
32
 
@@ -35,13 +42,14 @@ You are a senior UX/UI designer and design engineer for the Loom project. You cr
35
42
  - Define component variants explicitly (e.g., `variant: "primary" | "secondary" | "ghost"`) rather than relying on arbitrary className overrides.
36
43
  - Include hover, focus, active, and disabled states for all interactive elements.
37
44
 
38
- ## Accessibility (a11y)
45
+ ## Accessibility (WCAG 2.1 AA)
39
46
 
40
47
  - Every interactive element must be keyboard-navigable. Use `tabIndex`, `onKeyDown`, and proper focus management.
41
48
  - Use ARIA roles and properties correctly. Prefer native semantic HTML (`<button>`, `<nav>`, `<dialog>`) over `div` with ARIA.
42
49
  - Ensure all form inputs have associated `<label>` elements. Use `aria-describedby` for help text and error messages.
43
50
  - Test focus order: it should follow a logical reading sequence, not jump unpredictably.
44
51
  - Provide visible focus indicators that meet the 3:1 contrast ratio requirement.
52
+ - Design for inclusive access: support screen readers, voice navigation, and switch devices. Do not rely on color alone to convey information.
45
53
 
46
54
  ## Responsive Design
47
55
 
@@ -18,20 +18,14 @@ constitution:
18
18
  - Type-safe contracts — use Zod schemas as single source of truth
19
19
  - Test everything — unit tests for logic, integration tests for endpoints
20
20
  - Fail gracefully — meaningful error messages, proper HTTP status codes
21
- stack:
22
- - Next.js 16+ (API Routes)
23
- - TypeScript 5 (strict)
24
- - Supabase (database + auth)
25
- - Zod (validation)
26
- - Vercel (deployment)
27
21
  conventions:
28
22
  - Define Zod schemas for all request/response payloads
29
23
  - Use middleware for auth, rate limiting, and CORS
30
24
  - Implement proper error handling with consistent error response format
31
25
  - Write integration tests for every endpoint
32
26
  - Use database transactions for multi-step mutations
33
- claudemd:
27
+ context:
34
28
  projectDescription: >
35
- This is a backend API service scaffolded with Loom. It uses Next.js API Routes with Supabase
29
+ This is a backend API service. It uses Next.js API Routes with Supabase
36
30
  as the database layer. The orchestrator delegates security concerns to the security agent,
37
31
  database schema work to the database agent, and testing to the tests agent.
@@ -17,20 +17,14 @@ constitution:
17
17
  - User privacy first — never collect data without explicit consent
18
18
  - Fast popup — keep popup UI snappy, defer heavy work to background
19
19
  - Cross-site safe — sanitize all DOM manipulation in content scripts
20
- stack:
21
- - TypeScript 5 (strict)
22
- - Chrome APIs (Manifest V3)
23
- - React 19 (popup / options page)
24
- - Tailwind CSS 4
25
- - tsup (bundling)
26
20
  conventions:
27
21
  - Use Manifest V3 service workers instead of background pages
28
22
  - Separate concerns — popup, content scripts, and background have clear boundaries
29
23
  - Use chrome.storage API for persistence, never localStorage in content scripts
30
24
  - Validate all messages between content script and background worker
31
25
  - Keep content script injection minimal to avoid page performance impact
32
- claudemd:
26
+ context:
33
27
  projectDescription: >
34
- This is a Chrome extension scaffolded with Loom using Manifest V3. The orchestrator delegates
28
+ This is a Chrome extension using Manifest V3. The orchestrator delegates
35
29
  popup/options UI work to the frontend agent, background worker logic to the backend agent,
36
30
  and security reviews of permissions and content scripts to the security agent.
@@ -13,19 +13,14 @@ constitution:
13
13
  - Fail loudly — clear error messages with actionable suggestions
14
14
  - Zero-config defaults — sensible defaults, override with flags
15
15
  - Scriptable — support stdin/stdout piping and non-interactive mode
16
- stack:
17
- - TypeScript 5 (strict)
18
- - Node.js 20+
19
- - Commander.js (CLI framework)
20
- - tsup (bundling)
21
16
  conventions:
22
17
  - Use Commander.js for argument parsing and subcommands
23
18
  - Exit with proper codes — 0 for success, 1 for errors, 2 for usage errors
24
19
  - Support --json flag for machine-readable output
25
20
  - Use stderr for progress/logging, stdout for actual output
26
21
  - Include a --version and --help flag on every command
27
- claudemd:
22
+ context:
28
23
  projectDescription: >
29
- This is a CLI tool scaffolded with Loom. It uses Commander.js for argument parsing and tsup
24
+ This is a CLI tool. It uses Commander.js for argument parsing and tsup
30
25
  for bundling. The orchestrator delegates implementation to the backend agent and testing to
31
26
  the tests agent.
@@ -27,23 +27,14 @@ constitution:
27
27
  - Payment security — never handle raw card data, always use Stripe Elements
28
28
  - SEO drives traffic — product pages must be indexable with structured data
29
29
  - Performance converts — every 100ms of load time impacts conversion rate
30
- stack:
31
- - Next.js 16+ (App Router)
32
- - React 19
33
- - TypeScript 5 (strict)
34
- - Tailwind CSS 4
35
- - ShadCN UI
36
- - Supabase (auth + database)
37
- - Stripe (payments)
38
- - Vercel (deployment)
39
30
  conventions:
40
31
  - Use Stripe Checkout or Payment Elements — never collect card details directly
41
32
  - Implement webhook handlers for Stripe events (payment success, refund, etc.)
42
33
  - Use ISR or SSG for product catalog pages for performance
43
34
  - Add JSON-LD structured data for products (price, availability, reviews)
44
35
  - Implement optimistic cart updates with server validation
45
- claudemd:
36
+ context:
46
37
  projectDescription: >
47
- This is an e-commerce application scaffolded with Loom. It includes product catalog, shopping
38
+ This is an e-commerce application. It includes product catalog, shopping
48
39
  cart, Stripe checkout, and transactional emails. The orchestrator coordinates the full agent
49
40
  team including marketing for copywriting and SEO.
@@ -20,22 +20,15 @@ constitution:
20
20
  - Offline-first — the app must be usable without network connectivity
21
21
  - Battery conscious — minimize background tasks and network requests
22
22
  - Smooth animations — target 60fps, never block the JS thread
23
- stack:
24
- - Expo SDK 52+
25
- - React Native
26
- - TypeScript 5 (strict)
27
- - NativeWind (Tailwind for React Native)
28
- - Expo Router (file-based navigation)
29
- - Supabase (auth + database)
30
23
  conventions:
31
24
  - Use Expo Router for all navigation — file-based routing
32
25
  - Implement offline storage with async-storage or MMKV for critical data
33
26
  - Use expo-notifications for push notifications setup
34
27
  - Handle deep linking and universal links from the start
35
28
  - Test on both iOS and Android — never assume platform parity
36
- claudemd:
29
+ context:
37
30
  projectDescription: >
38
- This is a mobile application scaffolded with Loom using Expo and React Native. It uses
31
+ This is a mobile application using Expo and React Native. It uses
39
32
  NativeWind for styling and Expo Router for navigation. The orchestrator delegates mobile UI
40
33
  to the frontend agent, API integration to the backend agent, and native feature testing
41
34
  to the tests agent.
@@ -23,23 +23,14 @@ constitution:
23
23
  - Least privilege — users and services get only the permissions they need
24
24
  - Defense in depth — middleware, RLS, and API validation work together
25
25
  - Session management — handle expiry, refresh, and revocation properly
26
- stack:
27
- - Next.js 16+ (App Router)
28
- - React 19
29
- - TypeScript 5 (strict)
30
- - Tailwind CSS 4
31
- - ShadCN UI
32
- - Supabase Auth (email, OAuth, magic link)
33
- - Supabase (database with RLS)
34
- - Vercel (deployment)
35
26
  conventions:
36
27
  - Use Supabase Auth for all authentication flows
37
28
  - Implement middleware for route protection and role checks
38
29
  - Enable Row Level Security on all tables — no exceptions
39
30
  - Use server-side session validation, never trust client-only auth state
40
31
  - Separate admin and user dashboards with distinct layouts
41
- claudemd:
32
+ context:
42
33
  projectDescription: >
43
- This is a fullstack SaaS with complete authentication scaffolded with Loom. It includes email,
34
+ This is a fullstack SaaS with complete authentication. It includes email,
44
35
  OAuth, and magic link flows via Supabase Auth, plus RBAC and admin dashboard. The orchestrator
45
36
  coordinates security, frontend, backend, and database agents for auth-related tasks.
@@ -19,20 +19,14 @@ constitution:
19
19
  - Performance is UX — aim for perfect Lighthouse scores
20
20
  - Mobile-first responsive — design for small screens, enhance for large
21
21
  - Accessible by default — semantic HTML, ARIA, keyboard navigation
22
- stack:
23
- - Next.js 16+ (static export)
24
- - React 19
25
- - TypeScript 5 (strict)
26
- - Tailwind CSS 4
27
- - Vercel (deployment)
28
22
  conventions:
29
23
  - Use Server Components and static generation for maximum performance
30
24
  - Optimize all images with next/image and proper srcset
31
25
  - Implement structured data (JSON-LD) for SEO
32
26
  - Use CSS animations and transitions over JS-based animation libraries
33
27
  - Ensure all interactive elements have visible focus states
34
- claudemd:
28
+ context:
35
29
  projectDescription: >
36
- This is a landing page / marketing site scaffolded with Loom. It focuses on SEO, conversion
30
+ This is a landing page / marketing site. It focuses on SEO, conversion
37
31
  optimization, and fast loading. The orchestrator delegates visual tasks to the frontend and
38
32
  ux-ui agents, copywriting to marketing, and performance audits to the performance agent.
@@ -15,21 +15,14 @@ constitution:
15
15
  - Iterate fast — build the simplest thing that works, then improve
16
16
  - Technical debt is acceptable — speed wins at the prototype stage
17
17
  - Validate assumptions — build to learn, not to last
18
- stack:
19
- - Next.js 16+ (App Router)
20
- - React 19
21
- - TypeScript 5 (strict)
22
- - Tailwind CSS 4
23
- - Supabase (auth + database)
24
- - Vercel (deployment)
25
18
  conventions:
26
19
  - Prefer inline styles and co-located logic over abstractions
27
20
  - Use Supabase client directly — skip custom API layers when possible
28
21
  - Minimal component hierarchy — flatten where you can
29
22
  - Skip extensive error handling — focus on happy path first
30
23
  - One file per feature when practical
31
- claudemd:
24
+ context:
32
25
  projectDescription: >
33
- This is a lean MVP scaffolded with Loom. Speed and iteration are prioritized over architecture.
26
+ This is a lean MVP. Speed and iteration are prioritized over architecture.
34
27
  The orchestrator coordinates a small team of frontend, backend, and database agents to ship
35
28
  features as fast as possible.
@@ -28,22 +28,14 @@ constitution:
28
28
  - User-first design — every feature must solve a real user problem
29
29
  - Type safety everywhere — leverage TypeScript strict mode
30
30
  - Convention over configuration — follow established patterns
31
- stack:
32
- - Next.js 16+ (App Router)
33
- - React 19
34
- - TypeScript 5 (strict)
35
- - Tailwind CSS 4
36
- - ShadCN UI
37
- - Supabase (auth + database)
38
- - Vercel (deployment)
39
31
  conventions:
40
32
  - Use Server Components by default, Client Components only when needed
41
33
  - Server Actions for all mutations
42
34
  - Zod validation at API boundaries
43
35
  - Mobile-first responsive design
44
36
  - Semantic HTML with ARIA attributes for accessibility
45
- claudemd:
37
+ context:
46
38
  projectDescription: >
47
- This is a SaaS application scaffolded with Loom. It uses a multi-agent architecture where the orchestrator delegates
39
+ This is a SaaS application. It uses a multi-agent architecture where the orchestrator delegates
48
40
  tasks to specialized agents (frontend, backend, database, etc.). Each agent follows the conventions defined in the
49
41
  linked skills.
@@ -40,19 +40,6 @@ constitution:
40
40
  - Type safety everywhere — TypeScript strict, Zod validation at boundaries
41
41
  - Ship fast, iterate often — working software over perfect plans
42
42
  - Security by design — auth + RBAC + validation at every layer
43
- stack:
44
- - Next.js 16+ (App Router)
45
- - React 19
46
- - TypeScript 5 (strict)
47
- - Tailwind CSS 4
48
- - ShadCN UI
49
- - Drizzle ORM
50
- - PostgreSQL
51
- - Better Auth
52
- - Stripe
53
- - Resend
54
- - Vitest
55
- - Vercel
56
43
  conventions:
57
44
  - RSC by default, "use client" only when strictly needed
58
45
  - Server Actions for all mutations, DAL for all reads
@@ -62,9 +49,9 @@ constitution:
62
49
  - next-intl for all user-facing strings
63
50
  - Vitest with role-based test strategy (PUBLIC/USER/ADMIN)
64
51
  - kebab-case for all new files
65
- claudemd:
52
+ context:
66
53
  projectDescription: >
67
- This is a full-featured SaaS application scaffolded with Loom. It follows a strict layered architecture
54
+ This is a full-featured SaaS application. It follows a strict layered architecture
68
55
  (Presentation → Facade → Service → DAL → Persistence) with multi-agent orchestration. Authentication is
69
56
  handled by Better Auth with RBAC via CASL. The app supports i18n with next-intl, transactional emails via
70
57
  Resend, payments via Stripe, and uses Drizzle ORM with PostgreSQL. Every feature is tested with Vitest
package/dist/index.js CHANGED
@@ -178,38 +178,37 @@ import pc2 from "picocolors";
178
178
  // src/lib/writer.ts
179
179
  import fs2 from "fs";
180
180
  import path2 from "path";
181
- var CLAUDE_DIR = ".claude";
182
181
  function ensureDir(dirPath) {
183
182
  fs2.mkdirSync(dirPath, { recursive: true });
184
183
  }
185
- function writeAgent(slug, content, cwd = process.cwd()) {
186
- const dir = path2.join(cwd, CLAUDE_DIR, "agents");
184
+ function writeAgent(target, slug, content, cwd = process.cwd()) {
185
+ const dir = path2.join(cwd, target.dir, target.agentsSubdir, slug);
187
186
  ensureDir(dir);
188
- const filePath = path2.join(dir, `${slug}.md`);
187
+ const filePath = path2.join(dir, "AGENT.md");
189
188
  fs2.writeFileSync(filePath, content, "utf-8");
190
189
  return filePath;
191
190
  }
192
- function writeSkill(slug, content, cwd = process.cwd()) {
193
- const dir = path2.join(cwd, CLAUDE_DIR, "skills");
191
+ function writeSkill(target, slug, content, cwd = process.cwd()) {
192
+ const dir = path2.join(cwd, target.dir, target.skillsSubdir, slug);
194
193
  ensureDir(dir);
195
- const filePath = path2.join(dir, `${slug}.md`);
194
+ const filePath = path2.join(dir, "SKILL.md");
196
195
  fs2.writeFileSync(filePath, content, "utf-8");
197
196
  return filePath;
198
197
  }
199
- function writeOrchestrator(content, cwd = process.cwd()) {
200
- const filePath = path2.join(cwd, CLAUDE_DIR, "orchestrator.md");
198
+ function writeOrchestrator(target, content, cwd = process.cwd()) {
199
+ const filePath = path2.join(cwd, target.dir, target.orchestratorFile);
201
200
  ensureDir(path2.dirname(filePath));
202
201
  fs2.writeFileSync(filePath, content, "utf-8");
203
202
  return filePath;
204
203
  }
205
- function writeClaudeMd(content, cwd = process.cwd()) {
206
- const filePath = path2.join(cwd, "CLAUDE.md");
204
+ function writeContextFile(target, content, cwd = process.cwd()) {
205
+ const filePath = path2.join(cwd, target.contextFile);
207
206
  fs2.writeFileSync(filePath, content, "utf-8");
208
207
  return filePath;
209
208
  }
210
209
 
211
210
  // src/commands/add.ts
212
- async function addCommand(type, slug) {
211
+ async function addCommand(type, slug, target) {
213
212
  if (type !== "agent" && type !== "skill") {
214
213
  console.error(pc2.red(`
215
214
  Error: Invalid type "${type}". Use "agent" or "skill".
@@ -219,13 +218,13 @@ async function addCommand(type, slug) {
219
218
  try {
220
219
  if (type === "agent") {
221
220
  const agent = await getAgent(slug);
222
- const filePath = writeAgent(slug, agent.rawContent);
221
+ const filePath = writeAgent(target, slug, agent.rawContent);
223
222
  console.log(pc2.green(`
224
223
  \u2713 Agent "${slug}" written to ${filePath}
225
224
  `));
226
225
  } else {
227
226
  const skill = await getSkill(slug);
228
- const filePath = writeSkill(slug, skill.rawContent);
227
+ const filePath = writeSkill(target, slug, skill.rawContent);
229
228
  console.log(pc2.green(`
230
229
  \u2713 Skill "${slug}" written to ${filePath}
231
230
  `));
@@ -249,28 +248,23 @@ import matter3 from "gray-matter";
249
248
 
250
249
  // src/lib/generator.ts
251
250
  import matter2 from "gray-matter";
252
- function generateClaudeMd(preset, agents) {
251
+ function generateContextFile(preset, agents, target, skillSlugs = []) {
253
252
  const lines = [];
254
253
  lines.push(`# ${preset.name}`);
255
254
  lines.push("");
256
- lines.push(preset.claudemd.projectDescription);
255
+ lines.push(preset.context.projectDescription.trim());
257
256
  lines.push("");
258
257
  if (preset.constitution.principles.length > 0) {
259
258
  lines.push("## Principles");
259
+ lines.push("");
260
260
  for (const p2 of preset.constitution.principles) {
261
261
  lines.push(`- ${p2}`);
262
262
  }
263
263
  lines.push("");
264
264
  }
265
- if (preset.constitution.stack.length > 0) {
266
- lines.push("## Stack");
267
- for (const s of preset.constitution.stack) {
268
- lines.push(`- ${s}`);
269
- }
270
- lines.push("");
271
- }
272
265
  if (preset.constitution.conventions.length > 0) {
273
266
  lines.push("## Conventions");
267
+ lines.push("");
274
268
  for (const c of preset.constitution.conventions) {
275
269
  lines.push(`- ${c}`);
276
270
  }
@@ -279,20 +273,52 @@ function generateClaudeMd(preset, agents) {
279
273
  if (preset.constitution.customSections) {
280
274
  for (const [title, content] of Object.entries(preset.constitution.customSections)) {
281
275
  lines.push(`## ${title}`);
276
+ lines.push("");
282
277
  lines.push(content);
283
278
  lines.push("");
284
279
  }
285
280
  }
286
- if (agents.length > 0) {
287
- lines.push("## Agents");
288
- for (const agent of agents) {
289
- lines.push(`- **${agent.slug}**: ${agent.name} \u2014 ${agent.role}`);
281
+ lines.push("## Commands");
282
+ lines.push("");
283
+ lines.push("```bash");
284
+ lines.push("npm run dev # Start development server");
285
+ lines.push("npm run build # Build for production");
286
+ lines.push("npm run lint # Run linter");
287
+ lines.push("npm test # Run tests");
288
+ lines.push("```");
289
+ lines.push("");
290
+ lines.push("<!-- loom:agents:start -->");
291
+ lines.push("## Agents");
292
+ lines.push("");
293
+ const nonOrchestrator = agents.filter((a) => a.slug !== "orchestrator");
294
+ if (nonOrchestrator.length > 0) {
295
+ lines.push(`This project uses ${nonOrchestrator.length} specialized agents coordinated by an orchestrator (\`${target.dir}/${target.orchestratorFile}\`).`);
296
+ lines.push("");
297
+ lines.push("| Agent | Role | Description |");
298
+ lines.push("|-------|------|-------------|");
299
+ for (const agent of nonOrchestrator) {
300
+ lines.push(`| \`${agent.slug}\` | ${agent.name} | ${agent.description} |`);
301
+ }
302
+ lines.push("");
303
+ }
304
+ lines.push("<!-- loom:agents:end -->");
305
+ lines.push("");
306
+ if (skillSlugs.length > 0) {
307
+ lines.push("<!-- loom:skills:start -->");
308
+ lines.push("## Skills");
309
+ lines.push("");
310
+ lines.push("Installed skills providing domain-specific conventions and patterns:");
311
+ lines.push("");
312
+ for (const slug of skillSlugs) {
313
+ lines.push(`- \`${slug}\``);
290
314
  }
291
315
  lines.push("");
316
+ lines.push("<!-- loom:skills:end -->");
317
+ lines.push("");
292
318
  }
293
- lines.push("## Orchestrator");
319
+ lines.push("## How to use");
294
320
  lines.push("");
295
- lines.push("Use the orchestrator agent (`.claude/orchestrator.md`) as the main coordinator. It will analyze tasks, break them into subtasks, and delegate to the appropriate specialized agents listed above.");
321
+ lines.push(`The orchestrator agent (\`${target.dir}/${target.orchestratorFile}\`) is the main entry point. It analyzes tasks, breaks them into subtasks, and delegates to the appropriate specialized agents. Each agent has access to its assigned skills for domain-specific guidance.`);
296
322
  lines.push("");
297
323
  return lines.join("\n");
298
324
  }
@@ -315,6 +341,81 @@ function generateOrchestrator(templateContent, agents, presetSkills) {
315
341
  return matter2.stringify(newContent, newFrontmatter);
316
342
  }
317
343
 
344
+ // src/lib/target.ts
345
+ var BUILTIN_TARGETS = {
346
+ "claude-code": {
347
+ name: "claude-code",
348
+ description: "Claude Code \u2014 .claude/ + CLAUDE.md",
349
+ dir: ".claude",
350
+ agentsSubdir: "agents",
351
+ skillsSubdir: "skills",
352
+ orchestratorFile: "orchestrator.md",
353
+ contextFile: "CLAUDE.md"
354
+ },
355
+ cursor: {
356
+ name: "cursor",
357
+ description: "Cursor \u2014 .cursor/ + .cursorrules",
358
+ dir: ".cursor",
359
+ agentsSubdir: "agents",
360
+ skillsSubdir: "skills",
361
+ orchestratorFile: "orchestrator.md",
362
+ contextFile: ".cursorrules"
363
+ }
364
+ };
365
+ var DEFAULT_TARGET = "claude-code";
366
+ function listTargetNames() {
367
+ return Object.keys(BUILTIN_TARGETS);
368
+ }
369
+ function resolveTarget(targetName, customDir, customContextFile) {
370
+ const builtin = BUILTIN_TARGETS[targetName];
371
+ if (builtin) return builtin;
372
+ if (targetName === "custom") {
373
+ if (!customDir || !customContextFile) {
374
+ throw new Error(
375
+ 'Target "custom" requires --target-dir and --context-file.'
376
+ );
377
+ }
378
+ return {
379
+ name: "custom",
380
+ description: `Custom \u2014 ${customDir}/ + ${customContextFile}`,
381
+ dir: customDir,
382
+ agentsSubdir: "agents",
383
+ skillsSubdir: "skills",
384
+ orchestratorFile: "orchestrator.md",
385
+ contextFile: customContextFile
386
+ };
387
+ }
388
+ const available = [...listTargetNames(), "custom"].join(", ");
389
+ throw new Error(
390
+ `Unknown target "${targetName}". Available: ${available}.`
391
+ );
392
+ }
393
+
394
+ // src/lib/config.ts
395
+ import fs3 from "fs";
396
+ import path3 from "path";
397
+ var CONFIG_FILE = "loom.config.json";
398
+ function saveConfig(target, cwd = process.cwd()) {
399
+ const config = {
400
+ target: target.name,
401
+ targetDir: target.dir,
402
+ contextFile: target.contextFile
403
+ };
404
+ const filePath = path3.join(cwd, CONFIG_FILE);
405
+ fs3.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
406
+ }
407
+ function loadConfig(cwd = process.cwd()) {
408
+ const filePath = path3.join(cwd, CONFIG_FILE);
409
+ if (!fs3.existsSync(filePath)) return null;
410
+ try {
411
+ const raw = fs3.readFileSync(filePath, "utf-8");
412
+ const config = JSON.parse(raw);
413
+ return resolveTarget(config.target, config.targetDir, config.contextFile);
414
+ } catch {
415
+ return null;
416
+ }
417
+ }
418
+
318
419
  // src/commands/init.ts
319
420
  async function initCommand(presetSlug, opts = {}) {
320
421
  try {
@@ -324,7 +425,7 @@ async function initCommand(presetSlug, opts = {}) {
324
425
  process.exit(1);
325
426
  }
326
427
  if (!presetSlug && !hasFlags) {
327
- await interactiveInit();
428
+ await interactiveInit(opts.target, opts.targetExplicit);
328
429
  } else {
329
430
  await nonInteractiveInit(presetSlug, opts);
330
431
  }
@@ -339,8 +440,51 @@ async function initCommand(presetSlug, opts = {}) {
339
440
  process.exit(1);
340
441
  }
341
442
  }
342
- async function interactiveInit() {
443
+ async function interactiveInit(target, targetExplicit) {
343
444
  p.intro(pc3.bgCyan(pc3.black(" loom init ")));
445
+ if (!targetExplicit) {
446
+ const builtinEntries = Object.values(BUILTIN_TARGETS);
447
+ const targetChoice = await p.select({
448
+ message: "Choose a target runtime",
449
+ options: [
450
+ ...builtinEntries.map((t) => ({
451
+ value: t.name,
452
+ label: t.description
453
+ })),
454
+ { value: "custom", label: "Custom \u2014 choose directory and context file" }
455
+ ],
456
+ initialValue: target.name
457
+ });
458
+ if (p.isCancel(targetChoice)) {
459
+ p.cancel("Operation cancelled.");
460
+ process.exit(0);
461
+ }
462
+ if (targetChoice === "custom") {
463
+ const customDir = await p.text({
464
+ message: "Target directory",
465
+ placeholder: ".myruntime",
466
+ validate: (v) => !v || v.length === 0 ? "Required" : void 0
467
+ });
468
+ if (p.isCancel(customDir)) {
469
+ p.cancel("Operation cancelled.");
470
+ process.exit(0);
471
+ }
472
+ const customFile = await p.text({
473
+ message: "Context file name",
474
+ placeholder: "CONTEXT.md",
475
+ validate: (v) => !v || v.length === 0 ? "Required" : void 0
476
+ });
477
+ if (p.isCancel(customFile)) {
478
+ p.cancel("Operation cancelled.");
479
+ process.exit(0);
480
+ }
481
+ target = resolveTarget("custom", customDir, customFile);
482
+ } else {
483
+ target = BUILTIN_TARGETS[targetChoice];
484
+ }
485
+ } else {
486
+ p.log.info(`Target: ${target.description}`);
487
+ }
344
488
  const presets = await listPresets();
345
489
  if (presets.length === 0) {
346
490
  p.cancel("No presets available.");
@@ -403,11 +547,13 @@ async function interactiveInit() {
403
547
  }
404
548
  const s = p.spinner();
405
549
  s.start("Generating project files...");
406
- await generateAndWrite(preset, agentSlugs, skillSlugs);
550
+ await generateAndWrite(preset, agentSlugs, skillSlugs, target);
551
+ saveConfig(target);
407
552
  s.stop("Project files generated.");
408
- p.outro(pc3.green(`Done! ${agentSlugs.length} agent(s), ${skillSlugs.length} skill(s), CLAUDE.md ready.`));
553
+ p.outro(pc3.green(`Done! ${agentSlugs.length} agent(s), ${skillSlugs.length} skill(s), ${target.contextFile} ready.`));
409
554
  }
410
555
  async function nonInteractiveInit(presetSlug, opts) {
556
+ const target = opts.target;
411
557
  const preset = await getPreset(presetSlug);
412
558
  const allAgents = await listAgents();
413
559
  let agentSlugs = [...preset.agents];
@@ -448,18 +594,19 @@ async function nonInteractiveInit(presetSlug, opts) {
448
594
  console.log(pc3.bold(pc3.cyan(`
449
595
  Initializing preset "${preset.name}"...
450
596
  `)));
451
- await generateAndWrite(preset, agentSlugs, skillSlugs);
597
+ await generateAndWrite(preset, agentSlugs, skillSlugs, target);
598
+ saveConfig(target);
452
599
  console.log(
453
600
  pc3.bold(
454
601
  pc3.cyan(
455
602
  `
456
- Done! ${agentSlugs.length} agent(s), ${skillSlugs.length} skill(s), CLAUDE.md ready.
603
+ Done! ${agentSlugs.length} agent(s), ${skillSlugs.length} skill(s), ${target.contextFile} ready.
457
604
  `
458
605
  )
459
606
  )
460
607
  );
461
608
  }
462
- async function generateAndWrite(preset, agentSlugs, skillSlugs) {
609
+ async function generateAndWrite(preset, agentSlugs, skillSlugs, target) {
463
610
  const agentResults = await Promise.allSettled(
464
611
  agentSlugs.map((slug) => getAgent(slug))
465
612
  );
@@ -478,13 +625,14 @@ async function generateAndWrite(preset, agentSlugs, skillSlugs) {
478
625
  if (slug === "orchestrator") {
479
626
  orchestratorTemplate = result.value.rawContent;
480
627
  } else {
481
- writeAgent(slug, result.value.rawContent);
628
+ writeAgent(target, slug, result.value.rawContent);
482
629
  console.log(pc3.green(` \u2713 Agent: ${slug}`));
483
630
  }
484
631
  agentInfos.push({
485
632
  slug,
486
633
  name: fm.name || slug,
487
- role: fm.role || ""
634
+ role: fm.role || "",
635
+ description: fm.description || ""
488
636
  });
489
637
  agentsWithSkills.push({
490
638
  slug,
@@ -502,22 +650,22 @@ async function generateAndWrite(preset, agentSlugs, skillSlugs) {
502
650
  agentsWithSkills,
503
651
  skillSlugs
504
652
  );
505
- writeOrchestrator(orchestratorContent);
506
- console.log(pc3.green(` \u2713 orchestrator.md generated`));
653
+ writeOrchestrator(target, orchestratorContent);
654
+ console.log(pc3.green(` \u2713 ${target.orchestratorFile} generated`));
507
655
  }
508
656
  for (let i = 0; i < skillSlugs.length; i++) {
509
657
  const slug = skillSlugs[i];
510
658
  const result = skillResults[i];
511
659
  if (result.status === "fulfilled") {
512
- writeSkill(slug, result.value.rawContent);
660
+ writeSkill(target, slug, result.value.rawContent);
513
661
  console.log(pc3.green(` \u2713 Skill: ${slug}`));
514
662
  } else {
515
663
  console.log(pc3.yellow(` \u26A0 Skill "${slug}" skipped: ${result.reason}`));
516
664
  }
517
665
  }
518
- const claudeContent = generateClaudeMd(preset, agentInfos);
519
- writeClaudeMd(claudeContent);
520
- console.log(pc3.green(` \u2713 CLAUDE.md generated`));
666
+ const contextContent = generateContextFile(preset, agentInfos, target, skillSlugs);
667
+ writeContextFile(target, contextContent);
668
+ console.log(pc3.green(` \u2713 ${target.contextFile} generated`));
521
669
  }
522
670
  function computeAvailableSkills(preset, selectedAgentSlugs, allAgents, allSkillSlugs) {
523
671
  const linkedToSelected = /* @__PURE__ */ new Set();
@@ -545,10 +693,37 @@ program.name("loom").description("Integrate Loom library (agents, skills, preset
545
693
  program.command("list").description("List available agents, skills, and presets").argument("[type]", "Filter by type: agents, skills, or presets").action(async (type) => {
546
694
  await listCommand(type);
547
695
  });
548
- program.command("add").description("Download an agent or skill from the library").argument("<type>", "Type: agent or skill").argument("<slug>", "Slug of the agent or skill").action(async (type, slug) => {
549
- await addCommand(type, slug);
696
+ program.command("add").description("Download an agent or skill from the library").argument("<type>", "Type: agent or skill").argument("<slug>", "Slug of the agent or skill").option("--target <name>", `Output target: ${[...listTargetNames(), "custom"].join(", ")}`, DEFAULT_TARGET).option("--target-dir <dir>", "Custom target directory").option("--context-file <file>", "Custom context file name").action(async (type, slug, opts) => {
697
+ const savedConfig = loadConfig();
698
+ const target = opts.target !== DEFAULT_TARGET || opts.targetDir || opts.contextFile ? resolveTarget(opts.target, opts.targetDir, opts.contextFile) : savedConfig ?? BUILTIN_TARGETS[DEFAULT_TARGET];
699
+ await addCommand(type, slug, target);
550
700
  });
551
- program.command("init").description("Initialize a project with a preset (agents + skills + CLAUDE.md)").argument("[preset]", "Preset slug (interactive if omitted)").option("--add-agent <slugs...>", "Add extra agents").option("--remove-agent <slugs...>", "Remove agents from preset").option("--add-skill <slugs...>", "Add extra skills").option("--remove-skill <slugs...>", "Remove skills from preset").action(async (preset, opts) => {
552
- await initCommand(preset, opts);
701
+ program.command("init").description("Initialize a project with a preset (agents + skills + context file)").argument("[preset]", "Preset slug (interactive if omitted)").option("--add-agent <slugs...>", "Add extra agents").option("--remove-agent <slugs...>", "Remove agents from preset").option("--add-skill <slugs...>", "Add extra skills").option("--remove-skill <slugs...>", "Remove skills from preset").option("--claude", "Use Claude Code target (.claude/ + CLAUDE.md)").option("--cursor", "Use Cursor target (.cursor/ + .cursorrules)").option("--target <name>", `Output target: ${[...listTargetNames(), "custom"].join(", ")}`).option("--target-dir <dir>", "Custom target directory").option("--context-file <file>", "Custom context file name").action(async (preset, opts) => {
702
+ let target;
703
+ let targetExplicit = false;
704
+ if (opts.claude) {
705
+ target = BUILTIN_TARGETS["claude-code"];
706
+ targetExplicit = true;
707
+ } else if (opts.cursor) {
708
+ target = BUILTIN_TARGETS["cursor"];
709
+ targetExplicit = true;
710
+ } else if (opts.target) {
711
+ target = resolveTarget(
712
+ opts.target,
713
+ opts.targetDir,
714
+ opts.contextFile
715
+ );
716
+ targetExplicit = true;
717
+ } else {
718
+ target = BUILTIN_TARGETS[DEFAULT_TARGET];
719
+ }
720
+ await initCommand(preset, {
721
+ addAgent: opts.addAgent,
722
+ removeAgent: opts.removeAgent,
723
+ addSkill: opts.addSkill,
724
+ removeSkill: opts.removeSkill,
725
+ target,
726
+ targetExplicit
727
+ });
553
728
  });
554
729
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@folpe/loom",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI to scaffold Claude Code projects with curated agents, skills, and presets",
5
5
  "type": "module",
6
6
  "license": "MIT",