Skip to main content

// catalog specialist

Run the lifecycle of every SKU.

Sync, classify, decide, execute. Each product sits in one lifecycle state, every move is checked against ALLOWED_TRANSITIONS, and each change written to Shopify carries a decision row you can reverse.

Live Shopify Admin GraphQL 8 lifecycle states Dry-run + Live phases 1,785 product changes written to Shopify (last 30 days, measured 17 Oct 2026)
decision_log · catalog · example
product     : "Brushed Linen Throw — Sand"
variant     : 'SKU-LIN-228-SND-L'
from_state  : OPTIMIZING
to_state    : ON_DISCOUNT
action      : DISCOUNT_TEST
delta       : −15% (€89 → €76)
window      : 14d, then reverted

reason      : OPTIMIZE_CYCLE_FAILED (2 cycles)
              margin tier = A (verified)
              p75 winner floor = 2.4x ROAS
              current ROAS    = 1.6x (28d)

evidence    : [perf#9123, cycle#771]
applied_at  : 2026-05-25T08:02:14Z
applied_by  : catalog_agent.discount_executor

status      : APPLIED (live)
reversal    : price restored on day 14
next: classify cycle 09:00logged

// what it does

Four phases. One loop. Every cycle.

The Catalog Specialist runs on a daily cycle for each store, not as a one-time sync. Each decision is written with the evidence it was made on.
01

Sync

catalog_sync pulls Shopify products, variants, and cost_per_item into the products table with Tier A cost confidence. performance_sync ingests Shopify orders + Google Ads spend into performance_daily per (date, variant_id).

catalog_syncperformance_syncTier A
02

Classify

self_calibrator derives thresholds from your store's own performance distribution: winner floor at p75, loser floor at p25, no hardcoded ROAS rules. classifier assigns WINNER / MID / LOSER / INSUFFICIENT_DATA / SEASONAL every cycle.

self_calibratorclassifierp75 / p25
03

Decide

decision_engine emits an Action enum per SKU: KEEP, SCALE_WINNER, OPTIMIZE_LOSER, DISCOUNT_TEST, DRAFT, VAULT, REVIVE_SEASONAL. Every state change validated against ALLOWED_TRANSITIONS before write.

decision_engineALLOWED_TRANSITIONSAction enum
04

Execute

action_executor mutates Shopify (draft / publish / edit). discount_executor changes prices. copy_rewriter rewrites titles + descriptions via LLM, gated by a trademark filter.

action_executordiscount_executorcopy_rewriter

// the real product

The catalog, graded and stateful.

A real screenshot of the dashboard, with demo store data. Every SKU carries its lifecycle state, grade, and margin in one view.
app.magistry.io/dashboard/catalog
The Magistry catalog view: products listed with lifecycle state, performance grade, price, and margin per SKU

// product deep view

Every SKU has a full dossier.

Click into any product and you get the whole history and the evidence the agent decides on.

180-day timeseries

Revenue, spend, ROAS, and orders per day, the same window the classifier reads.

Variants heatmap

Per-variant performance at a glance: the size that carries the product and the color that drags it.

Decision history

Every lifecycle move, price change, and copy rewrite the agent made on this SKU, with its evidence.

Copy versions

Each generated title and description is versioned, so you can compare what shipped and roll back.

// lifecycle state machine

Eight states. One state per SKU. Always.

Every product variant lives in exactly one lifecycle state. Transitions are validated against the ALLOWED_TRANSITIONS map before any catalog write. A move outside the map is refused and nothing is written to Shopify.
01

AUDIT

Fresh import, awaiting first decision.

02

PUBLISHED

Live on storefront, gathering signal.

03

ACTIVE

Selling within range, keep cycle.

04

OPTIMIZING

Copy or pricing under iteration.

05

ON_DISCOUNT

Discount window open, time-bounded.

06

DRAFTED

Unpublished, removed from catalog.

07

SEASONAL_VAULT

Parked off-season, republished when its season returns.

08

ARCHIVED

Terminal. Nothing moves a product out of it automatically.

ALLOWED_TRANSITIONS
AUDIT          → PUBLISHED, ACTIVE, OPTIMIZING,
                 ON_DISCOUNT, DRAFTED,
                 SEASONAL_VAULT, ARCHIVED
PUBLISHED      → ACTIVE, DRAFTED
ACTIVE         → OPTIMIZING, ON_DISCOUNT,
                 DRAFTED, SEASONAL_VAULT
OPTIMIZING     → ACTIVE, ON_DISCOUNT
ON_DISCOUNT    → ACTIVE, DRAFTED
DRAFTED        → ACTIVE, SEASONAL_VAULT,
                 ARCHIVED
SEASONAL_VAULT → PUBLISHED, ARCHIVED
ARCHIVED       → (terminal)

validate(from, to) → bool
invalid → refused, nothing written

// action enum

The full move set.

decision_engine emits one of these per SKU per cycle. Each action carries its own trigger and its own valid from-states, and every write records what stood there before so it can be reverted.
ActionWhat it doesValid fromTrigger
KEEPContinue selling at current price.PUBLISHED, ACTIVEWithin ROAS band
SCALE_WINNERFlagged for budget lift on paid side.ACTIVEROAS > p75 winner floor
OPTIMIZE_LOSERCopy + image regenerate cycle.AUDIT, ACTIVEROAS below the store's loser ceiling
DISCOUNT_TEST14-day price test, then reverted. Needs Tier A cost and a margin above the floor.AUDIT, ACTIVE, OPTIMIZINGOPTIMIZE_CYCLE_FAILED
DRAFTUnpublish from storefront.ON_DISCOUNT, ACTIVESALES_ZERO_N_DAYS
VAULTPark as seasonal candidate.AUDIT, ACTIVE, DRAFTEDSeasonal pattern, currently off-season
REVIVE_SEASONALRepublish ahead of season window.SEASONAL_VAULTSeasonal revive, proposed for review

// cost confidence

Tier-gated writes. No guesswork.

Magistry will not move money or change prices on a SKU whose margin it cannot prove. Every variant gets one of three cost confidence tiers, and the tier decides what the agent is allowed to do.

Tier A

// data source

Shopify cost_per_item field, confirmed per variant.

// what is allowed

All actions enabled: price changes, scale, archive, publish.

Tier B

// data source

Supplier cost discovered via reverse-image match against supplier sites.

// what is allowed

Performance-based actions such as KEEP and OPTIMIZE_LOSER. No price or discount writes.

Tier C

// data source

Missing or unverifiable cost, orphan SKU.

// what is allowed

No price or discount writes. Lifecycle moves can still apply.

Why this matters. Most catalog tools assume your cost data is right. Magistry assumes it isn't: every SKU is scored, every write is gated, and a product without Tier A cost never gets a discount on its own. Your margin floor is checked in code before any price write.

// catalog specialist

See your catalog the way Magistry sees it.

Connect your Shopify store and the Catalog Specialist starts in dry-run: every product classified and every proposed action explained, with nothing written to Shopify until you switch it to live.

Starts in dry-run · One owner per change · Catalog changes reversible