Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions .claude/commands/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ tool.
If that fails (e.g. no base branch found), fall back to `git status` and `git diff` against HEAD to
see uncommitted changes instead.

Sync the changelog files from `properties.yml` (see `.github/instructions/docs.instructions.md`) by
running `uv run --no-sync invoke docs.update_changelogs` using the Bash tool.

Using that diff, audit every doc and AI-config file that could be stale because of it. At minimum
check:

Expand All @@ -21,14 +24,19 @@ check:
references to removed/renamed modules, commands, tasks, or config keys.
4. **`AGENTS.md` / `CLAUDE.md`** — thin pointer files; only need edits if the pointer chain itself
changed (rare).
5. **The four synced command dirs** — `.github/prompts/*.prompt.md` (source of truth),
`.claude/commands/*.md`, `.claude/skills/*/SKILL.md`, `.clinerules/workflows/*.md` — these must
describe the same behavior; if one changed, the other three need the matching edit (see
`.github/instructions/prompts.instructions.md`).
5. **The five synced command dirs** — `.github/prompts/*.prompt.md` (source of truth),
`.claude/commands/*.md`, `.claude/skills/*/SKILL.md`, `.clinerules/workflows/*.md`, and
`.opencode/command/*.md` — these must describe the same behavior; if one changed, the other
four need the matching edit (see `.github/instructions/prompts.instructions.md`).
6. **`properties.yml`'s built-in template fragments** (`modules/setup/templates/properties/*.yml`) and
any other example/config file describing setup — if `setup.sh`, `setup.ps1`, or
`modules/setup/properties.py` changed what gets generated.
7. Any other `*.md` file that references a file, command, module, or behavior touched by the diff.
8. If the diff touches a component tracked under one of `properties.yml`'s change log categories
(see `.github/instructions/docs.instructions.md` — empty by default until a downstream repo adds
one), confirm that entry's `version`/`latest_changes` was actually bumped — the
`docs.update_changelogs` step above only syncs the changelog file to whatever's currently in
`properties.yml`; it can't tell you the version itself is stale. Flag it if it wasn't.

