From cf9a671fb88ed51f9fe35f76674857c168c0dd6d Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 17 Sep 2026 09:56:58 -0400 Subject: [PATCH 1/3] feat(skills): add style review workflow --- .pi/prompts/review-nix.md | 31 -------------- .pi/prompts/review.md | 42 +++++++++++++++++++ .pi/skills/nix-style | 2 +- .pi/skills/rust-style | 1 + src/skills/AGENTS.md | 0 src/skills/README.md | 1 + src/skills/nix-style/SKILL.md | 34 --------------- .../{nix-style => style}/RULE-FORMAT.md | 0 src/skills/style/STYLE.md | 21 ++++++++++ src/skills/style/nix/SKILL.md | 18 ++++++++ .../{nix-style => style/nix}/rules/flake.md | 0 .../{nix-style => style/nix}/rules/let.md | 0 src/skills/style/rust/SKILL.md | 9 ++++ src/skills/style/rust/rules/build.md | 39 +++++++++++++++++ src/skills/style/rust/rules/files.md | 28 +++++++++++++ 15 files changed, 160 insertions(+), 66 deletions(-) delete mode 100644 .pi/prompts/review-nix.md create mode 100644 .pi/prompts/review.md create mode 120000 .pi/skills/rust-style delete mode 100644 src/skills/AGENTS.md delete mode 100644 src/skills/nix-style/SKILL.md rename src/skills/{nix-style => style}/RULE-FORMAT.md (100%) create mode 100644 src/skills/style/STYLE.md create mode 100644 src/skills/style/nix/SKILL.md rename src/skills/{nix-style => style/nix}/rules/flake.md (100%) rename src/skills/{nix-style => style/nix}/rules/let.md (100%) create mode 100644 src/skills/style/rust/SKILL.md create mode 100644 src/skills/style/rust/rules/build.md create mode 100644 src/skills/style/rust/rules/files.md diff --git a/.pi/prompts/review-nix.md b/.pi/prompts/review-nix.md deleted file mode 100644 index 7339187..0000000 --- a/.pi/prompts/review-nix.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -description: Review Nix changes against repository Nix style rules -argument-hint: "[target]" ---- - -Use the `nix-style` skill. -Audit ${ARGUMENTS:-the staged diff} for violations of the repository Nix style rules. - -Report only actionable findings. -Order findings by severity. -Do not report preferences unless a loaded rule states them. - -Use this format for each finding: - -```text -`code-path:line` -> `smallest reviewed-code excerpt that shows the violation` - -`rule-file:line`: Finding title. -Summary: why the code breaks the rule -Fix: suggested fix -``` - -Keep the code excerpt to one to three lines when possible. -Use a longer excerpt only when the violation needs surrounding context. -Use `...` to omit unrelated lines from a multi-line excerpt. -Use a skill-relative rule citation, such as `let.md:7`. -Make the fix direct. -Do not include alternatives when one fix best follows the cited rule. - -It is acceptable to report no findings when the reviewed Nix already follows the loaded rules. diff --git a/.pi/prompts/review.md b/.pi/prompts/review.md new file mode 100644 index 0000000..d0e78c6 --- /dev/null +++ b/.pi/prompts/review.md @@ -0,0 +1,42 @@ +--- +description: Review changes against repository style rules +argument-hint: "[target]" +--- + +Review target: `${ARGUMENTS:-the staged diff}`. +Audit the target for violations of the repository style rules. + +Choose skills from the reviewed files: + +- Use the `nix-style` skill for `*.nix` files. +- Use the `rust-style` skill for `*.rs` files. +- Use the `rust-style` skill for `Cargo.toml` files. +- Use the `rust-style` skill for Bazel files that define Rust targets. + +If the target includes multiple matching file types, use all matching skills. +If the target is a diff, choose skills from the changed files. +Do not use a style skill when no reviewed file matches it. + +Report only actionable findings. +Order findings by severity. +Do not report preferences unless a loaded rule states them. + +Use this format for each finding: + +```text +`code-path:line` +> `smallest reviewed-code excerpt that shows the violation` + +`skill::rule-file:line`: Finding title. +Summary: why the code breaks the rule +Fix: suggested fix +``` + +Keep the code excerpt to one to three lines when possible. +Use a longer excerpt only when the violation needs surrounding context. +Use `...` to omit unrelated lines from a multi-line excerpt. +Use a style-skill rule citation, such as `rust::files.md:23` or `nix::let.md:7`. +Make the fix direct. +Do not include alternatives when one fix best follows the cited rule. + +It is acceptable to report no findings when the target follows the loaded rules. diff --git a/.pi/skills/nix-style b/.pi/skills/nix-style index 1622f88..cb71dea 120000 --- a/.pi/skills/nix-style +++ b/.pi/skills/nix-style @@ -1 +1 @@ -../../src/skills/nix-style \ No newline at end of file +../../src/skills/style/nix \ No newline at end of file diff --git a/.pi/skills/rust-style b/.pi/skills/rust-style new file mode 120000 index 0000000..b48fcfb --- /dev/null +++ b/.pi/skills/rust-style @@ -0,0 +1 @@ +../../src/skills/style/rust \ No newline at end of file diff --git a/src/skills/AGENTS.md b/src/skills/AGENTS.md deleted file mode 100644 index e69de29..0000000 diff --git a/src/skills/README.md b/src/skills/README.md index 75ed668..4c86489 100644 --- a/src/skills/README.md +++ b/src/skills/README.md @@ -6,6 +6,7 @@ This directory contains monorepo-owned agent skill sources. ```text src/skills/ Monorepo-owned skill sources +src/skills/// Grouped monorepo skill sources .pi/skills/ Monorepo-wide enabled Pi skill symlinks src//skills/ Project-owned skill sources src//.pi/skills/ Project-specific enabled Pi skill symlinks diff --git a/src/skills/nix-style/SKILL.md b/src/skills/nix-style/SKILL.md deleted file mode 100644 index e943686..0000000 --- a/src/skills/nix-style/SKILL.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: nix-style -description: Use when creating, editing, or reviewing Nix files in this repository. ---- - -# nix-style - -Use this skill as the source of truth for repository Nix conventions. - -## Load rules - -Read every Markdown file directly under [`rules/`](rules/) before applying this skill. -Resolve [`rules/`](rules/) relative to this `SKILL.md`. - -Finish when all discovered rule files have been read. - -## Apply rules - -Apply the loaded rules when editing or reviewing Nix files. -When loaded rules conflict, follow the most specific rule. - -After editing Nix files, run: - -```bash -nix run .#fix -``` - -Finish when `nix run .#fix` succeeds and the Nix change follows the loaded rules. -If the command fails, report the failure. - -## Maintain rules - -When adding or changing files under [`rules/`](rules/), read [`RULE-FORMAT.md`](RULE-FORMAT.md) first. -Finish when the changed rule files follow that format. diff --git a/src/skills/nix-style/RULE-FORMAT.md b/src/skills/style/RULE-FORMAT.md similarity index 100% rename from src/skills/nix-style/RULE-FORMAT.md rename to src/skills/style/RULE-FORMAT.md diff --git a/src/skills/style/STYLE.md b/src/skills/style/STYLE.md new file mode 100644 index 0000000..79a89d0 --- /dev/null +++ b/src/skills/style/STYLE.md @@ -0,0 +1,21 @@ +# Style skill instructions + +Use this document for skills that own repository style conventions. + +## Load rules + +Read every Markdown file directly under `rules/` before applying the skill. +Resolve `rules/` relative to the skill's `SKILL.md`. + +Finish when all discovered rule files have been read. + +## Apply rules + +Apply the loaded rules when editing or reviewing files covered by the skill. +When loaded rules conflict, follow the most specific rule. + + +## Maintain rules + +When adding or changing files under `rules/`, read `src/skills/style/RULE-FORMAT.md` first. +Finish when the changed rule files follow that format. diff --git a/src/skills/style/nix/SKILL.md b/src/skills/style/nix/SKILL.md new file mode 100644 index 0000000..cfcd9bd --- /dev/null +++ b/src/skills/style/nix/SKILL.md @@ -0,0 +1,18 @@ +--- +name: nix-style +description: Use when creating, editing, or reviewing Nix files in this repository. +--- + +# nix-style + +Use this skill as the source of truth for repository Nix conventions. +Follow the shared style skill instructions in `src/skills/style/STYLE.md`. + +After editing Nix files, run: + +```bash +nix run .#fix +``` + +Finish when `nix run .#fix` succeeds and the Nix change follows the loaded rules. +If the command fails, report the failure. diff --git a/src/skills/nix-style/rules/flake.md b/src/skills/style/nix/rules/flake.md similarity index 100% rename from src/skills/nix-style/rules/flake.md rename to src/skills/style/nix/rules/flake.md diff --git a/src/skills/nix-style/rules/let.md b/src/skills/style/nix/rules/let.md similarity index 100% rename from src/skills/nix-style/rules/let.md rename to src/skills/style/nix/rules/let.md diff --git a/src/skills/style/rust/SKILL.md b/src/skills/style/rust/SKILL.md new file mode 100644 index 0000000..f9dd09b --- /dev/null +++ b/src/skills/style/rust/SKILL.md @@ -0,0 +1,9 @@ +--- +name: rust-style +description: Use when creating, editing, or reviewing Rust files in this repository. +--- + +# rust-style + +Use this skill as the source of truth for repository Rust conventions. +Follow the shared style skill instructions in `src/skills/style/STYLE.md`. diff --git a/src/skills/style/rust/rules/build.md b/src/skills/style/rust/rules/build.md new file mode 100644 index 0000000..4ccf566 --- /dev/null +++ b/src/skills/style/rust/rules/build.md @@ -0,0 +1,39 @@ +# Build rules + +## Use workspace dependency versions + +### Rule + +Declare Rust dependency versions in the repository root `Cargo.toml` under `[workspace.dependencies]`. +Reference workspace dependencies from package `Cargo.toml` files with `workspace = true`. +Do not declare dependency versions in package `Cargo.toml` files unless the operator explicitly requests a package-local version. +Add package-local dependency features only when the feature set is specific to that package. + +### Rationale + +The repository has one Cargo workspace and one `Cargo.lock`. +Centralized dependency versions keep package manifests consistent with the workspace lockfile. + +## Declare Rust tests in Bazel + +### Rule + +Declare Rust test files in the nearest Bazel `BUILD` file with `rust_test`. +Do not add `[[test]]` entries to `Cargo.toml` unless the operator explicitly requests Cargo test declarations. + +### Rationale + +Bazel is the source of truth for Rust test targets in this repository. +Keeping test declarations in Bazel avoids duplicate test target lists. + +## Use one source input style per `rust_test` + +### Rule + +Do not set both `crate` and `srcs` on a `rust_test` target. +Use exactly one input style for each Rust test target. + +### Rationale + +`rules_rust` rejects `rust_test` targets that set both `crate` and `srcs`. +Keeping one input style per target makes the test declaration valid and unambiguous. diff --git a/src/skills/style/rust/rules/files.md b/src/skills/style/rust/rules/files.md new file mode 100644 index 0000000..283cd04 --- /dev/null +++ b/src/skills/style/rust/rules/files.md @@ -0,0 +1,28 @@ +# File rules + +## Avoid generic Rust file names + +### Rule + +Do not name Rust source files `lib.rs` or `main.rs`. +Name library crate root files after the crate they define. +Name binary crate root files after the binary they define, or use a `_main.rs` suffix. +Set explicit Cargo paths and Bazel `srcs` when needed. + +### Rationale + +Generic root names make file search results and review context less clear. +Descriptive file names show which crate or binary owns the code. + +## Keep Rust tests in separate files + +### Rule + +Put Rust tests in separate `*_test.rs` files. +Name each test file after the Rust source file or crate root that it tests. +Do not use generic test file names such as `lib_test.rs` or `main_test.rs`. +Do not add inline `#[cfg(test)]` modules. + +### Rationale + +Separate test files keep production modules focused and match the repository's Bazel test layout. -- 2.47.3 From b4b77faaa9eb65fc35aeae81b8d9c6b92e15bddf Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 17 Sep 2026 09:57:11 -0400 Subject: [PATCH 2/3] refactor(rust): align workspace with style rules --- Cargo.lock | 5 ++ Cargo.toml | 7 +++ src/ariadne/BUILD | 5 +- src/ariadne/Cargo.toml | 11 +++-- src/ariadne/{lib.rs => ariadne.rs} | 0 src/ariadne/{main.rs => ariadne_main.rs} | 15 +----- src/machoke/BUILD | 4 +- src/machoke/Cargo.toml | 6 +-- src/machoke/{lib.rs => machoke.rs} | 0 src/machoke/{lib_test.rs => machoke_test.rs} | 0 src/monorepo/BUILD | 17 +++++++ src/monorepo/Cargo.toml | 9 ++++ src/monorepo/monorepo.rs | 1 + src/monorepo/workspace.rs | 20 ++++++++ src/monorepo/workspace_test.rs | 52 ++++++++++++++++++++ 15 files changed, 124 insertions(+), 28 deletions(-) rename src/ariadne/{lib.rs => ariadne.rs} (100%) rename src/ariadne/{main.rs => ariadne_main.rs} (69%) rename src/machoke/{lib.rs => machoke.rs} (100%) rename src/machoke/{lib_test.rs => machoke_test.rs} (100%) create mode 100644 src/monorepo/BUILD create mode 100644 src/monorepo/Cargo.toml create mode 100644 src/monorepo/monorepo.rs create mode 100644 src/monorepo/workspace.rs create mode 100644 src/monorepo/workspace_test.rs diff --git a/Cargo.lock b/Cargo.lock index 6fb8080..598e909 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,7 @@ name = "ariadne" version = "0.1.0" dependencies = [ "clap", + "monorepo", "serde", "serde_json", ] @@ -135,6 +136,10 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "monorepo" +version = "0.1.0" + [[package]] name = "once_cell_polyfill" version = "1.70.2" diff --git a/Cargo.toml b/Cargo.toml index 10b9230..06ff695 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,12 @@ members = [ "src/ariadne", "src/machoke", + "src/monorepo", ] resolver = "3" + +[workspace.dependencies] +clap = "4" +monorepo = { path = "src/monorepo" } +serde = "1.0" +serde_json = "1.0" diff --git a/src/ariadne/BUILD b/src/ariadne/BUILD index d035e0b..e1f9832 100644 --- a/src/ariadne/BUILD +++ b/src/ariadne/BUILD @@ -4,8 +4,8 @@ rust_library( name = "ariadne_lib", crate_name = "ariadne", srcs = [ + "ariadne.rs", "clew.rs", - "lib.rs", "pipeline.rs", ], deps = [ @@ -17,9 +17,10 @@ rust_library( rust_binary( name = "ariadne", crate_name = "ariadne_cli", - srcs = ["main.rs"], + srcs = ["ariadne_main.rs"], deps = [ ":ariadne_lib", + "//src/monorepo:monorepo", "//third_party/crates:clap", ], ) diff --git a/src/ariadne/Cargo.toml b/src/ariadne/Cargo.toml index 9479df0..faa94af 100644 --- a/src/ariadne/Cargo.toml +++ b/src/ariadne/Cargo.toml @@ -4,13 +4,14 @@ version = "0.1.0" edition = "2024" [lib] -path = "lib.rs" +path = "ariadne.rs" [[bin]] name = "ariadne" -path = "main.rs" +path = "ariadne_main.rs" [dependencies] -clap = { version = "4", features = ["derive"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +clap = { workspace = true, features = ["derive"] } +monorepo = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } diff --git a/src/ariadne/lib.rs b/src/ariadne/ariadne.rs similarity index 100% rename from src/ariadne/lib.rs rename to src/ariadne/ariadne.rs diff --git a/src/ariadne/main.rs b/src/ariadne/ariadne_main.rs similarity index 69% rename from src/ariadne/main.rs rename to src/ariadne/ariadne_main.rs index f364e12..cbed38e 100644 --- a/src/ariadne/main.rs +++ b/src/ariadne/ariadne_main.rs @@ -17,7 +17,7 @@ struct Args { impl From for ariadne::Config { fn from(args: Args) -> Self { ariadne::Config { - output_dir: resolve_workspace_path(args.output_dir), + output_dir: monorepo::workspace::resolve_workspace_path(args.output_dir), force: args.force, target_stage: args.target_stage, } @@ -32,19 +32,6 @@ fn parse_stage(value: &str) -> Result { .ok_or_else(|| format!("unknown stage: {value}")) } -// TODO: Move this into a shared Rust utility crate. -fn resolve_workspace_path(path: PathBuf) -> PathBuf { - if path.is_absolute() { - return path; - } - - if let Some(workspace) = std::env::var_os("BUILD_WORKSPACE_DIRECTORY") { - return PathBuf::from(workspace).join(path); - } - - path -} - fn main() -> ariadne::Result<()> { let config: ariadne::Config = Args::parse().into(); ariadne::run(&config) diff --git a/src/machoke/BUILD b/src/machoke/BUILD index 1f4a86d..0d4ac70 100644 --- a/src/machoke/BUILD +++ b/src/machoke/BUILD @@ -3,11 +3,11 @@ load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test") rust_library( name = "machoke_lib", crate_name = "machoke", - srcs = ["lib.rs"], + srcs = ["machoke.rs"], ) rust_test( name = "machoke_test", - srcs = ["lib_test.rs"], + srcs = ["machoke_test.rs"], deps = [":machoke_lib"], ) diff --git a/src/machoke/Cargo.toml b/src/machoke/Cargo.toml index c121f08..ad416f6 100644 --- a/src/machoke/Cargo.toml +++ b/src/machoke/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = "2024" [lib] -path = "lib.rs" - -[[test]] -name = "lib_test" -path = "lib_test.rs" +path = "machoke.rs" [dependencies] diff --git a/src/machoke/lib.rs b/src/machoke/machoke.rs similarity index 100% rename from src/machoke/lib.rs rename to src/machoke/machoke.rs diff --git a/src/machoke/lib_test.rs b/src/machoke/machoke_test.rs similarity index 100% rename from src/machoke/lib_test.rs rename to src/machoke/machoke_test.rs diff --git a/src/monorepo/BUILD b/src/monorepo/BUILD new file mode 100644 index 0000000..6170275 --- /dev/null +++ b/src/monorepo/BUILD @@ -0,0 +1,17 @@ +load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test") + +rust_library( + name = "monorepo", + crate_name = "monorepo", + srcs = [ + "monorepo.rs", + "workspace.rs", + ], + visibility = ["//visibility:public"], +) + +rust_test( + name = "workspace_test", + srcs = ["workspace_test.rs"], + deps = [":monorepo"], +) diff --git a/src/monorepo/Cargo.toml b/src/monorepo/Cargo.toml new file mode 100644 index 0000000..7e6cae6 --- /dev/null +++ b/src/monorepo/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "monorepo" +version = "0.1.0" +edition = "2024" + +[lib] +path = "monorepo.rs" + +[dependencies] diff --git a/src/monorepo/monorepo.rs b/src/monorepo/monorepo.rs new file mode 100644 index 0000000..b91220b --- /dev/null +++ b/src/monorepo/monorepo.rs @@ -0,0 +1 @@ +pub mod workspace; diff --git a/src/monorepo/workspace.rs b/src/monorepo/workspace.rs new file mode 100644 index 0000000..1a81a32 --- /dev/null +++ b/src/monorepo/workspace.rs @@ -0,0 +1,20 @@ +use std::path::PathBuf; + +pub fn resolve_workspace_path(path: PathBuf) -> PathBuf { + resolve_workspace_path_impl( + path, + std::env::var_os("BUILD_WORKSPACE_DIRECTORY").map(PathBuf::from), + ) +} + +fn resolve_workspace_path_impl(path: PathBuf, workspace: Option) -> PathBuf { + if path.is_absolute() { + return path; + } + + if let Some(workspace) = workspace { + return workspace.join(path); + } + + path +} diff --git a/src/monorepo/workspace_test.rs b/src/monorepo/workspace_test.rs new file mode 100644 index 0000000..6201822 --- /dev/null +++ b/src/monorepo/workspace_test.rs @@ -0,0 +1,52 @@ +use std::path::PathBuf; + +use monorepo::workspace::resolve_workspace_path; + +const BUILD_WORKSPACE_DIRECTORY: &str = "BUILD_WORKSPACE_DIRECTORY"; + + +#[derive(Debug)] +struct Case { + name: &'static str, + workspace: Option<&'static str>, + path: &'static str, + expected: &'static str, +} + +#[test] +fn resolve_workspace_path_cases() { + let cases = [ + Case { + name: "absolute path returns unchanged path", + workspace: Some("/workspace"), + path: "/tmp/output", + expected: "/tmp/output", + }, + Case { + name: "relative path joins workspace path", + workspace: Some("/workspace"), + path: "output/graph", + expected: "/workspace/output/graph", + }, + Case { + name: "relative path without workspace returns unchanged path", + workspace: None, + path: "output/graph", + expected: "output/graph", + }, + ]; + + for case in cases { + unsafe { + if let Some(workspace) = case.workspace { + std::env::set_var(BUILD_WORKSPACE_DIRECTORY, workspace); + } else { + std::env::remove_var(BUILD_WORKSPACE_DIRECTORY); + } + } + + let resolved = resolve_workspace_path(PathBuf::from(case.path)); + + assert_eq!(resolved, PathBuf::from(case.expected), "{}", case.name); + } +} -- 2.47.3 From 498d0dd467c985584bcbb98a29491f61a440d775 Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 17 Sep 2026 09:57:17 -0400 Subject: [PATCH 3/3] docs: update project todo list --- docs/TODO.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/TODO.md b/docs/TODO.md index 157d245..2ff2f1b 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -3,6 +3,8 @@ - machoke - falinks - dotfiles +- xatu +- nix-style / refactor # project ideas @@ -18,8 +20,8 @@ - amazon / actualbudget exporter - vim-obsidian-markdown - dictionary cli tool -- repo-local Nix style linter - kitchen.md +- Rust project creator # migration @@ -102,6 +104,9 @@ - better remote deployment - expose remote deployment as a flake app, replacing the Fish-only `deploy-to` workflow - centralize shared system group names, starting with the `storage` group +- Investigate Rust Bazel target structure. + Prefer clear per-file dependency edges, but `rust_library` maps each target to a crate. + Decide whether wrapper rules or another pattern can improve graph clarity without forcing artificial crate boundaries. ## nix refactor @@ -109,9 +114,9 @@ Review Nix files in entrypoint order: - [x] `flake.nix` - [x] `src/dotfiles/default.nix` -- [ ] `src/dotfiles/util.nix` -- [ ] `src/dotfiles/formatter.nix` -- [ ] `src/dotfiles/apps.nix` +- [x] `src/dotfiles/util.nix` +- [x] `src/dotfiles/formatter.nix` +- [x] `src/dotfiles/apps.nix` - [ ] `src/dotfiles/registry.nix` - [ ] `configs/nixos/registry/address.nix` - [ ] `configs/nixos/registry/env-var.nix` -- 2.47.3