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 AI_ENDPOINT and AI_MODEL manually. A local endpoint such as Ollama can use http://localhost:11434; cloud endpoints must use HTTPS and also require AI_AUTH_TOKEN. Shell integration is optional: 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, and ash install adds that directory to your PATH through the managed ~/.ash/.ash_env file. Open a new terminal, then run command -v ash to confirm. The self-updater installs its replacement binary to the same ~/.local/bin/ash location.
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 AI_ENDPOINT and AI_MODEL are non-empty in the environment where ash runs. For a cloud hostname, also set AI_AUTH_TOKEN. Run printf '%s\n' "$AI_ENDPOINT" "$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 as a currently released, fully supported platform. ash has a PowerShell 7 install target, but Windows release packaging is disabled and ash update intentionally rejects Windows. Use WSL for the supported Linux experience.
How do I install ash in the Windows Subsystem for Linux (WSL)?
Install it inside your WSL distribution as Linux: curl -fsSL https://jonconradt.github.io/ash/install.sh | sh. Then configure AI_ENDPOINT and AI_MODEL, and run ash install for the shell running inside WSL. This is separate from any Windows PowerShell configuration.
How do I update ash to the latest release version?
Run ash update on macOS, Linux, or FreeBSD. It downloads the latest stable matching archive, verifies the release manifest with its Sigstore bundle and SHA-256 digest, then installs to ~/.local/bin/ash. Use ash update --version vX.Y.Z for a specific version; use --yes only when you want customized managed files replaced.
I ran ash install. Why does nothing change in this terminal?
Installation updates a startup file; it does not rewrite the shell process already running. Open a new terminal, or reload the file for your shell: source ~/.bashrc for Bash, source ~/.zshrc for zsh, or source ~/.config/fish/config.fish for Fish unless you use a custom XDG_CONFIG_HOME.
Unknown commands still say “not found.” How do I troubleshoot shell integration?
First run command -v ash; the wrapper cannot invoke a binary your shell cannot find. Then 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 adds or updates one marked ash block in the selected shell startup file and manages files under ~/.ash, including configuration, wrappers, and bundled tools. Run ash install --shell bash --dry-run to preview the startup-file change without writing it. 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. 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 AI_ENDPOINT and 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 AI_PROVIDER override.
Where can I find the AUTH_KEY for the most popular cloud AI providers?
ash calls this value AI_AUTH_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 AI_AUTH_TOKEN directly). ash install auto-detects most of these provider-specific environment variables. Cloud endpoints must use HTTPS and require a token.
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 AI_TIMEOUT, for example 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 ~/.ash/.ash_tools and list bare executable names, one per line or comma-separated. Its standalone $TOOLS_DIR_LIST directive permits eligible managed scripts; replace it with literal names for a restrictive policy. Eligible scripts are regular files in ~/.ash/tools/ with read and execute bits. Alternatively set ASH_TOOL_ALLOWLIST to a comma-separated list; it overrides the file for that invocation. 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. The managed ~/.ash workspace is permission-hardened, but its 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?
During installation, ash hardens the ~/.ash directory to owner-only permissions and managed files to owner-readable and owner-writable permissions. 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 ~/.ash/.ash_system, installed from the bundled default when you run ash install. ash reads that file first. If it is absent, ash falls back to .ash_system in the current working directory and then ~/.ash_system. Ordinary $VARIABLE values are expanded from the environment, but $TOOLS_DIR_LIST and $IF_PYTHON_AVAILABLE are reserved internal Ash substitutions and never environment-derived.
Where do I put my own scripts for ash to call as tools?
Put them in ~/.ash/tools/. Add the script's bare executable name to ~/.ash/.ash_tools, ensure it is executable, and keep its interface suitable for direct argv calls. ash does not invoke a shell for allowed Unix commands.
What are best practices for a Python tool in ~/.ash/tools so the AI understands its purpose and use?
Follow the bundled-tool pattern: use a descriptive filename and #!/usr/bin/env python3 shebang; expose predictable named options with argparse; and implement an --ai-docs option that explains capabilities, every argument and default, output schema, failure states, and when the AI should use the tool. 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, handle expected failures, and make the tool safe to call repeatedly. Add its bare filename to ~/.ash/.ash_tools; ash can execute it only when it is allowlisted.
What are the provided tool scripts and where can I find their code in the repository?
The installed bootstrap scripts are headlines.py, wikipedia.py, and yfinance.py. Their source lives in ash_bootstrap/tools and is installed into ~/.ash/tools/.
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 ~/.ash, which are tracked in ~/.ash/inventory.md, and session-scoped scratch files under ~/.ash/scratch/<session-id>/. Use persistent workspace files for information you intend to keep; use scratch files for temporary plans, notes, and helper artifacts.
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.
Sessions and Storage
Where are the history or log files for ash?
Conversation history is stored as JSON in ~/.ash/history/<SESSION_ID>.json; scheduled runs use task_<SESSION_ID>.json. When scheduled debug logging is enabled, its default log location is ~/.ash/logs/task_<SESSION_ID>.log. 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 ~/.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 the SESSION_ID and where is it generated?
It is the per-session identifier used to separate history, scratch space, broker sockets, and scheduled log names. The managed shell environment generates a random 16-character alphanumeric value from /dev/urandom when the shell starts; ash also creates one when an interactive invocation has no value.
Can I replace the implementation of the SESSION_ID generator?
You can supply your own SESSION_ID before starting ash or customize your local managed environment file, but ash validates it. 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.