AIShell-Gate — Getting Started Guide

Getting Started Guide

A practical guide to building, configuring, and running the two-program system that puts a deterministic policy layer between AI-generated shell commands and Unix execution.

aishell-gate-policy 0.65.0-beta  ·  aishell-gate-exec 0.24.0-beta

Copyright © 2026 AIShell Labs LLC. All Rights Reserved. — www.aishell.org/aishellgate

01 What This Is

This guide assumes familiarity with Unix command-line environments and basic JSON structure.

AIShell-Gate is two C programs that work together. The first, aishell-gate-policy, is a policy engine: it reads a proposed shell command, evaluates it against your rules, and emits a structured JSON verdict. The second, aishell-gate-exec, is an execution harness: it accepts a JSON plan from an AI agent or caller, runs each command through the policy engine, handles any required human confirmation, and finally calls execve() with the validated arguments.

Neither program is optional. The policy engine never executes anything. The executor has no policy logic of its own — it cannot approve or deny a command; it only acts on what the engine decides. That separation is the security property the system depends on.

The practical result is that AI-generated commands do not go directly to a shell. Every command passes through a deterministic gate first. What comes out the other side is either a denial with a reason, or a validated argument array accompanied by a required confirmation level. The executor acts on that, not on the original command string.

AI agent aishell-gate-exec (no policy logic) aishell-gate-policy (policy engine, separate process) ALLOW / DENY + confirmation level execve() (validated argv only, no shell)

02 Before You Build

You need a C compiler and a POSIX-compatible Unix system. Linux, macOS, and the BSDs all work. There are no external library dependencies: both programs embed a JSON tokenizer (JSMN) and a SHA-256 implementation directly. A standard cc or clang invocation is all that is required.

Check that you have a compiler:

cc --version

That is the complete prerequisite list.

03 Building

Compile each program separately. Put both source files in the same directory and run:

cc -std=c11 -Wall -Wextra -O2 -o aishell-gate-policy aishell-gate-policy.c
cc -std=c11 -Wall -Wextra -o aishell-gate-exec   aishell-gate-exec.c

Both should compile cleanly with no warnings. Verify the builds:

./aishell-gate-policy --version
./aishell-gate-exec   --version

Leave both binaries in the same directory while you are getting started. The executor needs to be told where the policy engine lives; co-locating them makes that simple.

Note: The --policy flag passed to the executor must be an explicit path containing a / character — for example ./aishell-gate-policy or /usr/local/bin/aishell-gate-policy. Bare names are rejected at startup to prevent PATH-based substitution.

04 First Run: Interactive Mode

The quickest way to see the system working is to run the policy engine interactively. With no arguments and a terminal on stdin, it drops into a command prompt where you can type Unix commands and watch it evaluate them:

./aishell-gate-policy
> git status
ALLOW: command validated by policy (confirmation: none)
> rm -rf /var/log
DENY: recursive deletion outside allowed paths
> ls -la
ALLOW: command validated by policy (confirmation: none)
> quit

The default policy preset is ops_safe, which allows a conservative set of read-only and repository inspection commands and denies destructive operations and privilege escalation. You will see this behavior without any configuration files in place.

Type json after any command to see the full JSON decision record for the previous evaluation. Type quit or exit to leave.

05 Choosing a Preset

A preset is a named starting policy. You select one with --preset. Four are built in:

PresetDescription
read_onlyAllows inspection commands only: ls, cat, grep, find, ps, df, git status, git log, and similar. Denies everything that writes, deletes, or escalates privilege. Use this when you want to let an AI agent observe a system without being able to change anything.
dev_sandboxAllows developer workflow commands: git, make, compilers, package managers (pip, cargo, go, npm). Blocks disk destructors and privilege escalation. A reasonable starting point for AI-assisted coding workflows.
ops_safeThe default. A small conservative set of read and repository commands. Denies shells, interpreters, most write operations, and all privilege commands.
danger_zoneMinimal restrictions. A wildcard allow rule permits most commands, but the built-in deny list (shells, interpreters, disk destructors, privilege escalation) still applies. Use cautiously and only when you have a good reason.

