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 engine

Waiting

Pick an example, or write your own call. The answer comes from the same policy engine the dashboard uses.

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.

Loading a run…

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.

    validClick a car to begin.

    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.

    RuleToolWhenEffectWhy

    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.mjs
    • The policy judges what will run.

      Every tool turns its arguments into one canonical form first. Paths like workspace/%2e%2e/secrets are rejected instead of being judged as harmless text.

      test/tools.test.mjs · test/adversarial.test.mjs
    • An 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.mjs
    • Two 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.mjs
    • A 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.mjs
    • The 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