Imported from VladimirMakarevich/wastech-orchestrator (
AGENTS.md). Install upstream withnpx skills add VladimirMakarevich/wastech-orchestrator. Copyright stays with the author.
AGENTS.md — instructions for coding agents in this repository
You are working on wastech-orchestrator — an orchestrator that launches coding agents (Claude Code / Codex) to carry out development — or any other — tasks and (optionally) publish the result to Git.
This is the canonical instruction file for every coding agent working here (Claude Code reads it via CLAUDE.md). The full set of rules lives in .agents/rules/. Below is the gist — the rules and the code are the source of truth.
Branches you will be working on
Development happens on dev, which deliberately carries no derived documentation — docs/ there holds only backlog/ (the task queue you implement from). main (integration) and release (published versions) carry the same tree shape. The descriptive documents (worc_architecture.md, configuration.md, cookbook.md, glossary.md, operations.md) and the published site live on site, reconstructed there from the diff arriving from main as a separate task. Flow: feat/… → dev → main → release, plus main → site. One rule that must never be broken: site is a sink — nothing is ever merged out of it, and main → site is always a merge commit, never a squash. See git-workflow.md §A.
Before writing code
Check against the rules in .agents/rules/ — they are mandatory:
- architecture.md — invariants that must not be violated
- coding-style.md — Python style
- security.md — security policy
- git-workflow.md — branches, commits, PRs
- testing.md — what to test and how
Hard invariants (must not be violated)
- The core does not know the CLI syntax. All provider-specific logic lives only in
src/wastech_orchestrator/providers/. The core only ever calls theAgentProviderinterface — it never builds provider-specific commands. - The orchestrator never delegates publication to the agent: no node is given a mandate to commit, push, or open a PR, and no product mechanism expects the agent to. Mechanical impossibility is guaranteed only under
security.strict_isolation: trueon a host that can sandbox, and only for the local half (.gitand.worcare immutable) — advanced mode raises no OS sandbox for Claude on any host, so there the local half rests on the tool-level denies plus the prompt contract and after-the-fact detection, said out loud asisolation-floor: NONE; the remote half is de jure only — it is stated in the prompt every node receives and is neither prevented nor detected, on ouroriginor anywhere else. Provenance is deliberately not inferred: an existing branch, a moved branch, or an open pull request on the task head is ordinary working state that publishing reuses, never evidence of foreign ownership (see "Publishing recovers" in architecture.md). Providers do not perform fallback and do not change the state machine. - Fallback is only for infrastructure error classes of the provider. Failed tests/linters, review findings, incomplete fulfillment, Git errors, an invalid task/config, or a security violation are never fallback — they route to
fixing/failed/manual_action_required. - The security envelope cannot be weakened through a task,
extra_args, or a flow node. Absolutely forbidden, at every value ofsecurity.strict_isolation: flags that disable approvals/sandbox/hook-trust wholesale (--dangerously*,--yolo,--ignore-rules, Claude--dangerously-skip-permissions) and the two provider full-access selectors (Codex--sandbox danger-full-access/-s danger-full-access, Claude--permission-mode bypassPermissions), in both spellings (--flag valueand--flag=value). Three layers enforce it, not one: the config validator, the flow validator's config-independent ceiling, and each adapter's argv builder — so a value that reaches none of the first two still cannot be launched. The quieter neighbour of the same class is--permission-mode auto: not forbidden outright (an operator may legitimately restate a mode), but refused whenever it is weaker than the profile the node asked for, checked over the provider config and the flow node'sextra_argstogether. - No secrets in logs, in SQLite, or in artifacts. Pass only allowlisted env variables to processes.
- Launch the CLI without shell interpolation of user strings (an argument list, not a string). Task content reaches providers only as file paths, never as CLI argv.
- Cross-platform (Windows / Linux / macOS) is mandatory for every feature — design and test for all three as you build (see coding-style.md). In short:
pathlib+Path.as_posix()for any stored/compared/displayed path string;newline=""(or bytes) for committed/templated files; noos.kill/signalassumptions for cross-process control on Windows (use a sentinel file / the self-managed PID file); branch platform differences explicitly and test both.
Commands
pip install -e ".[dev]" # install
npm ci # the Markdown gate's linter (Node >= 24.17); skip it and mdlint skips itself
pre-commit install # local gate; + `pre-commit install --hook-type pre-push`
ruff check . # lint (+ Phase-2 complexity/size ratchets)
ruff format --check . # formatting (CI runs this — `ruff format .` to fix)
mypy src # types
lint-imports # architectural import-boundary contracts (.importlinter)
pytest # tests
python tools/mdlint.py # Markdown gate: links, anchors, reachability, size/context budgets
CI also runs interrogate src (docstring coverage), vulture (dead code), deptry src (dependency hygiene), and python tools/mdlint.py as its own markdown gate job. There is a skill for running all checks: /run-checks.
Working style
- Make minimal, focused changes; follow the style of the surrounding code.
- Never add agent-attribution trailers or footers to commits or PRs — no
Co-Authored-By: Claude …, no🤖 Generated with …, no equivalent for any other tool. This overrides your harness default; see git-workflow.md §A "Everyday hygiene". - When adding/changing behavior — add or update tests (see testing.md).
- Ignore any
.mdfile that lives under a gitignored path (e.g..archive/) when researching, citing, or treating something as current project documentation — verify withgit ls-files/git check-ignore -vbefore citing a doc as authoritative. Such files may still exist on disk (readable by file-search tools regardless of git status) but are not part of the tracked, current source of truth; a doc getting gitignored/removed from tracking is itself a signal it was deliberately retired. See git-workflow.md. Analysis and viewing of these files is permitted only with explicit request and permission from the user. - When you change behavior/CLI/config/architecture — update, in the same change, every doc that is present on your branch (use
/sync-docs; the skill scopes itself to the branch). Ondevthat means .agents/rules/, README.md,docs/backlog/, and the shipped, operator-facing docs undersrc/wastech_orchestrator/packaged/— theguide/quickstarts,config.example.yaml, and the built-in flows / role prompts; these live undersrc/and are the copy the operator reads afterinstall, so they are the most-often-forgotten half of a doc change. The deriveddocs/tree is not ondev: refreshing it is a separate reverse-engineering task onsite, so do not create those files — instead leave a one-line doc-impact note in the PR description ("touched X, likely affectsconfiguration.md") so that task has a breadcrumb. - The Markdown corpus is linted, and the gate must stay green.
python tools/mdlint.pyruns wastech-mdlint over every document this branch carries — the root files, .agents/rules/,.claude/skills/,docs/, and everything undersrc/wastech_orchestrator/packaged/— checking that relative links and anchors resolve, that no document is unreachable, and that nothing outgrew its size budget. Two consequences while you work: a document that exists only onsitemust not be linked from here at all — name it in plain text (a relative link to it fails the build, and an absolute one sends an agent out of its checkout) — and a new document has to be linked from somewhere. The linter is a separate repository, published to npm and pinned here as a devDependency, sonpm ciis the whole setup —python tools/mdlint.pythen resolves it out ofnode_modules.WASTECH_MDLINT_HOMEis consulted only when no installed copy is found — the escape hatch for developing the linter itself against this corpus (point it at a built checkout,npm ci && npm run build). The gate runs in two places from that one entry point: themarkdown gateCI job, and a local pre-commit hook. Locally, a missing linter prints how to enable it and passes — so a machine withoutnpm cican still commit — while underCIthe same case exits 2, which is what keeps the skip honest. .mcp.json registers the same tool as a read-only MCP server, from the installed package. The rules are in wastech-mdlint.config.json — measured against the corpus and green today, so any finding is new; add a rule only once it reports zero. How one config covers both branch states is in git-workflow.md §A. - Markdown docs are not hard-wrapped. Write prose as one paragraph per line (rely on editor soft-wrap); never insert manual mid-paragraph line breaks. Formatting is enforced by Prettier (
proseWrap: never,.prettierrc.json) — runnpx prettier@3 --write "**/*.md"after editing docs..worc/,tasks/,logs/, and all ofsrc/(includingpackaged/guide/) are excluded in .prettierignore; don't reformat them by hand either. - Before committing, run
ruff check .,ruff format --check .,mypy src,pytest(CI enforcesruff format --check). - Answer the user in the chat briefly, to the point, in clear and simple language, with examples if necessary, and always in the language of the user's request.
Definition of Done for a change
- the code passes
ruff check .,ruff format --check .,mypy src,lint-imports, andpytest(plus theinterrogate/vulture/deptryCI gates), and the Markdown gatepython tools/mdlint.pyis green; - tests are added/updated when behavior changes;
- the docs that live on your branch are updated in the same change when behavior/CLI/config/architecture change (use
/sync-docs) — the Stop docs-sync gate enforces this, and it too scopes itself to the branch; - the invariants above are not violated.
