Every agent action stops at the gate.
AgentGate checks each tool call an AI agent makes against a policy you can read. Safe calls run. Risky ones wait for a person. Every step goes into a log that shows if anyone edits it.
Send a call through the gate
connecting to the policy engineWaiting
Pick an example, or write your own call. The answer comes from the same policy engine the dashboard uses.
A person has to decide this one. In the dashboard that is a different, signed-in account. Here you can play the approver.
- What would actually run
- Call hash. An approval is tied to this.
A run is a train. Each step is a car.
Pick a scripted agent. The server sends each of its calls through the gate and writes a log. Every record carries the hash of the one before it, so changing any record breaks every coupling after it.
What the gate decided
Try to rewrite history
Click a car to open its record. Change anything and press Verify. The server re-hashes the chain and says where it breaks.
The policy is a file you can read.
Plain JSON, so it can be reviewed, diffed and versioned. When several rules match, deny beats approve beats allow. When none match, the call is denied.
| Rule | Tool | When | Effect | Why |
|---|
Six promises, each one tested.
Unknown means no.
A call that matches no rule is denied. Unknown tools and unexpected arguments are rejected before the policy even runs.
test/policy.test.mjs · test/tools.test.mjsThe policy judges what will run.
Every tool turns its arguments into one canonical form first. Paths like
workspace/%2e%2e/secretsare rejected instead of being judged as harmless text.test/tools.test.mjs · test/adversarial.test.mjsAn approval covers one call.
Approving means approving a hash. If the call changed after the person looked, the approval is refused and nothing runs.
test/runtime.test.mjsTwo people, and a clock.
The account that started a run cannot approve its own call. Approvals expire after 15 minutes, and the policy is checked again at the moment a call would run.
test/runtime.test.mjsA crash does not repeat a refund.
Run state is rebuilt from the log. Restart the server mid-run and it continues once, not twice. The Postgres store is tested against the same contract.
test/runtime.test.mjs · test/store-contract.test.mjsThe log shows tampering.
Edits, deletions and reordering break the hash chain, as you can check above with the real verifier.
test/runtime.test.mjs · test/play.test.mjs
What it does not do.
Stated here so nobody finds out later.
- The tools are simulated. No email is sent, no money moves, no command runs. The point is the gate, not the tools.
- The agents are scripts. Five scripted scenarios exercise the gate. Plugging in a model-driven agent means writing a planner with the same small interface.
- The chain detects, it does not prevent. Someone who can write to the database and recompute every hash after an edit can forge a history. Dropping the newest records is only visible if you kept the head hash somewhere else.
- It is not your authorization layer. It decides whether an agent may call a tool. It does not replace permissions in the systems those tools talk to.
- Not load-tested or audited. Built and tested as a portfolio project by one person.
Run it yourself.
git clone https://github.com/karthik1122-code/agentgate cd agentgate && npm ci AUTH=off npm start
AUTH=off is a local demo mode with no sign-in. A deployed copy uses accounts and a Postgres database.
Open the dashboard