Moss Home USA: How Three Connected Automations Gave Three Key Employees Their Week Back

A Los Angeles custom upholstery manufacturer moved order intake, quote-to-order review, and support email into three production systems. That automated away a full week of work for three key employees. They stayed, and the CEO reassigned them to grow the brand. AI drafts language. Deterministic code still owns the records.

By Douglas Schwartz, Founder, Asgard Technologies · Published September 24, 2026 · Updated September 25, 2026 · 18 min read

TL;DR — Moss Home USA, a custom upholstery manufacturer in Los Angeles, runs three production systems built by Asgard Technologies: an hourly importer for genuine orders, an annual log of the quote-to-order lifecycle, and an AI-assisted decision engine on the support inbox. Together they automated away a full week of work for three key employees, who stayed and were reassigned to grow the brand. The language model interprets and drafts. Ordinary code still controls orders, inventory, pricing, and whether a reply is allowed to send.

Case study at a glance

ItemDetail
ClientMoss Home USA, a custom upholstered furniture manufacturer in Los Angeles, California
EngagementAsgard Technologies as the embedded engineering team for four-plus years, including the website
Systems in this article1. Master Open Order importer. 2. AMP Order Review Log sync. 3. Customer-service decision engine
Data flowAMPtab ERP export to Smartsheet for orders and quotes. Gmail to n8n to a Next.js decision app, with Smartsheet lookups, for support email
ScheduleHourly on Vercel Cron. The importer runs around the clock. The review log runs weekdays, 8:00 a.m. to 8:00 p.m. Pacific
What AI doesClassifies intent, extracts order numbers and fabric names from messy email, drafts replies from retrieved facts
What code doesMatching, deduplication, archive checks, field mapping, status rewriting, and every send permission
What people doCancellations, refunds, complaints, claims, fabric holds, shortages, and any case where the records conflict
OutcomeA full week of work automated away for three key employees. They stayed. The CEO reassigned them, which is letting the company grow the brand
StackPython 3, Smartsheet SDK, n8n, Next.js, Zod, Claude, Vercel

Who this case study is for

This write-up is for operators and owners of made-to-order businesses, and for the technical people who support them. It will be most useful if:

If that describes your operation, the three systems below are a pattern you can copy, with or without the same tools.

The operating problem

Moss Home makes configurable upholstered furniture. A single order can carry a dealer, a purchase order, a discount, a territory manager, and several line items, each with its own SKU, price, and quantity. Quotes become genuine orders. Completed work moves into yearly archives. Customers write the support inbox about shipping, fabric, damage, and paperwork, often without a clean order number.

Staff were spending their days on the transfer itself. New orders had to be copied onto the operations sheet. Quotes had to be reconciled when they became confirmed orders. Support had to search several sheets before anyone could answer a routine question.

A designer living room with a tailored sofa, the kind of configured piece behind each Moss Home order
Configurable upholstery is the product. The operating problem is everything that has to stay attached to each order.

Three facts made a simple point-to-point sync the wrong design.

  1. The same order can show up as a quote, then as a genuine order, across more than one annual sheet. A naive import creates duplicates and stale rows.
  2. A partial export or a missing archive can look like a healthy run and then reimport work that was already finished.
  3. Customer email mixes easy questions with commitments. A fluent reply that invents a ship date, a dye lot, or a price is worse than a slow one.

The build had to get faster and get more conservative at the same time.

What we refused to automate away

The rule for the whole engagement is simple. A language model may interpret a request and draft language. It may not be the source of truth for an order, a price, a yardage number, or a customer record.

Kind of workWho owns it
Matching records, deduplicating, mapping fields, checking archives, enforcing send permissionsOrdinary code
Classifying intent, pulling order numbers and fabric names out of messy email, drafting a reply from those factsA language model
Cancellations, refunds, complaints, holds, shortages, and anything the records do not cleanly supportA person

That split is why this is an AI-assisted operations layer, not an autonomous one. The sections below are the three systems in production. They are the ones that carry the day-to-day load.

How the three systems connect

Each system has one trigger, reads from a defined set of sources, writes to one destination, and has a named point where a person takes over. None of them writes back to the ERP.

