Skip to content

Roles and skills — findings of 2026-09-12 (sandbox, guests, feedback, admin chat)

Part of roles-and-skills. Nine findings from 2026-09-12: sandbox skills, sandbox links and permission, admin layout, theme toggle, guests, feedback, and the admin Claude chat. Text moved verbatim from roles-and-skills; references such as "above", "below" and "earlier" point into that note or its sibling files.

Findings, 2026-09-12 — investigated, not yet built

Angel: "give myself permission to use the assistant in the sandbox so I can create part numbers, sales orders, purchases… I cannot find the sandbox chat or the sandbox MRP in the admin page… allow certain users to use the sandbox… a couple of admin fields are squeezed… the light/dark toggle on the home page floats over a corner."

1. The sandbox assistant can only do Sales — measured, not assumed

~/Notes/skills/ contains exactly one file, sales/SKILL.md, and app.py has a single entry point, run_sales_turn. The department registry lists skills for six departments, but five of them name files that do not exist. So the sandbox is not restricted by permission — the skills themselves were never written. Heavy testing of parts, purchase orders and builds needs those skills built, and they are the same work whether they run in the sandbox or in production.

Order to build them, cheapest first, each drafting and waiting for Confirm exactly like Sales: 1. Purchasing — draft a purchase order to a supplier from "order 500 of EE-C-0042 from LCSC"; receive against a PO. Reuses the sales machinery almost entirely (find company, find part, lines). 2. Engineering — create a part from a manufacturer number or a datasheet (already designed above), plus "add a supplier part". This is the one Angel asked for first and the one with the most fields, so it needs the guided-form work below. 3. Production — start a build order, report what a build is short of, print a traveler. The shared prerequisite is guided forms (also designed above): a part needs a dozen fields, so the one-sentence pattern stops being enough. Build order: guided forms → Purchasing skill → Engineering skill → Production skill.

2. Nothing points at the sandbox from the admin page

