fabricatio-skill
An extension of fabricatio.
Installation
This package is part of the fabricatio monorepo and can be installed as an optional dependency:
pip install fabricatio[skill]
# or with uv
# uv pip install fabricatio[skill]
Or install fabricatio-skill along with all other components of fabricatio:
pip install fabricatio[full]
# or with uv
# uv pip install fabricatio[full]
Overview
A text-based skill system for fabricatio agents. Skills are plain markdown files
(YAML frontmatter name/description/tags + markdown body) that inject
just-in-time, task-relevant context into LLM prompts through progressive
disclosure: cheap metadata first, LLM-powered selection next, distilled
essence last — never the full corpus.
Exclusion is just as progressive: a deterministic Rust keyword pre-filter thins oversized pools before any LLM sees them, selection admits only catalog-validated candidates (capped), and distillation drops everything the question does not need. Content that fails an earlier stage never reaches a later prompt.
Key Features
- Markdown-native skills — author skills as
.mdfiles with YAML frontmatter; no schema lock-in beyond three metadata keys. - Two library layouts — per root, skills resolve either by the agent-skills convention (
<name>/SKILL.md) or as flat files (<name>.md); the library loads the cross-client.agents/skillslocations (project +~), plus anyextra_skill_dirsyou configure. - By-name gathering —
gather_skills(names, dirs=None)resolves skills straight from the lookup roots by name (direct path reads, no corpus scan), loads them into the library, and tracks them on the role. - Progressive pipeline — Level 0 (library): the process-wide
SkillRegistry— recursive scanning (load_scanned), by-name resolution (load_by_name), keyword search (SkillRegistry.search, also the deterministic pre-filter for huge libraries); Level 1 (Python): LLM-powered relevance selection (select_skills, delegated to the frameworkUseLLM.achoosechooser over skill briefings — set-validated, auto-retried, SMOL tier, capped) and essence distillation (distill_skills); Level 2: the composedconsult_skillspipeline (select -> distill -> consulted knowledge). Consultation only — answering stays in your Action. - Progressive disclosure dial — every call trades fidelity for tokens via
select=/distill=/ forcednames=. - Lightweight composition — heavy
Skillobjects live in the process-wide library (get_skill_registry(), reachable from a role asrole.skill_library); your roles/actions carry only a list of name handles, and the loaders (scan_skills,gather_skills,add_skills) chain on the role. - Rust-backed performance — parsing, lookup, and keyword matching are PyO3 (
fabricatio_skill.rust).
Usage
1. Author skill files
Drop markdown files into a skill directory. The default roots are the
cross-client ones only — .agents/skills (project) and ~/.agents/skills
(user), the location the Agent Skills standard tells
every host to read. Each root supports both layouts — the agent-skills
directory convention and flat files:
.agents/skills/
├── rust-async/SKILL.md # <name>/SKILL.md layout
└── code_review.md # <name>.md layout
---
name: rust-async
description: "How to write async Rust with tokio correctly"
tags: [rust, async]
---
Markdown body with the actual instructions...
Frontmatter notes:
nameis the unique catalog id (the LLM selects by it);descriptionis the whole selection surface — keep it a dense one-liner;tagshelp the Rust keyword pre-filter.- YAML rules apply: quote string values that contain
:(e.g. descriptions), or the field silently parses as empty.
2. Consult — zero-config (canonical path)
Nothing to load. The process-wide library is created already loaded from the
cross-client directories (.agents/skills under the process working directory,
plus the user-level ~/.agents/skills) and from extra_skill_dirs; a role that
loaded no names of its own consults the whole library. Authoring files and
consulting is the whole loop:
from fabricatio import Action, Event, Role, Task, WorkFlow
from fabricatio_skill import UseSkill
class AnswerWithSkills(Action, UseSkill):
"""Answer the task briefing grounded in consulted skill knowledge."""
output_key: str = "task_output"
async def _execute(self, task_input: Task[str], **_) -> str:
# select relevant skills -> distill what they say (both SMOL tier);
# "" when nothing is relevant. Answering stays YOUR job.
knowledge = await self.consult_skills(task_input.briefing)
if not knowledge:
return task_input.briefing
return await self.aask(f"{knowledge}\n\n---\n\n{task_input.briefing}")
role = (
Role.with_bio(name="skilled", description="answers using the skill library")
.subscribe(
Event.quick_instantiate("ask"),
WorkFlow(name="skill_qa", steps=(AnswerWithSkills,)),
)
.dispatch()
)
# dispatch a Task whose briefing is the question to Event "ask" — done
Need the library without consulting anything? A role that tracked nothing resolves the whole library, and the handle is always at hand:
self.skills # the role's pool as Skill objects (the library, when nothing was tracked)
self.skill_library.names() # every name the library holds right now
self.skill_library.get("rust-async") # one skill by exact name, or None
The library comes from get_skill_registry(), created once per process: it loads
the cross-client roots — fixed on the Rust side, with ~ expanded and absent
roots skipped — plus extra_skill_dirs.
Client-specific locations (.claude/skills, a bundled skills/ dir, …) are
deliberately not part of the standard roots. Load them explicitly —
scan_skills(".claude/skills"), gather_skills([...], dirs=[...]), or list them
in extra_skill_dirs to search them process-wide.
3. Tune the disclosure level per call
consult_skills() is the progressive-disclosure dial; it returns what the
relevant skills say (or "" when nothing is relevant — a "[]" selection
from the LLM, an exhausted selection retry, or an empty library all mean the
same thing: there is nothing to consult):
| Call | Returns |
|---|---|
await self.consult_skills(q) |
Distilled essence of LLM-selected skills (2 extra LLM calls on the SMOL tier). |
await self.consult_skills(q, k=3) |
Same, but this call fetches at most 3 skills (k=0 = no limit, k=None = the max_selected_skills config). |
await self.consult_skills(q, names=["rust-async"]) |
Forced skills — skips LLM selection entirely. |
await self.consult_skills(q, distill=False) |
Full bodies of selected skills — no compression call. |
await self.consult_skills(q, select=False, distill=False) |
Every registered skill verbatim — zero LLM calls. |
For finer control, step through the levels manually:
picked = await agent.select_skills(question) # metadata-only chooser
if picked: # None = LLM never answered validly
essence = await agent.distill_skills(question, picked) # compress only selected bodies
answer = await agent.aask(f"{essence}\n\n---\n\n{question}")
else:
answer = question # nothing relevant: no skill context
What the LLM sees at each stage (progressive exclusion in action):
- SELECT — the framework
UseLLM.achoosechooser lists every candidate by its briefing (name: description; bodies never enter this prompt) and asks for a JSON array of catalog names. The reply is parsed as a set: unknown names are ignored, duplicates collapse, unparseable replies are retried automatically (up to 3 attempts). A deterministic keyword search (SkillRegistry.search(..., names=<the role's pool>)) pre-filters the pool first when it exceedsprefilter_threshold, and the result is trimmed tomax_selected_skills(or the per-callk). - DISTILL — only the selected skills' bodies enter this prompt, with the instruction to extract just the parts relevant to the question and discard everything else.
4. Explicit loading — custom directories & the registry
Skip the auto-load by loading skills yourself. The loaders chain, and re-running one is safe: a name already in the library keeps its first copy, and the loader reports it again rather than re-reading the file, so the role tracks it either way:
from fabricatio import Action, Task
from fabricatio_skill import UseSkill
class AnswerWithTeamSkills(Action, UseSkill):
"""Answer using skills from a non-default directory."""
output_key: str = "task_output"
async def _execute(self, task_input: Task[str], **_) -> str:
# scan the custom root, then resolve two names against it
self.scan_skills("team-skills").gather_skills(["security", "review"], dirs=["team-skills"])
knowledge = await self.consult_skills(task_input.briefing)
...
add_skills(skills) registers Skill objects you parsed yourself.
5. Gather directly by name
When you already know which skills you want, skip scanning entirely:
gather_skills resolves each name through the lookup roots — trying
<dir>/<name>/SKILL.md first, then <dir>/<name>.md (direct path reads, no
directory walk) — registers the hits, and tracks them on the role.
Unresolvable names are skipped, not raised: the library reports them in one
warning naming every root it searched, so an all-miss call simply tracks
nothing. With no dirs=, the lookup roots are the cross-client ones plus
extra_skill_dirs, so the agent-skills library is available with zero
configuration:
from fabricatio import Action, Task
from fabricatio_skill import UseSkill
class AnswerWithNamedSkills(Action, UseSkill):
"""Answer using two explicitly gathered skills."""
output_key: str = "task_output"
async def _execute(self, task_input: Task[str], **_) -> str:
self.gather_skills(["rust-async", "code_review"]) # by name, no scan
knowledge = await self.consult_skills(task_input.briefing)
return await self.aask(f"{knowledge}\n\n---\n\n{task_input.briefing}")
Pass dirs=[...] to resolve against custom libraries instead of the standard
roots (~ is expanded by the library). Without a role, the same resolution goes
straight through the library: load_by_name returns the names it made available.
On a role or action, the library is the skill_library property, so
role.skill_library.search("async", names=role.skill_names) searches exactly
the pool the role consults.
The library is also exposed for framework-free pipelines: SkillRegistry() is a
bare handle over the same process-wide store, and get_skill_registry() is the
instance loaded from the standard roots plus the extra ones:
from fabricatio_skill import SkillRegistry
library = SkillRegistry() # process-wide: one copy per name
scanned = library.load_scanned([".agents/skills"]) # parse every .md file under a root
library.load_skill_dirs(["~/my-skills"]) # the standard roots + these extras
wanted = library.load_by_name(["rust-async"], [".agents/skills"]) # resolve by name (no walk)
library.search("async", names=wanted, in_content=True) # keyword search over that pool
library.get("rust-async") # one loaded skill, or None
library.remove(["rust-async"]) # free the name; next load re-reads it
Both loaders return the names they made available — a name already in the
library is reported too, never read a second time — which is how the role-level
scan_skills/gather_skills track what they loaded. load_scanned is strict
(a missing root raises FileNotFoundError), while load_by_name and
load_skill_dirs are lenient: unresolved names and absent roots are skipped, and
load_by_name reports the names nothing resolved in one warning naming the roots
it searched; add, remove, and clear return the library for chaining.
Configuration
All options below are read through the fabricatio configuration chain (see the
Configuration Guide at ../../docs/source/configuration.rst). Set them under the
[ext.skill] table in fabricatio.toml, equivalently under
[tool.fabricatio.ext.skill] in pyproject.toml, or via
FABRICATIO_EXT__SKILL__<FIELD_UPPER> environment variables.
# fabricatio.toml
[ext.skill]
distill_skills_template = "built-in/distill_skills"
max_selected_skills = 8
prefilter_threshold = 100
extra_skill_dirs = []
| Option | Type | Default | Description |
|---|---|---|---|
distill_skills_template |
str |
"built-in/distill_skills" |
Template name for the LLM prompt that distills skill content to its essence. |
max_selected_skills |
int |
8 |
Maximum number of skills the LLM may select per call (0 = unlimited). Caps how many bodies reach distillation. |
prefilter_threshold |
int |
100 |
Pool size above which selection keyword-prefilters with the library's SkillRegistry.search before the LLM stage (0 disables the prefilter). |
extra_skill_dirs |
List[str] |
[] |
Extra directories loaded and searched besides the cross-client Agent Skills roots (fixed in Rust). Loaded after them, so a standard-location skill wins a name collision (~ is expanded at use time). Add client-specific roots here (e.g. .claude/skills) or pass dirs= per call. |
Access at runtime: from fabricatio_skill.config import skill_config.
Dependencies
Core dependencies:
fabricatio-core- Core interfaces and utilities ...
License
This project is licensed under the MIT License.
Metadata
Release files for fabricatio-skill 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 19.3 MB
Release files / fabricatio_skill-0.4.2-cp314-cp314-win_amd64.whl
| Download URL | fabricatio_skill-0.4.2-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
e4eba17bed3c58c794a23d4ecd43dd13b3b44876cd330517bfcd8978af64530b
|
|
BLAKE2b-256 checksum How to use checksums |
54ce96ab6d874fb201c73c1516553dc0a4b58a0769c1be83d28ec5a77a93f6ad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp314-cp314-manylinux_2_34_x86_64.whl
| Download URL | fabricatio_skill-0.4.2-cp314-cp314-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.14 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
c830137a996a967aa0ddb6bf555ce57623688582dd09fa45693bc5adedb240d8
|
|
BLAKE2b-256 checksum How to use checksums |
ab465e7e4a8583de5c49effd0047eea22f6df1928b26522ad123e16727ea9f02
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp314-cp314-manylinux_2_34_aarch64.whl
| Download URL | fabricatio_skill-0.4.2-cp314-cp314-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.14 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
1e686260d3de46c6ab99436fbcb45f279ae93debcd2eff1822865bdcef841971
|
|
BLAKE2b-256 checksum How to use checksums |
f646547f5fc10fcb334e755c535b3736be3bf7cbcbad4029f68b1a71554de977
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp314-cp314-macosx_11_0_arm64.whl
| Download URL | fabricatio_skill-0.4.2-cp314-cp314-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.14 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a16ec99fb06a4b1cf7776fbaf932821466dc52ebff9e62db0cbd3d2d57ce2cab
|
|
BLAKE2b-256 checksum How to use checksums |
64012285be8c530d6342d9295d9c2f8598163a155f20e62a128ad074e31b153f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp313-cp313-win_amd64.whl
| Download URL | fabricatio_skill-0.4.2-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
27822521636a36d21acb50cc7c36efddb92277580791762a1526eb4d880283f6
|
|
BLAKE2b-256 checksum How to use checksums |
00267c4fbd18e3d03771003838290e3c13b4006c514818b3684b6ab0b87715e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp313-cp313-manylinux_2_34_x86_64.whl
| Download URL | fabricatio_skill-0.4.2-cp313-cp313-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.13 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
2ee80fa0d5378c302ae454e0f07a6b80d0fa51f68a7f5c8846780e603ccfc870
|
|
BLAKE2b-256 checksum How to use checksums |
326120b482f8cddb48742fd135e6f13765356c5bf6df9e33341e7767adc61fd0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp313-cp313-manylinux_2_34_aarch64.whl
| Download URL | fabricatio_skill-0.4.2-cp313-cp313-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.13 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
fb2076ed649880f7581a564541266ce136ed331dfc14e18884269121f418f7f8
|
|
BLAKE2b-256 checksum How to use checksums |
5495aa48026fd6a0a76ae7f7803ab0713acdf97c36fff96b30d604937668dfba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp313-cp313-macosx_11_0_arm64.whl
| Download URL | fabricatio_skill-0.4.2-cp313-cp313-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.13 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b6a0fcce60e44e3e64dd7451b945c7fb5bed13b214cd2123bf45b0595620c352
|
|
BLAKE2b-256 checksum How to use checksums |
3a87244113f746394eeb815e7b814d72cbf3397627a9f188f0630fe7c05641a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp312-cp312-win_amd64.whl
| Download URL | fabricatio_skill-0.4.2-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
b3cb8652f6c5d2aff08a54c6cf359174485eb3e04c39c35bd04882a835e9985d
|
|
BLAKE2b-256 checksum How to use checksums |
0ca32a2dddec11ca4ef7ff4fc80f2bc881b17f942871bbcda8885c58d51312a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp312-cp312-manylinux_2_34_x86_64.whl
| Download URL | fabricatio_skill-0.4.2-cp312-cp312-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.12 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
4462cf3c88f52381718711b91fcff27c3598f94a1fd0bb782cffae13ab04adb0
|
|
BLAKE2b-256 checksum How to use checksums |
e54196058149ebd1295fd1aa9ac4d09f9b413fbc63e285da80e740f595749d5b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp312-cp312-manylinux_2_34_aarch64.whl
| Download URL | fabricatio_skill-0.4.2-cp312-cp312-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.12 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
9aac5aa28c5cd7aae34f7c0c3990407990155c420953c8bc6b43733bcd5fa0c4
|
|
BLAKE2b-256 checksum How to use checksums |
3e875bf09eb37846cafda59ad56cfc7644b1c635d4872f012580a95fd8fbe57a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fabricatio_skill-0.4.2-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | fabricatio_skill-0.4.2-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
270cad183c0f68e3c238379416780d3b0415a7562c0f4fffb73ff9de248a8556
|
|
BLAKE2b-256 checksum How to use checksums |
034d9581b99311e0295f13fed0c4170cedcec4f5326977792f973206e6629a5e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|