SystemTriggerReadsWritesWhere a person takes over
Master Open Order importerVercel Cron, hourly, 24/7AMPtab CSV export, Master sheet, 2025 and 2026 archivesNew rows on the Master Open Order sheetWhen an archive cannot be verified, the run aborts and waits
Order Review Log syncVercel Cron, hourly, weekdays 8 a.m. to 8 p.m. PacificAMPtab quotes-and-orders export, yearly review sheetsUpdated or inserted rows on the year's AMP Order Review LogNever deletes, so a person can audit any row
Customer-service decision engineNew message in the support inbox, via n8nOpen orders, Basics sheet, yearly archives, BarCloud inventory, Fabric MasterA decision returned to n8n, an optional review queue, an optional audit tableDraft only, human review, and any closed send gate

1. Master Open Order importer

This is the hourly order importer. It pulls orders from the AMPtab CMS and appends new line items to the Master Open Order sheet in Smartsheet. Anything already on that sheet, or on the 2025 or 2026 archive sheets, is skipped. Existing Master rows are not updated.

What the importer does every hour

Each run follows the same path.

  1. Fetch. Download the CSV export from AMPtab.
  2. Filter. Keep only header rows whose status is Genuine Order. Quotes and other statuses are dropped, along with their line items.
  3. Combine. Join each line item to its order header on order id, so one sheet row holds both the order (customer, PO, date, discount, rep) and the line (SKU, name, price, quantity).
  4. Sort. Oldest first, by the source timestamp.
  5. Deduplicate. The unique key is the AMP order number. If that number is already on the Master sheet or either archive, skip it.
  6. Write. Append new rows to the bottom of the Master sheet in batches through the Smartsheet API.

How the importer avoids reimporting completed orders

The safety control is the part worth copying. If either archive fails to load, is missing the order-number column, or returns zero keys, the sync aborts. A bad read must not reimport completed orders. The importer would rather wait an hour than invent a duplicate.

A sculpted designer armchair, one configured piece among the line items the importer writes
Each line item stays tied to its order header. The importer does not update rows it has already written.

Field mapping is fixed, not inferred:

How the importer runs

Vercel Cron calls the Python function every hour. The function can require a bearer secret. It is allowed up to 300 seconds. An optional business-hours gate can limit runs to weekday daytime in Los Angeles. That gate is off, so the job runs around the clock. The same core function can run locally in batches of 50 if the cloud path is down, with a written fallback runbook. Both paths share one sync function, so recovery is not a second product.

The stack is small on purpose: Python 3, requests for the CSV, the standard csv parser, and the Smartsheet Python SDK. Secrets and sheet ids live in environment variables. There is no database in this service.

2. Order review log

The second system is also a one-way sync from AMPtab into Smartsheet, with a different job. It maintains the quote-to-order lifecycle on sheets named AMP Order Review Log, one sheet per year.

How a quote and its confirmed order become one row

On each run it:

  1. Downloads the quotes-and-orders export.
  2. Maps source columns onto the review schema: order number, dealer, PO, total, status, contact, and rep.
  3. Drops rows with no AMP order number.
  4. Deduplicates on that number, keeping the row with the most recent sales-order date. A later genuine order replaces an earlier quote instead of becoming a second entry.
  5. Routes the row to the sheet for its sales-order year. A year without a mapping goes to a default sheet.
  6. Looks up existing rows by AMP order number and either updates them or inserts new ones at the bottom.

Status labels are rewritten into Moss Home's operating terms: a quote becomes HFC, and a genuine order becomes Confirmed. Numeric order numbers are normalized so a leading zero does not create a second row for the same order.

How the review log runs

The same shape as the importer: an hourly Vercel Cron job, a bearer check, and a weekday window from 8:00 a.m. to 8:00 p.m. Los Angeles time. The local fallback uses a file lock so two runs cannot overlap, and a lock older than 45 minutes is treated as stale so a hung process cannot block the next day. Older documentation describes a daily 9:00 a.m. job. The live path is the hourly function.

Runtime dependencies are requests, the Smartsheet SDK, and timezone data. There is no web UI.

3. The customer-service decision engine

The third system is the support inbox at Moss Home. An n8n workflow named Moss Home - CS Auto-Reply watches Gmail, labels a message immediately so it is not processed twice, and posts it to a Next.js app. The app does not send mail. Sending, labeling, and inbox polling stay in n8n. The app returns a decision. n8n routes on that decision: send a reply, forward a quote, label the thread for a person, or do nothing.

An emerald velvet sofa, the kind of fabric decision the inbox has to answer from inventory records rather than from a guess
Fabric answers come from inventory and the fabric master. Holds, care, and unresolved stock stay with a person.

How a support email becomes a decision

