Full-funnel positionless AI marketing for tabletop brands.
Any SKU a customer can grip, rotate, and inspect in 3D — bottles, jars, tubes, tins, boxes, sachets. Paste one web page URL from the brand's own domain and get back a brand-safe 3D configurator plus publishable creative. AGPL-3.0, self-hostable.
Status: pre-v0.1.
apps/landingis the only app with runtime code. Every otherapps/*,packages/*, andinfra/*entry is a scaffold — the tree below is a build plan, not a shipped system. Dates and definitions of done live inMILESTONES.md; the $/mo baseline lives inCOSTS.md; locked decisions and their reasoning live indocs/decisions/.
Shoploop turns an existing brand's own web pages into a governed, measurable content supply chain: one reusable product twin per SKU powers the shopper experience, campaign production, publishing, and the feedback loop that decides what to make next.
Shoploop is a CPG-specialized, agentic 3D commerce layer whose canonical Product Graph Port is Shoploop-owned, with Pimcore as its first and preferred adapter — not another PIM, and not a closed twin factory.
The Product Graph Port is the canonical contract, and Pimcore is the one bound product spine in Phase 1: Data Objects, Classification Store, Data Quality, Studio Backend REST, Datahub GraphQL (ADR 0003). Out of the box those are horizontal, category-agnostic primitives. Shoploop specializes them for the workflows tabletop CPG actually has — volume and pack variant axes on one parametric container, regulated-claim and compliance fields that are human-locked, ingredient trees deep enough to drive molecular storytelling, and a twin manifest that points at OpenUSD layers instead of at flat renders — and then adds the two planes Pimcore is architecturally wrong for:
| Plane | Runtime | Why not Pimcore |
|---|---|---|
| Behaviour + posterior | PostHog (one shared partition) + pybandits inside Temporal |
PHP-FPM on single-AZ RDS is a cold-path system of record. High-frequency shopper events never touch a Pimcore field; only versioned aggregates cross back. |
| Twin + render | Blender headless authoring → usd-runtime canonicalization → Kit-App-Template + OVAS |
There is no GPU path in PHP. Pimcore holds the manifest and the artifact versions, not the pixels. |
The result is the surface no one in the category ships: a streamed 3D configurator the shopper actually uses, wired as the sensor that feeds the production loop. The enterprise twin factories generate channel assets and read back aggregate campaign performance; the CDPs read customer events but have no product twin. Shoploop closes the gap between them with Shoploop Core at $0 and AGPL-3.0, self-hostable in the brand's own infrastructure. Third-party adapters and deployment components keep their own licences and costs; the complete Pimcore-backed stack is not unconditionally $0 to self-host (ADR 0021).
The full technical teardown of the vendors that own the adjacent planes — and the OSS bill of materials proving each piece is adopted rather than rebuilt — is in docs/competitive/. The commercial matrix is docs/competitive-matrix.md.
Intake is still one URL. The parser resolves whatever page is pasted to a PDP (ADR 0011), then discovers the rest of that same domain's public PDPs to build the catalog (ADR 0018). Same-domain only, robots.txt honoured, authorized domains only. Catalog discovery is the Phase 2 acceptance target, not shipped — see the status note above.
Shoploop is an infrastructure project. The work is plumbing — NVIDIA Omniverse, Pimcore, and AWS wired into one governed, scalable, enterprise-ready pipeline. The work is not inventing schemas, hashes, validators, or protocols.
Law 0 — never rebuild a solved problem. Every layer here already has a governed standard, an official SDK, or a maintained reference implementation.
docs/STANDARDS.mdis the normative registry of all of them, locked by ADR 0012. A PR that re-encodes anything in it is closed, not reviewed.
| Layer | Standard adopted | Never build |
|---|---|---|
| Product + variant contract | OpenUSD — UsdGeom, UsdShade, UsdVariantSets |
a product/geometry JSON Schema |
| Domain schema authoring | usdGenSchema + applied API schemas |
a schema compiler |
| Material fidelity | OpenPBR Surface + MaterialX | a private PBR spec |
| Asset identity | SdfLayer + Ar 2.0 |
a content-hash scheme |
| Validation | usdchecker |
an asset linter |
| USD authoring | OpenUSD Exchange SDK | raw Sdf/Usd helpers |
| Delivery packaging | USDZ | a single-file 3D format |
| Canonical product-data boundary | Shoploop-owned Product Graph Port with one bound adapter (ADR 0021) | a second graph or multi-adapter runtime |
| Product data implementation | Pimcore Data Objects / Classification Store / Data Quality | a mirrored product table |
| PIM access | Pimcore Studio Backend REST + Datahub GraphQL | a REST gateway |
| GPU app | kit-app-template + Kit Extensions |
a Kit bootstrapper |
| Streaming | Omniverse App Streaming (OVAS) + NGC Helm charts | a WebRTC session broker |
| Browser viewport | web-viewer-sample |
a client-side USD renderer |
| GPU on AWS | NVIDIA GPU Operator on EKS | device-plugin manifests |
| Geometry + material authoring | Blender headless + bpy + Geometry Nodes |
a modelling kernel, UV unwrapper, or texture baker |
| Authoring + batch render plane | AWS Deadline Cloud (Blender) | an SQS render farm |
| Page → product data | schema.org Product + Open Graph via extruct |
a DOM/regex extractor |
| Product identity | GS1 Digital Link | a private product-ID scheme |
| Orchestration | Temporal | a Postgres job queue |
| Experimentation | PostHog Experiments + Holdouts | an A/B stats engine |
| Bandit posterior | pybandits |
hand-written sampling math |
| Publishing | Postiz Public API + MCP | a scheduling API |
| OAuth | Nango | per-platform OAuth flows |
| Agent tool-calling | MCP | a function-schema convention |
Full registry, licenses, and license traps: docs/STANDARDS.md. What gets built in what order, and what closes each phase: docs/BUILD_ORDER.md.
v1 is the twin and the world around the twin. URL → Product Graph Port → bound Pimcore record → OpenUSD twin (OpenPBR/MaterialX materials, variant sets, BrandRulesAPI applied schema) → usdchecker gate → Kit app on AWS GPU → Omniverse App Streaming → configurator link. One neutral tenant, end to end, streaming — that is the plumbing gate.
The target demonstration is the catalog-scale content factory (ADR 0018): one existing brand website URL in, public PDPs discovered on that domain, ≥10 accepted tabletop SKUs written through the Product Graph Port into bound Pimcore, one real OpenUSD twin each, and ≥250 assets out — 5 compositions × 5 aspect ratios (9:16, 1:1, 16:9, 3:4, 4:5) per SKU — from shared twins and manifests, with a single human gate on the Pimcore record.
v2 is everything downstream of the twin: operator shot builder, Postiz publishing, Nango connectors, PostHog posterior, Thompson Sampling, multi-tenancy, page-writer, embed, i18n. Specified and scaffolded — not started until the v1 twin streams. See ADR 0012.
Countertop / shelf-visible SKUs. Not injectables, devices, or Rx-only. First wedge: Ayurveda + nutraceutical + OTC wellness — molecular storytelling plus near-zero 3D adoption makes it the softest target. Beyond the wedge: skincare, spirits, coffee, sauces, supplements, candles.
Shoploop is a single pnpm monorepo. One workspace, one PR queue, one CI pipeline. Earlier prose describing a four- or five-repo split (shoploop-core, shoploop-delivery, shoploop-growth, shoploop-postiz) is obsolete.
apps/
landing → shoploop.studio marketing + URL intake
operator-studio → shoploop.studio/op/{slug}
configurator → shoploop.studio/{slug}
packages/
page-parser → URL → DOM + JSON-LD + OG + PDP heuristics → product draft
product-graph → canonical vendor-neutral Product Graph Port + conformance suite
pimcore-sdk → first and preferred Pimcore adapter behind the port
usd-runtime → Blender job manifests + pinned bpy scripts; canonicalizes the
Blender export into the OpenUSD twin, variant sets, stage
composition (Exchange SDK)
brand-rules → BrandRulesAPI applied schema (usdGenSchema) + usdchecker/OpenPBR CI gate
page-writer → page updates: PR against the page repo, or hosted publish API (Loop 6)
embed → embeddable configurator/viewer widget
postiz-client → arm's-length client for the Postiz public API + MCP
i18n → locale contract + Language-QA fixtures (Loop 7 — deferred, ADR 0008)
connector-shopify → optional secondary ingest (never the front door)
connector-google-ads → optional secondary ingest (never the front door)
infra/
kit-app-template → Omniverse Kit app for streaming
streaming → Omniverse App Streaming plane
pimcore → Pimcore deployment
postiz → Postiz deployment (upstream image, pinned by digest)
The tree above is canonical. packages/product-graph is accepted by ADR 0021 but is not on disk until the separate contract implementation PR; every other entry shown reflects the 2026-07-27 tree cleanup. campaigns/, growth/, shopify/ and landings/ were deleted; connectors/* became packages/connector-*; apps/shoploop-studio-site became apps/landing; root design.md became docs/design-system.md. Everything is recoverable from the archive/pre-cleanup-2026-07-27 tag. Do not recreate those directories.
The only intake is a product web page link. Paste any PDP, landing page, Linktree, or brand homepage and Shoploop parses it through the Product Graph Port into a product record in the bound Pimcore adapter, a USD product twin, brand rules, and a variant graph. No catalog upload, no OAuth wizard, no CSV.
Platform connectors (Shopify, Google Ads, and anything brokered through Nango) are optional secondary ingest — enrichment after the URL, never the front door.
Inspired by the NVIDIA OpenUSD product configurator reference architecture: aggregate the product data, express it as OpenUSD, expose variants (model × material × style × artwork), render, QC, distribute.
One web page URL on the brand's own domain
→ page-parser: resolve to a PDP (ADR 0011), then discover the same-domain catalog (ADR 0018)
→ Product Graph Port → bound Pimcore PXM graph — the Phase 1 source of truth, one object per accepted SKU
→ Blender headless: parametric geometry, UV unwrap, label projection,
material authoring, texture bake — a deterministic executor, typed
manifest in, pinned scripts, editable .blend retained and versioned
→ usd-runtime: canonicalizes the Blender export → one OpenUSD twin per SKU
+ UsdVariantSets, OpenPBR/MaterialX materials via UsdShade
→ usd-content-agents: Material/Texture enrichment where evidence is
uncertain; the Validation Agent advises the pbr_score
→ brand-rules: BrandRulesAPI applied schema, usdchecker is the hard gate,
the OpenPBR fidelity score (≥ 0.85) advises alongside it
→ render: Kit-App-Template + Omniverse App Streaming, or Blender/Cycles still + MP4
→ two links out per tenant: /op/{slug} (operator) and /{slug} (shopper)
→ Postiz publishes to Meta / Google / YouTube Shorts — gate runs first
→ PostHog (one shared partition) measures impact
→ posterior compounds nightly → BrandRulesAPI
Two links out is the deliverable — exactly two entry links per tenant, however many SKUs one URL discovers. Everything else is plumbing.
| Component | Platform | Target |
|---|---|---|
apps/landing |
Vercel | shoploop.studio |
apps/operator-studio |
Vercel | shoploop.studio/op/{slug} |
apps/configurator |
Vercel | shoploop.studio/{slug} |
| Postiz | AWS | internal publishing service |
| Pimcore | AWS | first and preferred Product Graph Port adapter; Phase 1 source of truth |
| Temporal | AWS | separate namespaces/task queues per domain |
| PostHog | AWS | single shared partition |
| Nango | AWS | OAuth broker for optional connectors |
| Omniverse Kit app | AWS | GPU |
| Streaming plane | AWS | GPU |
shoploop.studio is the canonical production landing and URL-intake surface. All Shoploop customer-facing frontends deploy to Vercel; everything non-frontend runs on AWS. GPU workloads never run on Vercel. The Postiz admin/frontend bundled in the upstream image is an internal AWS surface, not a Shoploop customer-facing frontend.
Blender headless authors the twin — parametric geometry via Geometry Nodes, UV unwrap, label projection, Principled BSDF materials, texture baking, Cycles reference renders. It runs as a deterministic executor driven by a typed job manifest and pinned Shoploop-owned scripts, invoked by Temporal, with no arbitrary tenant Python. The editable .blend source is a retained, versioned artifact, not a build temporary. packages/usd-runtime then canonicalizes that export into the real contract: OpenPBR/MaterialX via UsdShade, UsdVariantSets, BrandRulesAPI, correct layers. A Blender export is never the shipped layer (ADR 0019).
The agent-facing path for bounded operator authoring and diagnosis is the official Blender Foundation Lab MCP server (Blender 5.1+), preferred over any community reimplementation. It executes LLM-generated code with no guards, so it runs only inside per-job/per-tenant isolation with scoped job-only credentials and allowlisted egress — never on the unattended batch path, and its output re-enters through canonicalization and the same gates.
Real Pimcore USD twins with BrandRulesAPI materials and lighting are streamed via NVIDIA Kit-App-Template + Omniverse App Streaming through the official web-viewer-sample client. The offline path is Blender/Cycles stills and MP4 via AWS Deadline Cloud — the same Blender, in its second role. No cheap Three.js stand-in for a real twin — React Three Fiber is chrome only (ADR 0005).
Four runtimes, strictly ordered. 1. Temporal — the deterministic workflow/control plane and the only orchestrator · 2. NemoClaw / OpenShell — the primary governed agent runtime for reasoning, tool use, and specialist orchestration, and the isolation boundary for the Blender MCP server · 3. Pimcore — canonical PXM state, not an agent runtime · 4. Blender headless — the deterministic batch authoring executor, not an orchestrator. Alongside them, NVIDIA usd-content-agents are post-authoring Material/Texture/Validation specialists, not the pipeline — and because Texture and Validation are Research Preview, the pbr_score advises alongside usdchecker, never instead of it. Kit + OVAS render and stream; they neither author nor orchestrate. Locked by ADR 0019.
Postiz is deployed as a separate AWS service from the official ghcr.io/gitroomhq/postiz-app image, pinned by immutable digest. No Postiz source is vendored into this workspace for v0.1; integration is arm's-length through the Postiz public API and MCP. Brand-rules gates run before anything publishes. See docs/orchestration-postiz.md and infra/postiz/UPSTREAM.md.
Shoploop ships its own scheduling frontend. Operators schedule, review, and track posts in apps/operator-studio on Vercel — a native Shoploop wrapper over Postiz capabilities, talking through packages/postiz-client to the AWS-hosted Postiz public API. The raw Postiz admin UI bundled in the upstream image stays internal on AWS for ops and debugging. It is never iframed into a Shoploop surface and never publicly exposed as the Shoploop product.
See LOOP_SPEC.md — ten loops, eleven entries (Loop 1b is the optional-connector sub-loop of Loop 1). Each loop is defined against the 9-primitive framework (Target · Fitness · Search Space · Stopping · Mutation · Memory · Ground Truth · Boundary · Decay). None of the loops run yet; see MILESTONES.md.
Frontend: TypeScript · React 19 · Next.js 15 · React Three Fiber (UI/scene chrome, never product twins) · Framer Motion · Tailwind
Product graph: Shoploop-owned Product Graph Port; Pimcore is the first, preferred, and only Phase 1 adapter — Data Objects, Classification Store, Data Quality, Studio Backend REST, Datahub GraphQL
3D contract: OpenUSD (UsdGeom · UsdShade · UsdVariantSets) · usdGenSchema applied API schemas · OpenPBR Surface · MaterialX · USDZ · Ar 2.0 · usdchecker · OpenUSD Exchange SDK
Authoring: Blender headless CLI + bpy · Geometry Nodes · UV unwrap + label projection · Principled BSDF → MaterialX · texture baking · Cycles reference renders — typed job manifests, pinned Shoploop-owned scripts only · official Blender Foundation Lab MCP server for bounded, isolated intervention
Rendering: NVIDIA Kit-App-Template · Kit SDK Extensions · Omniverse App Streaming (OVAS) · web-viewer-sample · usd-content-agents (post-authoring enrichment + advisory validation) · Blender/Cycles + MolecularNodes offline path
Intake: URL fetch → extruct (JSON-LD + microdata + RDFa + OG) → schema.org Product → Product Graph Port → bound Pimcore adapter → USD twin + BrandRulesAPI
Backend / Infra: Node.js · Python · Postgres/Supabase · Nango (self-hosted OAuth broker) · Temporal (per-domain namespaces) · AWS EKS + NVIDIA GPU Operator · g5.xlarge spot · AWS Deadline Cloud · S3 + CloudFront · Vercel (frontends only)
AI / Agent: Mistral / Codestral · MCP · pybandits Thompson Sampling · autoresearch loops
Analytics: PostHog — one shared partition, tenant-scoped, native Experiments + Holdouts
Distribution: Postiz (upstream image, arm's-length API/MCP) · Google Ads · Meta Ads · Klaviyo
Every entry above is an adopted standard or upstream component, not a Shoploop invention. Licenses and traps: docs/STANDARDS.md.
| Dependency | Status |
|---|---|
| Polotno production SDK | Rejected for now. Commercial, closed-source, $899/month self-serve (pricing, license). Not approved, not budgeted, and must not become a production dependency. |
Polotno publishes an open JSON scene schema, offers a free hosted Studio demo, and is built on the open-source Konva canvas library. None of that makes the Polotno SDK open source — the SDK is proprietary and separately licensed, and adopting it means paying for it. Treat the schema, the demo, and Konva as three separate things from the product we would be buying.
No editor is being selected — the requirement is deleted (ADR 0009). The Operator link authors a shot list: a typed spec of camera, lighting, variant, molecule and overlay text, constrained by brand_rules, stored on the Pimcore record and composited server-side by Omniverse Kit on AWS. Nothing is hand-positioned in a browser, because Loop 3's nightly Thompson Sampling pass has to be able to mutate the composition — and a declarative spec is a search space where a canvas document is opaque state. grip.tools has no canvas editor either; it wins on production at scale, which is where the dev time goes.
Also evaluated and rejected: Konva/react-konva and Fabric.js (right tools, deleted requirement), PixiJS (wrong category), tldraw (production license key), Penpot (a second application to operate), and Jaaz — its Community License prohibits team deployment, modification, redistribution inside another product, and competing commercial use, which is incompatible with AGPL-3.0, and it ships as an Electron desktop app rather than an embeddable component.
See POSITIONING.md, the summary near the top of this file, and the technical teardowns in docs/competitive/.
One line: Shoploop is grip.tools, democratized — for every tabletop brand with a web page.
Shoploop's own code and documentation are AGPL-3.0 — full text in LICENSE. Self-hostable. Fork it, ship your own version, contribute back.
Third-party components (Pimcore, PostHog, Postiz, Nango, NVIDIA Omniverse) are governed by their own upstream licences. They do not inherit Shoploop's licence; conversely, Shoploop's AGPL-3.0 does not make their terms disappear. A deployment that includes them is governed by those terms too, and Shoploop neither restates nor warrants them.
git clone https://github.com/ninan-versioning/shoploop
cd shoploop
pnpm install
pnpm dev # runs apps/landing on http://localhost:3000
pnpm typecheck # what CI runspnpm dev runs apps/landing, the only app with runtime code today. apps/operator-studio and apps/configurator are scaffolds — there is no local twin render yet. Read AGENTS.md before opening a PR, and CONTRIBUTING.md for the gate every PR has to clear.
Two tiers. $0 Shoploop Core — Shoploop's own AGPL-3.0 source, self-hostable in your own infrastructure. Locked; does not move. Third-party adapters and deployment components retain their own licence and infrastructure costs; Pimcore Community eligibility follows Pimcore's stated EUR/USD 5M annual-revenue threshold, with a commercial subscription required above it. And Managed — hosted twin, GPU streaming, operator link, publishing, the loop running on your data, 30-day trial, no card — whose price is to be determined after production benchmarks (ADR 0017). The former $299/mo was reopened and deliberately not replaced with another number: product quality defines architecture, cost is telemetry, and a price fixed before unit economics are measured turns every cost question into a capability question. No $99 tier. No enterprise tier at v0.
Contributors wanted in:
- Blender headless authoring —
bpyscripts and Geometry Nodes for parametric containers, UV unwrap, and label projection - OpenPBR / MaterialX material accuracy in Blender + MolecularNodes
BrandRulesAPIapplied schema viausdGenSchema, and theusdcheckerCI gate- URL → USD product-twin extractor built on
extruct+ schema.orgProduct - OVAS deployment on EKS via the NGC Helm charts
- Postiz public-API and MCP integration (client-side only — no forking upstream)
Read AGENTS.md and docs/STANDARDS.md first. Every PR answers the seven-question decision gate, including which existing standard does this use? Open a PR or a discussion.
An Ayurvedic operator is evaluating Shoploop as a design partner. No partner or prospect brand name, domain, contact, or logo appears in this repo or on any customer-facing surface. Public wording is tabletop brands, with Ayurveda as the wedge. ashwagandha.shoploop.studio is Shoploop's own brand-neutral reference tenant.
Offense. Attack attack attack, never defense.