flavor is a personal check-only code flavor lint CLI.
It owns AST-backed code-shape rules, path-scoped checks, report output, bad-flavor notes, and action hints. It does not own product semantics, formatting, rewriting, service execution, repository orchestration, or runtime management.
crates/contains the Rust workspace crates. Each core crate owns its localAGENTS.md; read the child file before editing that subtree..github/workflows/contains CI and release workflows..github/scripts/contains workflow-only helper scripts. Keep workflow-only scripts there.runseal.tomland.runseal/wrappers/are the repo-local operator entrypoints for support tasks that do not belong in the installableflavorproduct binary. Current support commands arerunseal :antlr,runseal :cloudflare,runseal :pr, andrunseal :release.grammars/contains the repo-visible.g4grammar source of truth plusmetadata.jsoncontract metadata. Parser backends, facts, diagnostics, and harnesses should align to these files.scripts/contains the repo-local uv-managed Python support command tree used by runseal wrappers..local/is repo-local private operator state (for example Cloudflare secrets). It must stay gitignored and must not become a source of truth for product behavior.scripts/init.pyis the idempotent post-clone initializer. It quick-fails on missing required tools or repository entrypoints, installs local hooks, and exits cleanly only when the checkout is ready for development.manage.shandmanage.ps1are the public install/uninstall entrypoints at the repository root.- Release and manager downloads use R2 metadata and artifacts as the source of truth.
crates/flavor-cli/AGENTS.md: installableflavorbinary, scan config, rule execution, reports, and CLI-facing behavior.crates/flavor-core/AGENTS.md: shared source text, spans, syntax tree glue, diagnostics, recovery, snapshots, product primitives, and typed state/config injection.crates/flavor-shared/AGENTS.md: first-party plugin implementation helpers that should not become public ABI.crates/flavor-plugin-filesystem/AGENTS.md: filesystem/source path and shape bundled plugin identity and behavior.crates/flavor-plugin-g4/AGENTS.md:.g4source analysis plugin identity and behavior.crates/flavor-plugin-python/AGENTS.md: Python syntax facts and code-shape frontend behavior.crates/flavor-plugin-rust/AGENTS.md: Rust syntax/facts frontend and embedded Rust lint facts.crates/flavor-plugin-typescript/AGENTS.md: TypeScript, JavaScript, and TSX lexer, parser, raw tree facts, visitor, and frontend state.crates/flavor-plugin-vue/AGENTS.md: Vue SFC descriptor, template/style facts, template parsing, and embedded expression validation.crates/flavor-plugin-svelte/AGENTS.md: Svelte descriptor, markup parsing, facts, and embedded expression validation.crates/flavor-grammar/AGENTS.md: grammar contract metadata,.g4source indexing, raw AST schema derivation, runtime kind lookup, parser backend adapters, dynamic grammar tree views, and validation harnesses.
When adding or removing a core subtree, update this index in the same change.
Child AGENTS.md files should stay local: ownership, directory shape, commands,
workflow notes, and FAQ for that subtree.
- Keep the CLI check-only.
- Keep rules about syntax, file shape, path shape, and abstract style attributes.
- Do not encode product-specific business concepts in built-in rules.
- Prefer reports that explain the bad flavor and suggest a direction of thought.
- Keep consumer-specific scope in consumer config files.
- Plugin crates may expose typed config injection through state. They do not define config file names, discovery rules, report rendering, or historical ecosystem compatibility.
python3 scripts/init.py
cargo fmt --all --check
cargo clippy --locked --workspace --all-targets -- -D warnings
cargo test --locked --workspace
cargo run --locked -p flavor-cli -- check --root . --config flavor.toml
runseal :antlr init
runseal :antlr check
runseal :pr --helppython3 scripts/init.py is the default post-clone command. It requires
runseal so repo-local support commands have one entrypoint shape. Use
--force only when intentionally replacing existing non-init hooks; the script
backs them up first.
runseal :antlr init builds the pinned local ANTLR Docker image.
runseal :antlr check is an optional Dockerized ANTLR validation helper. It
requires the image prepared by init, checks .g4 files under grammars/ in
ANTLR dependency mode, and does not generate Java artifacts.
After cloning or when hooks look stale, run:
python3 scripts/init.pyThe generated hooks contain their concrete actions directly. The pre-commit hook
currently runs fmt, cargo check, flavor self-check, shell syntax checks, and
PowerShell syntax checks when pwsh is available. The commit-msg hook validates
the commit subject shape.
Open https://github.com/PerishCode/flavor/issues first when the right shape is
not obvious from behavior or this AGENTS tree. Examples include a new rule with a
payload decision, a CLI shape change that affects output stability, or a release
flow tweak. For clear, scoped fixes that are not part of the global PerishCode
issue operations SOP, open a PR directly and reference any related issue from
the PR body with Closes #N.
The cross-repo issue handling and reporter verification loop is maintained in
the user's global Codex instructions at ~/.codex/AGENTS.md. Do not duplicate
that cadence, role split, GitHub comment policy, or token policy here.
Flavor-specific facts for that SOP:
- No-install validation is the Pre-PR checks below plus any focused
cargo run --locked -p flavor-cli -- ...reproduction commands needed for the issue. - Beta and stable publication use the repo-local release entrypoint
runseal :release. - After reporter closure, merge through the repo-local
runseal :prflow. - Local installed CLI updates use the root manager entrypoints
manage.shandmanage.ps1, with release metadata and artifacts coming from R2.
Use <area>/<kebab-case-slug>, where <area> matches the touched crate or
concern. Recent examples:
cli/auto-discover-configcli/warn-empty-scanconfig/match-arraycli/rules-subcommanddocs/config-schema
Subject: <area>: <imperative summary> on one line, ideally <= 72 characters.
The body explains why the change is shaped this way first, then the change list.
End with any Co-Authored-By: trailers when pair-coded or agent-assisted.
Unit tests for flavor-cli live under crates/flavor-cli/tests/unit/<area>.rs
and are registered in crates/flavor-cli/tests/unit.rs:
// in crates/flavor-cli/tests/unit.rs
#[path = "../src/<file>.rs"] // only if the touched module is not already mounted
mod <module>;
#[path = "unit/<area>.rs"]
mod <area>_cases;Tests that need a writable fixture follow the
std::env::temp_dir().join(format!("flavor-<slug>-{pid}-{seq}")) pattern and
clean up with fs::remove_dir_all at the end of each case. See
tests/unit/scan.rs and tests/unit/config.rs for live examples. Pure-function
tests follow tests/unit/model.rs and tests/unit/naming.rs.
Every PR must pass these commands before review:
cargo fmt --all --check
cargo clippy --locked --workspace --all-targets -- -D warnings
cargo test --locked --workspace
cargo run --locked -p flavor-cli -- check --root . --config flavor.tomlCI reruns them across Linux, Windows, and macOS.
Use these top-level sections, in order:
## Why
<what is broken or missing today>
## What
<concrete change list; reference filenames and modules>
## Tests
<commands run and results>Add ## Compatibility when an output shape, config field, or exit-code behavior
moves. Add ## Trade-off worth flagging when the change has a downside that
reviewers should hold in mind.
main is PR-only and protected by the guard workflow. Required approvals are
intentionally 0; the guard matrix is the merge gate.
After opening a non-draft PR, default to enabling repository auto-merge:
gh pr merge <num> --auto --squash --delete-branchDo not add workflow files just to auto-enable auto-merge. If auto-merge cannot
be enabled or the repository disables merge commits, wait for green checks and
fall back to the smallest equivalent manual command, usually
gh pr merge <num> --squash --delete-branch. Agents merge their own PRs after
the issue resolution is concrete and CI has passed; no manual approval handoff
is part of this loop.
No. The CLI is check-only. It reports bad flavor and action hints, but it does not format, rewrite, run services, or manage runtime state.
In consumer config files. Built-in rules stay about syntax, file shape, path shape, and abstract style attributes.
flavor-cli owns config file names, discovery, scan setup, report output, and
exit behavior. Plugin crates only expose plugin-facing inputs, facts,
diagnostics, and typed state/config injection where needed.
Public install/uninstall entrypoints live at the repository root as manage.sh
and manage.ps1. Release and smoke scripts should reference those root files.
Workflow-only helpers belong under .github/scripts/. The repository
initialization entrypoint is scripts/init.py; additional local support
commands, if added, should use runseal wrappers plus scripts/cli/.
Not by default. If a hook exists and was not generated by scripts/init.py, the
script stops and asks for --force. With --force, it backs up the existing
hook to a numbered .bak path before replacing it. Older bootstrap-generated
hooks are treated as generated and are replaced idempotently.