agentleFS
MatrixFounderMatrixFounder/Universal-skills/AGENTS.md

Universal-skills

AGENTS.md1 starsChanged 6 months agoApache-2.0View on GitHub

This file is the authoritative behavioural contract for agents (Codex, Anthropic Agent SDK, etc.) working in this repository. It is kept in lockstep with GEMINI.md — any rule added here is added there too. Public-facing project documentation is in README.md; contributor protocol is in docs/CONTRIBUTING.md. - Python: Always use .venv/ virtual environment (per skill). Never pip install globally. - Node.js: Always use local node_modules/ (per skill). Never npm install -g. - Bootstrap shortcut for skills that have one: bash skills/<skill>/scripts/install.sh.…

  • Deletes or force-pushes
  • Installs packages

The file

Show its rules and text

We split this AGENTS.md into the rules it gives an agent

21 rules. About 0 are common, 9 are distinctive, and 12 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈9

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 12

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Python: Always use .venv/ virtual environment (per skill).

    line 16
  2. Very specific:

    Node.js: Always use local node_modules/ (per skill).

    line 23
  3. Distinctive:

    Must exit 0 before declaring any change complete.

    line 45
  4. Very specific:

    Always run end-to-end on a real fixture from examples/ or tmp/test-data/.

    line 46
  5. Very specific:

    When you change ANYTHING under skills/docx/scripts/office/ or skills/docx/scripts/_soffice.py:

    line 64
  6. Distinctive:

    Edit only the docx copy: Never edit the xlsx or pptx copies.

    line 67
  7. Distinctive:

    Verify byte-identity: before committing:

    line 79
  8. Distinctive:

    All four must produce no output.

    line 86
  9. Distinctive:

    When you change either of these:

    line 119
  10. Very specific:

    When you change office_passwd.py:

    line 150
  11. Very specific:

    If the user asks for a *specification* / *plan* / *spec* (and not code), produce the planning artifact (e.g.

    line 270
  12. Distinctive:

    STOP: Do not start writing code until the user explicitly says "implement".

    line 273
  13. Very specific:

    When a test or review needs a stand-in for a system tool (brew, pip, ffmpeg, …) in a private fakebin/ on PATH:

    line 350
  14. Very specific:

    Before writing to any path under a scratch directory, check it is not a symlink (test -L path && exit 1).

    line 356
  15. Very specific:

    Never point >/>>/tee at anything outside the repository or the scratchpad.

    line 359
  16. Very specific:

    When an architecture, a stack table or a dependency pin names a version, it names the current stable line verified on the day of writing — …

    line 402
  17. Distinctive:

    Verify before writing; record the date of the check.

    line 410
  18. Distinctive:

    If the newest line breaks a requirement (no wheels for a dependency, an unsupported platform, a licence change), say so, pin the newest …

    line 411
  19. Distinctive:

    Never silently fall back to an older line because it is familiar.

    line 414
  20. Very specific:

    If a feature has a known limitation (e.g.

    line 424
  21. Very specific:

    All third-party material (XSD schemas from ECMA-376 / Microsoft OSP / W3C, runtime dependencies, external CLI tools) is attributed in …

    line 452

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md 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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

Agent Rules — Universal-Skills

This file is the authoritative behavioural contract for agents (Codex, Anthropic Agent SDK, etc.) working in this repository. It is kept in lockstep with GEMINI.md — any rule added here is added there too. Public-facing project documentation is in README.md; contributor protocol is in docs/CONTRIBUTING.md.


1. Local-development rules

Package management

  • Python: Always use .venv/ virtual environment (per skill). Never pip install globally.
    cd skills/<skill>/scripts
    python3 -m venv .venv && source .venv/bin/activate
    pip install -r requirements.txt
  • Node.js: Always use local node_modules/ (per skill). Never npm install -g.
    cd skills/<skill>/scripts && npm install
  • Bootstrap shortcut for skills that have one: bash skills/<skill>/scripts/install.sh. The script creates .venv/ + node_modules/ and prints install hints for missing system tools (LibreOffice, Poppler, pango, …) — it does NOT install system tools itself; that's the user's choice.

Testing

  • Tests run through the per-skill venv:
    cd skills/<skill>/scripts
    ./.venv/bin/python -m unittest discover -s <module>/tests
  • Skill structural validation (Gold Standard / CSO):
    python3 .Codex/skills/skill-creator/scripts/validate_skill.py skills/<skill>
    Must exit 0 before declaring any change complete.
  • Always run end-to-end on a real fixture from examples/ or tmp/test-data/. Don't ship code that hasn't actually run on data.

2. Office-skills modification protocol — STRICT

docx, xlsx, and pptx share an identical OOXML helper module (scripts/office/) and LibreOffice wrapper (scripts/_soffice.py). The docx skill is the MASTER. xlsx and pptx carry byte-identical copies of those files. There is no symlink, no submodule, no shared import — physical duplication is intentional (per project plan §"Независимость скиллов": each skill must be installable and runnable in isolation, including as a packaged .skill archive).

Rule

When you change ANYTHING under skills/docx/scripts/office/ or skills/docx/scripts/_soffice.py:

  1. Edit only the docx copy. Never edit the xlsx or pptx copies.
  2. Run the docx tests (office/tests/) to confirm the change works.
  3. Replicate to xlsx and pptx in the SAME commit:
    rm -rf skills/xlsx/scripts/office skills/pptx/scripts/office
    cp -R skills/docx/scripts/office skills/xlsx/scripts/office
    cp -R skills/docx/scripts/office skills/pptx/scripts/office
    cp skills/docx/scripts/_soffice.py skills/xlsx/scripts/_soffice.py
    cp skills/docx/scripts/_soffice.py skills/pptx/scripts/_soffice.py
    find skills -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null
  4. Verify byte-identity before committing:
    diff -qr skills/docx/scripts/office skills/xlsx/scripts/office
    diff -qr skills/docx/scripts/office skills/pptx/scripts/office
    diff -q  skills/docx/scripts/_soffice.py skills/xlsx/scripts/_soffice.py
    diff -q  skills/docx/scripts/_soffice.py skills/pptx/scripts/_soffice.py
    All four must produce no output.
  5. Re-run skill-validator on all four office skills:
    for s in docx xlsx pptx pdf; do
        python3 .Codex/skills/skill-creator/scripts/validate_skill.py skills/$s
    done

What counts as an office/ change

In scope (must replicate): everything under skills/docx/scripts/office/ (unpack, pack, validate, validators/, helpers/, shim/, tests/, _encryption.py, _macros.py, schemas/README.md, schemas/fetch.sh, schemas/w3c/) plus skills/docx/scripts/_soffice.py.

Out of scope (docx-only, no replication): skills/docx/scripts/docx_*.py, skills/docx/SKILL.md, skills/docx/references/, skills/docx/examples/, skills/docx/scripts/package.json, skills/docx/scripts/requirements.txt, skills/docx/scripts/install.sh.

Cross-skill scripts (4-skill replication, includes pdf)

Two helper files live at skills/<skill>/scripts/ (sibling to _soffice.py, NOT inside office/) and are byte-identical across all four office skills (docx, xlsx, pptx, pdf):

  • _errors.py — --json-errors envelope helper used by every Python CLI for uniform machine-readable failure output.
  • preview.py — universal INPUT → PNG-grid renderer; routes .pdf through Poppler directly and .docx/.xlsx/.pptx (incl. .docm/ .xlsm/.pptm) through LibreOffice → Poppler.

When you change either of these:

  1. Edit only the docx copy.
  2. Replicate to xlsx, pptx, AND pdf (note: pdf is included even though it has no office/):
    for s in xlsx pptx pdf; do
        cp skills/docx/scripts/_errors.py skills/$s/scripts/_errors.py
        cp skills/docx/scripts/preview.py skills/$s/scripts/preview.py
    done
  3. Verify byte-identity:
    for s in xlsx pptx pdf; do
        diff -q skills/docx/scripts/_errors.py skills/$s/scripts/_errors.py
        diff -q skills/docx/scripts/preview.py  skills/$s/scripts/preview.py
    done
  4. Re-run all four E2E suites + validate_skill.py on all four skills.

Cross-skill scripts (3-skill replication, OOXML only)

One helper file is byte-identical across the three OOXML office skills (docx, xlsx, pptx) but NOT pdf, because it operates on the OOXML container format directly:

  • office_passwd.py — set/remove password protection on .docx/.xlsx/.pptx via msoffcrypto-tool (MS-OFB Agile, Office 2010+). Pdf has its own encryption mechanism (pypdf PdfWriter.encrypt) and does not use this script.

When you change office_passwd.py:

  1. Edit only the docx copy.
  2. Replicate to xlsx and pptx:
    cp skills/docx/scripts/office_passwd.py skills/xlsx/scripts/office_passwd.py
    cp skills/docx/scripts/office_passwd.py skills/pptx/scripts/office_passwd.py
  3. Verify byte-identity:
    diff -q skills/docx/scripts/office_passwd.py skills/xlsx/scripts/office_passwd.py
    diff -q skills/docx/scripts/office_passwd.py skills/pptx/scripts/office_passwd.py
  4. Re-run E2E for the three OOXML skills + validate_skill.py.

The msoffcrypto-tool>=5.4.0 dependency must stay in requirements.txt of all three OOXML skills; it is NOT a pdf dependency.

Skill html (formerly html2md) — TWO-master replication

The standalone skill html (Proprietary, All Rights Reserved — it embeds byte-identical copies of proprietary docx/pdf code, so it joins the office-proprietary set per §3 License hygiene, NOT Apache-2.0; Web/HTML acquisition + HTML→Markdown for Obsidian clipping + agent workflows; see docs/office-skills-backlog.md §2 «html» and TASK 022 / TASK 027) reuses hardened code from both docx and pdf. Because the HTML-cleaning code physically originates in pdf and the conversion core in docx, html is the one documented exception to "docx is always master" — it has two masters. Follow this topology exactly and do NOT fork.

Naming caveat (load-bearing — do not "fix"): the user-facing launcher is the extensionless file skills/html/scripts/html (NOT html.py), and the internal Python package is still skills/html/scripts/html2md/. A html.py file or a html/ package on scripts/ (which sits at sys.path[0]) would shadow the stdlib html module that acquire.py and the pdf-mastered web_clean/preprocess.py import (html.escape / html.unescape). Keep the launcher extensionless and the package named html2md. skills/html/scripts/html2md.py is the combined end-to-end command (fetch → md → delete the intermediate HTML). Config env vars are HTML_* (a hard rename from HTML2MD_*, no aliases).

Replication units (each byte-identical, diff -q gated):

  1. HTML→MD core — MASTER = docx. html2md_core.js is lifted verbatim from skills/docx/scripts/docx2md.js (buildTurndown + expandTableToGrid, lines ~258-336). docx2md.js imports it; html carries a byte-identical copy — KEEP the html2md_core.js filename (it matches the docx master; diff -q is content-based). Edit only the docx copy.
  2. HTML-cleaning cluster — MASTER = pdf (the exception). The five pure-regex/stdlib modules under skills/pdf/scripts/html2pdf_lib/ — archives.py, reader_mode.py, preprocess.py, dom_utils.py, normalize_css.py — replicate to skills/html/scripts/web_clean/. Edit only the pdf copy. NEVER replicate render.py, chrome_engine.py, or the package __init__.py — they are the only weasyprint/playwright carriers (weasyprint is a module-level import in render.py alone). html ships its OWN thin web_clean/__init__.py (html-authored, NOT under the gate) re-exporting only clean symbols.
  3. Shared helpers — MASTER = docx, 4→5-skill loop. _errors.py and _venv_bootstrap.py include html in their replication loop. preview.py / _soffice.py are NOT needed (html emits Markdown, not renderable office docs).

Guards (non-negotiable):

  • An import smoke-test MUST assert weasyprint and playwright stay out of sys.modules after importing web_clean (the __init__.py trap).
  • Carry the pdf cleaning modules whole — do NOT trim weasyprint- specific functions. They are inert regex with no heavy imports; trimming makes diff -q impossible and silently forks on the next pdf change.
  • The CI diff -q gate lives in skills/html/scripts/tests/test_e2e.sh (run by the office-skills matrix) covering both the docx→core and pdf→cluster replicas; it also fails on a zero-test discover run.
  • Licensing: html is Proprietary (derived work embedding proprietary docx/pdf source) — its per-skill LICENSE/NOTICE mirror the office four, THIRD_PARTY_NOTICES.md re-points to it, and it is never published under Apache-2.0 (see §3 License hygiene).

Framework copies — agentic-development is the master

Some skills of skills/ are full copies of skills that agentic-development maintains. A directory of skills/ is such a copy when .agentic-development/.agent/skills/<name> is a directory; on 2026-11-07 there were six: brainstorming, hooks-creator, skill-creator, skill-enhancer, vdd-adversarial, vdd-sarcastic.

  1. Edit the canonical skill in agentic-development. An edit made here first goes to canonical in the same change.
  2. Copy the changed files: cp <agentic-development>/.agent/skills/<name>/<file> skills/<name>/<file>.
  3. Check with python3 scripts/check_framework_copies.py: exit 0, every copy ok. A DRIFT line names each file that differs or exists on one side only. Without the sibling repository the script prints SKIPPED; CI runs only its own test (tests/test_framework_copies.py).
  4. A copy works outside the framework. It names no path, command or role that only agentic-development resolves. It may name a framework skill together with what to do without it, as brainstorming does for mermaid-authoring-guidelines. Open exceptions: skill-creator and skill-enhancer still name framework paths such as .agent/ and docs/issues/ (agentic-development TASK 142, §5); vdd-sarcastic still names docs/reviews/… and audit-NNN IDs (agentic-development TASK 141, §5).

Anti-patterns — DO NOT

  • ❌ Edit skills/xlsx/scripts/office/foo.py directly.
  • ❌ Replicate from xlsx → docx (always docx is source of truth).
  • ❌ Symlink skills/xlsx/scripts/office -> ../../docx/scripts/office.
  • ❌ Forget to clean __pycache__ before diff -qr (false positives).
  • ❌ Replicate without running tests + validator afterwards.
  • ❌ Re-point the html skill's web_clean/ cluster to docx-master — its master is pdf (documented exception above). Conversely, do NOT copy render.py/chrome_engine.py/__init__.py into html.

Full protocol with rationale: docs/CONTRIBUTING.md §3.


3. Behavioural conventions

Spec-first when explicitly requested

If the user asks for a specification / plan / spec (and not code), produce the planning artifact (e.g. implementation_plan.md or write to the plan file in ~/.Codex/plans/ if in plan-mode) and STOP. Do not start writing code until the user explicitly says "implement".

Tests first when the change is non-trivial

For changes >5 lines of business logic, write or update tests in the relevant tests/ directory before declaring the work done. Tests are the contract; passing tests is the verification that the change behaves as advertised.

CLI I/O encoding — name the codec, never inherit it from the locale

Closed repo-wide 2026-08-31 … 2026-09-02 as four issue records (~210 call sites). New CLIs must be born compliant. The root is always the same — CPython takes the codec from the caller's locale instead of from the contract — but the four channels want four different answers:

ChannelContractSpelling
Human stdout/stderr — reports, --helpObey the locale; degrade per character; never crashone install_human_channel() at the top of main()
Machine stdout — JSON payloadIgnore the locale; always UTF-8 bytes (RFC 8259 §8.1)write_json_stdout(...) (office _errors.py) / the skill's own emit_json
--json-errors envelope on stderrMust stay parseable under any localeensure_ascii=True — ASCII-only, no exceptions
Child output — subprocessThe codec belongs to the child (node, soffice, tesseract, git, yt-dlp), not to ussubprocess.run(..., text=True, encoding="utf-8", errors="replace")
Files we read/writeName the codec the file isread_text(encoding="utf-8"), open(p, "w", encoding="utf-8") — no errors=, it would hide our own corruption

argparse specifically:

  • --help is printed by argparse, not by your code. ArgumentParser._print_message catches AttributeError and OSError but not UnicodeEncodeError, so one em dash in one help= string returns rc 1 and 0 bytes. 31 of 102 measured findings were --help; no audit of print() sites finds them. Therefore every new CLI entry point calls install_human_channel() as the first statement of main(), before parse_args().
  • Never call it at import time — reconfigure() mutates a global stream and would impose the behaviour on anyone who merely imports the module.
  • ASCII-only source does not make a CLI safe: 44 of 102 findings came from data (a Cyrillic filename in an f-string), not from literals.

Gates — green before the change is done:

python3 tests/test_subprocess_decode.py   # CI harness → "subprocess-decode guard"
python3 tests/test_file_codec.py          # CI harness → "file-codec guard"

plus the per-skill test that runs every script's --help under a restricted locale. Both AST gates exempt tests/ by design and print the size of the carve-out; do not widen it to production code. Repro for the output side needs the PEP 538/540 safeties off (env PYTHONIOENCODING=ascii PYTHONUTF8=0 LC_ALL=C <cmd>); the subprocess side does not — LC_ALL=ja_JP.SJIS alone is enough.

Do NOT:

  • ❌ sys.stdout.reconfigure(encoding="utf-8") to "fix" the human channel — it overrides the caller's explicit choice process-wide. errors= is a different keyword and is exactly the fix; encoding= is banned here.
  • ❌ Re-introduce wrapper layers (say(), HumanArgumentParser) — deliberately removed: they duplicated a stdlib mechanism and failed silently when someone added a plain print.
  • ❌ Escape via exc.encoding — charmap codecs report the literal "charmap" and hand back a raw byte. Escape against ASCII.
  • ❌ errors="strict" on a subprocess read, or errors= on files we write.
  • ❌ Drop encoding= while refactoring a subprocess call — the gate will fail, and that is its job, not a nuisance.
  • ❌ Import the proprietary _errors.py from an Apache-2.0 skill — each such skill carries its own stdlib-only copy (see License hygiene below). _errors.py is docx-master: change it there and replicate per §2.

Records: human-cli-output-locale-class, pdf-cli-stdout-json-locale-class, subprocess-text-decode-locale-class, file-text-codec-locale-class.

Fake binaries and PATH shims — copy, never symlink

When a test or review needs a stand-in for a system tool (brew, pip, ffmpeg, …) in a private fakebin/ on PATH:

  • Create the stand-in with cp or a fresh heredoc. Never ln -s a system binary into fakebin/. A later cat > fakebin/<tool> or chmod/sed -i follows the symlink and rewrites the real file.
  • Before writing to any path under a scratch directory, check it is not a symlink (test -L path && exit 1); the write must land in the scratch tree, not in /opt/homebrew, /usr/local or $HOME/.pyenv.
  • Never point >/>>/tee at anything outside the repository or the scratchpad. System files are read-only for every agent role.

Why this rule exists (2026-09-01). A review agent ran ln -sf /opt/homebrew/bin/brew $SCRATCH/fakebin/brew, then six minutes later cat > $SCRATCH/fakebin/brew <<'EOF' … EOF. The redirection followed the symlink and replaced the real /opt/homebrew/bin/brew with a three-line stub that printed "whisper-cpp — уже установлен" and exited 0. Homebrew stayed silently broken for a week; every brew install on the machine reported success and installed nothing. Restored with git -C /opt/homebrew checkout -- bin/brew.

Project-local toolchains — never install into the machine

Everything a project needs beyond the language runtime lives inside the project tree, pinned, and is reproducible from the project's own setup target:

  • Python: a venv under the project (.venv/); never pip install into the system, Homebrew or pyenv interpreter.
  • Node: the project's node_modules/ from the lockfile (npm ci); never npm install -g a project tool.
  • Go and other single-binary tools (linters, formatters, generators, protoc plugins): install into a project-local bin directory (GOBIN=$PROJECT/.bin go install …@vX.Y.Z, cargo install --root) and invoke them by that path.
  • Runtimes themselves (interpreter, compiler, node) belong to a version manager (pyenv, nvm, goenv) or the OS package manager, and are installed only on the user's explicit say-so.

The tools/check target looks for tools at the project-local path, not on PATH. A tool found only on PATH is a setup defect, not a fallback.

Why this rule exists (2026-09-08). One machine hosts many projects. A global install changes what every other project sees: a different linter or formatter version, a package that shadows one a neighbour pinned. One broken global tool (the brew stub above) silently affected every project for a week. Local means a project can break only itself.

Design against current versions, not remembered ones

When an architecture, a stack table or a dependency pin names a version, it names the current stable line verified on the day of writing — registry or release page (pip index versions, npm view, go list -m -versions, the project's releases page) — with the date of the check recorded next to the pin. Model memory is not a source for a version number: training data lags, so "the version I remember" is old by construction.

  • Verify before writing; record the date of the check.
  • If the newest line breaks a requirement (no wheels for a dependency, an unsupported platform, a licence change), say so, pin the newest line that does not, and ask the user when the trade-off is theirs.
  • Never silently fall back to an older line because it is familiar.

Why this rule exists (2026-09-08). An architecture pinned PostgreSQL 16 and Redis 7 from memory while 18 and 8 were current, and the implementation then reached for Python 3.12 while 3.14 was current. The user caught it in a dialogue and had to be re-asked. The check costs one registry query; the miss costs a re-plan.

Honest scope, not aspirational

If a feature has a known limitation (e.g. the AF_UNIX shim does NOT provide cross-process IPC — see skills/docx/scripts/office/shim/lo_socket_shim.c file-level comment), document the limitation in the file's docstring AND lock it in with a regression test (e.g. TestShimCrossProcessIPCLimitation). Do not let documentation overstate what the code does.

License hygiene

This repository uses a split licensing model (effective 2026-04-25):

  • Repository root and all skills except the four office skills are Apache-2.0 (LICENSE).
  • The four office skills — skills/docx/, skills/xlsx/, skills/pptx/, skills/pdf/ — are Proprietary, All Rights Reserved, governed by their per-skill LICENSE and NOTICE files (e.g. skills/docx/LICENSE). Source is available for audit only; any use, execution, copying, modification, or distribution requires prior written permission.
  • skills/html/ (formerly html2md; TASK 022 / TASK 027) is also Proprietary, All Rights Reserved — it embeds byte-identical copies of proprietary docx/pdf code (turndown core, web_clean/ cluster) and therefore cannot be Apache-2.0. It has its own per-skill LICENSE/ NOTICE mirroring the office four; the first bullet's "except the four office skills" should be read as "except the four office skills and html".

All third-party material (XSD schemas from ECMA-376 / Microsoft OSP / W3C, runtime dependencies, external CLI tools) is attributed in THIRD_PARTY_NOTICES.md (root, governs both license scopes) and re-pointed from each office skill's NOTICE file. When you add a new external dependency, update THIRD_PARTY_NOTICES.md in the same commit. Do not alter or strip the per-skill LICENSE / NOTICE files in the four office skills.


4. Reference index for agents working here

  • README.md — public registry of all skills.
  • docs/CONTRIBUTING.md — full contributor protocol (this file is a behavioural summary; CONTRIBUTING is the reference).
  • docs/SKILL_EXECUTION_POLICY.md — script-first vs prompt-first; Tier definitions.
  • docs/Manuals/office-skills_manual.md — practical guide to docx/xlsx/pptx/pdf.
  • docs/refactoring-office-skills.md — historical design rationale for the open-source office-skills architecture; do not edit, supersede via docs/CONTRIBUTING.md.
  • .Codex/skills/skill-creator/ — init_skill.py for new skills; validate_skill.py for Gold-Standard checks.
  • .Codex/skills/skill-validator/ — security and structural compliance scanner.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.