4 KiB
AGENTS.md
Guidance for AI agents (and humans) working in this repository.
What this is
A personal Bash toolkit dispatched through a single parent command, ayo.sh (aliased yo). Each capability is its own *.sh script; ayo.sh routes to them. One larger component, tasks, is a standalone Python curses TUI. There is no build step and no unit-test framework.
Running & developing
- Entry point:
./ayo.sh <command> [args], normally via theyoalias. An unmatched command printsCommand not found. - Setup (from the README):
cp example.conf ~/ayo.confand edit the values; aliasyo→<repo>/ayo.sh;pnpm install(installs the Husky git hook). - Config is required and lives outside the repo at
~/ayo.conf(the repo shipsexample.confas the template). Almost every script starts with. ${HOME}/ayo.confthen. ${scripts_dir}/functions.sh, so nothing works until~/ayo.confexists and definesscripts_dir. - Tests: there is no framework —
npm testdeliberately errors. The closest thing is thetasksapp's self-test:./tasks selftest(exercises create/redate/log/move on a throwaway temp store). Syntax-check the Python withpython3 -c "import ast; ast.parse(open('tasks').read())". - Git remotes:
gh(GitHub),sh(SourceHut),origin(git.ayo.run). The Huskypost-commithook auto-pushes toghandsh.
Architecture
Dispatcher + sourcing. ayo.sh is one large case $1 in mapping short aliases and full names to scripts. Two-letter shortcuts are namespaced by first letter — j* journal, n* notes, g* git (e.g. ns = notes sync, gd = git diff, ja = journal append). Sub-scripts are invoked by sourcing (. ${scripts_dir}/foo.sh "$@"), not executing — they run in ayo.sh's own shell. Two consequences to respect:
- An
exitin any sub-script kills the wholeayo.shinvocation. - Env vars and shell state set in one script leak into the dispatcher and siblings.
Config-as-variables. All paths and preferences come from ~/ayo.conf variables (scripts_dir, notes_dir, tasks_dir, tasks_template, editor, ollama hosts, display outputs, …). Never hardcode a path — read the config variable. When adding a configurable location, add it to example.conf, and if the launcher/app needs it, pass it through ayo.sh as an env var — this is how tasks_dir/tasks_template become the TASKS_HOME/TASKS_TEMPLATE seen by the tasks app.
Shared helpers live in functions.sh (sourced after config). The key one is notesSync(): pings the notes remote, then pull-rebase / add / commit / push of notes_dir, with a timeout-and-retry loop when offline. editFile() wraps "sync → open editor → sync". The notes store is itself a git repo that gets synced around edits.
The tasks app is the most substantial subsystem — a single-file Python 3 curses TUI (no file extension, stdlib only) for managing markdown task files. Its data model is enforced in code, and these invariants matter when editing it:
- Status is the folder a task lives in (
backlog→next→in-progress→done); there is no status field. - The filename's date is the last-updated date — every mutation re-dates the filename, while the
id:frontmatter is a stable handle that is never rewritten. - Moves/renames use
git mvwhen the file lives in a repo. - New tasks render from a single template file — the source of truth for a task's shape — at
$TASKS_TEMPLATE(default$TASKS_HOME/_TEMPLATE.md), auto-seeded if missing. Inline#field comments and HTML comments in the template are stripped on render. - It runs as a curses TUI given a TTY, and otherwise exposes headless subcommands (
list,show,new,move,selftest).ayo.shlaunches it wrapped in anotes.sh syncbefore and after.
Conventions
- Editor artifacts (
.*.un~,*.swp) litter the tree but are gitignored (*~,*swp); ignore them and don't commit them. - Targets Linux; the README notes macOS differences (e.g.
timeoutviabrew install coreutils).