For each stale doc you find, fix it directly — this is a repo-local consistency sweep, not a
cross-repo sync, so no confirmation is needed before editing; git history is the safety net.
Expand Down
13 changes: 10 additions & 3 deletions .claude/skills/docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ Gather what changed on this branch:
uv run --no-sync invoke repo.pr_diff
```

Sync the changelog files from `properties.yml` (see `.github/instructions/docs.instructions.md`):

```bash
uv run --no-sync invoke docs.update_changelogs
```

Then sweep every doc/AI-config surface the prompt lists (root `README.md`, module `README.md`s,
`.github/instructions/*.md`, `AGENTS.md`/`CLAUDE.md`, the synced command dirs, `properties.yml`'s
built-in template fragments) and fix anything stale directly — this is a repo-local consistency
sweep, so no confirmation is needed before editing.
`.github/instructions/*.md`, `AGENTS.md`/`CLAUDE.md`, the five synced command dirs,
`properties.yml`'s built-in template fragments, and whether any touched change-log-category entry
in `properties.yml` was actually bumped) and fix anything stale directly — this is a repo-local
consistency sweep, so no confirmation is needed before editing.
21 changes: 17 additions & 4 deletions .clinerules/workflows/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ uv run --no-sync invoke repo.pr_diff
If that fails (e.g. no base branch found), fall back to `git status` and `git diff` against HEAD to
see uncommitted changes instead.

Sync the changelog files from `properties.yml` (see `.github/instructions/docs.instructions.md`):

Run this terminal command:

```
uv run --no-sync invoke docs.update_changelogs
```

Using that diff, audit every doc and AI-config file that could be stale because of it. At minimum
check:

Expand All @@ -18,14 +26,19 @@ check:
references to removed/renamed modules, commands, tasks, or config keys.
4. **`AGENTS.md` / `CLAUDE.md`** — thin pointer files; only need edits if the pointer chain itself
changed (rare).
5. **The four synced command dirs** — `.github/prompts/*.prompt.md` (source of truth),
`.claude/commands/*.md`, `.claude/skills/*/SKILL.md`, `.clinerules/workflows/*.md` — these must
describe the same behavior; if one changed, the other three need the matching edit (see
`.github/instructions/prompts.instructions.md`).
5. **The five synced command dirs** — `.github/prompts/*.prompt.md` (source of truth),
`.claude/commands/*.md`, `.claude/skills/*/SKILL.md`, `.clinerules/workflows/*.md`, and
`.opencode/command/*.md` — these must describe the same behavior; if one changed, the other
four need the matching edit (see `.github/instructions/prompts.instructions.md`).
6. **`properties.yml`'s built-in template fragments** (`modules/setup/templates/properties/*.yml`) and
any other example/config file describing setup — if `setup.sh`, `setup.ps1`, or
`modules/setup/properties.py` changed what gets generated.
7. Any other `*.md` file that references a file, command, module, or behavior touched by the diff.
8. If the diff touches a component tracked under one of `properties.yml`'s change log categories
(see `.github/instructions/docs.instructions.md` — empty by default until a downstream repo adds
one), confirm that entry's `version`/`latest_changes` was actually bumped — the
`docs.update_changelogs` step above only syncs the changelog file to whatever's currently in
`properties.yml`; it can't tell you the version itself is stale. Flag it if it wasn't.

For each stale doc you find, fix it directly — this is a repo-local consistency sweep, not a
cross-repo sync, so no confirmation is needed before editing; git history is the safety net.
Expand Down
40 changes: 40 additions & 0 deletions .github/instructions/docs.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,46 @@ applyTo: "*.md"
- Show invoke commands in fenced `sh` code blocks (`uv run --no-sync invoke ...`)
- Keep it concise — link out rather than duplicating content

## Change Logs (`docs/change_logs/<category>/<name>.md`)
Per-entry markdown change logs, generated from `properties.yml` — not hand-written prose. One
file per entry, newest version at the top. `modules/docs/lib/change_logs.py`'s
`CHANGELOG_CATEGORIES` tuple is empty by default here — this template has nothing version-tracked
in `properties.yml` yet. A downstream repo adds its own category (e.g. `cloudformation` for CDK
stacks, keyed by construct_id) to that tuple once it has entries worth logging; everything else in
the module already supports it.

**Source of truth is `properties.yml`**, not the markdown file — each category section has one
entry per name:
```yaml
<category>:
<name>:
version: 1.0.0
latest_changes:
author: Levon Becker # git config user.name — modules.common.properties.get_git_author()
date: 2026-08-11
description: Initial Release # comma-separate for multiple bullets: "Added X, Fixed Y"
```
Bumped by hand when the entry changes meaningfully — not automated. **A brand-new entry's first
`description` is always `"Initial Release"`.**

**Rendered entry format** (`modules/docs/lib/change_logs.py`'s `expected_entry_text()`):
```markdown
## 1.0.0 - 2026-08-11 - Levon Becker
* Initial Release
```
`## <version> - <date> - <author>` heading, one `* ` bullet per comma-separated `description`
item, blank line, next-newest entry below. No H1 title in the file — the first line is always a
`##` entry heading.

**Sync mechanism** — `modules/docs/lib/change_logs.py`:
- `check_each_log(update=True)` — prepends any missing entry (idempotent; a current entry is a
no-op). Backs `invoke docs.update_changelogs`, which also runs as part of `invoke fix` and
`/docs` (see `.github/prompts/docs.prompt.md`)
- `check_each_log(update=False)` — read-only; raises `ValueError` on the first stale entry instead
of writing. Backs the drift gate `tests/drift/docs/test_changelogs_current.py` — bump
`properties.yml` without running `docs.update_changelogs` (or `invoke fix`) and this fails.
A no-op while `CHANGELOG_CATEGORIES` is empty.

## Inline Code Comments
- Comment the *why*, not the *what*
- Reference external docs or issue numbers when a workaround is non-obvious
Expand Down
23 changes: 22 additions & 1 deletion .github/instructions/modules.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ Modules provide reusable Python logic consumed by invoke tasks, prompts, and scr
## Locations
| Path | Purpose |
|------|---------|
| `modules/common/` | Helpers tightly coupled to invoke tasks (`cli`, `properties`, `utils`) |
| `modules/common/` | Helpers tightly coupled to invoke tasks (`cli`, `properties`, `prompt_commands`, `route_utils`, `utils`) |
| `modules/docs/` | Changelog sync — keeps `docs/change_logs/<category>/<name>.md` in sync with `properties.yml` (`update.py`, `lib/change_logs.py`); `CHANGELOG_CATEGORIES` is empty until a downstream repo adds one |
| `modules/hermes/` | Syncs `~/.hermes/` config + SKILL.md from `.github/prompts/` (`sync.py`) |
| `modules/ollama/` | Local-LLM management — install/list/status/uninstall/update |
| `modules/opencode/` | Syncs `.opencode/command/` from `.github/prompts/` (`sync.py`) |
| `modules/repo/` | Git/PR workflow logic (pull, push, log, squash, rebase, pr) |
| `modules/setup/` | Repo bootstrap logic called by `setup.sh`/`setup.ps1` (`properties.py`) |
| `modules/template/` | Syncs shared, generic tooling with the parent template repo for `/template` |
Expand All @@ -19,6 +23,23 @@ Modules provide reusable Python logic consumed by invoke tasks, prompts, and scr
Repo consistency checks (`check_agents`) live under root `tests/` as pytest tests, not `modules/` —
see `.github/instructions/tests.instructions.md`.

## AI Tool Sync Modules

`.github/prompts/` is the single source of truth for all slash commands. Two sync modules
generate tool-specific formats from it, both consuming the shared parser in
`modules/common/prompt_commands.py`:

| Module | Output | Invoke command |
|---|---|---|
| `modules/hermes/sync.py` | `~/.hermes/config.yaml` + `SKILL.md` (real, global, user-home files — not repo-scoped) | `inv hermes.sync` |
| `modules/opencode/sync.py` | `.opencode/command/*.md` (repo-local, additive-only unless `--force`) | `inv opencode.sync` |

Run `inv ai.sync` to regenerate both at once. Never hand-edit `.opencode/command/`.

`.claude/commands/*.md`, `.claude/skills/*/SKILL.md`, and `.clinerules/workflows/*.md` have no
sync script — they're hand-maintained mirrors of `.github/prompts/`, verified by
`inv tests.check_agents`. See `.github/instructions/prompts.instructions.md`.

## Module Conventions
- One concern per file; filename matches the concern in snake_case
- Use module-level functions, not classes, unless state genuinely requires it
Expand Down
32 changes: 24 additions & 8 deletions .github/instructions/prompts.instructions.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
---
description: "Use when creating or editing slash-command prompt files for this project. Covers prompt structure, frontmatter, naming, the four-way sync across .github/prompts/, .claude/commands/, .claude/skills/, and .clinerules/workflows/, and how prompts interact with invoke tasks and modules."
applyTo: ".github/prompts/**,.claude/commands/**,.clinerules/workflows/**"
description: "Use when creating or editing slash-command prompt files for this project. Covers prompt structure, frontmatter, naming, the five-way sync across .github/prompts/, .claude/commands/, .claude/skills/, .clinerules/workflows/, and .opencode/command/, and how prompts interact with invoke tasks and modules."
applyTo: ".github/prompts/**,.claude/commands/**,.clinerules/workflows/**,.opencode/command/**"
---
# Prompts Instructions

## Location & Source of Truth
`.github/prompts/*.prompt.md` is the **source of truth** for every slash command. It's mirrored
into `.claude/commands/*.md` (Claude Code slash commands), `.claude/skills/*/SKILL.md` (Claude
Code Skills — auto-discovered, not explicitly invoked, format documented in
`skills.instructions.md`), and `.clinerules/workflows/*.md` (Cline) — see Required Frontmatter and
Command Body below for the commands/clinerules format.
`skills.instructions.md`), `.clinerules/workflows/*.md` (Cline), and `.opencode/command/*.md`
(OpenCode) — see Required Frontmatter and Command Body below for the format each tool needs.
`.claude/commands/`, `.claude/skills/`, and `.clinerules/workflows/` are hand-maintained mirrors;
`.opencode/command/` is the one generated mirror — regenerate it with `invoke opencode.sync`
instead of hand-editing it (see `tasks.instructions.md`).

## Architecture
Commands are the AI-facing entrypoint layer described in `.github/instructions/logic.instructions.md`
Expand Down Expand Up @@ -47,11 +50,23 @@ Claude Code uses the filename as the command name. Extra frontmatter fields are
No frontmatter — Cline workflows are plain markdown body only. The filename (minus extension) is
the command name.

### OpenCode (.opencode/command/*.md)
```yaml
---
description: Brief description
subtask: false # CRITICAL — prevents Task tool recursion
agent: general
slash_command: /command_name
---
```
Generated by `invoke opencode.sync` from `.github/prompts/*.prompt.md` — never hand-edit; a
mismatch is a sync bug in `modules/opencode/sync.py`, not something to patch here directly.

Claude Code Skills (`.claude/skills/*/SKILL.md`) also mirror every command, and GitHub Copilot
Skills (`.github/skills/*/SKILL.md`) optionally do — see `skills.instructions.md` for both formats.

## Command Body
Claude Code and Copilot use the same inline-execution syntax:
Claude Code, Copilot, and OpenCode use the same inline-execution syntax:
```
!`uv run --no-sync python -m modules.your_module.route "$ARGUMENTS"`
```
Expand Down Expand Up @@ -104,9 +119,10 @@ uv run --no-sync python -m modules.your_module.route "$ARGUMENTS"
if __name__ == "__main__":
raise SystemExit(main())
```
3. Create command files in **all four tool dirs** (`.github/prompts/`, `.claude/commands/`,
`.clinerules/workflows/` with the thin wrapper body, and `.claude/skills/<name>/SKILL.md` with a
pointer body) — see Command Body above and `skills.instructions.md` for the SKILL.md format.
3. Create command files by hand in `.github/prompts/`, `.claude/commands/`,
`.clinerules/workflows/` (thin wrapper body), and `.claude/skills/<name>/SKILL.md` (pointer
body) — see Command Body above and `skills.instructions.md` for the SKILL.md format. Then run
`invoke opencode.sync` to generate the matching `.opencode/command/*.md` — don't hand-write it.
4. Run `uv run --no-sync invoke fix && uv run --no-sync invoke test` (must be 10/10 for `.py` changes)

**DO NOT:**
Expand Down
6 changes: 3 additions & 3 deletions .github/instructions/review.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ description: "Use when reviewing a pull request or code change in this repo —
- `.github/instructions/` is this repo's source of truth for all AI/agent rules — a PR that
changes behavior without updating the relevant instruction file is incomplete, not just
under-documented.
- The four synced command dirs (`.github/prompts/`, `.claude/commands/`, `.claude/skills/`,
`.clinerules/workflows/`) must stay behaviorally consistent — see
`.github/instructions/prompts.instructions.md`. Flag a PR that edits some but not all of the four.
- The five synced command dirs (`.github/prompts/`, `.claude/commands/`, `.claude/skills/`,
`.clinerules/workflows/`, `.opencode/command/`) must stay behaviorally consistent — see
`.github/instructions/prompts.instructions.md`. Flag a PR that edits some but not all of the five.
- Branch name and PR title/body should follow `.github/instructions/git.instructions.md` — flag a
branch name that isn't lowercase `snake_case` ending in `_<github_username>`, or a PR body
missing the `## Summary`/`## Changes` structure.
Expand Down
Loading
Loading