Thank you for contributing to the Zenzic documentation portal. This guide is written for Technical Writers and Documentation Engineers — not Python programmers. If you want to contribute to the Zenzic engine itself, see the core repository.
| Tool | Version | Install |
|---|---|---|
| Node.js | 20 or newer (24 recommended) | nodejs.org |
| npm | 10 or newer | bundled with Node.js |
| just | any | brew install just / cargo install just |
| uv / uvx | any | pip install uv or docs.astral.sh |
Verify your setup:
node --version # must be ≥ 20 (≥ 24 recommended)
npm --version # must be ≥ 10
just --versionClone the repository and install dependencies:
git clone https://github.com/PythonWoods/zenzic-doc.git
cd zenzic-doc
npm ciInstall the pre-commit hooks (run once after cloning):
uvx pre-commit install # commit-stage: hygiene + typecheck + zenzic
uvx pre-commit install -t pre-push # pre-push: 🛡️ Final Guard runs `just verify`just start # EN only — fastest for editing
just start-it # IT only — use when editing Italian contentThe dev server reloads automatically when you save a file.
The language switcher is inactive in dev mode — use just serve after
just build to test locale switching.
docs/ ← English source content (all .mdx)
tutorials/ ← Learning-oriented guides
how-to/ ← Task-oriented recipes
reference/ ← Information-oriented reference
explanation/ ← Conceptual background
community/ ← Contributing, FAQ, license, brand-kit
i18n/
it/ ← Italian translations — mirrors docs/ exactly
blog/ ← Zenzic Blog engineering posts
src/
components/ ← React components (Icon, Homepage sections)
css/custom.css ← design system (do not edit without CEO approval)
static/ ← Static files served verbatim
Rule: Every file inside docs/ must be .mdx. Never create .md files there.
This portal follows the Diátaxis framework. Before writing, identify which quadrant your contribution belongs to:
| Section | Question it answers | Example |
|---|---|---|
tutorials/ |
"How do I learn X step by step?" | First-time setup walkthrough |
how-to/ |
"How do I accomplish X?" | How to add badges |
reference/ |
"What does X do exactly?" | Engine configuration reference |
explanation/ |
"Why does Zenzic work this way?" | Architecture overview |
Place your file in the correct section and follow the naming convention:
verb-noun.mdx for how-to (e.g. add-badges.mdx), noun.mdx for reference.
Every .mdx file must begin with:
---
sidebar_label: Short Label
---Do not add slug: frontmatter. URLs must mirror the filesystem path exactly
(Slug Law — see Governance docs).
Use <Icon name="icon-name" /> anywhere without per-file imports.
Available names are listed in src/components/Icon.tsx.
The Italian locale lives in i18n/it/docusaurus-plugin-content-docs/current/ and
mirrors docs/ exactly.
When you add a new file:
- Create the English version in
docs/. - Create the Italian version in the corresponding
i18n/it/path. - The content of the Italian file must be a faithful translation — not a machine translation without review.
When you rename a file:
- Rename in both
docs/andi18n/it/. - Run
just buildto confirm no broken links.
To regenerate translation stubs after structural changes:
npm run write-translationsTo ensure consistency between the core engine (zenzic) and the documentation (zenzic-doc), our CI system enforces the Rule of Branch Parity.
- Local Development: Core resolution follows deterministic precedence:
ZENZIC_CORE_PATH→./_zenzic_core→../zenzic. You are responsible for keeping local branches aligned. - In CI (GitHub Actions): The documentation pipeline attempts to clone the core repository by looking for a branch with the exact same name as the one being built in the doc repo.
- Fallback: If the mirrored branch is not found in the core repo, the CI will automatically fall back to the
mainbranch.
| Scenario | Required Action | CI Behavior |
|---|---|---|
| Documentation Fix | Push only to zenzic-doc |
Validates against core main. |
| New Feature (Synchronized) | Push to zenzic BEFORE pushing to zenzic-doc |
Validates against the exact feature code. |
| Naming Convention | Use identical branch names in both repos | Guarantees perfect "Dogfooding". |
Note: Never push documentation changes that depend on core features not yet present on the remote server (even if on different branches), otherwise the build will fail due to misalignment.
Because the repositories are tightly coupled, we recommend managing them through a single Multi-Root Workspace in VS Code.
- Clone both repositories into the same parent directory.
- Open VS Code and go to File > Save Workspace As..., saving it as
zenzic.code-workspacein the parent directory. - Edit the newly created file like this:
{
"folders": [
{ "path": "zenzic" },
{ "path": "zenzic-doc" },
{ "path": "zenzic-action" }
],
"settings": {
"python.analysis.extraPaths": ["./zenzic/src"],
"files.exclude": {
"**/.venv": true,
"**/_zenzic_core": true
}
}
}This allows you to perform global searches across all repositories simultaneously and manage branches from the Source Control panel in a single, unified interface.
If Zenzic fails on a pre-launch external URL (HTTP 404), do not disable external checks globally.
Apply a surgical runtime exclusion with ZENZIC_EXTRA_ARGS:
ZENZIC_EXTRA_ARGS="--exclude-url https://example.com/prelaunch" just verifyRules:
- Exclude only the exact pre-launch URL(s), never broad domains unless explicitly approved.
- Use
ZENZIC_EXTRA_ARGSfor transient pre-launch URLs only. For permanent structural constraints (e.g. rate-limited infrastructure, consistently timing-out third-party services), useexcluded_external_urlsin.zenzic.tomlwith an inline comment explaining the rationale. - Remove each exclusion as soon as the URL is publicly reachable.
For full architecture and lifecycle policy, see Sovereign Override Guide.
Run the full local gate:
just verify # lint-all + build + codes parity + strict audit + score stamp + freshness gateThis must pass with zero errors before you open or update a PR.
- Execute a D.I.A. (Documentation Impact Analysis). If your PR alters CLI behavior or API contracts, explicitly state it in your PR description. You are encouraged to open a matching PR on zenzic-doc, but if you cannot, the maintainers will handle the documentation sync before release.
The repository enforces quality automatically on every git commit:
| Hook | What it checks |
|---|---|
| trailing-whitespace | No trailing spaces |
| end-of-file-fixer | Files end with a newline |
| check-yaml / check-json / check-toml | Valid structured data |
| TypeScript Typecheck | tsc --noEmit must pass |
| Zenzic | zenzic check all must exit 0 |
| REUSE/SPDX | All files have licence information |
If a hook fails, fix the reported issue and retry the commit.
All rev: keys in .pre-commit-config.yaml must point to a 40-char commit
hash, never to a semantic tag (v1.2.3). Git tags are mutable: an upstream
maintainer (or an attacker) can move a tag silently, poisoning the local
Gate 2 without any diff in this repository.
This is an internal CI policy for the zenzic-doc project, not a public
Zenzic linter rule. Enforcement: just check-pinning (dependency of
just verify); violations raise [ADR-089] FATAL at pre-push.
The local exposure window is smaller than the GHA one because pre-commit
freezes hook repos in ~/.cache/pre-commit/ until the user runs autoupdate
or clean; GitHub Actions instead re-resolves the ref on every run. Pinning
is still mandatory locally for new-clone safety and parity with the remote
ADR-089 enforcement.
Updating pinned hooks. Never run plain pre-commit autoupdate — it
rewrites SHAs back to mutable tags. Always use:
uvx pre-commit autoupdate --freezeThis preserves the # vX.Y.Z annotation comment. Commit the diff and
re-verify with just check-pinning.
Blog posts live in blog/ and use the filename format YYYY-MM-DD-slug.mdx.
Required frontmatter:
---
slug: your-post-slug
title: The Full Title
authors: [pythonwoods]
tags: [engineering, release]
date: 2026-04-22
---The author pythonwoods is defined in blog/authors.yml.
Every file in this repository must carry SPDX-FileCopyrightText and
SPDX-License-Identifier metadata. For most files this is handled automatically
via glob annotations in REUSE.toml.
If you add a new file type or directory not covered by existing globs, add an
annotation to REUSE.toml before committing. The reuse lint hook will catch
any gaps.
Check compliance manually:
just reuseAll contributors are expected to follow the
Contributor Covenant Code of Conduct.
Report violations to dev@pythonwoods.dev.
zenzic-doc is developed by PythonWoods · Apache-2.0