o: use session/agent slash syntax for context

Simplify context parsing:
- o <cmd>                   Root level
- o <session> <cmd>         Session level
- o <session>/<agent> <cmd> Agent level

The slash disambiguates between session and agent context,
eliminating the need for 'session' and 'agent' keywords.

Examples:
  o myproj ls               # session level
  o myproj/coding prompt    # agent level
This commit is contained in:
Levi Neely 2026-08-10 13:40:26 +02:00
parent 14a52236c8
commit d621e7322a
8 changed files with 87 additions and 105 deletions

View File

@ -38,4 +38,4 @@ prompt="Write unit tests for this code${location}:
$selection
\`\`\`"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -24,4 +24,4 @@ eval $(acme-ollie-ensure)
# Build and send the prompt
prompt="Describe and explain this file: $filename"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -38,4 +38,4 @@ prompt="Add documentation comments to this code${location}:
$selection
\`\`\`"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -38,4 +38,4 @@ prompt="Explain this code${context}:
$selection
\`\`\`"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -38,4 +38,4 @@ prompt="Fix this code${location}:
$selection
\`\`\`"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -38,4 +38,4 @@ prompt="Refactor this code${location}:
$selection
\`\`\`"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -62,4 +62,4 @@ prompt="\`\`\`${lang}
$selection
\`\`\`"
echo "$prompt" | o agent "$OLLIE_SESSION" "$OLLIE_AGENT" prompt
echo "$prompt" | o "$OLLIE_SESSION/$OLLIE_AGENT" prompt

View File

@ -1,12 +1,12 @@
#!/bin/bash
# o — unified CLI for the ollie 9P namespace.
#
# Hierarchical access:
# o <op> [args] Root level operations
# o session <sname> <op> [args] Session-level operations
# o agent <sname> <aname> <op> [args] Agent-level operations
# Context is determined by the first argument:
# o <cmd> Root level
# o <session> <cmd> Session level
# o <session>/<agent> <cmd> Agent level
#
# Environment variables ($session, $agent) can substitute for positional args.
# The slash in session/agent disambiguates context level.
#
# Subcommands:
# read <path> Read a file (-l to loop)
@ -17,14 +17,14 @@
# prompt Interactive REPL for submitting prompts (agent-level)
# tui Launch tmux TUI (agent-level)
# generate <prompt> One-shot generation (root-level only)
# env Print resolved session/agent environment
# env Print export statements for context
#
# Examples:
# o ls List root (sessions, models, etc.)
# o session myproj ls List session contents
# o session myproj new coding Create agent 'coding' in 'myproj'
# o agent myproj coding prompt Interactive prompt
# o agent myproj coding read chat Read chat output
# o ls List root (sessions, models, etc.)
# o myproj ls List session contents
# o myproj new coding Create agent 'coding' in 'myproj'
# o myproj/coding prompt Interactive prompt
# o myproj/coding read chat Read chat output
set -euo pipefail
@ -33,6 +33,18 @@ PREFIX="" # Path prefix based on context
CTX_SESSION="" # Session name if in session/agent context
CTX_AGENT="" # Agent name if in agent context
# ── Known commands (to distinguish from context) ─────────────────
COMMANDS="read write ls new ctl prompt log tui env generate help"
is_command() {
local arg="$1"
for cmd in $COMMANDS; do
[[ "$arg" == "$cmd" ]] && return 0
done
[[ "$arg" == "-h" || "$arg" == "--help" ]] && return 0
return 1
}
# ── Subcommands ─────────────────────────────────────────────────
cmd_read() {
@ -111,8 +123,8 @@ cmd_ctl() {
if [[ -z "$PREFIX" ]]; then
echo "error: ctl requires session or agent context" >&2
echo " usage: o session <name> ctl <cmd>" >&2
echo " or: o agent <session> <agent> ctl <cmd>" >&2
echo " usage: o <session> ctl <cmd>" >&2
echo " or: o <session>/<agent> ctl <cmd>" >&2
exit 1
fi
@ -128,7 +140,7 @@ cmd_ctl() {
cmd_prompt() {
if [[ -z "$CTX_AGENT" ]]; then
echo "error: prompt requires agent context" >&2
echo " usage: o agent <session> <agent> prompt" >&2
echo " usage: o <session>/<agent> prompt" >&2
exit 1
fi
@ -215,7 +227,7 @@ cmd_log() {
if [[ -z "$CTX_AGENT" ]]; then
echo "error: log requires agent context" >&2
echo " usage: o agent <session> <agent> log [-n N]" >&2
echo " usage: o <session>/<agent> log [-n N]" >&2
exit 1
fi
ollie-9p read "${PREFIX}/log" | tail -n "$lines"
@ -230,7 +242,7 @@ cmd_new() {
if [[ -n "$CTX_SESSION" ]]; then
# Create agent in current session
if [[ $# -lt 1 ]]; then
echo "usage: o session <sname> new <agent> [cwd]" >&2
echo "usage: o <session> new <agent> [cwd]" >&2
exit 1
fi
local agent_name="$1"
@ -253,7 +265,7 @@ cmd_new() {
cmd_tui() {
if [[ -z "$CTX_AGENT" ]]; then
echo "error: tui requires agent context" >&2
echo " usage: o agent <session> <agent> tui" >&2
echo " usage: o <session>/<agent> tui" >&2
exit 1
fi
@ -270,13 +282,11 @@ cmd_tui() {
tmux kill-session -t "$tmux_session" 2>/dev/null || true
# Layout: chat (top 80%), prompt (bottom 20%)
tmux -CC new-session -d -s "$tmux_session" -c "$HOME" \
-e "session=$s" -e "agent=$a"
tmux send-keys -t "$tmux_session" "o agent $s $a log -n 1000 | grep -v '\\[\\[\\[.*\\]\\]\\]' | grep -v '^\`\`\`'; o agent $s $a read chat" Enter
tmux -CC new-session -d -s "$tmux_session" -c "$HOME"
tmux send-keys -t "$tmux_session" "o $s/$a log -n 1000 | grep -v '\\[\\[\\[.*\\]\\]\\]' | grep -v '^\`\`\`'; o $s/$a read chat" Enter
tmux split-window -t "$tmux_session" -v -l 20% \
-e "session=$s" -e "agent=$a"
tmux send-keys -t "$tmux_session" "clear; o agent $s $a prompt" Enter
tmux split-window -t "$tmux_session" -v -l 20%
tmux send-keys -t "$tmux_session" "clear; o $s/$a prompt" Enter
tmux set-option -t "$tmux_session" status-right "starting... | %H:%M"
tmux set-option -t "$tmux_session" status-right-length 64
@ -304,22 +314,20 @@ cmd_tui() {
cmd_env() {
# Print export statements for current context
[[ -n "$CTX_SESSION" ]] && echo "export session=$CTX_SESSION"
[[ -n "$CTX_AGENT" ]] && echo "export agent=$CTX_AGENT"
[[ -n "$CTX_SESSION" ]] && echo "export OLLIE_SESSION=$CTX_SESSION"
[[ -n "$CTX_AGENT" ]] && echo "export OLLIE_AGENT=$CTX_AGENT"
}
cmd_help() {
cat <<'EOF'
usage: o [context] <command> [args...]
Context selectors:
o <cmd> Root level
o session <sname> <cmd> Session level
o agent <sname> <aname> <cmd> Agent level
Context is determined by the first argument:
o <cmd> Root level
o <session> <cmd> Session level
o <session>/<agent> <cmd> Agent level
Environment variables $session and $agent can substitute for positional args:
export session=foo agent=bar
o agent prompt # equivalent to: o agent foo bar prompt
The slash in <session>/<agent> disambiguates context level.
Commands (availability depends on context):
@ -328,13 +336,13 @@ Commands (availability depends on context):
new <session> [cwd] Create a new session
generate <prompt> One-shot generation (no session needed)
Session level (o session <name> ...):
Session level (o <session> ...):
ls List session contents (agents, config)
new <agent> [cwd] Create a new agent
ctl <cmd> Session control (kill, pause, resume)
read/write <path> Access session files
Agent level (o agent <session> <agent> ...):
Agent level (o <session>/<agent> ...):
ls List agent files
ctl <cmd> Agent control (stop, compact, model, etc.)
prompt Interactive multi-line prompt REPL
@ -349,18 +357,14 @@ Commands (availability depends on context):
help Show this help
Examples:
o ls # list root (sessions, models)
o new myproj # create session 'myproj'
o session myproj ls # list session contents
o session myproj new coding # create agent 'coding'
o agent myproj coding prompt # interactive prompt
o agent myproj coding read chat # read chat stream
o agent myproj coding tui # launch tmux TUI
o generate "explain monads" # one-shot, no session
# With environment:
export session=myproj agent=coding
o agent prompt # uses env vars
o ls # list root (sessions, models)
o new myproj # create session 'myproj'
o myproj ls # list session contents
o myproj new coding # create agent 'coding'
o myproj/coding prompt # interactive prompt
o myproj/coding read chat # read chat stream
o myproj/coding tui # launch tmux TUI
o generate "explain monads" # one-shot, no session
EOF
}
@ -388,61 +392,39 @@ dispatch_cmd() {
esac
}
# Main dispatch: check for context selectors
# Parse context from first argument
parse_context() {
local arg="$1"
if [[ "$arg" == */* ]]; then
# session/agent format
CTX_SESSION="${arg%%/*}"
CTX_AGENT="${arg#*/}"
PREFIX="session/$CTX_SESSION/agent/$CTX_AGENT"
else
# session only
CTX_SESSION="$arg"
PREFIX="session/$CTX_SESSION"
fi
}
# Main dispatch
if [[ $# -lt 1 ]]; then
cmd_help
exit 0
fi
case "$1" in
session)
shift
# Get session name from arg or env
CTX_SESSION="${1:-${session:-}}"
if [[ -n "${1:-}" ]]; then shift; fi
if [[ -z "$CTX_SESSION" ]]; then
echo "error: session name required" >&2
echo " usage: o session <name> <command>" >&2
exit 1
fi
PREFIX="session/$CTX_SESSION"
if [[ $# -lt 1 ]]; then
echo "error: command required after 'session <name>'" >&2
exit 1
fi
# Check if first arg is a command (root level) or context
if is_command "$1"; then
# Root level - no context
dispatch_cmd "$@"
else
# First arg is context (session or session/agent)
parse_context "$1"
shift
if [[ $# -lt 1 ]]; then
# No command after context - default to ls
cmd_ls
else
dispatch_cmd "$@"
;;
agent)
shift
# Get session and agent from args or env
CTX_SESSION="${1:-${session:-}}"
if [[ -n "${1:-}" ]]; then shift; fi
CTX_AGENT="${1:-${agent:-}}"
if [[ -n "${1:-}" ]]; then shift; fi
if [[ -z "$CTX_SESSION" || -z "$CTX_AGENT" ]]; then
echo "error: session and agent names required" >&2
echo " usage: o agent <session> <agent> <command>" >&2
exit 1
fi
PREFIX="session/$CTX_SESSION/agent/$CTX_AGENT"
if [[ $# -lt 1 ]]; then
echo "error: command required after 'agent <session> <agent>'" >&2
exit 1
fi
dispatch_cmd "$@"
;;
*)
# Root level - check env vars for backwards compat
if [[ -n "${agent:-}" && -n "${session:-}" ]]; then
# Has agent context from env
CTX_SESSION="$session"
CTX_AGENT="$agent"
PREFIX="session/$CTX_SESSION/agent/$CTX_AGENT"
elif [[ -n "${session:-}" ]]; then
# Has session context from env
CTX_SESSION="$session"
PREFIX="session/$CTX_SESSION"
fi
dispatch_cmd "$@"
;;
esac
fi
fi