aiperf
Copilot instructions839 starsChanged 51 days agoApache-2.0View on GitHub
Python 3.11+ async AI benchmarking tool for measuring LLM inference server performance. 10 services communicate via ZMQ message bus. Reference documentation: - docs/architecture.md - Three-plane architecture, core components, credit system, data flow, communication patterns - docs/dev/patterns.md - Code examples for CLI commands, services, models, messages, plugins, error handling, logging, testing - docs/cli-options.md - Complete CLI command and option reference - docs/environment-variables.md - All AIPERF_* environment variables by subsystem - docs/metrics-reference.md - Metric definitions, formulas, and requirements - docs/plugins/plugin-system.md - Plugin…
- Reads credentials
We split this copilot-instructions.md into the rules it gives an agent
15 rules. About 0 are common, 6 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 31
Always orjson.loads(s), orjson.dumps(d) for JSON.
- Distinctive: line 37
Use mermaid diagrams instead of ASCII art in markdown files.
- Distinctive: line 38
Do not create markdown files to document code changes or decisions.
- Distinctive: line 39
Do not over-comment code. Removing code is fine without adding comments to explain why.
- Distinctive: line 41
No emojis in code or comments.
- Distinctive: line 71
Run pre-commit after every code change, even before creating commits:
- Very specific: line 82
Create class extending BaseComponentService with @on_message handlers
- Very specific: line 84
Add message type to common/enums/enums.py if new messages needed
- Very specific: line 85
Create message class in messages/ with message_type field
- Very specific: line 90
Add enum value to MessageType in common/enums/enums.py
- Very specific: line 91
Create message class in messages/ inheriting from Message with message_type field set
- Very specific: line 92
Add @on_message(MessageType.X) handler in the receiving service
- Distinctive: line 97
Create plugin class implementing the appropriate base
- Very specific: line 98
Add entry to src/aiperf/plugin/plugins.yaml with class, description, metadata
- Very specific: line 146
Use from pytest import param and put # fmt: skip on the ) line:
≈ “Common” is an estimate: at least 1 in 5 of the 3,669 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!--
SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->AIPerf
Python 3.11+ async AI benchmarking tool for measuring LLM inference server performance. 10 services communicate via ZMQ message bus.
Reference documentation:
docs/architecture.md- Three-plane architecture, core components, credit system, data flow, communication patternsdocs/dev/patterns.md- Code examples for CLI commands, services, models, messages, plugins, error handling, logging, testingdocs/cli-options.md- Complete CLI command and option referencedocs/environment-variables.md- AllAIPERF_*environment variables by subsystemdocs/metrics-reference.md- Metric definitions, formulas, and requirementsdocs/plugins/plugin-system.md- Plugin architecture, categories, creation guideCONTRIBUTING.md- Development setup, available commands, pre-commit hooks, DCO
Coding Standards
- async/await for ALL I/O - no
time.sleep, no blocking calls. Field(description="...")on EVERY Pydantic field. Docstrings on dataclass fields.- Type hints on ALL functions (params and return).
- KISS + DRY: minimal code, optimize for reader.
AIPerfBaseModelfor data,BaseConfigfor configuration.@dataclass(slots=True)for hot-path inner models created at high volume (e.g. SSE chunks, parsed responses) where Pydantic overhead matters. Use__pydantic_config__ = ConfigDict(extra="forbid")on dataclasses that participate in Pydantic union discrimination.BaseComponentServicefor services,BaseServicefor SystemController only.- Message bus for inter-service communication - no shared mutable state.
- CLI commands: one file per command in
cli_commands/, lazily loaded via import strings incli.py. Seedocs/dev/patterns.md. - YAML plugin registry for extensible features (
src/aiperf/plugin/plugins.yaml). - Lambda for expensive logs:
self.debug(lambda: f"{self._x()}"). Direct string for cheap ones. - Always
orjson.loads(s),orjson.dumps(d)for JSON. - Reading filesystem paths: use
aiperf.common.path_safety.safe_read_template_pathinstead of inlinePath().read_text()/open().read(). ReturnsNoneon safety-check failure; caller picks the fallback semantic. Seedocs/dev/patterns.md§ "Safe Filesystem Reads Pattern". - No
Optional[X]orUnion[X, Y]- useX | Y. - Comments only for "why?" not "what".
- Enums are string-based - use
MessageType.Xdirectly, never.value. - Dependencies: always use
uv(never pip) -uv add package,uv run pytest. - Use mermaid diagrams instead of ASCII art in markdown files.
- Do not create markdown files to document code changes or decisions.
- Do not over-comment code. Removing code is fine without adding comments to explain why.
- Multi-line docstrings are permitted. Use them when the behavior is non-obvious.
- No emojis in code or comments.
- Hide a metric from the console table with
console_group = MetricConsoleGroup.NONE; group it into a separate section withMetricConsoleGroup.{USAGE,CACHE,PREDICTION,AUDIO,REASONING,SPEC_DECODE,GPU_POWER_EFFICIENCY_NVIDIA,GPU_POWER_EFFICIENCY_AMD}. Default isDEFAULT. Seedocs/metrics-reference.md"Metric Console Group Reference". - Platform-conditional code MUST branch on
IS_WINDOWS/IS_MACOS/IS_LINUXfromaiperf.common.constants, never onplatform.system()directly. The constants are evaluated once at import time, are uniformly greppable, and produce smaller diffs. Seesrc/aiperf/common/bootstrap.pyandsrc/aiperf/config/comm/ipc.pyfor canonical examples.
NaN/Inf Discipline
Numeric metric values crossing a serialization boundary or feeding a numerical algorithm must be finite or explicitly None. Use aiperf.common.finite (FiniteFloat, scrub_non_finite, nan_safe_mean/std, is_finite_value). Mechanical CI invariants in tests/unit/property/test_finite_invariants.py reject new violations and ratchet existing debt to zero via baseline files. See docs/dev/patterns.md § "NaN/Inf Discipline Pattern" and docs/dev/global-invariants.md for the full contract.
CLI Flag Routing Under --config
A CLI flag passed alongside --config MUST either change the resolved config or raise an error naming the flag — never be silently ignored, which for a benchmarking tool means publishing numbers that do not match what was asked for. CLIConfig is the source of truth, structurally: resolve_config receives a CLIConfig and a path and nothing else, so a flag reaches AIPerfConfig only by being a field on it. Every field must be classified in src/aiperf/config/flags/_config_flag_routing.py as ROUTED_UNDER_CONFIG, UNROUTED_UNDER_CONFIG, EXEMPT_FROM_CONFIG_ROUTING, or one of the conditional sets (COMPANION_ROUTED, MAGIC_LIST_ONLY_UNDER_CONFIG). Adding a flag without classifying it fails test_every_cli_config_field_is_classified; claiming a flag is routed when nothing routes it fails test_routed_field_never_silently_no_ops. Prefer routing the flag (check whether a builder already exists) over listing it as unrouted. See docs/dev/global-invariants.md § "CLI flag routing under --config".
Build and Test Commands
make first-time-setup # Initial environment setup
make install # Install project + mock server
uv run pytest tests/unit/ -n auto # Unit tests (fast, isolated)
uv run pytest -m integration -n auto # Integration tests (real services, multiprocess)
uv run pytest -m component_integration -n auto # Component integration tests (single process)
ruff format . && ruff check --fix . # Format and lint
make validate-plugin-schemas # Validate plugin registry
pre-commit run # Pre-commit on staged files
pre-commit run --all-files # Pre-commit on all files
make generate-all-docs # Regenerate CLI + env var docs
make generate-all-plugin-files # Regenerate plugin enums, overloads, schemasPre-Commit Hooks
Run pre-commit after every code change, even before creating commits:
pre-commit run # Staged files only
pre-commit run --all-files # All files (recommended after significant changes)Hooks: check-ast, debug-statements, detect-private-key, check-added-large-files, check-case-conflict, check-executables-have-shebangs, check-merge-conflict, check-json, check-toml, check-yaml, check-shebang-scripts-are-executable, end-of-file-fixer, mixed-line-ending, no-commit-to-branch, requirements-txt-fixer, trailing-whitespace, codespell, add-license, generate-cli-docs, generate-env-vars-docs, generate-plugin-artifacts, validate-plugin-schemas, test-imports, check-agent-files-sync, check-ergonomics, check-ruff-baselined, ruff, ruff-format.
Adding a New Service
- Create class extending
BaseComponentServicewith@on_messagehandlers - Register in
src/aiperf/plugin/plugins.yamlunderservicecategory withclass,description,metadata - Add message type to
common/enums/enums.pyif new messages needed - Create message class in
messages/withmessage_typefield - Validate with
aiperf plugins --validate
Adding a New Message
- Add enum value to
MessageTypeincommon/enums/enums.py - Create message class in
messages/inheriting fromMessagewithmessage_typefield set - Add
@on_message(MessageType.X)handler in the receiving service - Auto-subscription happens during
@on_initphase
Adding a New Plugin
- Create plugin class implementing the appropriate base
- Add entry to
src/aiperf/plugin/plugins.yamlwithclass,description,metadata - Validate with
make validate-plugin-schemas - Use via
plugins.get_class(PluginType.X, 'name')
Adding a New CLI Flag
See docs/dev/patterns.md § "Adding a New CLI Flag". CLIConfig is flat; never add a nested config class.
Kubernetes
The Kubernetes operator and CLI layer live in src/aiperf/operator/, src/aiperf/kubernetes/, and src/aiperf/cli_commands/kube/. Key patterns:
- kopf handlers — The operator entry point is
src/aiperf/operator/main.py. All@kopf.on.*decorators live there; handler bodies are decorator-free functions insrc/aiperf/operator/handlers/{create,cleanup,completion,lifecycle,monitor}.py. Raisekopf.PermanentErrorto stop retrying,kopf.TemporaryError(..., delay=N)to retry after delay — generic exceptions retry forever. kopf calls handlers with a fixed kwarg set (body, spec, name, namespace, patch, uid, **_: Any); these signatures are baselined againstkeyword-only-argsbecause kopf owns the calling convention. kopf passesbody(andspec/status) askopf.Body-family Mapping views, notdictsubclasses — type-guard handler inputs withcollections.abc.Mapping; anisinstance(body, dict)fence is silently False and turns the handler into a no-op that still reports success. - kubernetes_asyncio access — Always use
async with k8s_client() as api:fromaiperf.kubernetes.client; never instantiateApiClient()directly. The helper handles in-cluster-or-kubeconfig fallback and closure. - Patch content type — Every
patch_*call MUST pass_content_type=explicitly, usingJSON_PATCH_CONTENT_TYPEorMERGE_PATCH_CONTENT_TYPEfromaiperf.kubernetes.constants, and MUST pair a list of RFC 6902 ops with JSON Patch and a dict with merge patch.kubernetes_asynciootherwise selects the first type it advertises — always JSON Patch — so a merge-patch dict ships under an RFC 6902 header and the apiserver answers 400cannot unmarshal object into Go value of type []handlers.jsonPatchOp. Both halves are enforced mechanically bytests/unit/property/test_kube_patch_invariants.py; test fakes must decode patches throughtests.harness.k8s.decode_patch_like_apiserverso a mismatch fails locally instead of only against a real cluster. aiperf kubeCLI — Subcommands live insrc/aiperf/cli_commands/kube/and are registered in_app.py. Composite flags (namespace,kubeconfig,kube-context) pass viaKubeManageOptionsfromaiperf.config.kube.- FastAPI routers — Two patterns: module-level
router = APIRouter(...)insrc/aiperf/api/routers/*.py, and factorycreate_xxx_router(deps...) -> APIRouterinsrc/aiperf/operator/routers/jobs.pywhen the router closes over live state. - Shellouts — Always
aiperf.kubernetes.subproc.run_command(...)/check_command/start_streaming_process+terminate_process; neverasyncio.create_subprocess_execdirectly. 60 s default timeout. - CLI user output — All kube-CLI output goes through
from aiperf.kubernetes import console as kube_console; neverprintorrich.print. Last-benchmark persistence (save_last_benchmark) lives there too — do not roll your ownlast_X.json. --output text|json— Read-only CLI checks (preflight, validate) exposeLiteral["text", "json"]; in JSON mode, wrap the work inkube_console.machine_readable_stdout()and emit viakube_console.emit_raw(orjson.dumps(..., option=OPT_INDENT_2).decode()). Result dataclasses own theto_dict()schema.- Machine-readable stdout — Every JSON/YAML payload goes through
kube_console.emit_raw, neverkube_console.console.print: Rich hard-wraps lines wider than the resolved console width (80 without a tty) and the break lands mid-token, so a long image reference makes the document unparseable under redirection.machine_readable_stdout()retargets theaiperf.kubehandlers to stderr rather than filtering by level, so no future log record can prepend text to stdout. Human-facing log text (kube logs, controller log streaming) stays onconsole.printbut must passsoft_wrap=True. Seedocs/dev/patterns.md§ "Machine-Readable Kube CLI Output Pattern". - Benchmark diagnosis —
aiperf kube watchand itsWatchOrchestrator/WatchRenderersplit were removed; the salvaged detectors live insrc/aiperf/kubernetes/benchmark_diagnosis.pyand are consumed byaiperf kube debug. Tunables areAIPERF_K8S_DIAGNOSIS_*. - CRD generator — Both CRDs (
deploy/helm/aiperf-operator/templates/crd-aiperfjob.yamlandcrd-aiperfsweep.yaml) are auto-generated fromAIPerfJobSpec/AIPerfSweepSpecPydantic models bytools/generate_crd.py. Do NOT hand-edit the YAML; runuv run python tools/generate_crd.pyand verify with--check. User-facing validation rule catalog indocs/kubernetes/crd-validation.md. - Durable completion claim — Exactly-once completion work is gated by
await try_claim_completion(...)inoperator/client_cache.py— a JSON-patch with atestop, so concurrent ticks race atomically on the apiserver. The in-process_shutdown_sentset is only a fast path; the CR annotation is authoritative. - Serialized Kubernetes run config — Every service container reads the same controller-rendered
BenchmarkRunthroughaiperf.kubernetes.serialized_run.read_serialized_run_json; never independently resolveCLIConfiginsideaiperf service, because seeds, synthesized defaults, and artifact identity must remain identical across pods. Work the resolver chain would have done must therefore ride inside the serialized run or be rendered from it:artifacts.user_filesis materialized byaiperf.kubernetes.user_files.materialize_serialized_run_user_filesin thesystem_controllercontainer only (the sole container owning the run directory), against theBenchmarkRun.run_metaidentity the operator freezes at create time. - Endpoint credential transport — Serialized
BenchmarkRunand ConfigMap data remain secret-free. Redact endpoint credentials before persistence, inject them only through Secret-backedAIPERF_INJECTED_API_KEY,AIPERF_INJECTED_HEADERS, orAIPERF_INJECTED_ENDPOINT_URLS, and useaiperf.common.endpoint_credentialsfor validation and rehydration. - Operator metrics — Wrap only kopf reconcile handlers with
@track_handler("name")(between the@kopf.*decorator and the function); never instrument helper functions. ServiceRunType.KUBERNETESis a generated plugin enum member: it is declared insrc/aiperf/plugin/plugins.yamland emitted intosrc/aiperf/plugin/enums.pybymake generate-all-plugin-files. Never hand-editsrc/aiperf/plugin/enums.py.- Operator-namespace fallback — code that needs the chart-default operator namespace MUST import
DEFAULT_OPERATOR_NAMESPACEfromaiperf.kubernetes.constants, never hardcode"aiperf-system". Callers with cluster API access should still preferfind_operator_namespace(cluster-wide pod-label search). - Dual-channel credit readiness — credit dispatch rides the DEALER (
CommAddress.CREDIT_ROUTER) but credit returns ride a separate PUSH/PULL fan-in (CommAddress.CREDIT_RETURN). A worker MUST passprobe_return_channel(aiperf.workers.return_channel_probe) before announcingWorkerDispatchable, otherwise a dead PUSH side is invisible and every credit routed there stalls until the run timeout. Any new startup signal must not assume the DEALER proves both directions. Seedocs/dev/kubernetes-flow.md§ "Dual-Channel Credit Readiness Gate".
For complete implementation details see docs/dev/kubernetes-flow.md.
Parameter Sweeping (Kubernetes)
In-process sweeps and adaptive search are documented in main's docs/sweeping/ tutorials. The Kubernetes-side path is:
- Cluster sweep —
AIPerfSweepCRD +operator/handlers/sweep/. The k8s operator owns the cluster-wide cardinality contract: oneAIPerfJob(and one controller pod) per variation; each child pod sees a single-config plan. Best for parallelism across nodes and restart durability. - Adaptive outer loop (BO) under the operator — the sweep-controller pod in
sweep_controller/main.pyinstantiates the sameBayesianSearchPlannerplugin the in-process path uses; the K8s executor creates oneAIPerfJobper iteration. kopf-side handlers stay BO-agnostic. - Mutual-exclusion gate — when
AIPERF_OPERATOR_MANAGED=1is set in a controller pod,cli_runner._reject_in_process_sweep_under_operatorhard-fails anyplan.is_sweepto keep both layers from sweeping at once. - Mode dispatch —
MultiRunOrchestrator.executedispatches onplan.is_adaptive_search, then on the grid sweep's iteration order (_plan_iteration_order(plan)→SweepMode.REPEATED/INDEPENDENT). The k8s sweep_controller's children-manifest walk insweep_controller/main.pymirrors the same idx → (var,trial) derivation.
Testing Conventions
@pytest.mark.asynciofor async tests,@pytest.mark.parametrizefor data-drivenfrom tests.harness import mock_pluginfor plugin mocking- Name:
test_<function>_<scenario>_<expected>e.g.test_parse_config_missing_field_raises_error - Imports at file top, fixtures for setup, one focus per test
- Use
from pytest import paramand put# fmt: skipon the)line:@pytest.mark.parametrize( "arg", [ param(..., id="case1"), param(..., id="case2"), ], ) # fmt: skip - Auto-fixtures (always active): asyncio.sleep runs instantly, RNG=42, singletons reset between tests
Git Workflow
Feature branches use <username>/feature-name format, forked from main. One PR = one concern.
Tips
- SystemController uses
BaseService(notBaseComponentService) - it's the orchestrator. - Worker/TimingManager disable GC for latency - see
service_metadata.disable_gc. - macOS child processes close terminal FDs to prevent Textual UI corruption.
- Plugin priority resolves conflicts: higher wins, external beats built-in at equal priority.
- Decorators:
@on_init,@on_start,@on_stop,@on_message,@on_command,@background_task,@on_pull_message,@on_request. - Communication:
publish()for broadcast,@on_messageto subscribe,send_command_to_controller()(services) /_send_control_command*()(controller) for commands on the DEALER/ROUTER control channel. - Control channel — commands, registration, heartbeats, and lifecycle status ride a DEALER/ROUTER socket at
CommAddress.CONTROLcarryingmsgspecstructs fromaiperf.common.control_structs, not the pub/sub event bus.@on_commandhandlers take aCommandand decodemessage.payloadwithorjson. ReturningNonesendsCommandAck; a value sendsCommandOk; no matching hook sendsCommandUnhandled, which callers may treat as a failure. The event bus still carries every other message type. Seedocs/dev/patterns.md§ "Control Channel Command Pattern". AIPerfLifecycleMixinfor standalone components:CREATED->INITIALIZING->INITIALIZED->STARTING->RUNNING->STOPPING->STOPPED;FAILEDterminal.dag_jsonlinput type: conversation DAG benchmarks (fork + spawn modes). Seedocs/benchmark-modes/dag.mdfor abstractions and authoring.- Validator gate convention: unsupported constructs raise
NotImplementedErrorwith a leading"<loc>: <reason>"prefix where<loc>identifies the conversation/turn (e.g."conversation 'foo' turn 3: ..."). New validators must follow this shape. - Per-turn payload contract:
extra_body/max_tokens/modelare dispatch-turn only;raw_toolsis the lone field that walks history (system-prompt-like). Dataset rows authorextra, notextra_body. Seedocs/dev/patterns.md"Per-turn datasetextra".
Plot Envelope Section
AIPerfConfig.plot: PlotEnvelopeConfig | None lets a single AIPerf YAML own its
visualization. Two forms: bare-string path (plot: ./plots/baseline.yaml,
resolved relative to the AIPerf YAML's dir) or inline dict mirroring
src/aiperf/plot/default_plot_config.yaml. When set, ~/.aiperf/plot_config.yaml
is ignored and artifacts.auto_plot flips to True (unless explicitly False).
The auto-plot callback materializes the resolved envelope to
<artifact_dir>/.aiperf-plot-config.yaml so aiperf plot <dir> reproduces.
See src/aiperf/config/plot.py for the Pydantic models.
Pre-Commit Checklist
- Review diff: all lines required?
ruff format . && ruff check --fix .uv run pytest tests/unit/ -n autouv run pytest tests/unit/property/ -n auto(mechanical NaN/inf and field-validator invariants)- Type hints on all functions
Field(description=...)on all Pydantic fieldsgit commit -s
Four-File Sync Rule
AGENTS.md, CLAUDE.md, .github/copilot-instructions.md, and .cursor/rules/python.mdc must contain identical content (only headers/frontmatter differ). When updating one, update all four. Run make check-agent-files-sync after editing to confirm sync — pre-commit enforces this on every commit that touches one of these files.
Documentation Updates
DOCUMENTATION IS REQUIRED, NOT OPTIONAL. Any PR that adds or changes a feature, CLI option, env var, plugin, message type, or service without updating the relevant docs is incomplete and will not be merged.
When making changes, update the appropriate documentation files using the table below. When adding a new tutorial, also add it to README.md's tutorial index. Any new file under docs/ must also be added to docs/index.yml (the Fern site index) — tools/check_docs_index.py enforces this in CI. If the change is internal-only and not user-facing (e.g. developer reference, internal mechanics, debugging notes), put the doc under docs/reference/ rather than skipping documentation.
| Change type | Files to update |
| Architecture, components, data flow, communication | docs/architecture.md |
| Coding standards, build commands, new patterns | AGENTS.md + CLAUDE.md + .github/copilot-instructions.md + .cursor/rules/python.mdc |
| Code patterns, examples, base classes | docs/dev/patterns.md |
| CLI arguments or commands | docs/cli-options.md (auto-generated via make generate-cli-docs) |
| Environment variables | docs/environment-variables.md (auto-generated via make generate-env-vars-docs) |
| Metrics definitions or formulas | docs/metrics-reference.md |
| Plugin system, categories, creation | docs/plugins/plugin-system.md |
| Accuracy benchmarks, graders | docs/accuracy/ |
| Server metrics, schemas | docs/server-metrics/ |
| Benchmark modes, timing, traces | docs/benchmark-modes/ |
| Tokenizer, reference docs | docs/reference/ |
| Dataset synthesis API | docs/api/synthesis.md |
| Dev setup, make targets, pre-commit | CONTRIBUTING.md |
| Contribution process, DCO | CONTRIBUTING.md |
| New services, message types, plugin types | docs/architecture.md + docs/dev/patterns.md |
| Kubernetes operator, handlers, CR lifecycle | docs/dev/kubernetes-flow.md |
| Kubernetes deployment, Helm chart, cluster setup | docs/kubernetes/getting-started.md + docs/kubernetes/configuration.md + docs/kubernetes/production.md + docs/kubernetes/workflow.md |
| Kube preflight checks / validate / debug | docs/kubernetes/preflight.md + docs/kubernetes/validate.md + docs/kubernetes/debug-command.md |
| Operator HTTP API / web dashboard | docs/kubernetes/results-api.md + docs/kubernetes/dashboard-ui.md |
| Sweeps on Kubernetes | docs/tutorials/sweeps.md#running-sweeps-on-kubernetes |
| Tutorials and feature guides | docs/tutorials/ + README.md tutorial index |
A feature is incomplete until documentation is updated.
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,297 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository13 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/python.mdcCursor rule
- aiperf-code-reviewSkill
- aiperf-kube-runSkill
- aiperf-kube-setupSkill
- aiperf-kube-sweepSkill
- aiperf-kube-triageSkill
- aiperf-llm-ergonomics-reviewSkill
- bump-versionSkill
- cherry-pickSkill
- docs-to-fernSkill
- linear-issueSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

