AgentsOpen SourceFreeActiveMachine-verified· beginner · ~10 min setup

QM: prove the destructive-action denials hold in every security posture, even the loosest

Run YC's company-wide QM agent with one org-wide security posture, and prove the predeclared hard denials (recursive delete, destructive SQL, mass delete) are refused in every posture including the loosest, so loosening the posture only relaxes approvals, never the destructive-action guardrails.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 2/2 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Anyone evaluating a company-wide agent who needs to know that 'loosest security setting' does not mean 'anything goes.' CI models QM's posture policy and asserts destructive commands (recursive delete, destructive SQL, mass delete) are denied under strict, standard, AND the loosest dangerous posture, while the approval-required surface shrinks as you loosen. Pure Python stdlib, no server, no network, no key. Per-room memory scoping, the swappable model core, and the actual Fly.io/AWS deploy are fenced.

Not for

  • Reading 'Dangerous' as 'anything goes', the loosest posture only removes the approval gate for ordinary tool calls; the hard denials (recursive delete, destructive SQL, mass delete) are refused in every posture, this recipe included
  • Letting one agent's memory bleed across rooms, each person and each channel gets its own scoped memory, files, and keychain, so keep a project in its own channel or context leaks between unrelated work
  • Skipping the email sender, QM emails one-time login links, so without a Resend key or SMTP wired in nobody can sign in, it is the step people most often forget
  • Treating it as a managed service, QM installs into your own Fly.io or AWS account and runs on your cloud bill with the keys in your hands, and it is days old and small, so pilot it on one channel for a week first
  • Assuming the posture is per-user, it is one org-wide setting; the person-versus-room boundary is scoped memory and permissions, not a different security posture per employee

The Stack

Tested Against

github.com/yc-software/qm README (2026-08)npm @yc-software/qm@0.1.4python@3.9-3.14

Side effects & data flow

Network
none, local only
Writes
no filesystem writes
Credentials
none required

Prerequisites

  • Python 3 for the policy check (no packages)
  • For a real deployment: Node.js + a Fly.io or AWS account + an email sender (Resend or SMTP)

Steps

  1. 1

    Model the posture policy and prove the hard denials survive the loosest posture

    QM's org picks one posture, from strict to dangerous, but a predeclared command policy hard-denies destructive actions in all of them. CI classifies each command, evaluates it under all three postures, and asserts every destructive command is denied everywhere (dangerous included) while the approval-required surface shrinks from strict to dangerous. Loosen the posture and ordinary tool calls stop pausing for approval, but recursive delete, destructive SQL, and mass delete stay refused.

    python3 - <<'EOF'
    import re
    postures = {
        "strict": ["read_file", "list_dir"],
        "standard": ["read_file", "list_dir", "run_tests", "open_pr", "search", "query_select"],
        "dangerous": "ALL",
    }
    hard_deny = [
        (r"rm +-rf", "recursive_delete"),
        (r"\bDROP +TABLE\b", "destructive_sql"),
        (r"\bDELETE +FROM +\w+ *;? *$", "delete_without_where"),
        (r"\bTRUNCATE\b", "mass_delete"),
    ]
    def is_hard_denied(cmd):
        return any(re.search(p, cmd, re.I) for p, _ in hard_deny)
    def evaluate(cmd, posture):
        if is_hard_denied(cmd):
            return "deny"
        allow = postures[posture]
        if allow == "ALL":
            return "allow"
        tool = cmd.split()[0] if cmd.split() else ""
        return "allow" if tool in allow else "needs_approval"
    
    destructive = ["rm -rf /data", "DROP TABLE users", "DELETE FROM orders", "TRUNCATE logs"]
    for posture in postures:
        for cmd in destructive:
            verdict = evaluate(cmd, posture)
            assert verdict == "deny", "posture " + posture + " failed to deny: " + cmd + " -> " + verdict
    
    probe = ["read_file x", "list_dir x", "run_tests", "open_pr", "search q", "query_select all", "deploy_app", "send_email"]
    approvals = {p: sum(1 for c in probe if evaluate(c, p) == "needs_approval") for p in postures}
    assert approvals["strict"] > approvals["standard"] > approvals["dangerous"] == 0, "approval surface must shrink to 0 at dangerous"
    assert evaluate("send_email", "dangerous") == "allow" and evaluate("send_email", "strict") == "needs_approval"
    
    print("posture policy OK: the hard denials (recursive delete, destructive SQL, mass delete) are refused in all 3 postures including the loosest (dangerous); only the approval surface relaxes (tool calls needing approval: strict=" + str(approvals["strict"]) + " -> standard=" + str(approvals["standard"]) + " -> dangerous=" + str(approvals["dangerous"]) + "). Per-room memory scoping, the swappable model core, and the real deploy are fenced")
    EOF
  2. 2

    Deploy QM into your own cloud (the parts CI cannot do for you)

    Run the real init from the QM npm package: qm init . --org <slug> --target <fly-or-aws>, then npm install, and answer the prompts (admin email, an email sender for the one-time login links, and optional Slack access). Pick your org's posture, keep each project in its own channel so memory stays scoped, and remember the whole thing runs on your own Fly.io or AWS bill with your own keys. Which model core drives it and what your team actually asks it are the fenced parts.

Eval, 2 fixtures

Last passed: verified today
  • posture-okcontainstimeout 30s · max $0

    Expected: posture policy OK: the hard denials (recursive delete, destructive SQL, mass delete) are refused in all 3 postures including the loosest (dangerous); only the approval surface relaxes (tool calls needing approval: strict=6 -> standard=2 -> dangerous=0). Per-room memory scoping, the swappable model core, and the real deploy are fenced

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 0

Results

QM is the agent YC open-sourced and says it runs its own accounting, legal, events, and engineering on: a company-wide teammate where every person and every room (a Slack channel or project) gets its own scoped memory, files, and workspace, and Pi, OpenCode, Codex, or Claude Code can each drive the same core. The reassuring part is the safety model. An org picks one posture, from strict (every tool call pauses for approval) to dangerous, but a predeclared command policy hard-denies destructive actions in EVERY posture. This recipe turns that promise into a check: flip to the loosest posture and the mass-delete and destructive-SQL denials still hold, while only the approval gate opens up.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Related workflows

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).