Whatever preset you choose, confirmation levels and risk scoring always apply on top of it. A high-risk command does not bypass confirmation just because the preset allows it.

06 Risk and Confirmation

When the policy engine allows a command, it also assigns a confirmation level that tells the executor how much human review is required before the command actually runs. There are four levels:

LevelMeaning
noneProceed immediately — no human review needed.
planShow the plan to a human before executing; review is suggested.
actionRequire explicit per-command human approval.
typedThe human must type a confirmation code derived from the exact command text.

Your policy rules can set a confirmation level for any allowed command. But the engine also scores every command for risk on a scale of 0 to 100, and will automatically raise the confirmation level if the score is high enough:

This escalation is strictly one-way. The engine can only raise a confirmation level, never lower it. A command that would normally require a typed confirmation cannot have that requirement removed by any policy layer beneath it.

Some representative scores: ls and cat score 0–5 and require no confirmation. git scores 20 and requires a plan-level review. curl and wget score 60 and require action confirmation. rm scores 80 and requires typed confirmation. dd, parted, mkfs, and wipefs score 95–98, also requiring typed confirmation. Arguments make the score worse: targeting a system path adds 15 points, a recursive flag on a destructive command adds 10, --force with rm or mv adds 10.

07 Running a Plan Through the Executor

For real use, you do not call the policy engine directly. You pass a JSON plan to aishell-gate-exec, and it handles the rest. The plan format is simple: a goal description, an optional source label, an optional strategy, and an array of commands.

echo '{
  "goal":     "check repository state",
  "source":   "ai",
  "strategy": "fail_fast",
  "actions": [
    {"cmd": "git pull"},
    {"cmd": "git status"},
    {"cmd": "npm test"}
  ]
}' | ./aishell-gate-exec \
  --policy ./aishell-gate-policy \
  --preset dev_sandbox

The executor submits each command to the policy engine in sequence, reads the JSON verdict back, collects human confirmation if the confirmation level requires it, and calls execve() with the validated argument array from the verdict. The raw command string never touches a shell.

The strategy field controls what happens when a command is denied or fails. fail_fast stops at the first problem. best_effort continues through failures and reports what happened.

08 Evaluating a Single Command

You can pipe a single command to the policy engine directly, without using the executor or writing a JSON plan. This is useful for scripting, testing, or integrating the policy check into other tools.

echo "git status" | ./aishell-gate-policy --preset dev_sandbox

Add --json to get the full machine-readable output:

echo "git status" | ./aishell-gate-policy --preset dev_sandbox --json

The JSON output includes the overall decision, the confirmation level, the matched rule, the policy layer that matched it, the validated argument array, the risk score and flags, the blast radius classification, and a short plain-text summary suitable for display to a human.

If you are integrating this into a script, the exit code from the policy engine is always 0 when it runs without internal error — regardless of whether the decision was ALLOW or DENY. The decision itself lives in the JSON output. Exit code 1 means an internal error; exit code 2 means a usage problem. This allows the policy engine to be used in pipelines without being mistaken for a command failure. The calling script reads the JSON to determine what happened.

09 Writing Your First Policy File

Presets are a starting point. For real use you will want to layer your own rules on top. Three optional JSON files can override any layer of the policy stack:

By default the engine looks for all three files in the current directory. You can point to different paths with --policy-base, --policy-project, and --policy-user. If a file is absent it is silently ignored. If it exists but cannot be parsed, the engine fails closed and reports the problem.

Here is a minimal project policy that allows a few specific git commands without confirmation, requires action confirmation for npm publish, and blocks curl entirely:

{
  "cmd_allow": [
    { "pattern": "git status",  "confirm": "none",   "reason": "safe read" },
    { "pattern": "git diff",    "confirm": "none",   "reason": "safe read" },
    { "pattern": "npm test",    "confirm": "plan",   "reason": "run tests" },
    { "pattern": "npm publish", "confirm": "action", "reason": "publish step" }
  ],
  "cmd_deny": [
    { "pattern": "curl", "reason": "no outbound network in this env" }
  ],
  "writable_dirs": [ "/home/user/myproject" ]
}

Save this as aishell-gate-policy_project.json in your working directory. It will be picked up automatically on the next run.

