Open source approval gates and a record of every agent action
A private deployment that never records which agent acted, and who allowed it, gives a reviewer nothing to test. Kortix is the open-source AI Operating System: your agents, their skills, your company memory, and every connector in one git repo you own, with the agents working on real cloud computers.
What private means to an auditor, and what it means to a buyer
A buyer asks where the data sits. An auditor asks what the system let an agent do, who said yes, and what still proves it six months later. Those are different questions, and only the second one survives contact with a test.
The buyer's checklist is familiar. A region, a retention period, a promise that prompts do not train a model, a certificate on the wall. Each item describes a boundary around data at rest. None of them describes the moment an agent sends an email, edits a ticket, or pushes a commit into the branch everyone deploys from. Confidential data with a faster exit is still a finding, and the exit is the agent holding a credential.
So a review moves to three artifacts: the rule that governs an action, the decision that rule produced, and the record of both. A reviewer can open the policy and read it, watch a call stop and wait, then pull the row afterwards. The perimeter diagram is context for those three, and nothing more.
The fact that matters about a control is its default, before anyone touches it. A feature grid that lists approval gates says nothing about what runs before anyone configures them, and a demo never shows the difference, because a demo has no destructive call in it.
Three controls to set on day one, and the default each ships with
| Control | Where it lives | Default before you touch it |
|---|---|---|
| ControlPer-action policy | Where it livespolicies: in the connector block | Default before you touch itevery action runs (allow_all) |
| ControlMerge gate | Where it livesthe merge permission, project.gitops.merge | Default before you touch itagents denied unless an admin grants it |
| ControlAudit record | Where it liveswritten per action | Default before you touch itrecorded; reading depends on the plan |
Who may run which agent at all is the outer control, and it is separate from the rules that follow. "Per-resource permissions for people and agents. Roles, groups, and an audit trail."
The per-action policy is the one that decides whether an agent can act at all. In Kortix a connector block in the project manifest carries a policies: list. Each rule has a match glob over <connector>.<tool> and an action: always_run, require_approval or block. A rule can match the arguments of the call too. So the hold applies to a payment over a threshold, or the message to a domain outside the company, and everything else runs untouched (policy reference). The order is the other half of the mechanism. Kortix decides each connector call in this order, and in each list the first rule that matches wins: the project's policies, then the calling agent's policy set on that connector, then the connector's own policies, which are the base rules. A set or a base rule cannot loosen a project rule, and a set can loosen a base rule for the agent that holds it.
The default is the part worth writing down. "Approval gates you set. Off until you set them." A project with no policy declared runs every action, and policy.default_mode stays allow_all until someone changes it. The middle setting, risk, is often the better starting point: reads run, writes and deletes wait for a person. One line in the manifest, and the first dangerous call of the week stops at a name.
The merge gate covers the other half of the risk, the half that outlives a session. Code and configuration are the company here, so an agent that can write to main can change the rules that govern it. The rule for session work reads: "Nothing merges itself: work reaches main through a change request a person approves, unless an admin granted the merge capability." Today that capability is project.gitops.merge, and an agent merges only when its grant names it. Two things are worth asking in your own setup: which agents hold that permission, and who granted it. The gate is the grant.
The audit record is the third control, and the one with the smallest print. "Every action is recorded. Reading, exporting and streaming the audit log depend on the plan." Recording is the part that happens whatever you pay. Reading, exporting and pushing the rows into your own SIEM are the parts the plan decides, so a team that plans to answer a regulator from this record should price the plan that exports it.
What the record answers six months later, and where it stops
Open one action and the row can tell you a great deal. Which agent ran, in which session, on which branch. Which connector and which connected account the call used. What arguments went out. Whether a policy held the call, who approved it, and when the approval landed. Whether the change that followed arrived as a change request, and which commit came out the other side.
That is enough to answer the questions a review actually asks. Did a person authorize this? Was the authorization in place before the action? Can you list every external write by a named agent in a date range? Can you show the same trail for a denied or expired call, which is the harder and more convincing artifact?
Where the record stops is intent. A row shows a call and its arguments. The reason behind the call stays inside a model, and no log makes that reason auditable. A record also proves that an account approved something, and says nothing about whether the approver read the diff. If your process needs that, the signature on the change request carries it.
Two more limits belong in the same paragraph, because procurement finds them late. Anything the agent read inside its sandbox and never sent through a tool may live only in the session transcript, if that was captured. And the row proves the call left your side. What the receiving system did with it lives in that system's log, which is a separate retention problem.
Retention is the quiet one. A record pruned before your audit window closes answers nothing. Ask for the retention period of the plan you are buying, and get it in writing.
Whose disk the record sits on
On most platforms the record is a screen inside the vendor's console. The rows are a feature of the subscription: their retention, their export, their deletion, their access model. You read the log through an interface someone else controls, and when the contract ends the evidence leaves with it.
When the database is one you operate, the arithmetic changes. Retention becomes a policy you write. A query runs against a table you can read. The rows survive a price rise, an acquisition, or a decision to move to a different deployment next year. What lands on your disk when you run the stack yourself is on the self-hosting page, down to the files.
Custody of the evidence is the point, and it is narrower than privacy of the network. Renting the machine an agent works on is a normal trade, and it does not decide who keeps the record of what the agent did. Those are two separate lines in an architecture note, and the second one is the line a reviewer marks. How each shape divides custody is on the platform page.
A test that works on any vendor's claim
Any team can run this against any product in an afternoon. It needs three things: a working tenant on the plan you would buy, a person who can log in as an approver, and an action with a consequence.
Pick the action first: send a message to an outside address, update a customer record, create an invoice. Something a business would notice if it happened without warning.
Then ask for the rule that governs it, in the form you would receive it. A file is better than a screen, because a file has a diff and a review. Ask what happens when no rule matches, and write down the answer, since that default is what runs on day one.
Run the action. Watch it hold. Note who is allowed to approve, and whether the requester can approve their own call. Ask what happens when nobody decides. In Kortix
approvals.ttldefaults to 24 hours and clamps between five minutes and 30 days. A held call that nobody decides expires without running.
Then export the rows for that call and read the fields: actor, action, arguments, decision, approver, timestamp, session. If the export needs a higher plan, you have just priced the control.
Ask last for the log of a denied action. Approvals are what every demo shows. Denials and expiries are where a policy engine either works or quietly does nothing. A vendor that can produce those rows has the thing you are buying.
Kortix is open source, so the policy engine and the audit route can be read in the repository. They run on your own server before a purchase order exists. That is the shortest version of this test: clone it, write one rule, run one call, read one row.
The rule that holds a call, in the project's manifest
# Connectors: the credentials live in Kortix, never in this file.
connectors:
- slug: github
provider: composio
app: github
- slug: linkedin
provider: composio
app: linkedin
policies:
- match: "linkedin.create_*"
action: require_approvalOne connector block from a Kortix project's kortix.yaml: the credential stays on the server, and every LinkedIn create call waits for a person. Source
What buyers ask about approvals and audit
Short answers, each one pointing at the artifact a reviewer would ask to see.
No, if completely private means with no network at all, because an agent's sandbox has to reach the instance that runs it. The testable version is narrower: a rule that holds a write for a person, and a log of the call, the approver and the change it produced.
Yes, at the level a review can check. Set the rule before the agent runs, start with one consequential write held for approval, and read the row it leaves behind. A private deployment with no policy and no record is confidential data with a faster exit.
The one whose approval rule and audit rows you can read before you buy, on the plan you would pay for. Ask for a held call and its log line from a tenant shaped like yours, then ask for a denied one.
Three lines: the server or the managed plan, the model calls, and the compute every session runs on. The line teams miss is the audit export, which often sits on a higher plan than recording does, so price it with the contract.
Write one rule, then watch it stop a call
The policy is a file, the record is a table, and both are testable before you sign anything.