Order-email triage for NanoClaw as a per-chat overlay plugin: fetches order-related Gmail, maintains the orders SQLite table, flags recent anomalies (cancellations/refunds, overdue deliveries, orders stuck in 'ordered' that never shipped), and ships a cadence companion that runs it on a schedule.
77
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Order-email triage for NanoClaw. Fetches order-related Gmail, keeps the orders SQLite table current, and flags recent anomalies — cancellations/refunds, overdue deliveries, and orders stuck in ordered that never shipped — surfacing only the flagged events so the alert channel stays signal-only.
Per-chat overlay plugin. Install via NanoClaw's containerConfig.additionalTiles mechanism.
last_checked, sanitized inside the container before any body reaches the sessionemail_message_id into the orders table; idempotent across overlapping fetch windowsordered that never shipped (statuses and per-status cutoffs owned by flag-anomalies.py, which also drops an overdue row whose logical order already shipped or arrived on another row; the stuck window owned by compute-stuck-orders.py; both pair on the persisted (source, order_number) key)nightly-order-sync cadence wrapper runs the lookup on a 3-day-capped 15 6 cadence and emits the observable-silence cursor marker the silent-success watchdog readstessl install jbaruch/nanoclaw-ordersAdd to a chat's overlay plugin list via update_group_config:
additionalTiles: ["nanoclaw-orders"]Load the overlay at the main or trusted tier. Two reasons: the Gmail fetch reaches Google through the OneCLI gateway, which injects credentials only for main/trusted agents (the untrusted tier runs secretMode: selective and is gated from Google by design), and the orders table lives in messages.db, which is mounted read-write only on main/trusted (read-only filtered copy on untrusted).
None. This container holds no Google credential (jbaruch/nanoclaw#638): the OneCLI TLS-MITM gateway owns the OAuth connection and injects Authorization: Bearer on the wire to the Google API hosts, refreshing the token itself. The fetch sends no auth header and reads no key from the environment — COMPOSIO_API_KEY / COMPOSIO_USER_ID are gone.
The gateway reaches the fetch via HTTPS_PROXY + the mounted CA bundle, both set on the spawn by the orchestrator. When it isn't on the request path, Google answers 401 and the fetch fails closed with an operator-actionable diagnostic rather than retrying.
The skill reads and writes the orchestrator's messages.db under the /workspace/store/ mount (read-write on main/trusted):
| Table | Access | Owner |
|---|---|---|
orders | read+write | this plugin |
orders_metadata (last_checked cursor) | read+write | this plugin |
nanoclaw-admin's morning-brief and check-email skills read flagged orders from the same orders table. Admin co-loads with this overlay in the same chat via the shared store mount. The cross-plugin reads resolve through that mount.
scripts/fetch-order-emails.py loads four shared helpers owned by nanoclaw-admin's heartbeat skill at runtime via the co-loaded tessl__heartbeat plugin mount:
sanitize-email-body.py — sanitize(), applied to every text field inside the container before it reaches the sessiongoogle-rest.py — the native Google REST transport over the OneCLI gateway (google_request, surface_url, and the GatewayNotInjecting / TierAccessRestricted faults)gmail-ops.py — list_messages / get_message against the Gmail REST APIgmail-message.py — flattens a raw users.messages.get resource (nested MIME tree, base64url bodies, raw header list) into sanitized fieldsAll four resolve when admin co-loads with this overlay (the owner's main/trusted chat). The fetch fails closed if any is unavailable.
| Skill | Description |
|---|---|
| check-orders | Fetches order-related emails from Gmail, updates the orders SQLite table, and flags recent anomalies. Use when the user asks about order status, order tracking, order emails, shipment status, purchase alerts, or needs to sync Gmail order data with the orders database. |
| nightly-order-sync | Cadence wrapper (cron 15 6, precheck-gated by a 3-day cadence cursor) that runs check-orders on a schedule, surfaces only its order alerts, and emits the observable-silence cursor marker the silent-success watchdog reads. |
check-orders invokes these deterministic scripts from its SKILL.md steps:
scripts/read-last-checked.py — reads the last_checked cursor from orders_metadatascripts/fetch-order-emails.py — multi-query native Gmail fetch, cross-query dedup, in-container sanitization, compact-row projectionscripts/compute-order-id.py — deterministic SHA-1-prefix order id from (source, order_date, description)scripts/extract-amount.py — extracts the order total from a sanitized email, preferring a labeled total line over any largest-amount pickscripts/classify-order.py — maps sender domain → source and subject/snippet keywords → statusscripts/apply-order.py — upserts an order row on email_message_idscripts/apply-exclusions.py — owns the user-preference exclusion table and matching; unflags matches and emits the id list flagging consumes via EXCLUDED_IDSscripts/compute-stuck-orders.py — computes the ids of orders stuck in ordered with no shipment, pairing on the persisted (source, order_number) keyscripts/flag-anomalies.py — applies the anomaly predicates (owns the statuses, per-status age cutoffs, and the supersession test that keeps a split order's stale row quiet); flags the supplied stuck idsscripts/get-flagged-orders.py — returns currently-flagged orders for the alert channel, collapsing rows that share a (source, order_number) orderscripts/render-order-alerts.py — HTML-escapes flagged rows into the ready-to-send Telegram alert envelopescripts/unflag-orders.py — clears flags the user has acknowledged (ad-hoc, outside the Step 6 flow)scripts/promote-stale-shipped.py — ages shipped orders past the delivery window into the overdue statescripts/within-days.py — date-window predicate helperscripts/write-orders-metadata.py — write-ahead cursor + metadata writerThe nightly-order-sync cadence wrapper carries its own scripts:
scripts/precheck-nightly-order-sync.py — fire-time precheck that gates wake-ups by the cadence cursorscripts/stamp-cursor.py — advances the success cursor after a clean runcheck-orders + its nightly-order-sync cadence wrapper from nanoclaw-admin as a standalone per-chat overlay plugin (jbaruch/nanoclaw-admin#319). The wrapper materialises one scheduled_tasks row in chats that load this overlay.See CHANGELOG.md for version history.
tessl.json declares this repo's dev-time plugin dependencies.
jbaruch/* dependency floats at latest (Runtime-Managed Manifest Carve-Out, jbaruch/coding-policy: dependency-management).finsi/codex-review is third-party and pins. No dependency scanner covers the tessl ecosystem. Renewal cadence: quarterly — run tessl outdated and bump the pin in its own commit..tessl-plugin
skills
check-orders
references
scripts
nightly-order-sync