Inside the app, each message goes through a fixed sequence.

  1. Clean the body, using HTML only as a fallback, and isolate the newest text from quoted history.
  2. Skip mail that should not be answered: Moss system mailboxes, no-reply senders, thank-you-only follow-ups, threads a teammate is already handling, and mail where Moss is only copied.
  3. Classify the sender from a contact-role registry: sales rep, employee, vendor, showroom or designer, end customer, or unknown.
  4. Ask a language model for intent, order numbers, fabric names, and risk signals. Deterministic guards can override that classification.
  5. Look up facts in Smartsheet and apply hard rules before any reply is allowed.
  6. Return one decision.

The six possible decisions

DecisionWhat it means
Auto replySafe to send, and only if every send gate is open
Draft onlyA draft exists, and a person must send it
Human reviewRisky, incomplete, or outside the approved boundary
No replyAn acknowledgment, spam, or a thread the automation should stay out of
IgnoreA duplicate, a skip-list sender, or Moss Home's own outbound mail
ErrorProcessing failed. Nothing customer-facing happens

What the engine will and will not answer

Order status. Lookup is an exact match on AMP order number, customer PO, or invoice number, across open orders, the Basics sheet, and the yearly archives. Customer wording uses estimated shipping and estimated completion. Pending materials, cancelled orders, multiple matches, and missing tracking go to a person. When an order is found, the system does not ask for an order number it already has.

New quotes. A furniture quote request can be forwarded internally and acknowledged. A question about fabric price per yard is not treated as a furniture quote.

Fabric. Stock and availability can draw on BarCloud inventory and the Fabric Master, along with width, repeat, content, and care codes when those facts are actually on record. Holds, reservations, specifications, care, shortages, split dye lots, and unresolved stock stay with a person. The system will not email a mill or a warehouse on its own.

Claims. Product damage, freight damage, freight price, vendor quality, and general complaints are separated. A claims-form link is only for actual damage, and that URL comes from configuration, never from the body of the customer's email.

Documents and changes. A request to resend a receipt or invoice is checked against prior sent mail and held for review. The system does not invent a document. Cancellations, returns, refunds, and address changes are always human review.

Why sending is fail-closed

A reply can leave only when dry-run is exactly off, automatic sending is exactly on, external sending is exactly on, and the intent is on the allowlist. The intended auto-send set is narrow: where-is-my-order, and new furniture quote requests. Closing any gate stops external mail. That is the shutdown switch.

Wording is linted before anything can be sent. Replies cannot say "scheduled to ship," cannot use em dashes, and cannot name the internal systems. Held cases can be written to a review queue, and each decision can be written to an audit table. If that database is not configured, the app still runs and simply skips the durable log.

The application is Next.js on Vercel, with Zod for validation. Extraction and drafting use Claude when an Anthropic key is set, and can fall back to another model by environment variable. Orders and fabric facts come from the Smartsheet API. Tests mock the model and Smartsheet.

The first version of this app was dry-run and order-status only. The current code classifies many more intents. It still refuses to send most of them.

What changed for the team

Moss Home is not a three-person company, and this is not a story about replacing people.

The result is narrower than that. These three systems automated away the entire week's work of three key employees. The week they got back had been spent on the recurring administration the systems now cover: moving genuine orders and line items onto the operations sheet, reconciling quotes into confirmed orders, and searching several sources before answering routine support email.

Nobody was let go. With that week gone, the CEO had to find different work for those three people. That reassignment is what is letting Moss Home grow the brand. This write-up does not convert "a full week" into a guessed hours figure, and it does not claim a headcount reduction.

The quality of the record changed with it.

A finished high-end interior, which is the point of the operating layer: tracking the order should not compete with making the piece
The staffing result is a full week back for three key employees, reassigned to grow the brand. The control result is that sensitive cases still stop.

What we are not claiming yet

A case study is only useful if a reader can tell what was verified. These items are real production behavior, described above. These items are not in this article, because we will not publish a number we cannot defend:

Duplicate protection and archive aborts are how the importer is built. They are controls, not a slogan that nothing has ever gone wrong. Fabric answers are grounded in inventory records and held when the facts are not clean. They are not advertised here as a universal under-a-minute promise.

Glossary

Terms used in this case study, in the sense Moss Home and Asgard use them.

Why this pattern transfers

Most growing manufacturers already have the same shape of problem. Orders live in one system, the working list lives in a sheet, and the customer writes an inbox that knows neither. The work looks clerical until a duplicate ships, an archive gets reimported, or a confident email invents a dye lot.

The Moss Home build is a pattern for that shape. Deterministic jobs keep the operating record. A model reads unstructured language and drafts from retrieved facts. People keep the decisions that change money, commitments, inventory, or a customer's outcome. Each new intent has to earn a place on the allowlist. Until it does, the system drafts or stays quiet.

