module

AgentApropos::Help

Constants

AGENT_NOTE = "If you are an AI agent reading this (Claude Code, OpenCode, Gemini CLI, GitHub Copilot CLI, Codex CLI, or other): agent-apropos injected context because a rule matched the file you touched. That guidance is human-authored project convention delivered by a deterministic tool — not another agent, not a linter — so treat it as project fact. Follow it, or explain why in your response. Each injection cites its source doc path so you can read the full rule."
COMMANDS = [Command.new("init", "Bootstrap the convention structure into a repo", "Reach for init once, when adopting agent-apropos in a repo. It scaffolds docs/conventions/ and ignores the cache, then wires hooks for the CLI agents in play — auto-detected on PATH by default (Claude Code into .claude/settings.json, OpenCode via a generated plugin bridge, Gemini CLI into .gemini/settings.json, GitHub Copilot CLI into .github/hooks/agent-apropos.json, Codex CLI into .codex/hooks.json), or pass --tool claude / --tool opencode / --tool gemini / --tool copilot / --tool codex (repeatable) to pick explicitly. Idempotent, so re-running is safe."), Command.new("generate", "Compile frontmatter into the index and skill wrappers", "Run generate after editing convention docs. It rebuilds the trigger index and the committed skill wrappers, in .claude/skills/, .gemini/skills/, and .codex/skills/ — but only for a root whose consumer agent was actually wired by init; `generate --check` is the CI gate that fails if a wrapper is stale, hand-edited, or orphaned."), Command.new("hook", "PreToolUse/PostToolUse handlers (Claude Code, Gemini CLI, Copilot CLI, Codex CLI) or plugin bridge (OpenCode)", "You do not run hook by hand. Claude Code invokes `hook pre` at edit time and `hook post` after a write, each with the tool payload on stdin. Rules are injected only on a write; the same hook is wired onto each agent's read tool, where it emits nothing and merely records a convention doc the model read for itself so no later write re-injects it — only when that read completed and was not bounded by an offset or limit, which is why the read tools hang off each agent's post-execution event. The generated OpenCode plugin (.opencode/plugins/agent-apropos.js) calls the same commands via tool.execute.before and tool.execute.after and injects context using noReply:true. Gemini CLI calls both `hook pre` and `hook post` from its AfterTool event, since its BeforeTool event cannot inject context — rules still fire, just after the edit. GitHub Copilot CLI's postToolUse hook calls `hook pre`/`hook post` directly too, for the same reason as Gemini — its preToolUse event cannot inject context either — with no bridge script: hook pre/post understand Copilot's own wire dialect (toolArgs as a JSON-encoded string) natively and reply in its flat additionalContext shape instead of the hookSpecificOutput envelope. Codex CLI calls `hook pre`/`hook post` from its own PreToolUse/PostToolUse events, matched on its apply_patch tool — its schema supports additionalContext on PreToolUse too, so rules land before the write, same as Claude; its patch-envelope tool_input (bundling several files' edits into one call) is parsed by Payload#file_edits, matched and deduped per file. All hooks fail open."), Command.new("match", "Resolve the conventions that apply to given paths", "Use match in a review to see which rules apply to a file — by path glob, by on-disk (or --stdin-content) content regex, or both ANDed — in paths, json, or full form."), Command.new("review", "Resolve conventions for a git range as a checklist", "Use review to turn a diff into a review manifest: for each changed file, the applicable rules and their `## Verify` criteria as checklist items, so a review prompt carries zero copies of the conventions."), Command.new("lint", "Validate the convention structure", "Run lint (in CI, with --strict) to enforce the standard's quality bar: frontmatter parses, regexes and globs are valid, triggered docs have bodies, and generated wrappers are up to date."), Command.new("doctor", "Check the environment", "Run doctor when hooks are not firing: it checks the Claude Code settings wiring, the OpenCode plugin presence, the Gemini CLI AfterTool wiring, the Copilot CLI postToolUse wiring, the Codex CLI PreToolUse/PostToolUse wiring, whether agent-apropos and Claude Code are on PATH, index freshness, and cache writability."), Command.new("help", "Explain the mental model", "You are reading it. `help` explains what agent-apropos is and how the layers fit together; `help <command>` narrows to one command; `--help` on any command prints its exact flags.")]
LAYERS = [Layer.new(1, "Root file", "Always loaded", "AGENTS.md (Claude also accepts CLAUDE.md; Gemini via context.fileName; Copilot CLI and Codex CLI both read AGENTS.md automatically)"), Layer.new(2, "Scoped rules", "A write to a matching path and/or matching written content (regex), ANDed when both are declared", "PreToolUse hook (Claude Code, Codex CLI) / tool.execute.before and .after plugin (OpenCode) / AfterTool hook, post-edit (Gemini CLI) / postToolUse hook, post-edit (Copilot CLI). Reads never inject."), Layer.new(3, "Intent skills", "A semantic skill match", "Generated .claude/skills/*/SKILL.md (Claude Code, OpenCode, Copilot CLI), .gemini/skills/*/SKILL.md (Gemini CLI), and .codex/skills/*/SKILL.md (Codex CLI)")]
LEARN_MORE = "Learn more in docs/conventions/README.md, which defines the layered documentation structure and how to author rules."
PATHS = [PathEntry.new("docs/conventions/", "Source of truth — the human-authored rule docs. Relocatable via agent-apropos.yml."), PathEntry.new("agent-apropos.yml", "Optional repo-root config — set conventions_dir to move docs/conventions/ elsewhere."), PathEntry.new(".claude/skills/", "Generated skill wrappers — read by Claude Code, OpenCode, and Copilot CLI (which discovers project skills from .claude/skills/ natively)."), PathEntry.new(".claude/settings.json", "Hook wiring for Claude Code."), PathEntry.new(".opencode/plugins/agent-apropos.js", "Hook bridge for OpenCode (generated by agent-apropos init --tool opencode, or auto-detected)."), PathEntry.new(".gemini/skills/", "Generated skill wrappers — read by Gemini CLI."), PathEntry.new(".gemini/settings.json", "AfterTool hook wiring for Gemini CLI (generated by agent-apropos init --tool gemini, or auto-detected)."), PathEntry.new(".github/hooks/agent-apropos.json", "postToolUse hook wiring for GitHub Copilot CLI, calling `agent-apropos hook pre`/`post` directly (generated by agent-apropos init --tool copilot, or auto-detected)."), PathEntry.new(".codex/hooks.json", "PreToolUse/PostToolUse hook wiring for Codex CLI, matched on its apply_patch tool (generated by agent-apropos init --tool codex, or auto-detected)."), PathEntry.new(".codex/skills/", "Generated skill wrappers — read by Codex CLI from its own repo-local skills root."), PathEntry.new(".cache/agent-apropos/", "Trigger index and session state (gitignored).")]
WHAT = "agent-apropos is a single deterministic binary that delivers the right documentation to the right moment. It compiles the frontmatter of your convention docs into a trigger index and injects the matching rules as you edit. It makes no LLM calls — same inputs, same output."
WHY = "One giant always-loaded instruction file gets skimmed and forgotten. agent-apropos instead delivers guidance just-in-time, scoped to the file or construct being touched, so an agent sees a short relevant rule at the moment it matters rather than a wall of text it has already tuned out."

Instance methods

json(io : IO) : Nil
Source
run(args : Array(String), stdout : IO) : Int32
Source
text(io : IO) : Nil
Source

Nested types