mirror of
https://github.com/boxpositron/absolute-dotfiles.git
synced 2026-10-24 08:23:19 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c155860ff1 | |||
| b2eca8e1a0 | |||
| adf62ac948 | |||
| d92041b6dd | |||
| 5fbdaa9810 |
+1
-1
Submodule .config/nvim updated: 13ddbe2f56...d24b3ba574
@@ -3,7 +3,8 @@
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{ "type": "command", "command": "~/.local/bin/omo-notify", "timeout": 10 }
|
||||
{ "type": "command", "command": "~/.local/bin/omo-notify", "timeout": 10 },
|
||||
{ "type": "command", "command": "~/.local/bin/owt hook", "timeout": 5 }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
+85
-13
@@ -5,6 +5,7 @@
|
||||
# with the agent launched inside it in its own tmux window. A workspace can
|
||||
# carry any number of Linear issues; the agent renames the branch to
|
||||
# feature/<keys>-<slug> once it knows them and keeps their status in sync.
|
||||
# It also titles the window with one to three words naming the work.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -42,6 +43,12 @@ Usage (run from anywhere inside the repo):
|
||||
feature/<keys>-<slug> (e.g. feature/pra-107-108-imap-timeouts), moves
|
||||
each issue to In Progress, and to In Review with the PR link.
|
||||
owt open <name> Open a tmux window running the agent in an existing workspace
|
||||
owt title <words> Title the tmux windows of the workspace you are in with one to
|
||||
three words naming the work (owt title imap timeouts). The
|
||||
agent does this itself; owt open reuses the saved title.
|
||||
owt hook omo UserPromptSubmit hook (wired in ~/.omo/agent/hooks.json):
|
||||
inside a workspace, tells the agent its tab title with each
|
||||
prompt so it keeps the title current; elsewhere prints nothing
|
||||
owt ls List this repo's workspaces and their branches
|
||||
owt all List the workspaces of every repo with their branches and
|
||||
source checkouts (works from any directory)
|
||||
@@ -149,6 +156,27 @@ pr_info() {
|
||||
}
|
||||
ws_dir() { printf '%s/%s/%s\n' "$OWT_ROOT" "$(repo_name)" "$1"; }
|
||||
|
||||
# A workspace's tab title, kept in the worktree's own git dir so owt open can
|
||||
# reuse it and removing the worktree removes it too.
|
||||
title_file() { printf '%s/owt-title\n' "$(git -C "$1" rev-parse --path-format=absolute --git-dir)"; }
|
||||
|
||||
ws_title() {
|
||||
local file
|
||||
file="$(title_file "$1")"
|
||||
if [[ -f "$file" ]]; then cat "$file"; fi
|
||||
}
|
||||
|
||||
# tmux windows with a pane open in a workspace, one id per line. tmux reports
|
||||
# resolved paths, so compare against the resolved workspace path.
|
||||
ws_windows() {
|
||||
local real_dir win path
|
||||
command -v tmux >/dev/null && tmux list-panes -a >/dev/null 2>&1 || return 0
|
||||
real_dir="$(cd "$1" && pwd -P)"
|
||||
tmux list-panes -a -F '#{window_id} #{pane_current_path}' | while read -r win path; do
|
||||
if [[ "$path" == "$real_dir" || "$path" == "$real_dir"/* ]]; then printf '%s\n' "$win"; fi
|
||||
done | sort -u
|
||||
}
|
||||
|
||||
name_taken() {
|
||||
[[ -e "$(ws_dir "$1")" ]] || git -C "$(main_root)" show-ref --verify --quiet "refs/heads/feature/$1"
|
||||
}
|
||||
@@ -197,7 +225,8 @@ install_deps() {
|
||||
|
||||
# Standing workspace conventions, appended to the agent's system prompt on every launch.
|
||||
workspace_prompt() {
|
||||
local name="$1" dir="$2" branch
|
||||
local name="$1" dir="$2" branch title
|
||||
title="$(ws_title "$dir")"
|
||||
branch="$(git -C "$dir" symbolic-ref --quiet --short HEAD || printf 'a detached HEAD')"
|
||||
printf 'You are in owt workspace "%s" (%s), a git worktree of %s on branch %s. ' \
|
||||
"$name" "$dir" "$(repo_name)" "$branch"
|
||||
@@ -207,17 +236,26 @@ workspace_prompt() {
|
||||
# shellcheck disable=SC2016
|
||||
printf '%s is a placeholder: once you know the issues, and before the branch is pushed, rename it with `git branch -m feature/<keys>-<slug>`, where <keys> are the lowercased issue keys joined by hyphens with the team prefix written once (PRA-107 and PRA-108 give pra-107-108) and <slug> is a 2 to 5 word kebab-case summary. ' "$branch"
|
||||
fi
|
||||
if [[ -n "$title" ]]; then
|
||||
printf 'Its tmux tab is titled "%s". ' "$title"
|
||||
else
|
||||
printf 'Its tmux tab shows the workspace name until you title it. '
|
||||
fi
|
||||
# shellcheck disable=SC2016
|
||||
printf 'As soon as you know what the work is, and again whenever its focus changes, run `owt title <words>` with one to three short words naming it, never a sentence (for example `owt title imap timeouts`). '
|
||||
printf 'When a pull request is open, comment on each issue with a short summary and the PR link, and move each to In Review.'
|
||||
}
|
||||
|
||||
# launch <name> <dir> [initial message]
|
||||
launch() {
|
||||
local name="$1" dir="$2" args
|
||||
local name="$1" dir="$2" args window
|
||||
shift 2
|
||||
args=(--name "$name" --append-system-prompt "$(workspace_prompt "$name" "$dir")" "$@")
|
||||
window="$(ws_title "$dir")"
|
||||
window="${window:-$name}"
|
||||
if [[ -n "${TMUX:-}" ]]; then
|
||||
tmux new-window -n "$name" -c "$dir" -- "$OWT_AGENT" "${args[@]}"
|
||||
say "opened tmux window '$name' running $OWT_AGENT"
|
||||
tmux new-window -n "$window" -c "$dir" -- "$OWT_AGENT" "${args[@]}"
|
||||
say "opened tmux window '$window' running $OWT_AGENT"
|
||||
else
|
||||
say "not in tmux; start with: cd $(printf '%q' "$dir") && $OWT_AGENT$(printf ' %q' "${args[@]}")"
|
||||
fi
|
||||
@@ -278,6 +316,45 @@ cmd_open() {
|
||||
launch "$name" "$dir"
|
||||
}
|
||||
|
||||
# Title the tmux windows of the current workspace with what is being worked on.
|
||||
cmd_title() {
|
||||
local name dir title words=() win renamed=0
|
||||
name="$(current_ws)" || die "not inside an owt workspace"
|
||||
dir="$(ws_dir "$name")"
|
||||
[[ -d "$dir" ]] || die "no workspace at $dir"
|
||||
read -ra words <<<"$(printf '%s ' "$@" | tr -s '[:space:]' ' ' | tr -d '[:cntrl:]')"
|
||||
[[ ${#words[@]} -ge 1 && ${#words[@]} -le 3 ]] \
|
||||
|| die "a title is one to three words naming the work, e.g. owt title imap timeouts"
|
||||
title="${words[*]}"
|
||||
|
||||
printf '%s\n' "$title" >"$(title_file "$dir")"
|
||||
while read -r win; do
|
||||
tmux rename-window -t "$win" "$title"
|
||||
renamed=$((renamed + 1))
|
||||
done < <(ws_windows "$dir")
|
||||
say "titled '$name' as '$title' ($renamed tmux window(s) renamed)"
|
||||
}
|
||||
|
||||
# omo UserPromptSubmit hook. Inside a workspace it hands the agent the tab's
|
||||
# current title with each prompt, so the title keeps up with the work.
|
||||
cmd_hook() {
|
||||
local name dir title context
|
||||
[[ -t 0 ]] || cat >/dev/null
|
||||
git rev-parse --git-dir >/dev/null 2>&1 || return 0
|
||||
name="$(current_ws)" || return 0
|
||||
dir="$(ws_dir "$name")"
|
||||
[[ -d "$dir" ]] || return 0
|
||||
title="$(ws_title "$dir")"
|
||||
if [[ -n "$title" ]]; then
|
||||
context="This is owt workspace \"$name\" and its tmux tab is titled \"$title\". If this prompt changes what the work is about, or the focus shifts while you work, retitle it with \`owt title <words>\`: one to three short words naming the work, never a sentence."
|
||||
else
|
||||
context="This is owt workspace \"$name\" and its tmux tab has no title yet, so it shows the workspace name. As soon as you know what the work is, title it with \`owt title <words>\`: one to three short words naming the work, never a sentence (for example \`owt title imap timeouts\`). Retitle it whenever the focus shifts."
|
||||
fi
|
||||
context="${context//\\/\\\\}"
|
||||
context="${context//\"/\\\"}"
|
||||
printf '{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"%s"}}\n' "$context"
|
||||
}
|
||||
|
||||
cmd_ls() {
|
||||
local prefix
|
||||
prefix="$OWT_ROOT/$(repo_name)/"
|
||||
@@ -471,14 +548,8 @@ cmd_done() {
|
||||
fi
|
||||
|
||||
# Windows with a pane open in the workspace, collected before the directory goes away.
|
||||
# tmux reports resolved paths, so compare against the resolved workspace path.
|
||||
local windows=() real_dir
|
||||
real_dir="$(cd "$dir" && pwd -P)"
|
||||
if command -v tmux >/dev/null && tmux list-panes -a >/dev/null 2>&1; then
|
||||
while read -r win path; do
|
||||
[[ "$path" == "$real_dir" || "$path" == "$real_dir"/* ]] && windows+=("$win")
|
||||
done < <(tmux list-panes -a -F '#{window_id} #{pane_current_path}' | sort -u)
|
||||
fi
|
||||
local windows=() win
|
||||
while read -r win; do windows+=("$win"); done < <(ws_windows "$dir")
|
||||
|
||||
if [[ $merged == yes && $remote_branch == yes ]]; then
|
||||
git -C "$root" push --quiet origin --delete "$branch" && say "deleted remote branch $branch"
|
||||
@@ -494,7 +565,6 @@ cmd_done() {
|
||||
say "deleted local branch $branch"
|
||||
fi
|
||||
|
||||
local win
|
||||
for win in $(printf '%s\n' "${windows[@]+"${windows[@]}"}" | sort -u); do
|
||||
tmux kill-window -t "$win" 2>/dev/null || true
|
||||
done
|
||||
@@ -504,6 +574,8 @@ case "${1:-}" in
|
||||
new) shift; cmd_new "$@" ;;
|
||||
done) shift; cmd_done "$@" ;;
|
||||
open) shift; cmd_open "$@" ;;
|
||||
title) shift; cmd_title "$@" ;;
|
||||
hook) shift; cmd_hook ;;
|
||||
ls) shift; cmd_ls ;;
|
||||
all) shift; cmd_all ;;
|
||||
cd) shift; cmd_cd "$@" ;;
|
||||
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env zsh
|
||||
# Open the file path under the mouse in a tmux pane, routed by type:
|
||||
# markdown -> Markdown Preview (GUI)
|
||||
# images, pdf, dirs -> yazi in a split pane (image preview via passthrough)
|
||||
# anything else -> nvim in a split pane, jumping to :line when present
|
||||
#
|
||||
# Called from a tmux mouse binding:
|
||||
# tmux-open-path <pane_id> <pane_current_path> <mouse_x> <mouse_line>
|
||||
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
|
||||
pane=$1 cwd=$2 x=$3 line=$4
|
||||
|
||||
fail() { tmux display-message -d 2000 "open-path: $1"; exit 1 }
|
||||
|
||||
[[ -n $pane && -n $cwd && $x == <-> ]] || fail "usage: tmux-open-path PANE CWD X LINE"
|
||||
|
||||
# Grab the run of path-like characters around the clicked column. Whitespace,
|
||||
# quotes, brackets and box-drawing borders end a token.
|
||||
local stop=$' \t"\'`()[]{}<>|│┃║─━'
|
||||
(( i = x + 1 )) # mouse_x is 0-based, zsh strings are 1-based
|
||||
(( i <= ${#line} )) || fail "nothing under cursor"
|
||||
[[ $stop == *${line[i]}* ]] && fail "nothing under cursor"
|
||||
(( s = i )); while (( s > 1 )) && [[ $stop != *${line[s-1]}* ]]; do (( s-- )); done
|
||||
(( e = i )); while (( e < ${#line} )) && [[ $stop != *${line[e+1]}* ]]; do (( e++ )); done
|
||||
token=${line[s,e]}
|
||||
|
||||
# Normalise: file:// URLs, @mentions, trailing punctuation, :line[:col], #Lnn.
|
||||
token=${token#file://}
|
||||
token=${token#@}
|
||||
token=${token%%[.,;:!?]##}
|
||||
lnum=
|
||||
if [[ $token == (#b)(*)\#L(<->)* ]]; then
|
||||
token=$match[1] lnum=$match[2]
|
||||
elif [[ $token == (#b)(*):(<->):<-> || $token == (#b)(*):(<->) ]]; then
|
||||
token=$match[1] lnum=$match[2]
|
||||
fi
|
||||
[[ -n $token ]] || fail "nothing under cursor"
|
||||
|
||||
# Resolve against the pane's directory, then the enclosing git root.
|
||||
token=${~token} # expand a leading ~
|
||||
# (not "path": zsh ties that name to $PATH)
|
||||
file=
|
||||
if [[ $token == /* ]]; then
|
||||
[[ -e $token ]] && file=$token
|
||||
else
|
||||
for base in $cwd $(git -C $cwd rev-parse --show-toplevel 2>/dev/null); do
|
||||
[[ -e $base/$token ]] && { file=$base/$token; break }
|
||||
done
|
||||
fi
|
||||
[[ -n $file ]] || fail "no such file: $token"
|
||||
file=${file:A}
|
||||
|
||||
if [[ -d $file ]]; then
|
||||
tmux split-window -h -t $pane -c $file "yazi ${(q)file}"
|
||||
exit
|
||||
fi
|
||||
|
||||
case ${file:e:l} in
|
||||
md|markdown|mdx|mdown|mkd|mkdn)
|
||||
open -a "Markdown Preview" $file ;;
|
||||
png|jpg|jpeg|gif|webp|avif|svg|bmp|tif|tiff|heic|ico|pdf)
|
||||
tmux split-window -h -t $pane -c ${file:h} "yazi ${(q)file}" ;;
|
||||
*)
|
||||
tmux split-window -h -t $pane -c $cwd "nvim ${lnum:++$lnum} ${(q)file}" ;;
|
||||
esac
|
||||
@@ -142,6 +142,11 @@ bind-key -T copy-mode-vi 'C-\' select-pane -l
|
||||
set -g set-clipboard on
|
||||
set -as terminal-features ',*:clipboard'
|
||||
|
||||
# Ctrl+click a file path in any pane (omo, shell, logs) to open it:
|
||||
# markdown in Markdown Preview, images/pdf/dirs in yazi, the rest in nvim.
|
||||
# yazi and nvim split beside the clicked pane. See ~/.local/bin/tmux-open-path.
|
||||
bind -n C-MouseDown1Pane run-shell -b "~/.local/bin/tmux-open-path #{q:pane_id} #{q:pane_current_path} #{mouse_x} #{q:mouse_line}"
|
||||
|
||||
#
|
||||
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
|
||||
run '~/.tmux/plugins/tpm/tpm'
|
||||
|
||||
@@ -198,11 +198,29 @@ _exists() {
|
||||
# TMUX + FZF Setup Start
|
||||
#
|
||||
|
||||
# Print session names of the running tmux server, one per line. Prints nothing
|
||||
# and returns 1 when no server is up, so callers and completion fail cleanly.
|
||||
function _tmux_sessions_raw() {
|
||||
tmux list-sessions -F '#S' 2>/dev/null
|
||||
}
|
||||
|
||||
# tml [prefix]: list tmux sessions, optionally only those starting with prefix.
|
||||
function tml() {
|
||||
sessions=$(tmux ls | sed -E 's/:.*$//')
|
||||
for session in $sessions; do
|
||||
echo $session
|
||||
done
|
||||
if ! _exists tmux; then
|
||||
echo "tml: tmux is not installed" >&2
|
||||
return 127
|
||||
fi
|
||||
local sessions
|
||||
sessions=$(_tmux_sessions_raw)
|
||||
if [[ -z $sessions ]]; then
|
||||
echo "tml: no tmux server running (start one with: tma <name>)" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -n $1 ]]; then
|
||||
sessions=$(print -r -- "$sessions" | grep -- "^$1")
|
||||
[[ -z $sessions ]] && { echo "tml: no session matches '$1'" >&2; return 1; }
|
||||
fi
|
||||
print -r -- "$sessions"
|
||||
}
|
||||
|
||||
|
||||
@@ -218,18 +236,37 @@ function tmx(){
|
||||
fi
|
||||
}
|
||||
|
||||
# tma [session]: attach to a tmux session. With no argument, pick one with fzf.
|
||||
# Inside tmux it switches the client instead of nesting. If no server is up,
|
||||
# it starts a new session (named after the argument, or the current directory).
|
||||
function tma() {
|
||||
if ! _exists tmux; then
|
||||
echo "tma: tmux is not installed" >&2
|
||||
return 127
|
||||
fi
|
||||
|
||||
# If no argument is passed, show the list of tmux sessions with fzf
|
||||
local target="$1"
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
tmux attach -t $(tml | fzf)
|
||||
if [[ -z $(_tmux_sessions_raw) ]]; then
|
||||
target="${target:-${PWD:t}}"
|
||||
echo "tma: no tmux server running, starting new session '$target'" >&2
|
||||
tmux new-session -s "$target"
|
||||
return
|
||||
fi
|
||||
|
||||
# If an argument is passed, attach to the session with that name
|
||||
tmux attach -t $1
|
||||
if [[ -z $target ]]; then
|
||||
target=$(_tmux_sessions_raw | fzf --reverse --prompt="tma> ") || return 1
|
||||
elif ! tmux has-session -t "=$target" 2>/dev/null; then
|
||||
echo "tma: no session named '$target'. Running sessions:" >&2
|
||||
_tmux_sessions_raw | sed 's/^/ /' >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -n $TMUX ]]; then
|
||||
tmux switch-client -t "=$target"
|
||||
else
|
||||
tmux attach-session -t "=$target"
|
||||
fi
|
||||
}
|
||||
|
||||
function get_tmn_recommendation() {
|
||||
@@ -258,7 +295,7 @@ function tmn() {
|
||||
}
|
||||
|
||||
_fzf_complete_tma() {
|
||||
_fzf_complete --multi --reverse --prompt="tma> " -- "$@" < <(tmux ls | sed -E 's/:.*$//')
|
||||
_fzf_complete --reverse --prompt="tma> " -- "$@" < <(_tmux_sessions_raw)
|
||||
}
|
||||
|
||||
_fzf_complete_tmn() {
|
||||
@@ -353,6 +390,20 @@ autoload -Uz compinit
|
||||
compinit
|
||||
# End of Docker CLI completions
|
||||
|
||||
# Tab completion for tma/tml: offer running tmux sessions with window counts.
|
||||
# Registered after the last compinit so it is not discarded by a re-init.
|
||||
_tmux_session_names() {
|
||||
local -a sessions
|
||||
sessions=(${(f)"$(tmux list-sessions -F '#S:#{session_windows} windows#{?session_attached, (attached),}' 2>/dev/null)"})
|
||||
if (( ! $#sessions )); then
|
||||
_message 'no tmux server running'
|
||||
return 1
|
||||
fi
|
||||
_describe -t tmux-sessions 'tmux session' sessions
|
||||
}
|
||||
compdef '_arguments "1:tmux session:_tmux_session_names"' tma tml
|
||||
zstyle ':completion:*:*:(tma|tml):*:messages' format '%F{yellow}%d%f'
|
||||
|
||||
sshm() { TERM=xterm-256color command sshm "$@"; }
|
||||
|
||||
source <(sshm completion zsh)
|
||||
|
||||
@@ -20,6 +20,7 @@ cask "charles"
|
||||
cask "cyberduck"
|
||||
cask "chromium"
|
||||
cask "johannesnagl/tap/showmd", trusted: true
|
||||
cask "markdown-preview"
|
||||
|
||||
# AI and agents
|
||||
cask "conductor"
|
||||
|
||||
@@ -22,7 +22,7 @@ This repository contains personal dotfiles for configuring a complete developmen
|
||||
|
||||
## Features
|
||||
|
||||
- **Neovim Configuration**: Extensive Lua-based configuration with LSP support, debugging, and 50+ productivity plugins
|
||||
- **Neovim Configuration**: Extensive Lua-based configuration with LSP support, debugging, and around 40 productivity plugins
|
||||
- **Terminal Emulators**: Configurations for Ghostty and WezTerm with custom themes and visual effects
|
||||
- **Shell Environment**: Optimized Zsh configuration with Starship prompt and useful aliases
|
||||
- **AI Integration**: OmO and Claude Code configuration, shared agent preferences, and `owt` workspaces that give each agent task its own git worktree
|
||||
@@ -122,13 +122,12 @@ Restart OmO and Claude Code after applying changes. On first use, Claude may ask
|
||||
- **Themes**: Multiple colorschemes including Catppuccin, Tokyo Night, and Rose Pine
|
||||
|
||||
Key features:
|
||||
- AI-powered coding assistance (Claude, OmO)
|
||||
- Advanced Git integration
|
||||
- snacks.nvim for the fuzzy picker, file explorer, notifications and input prompts (replacing Telescope, nvim-notify and dressing)
|
||||
- Completion with blink.cmp (replacing nvim-cmp)
|
||||
- Advanced Git integration, including inline current-line blame
|
||||
- Flutter and mobile development support
|
||||
- Python environment management
|
||||
- Integrated debugging (DAP)
|
||||
- File tree navigation
|
||||
- Fuzzy finding with Telescope
|
||||
- Terminal integration
|
||||
|
||||
### Terminal Emulators
|
||||
@@ -153,11 +152,12 @@ Key features:
|
||||
- Starship prompt with custom configuration
|
||||
- Auto-completion and syntax highlighting
|
||||
- 1Password as the SSH agent, an `sshm` wrapper with completion, and `fs [session]` to reach the remote dev box over mosh into a named tmux session
|
||||
- tmux session helpers: `tma [session]` attaches (fzf picker with no argument, switches the client when already inside tmux) and `tml [prefix]` lists sessions. Both Tab-complete the running sessions with their window counts. When no tmux server is up, `tma` starts a new session named after the argument or the current directory, and `tml` and completion say so instead of erroring
|
||||
- Resets mouse-reporting modes at each prompt, so an unclean SSH or tmux disconnect cannot leave the terminal spewing escape codes
|
||||
|
||||
### Development Tools
|
||||
|
||||
- **tmux** (`.tmux.conf`): Terminal multiplexer with custom key bindings; sets the terminal title to the session name, after the omo status marker when there is one
|
||||
- **tmux** (`.tmux.conf`): Terminal multiplexer with custom key bindings; sets the terminal title to the session name, after the omo status marker when there is one. Ctrl+click a file path in any pane (omo, a shell, logs) to open it with `tmux-open-path`: markdown in Markdown Preview, images, PDFs and directories in yazi, anything else in nvim at the clicked `:line`. yazi and nvim open in a split beside the clicked pane
|
||||
- **Zed** (`.config/zed/keymap.json`): Editor key bindings. Settings stay local because they reference machine-specific agent paths
|
||||
- **tmux server** (`.tmux-server.conf`): Lightweight tmux config for remote servers
|
||||
- **Git**: Global gitignore patterns (`.rgignore`, `.gitignore`)
|
||||
@@ -174,7 +174,7 @@ Key features:
|
||||
OpenCode is retired. Its agents, commands and plugins are left in `.config/opencode/` for reference, are no longer installed or linked, and its skills and slash commands moved here.
|
||||
|
||||
- `omo.jsonc` (linked as `~/.omo/omo.jsonc`): model routing for the main session, task categories and curated agents. `design-critique-a` and `design-critique-b` are the two lanes the Impeccable critique delegates its assessments to.
|
||||
- `hooks.json` (linked as `~/.omo/agent/hooks.json`): runs `omo-notify` when you send a prompt, when a session stops and when it asks you something, for the sound, the notification and the coloured tab marker.
|
||||
- `hooks.json` (linked as `~/.omo/agent/hooks.json`): runs `omo-notify` when you send a prompt, when a session stops and when it asks you something, for the sound, the notification and the coloured tab marker. It also runs `owt hook` with each prompt, which tells an agent in an `owt` workspace its current tab title so it retitles the tab as the work changes. omo runs a new hook only after you approve it with `/hooks trust <id>` (ids are in `/hooks list`).
|
||||
- `prompts/` (linked as `~/.omo/agent/prompts`): slash commands.
|
||||
- `/linear-sync [notes]` posts a progress comment on the workspace's Linear issues and sets them to In Progress, or In Review once a PR is open.
|
||||
- `/owt-done [notes]` finishes a workspace after its PR merges: it comments on each issue and moves it to Done, then runs `owt done --detach`. It asks before discarding uncommitted or unmerged work.
|
||||
@@ -196,21 +196,16 @@ owt ls # workspaces and their current branches
|
||||
owt all # workspaces of every repo, with branches and source checkouts (from anywhere)
|
||||
owt cd # jump into a workspace with fzf; owt cd lagos goes straight there
|
||||
owt open lagos # reopen the agent in a workspace
|
||||
owt title imap timeouts # title the workspace's tmux tab (one to three words); the agent does this itself
|
||||
owt done # remove the workspace you are in once its work is merged
|
||||
```
|
||||
|
||||
`owt new` starts from the latest `origin` default branch, copies local `.env` files, installs dependencies, and opens a tmux window running omo with the workspace conventions: rename the placeholder branch to `feature/<keys>-<slug>` before pushing, and keep the Linear issues' statuses in sync. Workspaces share the main checkout's omo memory through a link under `~/.omo/memory/agents/`.
|
||||
`owt new` starts from the latest `origin` default branch, copies local `.env` files, installs dependencies, and opens a tmux window running omo with the workspace conventions: rename the placeholder branch to `feature/<keys>-<slug>` before pushing, title the tab with one to three words naming the work (`owt title`) and update it when the focus changes, and keep the Linear issues' statuses in sync. The title is saved with the worktree, so `owt open` reopens the tab under it. Workspaces share the main checkout's omo memory through a link under `~/.omo/memory/agents/`.
|
||||
|
||||
`owt cd` works from any directory. Inside a repository the picker starts filtered to that repo's workspaces and jumps straight in when only one matches. The `owt` function in `.zshrc` performs the `cd`; without it, `owt cd` only prints the path.
|
||||
|
||||
`owt done` refuses to discard work unless you pass `--force`. Work counts as merged when the branch is part of the default branch or its Gitea PR is merged (checked with `tea`). It then deletes the remote and local branch, removes the worktree and its memory link, and closes tmux windows open in it. `OWT_ROOT` (default `~/worktrees`) and `OWT_AGENT` (default `omo`) override the defaults; `owt --help` lists every option.
|
||||
|
||||
#### Neovim AI Integration
|
||||
|
||||
- **CodeCompanion**: AI pair programming with multiple providers
|
||||
- **Gen.nvim**: Local LLM integration
|
||||
- **LLM.nvim**: Additional LLM capabilities
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
@@ -231,6 +226,7 @@ Custom scripts and binaries are stored in `.local/bin/`:
|
||||
- `claude-tmux`: Claude integration with tmux
|
||||
- `cldir`: Change directory with Claude context
|
||||
- `owt`: Git worktree workspaces for coding agents (see [Agent workspaces](#agent-workspaces-owt))
|
||||
- `tmux-open-path`: Backs tmux's Ctrl+click. Takes the path under the mouse, strips `:line:col`, `#L10`, `@` and `file://`, resolves it against the pane's directory and then its git root, and routes it by type: markdown to Markdown Preview (`cask "markdown-preview"` in `Brewfile.apps`), images, PDFs and directories to yazi, the rest to nvim
|
||||
- `omo-notify`: Sound, tab marker and notification for OmO's hooks. Ghostty posts the notification, so clicking it opens the session's tab and pane
|
||||
- `omo-status`: Coloured marker in front of the Ghostty tab title for each tmux session running omo: 🔴 stopped with an error, 🟡 waiting for your answer, 🟢 finished, 🔵 working. A tab with several agents shows the most urgent one; focusing the tab clears red, amber and green, and undoes any title you gave the tab by hand so it always shows its session name
|
||||
- `docker-nuke`: Force-restart a wedged Docker Desktop, capturing diagnostics to `~/.local/state/docker-nuke/` first (`--dry-run` to preview, `--no-restart` to leave it down, `--deep` for root helpers)
|
||||
|
||||
Reference in New Issue
Block a user