From f4c4922f0e1b6a6a698a8ab7dec58ec4b1342679 Mon Sep 17 00:00:00 2001 From: Rootiest Date: Sat, 22 Aug 2026 00:53:54 -0400 Subject: [PATCH] docs(contributing): add CONTRIBUTING.md formalizing repo standards Documents the branching/PR workflow, commit conventions, fish function doc-header and colored --help conventions, the docs generation pipeline, testing, and the secrets/machine-config placement rule, so these practices live somewhere durable instead of only in commit history and conversation memory. --- CONTRIBUTING.md | 276 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fc0ee85 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,276 @@ +# Contributing to fish-config + +This is a personal dotfiles repo, but it's run with practices meant to scale +to a team of contributors, not just one person's solo habits. This document +formalizes those practices so they live somewhere durable instead of only in +commit history and conversation memory. It will grow as the project does — +treat it as a living document, not a final word. + +## Table of Contents + +- [Getting Started](#getting-started) +- [Branching & Pull Requests](#branching--pull-requests) +- [Commit Conventions](#commit-conventions) +- [Fish Coding Standards](#fish-coding-standards) +- [Opinionated Components](#opinionated-components) +- [Documentation Pipeline](#documentation-pipeline) +- [Testing](#testing) +- [Secrets & Machine-Specific Config](#secrets--machine-specific-config) +- [License](#license) + +--- + +## Getting Started + +You'll need [fish 4.x](https://fishshell.com/). Clone the repo and run the +test suite to confirm your environment is sane: + +```fish +fish tests/run-tests.fish +``` + +If you're touching anything under `docs/manual/`, you'll also want `pandoc`, +`python3-yaml`, and Node 24+ to exercise the full doc-build pipeline locally +(see [Documentation Pipeline](#documentation-pipeline)) — otherwise CI will +catch problems on push. + +## Branching & Pull Requests + +- **Branch off `main` before starting work.** Don't accumulate uncommitted + changes directly on `main`. (If you already started editing before + branching, that's fine — create the branch now, before your first commit; + branching doesn't touch the working tree.) +- **Merge target is `main`, via PR.** Contributors open the PR; the repo + owner merges it. Don't merge your own PR. +- **Keep feature branches focused.** If you stumble onto something unrelated + to your current task while working (a pre-existing bug, a stray cleanup), + don't fold it into the same commit or PR. Handle it with one of these, + in order of preference: + 1. **Separate branch, separate PR, merged to `main` independently.** The + default for anything that doesn't overlap the code your current branch + touches. The two PRs review and merge independently, in either order. + 2. **Separate branch and PR, then sync `main` back into your feature + branch** once it merges. Use this only when the unrelated fix actually + touches the same file/function as your feature branch, or your feature + branch depends on the corrected behavior to work or test correctly. + 3. **Commit directly to `main`.** Reserved for changes too small to + justify a branch, or genuinely urgent fixes. **Always ask for explicit + approval before doing this** — there's no standing exception, no matter + how trivial the change looks. + +## Commit Conventions + +Commit subjects follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +type(scope): description +``` + +Types currently in use in this repo: `feat`, `fix`, `docs`, `test`, `chore`, +`perf`. The scope is usually the function, component, or subsystem touched +(e.g. `feat(help): ...`, `fix(scrub): ...`, `chore(docs): ...`). Look at +`git log` for recent examples before picking a type/scope for something +novel. + +## Fish Coding Standards + +### File header + +Every hand-authored `.fish` file starts with: + +```fish +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later +``` + +(A few completion scripts adapted directly from a tool's own upstream +completions keep that tool's original attribution comment instead of this +header — match whichever convention the specific file already follows. New +files use the standard header above.) + +### Public function documentation header + +Every user-facing function gets a machine-parsed comment header directly +above its `function` line. This header is the single source of truth for +the generated manual (`docs/fish-config.md` / the man page / the docs +site) — see [Documentation Pipeline](#documentation-pipeline) for how it +gets consumed. The parser (`docs/manualtools.py`) recognizes these labels, +all optional except where noted: + +| Label | Purpose | +|---|---| +| `CATEGORY` | **Required to appear in the manual at all** — see below. | +| `COMPONENT` | Only for functions gated by the [opinionated-component system](#opinionated-components). | +| `DEPENDENCIES` | Other functions this one calls that a reader may want to look up. | +| `SYNOPSIS` | One-line usage form. | +| `DESCRIPTION` | Prose description; can span multiple paragraphs. | +| `ARGUMENTS` | Flags/positional args, one per line. | +| `EXIT STATUS` | Exit codes and what they mean. | +| `RETURNS` | For functions used for their output/return value rather than exit status. | +| `EXAMPLE` | One or more realistic invocations. | +| `NOTES` | Anything else worth flagging (fallback behavior, caveats, gotchas). | + +A full example (`functions/claude.fish`): + +```fish +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# CATEGORY +# 12-ai-and-developer-tools +# +# COMPONENT +# aliases/dev-tools +# +# DEPENDENCIES +# agents-init +# +# SYNOPSIS +# claude [ARGS...] +# +# DESCRIPTION +# Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is +# initialized and any agent-made changes are committed before launch. +# ... +``` + +**`CATEGORY` is the opt-in gate for the manual:** a function with no +`# CATEGORY` line produces no manual entry at all — this is how bundled +plugin internals and prompt guts stay out of user-facing docs without an +exclusion list. `CATEGORY` must exactly match one of the existing +`docs/manual/05-functions/NN-*.md` stubs: + +``` +01-file-and-directory 08-terminal-management +02-navigation 09-clipboard +03-editors-and-viewers 10-network +04-git-and-version-control 11-pager-and-logging +05-package-management 12-ai-and-developer-tools +06-dependency-management 13-media-and-utilities +07-system-and-monitoring 14-miscellaneous +``` + +If your function genuinely doesn't fit any of these, add a new +`docs/manual/05-functions/NN-your-category.md` stub (with frontmatter +matching its siblings) rather than force-fitting it into an existing one. + +### Private/internal helper functions + +Functions named with a leading `_` (e.g. `_agents_init_ensure_gitignore`, +`__fish_config_op_enabled`) are excluded from the manual unconditionally, +regardless of whether they carry a `CATEGORY` line — so they generally don't +have one. They should still carry the standard file header, and a lighter +`SYNOPSIS`/`DESCRIPTION` comment is encouraged wherever the function's +purpose or calling convention isn't obvious from its body, matching the +convention already used across `__fish_config_op_*.fish` and similar files. + +### Function declaration + +Give every function a `--description`, since it's what shows up in `fish -c +'functions'`/completions and other introspection: + +```fish +function my_function --description 'Short, imperative description' +``` + +### Colored `--help` output + +Every function with a `-h`/`--help` flag uses this standardized color +palette (established across the codebase 2026-08-22): + +```fish +set -l c_head (set_color --bold cyan) # section headers +set -l c_cmd (set_color --bold) # the command name itself (theme-adaptive) +set -l c_flag (set_color yellow) # flags +set -l c_arg (set_color cyan) # required-argument placeholders +set -l c_dim (set_color brblack) # optional-argument placeholders +set -l c_ok (set_color green) # success/positive status +set -l c_warn (set_color yellow) # warnings +set -l c_err (set_color red) # errors +set -l c_reset (set_color normal) +``` + +Not every function needs every variable — pull in only the ones your help +text actually uses. Structure the usage block as `Usage:`, then sections +for arguments/flags/examples as needed; see `functions/rand_string.fish` or +any recently-touched function for a full worked example. + +## Opinionated Components + +Some functionality in this config is classified into one of six toggleable +categories (C1–C6: aliases, autoexec, overrides, integrations, logging, +greeting) plus sub-categories, so users can disable pieces of it via +`config-settings` or universal variables. If you're adding something that +shadows a builtin, runs at startup, overrides a key binding/environment +variable, or otherwise falls under an existing category, tag it with a +`# COMPONENT` header (`/`, e.g. +`overrides/key-bindings`) and guard it with `__fish_config_op_enabled`. See +the [README's Minimal Mode section](README.md#minimal-mode) for the full +category list and toggle semantics, and +`AGENTS/specs/2026-08-17-opinionated-component-subcategories-design.md` for +the underlying design. Most new functions are *not* opinionated components +— only tag something if it fits an existing category; this isn't something +to force. + +## Documentation Pipeline + +`docs/manual/` is the single source of truth for the user manual, man page, +and documentation site. **Never hand-edit `docs/fish-config.md` or +`docs/fish-config.1`** — they're generated by `docs/build-manual.py` from +`docs/manual/**` plus every function's doc-header (see above), verified by +`docs/verify-manual.py`, and auto-committed by CI on push to `main` +(`chore(docs): regenerate manual, man page, and component registry`). + +If you're changing something under `docs/manual/` directly, or adding a +function whose `CATEGORY`/`COMPONENT` header should surface new content, you +can build and check it locally before pushing: + +```fish +python3 docs/build-manual.py --concat -o docs/fish-config.md +python3 docs/verify-manual.py +``` + +CI runs the same verification and regenerates the site/man page — a broken +manual won't get published, but running it locally saves a round trip. + +## Testing + +```fish +fish tests/run-tests.fish +``` + +Runs before every push and gates the documentation build in CI. Two phases: + +1. **Syntax lint** — every tracked `.fish` file (`config.fish`, `functions/`, + `conf.d/`, `completions/`, `integrations/`) is checked with `fish -n`. +2. **Sandboxed functional checks** — the config is copied into a throwaway + `HOME`/`XDG_CONFIG_HOME` sandbox (never this checkout itself, since it + doubles as a real `~/.config/fish`) and loaded as an isolated interactive + session. `tests/functional.fish` then runs against foundational behavior: + XDG/PATH/CDPATH setup, key bindings, abbreviations, core functions, the + opinionated-component registry, and more. + +To add a new functional check, add a `test_*` function to +`tests/functional.fish` — it's picked up automatically by +`functional_test_main`, no registration needed. Return 0 on pass, non-zero +on fail; print a short diagnostic on failure. + +## Secrets & Machine-Specific Config + +**Nothing containing credentials, tokens, personal identifiers, or a +specific machine's paths belongs in this repo — not even in a PR.** That +kind of thing lives in each user's own private overlay +(`~/.config/.user-dots/fish/secrets.fish` and `local.fish`), which is +git-ignored by design. If you're writing something that needs a secret or a +machine-specific path, source it from there rather than hardcoding it. +Everything else — general-purpose, reusable across machines — belongs in +the tracked repo as normal. See [README's Personalization +section](README.md#personalization) and +[`docs/manual/07-customization.md`](docs/manual/07-customization.md) for the +full mechanics. + +## License + +This project is licensed under AGPL-3.0-or-later (see `LICENSE`). Every new +hand-authored file needs the SPDX header shown in [File +header](#file-header) above.