Is this pattern a fit for your operation?

You do not need the same tools. You need the same shape of problem. The pattern is likely to fit if most of these are true:

The pattern is a poor fit if the working record and the source system are already the same thing, or if the volume is low enough that a human transfer costs a few minutes a week.

Asgard Technologies has been the engineering team on this engagement for four years, including the website. You can see the broader Moss Home work, including the design side, on our flagship clients page, and the service behind it on automated systems. If you run a furniture or made-to-order business and the same three workloads are still manual, tell us which one hurts and we will say honestly whether this pattern fits.


Moss Home USA is a client of Asgard Technologies. This article describes production systems at the architecture level. It omits credentials, export URLs, sheet identifiers, and customer data.

Key takeaways

  • Three production systems now cover genuine-order import, quote-to-order review, and support-email decisions
  • The systems automated away a full week of work for three key employees. They stayed, and the CEO reassigned them to grow the brand
  • Language models classify and draft. They do not own order, inventory, pricing, or customer records
  • If an archive cannot be verified, the order importer aborts rather than risk reimporting completed work
  • A customer reply can leave only when dry-run is off, send gates are open, and the intent is on an allowlist
  • Complaints, holds, cancellations, refunds, and uncertain fabric facts stay with a person

Frequently asked questions

Is the Moss Home support inbox fully autonomous?

No. It is AI-assisted. The application classifies a message, looks up order and fabric facts, and returns a decision. n8n still polls the inbox and sends mail. A reply can leave only when dry-run is off, automatic sending is on, external sending is on, and the intent is on a short allowlist. Everything else is drafted for a person, held for review, or left unanswered.

What happens if the order archive cannot be read?

The Master Open Order importer stops. If an archive sheet fails to load, is missing the order-number column, or returns no keys, the run aborts. Delaying new rows is safer than appending orders that may already have been completed.

What happened to the three employees whose week was automated?

They stayed. Moss Home is not a three-person company, and nobody was replaced. The systems took the entire week those three key employees had been spending on recurring administration: moving genuine orders and line items onto the operations sheet, reconciling quotes into confirmed orders, and searching several sources before answering routine support email. With that week gone, the CEO had to find different work for them. That reassignment is what is letting the company grow the brand.

Which decisions still require a person?

Cancellations, returns, refunds, and address changes. Complaints, claims, and freight issues. Fabric holds, reservations, specifications, care instructions, shortages, split dye lots, and unresolved availability. Multiple order matches, missing tracking, and any case where the records are incomplete or in conflict.

What tools does the Moss Home automation stack use?

The two sync jobs are Python 3 functions on Vercel Cron using the requests library and the Smartsheet Python SDK, reading a CSV export from the AMPtab ERP and writing through the Smartsheet API. The support inbox is an n8n workflow watching Gmail plus a Next.js application on Vercel, validated with Zod, that calls Claude for classification and drafting and reads order and fabric facts from Smartsheet. Secrets and sheet identifiers live in environment variables.

Does this pattern require AMPtab and Smartsheet?

No. The importer consumes a CSV export and writes rows through an API, so the source can be any ERP that exports orders and the destination can be any sheet or database with an API. What transfers is the set of controls: a single deduplication key, a check against completed work before writing, a fixed field mapping, and a job that aborts when it cannot verify its inputs.

What is a fail-closed send gate?

A rule that a customer-facing email can only leave when every permission is explicitly on. At Moss Home a reply sends only when dry-run is off, automatic sending is on, external sending is on, and the message intent is on a short allowlist. If any one of those is missing, the system drafts for a person or stays silent. Turning off any single gate stops all outbound mail, which makes it the shutdown switch.

How long has Asgard Technologies worked with Moss Home USA?

Asgard has been the embedded engineering team for Moss Home USA for more than four years. The engagement covers the website, brand and design work, the order-flow automations described here, and the AI-assisted customer-service layer. The three systems in this article are the ones that carry the daily operational load.

Related articles

You are viewing Moss Home USA: How Three Connected Automations Gave Three Key Employees Their Week Back | Asgard Technologies on Asgard Technologies. We are an engineering-first technology partner shipping AI, blockchain, mobile, automation, and full-stack systems for companies that need real production work.

Explore more from Asgard Technologies: AI development, blockchain, mobile apps, business automation, blog, contact us.

Quick links: Home | About | Contact | FAQ | Blog | AI Models | Mobile | API | Blockchain Fintech | XML Sitemap | Full Site Map