ruv.sgit.airUv + sgit

The mechanism, with the file names

Architecture

One mandate document, several enforcers. One vault model, several writers. Everything on this page maps to a file in the repository.

Layers, and where we sit

flowchart TB
  subgraph hosts["Hosts: where agents run"]
    CC["Claude Code
(Ruflo as MCP / plugin)"] GH["GitHub Actions
(.github/workflows/pocs.yml)"] BR["Browser
(site/app, served from the vault)"] end subgraph orch["Orchestration and policy"] RF["Ruflo swarm: queens + workers"] PE["Ruflo AgenticPolicyEngine
@claude-flow/security"] MH["MetaHarness scaffold
.claude/settings.json"] end subgraph mem["Memory"] RV["Ruflo memory / RuVector
.swarm/memory.db, ruvector.db"] WASM["@ruvector/wasm
VectorDB in the page"] end subgraph metal["Below the host"] RVM["RVM: capabilities, 7 rights, witness log"] end subgraph ours["sgit.ai"] ABP["ABP
abp/examples/*.abp.json
abp/schema · abp/vocabulary · abp/mapping.json"] VP[("ruv-pocs-public")] VM[("ruv-pocs-memory")] end CC --> RF --> PE GH --> PE BR --> WASM RF --> RV ABP -- "poc1 compile.mjs" --> PE ABP -- "poc3 abp_to_rvm.py" --> RVM MH -- "poc5 harness-to-abp.mjs" --> ABP PE -- receipts --> VP ABP --> VP VP -- "app/ + data/" --> BR RV -- "poc2 run.sh: branch per role" --> VM CC -- "poc6: session record" --> VM classDef ours fill:#d9f1ee,stroke:#0f766e,color:#1a1917 class ABP,VP,VM ours

The Agent Behaviour Policy

An ABP describes one agent system in one deployment. For each role it lists rows, and each row is one capability (a primitive from the vocabulary) with:

  • reach: can it, technically, today? (boolean)
  • mandate: is it authorised to? yes · no · approval
  • instances: paths, hosts, repos, budgets: instances of the primitive, never new primitives
  • barrier: what actually stops it when the mandate is no or approval
  • why: one line for the reader

At the top: deployment, owner (the named person who signs), valid_until (a licence to operate expires). A row with reach, a mandate other than yes, and no barrier is a gap; the CI gate fails on gaps.

{ "capability": "send.message.world",
  "reach": true, "mandate": "no",
  "why": "agents draft, a person sends",
  "barrier": "policy deny + no mail credential in the sandbox" }

Schema: abp/schema/abp.schema.json. Example: abp/examples/ruflo-sparc-swarm.abp.json (6 roles, 36 rows).

One ABP row: reach, mandate, gap, barrier, owner
One row, five questions. The grammar is verb.object.reach.

The whole swarm's ABP

loading…

Grammar: verb . object . reach

23 primitives, each with an undo class. A specific path, host or mailbox is an instance of a primitive, never a new one, which is what keeps the document short enough to sign.

Verbs

read write create delete execute send receive authenticate-as grant revoke

Objects

file process network-endpoint credential message record repository budget schedule

Reaches

self the agent's own process · project the working tree · host the machine · tenant the organisation's systems · allowed a listed set · world anything else

Vocabulary: abp/vocabulary/capabilities.json, promoted from RiskMandate's published capability map without renaming.

Compile targets

The same row becomes different things in different enforcers. The mapping lives in abp/mapping.json; the action strings are our convention for the trace, and Ruflo matches rules on whatever strings the caller emits.

TargetrUv surface (verified 14 Oct 2026)Our mappingPOC
Ruflo policy engineAgenticPolicyEngine: modes legacy / observe / enforce; PolicyRule {id, effect, actions[], principals[], resources[], priority, constraints}; setBudget; hash-chained receipts; verifyLedger()mandate yes → allow; no → deny; approval → require_approval; write.budget.* → setBudget; primitive → action strings1
RVM7 rights READ, WRITE, GRANT, REVOKE, EXECUTE, PROVE, GRANT_ONCE; no ambient authority; witness logper-role token rights from mandated rows; withheld list from the rest; gaps3
Browser viewer@ruvector/wasm VectorDB, cosine, HNSWeach row embedded (bag-of-words hash, no model) and searchable4
MetaHarness.claude/settings.json permissions allow/deny, mcpServers, CLAUDE.md ruleseach setting → an ABP row; diff both ways5
Ruflo claimsruflo claims list|check|grant|revoke|roles|policiesroles = ABP roles; claims = allowed primitives (next step)next
Ruflo guidanceruflo guidance compile (CLAUDE.md → policy bundle), gatesour CLAUDE.md is the builder's ABP in prose; compile it and comparenext
RuVector MCPRUVECTOR_MCP_PROFILE=readonly, RUVECTOR_MCP_ALLOW / _DENYrows on memory tools → allow/deny listsnext
ABP rows for coder compile into a capability token with READ, WRITE, EXECUTE lit and GRANT, REVOKE, PROVE, GRANT_ONCE withheld
POC3: the token says what; the ABP keeps why.
ABP to compile to Ruflo policy engine, legacy lane and enforce lane, receipts, vault
POC1: the same trace through legacy and enforce.

The two vaults

ruv-pocs-public

Published with its read key, on purpose. Holds the ABPs, compiled rules, the POC1 report and receipts, the RVM table, the MetaHarness diff, and the browser app under app/. Every CI run adds runs/<run_id>/. Publishing the read key is irreversible; that is why it is a separate, single-purpose vault.

ruv-pocs-memory

Private. Agent memory per role under memory/<role>/, written on a branch per role and merged; recorded Claude Code sessions under sessions/<date>/. The key lives only in repository secrets and in the owner's keychain.

What the server sees

Ciphertext under opaque ids. sgit encrypts files client-side with AES-256-GCM before upload; filenames, contents and commit messages are inside the envelope. The vault key is {passphrase}:{vault_id}; there is no reset. Keys are passed to sgit clone on stdin, never as an argument.

Data flow in one run

sequenceDiagram
  autonumber
  participant Dev as developer / CI
  participant G as abp:gate
  participant P1 as poc1 run.mjs
  participant P3 as poc3 abp_to_rvm.py
  participant P4 as poc4:build
  participant H as human approver (environment vault)
  participant VP as ruv-pocs-public
  participant P2 as poc2 run.sh
  participant VM as ruv-pocs-memory
  Dev->>G: compile the ABP, count gaps
  G-->>Dev: 0 gaps
  Dev->>P1: evaluate trace in legacy and enforce
  P1-->>Dev: report.json, rules.json, state-abp.json, ledger valid
  Dev->>P3: rights per role + withheld + gaps
  Dev->>P4: app/ with vendored WASM + data/
  Dev->>H: approve publish?
  H-->>VP: sgit write runs/run_id --push, then sgit publish --visibility public
  Dev->>P2: write coder → branch, push, merge
  Dev->>P2: write tester → branch, push, merge
  P2->>VM: encrypted DB files + memory-list.txt
  P2->>VM: fresh runner clones, restores, runs ruflo memory list
  VM-->>P2: same entries

The builder's own ABP

The agent that built this repository (a Claude Code session) had its own ABP: abp/examples/builder-agent.abp.json, in prose as CLAUDE.md. It may write files in this repo, run processes, reach the npm and PyPI registries, GitHub and the sgit server, and push to feature branches. It may not send messages to the world (no emails, issues or comments on rUv's repos), and may not print, log or commit a vault key or token. Where the build hit a limit, the note is in build notes; where it had to stop (Ruflo's interactive policy admin), it did not work around it.

capabilityreachmandatebarrier
write.file.projectyesyesthis repo only
execute.process.selfyesyesnpm, pip, node, python in the repo or runner
send.endpoint.allowedyesyesregistries, GitHub, sgit server, rUv's public repos
write.repository.projectyesyesfeature branches and PRs; never force-push main
authenticate-as.credential.tenantyesapprovalrepo secrets only; masked
send.message.worldyesnorule in CLAUDE.md: Dinis talks to rUv
read.credential.hostyesnogit diff before every commit; keys only via env