scripts/AGENTS.md

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 the yo alias. An unmatched command prints Command not found.
  • Setup (from the README): cp example.conf ~/ayo.conf and edit the values; alias yo<repo>/ayo.sh; pnpm install (installs the Husky git hook).
  • Config is required and lives outside the repo at ~/ayo.conf (the repo ships example.conf as the template). Almost every script starts with . ${HOME}/ayo.conf then . ${scripts_dir}/functions.sh, so nothing works until ~/ayo.conf exists and defines scripts_dir.
  • Tests: there is no framework — npm test deliberately errors. The closest thing is the tasks app's self-test: ./tasks selftest (exercises create/redate/log/move on a throwaway temp store). Syntax-check the Python with python3 -c "import ast; ast.parse(open('tasks').read())".
  • Git remotes: gh (GitHub), sh (SourceHut), origin (git.ayo.run). The Husky post-commit hook auto-pushes to gh and sh.

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 exit in any sub-script kills the whole ayo.sh invocation.
  • 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 (backlognextin-progressdone); 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 mv when 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.sh launches it wrapped in a notes.sh sync before 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. timeout via brew install coreutils).