Tool policy

One file per repository decides what the model may call, where, and whether to ask.

Tools are off until the directory ahi tui starts in has an ahi.tools.yaml with an approve rule. Only tools compiled into ahi exist; the file selects and bounds them and never defines or fetches one.

Start from a shipped policy

ahi tools examples          # names the shipped policies
ahi tools examples show commands
ahi tools init --write      # writes read-all into the working directory
ahi tools list              # shows the file in place, painted by outcome

init prints first and writes only with --write; an existing file is replaced only with --write --force. In a terminal every rule is painted green for approve, gray for ask, and red for deny, the same colors the chat uses for diffs. The output of both commands is reproduced in Shipped policies below.

The rules

version: 1
default: deny
rules:
  - id: no-env
    action: tool_call
    match: {tool: read_file, path: .env}
    effect: deny
  - id: read-tree
    action: tool_call
    match: {tool: read_file}
    effect: approve
  - id: edit-sources
    action: file_write
    match: {tool: edit_file, path: src}
    effect: approve
    ask: true
  - id: cargo-test
    action: command
    match: {argv: [cargo, test]}
    effect: approve
    toolchain_env: [CARGO_TARGET_DIR]

Three action kinds govern the seven tools:

ActionToolsMatched on
tool_callread_file, list_dir, find_files, search_filesA path prefix
file_writeedit_file, write_fileA path prefix, and which of the two
commandrun_commandA token-by-token argv prefix and a working-directory prefix

A matching deny beats any approval. ask: true prompts in chat for each call: y once, s for the session, n deny. Only tools an approve rule names are advertised to the model. Model output and tool results never create a grant.

What the boundary is

Every builtin tool works inside the working directory. Paths are relative to it; absolute paths, .., and symbolic links are refused before any read, write, or command, and run_command starts only in a directory inside it. The policy file, the hook configuration, .gitignore, and .git can never be written by a tool.

This is not a sandbox. A program approved by a command rule runs on the host with the operator's access: it can follow symbolic links, read files above the working directory, and run other programs. Approve commands accordingly, or run ahi tui inside ahi dev run for a container boundary.

Shipped policies

Seven policies ship inside the binary. ahi tools examples names them; ahi tools examples show prints each one with every rule painted by its outcome: approve hands the call to the model, ask prompts in chat first, deny refuses it. A rule's outcome is its effect, with ask: true turning an approval into a prompt.

ahi tools examples

Shipped tool policies (examples/tools, embedded in ahi). Each is a complete ahi.tools.yaml.

read-all        read, list, find, and search the whole working directory; root .env denied; no prompts (default)
ask-every-read  every read, listing, find, and search in the working directory asks in chat
sources-only    list the whole working directory; read, find, and search only src and docs
list-only       list directories in the working directory only; reads are denied
edit-sources    read the whole working directory; edit under src and tests after a prompt; create under tests
commands        read the whole working directory; cargo check and test run; other cargo asks; publish and install denied
deny-all        valid, no approve rule: no tool is advertised

Every builtin tool works inside the directory `ahi tui` starts in: paths are relative to it, and absolute paths, `..`, and symbolic links are refused.
This is not a sandbox. A program approved by a command rule runs on the host with the operator's access: it can follow symbolic links, read files above the working directory, and run other programs. Approve commands accordingly, or run `ahi tui` inside `ahi dev run` for a container boundary.

`ahi tools examples show <name>` prints one.
`ahi tools examples show` prints all.
`ahi tools init --example <name> --write` copies one into the working directory.

ahi tools examples show

approve ask deny the model gets the call, is asked in chat first, or is refused

read-all examples/tools/read-all.yaml

# Read, list, find, and search anywhere in the working tree; no prompts. The
# root .env is denied to read_file. Rules match a path prefix, so a nested
# .env or .env.local is not covered, and search_files skips it only when
# .gitignore does.
version: 1
default: deny
rules:
  - id: no-env                                                              
    action: tool_call                                                       
    match: {tool: read_file, path: .env}                                    
    effect: deny                                                            
  - id: list-tree                                                           
    action: tool_call                                                       
    match: {tool: list_dir}                                                 
    effect: approve                                                         
  - id: find-tree                                                           
    action: tool_call                                                       
    match: {tool: find_files}                                               
    effect: approve                                                         
  - id: search-tree                                                         
    action: tool_call                                                       
    match: {tool: search_files}                                             
    effect: approve                                                         
  - id: read-tree                                                           
    action: tool_call                                                       
    match: {tool: read_file}                                                
    effect: approve                                                         

ask-every-read examples/tools/ask-every-read.yaml

# Every read, listing, find, and search shows an approval prompt in chat.
version: 1
default: deny
rules:
  - id: ask-list                                                         
    action: tool_call                                                    
    match: {tool: list_dir}                                              
    effect: approve                                                      
    ask: true                                                            
  - id: ask-read                                                         
    action: tool_call                                                    
    match: {tool: read_file}                                             
    effect: approve                                                      
    ask: true                                                            
  - id: ask-find                                                         
    action: tool_call                                                    
    match: {tool: find_files}                                            
    effect: approve                                                      
    ask: true                                                            
  - id: ask-search                                                       
    action: tool_call                                                    
    match: {tool: search_files}                                          
    effect: approve                                                      
    ask: true                                                            

sources-only examples/tools/sources-only.yaml

# List anywhere; read, find, and search only under src and docs. Deny rules
# win over approvals. The .env and target denies are root paths.
version: 1
default: deny
rules:
  - id: no-env                                                             
    action: tool_call                                                      
    match: {tool: read_file, path: .env}                                   
    effect: deny                                                           
  - id: no-build-output                                                    
    action: tool_call                                                      
    match: {tool: read_file, path: target}                                 
    effect: deny                                                           
  - id: list-tree                                                          
    action: tool_call                                                      
    match: {tool: list_dir}                                                
    effect: approve                                                        
  - id: read-sources                                                       
    action: tool_call                                                      
    match: {tool: read_file, path: src}                                    
    effect: approve                                                        
  - id: read-docs                                                          
    action: tool_call                                                      
    match: {tool: read_file, path: docs}                                   
    effect: approve                                                        
  - id: find-sources                                                       
    action: tool_call                                                      
    match: {tool: find_files, path: src}                                   
    effect: approve                                                        
  - id: find-docs                                                          
    action: tool_call                                                      
    match: {tool: find_files, path: docs}                                  
    effect: approve                                                        
  - id: search-sources                                                     
    action: tool_call                                                      
    match: {tool: search_files, path: src}                                 
    effect: approve                                                        
  - id: search-docs                                                        
    action: tool_call                                                      
    match: {tool: search_files, path: docs}                                
    effect: approve                                                        

list-only examples/tools/list-only.yaml

# The model may list directories but every read is denied.
version: 1
default: deny
rules:
  - id: list-tree                                         
    action: tool_call                                     
    match: {tool: list_dir}                               
    effect: approve                                       

edit-sources examples/tools/edit-sources.yaml

# Read anywhere; edit existing files under src and tests after a prompt;
# create new files under tests without one. Policy files, hook
# configuration, .gitignore, and .git are never writable whatever is here.
# The .env and Cargo.lock rules name root paths; rules match a path prefix.
version: 1
default: deny
rules:
  - id: no-env                                                             
    action: tool_call                                                      
    match: {tool: read_file, path: .env}                                   
    effect: deny                                                           
  - id: read-tree                                                          
    action: tool_call                                                      
    match: {tool: read_file}                                               
    effect: approve                                                        
  - id: list-tree                                                          
    action: tool_call                                                      
    match: {tool: list_dir}                                                
    effect: approve                                                        
  - id: find-tree                                                          
    action: tool_call                                                      
    match: {tool: find_files}                                              
    effect: approve                                                        
  - id: search-tree                                                        
    action: tool_call                                                      
    match: {tool: search_files}                                            
    effect: approve                                                        
  - id: edit-sources                                                       
    action: file_write                                                     
    match: {tool: edit_file, path: src}                                    
    effect: approve                                                        
    ask: true                                                              
  - id: edit-tests                                                         
    action: file_write                                                     
    match: {tool: edit_file, path: tests}                                  
    effect: approve                                                        
    ask: true                                                              
  - id: new-tests                                                          
    action: file_write                                                     
    match: {tool: write_file, path: tests}                                 
    effect: approve                                                        
  - id: no-lockfile                                                        
    action: file_write                                                     
    match: {path: Cargo.lock}                                              
    effect: deny                                                           

commands examples/tools/commands.yaml

# Reads anywhere except the root .env; cargo check and test run without a
# prompt; any other cargo subcommand asks; cargo publish and cargo install
# are denied; any sh command whose working directory is scripts asks (an
# argv prefix cannot name a file, so `sh -c` is included). Commands run on
# the host with the hook runner's scrubbed environment plus the named
# toolchain variables.
version: 1
default: deny
rules:
  - id: no-env                                                            
    action: tool_call                                                     
    match: {tool: read_file, path: .env}                                  
    effect: deny                                                          
  - id: read-tree                                                         
    action: tool_call                                                     
    match: {tool: read_file}                                              
    effect: approve                                                       
  - id: list-tree                                                         
    action: tool_call                                                     
    match: {tool: list_dir}                                               
    effect: approve                                                       
  - id: find-tree                                                         
    action: tool_call                                                     
    match: {tool: find_files}                                             
    effect: approve                                                       
  - id: search-tree                                                       
    action: tool_call                                                     
    match: {tool: search_files}                                           
    effect: approve                                                       
  - id: cargo-check                                                       
    action: command                                                       
    match: {argv: [cargo, check]}                                         
    effect: approve                                                       
    toolchain_env: [CARGO_TARGET_DIR]                                     
  - id: cargo-test                                                        
    action: command                                                       
    match: {argv: [cargo, test]}                                          
    effect: approve                                                       
    toolchain_env: [CARGO_TARGET_DIR]                                     
  - id: cargo-other                                                       
    action: command                                                       
    match: {argv: [cargo]}                                                
    effect: approve                                                       
    ask: true                                                             
  - id: no-publish                                                        
    action: command                                                       
    match: {argv: [cargo, publish]}                                       
    effect: deny                                                          
  - id: no-install                                                        
    action: command                                                       
    match: {argv: [cargo, install]}                                       
    effect: deny                                                          
  - id: repo-scripts                                                      
    action: command                                                       
    match: {argv: [sh], path: scripts}                                    
    effect: approve                                                       
    ask: true                                                             

deny-all examples/tools/deny-all.yaml

# Valid policy with no approve rule: no tool is advertised to the model.
version: 1
default: deny
rules:
  - id: no-reads                                                        
    action: tool_call                                                   
    match: {tool: read_file}                                            
    effect: deny                                                        
  - id: no-lists                                                        
    action: tool_call                                                   
    match: {tool: list_dir}                                             
    effect: deny                                                        

Captured from ahi 0.14.1. Comments and the header stay plain; each rule is painted by its outcome, the same colours the chat screen uses for diffs.