Imported from Sidub-Inc/Monaiq.AI.Plugin (
skills/manage-catalog/SKILL.md). Install upstream withnpx skills add Sidub-Inc/Monaiq.AI.Plugin --skill manage-catalog. Copyright stays with the author.
<execution_context>
Follows the skill layout and shared workflows in _shared/protocols.md. This skill contributes only catalog-specific decisions and product/product_feature/offering/feature_offering tool calls.
</execution_context>
Output: catalogSpec: { productCode, features: [{ key, type, displayName }], offerings: [{ code, classification, baseRate, currency, interval }], assignments: [{ featureKey, offeringCode, accessLevel | rateLimit }] }, preserved route boundaries (activePlatform, targetProject, outOfScopePlatforms), plus catalogComplete: true after read-back verification. Downstream chain: manage-catalog -> implement-licensing -> implement-feature.
- No products -> full creation flow.
- Products exist, no features -> create features for existing product.
- Products and features exist, no offerings -> create offerings.
- Products, features, offerings exist but assignments are missing -> create assignments.
- Everything exists -> show catalog summary and use utility workflows.
New Catalog Flow
Response Pattern. Follow _shared/protocols.md § Response Pattern. The gate this skill owns is catalog mutation. Evidence sources, in priority order: quickStartSpec from getting-started, pricingPlan from Discovery delegation (analyze-codebase + scenario-advisor + design-monetization), prior journal discoveredCapabilities, existing catalog state, conversation cues. Recommendation precedes evidence in every reply; never open with "what features does your product have?".
Interaction 1: starter product and features
Recommend a starter product (name + derived code) and feature set inferred from upstream evidence. Map binary capabilities to ProductAccessFeature, usage-counted capabilities to ProductRateLimitFeature; derive feature keys lowercase-hyphenated from the capability name. Present as the default; invoke the Host-Native Ask Pattern (see _shared/protocols.md § Host-Native Ask Pattern) with options: approve the starter catalog, refine features, refine the product name, or pause to inspect the source analysis. Block until the user responds.
Confirm via CHECKPOINT-PRE-CATALOG-MUTATION before any product / product_feature create call. Smart defaults: Product Status = Active, feature key derived from name.
Interaction 2: starter pricing
Ask how the user wants to charge, or use quickStartSpec.pricingChoice if provided. When asking, invoke the Host-Native Ask Pattern (see _shared/protocols.md § Host-Native Ask Pattern) with the pricing options listed below as option labels. Block until the user responds.
Present pricing options in plain language:
- "Free trial + paid subscription" → Create a Trial offering (14 days, $0) + Subscription offering ($X/month)
- "Just a subscription" → Create a Subscription offering ($X/month)
- "One-time purchase" → Create a Perpetual offering ($X one-time)
- "Free tier + paid tier" → Create a free Subscription ($0/month) + paid Subscription ($X/month)
- "Usage-based" → Create a Subscription with usage limit values scaled per tier
For each pricing tier (called an Offering in Monaiq), apply smart defaults:
- Currency:
USD - Interval: 1 Month for Subscription, none for Perpetual, 14 days for Trial
- Status:
Draft(safe default — user publishes when ready)
[CONFIRM] Execute tool calls: offering (create for each tier) → feature_offering (assign features to each offering).
Default assignment values:
-
Paid tiers: All feature flags (
ProductAccessFeature) set toAllowed, usage limits (ProductRateLimitFeature) at user-specified or suggested quotas -
Free/Trial tiers: Feature flags selectively
Allowed/Deniedbased on user description, usage limits at reduced quotas -
Catalog identifiers (offering ids, product ids, feature keys) referenced in code MUST live in a constants module. Inline string literals are forbidden (D-30).
Required payload shape — feature_offering create for an access feature. ServiceAccessLevel is required; omitting it is rejected by the API. Always send it explicitly:
{
"__sidub_entityType": "ProductFeatureOffering.ServiceAccess",
"OfferingId": "<offering-id>",
"FeatureKey": "<feature-key>",
"ServiceAccessLevel": "Allowed"
}
For rate-limit features, both SampleSeconds and RateLimit are required (use matching "unlimited" strings or matching positive integers — asymmetric combinations are rejected).
Read-back verification (mandatory after any create/update of paid-tier assignments):
- Call
feature_offering(list) for each paid offering. - Assert every
ProductFeatureOffering.ServiceAccessrow hasServiceAccessLevel: "Allowed"(unless the user explicitly intendedDeniedfor that tier). - If any assignment shows
ServiceAccessLevel: "Denied"that the user did not intend, stop and surface it to the user — this is the silent-failure mode where customers receive credentials butAssertLicensealways returnsfalse. Re-runfeature_offering(update) with the correct level.
Utility Workflows
When state detection shows everything already exists, offer these options:
- Update features: Add new features to existing product, modify feature key, change feature type
- Modify offerings: Change pricing, update billing interval, change license type (e.g., promote Trial to Subscription — called
LicenseClassificationin Monaiq) - Modify assignments: Change feature values for a pricing tier — toggle access, adjust rate limits
- Add tier: Create a new pricing tier (Offering) and assign features (common when adding a free or enterprise tier)
- View catalog: Show full product → features → pricing tiers → feature assignments summary
| Failure Point | Symptom | Recovery Action |
|---|---|---|
| Product creation fails | Tool returns error on product create |
Retry once. If persistent, check session is authenticated via register_or_login. |
| Feature creation fails after product created | product_feature returns validation error |
Product is safe — retry the feature creation with corrected input. List existing features first to avoid duplicates. |
| Offering creation fails after features created | offering returns error |
Product and features are safe. Retry offering creation. Check that LicenseClassification is valid (Trial, Subscription, or Perpetual). |
| Feature assignment fails after offering created | feature_offering returns error |
Offering exists but is incomplete. Retry assignment. Verify FeatureKey matches exactly and feature type matches assignment type (Access → ServiceAccessFeatureOffering, RateLimit → RateLimitFeatureOffering). |
| Partial catalog state | Some entities created, process interrupted | Re-run state detection — the skill will resume from the last incomplete step. Already-created entities are preserved. |
All catalog operations are idempotent at the entity level — creating a product that already exists will return the existing entity. Feature assignments can be updated in place.
<success_criteria>
- Product exists with features, offerings configured with pricing, all features assigned to offerings with correct values
- Read-back verification passes
- catalogSpec output-context populated for downstream skills </success_criteria>