LLM-powered shell agent — a ZSH extension for coding, debugging, and shell assistance
Project description
friday
LLM-powered shell agent that lives in your ZSH terminal.
friday:auto(glm-5-turbo)> explain why this test is failing
Friday is a conversational AI assistant with coding, debugging, and documentation modes. It routes tasks to specialized sub-agents, remembers context across sessions, and integrates with your shell workflow via keybindings and completions.
Quick Start
Install with uvx (no clone needed)
uvx --from git+https://github.com/oornnery/friday-sh friday chat
Install with uv tool (global)
uv tool install git+https://github.com/oornnery/friday-sh
friday chat
Install from source
git clone https://github.com/oornnery/friday-sh.git
cd friday
uv sync --group dev --group test
Set up API keys
cp .env.example .env
# Edit .env with at least one provider key
# Anthropic
ANTHROPIC_API_KEY=
# OpenAI
OPENAI_API_KEY=
# Mistral
MISTRAL_API_KEY=
# Z.AI (ZhipuAI / GLM)
ZAI_API_KEY=
ZAI_BASE_URL=https://api.z.ai/api/coding/paas/v4
ZSH plugin
Source the plugin in your .zshrc:
source /path/to/friday/src/friday/shell/friday.plugin.zsh
Now use f from anywhere in your shell:
f "why did my last command fail?"
f "how do I use find to delete tmp files?"
Requirements
- Python 3.13+
- uv
- At least one LLM provider key (or local Ollama)
Usage
CLI
# Ask a single question (uses router agent by default)
friday ask "explain this error"
# Pipe input
cat error.log | friday ask "what went wrong?"
git diff | friday ask "review this"
# Force a specific mode
friday ask --mode debug "why is pytest failing?"
friday ask --mode reader "explain the router module"
# Use a specific model
friday ask --model mistral:codestral-latest "refactor this function"
# Interactive chat
friday chat
friday chat --mode code --model zai:glm-5-turbo
REPL
The chat REPL has a styled prompt showing mode and model:
friday:auto(glm-5-turbo)> hello
friday:code(codestral-latest)> fix the failing test
friday:debug(glm-5-turbo)[debug]> /mode show
Commands:
/model Interactive model picker (or /model show | /model <name>)
/mode Interactive mode picker (or /mode show | /mode <name>)
/session Resume session picker (or /session show | resume | new | delete)
/setting Show settings (or /setting <key> | /setting <key>=<value>)
/memory List memories (or /memory show | search | add | delete)
/debug Toggle debug (or /debug on | off | show)
/clear Clear conversation
/quit Exit Friday
Type @ to trigger file completion, / for command completion.
The /model and /mode pickers support search -- type to filter:
Select model (3/87)
/ glm
zai:glm-4.5
> zai:glm-5-turbo (active)
zai:glm-5.1
ZSH Keybindings
| Key | Action |
|---|---|
f "question" |
Ask Friday from anywhere |
Ctrl+F |
Ask about current buffer / last command |
Ctrl+G |
Fuzzy session picker (requires fzf) |
friday-select-model |
Interactive model picker with fzf |
Resource Commands (CLI)
friday model show # List all models from providers
friday model set # Interactive picker
friday mode show # List modes
friday session show # List saved sessions
friday session resume <id> # Resume session
friday setting show # Show all settings
friday memory show # List shared memories
friday memory add "user prefers concise answers"
friday memory search "preferences"
Architecture
+-------------------+
| ZSH Shell |
| f "question" |
| Ctrl+F / Ctrl+G |
+---------+---------+
|
+---------v---------+
| friday CLI |
| ask | chat |
+---------+---------+
|
+---------------v---------------+
| Router Agent |
| (auto mode -- conversational)|
+--+--------+--------+--------+-+
| | | |
+--------v--+ +---v----+ +-v------+ +--v-------+
| Code Agent| | Reader | | Writer | | Debug |
| read,write| | read | | read, | | read, |
| patch, | | list, | | write, | | list, |
| shell, | | search | | list, | | search, |
| search | | | | search | | shell |
+-----------+ +--------+ +--------+ +----------+
| | | |
+--v--------v--------v--------v--+
| Tool Layer |
| filesystem | shell | memory |
+---------------+----------------+
|
+---------------v---------------+
| Infrastructure |
| config | sessions | memory.db |
| MCP servers | model providers |
+-------------------------------+
Agent Modes
| Mode | Purpose | Tools |
|---|---|---|
| auto | Routes to the right specialist | delegation only |
| code | Write, edit, test code | read, write, patch, list, search, shell |
| reader | Analyze and explain code | read, list, search |
| write | Generate docs and text | read, write, list, search |
| debug | Diagnose errors and bugs | read, list, search, shell |
Each mode is defined in src/friday/agent/prompts/<mode>.md with YAML
frontmatter specifying tools, max steps, model override, and thinking.
Approval System
Risky tools (write_file, patch_file, run_shell) require user
confirmation before executing:
+-- Confirm ----------------------+
| run_shell: Execute shell command |
| |
| rm -rf node_modules && npm i |
+----------------------------------+
Allow? [y/N]
Configurable via approval_policy:
- ask (default) -- prompt for each risky action
- auto -- execute without asking
- never -- always deny
Memory System
Friday has three layers of memory:
+---------------------------+
| Shared Memory (SQLite) | <-- cross-session, searchable
| profile, preferences, | agent saves via save_memory
| notes, decisions |
+---------------------------+
| Working Memory | <-- per-session, short-term
| task, files, notes, | auto-managed by harness
| entities, decisions |
+---------------------------+
| Message History | <-- per-session transcript
| pydantic-ai messages | trimmed by history processor
+---------------------------+
The agent decides what to save to shared memory via the save_memory
tool. The harness indexes chat turns for cross-session search.
Supported Providers
| Prefix | Provider | Auth |
|---|---|---|
anthropic: |
Anthropic (Claude) | ANTHROPIC_API_KEY |
openai: |
OpenAI (GPT) | OPENAI_API_KEY |
mistral: |
Mistral AI | MISTRAL_API_KEY |
zai: |
Z.AI (GLM) | ZAI_API_KEY |
ollama: |
Ollama (local) | no key needed |
Model fallback: if the default model fails (missing key), Friday
automatically tries fallback_model from config.
MCP Integration
Friday supports Model Context Protocol
servers. Configure in ~/.config/friday/config.toml:
[[mcp_servers]]
name = "github"
transport = "http"
url = "http://localhost:3000/mcp"
[[mcp_servers]]
name = "filesystem"
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
Configuration
Friday reads config from (in priority order):
- Environment variables (
FRIDAY_*prefix) .envfile~/.config/friday/config.tomlorfriday.toml
Settings
| Key | Default | Description |
|---|---|---|
default_model |
zai:glm-5-turbo |
Default LLM |
fallback_model |
mistral:devstral-latest |
Fallback if default fails |
default_mode |
auto |
Default agent mode |
approval_policy |
ask |
Risky tool confirmation |
max_steps |
25 |
Max tool calls per turn |
session_dir |
~/.local/share/friday/sessions |
Session storage |
config_dir |
~/.config/friday |
Config directory |
memory_db_path |
memory.db |
SQLite memory database |
memory_top_k |
6 |
Memory results per turn |
Runtime override in chat: /setting default_model=mistral:codestral-latest
Project Structure
src/friday/
|-- __init__.py # package version
|-- __main__.py # python -m friday
|
|-- agent/ # core AI runtime
| |-- core.py # agent factory, execution loop, approval flow
| |-- router.py # delegation tools (delegate_code, etc.)
| |-- memory.py # shared memory retrieval + chat indexing
| |-- context.py # workspace snapshot (git, env, shell state)
| |-- contracts.py # AgentReply, RouterDecision, TurnOutput
| |-- deps.py # AgentDeps injected into tools
| |-- modes.py # mode config loader (YAML frontmatter)
| |-- history.py # history trimming (pair-safe, dedup)
| |-- stats.py # token/cost tracking per turn
| `-- prompts/ # system prompts per mode
| |-- router.md # auto mode -- conversational router
| |-- code.md # code mode -- full access
| |-- reader.md # reader mode -- read-only
| |-- writer.md # writer mode -- docs generation
| `-- debug.md # debug mode -- error diagnosis
|
|-- cli/ # terminal interface
| |-- app.py # typer entrypoint + all CLI commands
| |-- chat.py # interactive REPL loop
| |-- ask.py # single-shot ask
| |-- catalog.py # command registry (REPL + CLI)
| |-- completer.py # / commands + @ file completion
| |-- picker.py # interactive list picker with search
| |-- confirm.py # approval dialogs for risky tools
| |-- models.py # dynamic model listing from providers
| |-- resources.py # interactive pickers for model/mode/session
| |-- output.py # rich console, markdown rendering
| |-- theme.py # unified color palette
| `-- debug.py # debug mode logging
|
|-- domain/ # pure business logic (no IO)
| |-- models.py # AgentMode, WorkingMemory, MemoryKind
| |-- validation.py # input limits (path, command, content)
| `-- permissions.py # safe_path, contains_secret, clip
|
|-- infra/ # IO boundary
| |-- config.py # FridaySettings (pydantic-settings)
| |-- sessions.py # JSON session store
| |-- memory.py # SQLite + FTS5 shared memory
| `-- mcp.py # MCP server factory
|
|-- tools/ # pydantic-ai tool implementations
| |-- filesystem.py # read, write, patch, list, search
| |-- shell.py # run_shell with validation
| |-- memory.py # search_memory, save_memory, list_memories
| `-- registry.py # tool metadata
|
`-- shell/
`-- friday.plugin.zsh # ZSH integration (f, Ctrl+F, Ctrl+G)
Development
# Setup
git clone https://github.com/oornnery/friday-sh.git
cd friday
uv sync --group dev --group test
# Run all checks (format + lint + typecheck + test)
uv run task check
# Individual tasks
uv run task format # ruff format
uv run task lint # ruff check --fix
uv run task typecheck # ty check
uv run task test # pytest -v
# Run a single test
uv run pytest tests/test_security.py::TestContainsSecret -v
# Run friday locally
uv run friday chat
uv run friday ask "hello"
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file friday_sh-0.1.0.tar.gz.
File metadata
- Download URL: friday_sh-0.1.0.tar.gz
- Upload date:
- Size: 208.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5127d09eabf901b7023c2922d908aba5a043f8b3c42118699ce1c7025a62a28a
|
|
| MD5 |
0bc36af40ce1d31a5fb7a7b628014b08
|
|
| BLAKE2b-256 |
407f6b9f1e22a89eb328a1a5fc9ab044454d4eca1ecc4d71cffae2e708c8ff43
|
Provenance
The following attestation bundles were made for friday_sh-0.1.0.tar.gz:
Publisher:
release.yml on oornnery/friday-sh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
friday_sh-0.1.0.tar.gz -
Subject digest:
5127d09eabf901b7023c2922d908aba5a043f8b3c42118699ce1c7025a62a28a - Sigstore transparency entry: 1265353555
- Sigstore integration time:
-
Permalink:
oornnery/friday-sh@502f87b2059579dd4b6557eb6d386ec43cc4bed2 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/oornnery
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@502f87b2059579dd4b6557eb6d386ec43cc4bed2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file friday_sh-0.1.0-py3-none-any.whl.
File metadata
- Download URL: friday_sh-0.1.0-py3-none-any.whl
- Upload date:
- Size: 64.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4447258a0a8b4f6035b971853eabcc674ad7e50ba2921c975276b31776f2b625
|
|
| MD5 |
66b1e2a8ff2571d248f0423ea27e4d8b
|
|
| BLAKE2b-256 |
16cd7d330445dc8578407920090fb51c9e44aab871e5628683c4b65aa8687645
|
Provenance
The following attestation bundles were made for friday_sh-0.1.0-py3-none-any.whl:
Publisher:
release.yml on oornnery/friday-sh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
friday_sh-0.1.0-py3-none-any.whl -
Subject digest:
4447258a0a8b4f6035b971853eabcc674ad7e50ba2921c975276b31776f2b625 - Sigstore transparency entry: 1265353693
- Sigstore integration time:
-
Permalink:
oornnery/friday-sh@502f87b2059579dd4b6557eb6d386ec43cc4bed2 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/oornnery
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@502f87b2059579dd4b6557eb6d386ec43cc4bed2 -
Trigger Event:
push
-
Statement type: