One foundation, one front door, many domains
Every skill reads through security_invoker views and writes through security definer RPCs that check em_private.accessible_write before touching a row - it never writes a base table directly. Meaningful account-level changes append to the account changelog for an audit trail.
How the EM invokes the toolkit
Domain plugins - the EM-facing capabilities
em-core - shared workers every domain calls
The platform database (and the connectors around it)
em schema (~80 tables + views)
Reads via security_invoker views · writes via security definer RPCs
Fireflies (transcripts) · Microsoft 365 (calendar, email, Teams)
Tability (OKR system of record, mirrored in-platform)
How a skill actually runs - and why you can trust it
The stack above is what the toolkit is. This is what happens when you use it - the mental model behind every skill, so you know what runs on your data and why the writes are safe.
Nothing magic runs - it's layers of text and tool calls
When a skill "runs," there is no special runtime. From bottom to top, only one layer is unpredictable:
em.* RPC through the em_db seam. Real code with real return values.DeterministicA markdown file with a trigger and a body
Strip away the mystique - a skill is a text file with frontmatter. That's it:
--- name: em-1on1-logger description: Use when the user says "log my 1:1"... # this is the TRIGGER --- <the instructions the model follows once this skill is active>
Progressive disclosure - why a big toolkit doesn't slow you down
At the start of a session the model does not load the body of every skill - only each skill's name + description, a lightweight index. The moment your message matches a description, the harness injects that one skill's full instructions. You carry the whole toolkit without filling up the context window.
The description is the router
That description field - "use when the user says X, Y, Z" - is the trigger logic that decides which skill fires. Getting it right is real engineering: skill-creator has eval and benchmark tooling to measure trigger accuracy, so the right skill firing is tested, not luck.
You're letting automation write to your platform database - here's why it won't corrupt it
The fair worry about any LLM tool: it can word things differently each time, so how is it safe to point at your tasks, risks, and people records? Five patterns - each one real in this platform - keep the unpredictable part away from your data, on top of the database's own RLS and write gate.
The math lives in code, not the model
em-1on1-logger has the model extract true/false signals (each with a verbatim quote), then computes the 0-10 satisfaction score by fixed arithmetic in code - not model judgment. The model does what it's good at (read a transcript, decide "did they raise a blocker? true/false"); code does the counting, identically every time. Same signals in, same score out.
Idempotency keys - run it twice, nothing breaks
Every write carries a dedup key, e.g. convlog:<engagement>:<date>T<HH:MM>. Run the same skill twice on the same meeting and the second run is a no-op - no duplicate row. It's the same trick payment systems use to avoid double-charging.
Ambiguous? It returns needs_human instead of guessing
em-identity-resolver is deterministic and account-scoped: if it can't be sure who a name refers to, it returns needs_human rather than picking. The toolkit is allowed to refuse to act when confidence is low - bounded autonomy with an explicit escalation path, not a confident wrong answer.
Skills hand each other validated JSON, not prose
When one skill feeds another, it passes a schema-checked payload. Malformed output is rejected at the tool layer and the model retries. The validation is deterministic even though the generation isn't - that's how skills chain without small errors compounding into a bad write.
Propose → approve → apply for anything irreversible
Risk and task changes use a tick-to-approve loop (the RISK- propose/approve/apply flow, the draft queues). The model proposes, you approve, deterministic code applies. Nothing irreversible happens straight from raw model output.
Packaging, and why the toolkit is yours after one setup
A plugin is a folder with a plugin.json and subfolders for skills / agents / commands / hooks. The marketplace (qualitara-em) is a set of domain plugins - people management, risk, OKRs, reporting, and more. The plugin is the unit you version, ship, and update.
Config-as-data - skills hold zero hardcoded data
The platform resolves your identity from your Postgres login (em_private.effective_uid()) and your accounts from your assignments; per-EM preferences live in em.em_settings_current. A small file-only em-manifest.json overlay still carries file paths (renderer locations, output directory, Tability slug) - never data ids. That separation buys two things:
It's scoped. Every read and write is scoped to the accounts you're assigned - the same skill points at your data because the database gates it by identity, not because of a hardcoded id.
Code and configuration stay separate - a 50-year-old software principle applied to AI tooling. A skill can be updated for everyone without touching anyone's private setup.
How multi-step work gets done
Three escalating levels - knowing which one is running tells you how much is happening behind a single request:
| Mechanism | What it is | When it kicks in |
|---|---|---|
| Single skill auto-trigger | One description matches, one skill runs | "log my 1:1" |
| Subagent | A fresh model instance with its own context window; does a scoped job and returns a result | Parallel independent work, or keeping a big search out of the main conversation |
| Orchestrator (Qira) | A "boss" skill that plans, confirms once, dispatches specialists in order, then reports back | Composite work: "close the quarter for Acme Robotics" |
em.proposals, the evening applies the approved ones. They coordinate through the database, not a shared conversation.One request, end to end
Read it as a loop: the harness assembles context, the model (the only red, unpredictable box) proposes actions, tools read from your systems, and every write passes through the green determinism gate before it lands.