feat: upgrade the lib interface
This commit is contained in:
48
skills/repo-lib-consumer/SKILL.md
Normal file
48
skills/repo-lib-consumer/SKILL.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: repo-lib-consumer
|
||||
description: Edit or extend repos that consume `repo-lib` through `repo-lib.lib.mkRepo`, `mkDevShell`, or `mkRelease`. Use when Codex needs to add or change tools, shell packages, checks or test phases, formatters, release steps, release channels, bootstrap hooks, or release automation in a Nix flake built on repo-lib.
|
||||
---
|
||||
|
||||
# Repo Lib Consumer
|
||||
|
||||
Use this skill to make idiomatic changes in a repo that already depends on `repo-lib`.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Detect the integration style.
|
||||
Search for `repo-lib.lib.mkRepo`, `repo-lib.lib.mkDevShell`, `repo-lib.lib.mkRelease`, or `inputs.repo-lib`.
|
||||
|
||||
2. Prefer the repo's current abstraction level.
|
||||
If the repo already uses `mkRepo`, stay on `mkRepo`.
|
||||
If the repo still uses `mkDevShell` or `mkRelease`, preserve that style unless the user asked to migrate.
|
||||
|
||||
3. Load the right reference before editing.
|
||||
Read `references/api.md` for exact option names, defaults, generated outputs, and limitations.
|
||||
Read `references/recipes.md` for common edits such as adding a tool, adding a test phase, wiring release file updates, or handling webhooks.
|
||||
|
||||
4. Follow repo-lib conventions.
|
||||
Add bannered CLIs through `perSystem.tools`, not `shell.packages`.
|
||||
Use `shell.packages` for packages that should be present in the shell but not shown in the banner.
|
||||
Keep shells pure-first; only use `bootstrap` with `allowImpureBootstrap = true`.
|
||||
Prefer structured `release.steps` over free-form shell when the task fits `writeFile` or `replace`.
|
||||
|
||||
5. Verify after edits.
|
||||
Run `nix flake show --json`.
|
||||
Run `nix flake check` when feasible.
|
||||
If local flake evaluation cannot see newly created files because the repo is being loaded as a git flake, stage the new files before rerunning checks.
|
||||
|
||||
## Decision Rules
|
||||
|
||||
- Prefer `repo-lib.lib.tools.fromPackage` for tools with explicit metadata.
|
||||
- Use `repo-lib.lib.tools.simple` only for very simple `--version` or `version` probes.
|
||||
- Put pre-commit and pre-push automation in `checks`, not shell hooks.
|
||||
- Treat `postVersion` as pre-tag and pre-push. It is not a true post-tag hook.
|
||||
- For a webhook that must fire after the tag exists remotely, prefer CI triggered by tag push over local release command changes.
|
||||
|
||||
## References
|
||||
|
||||
- `references/api.md`
|
||||
Use for the exact consumer API, option matrix, generated outputs, release ordering, and legacy compatibility.
|
||||
|
||||
- `references/recipes.md`
|
||||
Use for concrete change patterns: add a tool, add a test phase, update release-managed files, or wire webhook behavior.
|
||||
4
skills/repo-lib-consumer/agents/openai.yaml
Normal file
4
skills/repo-lib-consumer/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Repo Lib Consumer"
|
||||
short_description: "Edit repos that use repo-lib safely"
|
||||
default_prompt: "Use $repo-lib-consumer to update a repo that consumes repo-lib."
|
||||
274
skills/repo-lib-consumer/references/api.md
Normal file
274
skills/repo-lib-consumer/references/api.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# repo-lib Consumer API
|
||||
|
||||
## Detect the repo shape
|
||||
|
||||
Look for one of these patterns in the consuming repo:
|
||||
|
||||
- `repo-lib.lib.mkRepo`
|
||||
- `repo-lib.lib.mkDevShell`
|
||||
- `repo-lib.lib.mkRelease`
|
||||
- `inputs.repo-lib`
|
||||
|
||||
Prefer editing the existing style instead of migrating incidentally.
|
||||
|
||||
## Preferred `mkRepo` shape
|
||||
|
||||
```nix
|
||||
repo-lib.lib.mkRepo {
|
||||
inherit self nixpkgs;
|
||||
src = ./.;
|
||||
systems = repo-lib.lib.systems.default; # optional
|
||||
|
||||
config = {
|
||||
includeStandardPackages = true;
|
||||
|
||||
shell = {
|
||||
env = { };
|
||||
extraShellText = "";
|
||||
allowImpureBootstrap = false;
|
||||
bootstrap = "";
|
||||
};
|
||||
|
||||
formatting = {
|
||||
programs = { };
|
||||
settings = { };
|
||||
};
|
||||
|
||||
checks = { };
|
||||
|
||||
release = null; # or attrset below
|
||||
};
|
||||
|
||||
perSystem = { pkgs, system, lib, config }: {
|
||||
tools = [ ];
|
||||
shell.packages = [ ];
|
||||
checks = { };
|
||||
packages = { };
|
||||
apps = { };
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Generated outputs:
|
||||
|
||||
- `devShells.${system}.default`
|
||||
- `checks.${system}.pre-commit-check`
|
||||
- `formatter.${system}`
|
||||
- `packages.${system}.release` when `config.release != null`
|
||||
- merged `packages` and `apps` from `perSystem`
|
||||
|
||||
## `config.shell`
|
||||
|
||||
Fields:
|
||||
|
||||
- `env`
|
||||
Attrset of environment variables exported in the shell.
|
||||
- `extraShellText`
|
||||
Extra shell snippet appended after the banner.
|
||||
- `bootstrap`
|
||||
Shell snippet that runs before the banner.
|
||||
- `allowImpureBootstrap`
|
||||
Must be `true` if `bootstrap` is non-empty.
|
||||
|
||||
Rules:
|
||||
|
||||
- Default is pure-first.
|
||||
- Do not add bootstrap work unless the user actually wants imperative setup.
|
||||
- Use `bootstrap` for unavoidable local setup only.
|
||||
|
||||
## `config.formatting`
|
||||
|
||||
Fields:
|
||||
|
||||
- `programs`
|
||||
Passed to `treefmt-nix.lib.evalModule`.
|
||||
- `settings`
|
||||
Passed to `settings.formatter`.
|
||||
|
||||
Rules:
|
||||
|
||||
- `nixfmt` is always enabled.
|
||||
- Use formatter settings instead of ad hoc shell formatting logic.
|
||||
|
||||
## Checks
|
||||
|
||||
`config.checks.<name>` and `perSystem.checks.<name>` use this shape:
|
||||
|
||||
```nix
|
||||
{
|
||||
command = "go test ./...";
|
||||
stage = "pre-push"; # or "pre-commit"
|
||||
passFilenames = false;
|
||||
runtimeInputs = [ pkgs.go ];
|
||||
}
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
- `stage = "pre-commit"`
|
||||
- `passFilenames = false`
|
||||
- `runtimeInputs = [ ]`
|
||||
|
||||
Rules:
|
||||
|
||||
- Only `pre-commit` and `pre-push` are supported.
|
||||
- The command is wrapped as a script and connected into `git-hooks.nix`.
|
||||
|
||||
## Tools
|
||||
|
||||
Preferred shape in `perSystem.tools`:
|
||||
|
||||
```nix
|
||||
(repo-lib.lib.tools.fromPackage {
|
||||
name = "Go";
|
||||
package = pkgs.go;
|
||||
exe = "go"; # optional
|
||||
version = {
|
||||
args = [ "version" ];
|
||||
regex = null;
|
||||
group = 0;
|
||||
line = 1;
|
||||
};
|
||||
banner = {
|
||||
color = "CYAN";
|
||||
};
|
||||
required = true;
|
||||
})
|
||||
```
|
||||
|
||||
Helper:
|
||||
|
||||
```nix
|
||||
repo-lib.lib.tools.simple "Nix" pkgs.nix [ "--version" ]
|
||||
```
|
||||
|
||||
Tool behavior:
|
||||
|
||||
- Tool packages are added to the shell automatically.
|
||||
- Banner probing uses absolute executable paths.
|
||||
- `required = true` by default.
|
||||
- Required tool probe failure aborts shell startup.
|
||||
|
||||
Use `shell.packages` instead of `tools` when:
|
||||
|
||||
- the package should be in the shell but not in the banner
|
||||
- the package is not a CLI tool with a stable version probe
|
||||
|
||||
## `config.release`
|
||||
|
||||
Shape:
|
||||
|
||||
```nix
|
||||
{
|
||||
channels = [ "alpha" "beta" "rc" "internal" ];
|
||||
steps = [ ];
|
||||
postVersion = "";
|
||||
runtimeInputs = [ ];
|
||||
}
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
- `channels = [ "alpha" "beta" "rc" "internal" ]`
|
||||
- `steps = [ ]`
|
||||
- `postVersion = ""`
|
||||
- `runtimeInputs = [ ]`
|
||||
|
||||
Set `release = null` to disable the generated release package.
|
||||
|
||||
## Release step shapes
|
||||
|
||||
### `writeFile`
|
||||
|
||||
```nix
|
||||
{
|
||||
writeFile = {
|
||||
path = "src/version.ts";
|
||||
text = ''
|
||||
export const APP_VERSION = "$FULL_VERSION" as const;
|
||||
'';
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `replace`
|
||||
|
||||
```nix
|
||||
{
|
||||
replace = {
|
||||
path = "README.md";
|
||||
regex = ''^(version = ")[^"]*(")$'';
|
||||
replacement = ''\1$FULL_VERSION\2'';
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `run`
|
||||
|
||||
```nix
|
||||
{
|
||||
run = {
|
||||
script = ''
|
||||
curl -fsS https://example.invalid/hook \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"tag":"'"$FULL_TAG"'"}'
|
||||
'';
|
||||
runtimeInputs = [ pkgs.curl ];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Also accepted for compatibility:
|
||||
|
||||
- `{ run = ''...''; }`
|
||||
- legacy `mkRelease { release = [ { file = ...; content = ...; } ... ]; }`
|
||||
|
||||
## Release ordering
|
||||
|
||||
The generated `release` command does this:
|
||||
|
||||
1. Update `VERSION`
|
||||
2. Run `release.steps`
|
||||
3. Run `postVersion`
|
||||
4. Run `nix fmt`
|
||||
5. `git add -A`
|
||||
6. Commit
|
||||
7. Tag
|
||||
8. Push branch
|
||||
9. Push tags
|
||||
|
||||
Important consequence:
|
||||
|
||||
- `postVersion` is still before commit, tag, and push.
|
||||
- There is no true post-tag or post-push hook in current `repo-lib`.
|
||||
|
||||
## Post-tag webhook limitation
|
||||
|
||||
If the user asks for a webhook after the tag exists remotely:
|
||||
|
||||
- Prefer CI triggered by pushed tags in the consuming repo.
|
||||
- Do not claim `postVersion` is post-tag; it is not.
|
||||
- Only extend `repo-lib` itself if the user explicitly wants a new library capability.
|
||||
|
||||
## Legacy API summary
|
||||
|
||||
`mkDevShell` still supports:
|
||||
|
||||
- `extraPackages`
|
||||
- `preToolHook`
|
||||
- `extraShellHook`
|
||||
- `additionalHooks`
|
||||
- old `tools = [ { name; bin; versionCmd; color; } ]`
|
||||
- `features.oxfmt`
|
||||
- `formatters`
|
||||
- `formatterSettings`
|
||||
|
||||
`mkRelease` still supports:
|
||||
|
||||
- `release = [ ... ]` as legacy alias for `steps`
|
||||
- `extraRuntimeInputs` as legacy alias merged into `runtimeInputs`
|
||||
|
||||
When a repo already uses these APIs:
|
||||
|
||||
- preserve them unless the user asked to migrate
|
||||
- do not mix old and new styles accidentally in the same call
|
||||
197
skills/repo-lib-consumer/references/recipes.md
Normal file
197
skills/repo-lib-consumer/references/recipes.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# repo-lib Change Recipes
|
||||
|
||||
## Add a new bannered tool
|
||||
|
||||
Edit `perSystem.tools` in the consuming repo:
|
||||
|
||||
```nix
|
||||
tools = [
|
||||
(repo-lib.lib.tools.fromPackage {
|
||||
name = "Go";
|
||||
package = pkgs.go;
|
||||
version.args = [ "version" ];
|
||||
banner.color = "CYAN";
|
||||
})
|
||||
];
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Do not also add `pkgs.go` to `shell.packages`; `tools` already adds it.
|
||||
- Use `exe = "name"` only when the package exposes multiple binaries or the main program is not the desired one.
|
||||
|
||||
## Add a non-banner package to the shell
|
||||
|
||||
Use `shell.packages`:
|
||||
|
||||
```nix
|
||||
shell.packages = [
|
||||
self.packages.${system}.release
|
||||
pkgs.jq
|
||||
];
|
||||
```
|
||||
|
||||
Use this for:
|
||||
|
||||
- helper CLIs that do not need a banner entry
|
||||
- internal scripts
|
||||
- the generated `release` package itself
|
||||
|
||||
## Add a test phase or lint hook
|
||||
|
||||
For a simple global check:
|
||||
|
||||
```nix
|
||||
config.checks.tests = {
|
||||
command = "go test ./...";
|
||||
stage = "pre-push";
|
||||
passFilenames = false;
|
||||
runtimeInputs = [ pkgs.go ];
|
||||
};
|
||||
```
|
||||
|
||||
For a system-specific check:
|
||||
|
||||
```nix
|
||||
perSystem = { pkgs, ... }: {
|
||||
checks.lint = {
|
||||
command = "bun test";
|
||||
stage = "pre-push";
|
||||
runtimeInputs = [ pkgs.bun ];
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Guidance:
|
||||
|
||||
- Use `pre-commit` for fast format/lint work.
|
||||
- Use `pre-push` for slower test suites.
|
||||
- Prefer `runtimeInputs` over inline absolute paths when the command needs extra CLIs.
|
||||
|
||||
## Add or change formatters
|
||||
|
||||
Use `config.formatting`:
|
||||
|
||||
```nix
|
||||
config.formatting = {
|
||||
programs = {
|
||||
shfmt.enable = true;
|
||||
gofmt.enable = true;
|
||||
};
|
||||
|
||||
settings = {
|
||||
shfmt.options = [ "-i" "2" "-s" "-w" ];
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## Add release-managed files
|
||||
|
||||
Generate a file from the release version:
|
||||
|
||||
```nix
|
||||
config.release.steps = [
|
||||
{
|
||||
writeFile = {
|
||||
path = "src/version.ts";
|
||||
text = ''
|
||||
export const APP_VERSION = "$FULL_VERSION" as const;
|
||||
'';
|
||||
};
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
Update an existing file with a regex:
|
||||
|
||||
```nix
|
||||
config.release.steps = [
|
||||
{
|
||||
replace = {
|
||||
path = "README.md";
|
||||
regex = ''^(version = ")[^"]*(")$'';
|
||||
replacement = ''\1$FULL_VERSION\2'';
|
||||
};
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
## Add a webhook during release
|
||||
|
||||
If the webhook may run before commit and tag creation, use a `run` step or `postVersion`.
|
||||
|
||||
Use a `run` step when it belongs with other release mutations:
|
||||
|
||||
```nix
|
||||
config.release = {
|
||||
runtimeInputs = [ pkgs.curl ];
|
||||
steps = [
|
||||
{
|
||||
run = {
|
||||
script = ''
|
||||
curl -fsS https://example.invalid/release-hook \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"version":"'"$FULL_VERSION"'"}'
|
||||
'';
|
||||
runtimeInputs = [ pkgs.curl ];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
```
|
||||
|
||||
Use `postVersion` when the action should happen after all `steps`:
|
||||
|
||||
```nix
|
||||
config.release.postVersion = ''
|
||||
curl -fsS https://example.invalid/release-hook \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"version":"'"$FULL_VERSION"'","tag":"'"$FULL_TAG"'"}'
|
||||
'';
|
||||
config.release.runtimeInputs = [ pkgs.curl ];
|
||||
```
|
||||
|
||||
Important:
|
||||
|
||||
- Both of these still run before commit, tag, and push.
|
||||
- They are not true post-tag hooks.
|
||||
|
||||
## Add a true post-tag webhook
|
||||
|
||||
Do not fake this with `postVersion`.
|
||||
|
||||
Preferred approach in the consuming repo:
|
||||
|
||||
1. Keep local release generation in `repo-lib`.
|
||||
2. Add CI triggered by tag push.
|
||||
3. Put the webhook call in CI, where the tag is already created and pushed.
|
||||
|
||||
Only change `repo-lib` itself if the user explicitly asks for a new local post-tag capability.
|
||||
|
||||
## Add impure bootstrap work
|
||||
|
||||
Only do this when the user actually wants imperative shell setup:
|
||||
|
||||
```nix
|
||||
config.shell = {
|
||||
bootstrap = ''
|
||||
export GOBIN="$PWD/.tools/bin"
|
||||
export PATH="$GOBIN:$PATH"
|
||||
'';
|
||||
allowImpureBootstrap = true;
|
||||
};
|
||||
```
|
||||
|
||||
Do not add bootstrap work for normal Nix-packaged tools.
|
||||
|
||||
## Migrate a legacy consumer to `mkRepo`
|
||||
|
||||
Only do this if requested.
|
||||
|
||||
Migration outline:
|
||||
|
||||
1. Move repeated shell/check/formatter config into `config`.
|
||||
2. Move old banner tools into `perSystem.tools`.
|
||||
3. Move extra shell packages into `perSystem.shell.packages`.
|
||||
4. Replace old `mkRelease { release = [ ... ]; }` with `config.release.steps`.
|
||||
5. Keep behavior the same first; do not redesign the repo in the same change unless asked.
|
||||
Reference in New Issue
Block a user