The Sandbox card shows state and Up/Reset/Down but no links. Add, on that card: Sandbox ERP (http://sandbox.lan), Sandbox chat (http://chat-sandbox.lan), and the admin password reminder ("printed by Up; changes on every reset"). Both are LAN-only, so the links should be marked as such and shown greyed when the sandbox is down. Also worth a Sandbox tile on the home page, visible only to departments that may use it, pointing at both.

3. Who may use the sandbox should be a permission

Today anyone on the shop network can open sandbox.lan and chat-sandbox.lan — they are not behind the gate, because the gate cannot cover a LAN name. Two options:

  • Cheap and honest: add sandbox: true|false to each department in departments.yml, have the sandbox chat check it (it already knows the person through ASSISTANT_DEV_EMAIL… which is the problem — see below), and note in SOP-012 that the sandbox is shop-network-only.
  • Correct: give the sandbox real identity. Publish it as sandbox.embeddedera.com and chat-sandbox.embeddedera.com through the tunnel behind their own Access apps, whose allow lists come from the same access: tokens (new tokens sandbox and chat-sandbox). Then onboard governs sandbox access exactly like everything else, the dev-identity shortcut disappears, and the guard that blocks production actions stays as the second wall.

Recommend the correct one: it removes the last place where a fixed identity is baked into a service, and it costs one Access app and one DNS record each. Keep the sandbox ERP's own password login as the break-glass path for when the gate itself is what you are testing.

4. Admin cards that still scroll sideways — measured

At 1280 px the page itself does not overflow, but two cards do: Sign-ins (5 columns in a 294 px column) and Recent turns (5 columns, 589 px of content). The grid is three fixed columns, so wide tables can never fit. Fix: make those two cards span the full row like People, drop the IP column into a tooltip on the country, and truncate the message column with the full text on hover.

5. The home page theme toggle floats over the corner

It is position: fixed at the top right, so it sits above the page and stays there while the content scrolls under it — which is what Angel is seeing. It also overlaps the first tile on a narrow window. Fix: move it into a proper header row beside the EmbeddedEra name, in normal flow, the way the SOP site and the assistant already do it. That also makes the three internal pages agree, which the internal-pages rule in ~/Notes/rules/CLAUDE.md already asks for.

6. Guests: showing the sandbox to people outside EmbeddedEra

Angel, 2026-09-12: "provide access to non-EmbeddedEra emails, especially to the sandbox… if I want to show this whole system to somebody that is not from my side… maybe I can make this a product."

This changes the sandbox's job. Today it is a rehearsal room that happens to hold a copy of real data. A demo room shown to outsiders is a different thing, and the difference is the data, not the access.

The blocking problem: the sandbox holds your real business. erp-sandbox reset restores a fresh production backup — real customers, real prices, real part costs, the LHG address, supplier terms. An outsider evaluating the system would be reading your books. So a guest-facing sandbox needs a demo dataset, not a restore:

  • erp-sandbox reset --demo builds from the same backup but then scrubs: customers and suppliers renamed to plausible fakes (Acme Instruments, Northwind Components), addresses and contacts replaced, prices and costs multiplied by a random factor per part, sales and purchase orders rewritten to fictional references, attachments and notes dropped, people replaced by two demo users. Everything structural survives — categories, BOMs, the part-number scheme, the templates, the SOPs — which is what a visitor is actually there to see.
  • Keep --fresh (real data) for your own rehearsal and mark the instance loudly: the banner already says SANDBOX; a demo instance says DEMO — fictional data.

Access for an outside address. The Google sign-in is restricted to embeddedera.com, so a guest cannot use it. Cloudflare Access's one-time PIN login method covers exactly this: the guest types their email, receives a code, and is in — no account for you to create, no password to send. Add it as a second login method on the guest apps only, never on the production gates.

  • New department guest in the registry: access: [sandbox, chat-sandbox], erp_groups: [Read-only], nas: false, reports: [], assistant.enabled: true with the skills you want to show.
  • New onboard guest --email someone@elsewhere.com --days 14 — adds the address to the two guest gates with an expiry, writes it to people.yml with an expires date, and the hourly access-sync removes it the day it lapses. Access itself has no per-user expiry, so the expiry lives in our registry and reconciliation enforces it. That is the same mechanism that just caught the stale address, pointed at a deadline.
  • The admin People card gains a Guests section: who, invited when, expires when, last seen (from the sign-in log), and a Revoke button.

What a guest must never reach, enforced rather than trusted: production hostnames (separate gates, separate policies); the vault, the NAS and the reports; outbound email (the sandbox mailer already redirects — make it refuse instead); the distributor API keys (the sandbox should carry none, so lookups degrade to "not configured"); and any admin action, which the sandbox guard already blocks. The guest's ERP group is read-only, so even the assistant's confirm path can only draft.

Cost and hygiene. A demo instance is five containers; bring it up for a demo and down after. Reset before and after every demo, so nobody sees the previous visitor's edits and no visitor's edits outlive the visit. Log every guest session; the Sign-ins card already shows who and from where.

If it becomes a product, this is also the honest first step: the demo dataset, the guest invite with an expiry, and the fact that everything is files in git means a second shop could be stood up from the same repository with its own data. That is a bigger conversation, but nothing here blocks it.

Where it sits in the order: after the sandbox gets real gates (item 3), because guest access is just another token on the same mechanism, and after the demo scrub exists, because inviting anyone before that means showing them your customers.

7. Guests should be able to do things, and to tell us what is wrong

Angel, 2026-09-12: "I would like the guest to be able to create work orders, sales orders and all that… a copy of the whole thing… they can play and provide feedback."

Correction to item 6: guests are not read-only. The point of the demo is that a visitor can create a part, raise a sales order, run a build and try to break the assistant. So a guest gets the same powers as a real user inside the demo instance:

  • guest department: erp_groups: [Owner] in the sandbox only. The sandbox ERP is a disposable copy with fictional data, so there is nothing to protect there; the protection is that the instance is separate, has no keys, cannot send email, and is wiped on reset.
  • The guard that matters stays: guest gates admit only the sandbox hostnames. Production is a different gate with a different policy and no guest ever appears on it.
  • The assistant in the demo runs every skill that exists, so a visitor can exercise the same paths an employee does.
  • Reset before and after each visit. A visitor's mess is expected and is thrown away, which is exactly why they can be trusted with full rights.

This also removes the odd asymmetry where a guest could see more than they could try.

8. Feedback, captured where the person already is

Two audiences, one pipeline: visitors in the demo, and employees using the real system. Both are telling us the same kind of thing, so it should land in the same place.

Capture. - In the assistant: a Feedback button on every card and a plain "feedback: …" message. It is a fifth reply shape — the assistant stores it and answers "noted", nothing else. In the demo instance it is the primary purpose, so the page says so. - On every internal page: a small "Feedback" link in the header beside Home (home page, SOP site, admin, reports), opening a one-field form. It posts to the same place with the page it came from. - From a customer: the website already has a contact form and the quote follow-up asks a question; those replies are feedback too and get filed by hand from Gmail into the same table. - Every item records: who (or "guest"), when, source (assistant / page / email / demo), the page or card it came from, the text, and for the demo instance the fact that it was a demo.

Storage. A feedback table beside the assistant's log, backed up nightly, visible on the admin page as a card with its own triage state: new → accepted / rejected / duplicate → done, plus who decided and one line of why. Not a ticket system; a list with a decision against each row.

The loop that makes it worth collecting. Weekly, alongside the audit and the assistant log review: read everything new, decide each item, reply to whoever sent it, and turn the accepted ones into either a to-do in the right project note or a change to an SOP. Anything rejected still gets a reply, because the fastest way to stop receiving feedback is to receive it silently.

Reports. Items per week by source, how many were acted on, how long triage takes, and the demo instance's feedback separately — that last one is the closest thing to product research this company will have.

The procedure for all of the above is SOP-013 Feedback, being written now. The mechanism is worth building right after the sandbox gates, because the demo is the first place it pays off.

9. A full Claude chat inside the admin page

Angel, 2026-09-12: "I would love to have a whole chat just like Claude right now… pick the model, the effort, keep the history."

Different animal from the department assistant. That one is deliberately caged: four reply shapes, five actions, no prose. This is an open conversation for Administration only. Both can live in the same service; they must not share a code path.

Two tiers, and the difference is the only decision that matters.

Tier A — conversation, no hands. Streaming chat, model picker (Haiku / Sonnet / Opus / Fable), an effort control (thinking budget), sessions with titles kept in sqlite and resumable, cost per session shown. Read-only context it can be given on request: the SOP index, the department registry, today's audit, the ERP through the same allow-listed read actions the department assistant uses. It cannot write anything, run a command or touch a file. This is safe to expose behind the gate and is most of what a phone-side Claude is useful for.

Tier B — hands on the server. The same thing plus the real tool set: shell, file edits, the API tokens. Honestly: that is a remote root shell on the machine that runs the shop, published on the internet, protected by one Google account. If that account is ever phished, the attacker does not get your invoices, they get the server, the vault host, the backups and the signing keys. The gate is good but it is one factor deep.

If Tier B is still wanted, the conditions I would insist on, all enforced not promised: a separate gate application requiring a hardware key or a one-time PIN in addition to Google; every tool call requiring an explicit confirm in the page, no exceptions and no "allow for this session"; a hard allow-list of commands with everything else refused; the whole transcript and every command logged to the audit table; a kill switch on the admin page; and never any equivalent of skipping permissions. Even then it is the largest security surface in this system by a wide margin.

Recommendation: build Tier A now, use it for a month, and see how often you actually wanted hands. Most of what you would ask it — what does this SOP say, why did the audit fail, what changed yesterday, draft this note — needs no hands at all. The rest can stay in a terminal session like this one, where the machine is in front of you.

Cost. This is the one place where an open-ended chat can spend real money, so: a monthly ceiling per person, the model picker defaulting to Haiku with Sonnet a deliberate choice, session cost shown live, and the same daily budget mechanism the distributor lookups already use.

Build order: after the demo dataset and guest invites (the approved queue), because those are promised to a visitor and this is for you alone. Roughly two days for Tier A.