A few things worth knowing. Rule lists append to the preset by default. If you want your project policy to replace the preset's cmd_allow list entirely rather than extend it, add "cmd_allow_replace": true alongside your cmd_allow array. Unknown keys in a policy file are an immediate hard error, not a silent no-op — a typo like "cmd_denny" will fail the load and tell you what went wrong. A failed load has zero effect on the running policy; the engine restores the previous state atomically.

Run --help-policy at any time to print the complete policy format reference:

./aishell-gate-policy --help-policy

10 Argument and Path Rules

Beyond allowing or denying commands by name, you can write rules that match on specific arguments or on the paths a command targets. These let you allow a command in general while blocking specific dangerous invocations of it.

An argument rule matches a glob pattern against each argument of a given command. This example denies rm with the -rf flag regardless of what the preset would otherwise say:

{
  "arg_rules": [
    { "cmd_pattern": "rm", "arg_glob": "-rf", "decision": "deny",
      "reason": "rm -rf blocked by project policy" }
  ]
}

A path rule matches against the canonicalized path of any argument. Path rules apply only to commands that the engine classifies as write-capable — read-only commands like ls or cat are not subject to path rule evaluation. This example denies any write command that targets the /etc tree:

{
  "path_rules": [
    { "path_glob": "/etc/*", "decision": "deny",
      "reason": "writes to /etc are not permitted" }
  ]
}

Network rules work the same way but match against the hostname extracted from URL arguments. The built-in default base policy already denies 169.254.* and metadata.google.internal to block cloud metadata endpoint access.

11 Enabling Audit Logging

Every evaluation can be written to a tamper-evident JSON Lines audit log. Add --audit with a path to the policy engine to enable it:

./aishell-gate-policy --preset ops_safe --audit /var/log/aishell.jsonl

Each log entry carries a sequence number, session identifier, the full decision context, and a SHA-256 hash that links it to the previous entry. A gap in sequence numbers or a hash mismatch identifies deleted or altered entries. Verify the chain at any time without interrupting operation:

./aishell-gate-policy --audit-verify /var/log/aishell.jsonl

For environments that need authenticated audit trails, generate a key and enable HMAC-SHA256 mode:

head -c 64 /dev/urandom > audit.key
./aishell-gate-policy --audit-key audit.key \
  --audit /var/log/aishell.jsonl \
  --preset ops_safe

With a key, only a holder of that key can forge valid chain hashes. The audit log file is append-only. The engine does not rotate it. Protect it with appropriate filesystem permissions.

The executor also has its own separate audit log for the execution side. Add --audit-log to the executor invocation to enable it:

./aishell-gate-exec \
  --policy ./aishell-gate-policy \
  --preset ops_safe \
  --audit-log /var/log/aishell_exec.log

12 Confining Commands to a Directory

The --jail-root flag tells the policy engine to enforce path containment during evaluation. Any write-like command whose path arguments fall outside the jail root will be denied, regardless of what the policy rules say:

./aishell-gate-policy --jail-root /home/user/myproject --preset dev_sandbox

This is the only sandbox enforcement that happens inside the policy engine itself. The other sandbox modes (chroot, container, userns) are advisory hints that are passed through to the executor in the JSON output, where the surrounding infrastructure can act on them.

The jail root check is strict about directory boundaries. A jail root of /tmp/jail will not accidentally allow /tmp/jailbreak/x — the path must be actually inside the named directory, not merely share its prefix.

13 A Complete Example

Here is what a full setup looks like for a developer workflow: a project policy file, an audit log, a jail root, and a plan passed through the executor.

First, create the project policy file:

# aishell-gate-policy_project.json
{
  "cmd_allow": [
    { "pattern": "git status", "confirm": "none" },
    { "pattern": "git diff",   "confirm": "none" },
    { "pattern": "git pull",   "confirm": "plan" },
    { "pattern": "make",       "confirm": "plan" },
    { "pattern": "npm test",   "confirm": "plan" }
  ],
  "cmd_deny": [
    { "pattern": "curl", "reason": "no outbound network" },
    { "pattern": "wget", "reason": "no outbound network" }
  ],
  "writable_dirs": [ "/home/user/myproject" ]
}

