@contextmanager
def Live(start, **kw):
print(start)
def update(s, refresh=False): clear_output(True);print(s)
yield NS(update=update)Core
Imports
CodeBlock.__rich_console__
def __rich_console__(
console, options
):
Chat
def Chat(
arg:VAR_POSITIONAL, kw:VAR_KEYWORD
):
Lazy load lisette to make ssage more responsive
Jupyter does work with rich.live.Live, this fixes it.
def print_md(md_stream):
"Print streamed markdown"
with Live(Spinner("dots", text="Connecting..."), auto_refresh=False) as live:
for part in md_stream: live.update(Markdown(part), refresh=True)Model Setup
System Environment
# aliases = _aliases('bash')
# print(aliases)# print(_sys_info())Tmux
get_pane
def get_pane(
n, pid:NoneType=None
):
Get output from a tmux pane
# p = get_pane(20)
# print(p[:512])get_panes
def get_panes(
n
):
# ps = get_panes(20)
# print(ps[:512])co(['tmux', 'display-message', '-p', '#{history-limit}'], text=True).strip()'2000'
tmux_history_lim
def tmux_history_lim(
):
tmux_history_lim()2000
get_history
def get_history(
n, pid:str='current'
):
Options and ShellSage
get_opts
def get_opts(
opts:VAR_KEYWORD
):
opts = get_opts(model=None, log=None, api_base=None, api_key=''); opts{'provider': 'anthropic', 'model': 'claude-opus-4-5', 'think': 'l', 'search': 'l', 'trust': 'view,rg', 'history_lines': '1000', 'code_theme': 'xcode', 'code_lexer': 'python', 'log': 'True', 'safecmd': 'True'}
{'api_base': '', 'api_key': '', 'log': True, 'model': 'claude-opus-4-5'}with_permission
def with_permission(
action_desc
):
print(tools[1]('.'))Directory contents of /Users/jhoward/aai-ws/shell_sage/nbs: /Users/jhoward/aai-ws/shell_sage/nbs/00_core.ipynb /Users/jhoward/aai-ws/shell_sage/nbs/_quarto.yml /Users/jhoward/aai-ws/shell_sage/nbs/sidebar.yml /Users/jhoward/aai-ws/shell_sage/nbs/styles.css /Users/jhoward/aai-ws/shell_sage/nbs/CNAME /Users/jhoward/aai-ws/shell_sage/nbs/01_config.ipynb /Users/jhoward/aai-ws/shell_sage/nbs/nbdev.yml /Users/jhoward/aai-ws/shell_sage/nbs/index.ipynb
get_sage
def get_sage(
model, mode:str='default', search:bool=False, use_safecmd:bool=False
):
# m = 'ollama_chat/qwen3:8b'
# ssage = get_sage(m)
# ssage('Howdy!')m = 'claude-sonnet-4-5'
ssage = get_sage(m, search='l')
ssage('Hi, how are ya?', think='l')Hey there! I’m doing well, thanks for asking. Ready to help you navigate the command line, troubleshoot shell issues, or dive into any system administration questions you’ve got. What can I help you with today?
- id:
chatcmpl-96ad87f4-6fd0-4088-a6d6-6bfa0ad36097 - model:
claude-sonnet-4-5-20250929 - finish_reason:
stop - usage:
Usage(completion_tokens=108, prompt_tokens=3387, total_tokens=3495, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=48, rejected_prediction_tokens=None, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=0, text_tokens=None, image_tokens=None, cache_creation_tokens=0, cache_creation_token_details=CacheCreationTokenDetails(ephemeral_5m_input_tokens=0, ephemeral_1h_input_tokens=0)), cache_creation_input_tokens=0, cache_read_input_tokens=0)
get_res
def get_res(
sage, q, opts
):
opts=NS(api_base='', api_key='', think='l')
list(get_res(ssage, 'Use tools to check if we have a .git in the current directory. Respond with yes/no', opts))['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'No', 'No']
print_md(get_res(ssage, 'Hi!', opts))Hey! What's up? Need help with something?
print_md(get_res(ssage, 'Please use your view command to see what files are in the current directory. Only respond with a single paragraph', opts))You're in the /Users/jhoward/aai-ws/shell_sage/nbs directory which contains several Jupyter notebooks
(00_core.ipynb, 01_config.ipynb, index.ipynb), configuration files for Quarto and nbdev (_quarto.yml, nbdev.yml,
sidebar.yml), a styles.css file, and a CNAME file, suggesting this is an nbdev project setup for documentation
generation with Quarto.
print_md(get_res(ssage, 'Please search the web for interesting facts about Linux. Only respond with a single paragraph.', opts));Linux has a fascinating history and impact on computing: created by Linus Torvalds in 1991 as a hobby project when he was just a 21-year-old student, it's now the backbone of the internet with over 96% of the world's top web servers running on it, powers Android devices (making it the most widely used OS on the planet), operates the International Space Station's computers, runs most supercomputers globally, and is completely open-source with thousands of developers contributing to its kernel—all while Torvalds still oversees development today, and the penguin mascot "Tux" was named after Torvalds' (T)orvalds (U)ni(X), though the actual inspiration came from a photo of a penguin that supposedly bit him at an Australian zoo.
Logging
mk_db
def mk_db(
):
Log
def Log(
args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):
Initialize self. See help(type(self)) for accurate signature.
# db = mk_db()
# log = db.logs.insert(Log(timestamp=datetime.now().isoformat(), query='Hi, who are you?', model='llama3.2',
# response='I am ShellSage, a command-line teaching assistant!', mode='default'))
# logMain
main
def main(
query:str <The query to send to the LLM>, v:<Print version>='%(prog)s 1.0.5',
pid:str='current', # `current`, `all` or tmux pane_id (e.g. %0) for context
skip_system:bool=False, # Whether to skip system information in the AI's context
history_lines:int=None, # Number of history lines. Defaults to tmux scrollback history length
mode:str='default', # Available ShellSage modes: ['default', 'sassy']
model:str=None, # The LLM model that will be invoked on the LLM provider
search:str=None, # Wheather to allow the LLM to search the internet
api_base:str=None, api_key:str=None,
think:str=None, # Reasoning effort level: 'l', 'm', 'h' (for supported models)
trust:str=None, # Comma-delimited list of tools to always allow (e.g. "view,rg")
code_theme:str=None, # The code theme to use when rendering ShellSage's responses
code_lexer:str=None, # The lexer to use for inline code markdown blocks
):
main(['Do you have a `bash` tool?.'], history_lines=0)Yes, I have a bash tool that can run shell commands safely. It supports most standard unix commands, git operations, pipes, and shell operators. However, it has an allow-list of safe commands and blocks output file redirection (>) to prevent accidental overwrites.
r = f'''
Hello, user! Here are some code blocks:
```python
for i in range(10): print(i)
```
```
This doesn't even have a language definition!
```
```bash
ls **/*
```
'''db = mk_db()
db.logs.insert(Log(timestamp=datetime.now().isoformat(), query='', response=r, model='', mode=''))Log(id=1, timestamp='2025-12-03T04:46:49.790878', query='', response="\nHello, user! Here are some code blocks:\n\n```python\nfor i in range(10): print(i)\n```\n\n```\nThis doesn't even have a language definition!\n```\n\n```bash\nls **/*\n```\n", model='', mode='')
extract_cf
def extract_cf(
idx
):
extract_cf(0)'for i in range(10): print(i)'
extract
def extract(
idx:int, # Index of code block to extract
copy:bool=False, # Copy to clipboard
do_print:bool=False, # Print (useful for readline custom shortcuts)
):
Extracts the idx’th codefence from the last shell sage response and sends it to tmux by default