Getting Started
What do I need before I can use ash?
You need the ash executable, an AI endpoint, and a model name. Running ash install auto-configures these: it uses an already-set cloud provider API key or a running local inference server when found, otherwise it shows a numbered provider menu and prompts for an API key, then lets you pick a model from the endpoint's model list. You can also set ASH_AI_ENDPOINT and ASH_AI_MODEL manually. A local endpoint such as Ollama can use http://localhost:11434, and a LAN host like http://brain.local:11434 or a private IP is also treated as local (unless ASH_STRICT=1); cloud endpoints must use HTTPS and usually require ASH_AI_AUTH_TOKEN. Shell integration is opt-in: you can always run ash "your question" directly.
Where does ash install, and how do I check that my shell can find it?
The verified installer places ash in ~/.local/bin/ash. Add that directory to your PATH using your shell's normal configuration; ash install does not edit shell startup files unless you pass --shell-integration. Open a new terminal, then run command -v ash to confirm. The self-updater installs its replacement binary to the same user-local location. The installer requires Sigstore cosign to verify the signed checksum manifest.
How do I use ash without changing my shell?
Pass a quoted prompt directly: ash "how do I find large files?". With no arguments, ash also accepts a non-interactive standard-input prompt, such as git diff | ash. Direct use is the least surprising option when you are learning ash or writing a script.
Why does ash say my AI configuration is incomplete?
Check that ASH_AI_ENDPOINT and ASH_AI_MODEL are non-empty in the environment where ash runs. For a cloud hostname, also set ASH_AI_AUTH_TOKEN when required by the provider. Run printf '%s\n' "$ASH_AI_ENDPOINT" "$ASH_AI_MODEL" to confirm the first two values are present, but do not print an authentication token into a terminal recording or shared log.
Installing and Updating
Does ash work on Windows 11?
Not natively. ash supports bash, zsh, and Fish on macOS, Linux, and FreeBSD; there is no PowerShell install target. Use WSL for the supported Linux experience.
How do I install ash in the Windows Subsystem for Linux (WSL)?
Follow the Linux installation instructions inside your WSL distribution, preferring its package manager. Then configure a provider and optionally enable Bash integration. There is no native Windows installer.
How do I update ash to the latest release version?
Use the owning package manager for Homebrew/APT/DNF/Pacman installs. ash update is only for stable Release installations under ~/.local/bin; it verifies the Sigstore-signed manifest and archive digest, and refuses a failed signature. Native .pkg and custom-directory installs need their original installer/manual replacement. See updates and channel subscriptions for Release, Beta, and Nightly.
I ran ash install. Why does nothing change in this terminal?
Shell integration is disabled by default. To enable it, run ash install --shell bash --shell-integration (or select zsh or fish); it does not rewrite the shell process already running. Open a new terminal or reload the selected startup file. Run ash install --shell bash --disable-shell-integration to remove Ash's managed block while preserving surrounding content.
Unknown commands still say “not found.” How do I troubleshoot shell integration?
First confirm you enabled shell integration with ash install --shell bash --shell-integration (substitute your shell), then run command -v ash; the hook cannot invoke a binary your shell cannot find. Reload or restart the shell and check that its startup file contains the >>> ash install >>> managed block. Finally run ash snooze off, because a snooze intentionally leaves unknown commands as normal “not found” failures.
What files does ash install change, and can I preview it?
It manages configuration under $XDG_CONFIG_HOME/ash (default ~/.config/ash), data under $XDG_DATA_HOME/ash (default ~/.local/share/ash), state under $XDG_STATE_HOME/ash (default ~/.local/state/ash), and cache under $XDG_CACHE_HOME/ash (default ~/.cache/ash). Startup files are changed only with --shell-integration. Use ash install --shell bash --shell-integration --dry-run to preview; dry-run does not write files. Re-running install is idempotent; use --overwrite only when you want managed bootstrap files refreshed.
Does ash support Fish?
Yes. Run ash install --shell fish --shell-integration to opt in. ash adds a managed block to $XDG_CONFIG_HOME/fish/config.fish, or ~/.config/fish/config.fish when XDG_CONFIG_HOME is unset. Fish uses fish_command_not_found, so an unresolved command reaches ash with its original arguments.
Why not lowercase test and type in Fish?
Fish reserves those lowercase names as essential builtins and does not allow a function to replace them. Use Test ... or Type ... to express ash intent, or invoke ash "..." directly. Other compatible collision wrappers remain available.
What about ksh93?
ksh93 is not supported for shell integration. Its FPATH behavior can only load a file named after an unknown command; it has no generic command-not-found callback that can safely implement ash prompt routing or broker lifecycle.
AI and Connections
Does ash include the AI?
No. ash is a client for an AI endpoint that you configure. Set ASH_AI_ENDPOINT and ASH_AI_MODEL; ash supports local Ollama and other local OpenAI-compatible servers (LM Studio, llama.cpp, MLX, LocalAI, vLLM, text-generation-webui, Jan, GPT4All), and detects supported cloud-provider adapters from the endpoint, with an optional ASH_AI_PROVIDER override.
What are MCP servers, and how do I add one?
MCP (Model Context Protocol) servers expose tools that an AI model can call, such as search, analysis, or service-specific actions. Remote servers are not enabled by default. To add a trusted Streamable HTTP MCP server, use ash mcp add <url> or add its URL on its own line in $XDG_CONFIG_HOME/ash/.ash_allow (default ~/.config/ash/.ash_allow). Ash connects through its broker and offers the server's tools to the model. Use only servers you trust: their tools may perform actions on your behalf. HTTPS is required except for localhost development servers. If MCP initialization fails, ash continues without remote MCP tools: it warns in interactive sessions and stays silent in non-interactive sessions.
Can scheduled jobs use MCP servers?
No. Scheduled and other non-interactive jobs do not inherit an interactive shell's broker, so remote MCP tools are unavailable. Ash still runs the prompt without MCP tools and suppresses this expected initialization failure. A prompt that relies on MCP may therefore finish without the requested data or action. Do not schedule prompts that require MCP.
Does MCP work when ASH_STRICT=1?
Yes. An HTTP(S) URL line explicitly registers an MCP server and is not treated as a shell executable. Strict mode does not disable configured MCP servers. It still applies Ash's untrusted-output protections to returned tool content.
How does MCP OAuth work, and where are credentials stored?
For an OAuth-protected server, Ash opens the authorization page in the desktop browser when a GUI is available; if it cannot open a browser, it prints a URL to authorize manually in a browser on the same host. Use ash mcp add <url> --no-browser to always use the terminal flow. For direct OAuth connections, discovery permits non-public IP addresses only for the exact registered MCP authority; other OAuth hosts remain subject to non-public-address blocking. A configured egress proxy is responsible for filtering its destination addresses. The broker handles the callback, token exchange, refresh, and persistent MCP session. Credentials are stored in the operating system credential manager when available. If it is unavailable, configure the encrypted-file fallback using a random 32-byte ASH_MCP_CREDENTIAL_KEY; Ash never stores the key itself.
Where can I find the AUTH_KEY for the most popular cloud AI providers?
ash uses ASH_AI_AUTH_TOKEN for its optional bearer token; it does not create or distribute provider keys. Create a key in your provider account, such as OpenAI, Anthropic, Google AI Studio, Azure OpenAI, Mistral, Cohere, Groq, xAI, DeepSeek, Together AI, OpenRouter, HuggingFace, or Ollama, then export it as the provider's environment variable (or set ASH_AI_AUTH_TOKEN directly). ash install auto-detects supported provider-specific environment variables. Cloud endpoints must use HTTPS and require a token except AWS Bedrock; private/LAN addresses and .local hostnames are treated as local unless ASH_STRICT=1 is set.
Does ash open a new connection each time?
Not for normal interactive Unix shell use. Bash, zsh, and Fish start one broker per shell session, communicate with it through a private Unix socket, and reuse its bounded HTTP connection pool. The broker exits after inactivity; scheduled jobs use direct requests rather than a persistent shell broker.
Does Fish use the broker?
Yes. The Fish wrapper starts and reuses the same per-session broker as bash and zsh, refreshes its lease immediately before an ash request, and keeps broker setup quiet.
What happens if a request is slow, unavailable, or I change my mind?
Press Ctrl-C to cancel an in-flight request. The default AI request timeout is three minutes; set ASH_AI_TIMEOUT, for example ASH_AI_TIMEOUT=90s, to change it. ash retries retryable AI failures up to three times by default with a short bounded backoff; tune that behavior with ASH_RETRY_MAX_ATTEMPTS, ASH_RETRY_BASE_DELAY, and ASH_RETRY_MAX_DELAY.
Safety and Control
How do I lock down ash to be safer, and what are the implications?
Keep the executable allowlist narrow, favor read-only tools, and do not add privileged or destructive commands. Set ASH_STRICT=1 to block recognized prompt-injection patterns from untrusted tool, file, script, pipeline, and child-agent output. This can also hide legitimate text that resembles an injection attempt. The allowlist is an execution boundary, not a sandbox: ash and permitted tools still run as you.
Can ash run destructive commands like rm?
Not with the installed default allowlist. It explicitly advises against rm, mv, dd, chmod, chown, kill, and sudo. If you add one of them, ash can request it with your permissions; review that decision carefully.
How do I change the commands ash is allowed to execute?
Edit $XDG_CONFIG_HOME/ash/.ash_allow (default ~/.config/ash/.ash_allow) and list bare executable names, one per line or comma-separated. Its standalone $TOOLS_DIR_LIST and $PLUGINS_DIR_LIST directives permit eligible managed scripts and native plugins; replace them with literal names for a restrictive policy. Eligible scripts and plugins are regular executable files under $XDG_DATA_HOME/ash/tools and $XDG_DATA_HOME/ash/plugins (default base ~/.local/share/ash). Add denied commands to $XDG_CONFIG_HOME/ash/.ash_deny, or set ASH_ALLOW / ASH_DENY to comma-separated lists. Changes are read on the next ash request.
What user is ash running under?
ash and every allowed tool run as the user who starts ash. It does not elevate privileges. Ash-managed XDG directories and files use restrictive permissions, but their contents remain accessible to your user and to any process you explicitly allow.
Does ash trust text received via pipe the same as user text? What protections exist for malicious data?
Yes. When ash receives no command-line arguments and standard input is piped, it treats that input as the user prompt. Do not pipe untrusted web pages, logs, or generated text directly to ash unless you intend to authorize it as a prompt. This differs from ash-managed tool, file, script, pipeline, and child-agent output: ash labels those results as untrusted evidence and instructs the model never to follow instructions from them. Set ASH_STRICT=1 to additionally replace recognized prompt-injection phrases in untrusted evidence. The allowlist and direct-argv execution rules still apply to tool execution.
Are my ash files private from other users on this computer?
Ash-managed XDG directories and files use restrictive owner-only permissions where supported. This protects against other local accounts under normal Unix permissions, but not against your own account, administrators, backups, or software you choose to run with access to your home directory.
Tools and Workflow
Does ash support pipes and other Unix traditions?
Yes. You can pipe text into ash as a prompt, for example git diff | ash. For AI-requested tool pipelines, ash supports two to sixteen allowlisted executables connected directly without a shell, such as ls | grep pattern | pbcopy. Shell-control patterns in tool arguments are blocked, and every executable in an ash-managed pipeline must be allowlisted.
Will ash reinterpret commands inside my shell scripts, SSH commands, or cron jobs?
No. The Bash and zsh integration wrappers return immediately in non-interactive shells, so scripts, CI jobs, SSH one-liners, and cron commands keep normal command-not-found behavior. Use an explicit invocation such as ash "summarize this log" or some-command | ash when automation should call ash.
How do I stop ash from interpreting my commands for a few minutes?
Run ash snooze for the default five minutes, or specify a duration such as ash snooze 30s or ash snooze 1h. Run ash snooze off to resume immediately. Snooze pauses automatic command-not-found and wrapper routing; explicit ash ... commands still work.
How can I debug ash and see more information about what it is doing?
Set ASH_VERBOSE=1 before running ash to enable structured debug output and a terminal execution dashboard. Set ASH_LOG_FILE to write debug JSON to a file; ASH_LOG_MAX_BYTES controls rotation and defaults to 1 MiB when a log file is configured.
What limits apply when ash runs tools?
By default, each tool call has a 15-second timeout and captures up to 8192 bytes of output. An AI request may make up to 16 tool-loop iterations, and an ash-managed pipeline has two to sixteen stages. Adjust the tool timeout and output limit with ASH_TOOL_TIMEOUT and ASH_TOOL_OUTPUT_MAX; keep output focused with commands such as head, tail, or grep.
Where is the default system prompt?
The canonical prompt file is $XDG_CONFIG_HOME/ash/.ash_system (default ~/.config/ash/.ash_system), installed from the bundled default when you run ash install. Existing files under the old ~/.ash workspace are not automatically migrated or read. Ordinary $VARIABLE values are expanded from the environment, but $TOOLS_DIR_LIST, $PLUGINS_DIR_LIST, and $IF_PYTHON_AVAILABLE are reserved internal Ash substitutions and never environment-derived.
Where do I put my own scripts and native plugins for ash to call as tools?
Put user Python scripts in $XDG_DATA_HOME/ash/tools/ and native binary plugins in $XDG_DATA_HOME/ash/plugins/ (default base ~/.local/share/ash). Ensure they are executable, and add the bare executable name to $XDG_CONFIG_HOME/ash/.ash_allow (or rely on $TOOLS_DIR_LIST / $PLUGINS_DIR_LIST). Ash does not invoke a shell for allowed Unix commands and plugins.
What are best practices for a tool or plugin so the AI understands its purpose and use?
Follow the native plugin contract: expose predictable CLI options, implement --help, --version, and versioned JSON --ai-docs metadata, and describe input/output schemas and failure behavior. Emit compact structured JSON with a status field and actionable error details instead of prose mixed with data. Keep output bounded, validate inputs, set network timeouts, and make the tool safe to call repeatedly. Add its bare filename to $XDG_CONFIG_HOME/ash/.ash_allow; ash can execute it only when it is allowlisted and not listed in $XDG_CONFIG_HOME/ash/.ash_deny.
What are the provided tool scripts and native plugins?
The installed bootstrap Python scripts are headlines.py, wikipedia.py, and yfinance.py in $XDG_DATA_HOME/ash/tools/. The provided native plugins are what_time_is_it (Go) and calculator (TypeScript) in $XDG_DATA_HOME/ash/plugins/. Linux and FreeBSD also bundle flip_a_coin (Rust); macOS builds exclude Rust plugins.
Why is the Rust plugin missing on macOS, and how can I install it manually?
macOS builds omit Rust plugins, including flip_a_coin, so both macOS architectures can be cross-compiled on Linux without macOS CI runners. This reduces release CI costs; it is not a macOS compatibility restriction. Homebrew still installs ash with the Go and TypeScript plugins, and Linux and FreeBSD releases still include the Rust plugin.
On your Mac, install Apple's Xcode Command Line Tools (xcode-select --install, if needed) and Rust via rustup. Then run the following in a directory where you want a new source checkout. The repository pins the Rust toolchain, and the plugin's own Makefile builds for your Mac's native architecture and installs directly into Ash's user plugin directory; no sudo is needed.
git clone https://github.com/Jonconradt/ash.git
cd ash
rustup toolchain install 1.99.0 --profile minimal
plugin_dir="${XDG_DATA_HOME:-$HOME/.local/share}/ash/plugins"
make -C internal/app/ash_bootstrap/plugins_src/flip_a_coin build BUILD_DIR="$plugin_dir"
"$plugin_dir/flip_a_coin" --version
"$plugin_dir/flip_a_coin" --ai-docs
Use the plugin's own Makefile, not the top-level make plugins-build, which deliberately skips Rust on macOS. To let the AI call it, keep $PLUGINS_DIR_LIST in ${XDG_CONFIG_HOME:-$HOME/.config}/ash/.ash_allow or add the bare name flip_a_coin there. It must not be listed in .ash_deny. Start a new ash invocation to discover it. You can also run "$plugin_dir/flip_a_coin" directly to verify a coin toss without an AI provider.
Can ash call sub-agents?
Yes. A parent agent can use run_sub_agent for one focused, independent task. A child inherits the working directory, configuration, tools, and OS permissions, returns a bounded result, and cannot create another child. The default maximum is six sub-agents per parent run and can be changed with ASH_MAX_AGENTS.
Can ash generate memory files to track complex tasks and what it has learned in the session?
Yes. It can write persistent workspace files under $XDG_CONFIG_HOME/ash (default ~/.config/ash), which are tracked in its workspace inventory, and session-scoped scratch files under $XDG_STATE_HOME/ash/scratch/<session-id>/ (default base ~/.local/state/ash). Scratch is optional: use it for reusable scripts, intermediate data, accumulated findings, or revisable artifacts when they add value. Its tools are read_scratch_file, write_scratch_file, append_scratch_file, replace_scratch_file, edit_scratch_file, and list_scratch_files. Active Ash and broker processes protect their session with an OS lock. Unlocked directories are cleaned up on Ash exit only after they are older than 48 hours and have not been accessed in 24 hours; crash-leftover lock files do not block later cleanup. Use persistent workspace files for information you intend to keep.
Can ash schedule work for later?
Yes, through its AI tools. On macOS, one-off scheduling uses a per-user launchd LaunchAgent and requires launchctl. On Linux, recurring schedules are supported through your user crontab; ash manages only its own marked entries. The one-off launchd scheduler is not available on Linux, so use a cron entry or another Linux scheduler for a one-time Linux job. Scheduled runs receive a limited environment and use direct HTTPS rather than an interactive shell broker, so ensure the required AI configuration is available to the scheduled job. They cannot use remote MCP tools; Ash runs without them and does not warn in non-interactive sessions. Do not schedule prompts that require MCP.
Sessions and Storage
Where are the history or log files for ash?
Conversation history is stored as JSON under $XDG_STATE_HOME/ash/history/ (default ~/.local/state/ash/history/). Scheduled history and debug logs are stored under that same state directory. You can choose another debug-log path with ASH_LOG_FILE.
How long are history files retained?
ash removes history JSON files older than 14 days during normal application cleanup, with a 300 ms cleanup budget so exit is not delayed. The recent-message window is separate: it keeps up to 40 messages per conversation by default and can be changed with ASH_HISTORY_MAX.
How do I clear a conversation or start fresh?
History is separated by session ID and AI endpoint/model key. Start a new terminal session for a new session ID, or remove the relevant JSON file under $XDG_STATE_HOME/ash/history/ (default ~/.local/state/ash/history/) when you intentionally want to discard that local conversation history. Removing a history file does not revoke a provider key or delete provider-side data; manage those separately with the provider.
What is ASH_SESSION_ID and where is it generated?
It is the Ash-owned per-session identifier used to separate history, scratch space, broker sockets, and scheduled log names. The managed shell environment creates one when the shell starts and preserves it when re-sourced; Ash creates one for invocations without a shell-provided value. A generic SESSION_ID is ignored.
Can I provide my own ASH_SESSION_ID?
Yes. Ash validates explicit IDs and rejects invalid values rather than silently replacing them. Valid IDs are at most 128 characters and use letters, digits, underscores, hyphens, with one optional child-session dot suffix. Do not use untrusted or shared values: collisions combine session history and runtime state.
Support and Community
How do I file a bug?
Open an issue at github.com/Jonconradt/ash/issues with the ash version or commit, your operating system and shell, the configuration relevant to the problem with secrets removed, reproducible steps, and the observed result. For a security vulnerability, do not open a public issue; report it privately by email or GitHub security advisory.
Is there a discussion board in the ash project?
Yes. Use GitHub Discussions for questions and ideas, and GitHub Issues for reproducible bugs and tracked work.