Then run a plan through the executor with audit logging and a jail root:

echo '{
  "goal":     "pull latest and run tests",
  "source":   "ai",
  "strategy": "fail_fast",
  "actions": [
    {"cmd": "git pull"},
    {"cmd": "make clean"},
    {"cmd": "npm test"}
  ]
}' | ./aishell-gate-exec \
  --policy ./aishell-gate-policy \
  --preset dev_sandbox \
  --audit-log /var/log/aishell_exec.log

The executor will submit each command to the policy engine. git pull scores in the plan-level range — the executor pauses and shows the plan for human review. After confirmation, it executes via execve(). If any action is denied, fail_fast stops the sequence immediately. A tamper-evident audit entry is written for each decision.

14 What the Policy Engine Will Not Do

A few things are worth being explicit about, especially if you are coming from a security background.

No quoted arguments. Quotes are shell syntax, and the engine deliberately rejects all shell metacharacters before tokenization. This is intentional: supporting shell quoting would require implementing a shell grammar subset, introducing the same parsing ambiguity and injection surface the system is designed to eliminate. A command like grep 'hello world' file.txt cannot be expressed; the single quotes are rejected outright. Arguments with spaces are not supported.

Network rules match hostnames, not resolved IPs. A rule blocking example.com will not catch a URL that resolves to the same IP through a different hostname. Network rules capture intent, not strong enforcement — use firewall rules for that.

The engine is not a sandbox. It decides whether a command should run before it runs. It does not intercept what the command does while running. It complements OS-level access controls, kernel sandboxing, and proper permission management; it does not replace them.

The engine does not guarantee security against a determined attacker with local system access. It raises the cost and visibility of unsafe AI-generated actions and ensures that every attempt is recorded. That is what it is designed to do.

15 Session Policy

Before the engine evaluates any command at all, it checks whether the current session is permitted to make requests. Session policy can gate evaluation on the caller's uid or gid, their username, whether they are in an SSH session, whether stdin is a TTY, the session mode (interactive, batch, or daemon), and the time of day.

Session constraints go in the "session" key of any policy file. Here is an example that restricts operation to two specific users and denies access from SSH sessions:

{
  "session": {
    "allow_users": ["alice", "bob"],
    "deny_ssh": true
  }
}

Session evaluation happens before any command rule is checked. If the session does not satisfy policy, the engine returns a denial without evaluating the command at all. This makes session policy a hard outer gate on the entire system.

16 Remote Deployment

This guide covers local and single-session use. If you want to give a remote AI system access to a machine over SSH — using a forced command to gate every connection through aishell-gate-exec — that is covered in a separate document.

See the AIShell-Gate Remote Deployment Guide for: creating a dedicated ai-agent account, configuring the forced SSH command in authorized_keys, setting up the aishell-confirm operator relay, and the directory and permission requirements for multi-session deployments.

Beta scope: For this beta, remote multi-AI-session deployment with concurrent human confirmation is not supported. Single-session remote use (one AI agent, one operator watching a second SSH window) works correctly and is documented in the Remote Deployment Guide. Multi-session remote confirmation will be fully supported in a post-beta release.

17 Quick Reference

Build

cc -std=c11 -Wall -Wextra -O2 -o aishell-gate-policy aishell-gate-policy.c
cc -std=c11 -Wall -Wextra -o aishell-gate-exec   aishell-gate-exec.c

Interactive mode

./aishell-gate-policy

Evaluate a single command

echo "git status" | ./aishell-gate-policy --preset dev_sandbox --json

Run a plan through the executor

cat plan.json | ./aishell-gate-exec \
  --policy ./aishell-gate-policy \
  --preset dev_sandbox \
  --audit-log /var/log/aishell_exec.log

Verify an audit log

./aishell-gate-policy --audit-verify /var/log/aishell.jsonl

Read the policy format reference

./aishell-gate-policy --help-policy

For complete option documentation, policy file syntax, session policy fields, exit codes, and known limitations, see the man page: aishell-gate-policy(1). For the security architecture and design rationale, see the AIShell-Gate white paper.