Imported from LF-Decentralized-Trust-labs/fabric-x-ansible-collection (
AGENTS.md). Install upstream withnpx skills add LF-Decentralized-Trust-labs/fabric-x-ansible-collection. Copyright stays with the author.
AGENTS.md — AI Agent Guide for hyperledger.fabricx
hyperledger.fabricx is an Ansible collection that automates deployment and lifecycle management of Hyperledger Fabric-X networks.
Namespace/name: hyperledger.fabricx. Authoritative version and deps: galaxy.yml.
Project-local Agent Skills
.agents/skills/ is the source of truth for project-local Agent Skills. Compatible agents discover their metadata from this trusted repository checkout and load the applicable SKILL.md on demand:
creating-fabricx-inventories: load when creating, adapting, or reviewing a custom operator-owned Fabric-X inventory.validating-fabricx-changes: load when checking, validating, reviewing, or preparing repository changes.
Rules — follow before every commit
-
License header — every YAML, shell, and Jinja2 file must begin with:
# # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 #CI enforces this via
scripts/check_license_header.sh. -
No trailing spaces in
.j2files — enforced byscripts/check_trailing_spaces.sh. -
Idempotency — all tasks must be idempotent; use
creates:,changed_when:, or appropriate modules. -
Task names — every
ansible.builtin.*task must have aname:field. -
Code order — first
name:field, thenvars:(if needed), FQDN name of task and finallywhen:(if needed). For blocks:name:, thenwhen:, thenblock:. -
Templates — Jinja2 templates go in
roles/<role>/templates/with.j2extension.
Working in isolation
Use git worktrees under .worktrees/ only for multi-agent jobs (i.e. with subagents). For single-agent work, edit the main checkout directly.
git worktree add .worktrees/<3-4-word-slug> -b worktree/<3-4-word-slug>
Do not remove the worktree when done — leave cleanup to the user.
Architecture
Always read the role argument_specs.yaml first
Before modifying any role, read roles/<role>/meta/argument_specs.yaml. It is the authoritative reference for that role: available tasks, variables, and which deployment modes (binary / container / k8s) it supports. Deployment mode support varies per role — do not assume.
Dispatch pattern
Roles that manage multiple sub-components (e.g. orderer: consenter/batcher/assembler/router; committer: validator/verifier/coordinator/sidecar/query-service) use a dispatcher: the top-level task file reads <role>_component_type and delegates to the matching sub-component directory:
ansible.builtin.include_role:
name: hyperledger.fabricx.<role>
tasks_from: <sub_component>/start # e.g. coordinator/start, assembler/bin/install
Role layout
roles/<role>/
├── defaults/main.yaml # auto-generated from meta/argument_specs.yaml
├── meta/argument_specs.yaml # single source of truth for variables and docs
├── tasks/
│ ├── start.yaml # top-level dispatcher (reads *_component_type)
│ ├── <sub_component>/
│ │ ├── bin/
│ │ ├── container/
│ │ └── k8s/
└── templates/ # *.j2 Jinja2 templates
Cross-role dependencies
These connections are not visible from within a single role:
| Dependency | Detail |
|---|---|
committer → postgres |
Started when postgres_port is defined in inventory |
committer → yugabyte |
Started when yugabyte_component_type is defined in inventory |
committer ↔ orderer |
Coordinator receives the assembler host list at startup |
fxconfig → committer, orderer |
Generates configs consumed by both; for k8s deployments also runs namespace creation |
block_explorer → committer (sidecar) |
Streams blocks over gRPC from the host named by sidecar_host; TLS/mTLS mode is derived from that host's committer_use_tls/committer_use_mtls, not a local flag |
block_explorer → postgres |
Reads/writes indexed blocks via the host named by postgres_db_host |
cryptogen / fabric_ca → orderer, committer |
Crypto artifacts must exist before either can be configured or started |
armageddon / configtxgen → crypto |
Genesis block generation depends on crypto output |
k8s role → k8s deployments |
Namespace setup is a prerequisite for any k8s-mode deployment |
| Monitoring | prometheus scrapes committer, orderer, loadgen, yugabyte; postgres_exporter scrapes postgres; node_exporter on all nodes; cadvisor scrapes container metrics; grafana for dashboards; elasticsearch/jaeger for logs and tracing |
Role reference
| Role | Component managed |
|---|---|
armageddon |
Genesis block builder (armageddon CLI) |
bin |
Generic binary build/install helpers |
block_explorer |
Fabric-X Block Explorer server + Next.js UI (streams blocks from sidecar) |
cadvisor |
cAdvisor container metrics exporter |
committer |
Fabric-X Committer (validator/verifier/coordinator/sidecar/query-service) |
configtxgen |
configtxgen CLI wrapper |
container |
Generic container helpers (start/stop/rm) |
cryptogen |
Crypto material generation |
elasticsearch |
Elasticsearch log backend |
fabric_ca |
Fabric CA server and client |
fxconfig |
fxconfig configuration tool |
git |
Git clone helper |
go |
Go binary build, install, and platform-mapping helpers |
grafana |
Grafana dashboard |
idemixgen |
idemixgen CLI wrapper |
jaeger |
Jaeger tracing backend |
k8s |
Shared Kubernetes helper (used by roles that deploy to k8s) |
loadgen |
Load generator |
node_exporter |
Prometheus Node Exporter |
openssl |
OpenSSL certificate helpers |
orderer |
Fabric-X Orderer (consenter/batcher/assembler/router) |
package |
OS package installation (apt / brew) |
postgres |
PostgreSQL database |
postgres_exporter |
Prometheus Postgres Exporter |
prometheus |
Prometheus monitoring |
tmux |
tmux session helpers |
utils |
Miscellaneous utility tasks |
yugabyte |
YugabyteDB |
Essential commands
make lint # full validation; run only when the user explicitly asks
make start / stop / teardown / wipe # lifecycle
make install-deps # set up control node (venv + python + ansible deps)
make help # full command reference
Agents must use the Makefile targets for repository checks. Do not rewrite or bypass the project check scripts (for example, with ad hoc Python replacements) unless the user explicitly asks for that.
make lint is very time consuming. Do not run it unless the user explicitly asks you to run make lint.
Modifying a role
-
Role variables and documentation are managed exclusively through
roles/<role>/meta/argument_specs.yaml. Bothdefaults/main.yamlandREADME.mdare auto-generated — never edit them directly. -
When you change
argument_specs.yaml, use these Makefile checks in order:make check-argument-specs make check-trailing-spaces make check-license-header -
Run
make lintonly if the user explicitly asks for it. -
Only when all checks pass, regenerate the docs:
make generate-roles-docs
Adding a role (rare)
- Create
roles/<new_role>/meta/argument_specs.yamlwith role options and entrypoints. - Create the task files under
roles/<new_role>/tasks/. - Add the Apache-2.0 license header to every file created.
- Run
make generate-roles-docsto generatedefaults/main.yamlandREADME.md. - Register the role in
roles/README.md(alphabetical order). - Add playbooks under
playbooks/<new_role>/following existing patterns. - Run
make lintand fix any issues before committing.
Adding a new inventory
When a new inventory is added under examples/inventory/, write a corresponding doc under examples/inventory/docs/ following the structure of existing docs (e.g. examples/inventory/docs/local/fabric-x.md). Then register the new doc in mkdocs.yml under the nav.Inventories section, in the appropriate deployment-type group.
Adding or modifying a tutorial lesson
The tutorial under docs/tutorial/ is hand-written and is the only documentation in the repository that is a learning path rather than reference material. Keep the two roles distinct: reference detail belongs in the inventory/playbook/role docs, and the tutorial links to them.
When adding or renaming a lesson:
- Follow the existing lesson skeleton:
# <N>. <Title>, a framing paragraph, a> [!NOTE]stating the estimated time and the prerequisite lesson,## Table of Contents <!-- omit in toc -->,## What You Will Learn, the content sections,## Exercise, and a## Nexttable. - Exercises pose the task in a
> [!TIP]callout and hide the answer in a<details markdown="1">block. Themarkdown="1"attribute is required — without itmd_in_htmldoes not render the fenced code inside the block on the MkDocs site. - Never place two callouts adjacent with only a blank line between them; markdownlint reports
MD028. Put prose between them, or merge them into one callout using a>continuation line. - Update the previous/next links in both neighbouring lessons, and the learning-path table in
docs/tutorial/index.md. - Register the lesson in
mkdocs.ymlundernav.Tutorial. Pages underdocs/tutorial/are copied to the site byscripts/build_mkdocs_source.py, but only the nav makes them reachable. - Verify with
npx --yes markdownlint-cli2 "docs/tutorial/**/*.md"(zero issues, using the repo's.markdownlint.yaml) andmake mkdocs-build, which runsmkdocs build --strictand fails on any broken internal link.
Markdown files need no license header — scripts/check_license_header.sh only checks *.yaml and *.yml.
Modifying a playbook
When a playbook under playbooks/ is modified, update the corresponding README.md in the same directory. These READMEs are not auto-generated.
WARNING: Never run
make installwhen the repo is cloned directly into the Ansible collections path — it overwrites the live checkout with a built artifact.